From 954418e7818dd5d8fc4103c9de45a04c9649bd0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20B=C5=82oniarz?= <56109050+bartlomiejbloniarz@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:50:40 +0100 Subject: [PATCH 01/54] Improve reduced motion warning (#5487) ## Summary This PR extends the reduced motion warning to inform that it is only displayed in development mode and adds a note in docs that explains why the warning is displayed and how it can be disabled. ## Test plan --- docs/docs/guides/troubleshooting.mdx | 16 ++++++++++++++++ src/reanimated2/animation/util.ts | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/docs/guides/troubleshooting.mdx b/docs/docs/guides/troubleshooting.mdx index 6fb8f8b0c8a..cc1c6770ba1 100644 --- a/docs/docs/guides/troubleshooting.mdx +++ b/docs/docs/guides/troubleshooting.mdx @@ -139,6 +139,22 @@ See [Multiple versions of Reanimated were detected](#multiple-versions-of-reanim **Solution:** Please upgrade to a newer version of React Native or downgrade to an older version of Reanimated. See [the compatibility table](compatibility) for a full list of supported versions of React Native. +## Warnings + +### Reduced motion setting is enabled on this device. + +**Problem:** This warning is displayed to avoid confusion that could arise when Reduced motion is enabled. + +**Solution:** Do nothing, this warning is safe to ignore as it is only displayed in development mode to avoid confusion. If you wish to disable it, you can add the following line to your project's root file: + +```js +LogBox.ignoreLogs([ + '[Reanimated] Reduced motion setting is enabled on this device.', +]); +``` + +See [the accessibility overview](accessibility) to learn more about Reduced Motion. + ## Threading issues ### Tried to synchronously call a non-worklet function on the UI thread diff --git a/src/reanimated2/animation/util.ts b/src/reanimated2/animation/util.ts index 027eb837b1a..1184c158c80 100644 --- a/src/reanimated2/animation/util.ts +++ b/src/reanimated2/animation/util.ts @@ -38,7 +38,7 @@ const IS_REDUCED_MOTION = isReducedMotion(); if (__DEV__ && IS_REDUCED_MOTION) { console.warn( - `[Reanimated] Reduced motion setting is enabled on this device. Some animations will be disabled by default. You can override the behavior for individual animations, see https://docs.swmansion.com/react-native-reanimated/docs/guides/accessibility.` + `[Reanimated] Reduced motion setting is enabled on this device. This warning is visible only in the development mode. Some animations will be disabled by default. You can override the behavior for individual animations, see https://docs.swmansion.com/react-native-reanimated/docs/guides/troubleshooting#reduced-motion-setting-is-enabled-on-this-device.` ); } From e99d2554027b933f3799e66392dd9ada6fab3b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bert?= <63123542+m-bert@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:15:33 +0100 Subject: [PATCH 02/54] Fix animation cleanup (#5474) ## Summary Current animation cleanup mechanism has many flaws. The biggest problem is that it may cause bugs such as disappearing components, or even removing predefined animations from DOM. This PR introduces new approach to cleaning animations, which should solve problems mentioned above. ## Test plan Tested on the code below (uncomment transform to see bugs)
Test code ```jsx import React from 'react'; import { StyleSheet, View, Text, Pressable } from 'react-native'; import Animated, { FadeIn, FadeInLeft, FadeInRight, FadeInUp, FadeInDown, FadeOut, FadeOutLeft, FadeOutRight, FadeOutUp, FadeOutDown, RollOutLeft, Keyframe, } from 'react-native-reanimated'; const DELAY = 500; const fadeAnimation = [ { enteringName: 'FadeIn', enteringAnimation: FadeIn, exitingName: 'FadeOut', exitingAnimation: RollOutLeft, }, { enteringName: 'FadeInLeft', enteringAnimation: FadeInLeft, exitingName: 'FadeOutLeft', exitingAnimation: FadeOutLeft, }, { enteringName: 'FadeInRight', enteringAnimation: FadeInRight, exitingName: 'FadeOutRight', exitingAnimation: FadeOutRight, }, { enteringName: 'FadeInUp', enteringAnimation: FadeInUp, exitingName: 'FadeOutUp', exitingAnimation: FadeOutUp, }, { enteringName: 'FadeInDown', enteringAnimation: FadeInDown, exitingName: 'FadeOutDown', exitingAnimation: FadeOutDown, }, ]; export default function App() { const [showExiting, setShowExiting] = React.useState(false); React.useEffect(() => { const timeout = setTimeout(() => { setShowExiting(true); }, DELAY * fadeAnimation.length); return () => clearTimeout(timeout); }, []); return ( {showExiting ? fadeAnimation.map((animation) => ( {animation.exitingName} )) : fadeAnimation.map((animation, i) => ( {animation.enteringName} ))} setShowExiting(!showExiting)}> Click me! ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, box: { height: 50, width: 250, margin: 4, alignItems: 'center', justifyContent: 'center', }, enteringBox: { backgroundColor: '#b58df1', }, enteringText: { fontSize: 16, color: 'white', }, exitingBox: { borderColor: '#b58df1', borderStyle: 'dashed', borderWidth: 1, }, exitingText: { fontSize: 16, color: '#b58df1', }, button: { width: 100, height: 40, marginTop: 50, backgroundColor: '#b58df1', borderRadius: 5, display: 'flex', alignItems: 'center', justifyContent: 'space-around', }, }); ```
--- .../createAnimatedComponent.tsx | 6 +- .../layoutReanimation/web/componentUtils.ts | 4 +- .../layoutReanimation/web/config.ts | 3 - .../layoutReanimation/web/domUtils.ts | 87 +++++++++++++++---- 4 files changed, 76 insertions(+), 24 deletions(-) diff --git a/src/createAnimatedComponent/createAnimatedComponent.tsx b/src/createAnimatedComponent/createAnimatedComponent.tsx index ebeaf6364bc..4f3f6c5eb07 100644 --- a/src/createAnimatedComponent/createAnimatedComponent.tsx +++ b/src/createAnimatedComponent/createAnimatedComponent.tsx @@ -60,6 +60,10 @@ import type { FlatList, FlatListProps } from 'react-native'; const IS_WEB = isWeb(); const IS_FABRIC = isFabric(); +if (IS_WEB) { + configureWebLayoutAnimations(); +} + function onlyAnimatedStyles(styles: StyleProps[]): StyleProps[] { return styles.filter((style) => style?.viewDescriptors); } @@ -149,8 +153,6 @@ export function createAnimatedComponent( this._InlinePropManager.attachInlineProps(this, this._getViewInfo()); if (IS_WEB) { - configureWebLayoutAnimations(); - if (this.props.exiting) { saveSnapshot(this._component as HTMLElement); } diff --git a/src/reanimated2/layoutReanimation/web/componentUtils.ts b/src/reanimated2/layoutReanimation/web/componentUtils.ts index 3986b314dde..8b00f637a7f 100644 --- a/src/reanimated2/layoutReanimation/web/componentUtils.ts +++ b/src/reanimated2/layoutReanimation/web/componentUtils.ts @@ -192,7 +192,9 @@ export function setElementAnimation( element.style.transform = convertTransformToString(existingTransform); }; - scheduleAnimationCleanup(animationName, duration + delay); + if (!(animationName in Animations)) { + scheduleAnimationCleanup(animationName, duration + delay); + } } export function handleLayoutTransition( diff --git a/src/reanimated2/layoutReanimation/web/config.ts b/src/reanimated2/layoutReanimation/web/config.ts index 83d0b4b2923..60307910897 100644 --- a/src/reanimated2/layoutReanimation/web/config.ts +++ b/src/reanimated2/layoutReanimation/web/config.ts @@ -39,9 +39,6 @@ import { ZoomIn, ZoomInData, ZoomOut, ZoomOutData } from './animation/Zoom.web'; import type { AnimationData } from './animationParser'; -// Since we cannot remove keyframe from DOM by its name, we have to store its id -export const customAnimations = new Map(); - export type AnimationCallback = ((finished: boolean) => void) | null; export interface AnimationConfig { diff --git a/src/reanimated2/layoutReanimation/web/domUtils.ts b/src/reanimated2/layoutReanimation/web/domUtils.ts index eff80e77cd5..9ec63f81b43 100644 --- a/src/reanimated2/layoutReanimation/web/domUtils.ts +++ b/src/reanimated2/layoutReanimation/web/domUtils.ts @@ -1,63 +1,114 @@ 'use strict'; -import { Animations, customAnimations } from './config'; +import { isWindowAvailable } from '../../PlatformChecker'; +import { Animations } from './config'; import type { AnimationNames } from './config'; -const WEB_ANIMATIONS_ID = 'ReanimatedWebAnimationsStyle'; +const PREDEFINED_WEB_ANIMATIONS_ID = 'ReanimatedPredefinedWebAnimationsStyle'; +const CUSTOM_WEB_ANIMATIONS_ID = 'ReanimatedCustomWebAnimationsStyle'; + +// Since we cannot remove keyframe from DOM by its name, we have to store its id +const animationNameToIndex = new Map(); +const animationNameList: string[] = []; /** * Creates `HTMLStyleElement`, inserts it into DOM and then inserts CSS rules into the stylesheet. * If style element already exists, nothing happens. */ export function configureWebLayoutAnimations() { - if (document.getElementById(WEB_ANIMATIONS_ID) !== null) { + if ( + !isWindowAvailable() || + document.getElementById(PREDEFINED_WEB_ANIMATIONS_ID) !== null + ) { return; } - const style = document.createElement('style'); - style.id = WEB_ANIMATIONS_ID; + const predefinedAnimationsStyleTag = document.createElement('style'); + predefinedAnimationsStyleTag.id = PREDEFINED_WEB_ANIMATIONS_ID; - style.onload = () => { - if (!style.sheet) { + predefinedAnimationsStyleTag.onload = () => { + if (!predefinedAnimationsStyleTag.sheet) { console.error( - '[Reanimated] Failed to create layout animations stylesheet' + '[Reanimated] Failed to create layout animations stylesheet.' ); return; } for (const animationName in Animations) { - style.sheet.insertRule(Animations[animationName as AnimationNames].style); + predefinedAnimationsStyleTag.sheet.insertRule( + Animations[animationName as AnimationNames].style + ); } }; - document.head.appendChild(style); + const customAnimationsStyleTag = document.createElement('style'); + customAnimationsStyleTag.id = CUSTOM_WEB_ANIMATIONS_ID; + + document.head.appendChild(predefinedAnimationsStyleTag); + document.head.appendChild(customAnimationsStyleTag); } export function insertWebAnimation(animationName: string, keyframe: string) { + if (!isWindowAvailable()) { + return; + } + const styleTag = document.getElementById( - WEB_ANIMATIONS_ID + CUSTOM_WEB_ANIMATIONS_ID ) as HTMLStyleElement; if (!styleTag.sheet) { - console.error('[Reanimated] Failed to create layout animations stylesheet'); + console.error( + '[Reanimated] Failed to create layout animations stylesheet.' + ); return; } - const customTransitionId = styleTag.sheet.insertRule(keyframe); - customAnimations.set(animationName, customTransitionId); + styleTag.sheet.insertRule(keyframe, 0); + animationNameList.unshift(animationName); + animationNameToIndex.set(animationName, 0); + + for (let i = 1; i < animationNameList.length; ++i) { + const nextAnimationName = animationNameList[i]; + const nextAnimationIndex = animationNameToIndex.get(nextAnimationName); + + if (nextAnimationIndex === undefined) { + throw new Error('[Reanimated] Failed to obtain animation index.'); + } + + animationNameToIndex.set(animationNameList[i], nextAnimationIndex + 1); + } } function removeWebAnimation(animationName: string) { - if (!customAnimations.has(animationName)) { + if (!isWindowAvailable()) { return; } const styleTag = document.getElementById( - WEB_ANIMATIONS_ID + CUSTOM_WEB_ANIMATIONS_ID ) as HTMLStyleElement; - styleTag.sheet?.deleteRule(customAnimations.get(animationName) as number); - customAnimations.delete(animationName); + const currentAnimationIndex = animationNameToIndex.get(animationName); + + if (currentAnimationIndex === undefined) { + throw new Error('[Reanimated] Failed to obtain animation index.'); + } + + styleTag.sheet?.deleteRule(currentAnimationIndex); + animationNameList.splice(currentAnimationIndex, 1); + animationNameToIndex.delete(animationName); + + for (let i = currentAnimationIndex; i < animationNameList.length; ++i) { + const nextAnimationName = animationNameList[i]; + const nextAnimationIndex = animationNameToIndex.get(nextAnimationName); + + if (nextAnimationIndex === undefined) { + throw new Error('[Reanimated] Failed to obtain animation index.'); + } + + animationNameToIndex.set(animationNameList[i], nextAnimationIndex - 1); + } } const timeoutScale = 1.25; // We use this value to enlarge timeout duration. It can prove useful if animation lags. From 532f2db206f39195e497c3892bd505b9b40cf8f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bert?= <63123542+m-bert@users.noreply.github.com> Date: Thu, 14 Dec 2023 10:23:30 +0100 Subject: [PATCH 03/54] [Web LA] Update `left` from snapshot. (#5491) ## Summary #5444 introduced one trick to calculate header height. After further investigation it turned out, that we also have to use the same technique for `left` property from the snapshot. Below you can find two short videos which show the difference. ## Comparison https://github.com/software-mansion/react-native-reanimated/assets/63123542/4f2ad34c-b5ab-41de-a0bb-4b1692cdd664 https://github.com/software-mansion/react-native-reanimated/assets/63123542/d237ee0c-57ea-4b5d-958a-633674bdd1f9 ## Test plan Tested on example app and code below
Test code ```jsx import React from 'react'; import { StyleSheet, View, Text, Pressable } from 'react-native'; import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'; const DELAY = 500; const fadeAnimation = [ { enteringName: 'FadeIn', enteringAnimation: FadeIn, exitingName: 'FadeOut', exitingAnimation: FadeOut, }, ]; export default function App() { const [show, setShow] = React.useState(true); React.useEffect(() => { const timeout = setTimeout(() => { setShow(true); }, DELAY * fadeAnimation.length); return () => clearTimeout(timeout); }, []); return ( {fadeAnimation.map( (animation, i) => show && ( {animation.enteringName} ) )} setShow(!show)}> Click me! ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, box: { height: 50, width: 250, margin: 4, alignItems: 'center', justifyContent: 'center', }, enteringBox: { backgroundColor: '#b58df1', }, enteringText: { fontSize: 16, color: 'white', }, exitingBox: { borderColor: '#b58df1', borderStyle: 'dashed', borderWidth: 1, }, exitingText: { fontSize: 16, color: '#b58df1', }, button: { position: 'absolute', top: 250, left: 250, width: 100, height: 40, backgroundColor: '#b58df1', borderRadius: 5, display: 'flex', alignItems: 'center', justifyContent: 'space-around', userSelect: 'none', }, parent: { height: 70, width: 270, display: 'flex', alignItems: 'center', justifyContent: 'space-around', borderWidth: 2, borderRadius: 10, borderColor: '#b58df1', borderStyle: 'dashed', }, }); ```
--- .../layoutReanimation/web/componentUtils.ts | 62 ++++++++++++++----- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/src/reanimated2/layoutReanimation/web/componentUtils.ts b/src/reanimated2/layoutReanimation/web/componentUtils.ts index 8b00f637a7f..a7eeafea84d 100644 --- a/src/reanimated2/layoutReanimation/web/componentUtils.ts +++ b/src/reanimated2/layoutReanimation/web/componentUtils.ts @@ -240,6 +240,50 @@ export function handleLayoutTransition( setElementAnimation(element, animationConfig, existingTransform); } +function fixElementPosition( + element: HTMLElement, + parent: HTMLElement, + snapshot: DOMRect +) { + const parentRect = parent.getBoundingClientRect(); + + const parentBorderTopValue = parseInt( + getComputedStyle(parent).borderTopWidth + ); + + const parentBorderLeftValue = parseInt( + getComputedStyle(parent).borderLeftWidth + ); + + const dummyRect = element.getBoundingClientRect(); + // getBoundingClientRect returns DOMRect with position of the element with respect to document body. + // However, using position `absolute` doesn't guarantee, that the dummy will be placed relative to body element. + // The trick below allows us to once again get position relative to body, by comparing snapshot with new position of the dummy. + if (dummyRect.top !== snapshot.top) { + element.style.top = `${ + snapshot.top - parentRect.top - parentBorderTopValue + }px`; + } + + if (dummyRect.left !== snapshot.left) { + element.style.left = `${ + snapshot.left - parentRect.left - parentBorderLeftValue + }px`; + } +} + +function setDummyPosition(dummy: HTMLElement, snapshot: DOMRect) { + dummy.style.transform = ''; + dummy.style.position = 'absolute'; + dummy.style.top = `${snapshot.top}px`; + dummy.style.left = `${snapshot.left}px`; + dummy.style.width = `${snapshot.width}px`; + dummy.style.height = `${snapshot.height}px`; + dummy.style.margin = '0px'; // tmpElement has absolute position, so margin is not necessary + + fixElementPosition(dummy, dummy.parentElement!, snapshot); +} + export function handleExitingAnimation( element: HTMLElement, animationConfig: AnimationConfig @@ -265,23 +309,7 @@ export function handleExitingAnimation( const snapshot = snapshots.get(element); - dummy.style.transform = ''; - dummy.style.position = 'absolute'; - dummy.style.top = `${snapshot.top}px`; - dummy.style.left = `${snapshot.left}px`; - dummy.style.width = `${snapshot.width}px`; - dummy.style.height = `${snapshot.height}px`; - dummy.style.margin = '0px'; // tmpElement has absolute position, so margin is not necessary - - const newRect = dummy.getBoundingClientRect(); - - // getBoundingClientRect returns DOMRect with position of the element with respect to document body. - // If react-navigation is used, `dummy` will be placed with wrong `top` position because of the header height. - // The trick below allows us to once again get position relative to body, and then calculate header height. - if (newRect.top !== snapshot.top) { - const headerHeight = Math.abs(newRect.top - snapshot.top); - dummy.style.top = `${snapshot.top - headerHeight}px`; - } + setDummyPosition(dummy, snapshot); const originalOnAnimationEnd = dummy.onanimationend; From 696a8c40584f438a6051f947ab1e5e295598be6e Mon Sep 17 00:00:00 2001 From: Alex Cynk Date: Thu, 14 Dec 2023 15:33:00 +0100 Subject: [PATCH 04/54] Fix overloads in createAnimatedComponent (#5463) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary 1. Move the overload with type deprecation to be the last one. It means that if user provides invalid type which isn't covered by any overload he will not get the warning about FlatList deprecation. This warning was very confusing if user wasn't using FlatList at all 2. Add overload of `ComponentType`. Since `ComponentType

= ComponentClass

| FunctionComponent

` we have assume that it is enough to have two overloads (ComponentClass & FunctionComponent), but it isn't |BEFORE|AFTER| |--|--| |Error for FastImage and deprecation for FastImage ❌ | Deprecation for FlatList only 😎| |Screenshot 2023-12-12 at 13 16 37|image| |image|| ## Test plan Co-authored-by: Aleksandra Cynk --- .../createAnimatedComponent.tsx | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/createAnimatedComponent/createAnimatedComponent.tsx b/src/createAnimatedComponent/createAnimatedComponent.tsx index 4f3f6c5eb07..67ed725ac83 100644 --- a/src/createAnimatedComponent/createAnimatedComponent.tsx +++ b/src/createAnimatedComponent/createAnimatedComponent.tsx @@ -91,15 +91,7 @@ type Options

= { * @see https://docs.swmansion.com/react-native-reanimated/docs/core/createAnimatedComponent */ -/** - * @deprecated Please use `Animated.FlatList` component instead of calling `Animated.createAnimatedComponent(FlatList)` manually. - */ -// @ts-ignore This is required to create this overload, since type of createAnimatedComponent is incorrect and doesn't include typeof FlatList -export function createAnimatedComponent( - component: typeof FlatList, - options?: Options -): ComponentClass>>; - +// Don't change the order of overloads, since such a change breaks current behavior export function createAnimatedComponent

( component: FunctionComponent

, options?: Options

@@ -110,6 +102,22 @@ export function createAnimatedComponent

( options?: Options

): ComponentClass>; +export function createAnimatedComponent

( + // Actually ComponentType

= ComponentClass

| FunctionComponent

but we need this overload too + // since some external components (like FastImage) are typed just as ComponentType + component: ComponentType

, + options?: Options

+): FunctionComponent> | ComponentClass>; + +/** + * @deprecated Please use `Animated.FlatList` component instead of calling `Animated.createAnimatedComponent(FlatList)` manually. + */ +// @ts-ignore This is required to create this overload, since type of createAnimatedComponent is incorrect and doesn't include typeof FlatList +export function createAnimatedComponent( + component: typeof FlatList, + options?: Options +): ComponentClass>>; + export function createAnimatedComponent( Component: ComponentType, options?: Options From f4cc3b8ee6964cd32bbc8003e846cfd93cc3ed27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bert?= <63123542+m-bert@users.noreply.github.com> Date: Thu, 14 Dec 2023 16:33:01 +0100 Subject: [PATCH 05/54] Add explanation for `isWindowAvailable` in `DOMUtils.ts` (#5500) ## Summary Add explanation for using `isWindowAvailable` inside `DOMUtils.ts`. We need this check because without it SSR crashes. ## Test plan yolo --- src/reanimated2/layoutReanimation/web/domUtils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/reanimated2/layoutReanimation/web/domUtils.ts b/src/reanimated2/layoutReanimation/web/domUtils.ts index 9ec63f81b43..72de2439a6b 100644 --- a/src/reanimated2/layoutReanimation/web/domUtils.ts +++ b/src/reanimated2/layoutReanimation/web/domUtils.ts @@ -17,7 +17,7 @@ const animationNameList: string[] = []; */ export function configureWebLayoutAnimations() { if ( - !isWindowAvailable() || + !isWindowAvailable() || // Without this check SSR crashes because document is undefined (NextExample on CI) document.getElementById(PREDEFINED_WEB_ANIMATIONS_ID) !== null ) { return; @@ -49,6 +49,7 @@ export function configureWebLayoutAnimations() { } export function insertWebAnimation(animationName: string, keyframe: string) { + // Without this check SSR crashes because document is undefined (NextExample on CI) if (!isWindowAvailable()) { return; } @@ -81,6 +82,7 @@ export function insertWebAnimation(animationName: string, keyframe: string) { } function removeWebAnimation(animationName: string) { + // Without this check SSR crashes because document is undefined (NextExample on CI) if (!isWindowAvailable()) { return; } From c5bf052050f0c926d65f85c9566251d683000848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20=C5=BBelawski?= <40713406+tjzel@users.noreply.github.com> Date: Thu, 14 Dec 2023 16:46:19 +0100 Subject: [PATCH 06/54] Improve TS in src [0/6] - Allow non-null assertion and remove some eslint directives (#5481) ## Summary Non-null assertions are considered to be a bad practice - however this is in regard to pure TypeScript code. This is not the case in Reanimated, since we have to deal with multiple platforms and multiple threads. Therefore sometimes we know that a value is defined, without a need for unnecessary checks for `undefined` or `null` - and non-null assertions are very handy there, since they are very short. Also, using `?` operator instead of TS `!` could lead to unexpected behavior that could be hard to understand. Consider the following example: ```TS function dispatchCommandPaper( animatedRef: AnimatedRef, commandName: string, args: Array = [] ) { 'worklet'; if (!_WORKLET) { return; } const viewTag = animatedRef() as number; // TS error - _dispatchCommandPaper is not defined _dispatchCommandPaper(viewTag, commandName, args); } ``` We get a TS error even though we are sure that `_dispatchCommandPaper` is defined - `dispatchCommandPaper` is only used on Paper and `_dispatchCommandPaper` is injected there. However, if we changed it to: ```TS _dispatchCommandPaper?(viewTag, commandName, args); ``` And something would go so wrong that `_dispatchCommandPaper` would actually be undefined this function would silently fail instead of throwing with a meaningful stacktrace. ## Test plan TS tests are sufficient for this. Co-authored by: @marmor157. --- .eslintrc.js | 1 + .../InlinePropManager.ts | 3 -- .../createAnimatedComponent.tsx | 5 --- src/reanimated2/PropAdapters.ts | 1 - src/reanimated2/UpdateProps.ts | 3 -- src/reanimated2/hook/useDerivedValue.ts | 3 +- src/reanimated2/hook/utils.ts | 11 ++++--- .../animationBuilder/Keyframe.ts | 19 +++++------ .../defaultTransitions/EntryExitTransition.ts | 8 +---- .../layoutReanimation/web/componentUtils.ts | 33 +++++++------------ 10 files changed, 30 insertions(+), 57 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 0184b9598ac..b4845edcf51 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -60,5 +60,6 @@ module.exports = { { fixMixedExportsWithInlineTypeSpecifier: false }, ], 'tsdoc/syntax': 'error', + '@typescript-eslint/no-non-null-assertion': 'off', }, }; diff --git a/src/createAnimatedComponent/InlinePropManager.ts b/src/createAnimatedComponent/InlinePropManager.ts index 993c9d1708c..1bf1884eebf 100644 --- a/src/createAnimatedComponent/InlinePropManager.ts +++ b/src/createAnimatedComponent/InlinePropManager.ts @@ -153,11 +153,8 @@ export class InlinePropManager implements IInlinePropManager { } this._inlinePropsViewDescriptors.add({ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion tag: viewTag as number, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion name: viewName!, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion shadowNodeWrapper: shadowNodeWrapper!, }); } diff --git a/src/createAnimatedComponent/createAnimatedComponent.tsx b/src/createAnimatedComponent/createAnimatedComponent.tsx index 67ed725ac83..74c819e2173 100644 --- a/src/createAnimatedComponent/createAnimatedComponent.tsx +++ b/src/createAnimatedComponent/createAnimatedComponent.tsx @@ -296,10 +296,8 @@ export function createAnimatedComponent( _updateFromNative(props: StyleProps) { if (options?.setNativeProps) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion options.setNativeProps(this._component as AnimatedComponentRef, props); } else { - // eslint-disable-next-line no-unused-expressions (this._component as AnimatedComponentRef)?.setNativeProps?.(props); } } @@ -428,11 +426,8 @@ export function createAnimatedComponent( // attach animatedProps property if (this.props.animatedProps?.viewDescriptors) { this.props.animatedProps.viewDescriptors.add({ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion tag: viewTag as number, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion name: viewName!, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion shadowNodeWrapper: shadowNodeWrapper!, }); } diff --git a/src/reanimated2/PropAdapters.ts b/src/reanimated2/PropAdapters.ts index 05950f0ac82..4c8e0f9af0e 100644 --- a/src/reanimated2/PropAdapters.ts +++ b/src/reanimated2/PropAdapters.ts @@ -14,7 +14,6 @@ export const createAnimatedPropAdapter = (( nativeProps?: string[] ): __AdapterWorkletFunction => { const nativePropsToAdd: { [key: string]: boolean } = {}; - // eslint-disable-next-line no-unused-expressions nativeProps?.forEach((prop) => { nativePropsToAdd[prop] = true; }); diff --git a/src/reanimated2/UpdateProps.ts b/src/reanimated2/UpdateProps.ts index 597c153cfc9..2a9b17d79d4 100644 --- a/src/reanimated2/UpdateProps.ts +++ b/src/reanimated2/UpdateProps.ts @@ -29,7 +29,6 @@ if (shouldBeUseWeb()) { updateProps = (viewDescriptors, updates) => { 'worklet'; processColorsInProps(updates); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion global.UpdatePropsManager!.update(viewDescriptors, updates); }; } @@ -78,7 +77,6 @@ const createUpdatePropsManager = isFabric() }); }, flush() { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion _updatePropsFabric!(operations); operations.length = 0; }, @@ -109,7 +107,6 @@ const createUpdatePropsManager = isFabric() }); }, flush() { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion _updatePropsPaper!(operations); operations.length = 0; }, diff --git a/src/reanimated2/hook/useDerivedValue.ts b/src/reanimated2/hook/useDerivedValue.ts index fd834e5ef64..adbed7f7590 100644 --- a/src/reanimated2/hook/useDerivedValue.ts +++ b/src/reanimated2/hook/useDerivedValue.ts @@ -46,8 +46,7 @@ export function useDerivedValue( initRef.current = makeMutable(initialUpdaterRun(updater)); } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const sharedValue: SharedValue = initRef.current!; + const sharedValue: SharedValue = initRef.current; useEffect(() => { const fun = () => { diff --git a/src/reanimated2/hook/utils.ts b/src/reanimated2/hook/utils.ts index 2f8a81e2c40..5aac98d5738 100644 --- a/src/reanimated2/hook/utils.ts +++ b/src/reanimated2/hook/utils.ts @@ -42,8 +42,10 @@ export function areDependenciesEqual( prevDeps: DependencyList ) { function is(x: number, y: number) { - // eslint-disable-next-line no-self-compare - return (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y); + return ( + (x === y && (x !== 0 || 1 / x === 1 / y)) || + (Number.isNaN(x) && Number.isNaN(y)) + ); } const objectIs: (nextDeps: unknown, prevDeps: unknown) => boolean = typeof Object.is === 'function' ? Object.is : is; @@ -83,8 +85,9 @@ export function isAnimated(prop: unknown) { // This function works because `Object.keys` // return empty array of primitives and on arrays // it returns array of its indices. -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function shallowEqual(a: any, b: any) { +export function shallowEqual< + T extends Record +>(a: T, b: T) { 'worklet'; const aKeys = Object.keys(a); const bKeys = Object.keys(b); diff --git a/src/reanimated2/layoutReanimation/animationBuilder/Keyframe.ts b/src/reanimated2/layoutReanimation/animationBuilder/Keyframe.ts index dec880a488c..a86fb1149dd 100644 --- a/src/reanimated2/layoutReanimation/animationBuilder/Keyframe.ts +++ b/src/reanimated2/layoutReanimation/animationBuilder/Keyframe.ts @@ -159,16 +159,14 @@ class InnerKeyframe implements IEntryExitAnimationBuilder { if (!Array.isArray(keyframe.transform)) { return; } - keyframe.transform.forEach( - (transformStyle: { [key: string]: any }, index) => { - Object.keys(transformStyle).forEach((transformProp: string) => { - addKeyPointWith( - makeKeyframeKey(index, transformProp), - transformStyle[transformProp] - ); - }); - } - ); + keyframe.transform.forEach((transformStyle, index) => { + Object.keys(transformStyle).forEach((transformProp: string) => { + addKeyPointWith( + makeKeyframeKey(index, transformProp), + transformStyle[transformProp as keyof typeof transformStyle] + ); + }); + }); } else { addKeyPointWith(key, keyframe[key]); } @@ -256,7 +254,6 @@ class InnerKeyframe implements IEntryExitAnimationBuilder { if (!('transform' in animations)) { animations.transform = []; } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion animations.transform!.push({ [key.split(':')[1]]: animation, }); diff --git a/src/reanimated2/layoutReanimation/defaultTransitions/EntryExitTransition.ts b/src/reanimated2/layoutReanimation/defaultTransitions/EntryExitTransition.ts index 45d1ae3be9e..8cd5a3c6cf2 100644 --- a/src/reanimated2/layoutReanimation/defaultTransitions/EntryExitTransition.ts +++ b/src/reanimated2/layoutReanimation/defaultTransitions/EntryExitTransition.ts @@ -78,7 +78,6 @@ export class EntryExitTransition } exitingValues.animations.transform.forEach((value, index) => { for (const transformProp of Object.keys(value)) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion animations.transform!.push({ [transformProp]: delayFunction( delay, @@ -135,16 +134,13 @@ export class EntryExitTransition } enteringValues.animations.transform.forEach((value, index) => { for (const transformProp of Object.keys(value)) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion animations.transform!.push({ [transformProp]: delayFunction( delay + exitingDuration, withSequence( withTiming( enteringValues.initialValues.transform - ? // TODO TYPESCRIPT - // @ts-ignore Read similar comment above. - enteringValues.initialValues.transform[index][ + ? enteringValues.initialValues.transform[index][ transformProp as keyof TransformArrayItem ] : 0, @@ -175,8 +171,6 @@ export class EntryExitTransition ? exitingValues.initialValues.transform : [] ).concat( - // TODO TYPESCRIPT - // @ts-ignore Read similar comment above. (Array.isArray(enteringValues.animations.transform) ? enteringValues.animations.transform : [] diff --git a/src/reanimated2/layoutReanimation/web/componentUtils.ts b/src/reanimated2/layoutReanimation/web/componentUtils.ts index a7eeafea84d..dc77f034cc7 100644 --- a/src/reanimated2/layoutReanimation/web/componentUtils.ts +++ b/src/reanimated2/layoutReanimation/web/componentUtils.ts @@ -17,20 +17,16 @@ import { _updatePropsJS } from '../../js-reanimated'; import type { ReanimatedHTMLElement } from '../../js-reanimated'; import { ReduceMotion } from '../../commonTypes'; import type { StyleProps } from '../../commonTypes'; -import { useReducedMotion } from '../../hook/useReducedMotion'; +import { isReducedMotion } from '../../PlatformChecker'; import { LayoutAnimationType } from '../animationBuilder/commonTypes'; -const snapshots = new WeakMap(); +const snapshots = new WeakMap(); function getEasingFromConfig(config: CustomConfig): string { - const easingName = ( - config.easingV !== undefined && - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - config.easingV!.name in WebEasings - ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - config.easingV!.name - : 'linear' - ) as WebEasingsNames; + const easingName = + config.easingV && config.easingV.name in WebEasings + ? (config.easingV.name as WebEasingsNames) + : 'linear'; return `cubic-bezier(${WebEasings[easingName].toString()})`; } @@ -50,14 +46,12 @@ function getDelayFromConfig(config: CustomConfig): number { return shouldRandomizeDelay ? getRandomDelay(config.delayV) - : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - config.delayV! / 1000; + : config.delayV / 1000; } export function getReducedMotionFromConfig(config: CustomConfig) { if (!config.reduceMotionV) { - // eslint-disable-next-line react-hooks/rules-of-hooks - return useReducedMotion(); + return isReducedMotion(); } switch (config.reduceMotionV) { @@ -66,8 +60,7 @@ export function getReducedMotionFromConfig(config: CustomConfig) { case ReduceMotion.Always: return true; default: - // eslint-disable-next-line react-hooks/rules-of-hooks - return useReducedMotion(); + return isReducedMotion(); } } @@ -81,14 +74,12 @@ function getDurationFromConfig( : Animations[animationName].duration; return config.durationV !== undefined - ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - config.durationV! / 1000 + ? config.durationV / 1000 : defaultDuration; } function getCallbackFromConfig(config: CustomConfig): AnimationCallback { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return config.callbackV !== undefined ? config.callbackV! : null; + return config.callbackV !== undefined ? config.callbackV : null; } function getReversedFromConfig(config: CustomConfig) { @@ -307,7 +298,7 @@ export function handleExitingAnimation( setElementAnimation(dummy, animationConfig); parent?.appendChild(dummy); - const snapshot = snapshots.get(element); + const snapshot = snapshots.get(element)!; setDummyPosition(dummy, snapshot); From d3ebe775c3bda7a0dcdbaf309e985e7481bdb943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20=C5=BBelawski?= <40713406+tjzel@users.noreply.github.com> Date: Fri, 15 Dec 2023 18:37:43 +0100 Subject: [PATCH 07/54] Improve TS in src [1/6] - Remove unused overloads (#5482) ## Summary Currently worklets RGBtoHSV and HSVtoRGB are overloaded so they either accept 3 arguments or 1 argument that has 3 properties. However, we only use the first case so removing those overloads simplifies the code. ## Test plan See that object overload is not used. Co-authored by: @marmor157. --- src/reanimated2/Colors.ts | 80 +++++++++++++++------------------------ 1 file changed, 30 insertions(+), 50 deletions(-) diff --git a/src/reanimated2/Colors.ts b/src/reanimated2/Colors.ts index 2375bfc8e77..78874ef94ca 100644 --- a/src/reanimated2/Colors.ts +++ b/src/reanimated2/Colors.ts @@ -453,36 +453,25 @@ export const rgbaColor = ( return c; }; -/* accepts parameters - * r Object = {r:x, g:y, b:z} - * OR - * r, g, b - * 0 <= r, g, b <= 255 - * returns 0 <= h, s, v <= 1 +/** + * + * @param r - red value (0-255) + * @param g - green value (0-255) + * @param b - blue value (0-255) + * @returns \{h: hue (0-1), s: saturation (0-1), v: value (0-1)\} */ -export function RGBtoHSV(rgb: RGB): HSV; -export function RGBtoHSV(r: number, g: number, b: number): HSV; -export function RGBtoHSV(r: any, g?: any, b?: any): HSV { +export function RGBtoHSV(r: number, g: number, b: number): HSV { 'worklet'; - /* eslint-disable */ - if (arguments.length === 1) { - g = r.g; - b = r.b; - r = r.r; - } const max = Math.max(r, g, b); const min = Math.min(r, g, b); const d = max - min; const s = max === 0 ? 0 : d / max; const v = max / 255; - let h; + let h = 0; switch (max) { - default: - /* fallthrough */ case min: - h = 0; break; case r: h = g - b + d * (g < b ? 6 : 0); @@ -503,50 +492,42 @@ export function RGBtoHSV(r: any, g?: any, b?: any): HSV { s: s, v: v, }; - /* eslint-enable */ } -/* accepts parameters - * h Object = {h:x, s:y, v:z} - * OR - * h, s, v - * 0 <= h, s, v <= 1 - * returns 0 <= r, g, b <= 255 +/** + * + * @param h - hue (0-1) + * @param s - saturation (0-1) + * @param v - value (0-1) + * @returns \{r: red (0-255), g: green (0-255), b: blue (0-255)\} */ -function HSVtoRGB(hsv: HSV): RGB; -function HSVtoRGB(h: number, s: number, v: number): RGB; -function HSVtoRGB(h: any, s?: any, v?: any) { - 'worklet'; - /* eslint-disable */ - var r, g, b, i, f, p, q, t; - if (arguments.length === 1) { - s = h.s; - v = h.v; - h = h.h; - } - i = Math.floor(h * 6); - f = h * 6 - i; - p = v * (1 - s); - q = v * (1 - f * s); - t = v * (1 - (1 - f) * s); - switch (i % 6) { +function HSVtoRGB(h: number, s: number, v: number): RGB { + ('worklet'); + let r, g, b; + + const i = Math.floor(h * 6); + const f = h * 6 - i; + const p = v * (1 - s); + const q = v * (1 - f * s); + const t = v * (1 - (1 - f) * s); + switch ((i % 6) as 0 | 1 | 2 | 3 | 4 | 5) { case 0: - (r = v), (g = t), (b = p); + [r, g, b] = [v, t, p]; break; case 1: - (r = q), (g = v), (b = p); + [r, g, b] = [q, v, p]; break; case 2: - (r = p), (g = v), (b = t); + [r, g, b] = [p, v, t]; break; case 3: - (r = p), (g = q), (b = v); + [r, g, b] = [p, q, v]; break; case 4: - (r = t), (g = p), (b = v); + [r, g, b] = [t, p, v]; break; case 5: - (r = v), (g = p), (b = q); + [r, g, b] = [v, p, q]; break; } return { @@ -554,7 +535,6 @@ function HSVtoRGB(h: any, s?: any, v?: any) { g: Math.round(g * 255), b: Math.round(b * 255), }; - /* eslint-enable */ } export const hsvToColor = ( From 97975168ed383ac17671e938df057ff087b726d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20=C5=BBelawski?= <40713406+tjzel@users.noreply.github.com> Date: Sun, 17 Dec 2023 17:22:09 +0100 Subject: [PATCH 08/54] Fix peer dependency in root (#5501) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🐓 --- package.json | 6 +- src/reanimated2/mock.ts | 2 +- yarn.lock | 281 ++++++++++++++++++++++++---------------- 3 files changed, 172 insertions(+), 117 deletions(-) diff --git a/package.json b/package.json index f3a5e3d822f..5016de3a76d 100644 --- a/package.json +++ b/package.json @@ -138,14 +138,14 @@ "babel-plugin-module-resolver": "^5.0.0", "clang-format": "^1.6.0", "code-tag": "^1.1.0", - "eslint": "^8.44.0", + "eslint": "^8.55.0", "eslint-config-prettier": "^8.3.0", - "eslint-config-standard": "^16.0.3", + "eslint-config-standard": "^17.1.0", "eslint-import-resolver-babel-module": "^5.3.1", "eslint-plugin-import": "^2.25.4", "eslint-plugin-jest": "^27.2.1", + "eslint-plugin-n": "^16.4.0", "eslint-plugin-no-inline-styles": "^1.0.5", - "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^6.0.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-standard": "^5.0.0", diff --git a/src/reanimated2/mock.ts b/src/reanimated2/mock.ts index c3cd9ff6499..697c5d75f7e 100644 --- a/src/reanimated2/mock.ts +++ b/src/reanimated2/mock.ts @@ -1,4 +1,4 @@ -/* eslint-disable node/no-callback-literal */ +/* eslint-disable n/no-callback-literal */ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck 'use strict'; diff --git a/yarn.lock b/yarn.lock index fbcb454506d..db465b58255 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1223,22 +1223,22 @@ dependencies: "@types/hammerjs" "^2.0.36" -"@eslint-community/eslint-utils@^4.2.0": +"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.4.0": - version "4.5.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.0.tgz#f6f729b02feee2c749f57e334b7a1b5f40a81724" - integrity sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ== +"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.0", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== -"@eslint/eslintrc@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.0.tgz#82256f164cc9e0b59669efc19d57f8092706841d" - integrity sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A== +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -1250,10 +1250,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.44.0": - version "8.44.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.44.0.tgz#961a5903c74139390478bdc808bcde3fc45ab7af" - integrity sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw== +"@eslint/js@8.55.0": + version "8.55.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.55.0.tgz#b721d52060f369aa259cf97392403cb9ce892ec6" + integrity sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA== "@hapi/hoek@^9.0.0": version "9.3.0" @@ -1267,12 +1267,12 @@ dependencies: "@hapi/hoek" "^9.0.0" -"@humanwhocodes/config-array@^0.11.10": - version "0.11.10" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" - integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" + "@humanwhocodes/object-schema" "^2.0.1" debug "^4.1.1" minimatch "^3.0.5" @@ -1281,10 +1281,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" @@ -2228,6 +2228,11 @@ "@typescript-eslint/types" "5.59.1" eslint-visitor-keys "^3.3.0" +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -2254,9 +2259,9 @@ acorn@^8.5.0: integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + version "8.11.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" + integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== aggregate-error@^3.0.0: version "3.1.0" @@ -2266,7 +2271,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.10.0, ajv@^6.12.4, ajv@~6.12.6: +ajv@^6.12.4, ajv@~6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2742,6 +2747,18 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + +builtins@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" + integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + dependencies: + semver "^7.0.0" + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -3543,15 +3560,20 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" +eslint-compat-utils@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz#f45e3b5ced4c746c127cf724fb074cd4e730d653" + integrity sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg== + eslint-config-prettier@^8.3.0, eslint-config-prettier@^8.5.0: version "8.8.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348" integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== -eslint-config-standard@^16.0.3: - version "16.0.3" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz#6c8761e544e96c531ff92642eeb87842b8488516" - integrity sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg== +eslint-config-standard@^17.1.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz#40ffb8595d47a6b242e07cbfd49dc211ed128975" + integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== eslint-import-resolver-babel-module@^5.3.1: version "5.3.2" @@ -3577,13 +3599,14 @@ eslint-module-utils@^2.7.4: dependencies: debug "^3.2.7" -eslint-plugin-es@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" - integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== +eslint-plugin-es-x@^7.5.0: + version "7.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz#d08d9cd155383e35156c48f736eb06561d07ba92" + integrity sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ== dependencies: - eslint-utils "^2.0.0" - regexpp "^3.0.0" + "@eslint-community/eslint-utils" "^4.1.2" + "@eslint-community/regexpp" "^4.6.0" + eslint-compat-utils "^0.1.2" eslint-plugin-eslint-comments@^3.2.0: version "3.2.0" @@ -3636,6 +3659,22 @@ eslint-plugin-jest@^27.2.1: dependencies: "@typescript-eslint/utils" "^5.10.0" +eslint-plugin-n@^16.4.0: + version "16.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-16.4.0.tgz#02ff70d2b164319b6d566672969a9c24688a43df" + integrity sha512-IkqJjGoWYGskVaJA7WQuN8PINIxc0N/Pk/jLeYT4ees6Fo5lAhpwGsYek6gS9tCUxgDC4zJ+OwY2bY/6/9OMKQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + builtins "^5.0.1" + eslint-plugin-es-x "^7.5.0" + get-tsconfig "^4.7.0" + ignore "^5.2.4" + is-builtin-module "^3.2.1" + is-core-module "^2.12.1" + minimatch "^3.1.2" + resolve "^1.22.2" + semver "^7.5.3" + eslint-plugin-no-inline-styles@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/eslint-plugin-no-inline-styles/-/eslint-plugin-no-inline-styles-1.0.5.tgz#c37a7e7a53b46312852d2c44c02cac0df2e700c3" @@ -3643,18 +3682,6 @@ eslint-plugin-no-inline-styles@^1.0.5: dependencies: lodash.get "^4.4.2" -eslint-plugin-node@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" - integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== - dependencies: - eslint-plugin-es "^3.0.0" - eslint-utils "^2.0.0" - ignore "^5.1.1" - minimatch "^3.0.4" - resolve "^1.10.1" - semver "^6.1.0" - eslint-plugin-prettier@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" @@ -3727,22 +3754,15 @@ eslint-scope@5.1.1, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b" - integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: +eslint-visitor-keys@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== @@ -3752,37 +3772,33 @@ eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.3.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz#c7f0f956124ce677047ddbc192a68f999454dedc" - integrity sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ== - -eslint-visitor-keys@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" - integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.44.0: - version "8.44.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.44.0.tgz#51246e3889b259bbcd1d7d736a0c10add4f0e500" - integrity sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A== +eslint@^8.55.0: + version "8.55.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.55.0.tgz#078cb7b847d66f2c254ea1794fa395bf8e7e03f8" + integrity sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.4.0" - "@eslint/eslintrc" "^2.1.0" - "@eslint/js" "8.44.0" - "@humanwhocodes/config-array" "^0.11.10" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.55.0" + "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - ajv "^6.10.0" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.0" - eslint-visitor-keys "^3.4.1" - espree "^9.6.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -3792,7 +3808,6 @@ eslint@^8.44.0: globals "^13.19.0" graphemer "^1.4.0" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" @@ -3804,13 +3819,12 @@ eslint@^8.44.0: natural-compare "^1.4.0" optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" -espree@^9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.0.tgz#80869754b1c6560f32e3b6929194a3fe07c5b82f" - integrity sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: acorn "^8.9.0" acorn-jsx "^5.3.2" @@ -4079,17 +4093,18 @@ find-up@^5.0.0: path-exists "^4.0.0" flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: - flatted "^3.1.0" + flatted "^3.2.9" + keyv "^4.5.3" rimraf "^3.0.2" -flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== +flatted@^3.2.9: + version "3.2.9" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== flatten@^1.0.2: version "1.0.3" @@ -4252,6 +4267,13 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" +get-tsconfig@^4.7.0: + version "4.7.2" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" + integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== + dependencies: + resolve-pkg-maps "^1.0.0" + glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -4295,9 +4317,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.19.0: - version "13.20.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" @@ -4476,11 +4498,16 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.0.5, ignore@^5.1.1, ignore@^5.2.0: +ignore@^5.0.5: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +ignore@^5.2.0, ignore@^5.2.4: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" + integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== + image-size@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.0.2.tgz#d778b6d0ab75b2737c1556dd631652eb963bc486" @@ -4496,7 +4523,7 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" -import-fresh@^3.0.0, import-fresh@^3.2.1: +import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -4623,12 +4650,19 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.1.0: +is-core-module@^2.1.0, is-core-module@^2.12.1, is-core-module@^2.13.0: version "2.13.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== @@ -5405,6 +5439,11 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -5461,6 +5500,13 @@ jsonfile@^6.0.1: array-includes "^3.1.5" object.assign "^4.1.3" +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kind-of@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -6630,9 +6676,9 @@ pump@^3.0.0: once "^1.3.1" punycode@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== pure-rand@^6.0.0: version "6.0.2" @@ -6917,11 +6963,6 @@ regexp.prototype.flags@^1.4.3: define-properties "^1.2.0" functions-have-names "^1.2.3" -regexpp@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - regexpu-core@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" @@ -6996,12 +7037,17 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + resolve.exports@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.1.6, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.21.0, resolve@^1.22.1: +resolve@^1.1.6, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.21.0, resolve@^1.22.1: version "1.22.2" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== @@ -7010,6 +7056,15 @@ resolve@^1.1.6, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.20 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.2: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + resolve@^2.0.0-next.4: version "2.0.0-next.4" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" @@ -7124,12 +7179,12 @@ semver@^5.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.5, semver@^7.3.7, semver@^7.5.2: +semver@^7.0.0, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -7471,7 +7526,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== From a083ef3161ec7fb0f2b94d8cd9882c91c9f5e09e Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Mon, 18 Dec 2023 18:45:00 +0100 Subject: [PATCH 09/54] Update versions in issue template (#5507) ## Summary ## Test plan --- .github/ISSUE_TEMPLATE/bug-report.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 5d7e3d09f02..5ac4a0f74b1 100755 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -57,7 +57,7 @@ body: attributes: label: Reanimated version description: What version of react-native-reanimated are you using? - placeholder: 2.9.0 + placeholder: 3.6.1 validations: required: true @@ -66,7 +66,7 @@ body: attributes: label: React Native version description: What version of react-native are you using? - placeholder: 0.69.0 + placeholder: 0.73.1 validations: required: true From 96d8426461e98440d62f6da06442e8ab6bdfdbc7 Mon Sep 17 00:00:00 2001 From: Abhishek <44975760+azashi@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:55:49 +0530 Subject: [PATCH 10/54] Layout-transition docs - Empty brackets removed (#5502) ## Summary Layout transition docs had empty brackets, which are removed in this PR ## Test plan --- docs/docs/layout-animations/layout-transitions.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/docs/layout-animations/layout-transitions.mdx b/docs/docs/layout-animations/layout-transitions.mdx index e88b2257ca9..5c239b17c23 100644 --- a/docs/docs/layout-animations/layout-transitions.mdx +++ b/docs/docs/layout-animations/layout-transitions.mdx @@ -108,8 +108,6 @@ Fading transition, animates the opacity of component, so it will disappear with #### Example -{" "} -

Type definitions ```typescript -type SharedValue = { value: T }; +interface SharedValue { + value: Value; + addListener: (listenerID: number, listener: (value: Value) => void) => void; + removeListener: (listenerID: number) => void; + modify: ( + modifier?: (value: T) => T, + forceUpdate?: boolean + ) => void; +} -function useSharedValue(initialValue: T): SharedValue; +function useSharedValue( + initialValue: Value, + oneWayReadsOnly?: boolean +): SharedValue; ``` diff --git a/src/createAnimatedComponent/PropsFilter.tsx b/src/createAnimatedComponent/PropsFilter.tsx index 2ac804924f4..23a831ab2d7 100644 --- a/src/createAnimatedComponent/PropsFilter.tsx +++ b/src/createAnimatedComponent/PropsFilter.tsx @@ -1,5 +1,5 @@ 'use strict'; -import type { StyleProps, SharedValue } from '../reanimated2'; +import type { StyleProps } from '../reanimated2'; import { isSharedValue } from '../reanimated2'; import { isChromeDebugger } from '../reanimated2/PlatformChecker'; import WorkletEventHandler from '../reanimated2/WorkletEventHandler'; @@ -78,7 +78,7 @@ export class PropsFilter implements IPropsFilter { } } else if (isSharedValue(value)) { if (component._isFirstRender) { - props[key] = (value as SharedValue).value; + props[key] = value.value; } } else if (key !== 'onGestureHandlerStateChange' || !isChromeDebugger()) { props[key] = value; diff --git a/src/reanimated2/ViewDescriptorsSet.ts b/src/reanimated2/ViewDescriptorsSet.ts index 277217f1c16..392d7eba12a 100644 --- a/src/reanimated2/ViewDescriptorsSet.ts +++ b/src/reanimated2/ViewDescriptorsSet.ts @@ -21,7 +21,7 @@ export function makeViewDescriptorsSet(): ViewDescriptorsSet { const data: ViewDescriptorsSet = { shareableViewDescriptors, add: (item: Descriptor) => { - shareableViewDescriptors.modify((descriptors: Descriptor[]) => { + shareableViewDescriptors.modify((descriptors) => { 'worklet'; const index = descriptors.findIndex( (descriptor) => descriptor.tag === item.tag @@ -36,7 +36,7 @@ export function makeViewDescriptorsSet(): ViewDescriptorsSet { }, remove: (viewTag: number) => { - shareableViewDescriptors.modify((descriptors: Descriptor[]) => { + shareableViewDescriptors.modify((descriptors) => { 'worklet'; const index = descriptors.findIndex( (descriptor) => descriptor.tag === viewTag diff --git a/src/reanimated2/commonTypes.ts b/src/reanimated2/commonTypes.ts index d7986541edf..8b1affa225f 100644 --- a/src/reanimated2/commonTypes.ts +++ b/src/reanimated2/commonTypes.ts @@ -13,11 +13,14 @@ export interface StyleProps extends ViewStyle, TextStyle { * * Shared values are defined using [useSharedValue](https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue) hook. You access and modify shared values by their `.value` property. */ -export interface SharedValue { +export interface SharedValue { value: Value; - addListener: (listenerID: number, listener: (value: any) => void) => void; + addListener: (listenerID: number, listener: (value: Value) => void) => void; removeListener: (listenerID: number) => void; - modify: (modifier?: (value: any) => any, forceUpdate?: boolean) => void; + modify: ( + modifier?: (value: T) => T, + forceUpdate?: boolean + ) => void; } // The below type is used for HostObjects returned by the JSI API that don't have @@ -27,7 +30,7 @@ export interface SharedValue { // check other methods that may use them. However, this field is not actually defined // nor should be used for anything else as assigning any data to those objects will // throw an error. -export type ShareableRef = { +export type ShareableRef = { __hostObjectShareableJSRef: T; }; diff --git a/src/reanimated2/isSharedValue.ts b/src/reanimated2/isSharedValue.ts index b57925150c9..4ef6f7f1485 100644 --- a/src/reanimated2/isSharedValue.ts +++ b/src/reanimated2/isSharedValue.ts @@ -1,7 +1,10 @@ 'use strict'; import type { SharedValue } from './commonTypes'; -export function isSharedValue(value: any): value is SharedValue { +export function isSharedValue( + value: unknown +): value is SharedValue { 'worklet'; - return value?._isReanimatedSharedValue === true; + // We cannot use `in` operator here because `value` could be a HostObject and therefore we cast. + return (value as Record)?._isReanimatedSharedValue === true; } diff --git a/src/reanimated2/shareables.ts b/src/reanimated2/shareables.ts index ad04964d177..0e8163d606f 100644 --- a/src/reanimated2/shareables.ts +++ b/src/reanimated2/shareables.ts @@ -15,10 +15,7 @@ import { jsVersion } from './platform-specific/jsVersion'; // runnning the code on separate VMs. const USE_STUB_IMPLEMENTATION = shouldBeUseWeb(); -const _shareableCache = new WeakMap< - Record, - ShareableRef | symbol ->(); +const _shareableCache = new WeakMap(); // the below symbol is used to represent a mapping from the value to itself // this is used to allow for a converted shareable to be passed to makeShareableClone const _shareableFlag = Symbol('shareable flag'); @@ -35,8 +32,8 @@ function isHostObject(value: NonNullable) { } export function registerShareableMapping( - shareable: any, - shareableRef?: ShareableRef + shareable: object, + shareableRef?: ShareableRef ): void { if (USE_STUB_IMPLEMENTATION) { return; @@ -44,7 +41,7 @@ export function registerShareableMapping( _shareableCache.set(shareable, shareableRef || _shareableFlag); } -function isPlainJSObject(object: object) { +function isPlainJSObject(object: object): object is object { return Object.getPrototypeOf(object) === Object.prototype; } @@ -61,7 +58,7 @@ const INACCESSIBLE_OBJECT = { return new Proxy( {}, { - get: (_: any, prop: string | symbol) => { + get: (_: unknown, prop: string | symbol) => { if ( prop === '_isReanimatedSharedValue' || prop === '__remoteFunction' @@ -351,7 +348,7 @@ export function makeShareableCloneOnUIRecursive( return cloneRecursive(value); } -export function makeShareable(value: T): T { +export function makeShareable(value: T): T { if (USE_STUB_IMPLEMENTATION) { return value; } From ea5c667cea87a673452a5224ee304a5ee81edb6d Mon Sep 17 00:00:00 2001 From: Alex Cynk Date: Thu, 21 Dec 2023 12:52:14 +0100 Subject: [PATCH 18/54] Add `withClamp` documentation (#5381) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Add documentation of withClamp animation modifier ### Interactive playround |☀️|🌙| |--|--| |image|image| ## Test plan --------- Co-authored-by: Aleksandra Cynk Co-authored-by: Kacper Kapuściak <39658211+kacperkapusciak@users.noreply.github.com> Co-authored-by: Tomasz Żelawski <40713406+tjzel@users.noreply.github.com> Co-authored-by: Krzysztof Piaskowy Co-authored-by: Tomek Zawadzki Co-authored-by: Gabriel Donadel Dall'Agnol Co-authored-by: Tomek Zawadzki Co-authored-by: Bartłomiej Błoniarz <56109050+bartlomiejbloniarz@users.noreply.github.com> Co-authored-by: Ugurcan Emre Atas <22047299+ugurcanatas@users.noreply.github.com> Co-authored-by: Uğurcan Emre Ataş Co-authored-by: Michał Bert <63123542+m-bert@users.noreply.github.com> Co-authored-by: Michał Bert Co-authored-by: Mariusz Morawski Co-authored-by: Hamzat Victor Oluwabori <63613078+Code-Victor@users.noreply.github.com> Co-authored-by: Michael Wood Co-authored-by: Amadeus Demarzi Co-authored-by: Tomasz Żelawski --- docs/docs/animations/withClamp.mdx | 81 +++++++++ docs/package.json | 2 +- .../InteractivePlayground/index.tsx | 64 +++++++ .../useClampPlayground/Example.tsx | 169 ++++++++++++++++++ .../useClampPlayground/index.tsx | 53 ++++++ docs/src/theme/DocSidebarItems/index.js | 7 +- docs/yarn.lock | 8 +- 7 files changed, 374 insertions(+), 10 deletions(-) create mode 100644 docs/docs/animations/withClamp.mdx create mode 100644 docs/src/components/InteractivePlayground/useClampPlayground/Example.tsx create mode 100644 docs/src/components/InteractivePlayground/useClampPlayground/index.tsx diff --git a/docs/docs/animations/withClamp.mdx b/docs/docs/animations/withClamp.mdx new file mode 100644 index 00000000000..8ed3778ca10 --- /dev/null +++ b/docs/docs/animations/withClamp.mdx @@ -0,0 +1,81 @@ +--- +sidebar_position: 7 +--- + +# withClamp + +`withClamp` is an [animation modifier](/docs/fundamentals/glossary#animation-modifier) that lets you limit the scope of movement of your animation to make it stay within some predefined range. +Use it with [withSpring](/docs/animations/withSpring) animation. + +import { useClampPlayground } from '@site/src/components/InteractivePlayground'; + + + +## Reference + +```javascript +import { withClamp } from 'react-native-reanimated'; + +function App() { + sv.value = withClamp({ min: -1, max: 1 }, withSpring(0)); + // ... +} +``` + +
+Type definitions + +```typescript +type AnimatableValue = number | string | number[]; + +function withClamp( + config: { + min?: T; + max?: T; + }, + clampedAnimation: T +): T; + +enum ReduceMotion { + System = 'system', + Always = 'always', + Never = 'never', +} +``` + +
+ +### Arguments + +#### `config` + +An object with following properties: + +| Name | Type Description | +| ---------------- | ---------------- | ------------------------------------------------ | +| min | `number` | The lowest value your animation can ever reach | +| max | `number` | The greatest value your animation can ever reach | + +#### `animation` + +The spring animation you want to clamp. + +```typescript +const clampedStyleWithDelay = useAnimatedStyle(() => { + return { + width: withClamp({ min: 0, max: 100 }, withSpring(randomWidth.value)), + }; +}); +``` + +### Returns + +`withClamp` returns an [animation object](/docs/fundamentals/glossary#animation-object). It can be either assigned directly to a [shared value](/docs/fundamentals/glossary#shared-value) or can be used as a value for a style object returned from [useAnimatedStyle](docs/core/useAnimatedStyle). + +
+ +| Android | iOS | Web | +| ------- | --- | --- | +| ✅ | ✅ | ✅ | + +
diff --git a/docs/package.json b/docs/package.json index 4c4390e1865..d5406980e9c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -41,7 +41,7 @@ "react-draggable": "^4.4.5", "react-native": "^0.71.4", "react-native-gesture-handler": "^2.13.2", - "react-native-reanimated": "^3.6.0-nightly-20231010-4a507b2c4", + "react-native-reanimated": "^3.6.0-nightly-20231120-1eb2acaa0", "react-native-svg": "^13.14.0", "react-native-web": "^0.18.12", "source-map": "^0.7.4", diff --git a/docs/src/components/InteractivePlayground/index.tsx b/docs/src/components/InteractivePlayground/index.tsx index 27272de154b..ac025e77a36 100644 --- a/docs/src/components/InteractivePlayground/index.tsx +++ b/docs/src/components/InteractivePlayground/index.tsx @@ -5,6 +5,7 @@ import styles from './styles.module.css'; import BrowserOnly from '@docusaurus/BrowserOnly'; import CodeBlock from '@theme/CodeBlock'; +import useClampPlayground from './useClampPlayground'; import useSpringPlayground from './useSpringPlayground'; import useTimingPlayground from './useTimingPlayground'; import useInterpolateColorPlayground from './useInterpolateColorPlayground'; @@ -23,6 +24,7 @@ import { } from '@mui/material'; export { + useClampPlayground, useSpringPlayground, useTimingPlayground, useInterpolateColorPlayground, @@ -99,6 +101,16 @@ interface RangeProps { label: string; } +interface DoubleRangeProps { + min: number; + max: number; + step?: number; + value: [number, number]; + onChange: [Dispatch, Dispatch]; + label: string; + color?: 'yellow' | 'green'; +} + const RangeStyling = { color: 'var(--swm-interactive-slider)', // color of the main path of slider '& .MuiSlider-thumb': { @@ -162,6 +174,58 @@ export function Range({ ); } +export function DoubleRange({ + min, + max, + value, + onChange, + label, + step = 1, + color, +}: DoubleRangeProps) { + return ( + <> +
+ + {[0, 1].map((idx) => { + return ( + { + const newValue = parseFloat(e.target.value); + onChange[idx]( + newValue > max[idx] + ? max[idx] + : newValue <= min[idx] + ? min[idx] + : newValue + ); + }} + /> + ); + })} +
+ { + onChange[0](parseFloat(e.target.value[0])); + onChange[1](parseFloat(e.target.value[1])); + }} + /> + + ); +} + interface CheckboxProps { value: boolean; onChange: Dispatch; diff --git a/docs/src/components/InteractivePlayground/useClampPlayground/Example.tsx b/docs/src/components/InteractivePlayground/useClampPlayground/Example.tsx new file mode 100644 index 00000000000..8a8be363e82 --- /dev/null +++ b/docs/src/components/InteractivePlayground/useClampPlayground/Example.tsx @@ -0,0 +1,169 @@ +import React from 'react'; +import { StyleSheet, View, Text, ViewStyle } from 'react-native'; +import Animated, { + useAnimatedStyle, + withClamp, + withSpring, + withRepeat, + withSequence, + withTiming, + withDelay, +} from 'react-native-reanimated'; + +const BOX_START = 0; +const BOX_STOP = 200; +const BOX_SIZE = 80; + +const FRAME_WIDTH = 400; +const FRAME_HEIGHT = 100; +const CLAMP_MARKER_HEIGHT = 40; + +interface ClampPlaygroundOptions { + lowerBound: number; + upperBound: number; +} + +interface Props { + options: ClampPlaygroundOptions; +} +export default function App({ options }: Props) { + const config = { + damping: 3, + }; + + const clampedStyle = useAnimatedStyle(() => { + return { + transform: [ + { + translateX: withClamp( + { min: options.lowerBound, max: options.upperBound }, + withRepeat( + withSequence( + withDelay(2000, withSpring(BOX_STOP, config)), + withTiming(BOX_START, { duration: 0 }) + ), + -1, + true + ) + ), + }, + ], + }; + }); + const defaultStyle = useAnimatedStyle(() => { + return { + transform: [ + { + translateX: withRepeat( + withSequence( + withDelay(2000, withSpring(200, config)), + withTiming(0, { duration: 0 }) + ), + -1, + true + ), + }, + ], + }; + }); + + function Example({ + testedStyle, + description, + showClampMarkers, + }: { + testedStyle: ViewStyle; + description: string; + showClampMarkers: boolean; + }) { + return ( + + + {showClampMarkers && ( + + )} + + + {description} + + + {showClampMarkers && ( + + )} + + + ); + } + + return ( + + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + padding: CLAMP_MARKER_HEIGHT, + paddingBottom: 0, + }, + clampMarker: { + position: 'absolute', + margin: 0, + opacity: 0.5, + height: 100, + borderColor: '#b58df1', + borderStyle: 'dashed', + }, + movingBox: { + height: BOX_SIZE, + width: BOX_SIZE, + borderColor: '#b58df1', + borderRadius: 20, + borderWidth: 1, + alignItems: 'center', + justifyContent: 'center', + }, + text: { + color: '#b58df1', + textTransform: 'uppercase', + fontWeight: 'bold', + textAlign: 'center', + }, +}); diff --git a/docs/src/components/InteractivePlayground/useClampPlayground/index.tsx b/docs/src/components/InteractivePlayground/useClampPlayground/index.tsx new file mode 100644 index 00000000000..137a8f2bbd9 --- /dev/null +++ b/docs/src/components/InteractivePlayground/useClampPlayground/index.tsx @@ -0,0 +1,53 @@ +import React, { useState } from 'react'; +import { DoubleRange } from '..'; +import Example from './Example'; + +const initialState = { + lowerBound: 100, + upperBound: 300, +}; + +export default function useClampPlayground() { + const [lowerBound, setLowerBound] = useState(initialState.lowerBound); + const [upperBound, setUpperBound] = useState(initialState.upperBound); + + const example = ( + + ); + + const controls = ( + + ); + + const resetOptions = () => { + setLowerBound(initialState.lowerBound); + setUpperBound(initialState.upperBound); + }; + + const code = `{ + width: withClamp( + { min: ${lowerBound}, max: ${upperBound} }, + withSpring(width.value) + ), +} +`; + + return { + code, + controls, + example, + resetOptions, + }; +} diff --git a/docs/src/theme/DocSidebarItems/index.js b/docs/src/theme/DocSidebarItems/index.js index 0d424fa9bc0..e41d3986c92 100644 --- a/docs/src/theme/DocSidebarItems/index.js +++ b/docs/src/theme/DocSidebarItems/index.js @@ -5,11 +5,8 @@ import SidebarLabel from '@site/src/components/SidebarLabel'; import styles from './styles.module.css'; const EXPERIMENTAL_APIs = ['shared-element-transitions/overview']; -const NEW_APIS = [ - 'advanced/setNativeProps', - 'threading/createWorkletRuntime', - 'device/useReducedMotion', -]; +const NEW_APIS = ['animations/withClamp']; + // TODO this item should probably not receive the "activePath" props // TODO this triggers whole sidebar re-renders on navigation function DocSidebarItems({ items, ...props }) { diff --git a/docs/yarn.lock b/docs/yarn.lock index 665292d4714..4d26a16c08e 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -10317,10 +10317,10 @@ react-native-gradle-plugin@^0.71.16: resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.71.16.tgz#822bb0c680e03b5df5aa65f2e5ffc2bc2930854a" integrity sha512-H2BjG2zk7B7Wii9sXvd9qhCVRQYDAHSWdMw9tscmZBqSP62DkIWEQSk4/B2GhQ4aK9ydVXgtqR6tBeg3yy8TSA== -react-native-reanimated@^3.6.0-nightly-20231010-4a507b2c4: - version "3.6.0-nightly-20231010-4a507b2c4" - resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-3.6.0-nightly-20231010-4a507b2c4.tgz#6b5debc759a9c57c6b611636932977d01fb59353" - integrity sha512-RO5lkTOsOYX3pGF0UepRHnPSnOpnkj/f59uFQlWu/2+yOy+6IjG9F7dU0fJpumJFt6cSV2p7RUygofC9TrxMVA== +react-native-reanimated@^3.6.0-nightly-20231120-1eb2acaa0: + version "3.6.0-nightly-20231120-1eb2acaa0" + resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-3.6.0-nightly-20231120-1eb2acaa0.tgz#0f3ae33f7ba1590d3cefc9e9cdd908b040a5f134" + integrity sha512-s836kPM2/SMR1347BYT0E95O7zR4NrNEN9B5ToeXxXRCXonydJcsSbecu5JuwcKIDv96ZPtwxHvjTMxzflJVEQ== dependencies: "@babel/plugin-transform-object-assign" "^7.16.7" "@babel/preset-typescript" "^7.16.7" From 1932f8d042d4e61e0db9bd064b578c4d0a953ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20B=C5=82oniarz?= <56109050+bartlomiejbloniarz@users.noreply.github.com> Date: Fri, 22 Dec 2023 16:03:07 +0100 Subject: [PATCH 19/54] Add option to substitute `isWeb` and `shouldBeUseWeb` in babel plugin. (#5283) ## Summary This PR changes the Babel plugin to substitute `isWeb()` and `shouldBeUseWeb()` calls with `true` so that Webpack is able to recognize dead code. ## Test plan Modify the NextExample/babel.config.js file: ```js ['react-native-reanimated/plugin', { omitNativeOnlyData: true, substituteWebPlatformChecks: true }] ``` Run yarn build in NextExample and verify that the difference between reanimated and noreanimated is around 34KB. --- __tests__/__snapshots__/plugin.test.ts.snap | 39 +++++++++++++ __tests__/plugin.test.ts | 63 +++++++++++++++++++++ plugin/build/plugin.js | 28 ++++++++- plugin/src/plugin.ts | 8 ++- plugin/src/substituteWebCallExpression.ts | 13 +++++ plugin/src/types.ts | 1 + 6 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 plugin/src/substituteWebCallExpression.ts diff --git a/__tests__/__snapshots__/plugin.test.ts.snap b/__tests__/__snapshots__/plugin.test.ts.snap index c281a83b3ab..4b2ee071d42 100644 --- a/__tests__/__snapshots__/plugin.test.ts.snap +++ b/__tests__/__snapshots__/plugin.test.ts.snap @@ -1620,6 +1620,40 @@ function App() { }" `; +exports[`babel plugin for web configuration doesn't substitute isWeb and shouldBeUseWeb in worklets 1`] = ` +"var _worklet_8641000714901_init_data = { + code: "function foo(){const{isWeb,shouldBeUseWeb}=this.__closure;const x=isWeb();const y=shouldBeUseWeb();}", + location: "/dev/null", + sourceMap: "\\"mock source map\\"", + version: "x.y.z" +}; +var foo = function () { + var _e = [new global.Error(), -3, -27]; + var foo = function foo() { + var x = true; + var y = true; + }; + foo.__closure = { + isWeb: isWeb, + shouldBeUseWeb: shouldBeUseWeb + }; + foo.__workletHash = 8641000714901; + foo.__initData = _worklet_8641000714901_init_data; + foo.__stackDetails = _e; + return foo; +}();" +`; + +exports[`babel plugin for web configuration doesn't substitute isWeb and shouldBeUseWeb with true when substituteWebPlatformChecks option is set to false 1`] = ` +"var x = isWeb(); +var y = shouldBeUseWeb();" +`; + +exports[`babel plugin for web configuration doesn't substitute isWeb and shouldBeUseWeb with true when substituteWebPlatformChecks option is undefined 1`] = ` +"var x = isWeb(); +var y = shouldBeUseWeb();" +`; + exports[`babel plugin for web configuration includes initData when omitNativeOnlyData option is set to false 1`] = ` "var _worklet_17472070642672_init_data = { code: "function foo(){var foo='bar';}", @@ -1653,6 +1687,11 @@ exports[`babel plugin for web configuration skips initData when omitNativeOnlyDa }();" `; +exports[`babel plugin for web configuration substitutes isWeb and shouldBeUseWeb with true when substituteWebPlatformChecks option is set to true 1`] = ` +"var x = true; +var y = true;" +`; + exports[`babel plugin for worklet nesting doesn't process nested worklets when disabled 1`] = ` "var _worklet_1678749606628_init_data = { code: "function foo(x){function bar(x){'worklet';return x+2;}return bar(x)+1;}", diff --git a/__tests__/plugin.test.ts b/__tests__/plugin.test.ts index 3a3a261ef7e..f8df1a8ce8d 100644 --- a/__tests__/plugin.test.ts +++ b/__tests__/plugin.test.ts @@ -1609,5 +1609,68 @@ describe('babel plugin', () => { expect(code).toHaveWorkletData(1); expect(code).toMatchSnapshot(); }); + + it('substitutes isWeb and shouldBeUseWeb with true when substituteWebPlatformChecks option is set to true', () => { + const input = html``; + + const { code } = runPlugin( + input, + {}, + { substituteWebPlatformChecks: true } + ); + expect(code).toContain('var x = true;'); + expect(code).toContain('var y = true;'); + expect(code).toMatchSnapshot(); + }); + + it("doesn't substitute isWeb and shouldBeUseWeb with true when substituteWebPlatformChecks option is set to false", () => { + const input = html``; + + const { code } = runPlugin( + input, + {}, + { substituteWebPlatformChecks: false } + ); + expect(code).toContain('var x = isWeb();'); + expect(code).toContain('var y = shouldBeUseWeb();'); + expect(code).toMatchSnapshot(); + }); + + it("doesn't substitute isWeb and shouldBeUseWeb with true when substituteWebPlatformChecks option is undefined", () => { + const input = html``; + + const { code } = runPlugin(input); + expect(code).toContain('var x = isWeb();'); + expect(code).toContain('var y = shouldBeUseWeb();'); + expect(code).toMatchSnapshot(); + }); + + it("doesn't substitute isWeb and shouldBeUseWeb in worklets", () => { + const input = html``; + + const { code } = runPlugin( + input, + {}, + { substituteWebPlatformChecks: true } + ); + expect(code).toContain('const x=isWeb();'); + expect(code).toContain('const y=shouldBeUseWeb();'); + expect(code).toMatchSnapshot(); + }); }); }); diff --git a/plugin/build/plugin.js b/plugin/build/plugin.js index 27ea4849a1a..5d735485608 100644 --- a/plugin/build/plugin.js +++ b/plugin/build/plugin.js @@ -978,6 +978,26 @@ var require_addCustomGlobals = __commonJS({ } }); +// lib/substituteWebCallExpression.js +var require_substituteWebCallExpression = __commonJS({ + "lib/substituteWebCallExpression.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.substituteWebCallExpression = void 0; + var types_1 = require("@babel/types"); + function substituteWebCallExpression(path) { + const callee = path.node.callee; + if ((0, types_1.isIdentifier)(callee)) { + const name = callee.name; + if (name === "isWeb" || name === "shouldBeUseWeb") { + path.replaceWith((0, types_1.booleanLiteral)(true)); + } + } + } + exports2.substituteWebCallExpression = substituteWebCallExpression; + } +}); + // lib/plugin.js Object.defineProperty(exports, "__esModule", { value: true }); var processForCalleesWorklets_1 = require_processForCalleesWorklets(); @@ -986,6 +1006,7 @@ var processInlineStylesWarning_1 = require_processInlineStylesWarning(); var processIfCallback_1 = require_processIfCallback(); var addCustomGlobals_1 = require_addCustomGlobals(); var globals_1 = require_globals(); +var substituteWebCallExpression_1 = require_substituteWebCallExpression(); module.exports = function() { function runWithTaggedExceptions(fun) { try { @@ -1004,7 +1025,12 @@ module.exports = function() { visitor: { CallExpression: { enter(path, state) { - runWithTaggedExceptions(() => (0, processForCalleesWorklets_1.processForCalleesWorklets)(path, state)); + runWithTaggedExceptions(() => { + (0, processForCalleesWorklets_1.processForCalleesWorklets)(path, state); + if (state.opts.substituteWebPlatformChecks) { + (0, substituteWebCallExpression_1.substituteWebCallExpression)(path); + } + }); } }, "FunctionDeclaration|FunctionExpression|ArrowFunctionExpression": { diff --git a/plugin/src/plugin.ts b/plugin/src/plugin.ts index 3a00944298e..431675b8b6a 100644 --- a/plugin/src/plugin.ts +++ b/plugin/src/plugin.ts @@ -7,6 +7,7 @@ import { processInlineStylesWarning } from './processInlineStylesWarning'; import { processIfCallback } from './processIfCallback'; import { addCustomGlobals } from './addCustomGlobals'; import { initializeGlobals } from './globals'; +import { substituteWebCallExpression } from './substituteWebCallExpression'; module.exports = function (): PluginItem { function runWithTaggedExceptions(fun: () => void) { @@ -27,7 +28,12 @@ module.exports = function (): PluginItem { visitor: { CallExpression: { enter(path: NodePath, state: ReanimatedPluginPass) { - runWithTaggedExceptions(() => processForCalleesWorklets(path, state)); + runWithTaggedExceptions(() => { + processForCalleesWorklets(path, state); + if (state.opts.substituteWebPlatformChecks) { + substituteWebCallExpression(path); + } + }); }, }, 'FunctionDeclaration|FunctionExpression|ArrowFunctionExpression': { diff --git a/plugin/src/substituteWebCallExpression.ts b/plugin/src/substituteWebCallExpression.ts new file mode 100644 index 00000000000..87e5ccb1f82 --- /dev/null +++ b/plugin/src/substituteWebCallExpression.ts @@ -0,0 +1,13 @@ +import type { NodePath } from '@babel/core'; +import { booleanLiteral, isIdentifier } from '@babel/types'; +import type { CallExpression } from '@babel/types'; + +export function substituteWebCallExpression(path: NodePath) { + const callee = path.node.callee; + if (isIdentifier(callee)) { + const name = callee.name; + if (name === 'isWeb' || name === 'shouldBeUseWeb') { + path.replaceWith(booleanLiteral(true)); + } + } +} diff --git a/plugin/src/types.ts b/plugin/src/types.ts index 50c6cd0dd8a..2ea1c613e93 100644 --- a/plugin/src/types.ts +++ b/plugin/src/types.ts @@ -12,6 +12,7 @@ export interface ReanimatedPluginOptions { processNestedWorklets?: boolean; omitNativeOnlyData?: boolean; globals?: string[]; + substituteWebPlatformChecks?: boolean; } export interface ReanimatedPluginPass { From f40ee24ebf31424ec7f75b58c0d80e34b13dae29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20=C5=BBelawski?= <40713406+tjzel@users.noreply.github.com> Date: Fri, 22 Dec 2023 17:56:43 +0100 Subject: [PATCH 20/54] Use relative file location in source maps with `relativeSourceLocation` enabled (#5464) ## Summary This option was added back when source maps were not included in https://github.com/software-mansion/react-native-reanimated/pull/3141. Source map addition for better LogBox experience was added in https://github.com/software-mansion/react-native-reanimated/pull/3846 - but it didn't take into account `relativeSourceLocation`. This PR fixes this and there is no more absolute location in the source map while `relativeSourceLocation` is on. I haven't found a way to generate the source map with relative location out-of-the-box. ## Test plan In `WorkletExample` see that LogBox is working as intended. Also plugin tests maybe. --- __tests__/plugin.test.ts | 19 ++++++++++++++++++- plugin/build/plugin.js | 3 ++- plugin/src/makeWorklet.ts | 7 ++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/__tests__/plugin.test.ts b/__tests__/plugin.test.ts index f8df1a8ce8d..b9a9a43f5e1 100644 --- a/__tests__/plugin.test.ts +++ b/__tests__/plugin.test.ts @@ -1,6 +1,6 @@ import { html } from 'code-tag'; import plugin from '../plugin'; -import { TransformOptions, transformSync } from '@babel/core'; +import { BabelFileResult, TransformOptions, transformSync } from '@babel/core'; import traverse from '@babel/traverse'; import { strict as assert } from 'assert'; import '../plugin/jestUtils'; @@ -97,6 +97,23 @@ describe('babel plugin', () => { ); }); + it('uses relative source location when `relativeSourceLocation` is set to `true`', () => { + process.env.REANIMATED_JEST_SHOULD_MOCK_SOURCE_MAP = '0'; // don't mock source maps + const input = html``; + + const { code } = runPlugin(input, undefined, { + relativeSourceLocation: true, + }); + + const matches = code?.match(new RegExp(`..${MOCK_LOCATION}`, 'g')); + expect(matches).toHaveLength(2); + }); + it('removes comments from worklets', () => { const input = html``; + + const { code } = runPlugin(input); + expect(code).toContain('var foo = function* foo() {'); + expect(code).toMatchSnapshot(); + }); + + it('makes a generator worklet string', () => { + const input = html``; + + const { code } = runPlugin(input); + expect(code).toContain( + `code: "function*foo(){yield'hello';yield'world';}"` + ); + expect(code).toMatchSnapshot(); + }); + }); }); diff --git a/plugin/build/plugin.js b/plugin/build/plugin.js index 40cf07a0100..1cee84f65f5 100644 --- a/plugin/build/plugin.js +++ b/plugin/build/plugin.js @@ -95,7 +95,7 @@ var require_buildWorkletString = __commonJS({ const expression = (0, types_1.isFunctionDeclaration)(draftExpression) ? draftExpression : draftExpression.expression; (0, assert_1.strict)("params" in expression, "'params' property is undefined in 'expression'"); (0, assert_1.strict)((0, types_1.isBlockStatement)(expression.body), "[Reanimated] `expression.body` is not a `BlockStatement`"); - const workletFunction = (0, types_1.functionExpression)((0, types_1.identifier)(name), expression.params, expression.body); + const workletFunction = (0, types_1.functionExpression)((0, types_1.identifier)(name), expression.params, expression.body, expression.generator); const code = (0, generator_1.default)(workletFunction).code; (0, assert_1.strict)(inputMap, "[Reanimated] `inputMap` is undefined."); const includeSourceMap = !(0, utils_1.isRelease)(); @@ -332,7 +332,7 @@ var require_makeWorklet = __commonJS({ const functionName = makeWorkletName(fun); const functionIdentifier = (0, types_1.identifier)(functionName); const clone = (0, types_1.cloneNode)(fun.node); - const funExpression = (0, types_1.isBlockStatement)(clone.body) ? (0, types_1.functionExpression)(null, clone.params, clone.body) : clone; + const funExpression = (0, types_1.isBlockStatement)(clone.body) ? (0, types_1.functionExpression)(null, clone.params, clone.body, clone.generator) : clone; let [funString, sourceMapString] = (0, buildWorkletString_1.buildWorkletString)(transformed.ast, variables, functionName, transformed.map); (0, assert_1.strict)(funString, "[Reanimated] `funString` is undefined."); const workletHash = hash(funString); diff --git a/plugin/src/buildWorkletString.ts b/plugin/src/buildWorkletString.ts index 52e215f8456..a6077530652 100644 --- a/plugin/src/buildWorkletString.ts +++ b/plugin/src/buildWorkletString.ts @@ -63,7 +63,8 @@ export function buildWorkletString( const workletFunction = functionExpression( identifier(name), expression.params, - expression.body + expression.body, + expression.generator ); const code = generate(workletFunction).code; diff --git a/plugin/src/makeWorklet.ts b/plugin/src/makeWorklet.ts index bebc073f674..1f6603b33d1 100644 --- a/plugin/src/makeWorklet.ts +++ b/plugin/src/makeWorklet.ts @@ -104,7 +104,7 @@ export function makeWorklet( const clone = cloneNode(fun.node); const funExpression = isBlockStatement(clone.body) - ? functionExpression(null, clone.params, clone.body) + ? functionExpression(null, clone.params, clone.body, clone.generator) : clone; let [funString, sourceMapString] = buildWorkletString( From ddca5694a2440eb3c2c15a66b7f29daf6e9ffcaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20=C5=BBelawski?= <40713406+tjzel@users.noreply.github.com> Date: Fri, 12 Jan 2024 09:48:09 +0100 Subject: [PATCH 45/54] Remove `makeRemote` (#5518) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary `makeRemote` function seems to be no longer necessary. Prettifying `useAnimatedStyle` as a bonus. ### Why can `makeRemote` be removed `makeRemote` utilizes the `ShareableHandle` idea. Let's look at its code: ```ts export function makeRemote(initial) { const handle = makeShareableCloneRecursive({ __init: () => { 'worklet'; return initial; }, }); registerShareableMapping(initial, handle); return initial; } ``` The object `handle` defined inside this function has `__init` worklet property. This worklet has the object `initial` in its closure. When `makeShareableCloneRecursive` is called with this worklet, `initial's` value will be copied to the `handle`'s closure. Therefore, calling `__init` on UI runtime will return the copied value of initial. So at this point we have a `ShareableObject` `handle` with a worklet property `__init`. Both this object and its worklet were saved in `_shareableCache` when `makeShareableCloneRecursive` was called. Current mappings are: `_shareableCache[handle]` - `handle` `_shareableCache[handle.__init]` - `handle.__init` Now `registerShareableMapping` is called. This function sets a new mapping for `_shareableCache`. It maps `initial` to `handle`. Therefore any worklet that has `initial` in its closure will take the mapping for `initial` instead, which is the `handle`. Then on the UI thread, when we evaluate worklet that uses `initial`, we run it through `valueUnpacker`. `valueUnpacker` checks if the object has `__init` property, if yes, then it return the result of `__init` worklet. So it returns the copied value of `initial` that was copied during evaluation of `__init`. To sum it up: `makeRemote` is a function that maps a given JS reference to a function that on UI thread will return the same value. With current implementation of Shareables this hardly serves any purpose, since we could just copy the value like a plain JS value, using its copy. For example, code: ```ts const a = { b: 5 }; makeRemote(a); function foo() { 'worklet'; console.log(a); } ``` Provides the same results as ```ts const a = { b: 5 }; function foo(){ `worklet`; console.log(a); } ``` Since all that `makeRemote` does is add unnecessary identity unpacking function. ## Test plan 🚀 To check `areAnimationsActive`:
```tsx import { StyleSheet, View, Button } from 'react-native'; import Animated, { useAnimatedStyle, useSharedValue, withTiming, } from 'react-native-reanimated'; import React from 'react'; export default function EmptyExample() { const [state, setState] = React.useState(0); const sv = useSharedValue(0); const animatedStyle = useAnimatedStyle(() => { return { transform: [{ rotate: `${sv.value}deg` }], }; }); return (
--- src/createAnimatedComponent/PropsFilter.tsx | 2 +- .../createAnimatedComponent.tsx | 4 +- src/reanimated2/ViewDescriptorsSet.ts | 14 +++++- src/reanimated2/core.ts | 2 +- src/reanimated2/hook/commonTypes.ts | 5 +- src/reanimated2/hook/useAnimatedStyle.ts | 48 ++++++++++--------- src/reanimated2/hook/useHandler.ts | 3 +- src/reanimated2/mutables.ts | 11 ----- 8 files changed, 46 insertions(+), 43 deletions(-) diff --git a/src/createAnimatedComponent/PropsFilter.tsx b/src/createAnimatedComponent/PropsFilter.tsx index 10047f0ee83..e8077c6de4a 100644 --- a/src/createAnimatedComponent/PropsFilter.tsx +++ b/src/createAnimatedComponent/PropsFilter.tsx @@ -37,7 +37,7 @@ export class PropsFilter implements IPropsFilter { const processedStyle: StyleProps = styles.map((style) => { if (style && style.viewDescriptors) { // this is how we recognize styles returned by useAnimatedStyle - style.viewsRef.add(component); + style.viewsRef?.add(component); if (component._isFirstRender) { this._initialStyle = { ...style.initial.value, diff --git a/src/createAnimatedComponent/createAnimatedComponent.tsx b/src/createAnimatedComponent/createAnimatedComponent.tsx index 508d03eff4d..2bb18288a2b 100644 --- a/src/createAnimatedComponent/createAnimatedComponent.tsx +++ b/src/createAnimatedComponent/createAnimatedComponent.tsx @@ -244,9 +244,7 @@ export function createAnimatedComponent( _detachStyles() { if (IS_WEB && this._styles !== null) { for (const style of this._styles) { - if (style?.viewsRef) { - style.viewsRef.remove(this); - } + style.viewsRef.delete(this); } } else if (this._viewTag !== -1 && this._styles !== null) { for (const style of this._styles) { diff --git a/src/reanimated2/ViewDescriptorsSet.ts b/src/reanimated2/ViewDescriptorsSet.ts index 392d7eba12a..1807865909e 100644 --- a/src/reanimated2/ViewDescriptorsSet.ts +++ b/src/reanimated2/ViewDescriptorsSet.ts @@ -3,6 +3,7 @@ import { useRef } from 'react'; import { makeMutable } from './core'; import type { SharedValue } from './commonTypes'; import type { Descriptor } from './hook/commonTypes'; +import { shouldBeUseWeb } from './PlatformChecker'; export interface ViewRefSet { items: Set; @@ -51,7 +52,18 @@ export function makeViewDescriptorsSet(): ViewDescriptorsSet { return data; } -export function useViewRefSet(): ViewRefSet { +const SHOULD_BE_USE_WEB = shouldBeUseWeb(); + +export const useViewRefSet = SHOULD_BE_USE_WEB + ? useViewRefSetJS + : useViewRefSetNative; + +function useViewRefSetNative() { + // Stub native implementation. + return undefined; +} + +function useViewRefSetJS(): ViewRefSet { const ref = useRef | null>(null); if (ref.current === null) { const data: ViewRefSet = { diff --git a/src/reanimated2/core.ts b/src/reanimated2/core.ts index c593153f27c..77d37356504 100644 --- a/src/reanimated2/core.ts +++ b/src/reanimated2/core.ts @@ -31,7 +31,7 @@ export { runOnJS, runOnUI } from './threads'; export { createWorkletRuntime, runOnRuntime } from './runtimes'; export type { WorkletRuntime } from './runtimes'; export { makeShareable, makeShareableCloneRecursive } from './shareables'; -export { makeMutable, makeRemote } from './mutables'; +export { makeMutable } from './mutables'; const IS_FABRIC = isFabric(); diff --git a/src/reanimated2/hook/commonTypes.ts b/src/reanimated2/hook/commonTypes.ts index a154fdfd4db..a346da9a47f 100644 --- a/src/reanimated2/hook/commonTypes.ts +++ b/src/reanimated2/hook/commonTypes.ts @@ -81,7 +81,10 @@ export interface AnimatedStyleHandle< value: AnimatedStyle - - diff --git a/MacOSExample/android/app/src/release/java/com/macosexample/ReactNativeFlipper.java b/MacOSExample/android/app/src/release/java/com/macosexample/ReactNativeFlipper.java deleted file mode 100644 index 39e94fd5a00..00000000000 --- a/MacOSExample/android/app/src/release/java/com/macosexample/ReactNativeFlipper.java +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - *

This source code is licensed under the MIT license found in the LICENSE file in the root - * directory of this source tree. - */ -package com.macosexample; - -import android.content.Context; -import com.facebook.react.ReactInstanceManager; - -/** - * Class responsible of loading Flipper inside your React Native application. This is the release - * flavor of it so it's empty as we don't want to load Flipper. - */ -public class ReactNativeFlipper { - public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { - // Do nothing as we don't want to initialize Flipper on Release. - } -} diff --git a/MacOSExample/android/build.gradle b/MacOSExample/android/build.gradle deleted file mode 100644 index 67d887b0307..00000000000 --- a/MacOSExample/android/build.gradle +++ /dev/null @@ -1,21 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - ext { - buildToolsVersion = "33.0.0" - minSdkVersion = 21 - compileSdkVersion = 33 - targetSdkVersion = 33 - - // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. - ndkVersion = "23.1.7779620" - } - repositories { - google() - mavenCentral() - } - dependencies { - classpath("com.android.tools.build:gradle:7.3.1") - classpath("com.facebook.react:react-native-gradle-plugin") - } -} diff --git a/MacOSExample/android/gradle.properties b/MacOSExample/android/gradle.properties deleted file mode 100644 index e4af465e8a1..00000000000 --- a/MacOSExample/android/gradle.properties +++ /dev/null @@ -1,44 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m -org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true - -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app's APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true -# Automatically convert third-party libraries to use AndroidX -android.enableJetifier=true - -# Version of flipper SDK to use with React Native -FLIPPER_VERSION=0.125.0 - -# Use this property to specify which architecture you want to build. -# You can also override it from the CLI using -# ./gradlew -PreactNativeArchitectures=x86_64 -reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 - -# Use this property to enable support to the new architecture. -# This will allow you to use TurboModules and the Fabric render in -# your application. You should enable this flag either if you want -# to write custom TurboModules/Fabric components OR use libraries that -# are providing them. -newArchEnabled=false - -# Use this property to enable or disable the Hermes JS engine. -# If set to false, you will be using JSC instead. -hermesEnabled=true diff --git a/MacOSExample/android/gradle/wrapper/gradle-wrapper.jar b/MacOSExample/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 41d9927a4d4fb3f96a785543079b8df6723c946b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59821 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 diff --git a/MacOSExample/android/gradle/wrapper/gradle-wrapper.properties b/MacOSExample/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 8fad3f5a98b..00000000000 --- a/MacOSExample/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/MacOSExample/android/gradlew b/MacOSExample/android/gradlew deleted file mode 100755 index 1b6c787337f..00000000000 --- a/MacOSExample/android/gradlew +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" -APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/MacOSExample/android/gradlew.bat b/MacOSExample/android/gradlew.bat deleted file mode 100644 index ac1b06f9382..00000000000 --- a/MacOSExample/android/gradlew.bat +++ /dev/null @@ -1,89 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/MacOSExample/android/settings.gradle b/MacOSExample/android/settings.gradle deleted file mode 100644 index d04d37bc438..00000000000 --- a/MacOSExample/android/settings.gradle +++ /dev/null @@ -1,4 +0,0 @@ -rootProject.name = 'MacOSExample' -apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) -include ':app' -includeBuild('../node_modules/react-native-gradle-plugin') diff --git a/MacOSExample/ios/.xcode.env b/MacOSExample/ios/.xcode.env deleted file mode 100644 index 3d5782c7156..00000000000 --- a/MacOSExample/ios/.xcode.env +++ /dev/null @@ -1,11 +0,0 @@ -# This `.xcode.env` file is versioned and is used to source the environment -# used when running script phases inside Xcode. -# To customize your local environment, you can create an `.xcode.env.local` -# file that is not versioned. - -# NODE_BINARY variable contains the PATH to the node executable. -# -# Customize the NODE_BINARY variable here. -# For example, to use nvm with brew, add the following line -# . "$(brew --prefix nvm)/nvm.sh" --no-use -export NODE_BINARY=$(command -v node) diff --git a/MacOSExample/ios/MacOSExample.xcodeproj/project.pbxproj b/MacOSExample/ios/MacOSExample.xcodeproj/project.pbxproj deleted file mode 100644 index 10b7e9ec2c1..00000000000 --- a/MacOSExample/ios/MacOSExample.xcodeproj/project.pbxproj +++ /dev/null @@ -1,721 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 00E356F31AD99517003FC87E /* MacOSExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* MacOSExampleTests.m */; }; - 0C80B921A6F3F58F76C31292 /* libPods-MacOSExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-MacOSExample.a */; }; - 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; - 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; - 7699B88040F8A987B510C191 /* libPods-MacOSExample-MacOSExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-MacOSExample-MacOSExampleTests.a */; }; - 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 13B07F861A680F5B00A75B9A; - remoteInfo = MacOSExample; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 00E356EE1AD99517003FC87E /* MacOSExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MacOSExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 00E356F21AD99517003FC87E /* MacOSExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MacOSExampleTests.m; sourceTree = ""; }; - 13B07F961A680F5B00A75B9A /* MacOSExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MacOSExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = MacOSExample/AppDelegate.h; sourceTree = ""; }; - 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = MacOSExample/AppDelegate.mm; sourceTree = ""; }; - 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = MacOSExample/Images.xcassets; sourceTree = ""; }; - 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = MacOSExample/Info.plist; sourceTree = ""; }; - 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = MacOSExample/main.m; sourceTree = ""; }; - 19F6CBCC0A4E27FBF8BF4A61 /* libPods-MacOSExample-MacOSExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MacOSExample-MacOSExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B4392A12AC88292D35C810B /* Pods-MacOSExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MacOSExample.debug.xcconfig"; path = "Target Support Files/Pods-MacOSExample/Pods-MacOSExample.debug.xcconfig"; sourceTree = ""; }; - 5709B34CF0A7D63546082F79 /* Pods-MacOSExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MacOSExample.release.xcconfig"; path = "Target Support Files/Pods-MacOSExample/Pods-MacOSExample.release.xcconfig"; sourceTree = ""; }; - 5B7EB9410499542E8C5724F5 /* Pods-MacOSExample-MacOSExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MacOSExample-MacOSExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-MacOSExample-MacOSExampleTests/Pods-MacOSExample-MacOSExampleTests.debug.xcconfig"; sourceTree = ""; }; - 5DCACB8F33CDC322A6C60F78 /* libPods-MacOSExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MacOSExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = MacOSExample/LaunchScreen.storyboard; sourceTree = ""; }; - 89C6BE57DB24E9ADA2F236DE /* Pods-MacOSExample-MacOSExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MacOSExample-MacOSExampleTests.release.xcconfig"; path = "Target Support Files/Pods-MacOSExample-MacOSExampleTests/Pods-MacOSExample-MacOSExampleTests.release.xcconfig"; sourceTree = ""; }; - ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 00E356EB1AD99517003FC87E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 7699B88040F8A987B510C191 /* libPods-MacOSExample-MacOSExampleTests.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 0C80B921A6F3F58F76C31292 /* libPods-MacOSExample.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 00E356EF1AD99517003FC87E /* MacOSExampleTests */ = { - isa = PBXGroup; - children = ( - 00E356F21AD99517003FC87E /* MacOSExampleTests.m */, - 00E356F01AD99517003FC87E /* Supporting Files */, - ); - path = MacOSExampleTests; - sourceTree = ""; - }; - 00E356F01AD99517003FC87E /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 00E356F11AD99517003FC87E /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 13B07FAE1A68108700A75B9A /* MacOSExample */ = { - isa = PBXGroup; - children = ( - 13B07FAF1A68108700A75B9A /* AppDelegate.h */, - 13B07FB01A68108700A75B9A /* AppDelegate.mm */, - 13B07FB51A68108700A75B9A /* Images.xcassets */, - 13B07FB61A68108700A75B9A /* Info.plist */, - 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, - 13B07FB71A68108700A75B9A /* main.m */, - ); - name = MacOSExample; - sourceTree = ""; - }; - 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { - isa = PBXGroup; - children = ( - ED297162215061F000B7C4FE /* JavaScriptCore.framework */, - 5DCACB8F33CDC322A6C60F78 /* libPods-MacOSExample.a */, - 19F6CBCC0A4E27FBF8BF4A61 /* libPods-MacOSExample-MacOSExampleTests.a */, - ); - name = Frameworks; - sourceTree = ""; - }; - 832341AE1AAA6A7D00B99B32 /* Libraries */ = { - isa = PBXGroup; - children = ( - ); - name = Libraries; - sourceTree = ""; - }; - 83CBB9F61A601CBA00E9B192 = { - isa = PBXGroup; - children = ( - 13B07FAE1A68108700A75B9A /* MacOSExample */, - 832341AE1AAA6A7D00B99B32 /* Libraries */, - 00E356EF1AD99517003FC87E /* MacOSExampleTests */, - 83CBBA001A601CBA00E9B192 /* Products */, - 2D16E6871FA4F8E400B85C8A /* Frameworks */, - BBD78D7AC51CEA395F1C20DB /* Pods */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - usesTabs = 0; - }; - 83CBBA001A601CBA00E9B192 /* Products */ = { - isa = PBXGroup; - children = ( - 13B07F961A680F5B00A75B9A /* MacOSExample.app */, - 00E356EE1AD99517003FC87E /* MacOSExampleTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - BBD78D7AC51CEA395F1C20DB /* Pods */ = { - isa = PBXGroup; - children = ( - 3B4392A12AC88292D35C810B /* Pods-MacOSExample.debug.xcconfig */, - 5709B34CF0A7D63546082F79 /* Pods-MacOSExample.release.xcconfig */, - 5B7EB9410499542E8C5724F5 /* Pods-MacOSExample-MacOSExampleTests.debug.xcconfig */, - 89C6BE57DB24E9ADA2F236DE /* Pods-MacOSExample-MacOSExampleTests.release.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 00E356ED1AD99517003FC87E /* MacOSExampleTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "MacOSExampleTests" */; - buildPhases = ( - A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */, - 00E356EA1AD99517003FC87E /* Sources */, - 00E356EB1AD99517003FC87E /* Frameworks */, - 00E356EC1AD99517003FC87E /* Resources */, - C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */, - F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - 00E356F51AD99517003FC87E /* PBXTargetDependency */, - ); - name = MacOSExampleTests; - productName = MacOSExampleTests; - productReference = 00E356EE1AD99517003FC87E /* MacOSExampleTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 13B07F861A680F5B00A75B9A /* MacOSExample */ = { - isa = PBXNativeTarget; - buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "MacOSExample" */; - buildPhases = ( - C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */, - FD10A7F022414F080027D42C /* Start Packager */, - 13B07F871A680F5B00A75B9A /* Sources */, - 13B07F8C1A680F5B00A75B9A /* Frameworks */, - 13B07F8E1A680F5B00A75B9A /* Resources */, - 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */, - E235C05ADACE081382539298 /* [CP] Copy Pods Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = MacOSExample; - productName = MacOSExample; - productReference = 13B07F961A680F5B00A75B9A /* MacOSExample.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 83CBB9F71A601CBA00E9B192 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1210; - TargetAttributes = { - 00E356ED1AD99517003FC87E = { - CreatedOnToolsVersion = 6.2; - TestTargetID = 13B07F861A680F5B00A75B9A; - }; - 13B07F861A680F5B00A75B9A = { - LastSwiftMigration = 1120; - }; - }; - }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "MacOSExample" */; - compatibilityVersion = "Xcode 12.0"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 83CBB9F61A601CBA00E9B192; - productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 13B07F861A680F5B00A75B9A /* MacOSExample */, - 00E356ED1AD99517003FC87E /* MacOSExampleTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 00E356EC1AD99517003FC87E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 13B07F8E1A680F5B00A75B9A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */, - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(SRCROOT)/.xcode.env.local", - "$(SRCROOT)/.xcode.env", - ); - name = "Bundle React Native code and images"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n"; - }; - 00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-MacOSExample/Pods-MacOSExample-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-MacOSExample/Pods-MacOSExample-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MacOSExample/Pods-MacOSExample-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-MacOSExample-MacOSExampleTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-MacOSExample-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-MacOSExample-MacOSExampleTests/Pods-MacOSExample-MacOSExampleTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-MacOSExample-MacOSExampleTests/Pods-MacOSExample-MacOSExampleTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MacOSExample-MacOSExampleTests/Pods-MacOSExample-MacOSExampleTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-MacOSExample/Pods-MacOSExample-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-MacOSExample/Pods-MacOSExample-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MacOSExample/Pods-MacOSExample-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-MacOSExample-MacOSExampleTests/Pods-MacOSExample-MacOSExampleTests-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-MacOSExample-MacOSExampleTests/Pods-MacOSExample-MacOSExampleTests-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MacOSExample-MacOSExampleTests/Pods-MacOSExample-MacOSExampleTests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - FD10A7F022414F080027D42C /* Start Packager */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = "Start Packager"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 00E356EA1AD99517003FC87E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 00E356F31AD99517003FC87E /* MacOSExampleTests.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 13B07F871A680F5B00A75B9A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, - 13B07FC11A68108700A75B9A /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 00E356F51AD99517003FC87E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 13B07F861A680F5B00A75B9A /* MacOSExample */; - targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 00E356F61AD99517003FC87E /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-MacOSExample-MacOSExampleTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = MacOSExampleTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - "$(inherited)", - ); - PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MacOSExample.app/MacOSExample"; - }; - name = Debug; - }; - 00E356F71AD99517003FC87E /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-MacOSExample-MacOSExampleTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - COPY_PHASE_STRIP = NO; - INFOPLIST_FILE = MacOSExampleTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - "$(inherited)", - ); - PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MacOSExample.app/MacOSExample"; - }; - name = Release; - }; - 13B07F941A680F5B00A75B9A /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-MacOSExample.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 1; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = MacOSExample/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = MacOSExample; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 13B07F951A680F5B00A75B9A /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-MacOSExample.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 1; - INFOPLIST_FILE = MacOSExample/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = MacOSExample; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; - 83CBBA201A601CBA00E9B192 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - _LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION, - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; - LD_RUNPATH_SEARCH_PATHS = ( - /usr/lib/swift, - "$(inherited)", - ); - LIBRARY_SEARCH_PATHS = ( - "\"$(SDKROOT)/usr/lib/swift\"", - "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", - "\"$(inherited)\"", - ); - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = "$(inherited)"; - OTHER_CPLUSPLUSFLAGS = ( - "$(OTHER_CFLAGS)", - "-DFOLLY_NO_CONFIG", - "-DFOLLY_MOBILE=1", - "-DFOLLY_USE_LIBCPP=1", - ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-Wl", - "-ld_classic", - ); - REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; - SDKROOT = iphoneos; - }; - name = Debug; - }; - 83CBBA211A601CBA00E9B192 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - _LIBCPP_ENABLE_CXX17_REMOVED_UNARY_BINARY_FUNCTION, - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; - LD_RUNPATH_SEARCH_PATHS = ( - /usr/lib/swift, - "$(inherited)", - ); - LIBRARY_SEARCH_PATHS = ( - "\"$(SDKROOT)/usr/lib/swift\"", - "\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"", - "\"$(inherited)\"", - ); - MTL_ENABLE_DEBUG_INFO = NO; - OTHER_CFLAGS = "$(inherited)"; - OTHER_CPLUSPLUSFLAGS = ( - "$(OTHER_CFLAGS)", - "-DFOLLY_NO_CONFIG", - "-DFOLLY_MOBILE=1", - "-DFOLLY_USE_LIBCPP=1", - ); - OTHER_LDFLAGS = ( - "$(inherited)", - "-Wl", - "-ld_classic", - ); - REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "MacOSExampleTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 00E356F61AD99517003FC87E /* Debug */, - 00E356F71AD99517003FC87E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "MacOSExample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 13B07F941A680F5B00A75B9A /* Debug */, - 13B07F951A680F5B00A75B9A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "MacOSExample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 83CBBA201A601CBA00E9B192 /* Debug */, - 83CBBA211A601CBA00E9B192 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; -} diff --git a/MacOSExample/ios/MacOSExample.xcodeproj/xcshareddata/xcschemes/MacOSExample.xcscheme b/MacOSExample/ios/MacOSExample.xcodeproj/xcshareddata/xcschemes/MacOSExample.xcscheme deleted file mode 100644 index 5454a628597..00000000000 --- a/MacOSExample/ios/MacOSExample.xcodeproj/xcshareddata/xcschemes/MacOSExample.xcscheme +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MacOSExample/ios/MacOSExample.xcworkspace/contents.xcworkspacedata b/MacOSExample/ios/MacOSExample.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index c1b0aed27c7..00000000000 --- a/MacOSExample/ios/MacOSExample.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/MacOSExample/ios/MacOSExample/AppDelegate.h b/MacOSExample/ios/MacOSExample/AppDelegate.h deleted file mode 100644 index 5d2808256ca..00000000000 --- a/MacOSExample/ios/MacOSExample/AppDelegate.h +++ /dev/null @@ -1,6 +0,0 @@ -#import -#import - -@interface AppDelegate : RCTAppDelegate - -@end diff --git a/MacOSExample/ios/MacOSExample/AppDelegate.mm b/MacOSExample/ios/MacOSExample/AppDelegate.mm deleted file mode 100644 index 087182219cc..00000000000 --- a/MacOSExample/ios/MacOSExample/AppDelegate.mm +++ /dev/null @@ -1,36 +0,0 @@ -#import "AppDelegate.h" - -#import - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - self.moduleName = @"MacOSExample"; - // You can add your custom initial props in the dictionary below. - // They will be passed down to the ViewController used by React Native. - self.initialProps = @{}; - - return [super application:application didFinishLaunchingWithOptions:launchOptions]; -} - -- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge -{ -#if DEBUG - return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; -#else - return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; -#endif -} - -/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. -/// -/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html -/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). -/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. -- (BOOL)concurrentRootEnabled -{ - return true; -} - -@end diff --git a/MacOSExample/ios/MacOSExample/Images.xcassets/AppIcon.appiconset/Contents.json b/MacOSExample/ios/MacOSExample/Images.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 81213230deb..00000000000 --- a/MacOSExample/ios/MacOSExample/Images.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MacOSExample/ios/MacOSExample/Images.xcassets/Contents.json b/MacOSExample/ios/MacOSExample/Images.xcassets/Contents.json deleted file mode 100644 index 2d92bd53fdb..00000000000 --- a/MacOSExample/ios/MacOSExample/Images.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/MacOSExample/ios/MacOSExample/Info.plist b/MacOSExample/ios/MacOSExample/Info.plist deleted file mode 100644 index b3d25919582..00000000000 --- a/MacOSExample/ios/MacOSExample/Info.plist +++ /dev/null @@ -1,55 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - MacOSExample - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - LSRequiresIPhoneOS - - NSAppTransportSecurity - - NSExceptionDomains - - localhost - - NSExceptionAllowsInsecureHTTPLoads - - - - - NSLocationWhenInUseUsageDescription - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/MacOSExample/ios/MacOSExample/LaunchScreen.storyboard b/MacOSExample/ios/MacOSExample/LaunchScreen.storyboard deleted file mode 100644 index 1f0ab01268f..00000000000 --- a/MacOSExample/ios/MacOSExample/LaunchScreen.storyboard +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MacOSExample/ios/MacOSExample/main.m b/MacOSExample/ios/MacOSExample/main.m deleted file mode 100644 index d645c7246c4..00000000000 --- a/MacOSExample/ios/MacOSExample/main.m +++ /dev/null @@ -1,10 +0,0 @@ -#import - -#import "AppDelegate.h" - -int main(int argc, char *argv[]) -{ - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/MacOSExample/ios/MacOSExampleTests/Info.plist b/MacOSExample/ios/MacOSExampleTests/Info.plist deleted file mode 100644 index ba72822e872..00000000000 --- a/MacOSExample/ios/MacOSExampleTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/MacOSExample/ios/MacOSExampleTests/MacOSExampleTests.m b/MacOSExample/ios/MacOSExampleTests/MacOSExampleTests.m deleted file mode 100644 index 4d0f2fa1a7e..00000000000 --- a/MacOSExample/ios/MacOSExampleTests/MacOSExampleTests.m +++ /dev/null @@ -1,66 +0,0 @@ -#import -#import - -#import -#import - -#define TIMEOUT_SECONDS 600 -#define TEXT_TO_LOOK_FOR @"Welcome to React" - -@interface MacOSExampleTests : XCTestCase - -@end - -@implementation MacOSExampleTests - -- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test -{ - if (test(view)) { - return YES; - } - for (UIView *subview in [view subviews]) { - if ([self findSubviewInView:subview matching:test]) { - return YES; - } - } - return NO; -} - -- (void)testRendersWelcomeScreen -{ - UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; - NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; - BOOL foundElement = NO; - - __block NSString *redboxError = nil; -#ifndef NDEBUG - RCTSetLogFunction( - ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { - if (level >= RCTLogLevelError) { - redboxError = message; - } - }); -#endif - - while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { - [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; - - foundElement = [self findSubviewInView:vc.view - matching:^BOOL(UIView *view) { - if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { - return YES; - } - return NO; - }]; - } - -#ifndef NDEBUG - RCTSetLogFunction(RCTDefaultLogFunction); -#endif - - XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); - XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); -} - -@end diff --git a/MacOSExample/ios/Podfile b/MacOSExample/ios/Podfile deleted file mode 100644 index 42ebb71b6c1..00000000000 --- a/MacOSExample/ios/Podfile +++ /dev/null @@ -1,62 +0,0 @@ -require_relative '../node_modules/react-native/scripts/react_native_pods' -require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' - -ENV['REANIMATED_EXAMPLE_APP_NAME'] = 'MacOSExample-ios' - -platform :ios, min_ios_version_supported -prepare_react_native_project! - -# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. -# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded -# -# To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` -# ```js -# module.exports = { -# dependencies: { -# ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), -# ``` -flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled - -linkage = ENV['USE_FRAMEWORKS'] -if linkage != nil - Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green - use_frameworks! :linkage => linkage.to_sym -end - -target 'MacOSExample' do - config = use_native_modules! - - # Flags change depending on the env values. - flags = get_default_flags() - - use_react_native!( - :path => config[:reactNativePath], - # Hermes is now enabled by default. Disable by setting this flag to false. - # Upcoming versions of React Native may rely on get_default_flags(), but - # we make it explicit here to aid in the React Native upgrade process. - :hermes_enabled => flags[:hermes_enabled], - :fabric_enabled => flags[:fabric_enabled], - # Enables Flipper. - # - # Note that if you have use_frameworks! enabled, Flipper will not work and - # you should disable the next line. - :flipper_configuration => flipper_config, - # An absolute path to your application root. - :app_path => "#{Pod::Config.instance.installation_root}/.." - ) - - target 'MacOSExampleTests' do - inherit! :complete - # Pods for testing - end - - post_install do |installer| - react_native_post_install( - installer, - # Set `mac_catalyst_enabled` to `true` in order to apply patches - # necessary for Mac Catalyst builds - :mac_catalyst_enabled => false - ) - __apply_Xcode_12_5_M1_post_install_workaround(installer) - end -end diff --git a/MacOSExample/ios/Podfile.lock b/MacOSExample/ios/Podfile.lock deleted file mode 100644 index 2e1d97dc2cc..00000000000 --- a/MacOSExample/ios/Podfile.lock +++ /dev/null @@ -1,776 +0,0 @@ -PODS: - - boost (1.76.0) - - CocoaAsyncSocket (7.6.5) - - DoubleConversion (1.1.6) - - FBLazyVector (0.72.6) - - FBReactNativeSpec (0.72.6): - - RCT-Folly (= 2021.07.22.00) - - RCTRequired (= 0.72.6) - - RCTTypeSafety (= 0.72.6) - - React-Core (= 0.72.6) - - React-jsi (= 0.72.6) - - ReactCommon/turbomodule/core (= 0.72.6) - - Flipper (0.182.0): - - Flipper-Folly (~> 2.6) - - Flipper-Boost-iOSX (1.76.0.1.11) - - Flipper-DoubleConversion (3.2.0.1) - - Flipper-Fmt (7.1.7) - - Flipper-Folly (2.6.10): - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt (= 7.1.7) - - Flipper-Glog - - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - - Flipper-Glog (0.5.0.5) - - Flipper-PeerTalk (0.0.4) - - FlipperKit (0.182.0): - - FlipperKit/Core (= 0.182.0) - - FlipperKit/Core (0.182.0): - - Flipper (~> 0.182.0) - - FlipperKit/CppBridge - - FlipperKit/FBCxxFollyDynamicConvert - - FlipperKit/FBDefines - - FlipperKit/FKPortForwarding - - SocketRocket (~> 0.6.0) - - FlipperKit/CppBridge (0.182.0): - - Flipper (~> 0.182.0) - - FlipperKit/FBCxxFollyDynamicConvert (0.182.0): - - Flipper-Folly (~> 2.6) - - FlipperKit/FBDefines (0.182.0) - - FlipperKit/FKPortForwarding (0.182.0): - - CocoaAsyncSocket (~> 7.6) - - Flipper-PeerTalk (~> 0.0.4) - - FlipperKit/FlipperKitHighlightOverlay (0.182.0) - - FlipperKit/FlipperKitLayoutHelpers (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutTextSearchable - - FlipperKit/FlipperKitLayoutIOSDescriptors (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - FlipperKit/FlipperKitLayoutIOSDescriptors - - FlipperKit/FlipperKitLayoutTextSearchable - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutTextSearchable (0.182.0) - - FlipperKit/FlipperKitNetworkPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitReactPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitUserDefaultsPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/SKIOSNetworkPlugin (0.182.0): - - FlipperKit/Core - - FlipperKit/FlipperKitNetworkPlugin - - fmt (6.2.1) - - glog (0.3.5) - - hermes-engine (0.72.6): - - hermes-engine/Pre-built (= 0.72.6) - - hermes-engine/Pre-built (0.72.6) - - libevent (2.1.12) - - OpenSSL-Universal (1.1.1100) - - RCT-Folly (2021.07.22.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - RCT-Folly/Default (= 2021.07.22.00) - - RCT-Folly/Default (2021.07.22.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - RCT-Folly/Futures (2021.07.22.00): - - boost - - DoubleConversion - - fmt (~> 6.2.1) - - glog - - libevent - - RCTRequired (0.72.6) - - RCTTypeSafety (0.72.6): - - FBLazyVector (= 0.72.6) - - RCTRequired (= 0.72.6) - - React-Core (= 0.72.6) - - React (0.72.6): - - React-Core (= 0.72.6) - - React-Core/DevSupport (= 0.72.6) - - React-Core/RCTWebSocket (= 0.72.6) - - React-RCTActionSheet (= 0.72.6) - - React-RCTAnimation (= 0.72.6) - - React-RCTBlob (= 0.72.6) - - React-RCTImage (= 0.72.6) - - React-RCTLinking (= 0.72.6) - - React-RCTNetwork (= 0.72.6) - - React-RCTSettings (= 0.72.6) - - React-RCTText (= 0.72.6) - - React-RCTVibration (= 0.72.6) - - React-callinvoker (0.72.6) - - React-Codegen (0.72.6): - - DoubleConversion - - FBReactNativeSpec - - glog - - hermes-engine - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-Core - - React-jsi - - React-jsiexecutor - - React-NativeModulesApple - - React-rncore - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - React-Core (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.72.6) - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/CoreModulesHeaders (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/Default (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/DevSupport (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.72.6) - - React-Core/RCTWebSocket (= 0.72.6) - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector (= 0.72.6) - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTActionSheetHeaders (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTAnimationHeaders (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTBlobHeaders (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTImageHeaders (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTLinkingHeaders (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTNetworkHeaders (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTSettingsHeaders (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTTextHeaders (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTVibrationHeaders (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-Core/RCTWebSocket (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.72.6) - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-perflogger - - React-runtimeexecutor - - React-utils - - SocketRocket (= 0.6.1) - - Yoga - - React-CoreModules (0.72.6): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.6) - - React-Codegen (= 0.72.6) - - React-Core/CoreModulesHeaders (= 0.72.6) - - React-jsi (= 0.72.6) - - React-RCTBlob - - React-RCTImage (= 0.72.6) - - ReactCommon/turbomodule/core (= 0.72.6) - - SocketRocket (= 0.6.1) - - React-cxxreact (0.72.6): - - boost (= 1.76.0) - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.72.6) - - React-debug (= 0.72.6) - - React-jsi (= 0.72.6) - - React-jsinspector (= 0.72.6) - - React-logger (= 0.72.6) - - React-perflogger (= 0.72.6) - - React-runtimeexecutor (= 0.72.6) - - React-debug (0.72.6) - - React-hermes (0.72.6): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - RCT-Folly/Futures (= 2021.07.22.00) - - React-cxxreact (= 0.72.6) - - React-jsi - - React-jsiexecutor (= 0.72.6) - - React-jsinspector (= 0.72.6) - - React-perflogger (= 0.72.6) - - React-jsi (0.72.6): - - boost (= 1.76.0) - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-jsiexecutor (0.72.6): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.72.6) - - React-jsi (= 0.72.6) - - React-perflogger (= 0.72.6) - - React-jsinspector (0.72.6) - - React-logger (0.72.6): - - glog - - react-native-pager-view (5.4.25): - - React-Core - - react-native-safe-area-context (4.7.2): - - React-Core - - react-native-slider (4.4.3): - - React-Core - - React-NativeModulesApple (0.72.6): - - hermes-engine - - React-callinvoker - - React-Core - - React-cxxreact - - React-jsi - - React-runtimeexecutor - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - React-perflogger (0.72.6) - - React-RCTActionSheet (0.72.6): - - React-Core/RCTActionSheetHeaders (= 0.72.6) - - React-RCTAnimation (0.72.6): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.6) - - React-Codegen (= 0.72.6) - - React-Core/RCTAnimationHeaders (= 0.72.6) - - React-jsi (= 0.72.6) - - ReactCommon/turbomodule/core (= 0.72.6) - - React-RCTAppDelegate (0.72.6): - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-Core - - React-CoreModules - - React-hermes - - React-NativeModulesApple - - React-RCTImage - - React-RCTNetwork - - React-runtimescheduler - - ReactCommon/turbomodule/core - - React-RCTBlob (0.72.6): - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.72.6) - - React-Core/RCTBlobHeaders (= 0.72.6) - - React-Core/RCTWebSocket (= 0.72.6) - - React-jsi (= 0.72.6) - - React-RCTNetwork (= 0.72.6) - - ReactCommon/turbomodule/core (= 0.72.6) - - React-RCTImage (0.72.6): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.6) - - React-Codegen (= 0.72.6) - - React-Core/RCTImageHeaders (= 0.72.6) - - React-jsi (= 0.72.6) - - React-RCTNetwork (= 0.72.6) - - ReactCommon/turbomodule/core (= 0.72.6) - - React-RCTLinking (0.72.6): - - React-Codegen (= 0.72.6) - - React-Core/RCTLinkingHeaders (= 0.72.6) - - React-jsi (= 0.72.6) - - ReactCommon/turbomodule/core (= 0.72.6) - - React-RCTNetwork (0.72.6): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.6) - - React-Codegen (= 0.72.6) - - React-Core/RCTNetworkHeaders (= 0.72.6) - - React-jsi (= 0.72.6) - - ReactCommon/turbomodule/core (= 0.72.6) - - React-RCTSettings (0.72.6): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.72.6) - - React-Codegen (= 0.72.6) - - React-Core/RCTSettingsHeaders (= 0.72.6) - - React-jsi (= 0.72.6) - - ReactCommon/turbomodule/core (= 0.72.6) - - React-RCTText (0.72.6): - - React-Core/RCTTextHeaders (= 0.72.6) - - React-RCTVibration (0.72.6): - - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.72.6) - - React-Core/RCTVibrationHeaders (= 0.72.6) - - React-jsi (= 0.72.6) - - ReactCommon/turbomodule/core (= 0.72.6) - - React-rncore (0.72.6) - - React-runtimeexecutor (0.72.6): - - React-jsi (= 0.72.6) - - React-runtimescheduler (0.72.6): - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker - - React-debug - - React-jsi - - React-runtimeexecutor - - React-utils (0.72.6): - - glog - - RCT-Folly (= 2021.07.22.00) - - React-debug - - ReactCommon/turbomodule/bridging (0.72.6): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.72.6) - - React-cxxreact (= 0.72.6) - - React-jsi (= 0.72.6) - - React-logger (= 0.72.6) - - React-perflogger (= 0.72.6) - - ReactCommon/turbomodule/core (0.72.6): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.72.6) - - React-cxxreact (= 0.72.6) - - React-jsi (= 0.72.6) - - React-logger (= 0.72.6) - - React-perflogger (= 0.72.6) - - RNCAsyncStorage (1.19.3): - - React-Core - - RNCMaskedView (0.3.0): - - React-Core - - RNCPicker (2.5.1): - - React-Core - - RNGestureHandler (2.13.2): - - React-Core - - RNReanimated (3.5.0): - - RCT-Folly (= 2021.07.22.00) - - React-Core - - ReactCommon/turbomodule/core - - RNScreens (3.27.0): - - RCT-Folly (= 2021.07.22.00) - - React-Core - - RNSVG (13.14.0): - - React-Core - - SocketRocket (0.6.1) - - Yoga (1.14.0) - - YogaKit (1.18.1): - - Yoga (~> 1.14) - -DEPENDENCIES: - - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - - Flipper (= 0.182.0) - - Flipper-Boost-iOSX (= 1.76.0.1.11) - - Flipper-DoubleConversion (= 3.2.0.1) - - Flipper-Fmt (= 7.1.7) - - Flipper-Folly (= 2.6.10) - - Flipper-Glog (= 0.5.0.5) - - Flipper-PeerTalk (= 0.0.4) - - FlipperKit (= 0.182.0) - - FlipperKit/Core (= 0.182.0) - - FlipperKit/CppBridge (= 0.182.0) - - FlipperKit/FBCxxFollyDynamicConvert (= 0.182.0) - - FlipperKit/FBDefines (= 0.182.0) - - FlipperKit/FKPortForwarding (= 0.182.0) - - FlipperKit/FlipperKitHighlightOverlay (= 0.182.0) - - FlipperKit/FlipperKitLayoutPlugin (= 0.182.0) - - FlipperKit/FlipperKitLayoutTextSearchable (= 0.182.0) - - FlipperKit/FlipperKitNetworkPlugin (= 0.182.0) - - FlipperKit/FlipperKitReactPlugin (= 0.182.0) - - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.182.0) - - FlipperKit/SKIOSNetworkPlugin (= 0.182.0) - - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) - - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) - - React (from `../node_modules/react-native/`) - - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - - React-Codegen (from `build/generated/ios`) - - React-Core (from `../node_modules/react-native/`) - - React-Core/DevSupport (from `../node_modules/react-native/`) - - React-Core/RCTWebSocket (from `../node_modules/react-native/`) - - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) - - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) - - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) - - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) - - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - - React-logger (from `../node_modules/react-native/ReactCommon/logger`) - - react-native-pager-view (from `../node_modules/react-native-pager-view`) - - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - - "react-native-slider (from `../node_modules/@react-native-community/slider`)" - - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) - - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) - - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) - - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) - - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) - - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) - - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) - - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) - - React-RCTText (from `../node_modules/react-native/Libraries/Text`) - - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) - - React-rncore (from `../node_modules/react-native/ReactCommon`) - - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) - - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) - - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) - - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) - - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - - "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)" - - "RNCPicker (from `../node_modules/@react-native-picker/picker`)" - - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - - RNReanimated (from `../node_modules/react-native-reanimated`) - - RNScreens (from `../node_modules/react-native-screens`) - - RNSVG (from `../node_modules/react-native-svg`) - - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) - -SPEC REPOS: - trunk: - - CocoaAsyncSocket - - Flipper - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt - - Flipper-Folly - - Flipper-Glog - - Flipper-PeerTalk - - FlipperKit - - fmt - - libevent - - OpenSSL-Universal - - SocketRocket - - YogaKit - -EXTERNAL SOURCES: - boost: - :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" - DoubleConversion: - :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" - FBLazyVector: - :path: "../node_modules/react-native/Libraries/FBLazyVector" - FBReactNativeSpec: - :path: "../node_modules/react-native/React/FBReactNativeSpec" - glog: - :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" - hermes-engine: - :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" - :tag: hermes-2023-08-07-RNv0.72.4-813b2def12bc9df02654b3e3653ae4a68d0572e0 - RCT-Folly: - :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" - RCTRequired: - :path: "../node_modules/react-native/Libraries/RCTRequired" - RCTTypeSafety: - :path: "../node_modules/react-native/Libraries/TypeSafety" - React: - :path: "../node_modules/react-native/" - React-callinvoker: - :path: "../node_modules/react-native/ReactCommon/callinvoker" - React-Codegen: - :path: build/generated/ios - React-Core: - :path: "../node_modules/react-native/" - React-CoreModules: - :path: "../node_modules/react-native/React/CoreModules" - React-cxxreact: - :path: "../node_modules/react-native/ReactCommon/cxxreact" - React-debug: - :path: "../node_modules/react-native/ReactCommon/react/debug" - React-hermes: - :path: "../node_modules/react-native/ReactCommon/hermes" - React-jsi: - :path: "../node_modules/react-native/ReactCommon/jsi" - React-jsiexecutor: - :path: "../node_modules/react-native/ReactCommon/jsiexecutor" - React-jsinspector: - :path: "../node_modules/react-native/ReactCommon/jsinspector" - React-logger: - :path: "../node_modules/react-native/ReactCommon/logger" - react-native-pager-view: - :path: "../node_modules/react-native-pager-view" - react-native-safe-area-context: - :path: "../node_modules/react-native-safe-area-context" - react-native-slider: - :path: "../node_modules/@react-native-community/slider" - React-NativeModulesApple: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" - React-perflogger: - :path: "../node_modules/react-native/ReactCommon/reactperflogger" - React-RCTActionSheet: - :path: "../node_modules/react-native/Libraries/ActionSheetIOS" - React-RCTAnimation: - :path: "../node_modules/react-native/Libraries/NativeAnimation" - React-RCTAppDelegate: - :path: "../node_modules/react-native/Libraries/AppDelegate" - React-RCTBlob: - :path: "../node_modules/react-native/Libraries/Blob" - React-RCTImage: - :path: "../node_modules/react-native/Libraries/Image" - React-RCTLinking: - :path: "../node_modules/react-native/Libraries/LinkingIOS" - React-RCTNetwork: - :path: "../node_modules/react-native/Libraries/Network" - React-RCTSettings: - :path: "../node_modules/react-native/Libraries/Settings" - React-RCTText: - :path: "../node_modules/react-native/Libraries/Text" - React-RCTVibration: - :path: "../node_modules/react-native/Libraries/Vibration" - React-rncore: - :path: "../node_modules/react-native/ReactCommon" - React-runtimeexecutor: - :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" - React-runtimescheduler: - :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" - React-utils: - :path: "../node_modules/react-native/ReactCommon/react/utils" - ReactCommon: - :path: "../node_modules/react-native/ReactCommon" - RNCAsyncStorage: - :path: "../node_modules/@react-native-async-storage/async-storage" - RNCMaskedView: - :path: "../node_modules/@react-native-masked-view/masked-view" - RNCPicker: - :path: "../node_modules/@react-native-picker/picker" - RNGestureHandler: - :path: "../node_modules/react-native-gesture-handler" - RNReanimated: - :path: "../node_modules/react-native-reanimated" - RNScreens: - :path: "../node_modules/react-native-screens" - RNSVG: - :path: "../node_modules/react-native-svg" - Yoga: - :path: "../node_modules/react-native/ReactCommon/yoga" - -SPEC CHECKSUMS: - boost: 57d2868c099736d80fcd648bf211b4431e51a558 - CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 - FBLazyVector: 748c0ef74f2bf4b36cfcccf37916806940a64c32 - FBReactNativeSpec: 966f29e4e697de53a3b366355e8f57375c856ad9 - Flipper: 6edb735e6c3e332975d1b17956bcc584eccf5818 - Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c - Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 - Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b - Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 - Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 - Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 - FlipperKit: 2efad7007d6745a3f95e4034d547be637f89d3f6 - fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 - glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b - hermes-engine: 8057e75cfc1437b178ac86c8654b24e7fead7f60 - libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 - OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c - RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 - RCTRequired: 28469809442eb4eb5528462705f7d852948c8a74 - RCTTypeSafety: e9c6c409fca2cc584e5b086862d562540cb38d29 - React: 769f469909b18edfe934f0539fffb319c4c61043 - React-callinvoker: e48ce12c83706401251921896576710d81e54763 - React-Codegen: a136b8094d39fd071994eaa935366e6be2239cb1 - React-Core: e548a186fb01c3a78a9aeeffa212d625ca9511bf - React-CoreModules: d226b22d06ea1bc4e49d3c073b2c6cbb42265405 - React-cxxreact: 44a3560510ead6633b6e02f9fbbdd1772fb40f92 - React-debug: 238501490155574ae9f3f8dd1c74330eba30133e - React-hermes: 46e66dc854124d7645c20bfec0a6be9542826ecd - React-jsi: fbdaf4166bae60524b591b18c851b530c8cdb90c - React-jsiexecutor: 3bf18ff7cb03cd8dfdce08fbbc0d15058c1d71ae - React-jsinspector: 194e32c6aab382d88713ad3dd0025c5f5c4ee072 - React-logger: cebf22b6cf43434e471dc561e5911b40ac01d289 - react-native-pager-view: da490aa1f902c9a5aeecf0909cc975ad0e92e53e - react-native-safe-area-context: 7aa8e6d9d0f3100a820efb1a98af68aa747f9284 - react-native-slider: 1cdd6ba29675df21f30544253bf7351d3c2d68c4 - React-NativeModulesApple: 02e35e9a51e10c6422f04f5e4076a7c02243fff2 - React-perflogger: e3596db7e753f51766bceadc061936ef1472edc3 - React-RCTActionSheet: 17ab132c748b4471012abbcdcf5befe860660485 - React-RCTAnimation: c8bbaab62be5817d2a31c36d5f2571e3f7dcf099 - React-RCTAppDelegate: af1c7dace233deba4b933cd1d6491fe4e3584ad1 - React-RCTBlob: 1bcf3a0341eb8d6950009b1ddb8aefaf46996b8c - React-RCTImage: 670a3486b532292649b1aef3ffddd0b495a5cee4 - React-RCTLinking: bd7ab853144aed463903237e615fd91d11b4f659 - React-RCTNetwork: be86a621f3e4724758f23ad1fdce32474ab3d829 - React-RCTSettings: 4f3a29a6d23ffa639db9701bc29af43f30781058 - React-RCTText: adde32164a243103aaba0b1dc7b0a2599733873e - React-RCTVibration: 6bd85328388ac2e82ae0ca11afe48ad5555b483a - React-rncore: fda7b1ae5918fa7baa259105298a5487875a57c8 - React-runtimeexecutor: 57d85d942862b08f6d15441a0badff2542fd233c - React-runtimescheduler: f23e337008403341177fc52ee4ca94e442c17ede - React-utils: fa59c9a3375fb6f4aeb66714fd3f7f76b43a9f16 - ReactCommon: dd03c17275c200496f346af93a7b94c53f3093a4 - RNCAsyncStorage: c913ede1fa163a71cea118ed4670bbaaa4b511bb - RNCMaskedView: f7c74478c83c4fdfc5cf4df51f80c0dd5cf125c6 - RNCPicker: 529d564911e93598cc399b56cc0769ce3675f8c8 - RNGestureHandler: bb86e378287f7713baf3ca205423eb8109790022 - RNReanimated: 518aef663d1661d60e50610fe05ebec14b404739 - RNScreens: 3c2d122f5e08c192e254c510b212306da97d2581 - RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396 - SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 - Yoga: b76f1acfda8212aa16b7e26bcce3983230c82603 - YogaKit: f782866e155069a2cca2517aafea43200b01fd5a - -PODFILE CHECKSUM: c7912d2be242755f04acff6ad99bd3fb81683d33 - -COCOAPODS: 1.14.2 From 897e716ef37ef3148b719a5c99cee542144c1b97 Mon Sep 17 00:00:00 2001 From: Krzysztof Piaskowy Date: Tue, 16 Jan 2024 08:17:12 +0100 Subject: [PATCH 52/54] Add missing plugin config to example apps (#5583) ## Summary Our example app tests nested worklets, specifically the `WorkletExample` that includes the `ThrowErrorNestedWorkletDemo`. This test requires additional plugin configuration. Previously, this configuration was only present in the Example app. This PR adds this config to rest of our example apps. ## Test plan Run example: Screenshot 2024-01-15 at 15 05 31 --- FabricExample/babel.config.js | 2 +- MacOSExample/babel.config.js | 2 +- TVOSExample/babel.config.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FabricExample/babel.config.js b/FabricExample/babel.config.js index cdeeffd80e3..a76ca0fbb2a 100644 --- a/FabricExample/babel.config.js +++ b/FabricExample/babel.config.js @@ -1,4 +1,4 @@ module.exports = { presets: ['module:metro-react-native-babel-preset'], - plugins: ['../plugin'], + plugins: [['../plugin', {processNestedWorklets: true}]], }; diff --git a/MacOSExample/babel.config.js b/MacOSExample/babel.config.js index 9e8617ed3ad..0239ce97c6b 100644 --- a/MacOSExample/babel.config.js +++ b/MacOSExample/babel.config.js @@ -10,6 +10,6 @@ module.exports = { }, }, ], - '../plugin', + [['../plugin', {processNestedWorklets: true}]], ], }; diff --git a/TVOSExample/babel.config.js b/TVOSExample/babel.config.js index cdeeffd80e3..a76ca0fbb2a 100644 --- a/TVOSExample/babel.config.js +++ b/TVOSExample/babel.config.js @@ -1,4 +1,4 @@ module.exports = { presets: ['module:metro-react-native-babel-preset'], - plugins: ['../plugin'], + plugins: [['../plugin', {processNestedWorklets: true}]], }; From 2c4c8fac86ab975f202dd22d2ba74818887ab014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Bert?= <63123542+m-bert@users.noreply.github.com> Date: Tue, 16 Jan 2024 08:21:19 +0100 Subject: [PATCH 53/54] [LA Web] Show exiting animation when ancestors are rendered conditionally (#5515) ## Summary One thing that Layout Animations on web are missing is working animation when one of the ancestors is rendered conditionally. Consider this example: ```jsx {show && ( )} ``` We won't see `FadeOut` animation If we change `show` value to `false`, because parent of `Animated.View` is also removed. This PR aims to bring that functionality. ## Test plan Tested on the code below.

Test code ```jsx import React from 'react'; import { StyleSheet, View, Text, Pressable } from 'react-native'; import Animated, { FadeIn, FadeOut, FadeOutLeft, FadeOutRight, FadeOutUp, FadeOutDown, FadeInLeft, FadeInRight, FadeInUp, FadeInDown, } from 'react-native-reanimated'; const fadeAnimation = [ { enteringName: 'FadeIn', enteringAnimation: FadeIn, exitingName: 'FadeOut', exitingAnimation: FadeOut, }, { enteringName: 'FadeInLeft', enteringAnimation: FadeInLeft, exitingName: 'FadeOutLeft', exitingAnimation: FadeOutLeft, }, { enteringName: 'FadeInRight', enteringAnimation: FadeInRight, exitingName: 'FadeOutRight', exitingAnimation: FadeOutRight, }, { enteringName: 'FadeInUp', enteringAnimation: FadeInUp, exitingName: 'FadeOutUp', exitingAnimation: FadeOutUp, }, { enteringName: 'FadeInDown', enteringAnimation: FadeInDown, exitingName: 'FadeOutDown', exitingAnimation: FadeOutDown, }, ]; function Parent() { return ( {fadeAnimation.map((animation, i) => ( {animation.enteringName} ))} ); } export default function App() { const [show, setShow] = React.useState(true); return ( {show && ( )} setShow(!show)}> Click me! ); } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', }, box: { height: 50, width: 250, margin: 4, alignItems: 'center', justifyContent: 'center', }, enteringBox: { backgroundColor: '#b58df1', }, enteringText: { fontSize: 16, color: 'white', }, exitingBox: { borderColor: '#b58df1', borderStyle: 'dashed', borderWidth: 1, }, exitingText: { fontSize: 16, color: '#b58df1', }, button: { position: 'absolute', top: 250, left: 250, width: 100, height: 40, backgroundColor: '#b58df1', borderRadius: 5, display: 'flex', alignItems: 'center', justifyContent: 'space-around', userSelect: 'none', }, parentBorder: { margin: 5, padding: 5, borderWidth: 2, borderRadius: 10, borderColor: 'crimson', borderStyle: 'dashed', }, grandParentBorder: { margin: 5, padding: 5, borderWidth: 2, borderRadius: 10, borderColor: 'green', borderStyle: 'dotted', }, }); ```
--- .../createAnimatedComponent.tsx | 3 + src/reanimated2/js-reanimated/index.ts | 2 + .../web/animationsManager.ts | 2 +- .../layoutReanimation/web/componentStyle.ts | 66 +++++++++++ .../layoutReanimation/web/componentUtils.ts | 69 +---------- .../layoutReanimation/web/domUtils.ts | 109 ++++++++++++++++++ 6 files changed, 187 insertions(+), 64 deletions(-) create mode 100644 src/reanimated2/layoutReanimation/web/componentStyle.ts diff --git a/src/createAnimatedComponent/createAnimatedComponent.tsx b/src/createAnimatedComponent/createAnimatedComponent.tsx index 09747c34761..0afc1754743 100644 --- a/src/createAnimatedComponent/createAnimatedComponent.tsx +++ b/src/createAnimatedComponent/createAnimatedComponent.tsx @@ -54,6 +54,7 @@ import { import { updateLayoutAnimations } from '../reanimated2/UpdateLayoutAnimations'; import type { CustomConfig } from '../reanimated2/layoutReanimation/web/config'; import type { FlatList, FlatListProps } from 'react-native'; +import { addHTMLMutationObserver } from '../reanimated2/layoutReanimation/web/domUtils'; const IS_WEB = isWeb(); const IS_FABRIC = isFabric(); @@ -199,6 +200,8 @@ export function createAnimatedComponent( this.props.exiting && !getReducedMotionFromConfig(this.props.exiting as CustomConfig) ) { + addHTMLMutationObserver(); + startWebLayoutAnimation( this.props, this._component as HTMLElement, diff --git a/src/reanimated2/js-reanimated/index.ts b/src/reanimated2/js-reanimated/index.ts index 1e89ea1d540..0afd36233f4 100644 --- a/src/reanimated2/js-reanimated/index.ts +++ b/src/reanimated2/js-reanimated/index.ts @@ -70,6 +70,8 @@ export interface ReanimatedHTMLElement extends HTMLElement { _touchableNode: { setAttribute: (key: string, props: unknown) => void; }; + reanimatedDummy?: boolean; + removedAfterAnimation?: boolean; } export const _updatePropsJS = ( diff --git a/src/reanimated2/layoutReanimation/web/animationsManager.ts b/src/reanimated2/layoutReanimation/web/animationsManager.ts index 8aa5962e4bb..8622a76901a 100644 --- a/src/reanimated2/layoutReanimation/web/animationsManager.ts +++ b/src/reanimated2/layoutReanimation/web/animationsManager.ts @@ -14,12 +14,12 @@ import { getProcessedConfig, handleExitingAnimation, handleLayoutTransition, - makeElementVisible, setElementAnimation, } from './componentUtils'; import { areDOMRectsEqual } from './domUtils'; import type { TransformsStyle } from 'react-native'; import type { TransitionData } from './animationParser'; +import { makeElementVisible } from './componentStyle'; function chooseConfig>( animationType: LayoutAnimationType, diff --git a/src/reanimated2/layoutReanimation/web/componentStyle.ts b/src/reanimated2/layoutReanimation/web/componentStyle.ts new file mode 100644 index 00000000000..c06297aa152 --- /dev/null +++ b/src/reanimated2/layoutReanimation/web/componentStyle.ts @@ -0,0 +1,66 @@ +'use strict'; + +import { _updatePropsJS } from '../../js-reanimated'; +import type { ReanimatedHTMLElement } from '../../js-reanimated'; + +export const snapshots = new WeakMap(); + +export function makeElementVisible(element: HTMLElement, delay: number) { + if (delay === 0) { + _updatePropsJS( + { visibility: 'initial' }, + { _component: element as ReanimatedHTMLElement } + ); + } else { + setTimeout(() => { + _updatePropsJS( + { visibility: 'initial' }, + { _component: element as ReanimatedHTMLElement } + ); + }, delay * 1000); + } +} + +function fixElementPosition( + element: HTMLElement, + parent: HTMLElement, + snapshot: DOMRect +) { + const parentRect = parent.getBoundingClientRect(); + + const parentBorderTopValue = parseInt( + getComputedStyle(parent).borderTopWidth + ); + + const parentBorderLeftValue = parseInt( + getComputedStyle(parent).borderLeftWidth + ); + + const dummyRect = element.getBoundingClientRect(); + // getBoundingClientRect returns DOMRect with position of the element with respect to document body. + // However, using position `absolute` doesn't guarantee, that the dummy will be placed relative to body element. + // The trick below allows us to once again get position relative to body, by comparing snapshot with new position of the dummy. + if (dummyRect.top !== snapshot.top) { + element.style.top = `${ + snapshot.top - parentRect.top - parentBorderTopValue + }px`; + } + + if (dummyRect.left !== snapshot.left) { + element.style.left = `${ + snapshot.left - parentRect.left - parentBorderLeftValue + }px`; + } +} + +export function setDummyPosition(dummy: HTMLElement, snapshot: DOMRect) { + dummy.style.transform = ''; + dummy.style.position = 'absolute'; + dummy.style.top = `${snapshot.top}px`; + dummy.style.left = `${snapshot.left}px`; + dummy.style.width = `${snapshot.width}px`; + dummy.style.height = `${snapshot.height}px`; + dummy.style.margin = '0px'; // tmpElement has absolute position, so margin is not necessary + + fixElementPosition(dummy, dummy.parentElement!, snapshot); +} diff --git a/src/reanimated2/layoutReanimation/web/componentUtils.ts b/src/reanimated2/layoutReanimation/web/componentUtils.ts index dc77f034cc7..fbedc198a38 100644 --- a/src/reanimated2/layoutReanimation/web/componentUtils.ts +++ b/src/reanimated2/layoutReanimation/web/componentUtils.ts @@ -19,8 +19,7 @@ import { ReduceMotion } from '../../commonTypes'; import type { StyleProps } from '../../commonTypes'; import { isReducedMotion } from '../../PlatformChecker'; import { LayoutAnimationType } from '../animationBuilder/commonTypes'; - -const snapshots = new WeakMap(); +import { setDummyPosition, snapshots } from './componentStyle'; function getEasingFromConfig(config: CustomConfig): string { const easingName = @@ -132,22 +131,6 @@ export function saveSnapshot(element: HTMLElement) { snapshots.set(element, element.getBoundingClientRect()); } -export function makeElementVisible(element: HTMLElement, delay: number) { - if (delay === 0) { - _updatePropsJS( - { visibility: 'initial' }, - { _component: element as ReanimatedHTMLElement } - ); - } else { - setTimeout(() => { - _updatePropsJS( - { visibility: 'initial' }, - { _component: element as ReanimatedHTMLElement } - ); - }, delay * 1000); - } -} - export function setElementAnimation( element: HTMLElement, animationConfig: AnimationConfig, @@ -231,56 +214,13 @@ export function handleLayoutTransition( setElementAnimation(element, animationConfig, existingTransform); } -function fixElementPosition( - element: HTMLElement, - parent: HTMLElement, - snapshot: DOMRect -) { - const parentRect = parent.getBoundingClientRect(); - - const parentBorderTopValue = parseInt( - getComputedStyle(parent).borderTopWidth - ); - - const parentBorderLeftValue = parseInt( - getComputedStyle(parent).borderLeftWidth - ); - - const dummyRect = element.getBoundingClientRect(); - // getBoundingClientRect returns DOMRect with position of the element with respect to document body. - // However, using position `absolute` doesn't guarantee, that the dummy will be placed relative to body element. - // The trick below allows us to once again get position relative to body, by comparing snapshot with new position of the dummy. - if (dummyRect.top !== snapshot.top) { - element.style.top = `${ - snapshot.top - parentRect.top - parentBorderTopValue - }px`; - } - - if (dummyRect.left !== snapshot.left) { - element.style.left = `${ - snapshot.left - parentRect.left - parentBorderLeftValue - }px`; - } -} - -function setDummyPosition(dummy: HTMLElement, snapshot: DOMRect) { - dummy.style.transform = ''; - dummy.style.position = 'absolute'; - dummy.style.top = `${snapshot.top}px`; - dummy.style.left = `${snapshot.left}px`; - dummy.style.width = `${snapshot.width}px`; - dummy.style.height = `${snapshot.height}px`; - dummy.style.margin = '0px'; // tmpElement has absolute position, so margin is not necessary - - fixElementPosition(dummy, dummy.parentElement!, snapshot); -} - export function handleExitingAnimation( element: HTMLElement, animationConfig: AnimationConfig ) { const parent = element.offsetParent; - const dummy = element.cloneNode() as HTMLElement; + const dummy = element.cloneNode() as ReanimatedHTMLElement; + dummy.reanimatedDummy = true; element.style.animationName = ''; // We hide current element so only its copy with proper animation will be displayed @@ -299,6 +239,7 @@ export function handleExitingAnimation( parent?.appendChild(dummy); const snapshot = snapshots.get(element)!; + snapshots.set(dummy, snapshot); setDummyPosition(dummy, snapshot); @@ -306,6 +247,7 @@ export function handleExitingAnimation( dummy.onanimationend = function (event: AnimationEvent) { if (parent?.contains(dummy)) { + dummy.removedAfterAnimation = true; parent.removeChild(dummy); } @@ -315,6 +257,7 @@ export function handleExitingAnimation( dummy.addEventListener('animationcancel', () => { if (parent?.contains(dummy)) { + dummy.removedAfterAnimation = true; parent.removeChild(dummy); } }); diff --git a/src/reanimated2/layoutReanimation/web/domUtils.ts b/src/reanimated2/layoutReanimation/web/domUtils.ts index 72de2439a6b..9d8b4ef0747 100644 --- a/src/reanimated2/layoutReanimation/web/domUtils.ts +++ b/src/reanimated2/layoutReanimation/web/domUtils.ts @@ -1,6 +1,8 @@ 'use strict'; +import type { ReanimatedHTMLElement } from '../../js-reanimated'; import { isWindowAvailable } from '../../PlatformChecker'; +import { setDummyPosition, snapshots } from './componentStyle'; import { Animations } from './config'; import type { AnimationNames } from './config'; @@ -11,6 +13,8 @@ const CUSTOM_WEB_ANIMATIONS_ID = 'ReanimatedCustomWebAnimationsStyle'; const animationNameToIndex = new Map(); const animationNameList: string[] = []; +let isObserverSet = false; + /** * Creates `HTMLStyleElement`, inserts it into DOM and then inserts CSS rules into the stylesheet. * If style element already exists, nothing happens. @@ -131,6 +135,111 @@ export function scheduleAnimationCleanup( setTimeout(() => removeWebAnimation(animationName), timeoutValue); } +function reattachElementToAncestor(child: ReanimatedHTMLElement, parent: Node) { + const childSnapshot = snapshots.get(child); + + if (!childSnapshot) { + console.error('[Reanimated] Failed to obtain snapshot.'); + return; + } + + // We use that so we don't end up in infinite loop + child.removedAfterAnimation = true; + parent.appendChild(child); + + setDummyPosition(child, childSnapshot); + + const originalOnAnimationEnd = child.onanimationend; + + child.onanimationend = function (event: AnimationEvent) { + parent.removeChild(child); + + // Given that this function overrides onAnimationEnd, it won't be null + originalOnAnimationEnd?.call(this, event); + }; +} + +function findDescendantWithExitingAnimation( + node: ReanimatedHTMLElement, + root: Node +) { + if (node.reanimatedDummy && node.removedAfterAnimation === undefined) { + reattachElementToAncestor(node, root); + } + + const children = Array.from(node.children); + + for (let i = 0; i < children.length; ++i) { + findDescendantWithExitingAnimation( + children[i] as ReanimatedHTMLElement, + root + ); + } +} + +type FiberNodeKey = `__reactFiber${string}`; + +interface FiberNode { + memoizedProps?: { + navigation?: unknown; + }; + + child?: FiberNode; +} + +type WithFiberNode = { + [key: FiberNodeKey]: FiberNode; +}; + +type MaybeWithFiberNode = Partial; + +function checkIfScreenWasChanged( + mutationTarget: ReanimatedHTMLElement & MaybeWithFiberNode +) { + let reactFiberKey: FiberNodeKey = '__reactFiber'; + + for (const key of Object.keys(mutationTarget)) { + if (key.startsWith('__reactFiber')) { + reactFiberKey = key as FiberNodeKey; + break; + } + } + + return ( + mutationTarget[reactFiberKey]?.child?.memoizedProps?.navigation !== + undefined + ); +} + +export function addHTMLMutationObserver() { + if (isObserverSet || !isWindowAvailable()) { + return; + } + + isObserverSet = true; + + const observer = new MutationObserver((mutationsList) => { + const rootMutation = mutationsList[mutationsList.length - 1]; + + if ( + checkIfScreenWasChanged( + rootMutation.target as ReanimatedHTMLElement & MaybeWithFiberNode + ) + ) { + return; + } + + for (let i = 0; i < rootMutation.removedNodes.length; ++i) { + findDescendantWithExitingAnimation( + rootMutation.removedNodes[i] as ReanimatedHTMLElement, + rootMutation.target + ); + } + }); + + observer.observe(document.body, { childList: true, subtree: true }); +} + export function areDOMRectsEqual(r1: DOMRect, r2: DOMRect) { // There are 4 more fields, but checking these should suffice return ( From c39f904101cf6efb6b0e533da6f89fc3b40b2508 Mon Sep 17 00:00:00 2001 From: Alex Cynk Date: Tue, 16 Jan 2024 10:28:44 +0100 Subject: [PATCH 54/54] Add new spring feature - clamp (#5195) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Add possibility to define limits that won't be crossed by bouncing spring. In simplification we can assume that range of bounces is related just with damping ratio, therefore we recalculate new damping ratio, that satisfies our expectation - the spring moves within its range. Simplified alghoritm: 1. Calculate $\mathtt{zeta}$ (dampingRatio), $\mathtt{omega1}$ and $\mathtt{omega0}$ 2. Calculate such a two values for $\mathtt{zeta}$ that the extrema match both edges of the range exactly 3. Compare the calculate $\mathtt{zeta}$ s with the provided damping ratio. Substitute the damping ratio with the biggest of the values 5. Ignore the fact that now values for $\mathtt{omega0}$ and $\mathtt{omega1}$ are outdated * The spring still looks like a real physical one and seems very convincing 6. We changed damping ratio, but the duration stays the same 🥳 ## Examples Two examples with different arbitrary chosen config.
Example 1Example 2
https://github.com/software-mansion/react-native-reanimated/assets/56199675/81857b94-1942-4e52-b7b3-fceb3d7d00a3 https://github.com/software-mansion/react-native-reanimated/assets/56199675/43ebadf6-bfc5-4cc9-862f-a47e17fa84d8
## Test plan
Resting example - code ```javascript import Animated, { useSharedValue, useAnimatedStyle, withSpring, } from 'react-native-reanimated'; import { View, Text, Button, StyleSheet, ViewStyle } from 'react-native'; import React, { useState } from 'react'; const VIOLET = '#b58df1'; const BORDER_WIDTH = 4; const FRAME_WIDTH = 300; const LOWER_CLAMP = 120; const UPPER_CLAMP = 220; function renderFramedExample(testedStyle: ViewStyle, description: string) { return ( <> {description} ); } export default function AnimatedStyleUpdateExample() { const randomWidth = useSharedValue(100); const [toggle, setToggle] = useState(false); const config = { duration: 5000, dampingRatio: 0.4, }; const clampedStyle = useAnimatedStyle(() => { return { width: withSpring(randomWidth.value, { ...config, clamp: [LOWER_CLAMP, UPPER_CLAMP], }), }; }); const style = useAnimatedStyle(() => { return { width: withSpring(randomWidth.value, config), }; }); return ( {renderFramedExample(clampedStyle, 'Clamp example')} {renderFramedExample(style, 'Default')}
--- __tests__/spring.test.tsx | 46 ++++++++++ app/.eslintrc.js | 1 + app/src/examples/PendulumExample.tsx | 24 +++-- app/src/examples/WithClampExample.tsx | 110 +++++++++++++++++------ src/reanimated2/animation/spring.ts | 6 ++ src/reanimated2/animation/springUtils.ts | 85 +++++++++++++++++- 6 files changed, 226 insertions(+), 46 deletions(-) create mode 100644 __tests__/spring.test.tsx diff --git a/__tests__/spring.test.tsx b/__tests__/spring.test.tsx new file mode 100644 index 00000000000..d44380f6095 --- /dev/null +++ b/__tests__/spring.test.tsx @@ -0,0 +1,46 @@ +import { + SpringAnimation, + bisectRoot, + scaleZetaToMatchClamps, +} from '../src/reanimated2/animation/springUtils'; + +describe('Spring utils', () => { + test.each([ + [[0, 5, (x) => x - 3, 20], 3], + [[0, 5, (x) => x * x - 9, 20], 3], + [[0, 5, (x) => x * x - 2, 20], Math.sqrt(2)], + [[0, 5, (x) => x - 1 / x - 1, 20], (1 + Math.sqrt(5)) / 2], + ] as const)('Bisect root', (testCase, result) => { + const [min, max, func, maxIterations] = testCase; + const calculatedOutput = bisectRoot({ + min, + max, + func, + maxIterations, + }); + expect(calculatedOutput).toBeCloseTo(result); + }); + + const animation = { + startValue: 0, + toValue: 10, + zeta: 0.5, + } as SpringAnimation; + + test.each([ + { min: -1, max: 10 }, + { min: -100, max: 100 }, + { min: -40, max: 50 }, + { min: -0.005, max: 10.005 }, + ] as const)('Test scaleZetaToMatchClamps', (clamp) => { + const zeta = scaleZetaToMatchClamps(animation, clamp); + const extremum1 = Math.exp(-zeta * Math.PI); + const extremum2 = Math.exp(-zeta * 2 * Math.PI); + + expect(extremum1).toBeLessThan(clamp.max); + expect(extremum1).toBeGreaterThan(clamp.min); + + expect(extremum2).toBeLessThan(clamp.max); + expect(extremum2).toBeGreaterThan(clamp.min); + }); +}); diff --git a/app/.eslintrc.js b/app/.eslintrc.js index 4fc8041ef39..fe55f881606 100644 --- a/app/.eslintrc.js +++ b/app/.eslintrc.js @@ -10,5 +10,6 @@ module.exports = { 'react-native/no-unused-styles': 'error', 'react-native/no-raw-text': 'off', // This rule is great, we don't enable it because of its performance. If we ever find similar rule we should enable it. 'react-native/no-single-element-style-arrays': 'error', + 'react/jsx-fragments': ['error', 'syntax'], }, }; diff --git a/app/src/examples/PendulumExample.tsx b/app/src/examples/PendulumExample.tsx index 3336000c5db..4cddd82f9a7 100644 --- a/app/src/examples/PendulumExample.tsx +++ b/app/src/examples/PendulumExample.tsx @@ -166,20 +166,16 @@ export default function SpringExample() {
- - {fields.map((item) => { - return ( - { - item.setValue(value); - }} - key={item.fieldName} - /> - ); - })} - + {fields.map((item) => { + return ( + + ); + })} ); } diff --git a/app/src/examples/WithClampExample.tsx b/app/src/examples/WithClampExample.tsx index 5172d6d0e20..b4e618fabf8 100644 --- a/app/src/examples/WithClampExample.tsx +++ b/app/src/examples/WithClampExample.tsx @@ -3,7 +3,6 @@ import Animated, { useAnimatedStyle, withSpring, withClamp, - withDelay, } from 'react-native-reanimated'; import { View, Text, Button, StyleSheet, ViewStyle } from 'react-native'; import React, { useState } from 'react'; @@ -17,7 +16,16 @@ const CLAMP_MARKER_HEIGHT = 40; const LOWER_BOUND = 120; const UPPER_BOUND = 220; -function renderExample(testedStyle: ViewStyle, description: string) { +const LOWER_SPRING_TO_VALUE = 150; +const UPPER_SPRING_TO_VALUE = 200; + +function Example({ + testedStyle, + description, +}: { + testedStyle: ViewStyle; + description: string; +}) { return ( <> {description} @@ -27,23 +35,47 @@ function renderExample(testedStyle: ViewStyle, description: string) { borderWidth: BORDER_WIDTH, borderColor: VIOLET, }}> - + + + + - + + + + ); @@ -59,7 +91,7 @@ export default function AnimatedStyleUpdateExample() { dampingRatio: 0.075, }; - const clampedStyle = useAnimatedStyle(() => { + const clampedStyleWithAnimationModifier = useAnimatedStyle(() => { return { width: withClamp( { min: LOWER_BOUND, max: UPPER_BOUND }, @@ -67,14 +99,16 @@ export default function AnimatedStyleUpdateExample() { ), }; }); - const clampedStyleWithDelay = useAnimatedStyle(() => { + + const clampedStyleWithConfig = useAnimatedStyle(() => { return { - width: withClamp( - { min: LOWER_BOUND, max: UPPER_BOUND }, - withDelay(0, withSpring(randomWidth.value, config)) - ), + width: withSpring(randomWidth.value, { + ...config, + clamp: { min: LOWER_BOUND, max: UPPER_BOUND }, + }), }; }); + const style = useAnimatedStyle(() => { return { width: withSpring(randomWidth.value, config), @@ -96,9 +130,15 @@ export default function AnimatedStyleUpdateExample() { return ( - {renderExample(clampedStyle, 'Clamped spring')} - {renderExample(clampedStyleWithDelay, 'Clamped spring with delay')} - {renderExample(style, 'Default spring')} + + + { - randomWidth.value = toggle ? 150 : 200; + randomWidth.value = toggle + ? LOWER_SPRING_TO_VALUE + : UPPER_SPRING_TO_VALUE; rotation.value = toggle ? '380deg' : '-120deg'; setToggle(!toggle); }} @@ -123,13 +165,23 @@ const styles = StyleSheet.create({ flexDirection: 'column', padding: CLAMP_MARKER_HEIGHT, }, + toValueMarker: { + position: 'absolute', + margin: 0, + opacity: 1, + zIndex: 100, + height: CLAMP_MARKER_HEIGHT / 2, + backgroundColor: VIOLET, + }, clampMarker: { + position: 'absolute', margin: 0, opacity: 0.5, - height: CLAMP_MARKER_HEIGHT, + height: 100, backgroundColor: VIOLET, }, movingBox: { + zIndex: 1, height: 100, opacity: 0.5, backgroundColor: 'black', diff --git a/src/reanimated2/animation/spring.ts b/src/reanimated2/animation/spring.ts index 96edfccccce..68dcf4410a7 100644 --- a/src/reanimated2/animation/spring.ts +++ b/src/reanimated2/animation/spring.ts @@ -19,6 +19,7 @@ import { underDampedSpringCalculations, criticallyDampedSpringCalculations, isAnimationTerminatingCalculation, + scaleZetaToMatchClamps, checkIfConfigIsValid, } from './springUtils'; @@ -58,6 +59,7 @@ export const withSpring = (( duration: 2000, dampingRatio: 0.5, reduceMotion: undefined, + clamp: undefined, } as const; const config: DefaultSpringConfig & SpringConfigInner = { @@ -210,6 +212,10 @@ export const withSpring = (( animation.zeta = zeta; animation.omega0 = omega0; animation.omega1 = omega1; + + if (config.clamp !== undefined) { + animation.zeta = scaleZetaToMatchClamps(animation, config.clamp); + } } animation.lastTimestamp = previousAnimation?.lastTimestamp || now; diff --git a/src/reanimated2/animation/springUtils.ts b/src/reanimated2/animation/springUtils.ts index 2c0e979dc87..466440d3edd 100644 --- a/src/reanimated2/animation/springUtils.ts +++ b/src/reanimated2/animation/springUtils.ts @@ -34,18 +34,21 @@ export type SpringConfig = { damping?: number; duration?: never; dampingRatio?: never; + clamp?: never; } | { mass?: never; damping?: never; duration?: number; dampingRatio?: number; + clamp?: { min?: number; max?: number }; } ); -// This type contains all the properties from SpringConfig, which are changed to be required, except for optional 'reduceMotion' +// This type contains all the properties from SpringConfig, which are changed to be required, +// except for optional 'reduceMotion' and 'clamp' export type DefaultSpringConfig = { - [K in keyof Required]: K extends 'reduceMotion' + [K in keyof Required]: K extends 'reduceMotion' | 'clamp' ? Required[K] | undefined : Required[K]; }; @@ -96,6 +99,14 @@ export function checkIfConfigIsValid(config: DefaultSpringConfig): boolean { errorMessage += `, duration can't be negative, got ${config.duration}`; } + if ( + config.clamp?.min && + config.clamp?.max && + config.clamp.min > config.clamp.max + ) { + errorMessage += `, clamp.min should be lower than clamp.max, got clamp: {min: ${config.clamp.min}, max: ${config.clamp.max}} `; + } + if (errorMessage !== '') { console.warn('[Reanimated] Invalid spring config' + errorMessage); } @@ -103,7 +114,8 @@ export function checkIfConfigIsValid(config: DefaultSpringConfig): boolean { return errorMessage === ''; } -function bisectRoot({ +// ts-prune-ignore-next This function is exported to be tested +export function bisectRoot({ min, max, func, @@ -166,6 +178,73 @@ export function initialCalculations( } } +/** We make an assumption that we can manipulate zeta without changing duration of movement. + * According to theory this change is small and tests shows that we can indeed ignore it. + */ +export function scaleZetaToMatchClamps( + animation: SpringAnimation, + clamp: { min?: number; max?: number } +): number { + 'worklet'; + const { zeta, toValue, startValue } = animation; + const toValueNum = Number(toValue); + + if (toValueNum === startValue) { + return zeta; + } + + const [firstBound, secondBound] = + toValueNum - startValue > 0 + ? [clamp.min, clamp.max] + : [clamp.max, clamp.min]; + + /** The extrema we get from equation below are relative (we obtain a ratio), + * To get absolute extrema we convert it as follows: + * + * AbsoluteExtremum = startValue ± RelativeExtremum * (toValue - startValue) + * Where ± denotes: + * + if extremum is over the target + * - otherwise + */ + + const relativeExtremum1 = + secondBound !== undefined + ? Math.abs((secondBound - toValueNum) / (toValueNum - startValue)) + : undefined; + + const relativeExtremum2 = + firstBound !== undefined + ? Math.abs((firstBound - toValueNum) / (toValueNum - startValue)) + : undefined; + + /** Use this formula http://hyperphysics.phy-astr.gsu.edu/hbase/oscda.html to calculate + * first two extrema. These extrema are located where cos = +- 1 + * + * Therefore the first two extrema are: + * + * Math.exp(-zeta * Math.PI); (over the target) + * Math.exp(-zeta * 2 * Math.PI); (before the target) + */ + + const newZeta1 = + relativeExtremum1 !== undefined + ? Math.abs(Math.log(relativeExtremum1) / Math.PI) + : undefined; + + const newZeta2 = + relativeExtremum2 !== undefined + ? Math.abs(Math.log(relativeExtremum2) / (2 * Math.PI)) + : undefined; + + const zetaSatisfyingClamp = [newZeta1, newZeta2].filter( + (x: number | undefined): x is number => x !== undefined + ); + // The bigger is zeta the smaller are bounces, we return the biggest one + // because it should satisfy all conditions + return Math.max(...zetaSatisfyingClamp, zeta); +} + +/** Runs before initial */ export function calculateNewMassToMatchDuration( x0: number, config: DefaultSpringConfig & SpringConfigInner,