feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,4 @@
'use strict';
export {};
//# sourceMappingURL=commonTypes.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":[],"sources":["commonTypes.ts"],"sourcesContent":["'use strict';\nimport type { Component, MutableRefObject } from 'react';\nimport type {\n AnimatedPropsAdapterFunction,\n ShadowNodeWrapper,\n SharedValue,\n WorkletFunction,\n} from '../commonTypes';\nimport type {\n ImageStyle,\n NativeSyntheticEvent,\n TextStyle,\n ViewStyle,\n NativeScrollEvent,\n} from 'react-native';\nimport type { ViewDescriptorsSet, ViewRefSet } from '../ViewDescriptorsSet';\nimport type { AnimatedStyle } from '../helperTypes';\n\nexport type DependencyList = Array<unknown> | undefined;\n\nexport interface Descriptor {\n tag: number;\n name: string;\n shadowNodeWrapper: ShadowNodeWrapper;\n}\n\nexport interface AnimatedRef<T extends Component> {\n (component?: T):\n | number // Paper\n | ShadowNodeWrapper // Fabric\n | HTMLElement; // web\n current: T | null;\n getTag: () => number;\n}\n\n// Might make that type generic if it's ever needed.\nexport type AnimatedRefOnJS = AnimatedRef<Component>;\n\n/**\n * `AnimatedRef` is mapped to this type on the UI thread via a shareable handle.\n */\nexport type AnimatedRefOnUI = {\n (): number | ShadowNodeWrapper | null;\n /**\n * @remarks `viewName` is required only on iOS with Paper and it's value is null on other platforms.\n */\n viewName: SharedValue<string | null>;\n};\n\ntype ReanimatedPayload = {\n eventName: string;\n};\n\n/**\n * This utility type is to convert type of events that would normally be\n * sent by React Native (they have `nativeEvent` field) to the type\n * that is sent by Reanimated.\n */\nexport type ReanimatedEvent<Event extends object> = ReanimatedPayload &\n (Event extends {\n nativeEvent: infer NativeEvent extends object;\n }\n ? NativeEvent\n : Event);\n\nexport type EventPayload<Event extends object> = Event extends {\n nativeEvent: infer NativeEvent extends object;\n}\n ? NativeEvent\n : Omit<Event, 'eventName'>;\n\nexport type NativeEventWrapper<Event extends object> = {\n nativeEvent: Event;\n};\n\nexport type DefaultStyle = ViewStyle | ImageStyle | TextStyle;\n\nexport type RNNativeScrollEvent = NativeSyntheticEvent<NativeScrollEvent>;\n\nexport type ReanimatedScrollEvent = ReanimatedEvent<RNNativeScrollEvent>;\n\nexport interface IWorkletEventHandler<Event extends object> {\n updateEventHandler: (\n newWorklet: (event: ReanimatedEvent<Event>) => void,\n newEvents: string[]\n ) => void;\n registerForEvents: (viewTag: number, fallbackEventName?: string) => void;\n unregisterFromEvents: (viewTag: number) => void;\n}\n\nexport interface AnimatedStyleHandle<\n Style extends DefaultStyle = DefaultStyle\n> {\n viewDescriptors: ViewDescriptorsSet;\n initial: {\n value: AnimatedStyle<Style>;\n updater: () => AnimatedStyle<Style>;\n };\n /**\n * @remarks `viewsRef` is only defined in Web implementation.\n */\n viewsRef: ViewRefSet<unknown> | undefined;\n}\n\nexport interface JestAnimatedStyleHandle<\n Style extends DefaultStyle = DefaultStyle\n> extends AnimatedStyleHandle<Style> {\n jestAnimatedStyle: MutableRefObject<AnimatedStyle<Style>>;\n}\n\nexport type UseAnimatedStyleInternal<Style extends DefaultStyle> = (\n updater: WorkletFunction<[], Style> | (() => Style),\n dependencies?: DependencyList | null,\n adapters?:\n | AnimatedPropsAdapterFunction\n | AnimatedPropsAdapterFunction[]\n | null,\n isAnimatedProps?: boolean\n) => AnimatedStyleHandle<Style> | JestAnimatedStyleHandle<Style>;\n"],"mappings":"AAAA,YAAY;;AAAC","ignoreList":[]}

View File

@@ -0,0 +1,19 @@
'use strict';
export { useAnimatedProps } from './useAnimatedProps';
export { useWorkletCallback } from './useWorkletCallback';
export { useSharedValue } from './useSharedValue';
export { useReducedMotion } from './useReducedMotion';
export { useAnimatedStyle } from './useAnimatedStyle';
export { useAnimatedGestureHandler } from './useAnimatedGestureHandler';
export { useAnimatedReaction } from './useAnimatedReaction';
export { useAnimatedRef } from './useAnimatedRef';
export { useAnimatedScrollHandler } from './useAnimatedScrollHandler';
export { useDerivedValue } from './useDerivedValue';
export { useAnimatedSensor } from './useAnimatedSensor';
export { useFrameCallback } from './useFrameCallback';
export { useAnimatedKeyboard } from './useAnimatedKeyboard';
export { useScrollViewOffset } from './useScrollViewOffset';
export { useEvent } from './useEvent';
export { useHandler } from './useHandler';
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useAnimatedProps","useWorkletCallback","useSharedValue","useReducedMotion","useAnimatedStyle","useAnimatedGestureHandler","useAnimatedReaction","useAnimatedRef","useAnimatedScrollHandler","useDerivedValue","useAnimatedSensor","useFrameCallback","useAnimatedKeyboard","useScrollViewOffset","useEvent","useHandler"],"sources":["index.ts"],"sourcesContent":["'use strict';\nexport type {\n DependencyList,\n AnimatedRef,\n ReanimatedScrollEvent as ScrollEvent,\n ReanimatedEvent,\n} from './commonTypes';\nexport { useAnimatedProps } from './useAnimatedProps';\nexport { useWorkletCallback } from './useWorkletCallback';\nexport { useSharedValue } from './useSharedValue';\nexport { useReducedMotion } from './useReducedMotion';\nexport { useAnimatedStyle } from './useAnimatedStyle';\nexport { useAnimatedGestureHandler } from './useAnimatedGestureHandler';\nexport type {\n GestureHandlerEvent,\n GestureHandlers,\n} from './useAnimatedGestureHandler';\nexport { useAnimatedReaction } from './useAnimatedReaction';\nexport { useAnimatedRef } from './useAnimatedRef';\nexport { useAnimatedScrollHandler } from './useAnimatedScrollHandler';\nexport type {\n ScrollHandler,\n ScrollHandlers,\n ScrollHandlerProcessed,\n ScrollHandlerInternal,\n} from './useAnimatedScrollHandler';\nexport { useDerivedValue } from './useDerivedValue';\nexport type { DerivedValue } from './useDerivedValue';\nexport { useAnimatedSensor } from './useAnimatedSensor';\nexport { useFrameCallback } from './useFrameCallback';\nexport type { FrameCallback } from './useFrameCallback';\nexport { useAnimatedKeyboard } from './useAnimatedKeyboard';\nexport { useScrollViewOffset } from './useScrollViewOffset';\nexport type {\n EventHandler,\n EventHandlerProcessed,\n EventHandlerInternal,\n} from './useEvent';\nexport { useEvent } from './useEvent';\nexport type { UseHandlerContext } from './useHandler';\nexport { useHandler } from './useHandler';\n"],"mappings":"AAAA,YAAY;;AAOZ,SAASA,gBAAgB,QAAQ,oBAAoB;AACrD,SAASC,kBAAkB,QAAQ,sBAAsB;AACzD,SAASC,cAAc,QAAQ,kBAAkB;AACjD,SAASC,gBAAgB,QAAQ,oBAAoB;AACrD,SAASC,gBAAgB,QAAQ,oBAAoB;AACrD,SAASC,yBAAyB,QAAQ,6BAA6B;AAKvE,SAASC,mBAAmB,QAAQ,uBAAuB;AAC3D,SAASC,cAAc,QAAQ,kBAAkB;AACjD,SAASC,wBAAwB,QAAQ,4BAA4B;AAOrE,SAASC,eAAe,QAAQ,mBAAmB;AAEnD,SAASC,iBAAiB,QAAQ,qBAAqB;AACvD,SAASC,gBAAgB,QAAQ,oBAAoB;AAErD,SAASC,mBAAmB,QAAQ,uBAAuB;AAC3D,SAASC,mBAAmB,QAAQ,uBAAuB;AAM3D,SAASC,QAAQ,QAAQ,YAAY;AAErC,SAASC,UAAU,QAAQ,cAAc","ignoreList":[]}

View File

@@ -0,0 +1,65 @@
'use strict';
import { useHandler } from './useHandler';
import { useEvent } from './useEvent';
const EVENT_TYPE = {
UNDETERMINED: 0,
FAILED: 1,
BEGAN: 2,
CANCELLED: 3,
ACTIVE: 4,
END: 5
};
// This type comes from React Native Gesture Handler
// import type { PanGestureHandlerGestureEvent as DefaultEvent } from 'react-native-gesture-handler';
/**
* @deprecated useAnimatedGestureHandler is an old API which is no longer supported.
*
* Please check https://docs.swmansion.com/react-native-gesture-handler/docs/guides/upgrading-to-2/
* for information about how to migrate to `react-native-gesture-handler` v2
*/
export function useAnimatedGestureHandler(handlers, dependencies) {
const {
context,
doDependenciesDiffer,
useWeb
} = useHandler(handlers, dependencies);
const handler = e => {
'worklet';
const event = useWeb ?
// On Web we get events straight from React Native and they don't have
// the `eventName` field there. To simplify the types here we just
// cast it as the field was available.
e.nativeEvent : e;
if (event.state === EVENT_TYPE.BEGAN && handlers.onStart) {
handlers.onStart(event, context);
}
if (event.state === EVENT_TYPE.ACTIVE && handlers.onActive) {
handlers.onActive(event, context);
}
if (event.oldState === EVENT_TYPE.ACTIVE && event.state === EVENT_TYPE.END && handlers.onEnd) {
handlers.onEnd(event, context);
}
if (event.oldState === EVENT_TYPE.BEGAN && event.state === EVENT_TYPE.FAILED && handlers.onFail) {
handlers.onFail(event, context);
}
if (event.oldState === EVENT_TYPE.ACTIVE && event.state === EVENT_TYPE.CANCELLED && handlers.onCancel) {
handlers.onCancel(event, context);
}
if ((event.oldState === EVENT_TYPE.BEGAN || event.oldState === EVENT_TYPE.ACTIVE) && event.state !== EVENT_TYPE.BEGAN && event.state !== EVENT_TYPE.ACTIVE && handlers.onFinish) {
handlers.onFinish(event, context, event.state === EVENT_TYPE.CANCELLED || event.state === EVENT_TYPE.FAILED);
}
};
if (useWeb) {
return handler;
}
// eslint-disable-next-line react-hooks/rules-of-hooks
return useEvent(handler, ['onGestureHandlerStateChange', 'onGestureHandlerEvent'], doDependenciesDiffer
// This is not correct but we want to make GH think it receives a function.
);
}
//# sourceMappingURL=useAnimatedGestureHandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,53 @@
'use strict';
import { useEffect, useRef } from 'react';
import { makeMutable, subscribeForKeyboardEvents, unsubscribeFromKeyboardEvents } from '../core';
import { KeyboardState } from '../commonTypes';
/**
* Lets you synchronously get the position and state of the keyboard.
*
* @param options - An additional keyboard configuration options.
* @returns An object with the current keyboard `height` and `state` as [shared values](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#shared-value).
* @see https://docs.swmansion.com/react-native-reanimated/docs/device/useAnimatedKeyboard
*/
export function useAnimatedKeyboard(options = {
isStatusBarTranslucentAndroid: false
}) {
const ref = useRef(null);
const listenerId = useRef(-1);
const isSubscribed = useRef(false);
if (ref.current === null) {
const keyboardEventData = {
state: makeMutable(KeyboardState.UNKNOWN),
height: makeMutable(0)
};
listenerId.current = subscribeForKeyboardEvents((state, height) => {
'worklet';
keyboardEventData.state.value = state;
keyboardEventData.height.value = height;
}, options);
ref.current = keyboardEventData;
isSubscribed.current = true;
}
useEffect(() => {
if (isSubscribed.current === false && ref.current !== null) {
const keyboardEventData = ref.current;
// subscribe again after Fast Refresh
listenerId.current = subscribeForKeyboardEvents((state, height) => {
'worklet';
keyboardEventData.state.value = state;
keyboardEventData.height.value = height;
}, options);
isSubscribed.current = true;
}
return () => {
unsubscribeFromKeyboardEvents(listenerId.current);
isSubscribed.current = false;
};
}, []);
return ref.current;
}
//# sourceMappingURL=useAnimatedKeyboard.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useEffect","useRef","makeMutable","subscribeForKeyboardEvents","unsubscribeFromKeyboardEvents","KeyboardState","useAnimatedKeyboard","options","isStatusBarTranslucentAndroid","ref","listenerId","isSubscribed","current","keyboardEventData","state","UNKNOWN","height","value"],"sources":["useAnimatedKeyboard.ts"],"sourcesContent":["'use strict';\nimport { useEffect, useRef } from 'react';\nimport {\n makeMutable,\n subscribeForKeyboardEvents,\n unsubscribeFromKeyboardEvents,\n} from '../core';\nimport type {\n AnimatedKeyboardInfo,\n AnimatedKeyboardOptions,\n} from '../commonTypes';\nimport { KeyboardState } from '../commonTypes';\n\n/**\n * Lets you synchronously get the position and state of the keyboard.\n *\n * @param options - An additional keyboard configuration options.\n * @returns An object with the current keyboard `height` and `state` as [shared values](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#shared-value).\n * @see https://docs.swmansion.com/react-native-reanimated/docs/device/useAnimatedKeyboard\n */\nexport function useAnimatedKeyboard(\n options: AnimatedKeyboardOptions = { isStatusBarTranslucentAndroid: false }\n): AnimatedKeyboardInfo {\n const ref = useRef<AnimatedKeyboardInfo | null>(null);\n const listenerId = useRef<number>(-1);\n const isSubscribed = useRef<boolean>(false);\n\n if (ref.current === null) {\n const keyboardEventData: AnimatedKeyboardInfo = {\n state: makeMutable<KeyboardState>(KeyboardState.UNKNOWN),\n height: makeMutable(0),\n };\n listenerId.current = subscribeForKeyboardEvents((state, height) => {\n 'worklet';\n keyboardEventData.state.value = state;\n keyboardEventData.height.value = height;\n }, options);\n ref.current = keyboardEventData;\n isSubscribed.current = true;\n }\n useEffect(() => {\n if (isSubscribed.current === false && ref.current !== null) {\n const keyboardEventData = ref.current;\n // subscribe again after Fast Refresh\n listenerId.current = subscribeForKeyboardEvents((state, height) => {\n 'worklet';\n keyboardEventData.state.value = state;\n keyboardEventData.height.value = height;\n }, options);\n isSubscribed.current = true;\n }\n return () => {\n unsubscribeFromKeyboardEvents(listenerId.current);\n isSubscribed.current = false;\n };\n }, []);\n return ref.current;\n}\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,SAAS,EAAEC,MAAM,QAAQ,OAAO;AACzC,SACEC,WAAW,EACXC,0BAA0B,EAC1BC,6BAA6B,QACxB,SAAS;AAKhB,SAASC,aAAa,QAAQ,gBAAgB;;AAE9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CACjCC,OAAgC,GAAG;EAAEC,6BAA6B,EAAE;AAAM,CAAC,EACrD;EACtB,MAAMC,GAAG,GAAGR,MAAM,CAA8B,IAAI,CAAC;EACrD,MAAMS,UAAU,GAAGT,MAAM,CAAS,CAAC,CAAC,CAAC;EACrC,MAAMU,YAAY,GAAGV,MAAM,CAAU,KAAK,CAAC;EAE3C,IAAIQ,GAAG,CAACG,OAAO,KAAK,IAAI,EAAE;IACxB,MAAMC,iBAAuC,GAAG;MAC9CC,KAAK,EAAEZ,WAAW,CAAgBG,aAAa,CAACU,OAAO,CAAC;MACxDC,MAAM,EAAEd,WAAW,CAAC,CAAC;IACvB,CAAC;IACDQ,UAAU,CAACE,OAAO,GAAGT,0BAA0B,CAAC,CAACW,KAAK,EAAEE,MAAM,KAAK;MACjE,SAAS;;MACTH,iBAAiB,CAACC,KAAK,CAACG,KAAK,GAAGH,KAAK;MACrCD,iBAAiB,CAACG,MAAM,CAACC,KAAK,GAAGD,MAAM;IACzC,CAAC,EAAET,OAAO,CAAC;IACXE,GAAG,CAACG,OAAO,GAAGC,iBAAiB;IAC/BF,YAAY,CAACC,OAAO,GAAG,IAAI;EAC7B;EACAZ,SAAS,CAAC,MAAM;IACd,IAAIW,YAAY,CAACC,OAAO,KAAK,KAAK,IAAIH,GAAG,CAACG,OAAO,KAAK,IAAI,EAAE;MAC1D,MAAMC,iBAAiB,GAAGJ,GAAG,CAACG,OAAO;MACrC;MACAF,UAAU,CAACE,OAAO,GAAGT,0BAA0B,CAAC,CAACW,KAAK,EAAEE,MAAM,KAAK;QACjE,SAAS;;QACTH,iBAAiB,CAACC,KAAK,CAACG,KAAK,GAAGH,KAAK;QACrCD,iBAAiB,CAACG,MAAM,CAACC,KAAK,GAAGD,MAAM;MACzC,CAAC,EAAET,OAAO,CAAC;MACXI,YAAY,CAACC,OAAO,GAAG,IAAI;IAC7B;IACA,OAAO,MAAM;MACXR,6BAA6B,CAACM,UAAU,CAACE,OAAO,CAAC;MACjDD,YAAY,CAACC,OAAO,GAAG,KAAK;IAC9B,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EACN,OAAOH,GAAG,CAACG,OAAO;AACpB","ignoreList":[]}

View File

@@ -0,0 +1,23 @@
'use strict';
import { useAnimatedStyle } from './useAnimatedStyle';
import { shouldBeUseWeb } from '../PlatformChecker';
// TODO: we should make sure that when useAP is used we are not assigning styles
function useAnimatedPropsJS(updater, deps, adapters) {
return useAnimatedStyle(updater, deps, adapters, true);
}
const useAnimatedPropsNative = useAnimatedStyle;
/**
* Lets you create an animated props object which can be animated using shared values.
*
* @param updater - A function returning an object with properties you want to animate.
* @param dependencies - An optional array of dependencies. Only relevant when using Reanimated without the Babel plugin on the Web.
* @param adapters - An optional function or array of functions allowing to adopt prop naming between JS and the native side.
* @returns An animated props object which has to be passed to `animatedProps` property of an Animated component that you want to animate.
* @see https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedProps
*/
export const useAnimatedProps = shouldBeUseWeb() ? useAnimatedPropsJS : useAnimatedPropsNative;
//# sourceMappingURL=useAnimatedProps.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useAnimatedStyle","shouldBeUseWeb","useAnimatedPropsJS","updater","deps","adapters","useAnimatedPropsNative","useAnimatedProps"],"sources":["useAnimatedProps.ts"],"sourcesContent":["'use strict';\nimport { useAnimatedStyle } from './useAnimatedStyle';\nimport type { DependencyList, UseAnimatedStyleInternal } from './commonTypes';\nimport { shouldBeUseWeb } from '../PlatformChecker';\nimport type { AnimatedPropsAdapterFunction } from '../commonTypes';\n\n// TODO: we should make sure that when useAP is used we are not assigning styles\n\ntype UseAnimatedProps = <Props extends object>(\n updater: () => Partial<Props>,\n dependencies?: DependencyList | null,\n adapters?:\n | AnimatedPropsAdapterFunction\n | AnimatedPropsAdapterFunction[]\n | null,\n isAnimatedProps?: boolean\n) => Partial<Props>;\n\nfunction useAnimatedPropsJS<Props extends object>(\n updater: () => Props,\n deps?: DependencyList | null,\n adapters?:\n | AnimatedPropsAdapterFunction\n | AnimatedPropsAdapterFunction[]\n | null\n) {\n return (useAnimatedStyle as UseAnimatedStyleInternal<Props>)(\n updater,\n deps,\n adapters,\n true\n );\n}\n\nconst useAnimatedPropsNative = useAnimatedStyle;\n\n/**\n * Lets you create an animated props object which can be animated using shared values.\n *\n * @param updater - A function returning an object with properties you want to animate.\n * @param dependencies - An optional array of dependencies. Only relevant when using Reanimated without the Babel plugin on the Web.\n * @param adapters - An optional function or array of functions allowing to adopt prop naming between JS and the native side.\n * @returns An animated props object which has to be passed to `animatedProps` property of an Animated component that you want to animate.\n * @see https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedProps\n */\nexport const useAnimatedProps: UseAnimatedProps = shouldBeUseWeb()\n ? (useAnimatedPropsJS as UseAnimatedProps)\n : useAnimatedPropsNative;\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,gBAAgB,QAAQ,oBAAoB;AAErD,SAASC,cAAc,QAAQ,oBAAoB;;AAGnD;;AAYA,SAASC,kBAAkBA,CACzBC,OAAoB,EACpBC,IAA4B,EAC5BC,QAGQ,EACR;EACA,OAAQL,gBAAgB,CACtBG,OAAO,EACPC,IAAI,EACJC,QAAQ,EACR,IACF,CAAC;AACH;AAEA,MAAMC,sBAAsB,GAAGN,gBAAgB;;AAE/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMO,gBAAkC,GAAGN,cAAc,CAAC,CAAC,GAC7DC,kBAAkB,GACnBI,sBAAsB","ignoreList":[]}

View File

@@ -0,0 +1,47 @@
'use strict';
import { useEffect } from 'react';
import { startMapper, stopMapper } from '../core';
import { useSharedValue } from './useSharedValue';
import { shouldBeUseWeb } from '../PlatformChecker';
/**
* Lets you to respond to changes in a [shared value](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#shared-value). It's especially useful when comparing values previously stored in the shared value with the current one.
*
* @param prepare - A function that should return a value to which you'd like to react.
* @param react - A function that reacts to changes in the value returned by the `prepare` function.
* @param dependencies - an optional array of dependencies. Only relevant when using Reanimated without the Babel plugin on the Web.
* @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useAnimatedReaction
*/
// @ts-expect-error This overload is required by our API.
export function useAnimatedReaction(prepare, react, dependencies) {
const previous = useSharedValue(null);
let inputs = Object.values(prepare.__closure ?? {});
if (shouldBeUseWeb()) {
var _dependencies;
if (!inputs.length && (_dependencies = dependencies) !== null && _dependencies !== void 0 && _dependencies.length) {
// let web work without a Reanimated Babel plugin
inputs = dependencies;
}
}
if (dependencies === undefined) {
dependencies = [...Object.values(prepare.__closure ?? {}), ...Object.values(react.__closure ?? {}), prepare.__workletHash, react.__workletHash];
} else {
dependencies.push(prepare.__workletHash, react.__workletHash);
}
useEffect(() => {
const fun = () => {
'worklet';
const input = prepare();
react(input, previous.value);
previous.value = input;
};
const mapperId = startMapper(fun, inputs);
return () => {
stopMapper(mapperId);
};
}, dependencies);
}
//# sourceMappingURL=useAnimatedReaction.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useEffect","startMapper","stopMapper","useSharedValue","shouldBeUseWeb","useAnimatedReaction","prepare","react","dependencies","previous","inputs","Object","values","__closure","_dependencies","length","undefined","__workletHash","push","fun","input","value","mapperId"],"sources":["useAnimatedReaction.ts"],"sourcesContent":["'use strict';\nimport { useEffect } from 'react';\nimport type { WorkletFunction } from '../commonTypes';\nimport { startMapper, stopMapper } from '../core';\nimport type { DependencyList } from './commonTypes';\nimport { useSharedValue } from './useSharedValue';\nimport { shouldBeUseWeb } from '../PlatformChecker';\n\n/**\n * Lets you to respond to changes in a [shared value](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#shared-value). It's especially useful when comparing values previously stored in the shared value with the current one.\n *\n * @param prepare - A function that should return a value to which you'd like to react.\n * @param react - A function that reacts to changes in the value returned by the `prepare` function.\n * @param dependencies - an optional array of dependencies. Only relevant when using Reanimated without the Babel plugin on the Web.\n * @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useAnimatedReaction\n */\n// @ts-expect-error This overload is required by our API.\nexport function useAnimatedReaction<PreparedResult>(\n prepare: () => PreparedResult,\n react: (prepared: PreparedResult, previous: PreparedResult | null) => void,\n dependencies?: DependencyList\n): void;\n\nexport function useAnimatedReaction<PreparedResult>(\n prepare: WorkletFunction<[], PreparedResult>,\n react: WorkletFunction<\n [prepare: PreparedResult, previous: PreparedResult | null],\n void\n >,\n dependencies?: DependencyList\n) {\n const previous = useSharedValue<PreparedResult | null>(null);\n\n let inputs = Object.values(prepare.__closure ?? {});\n\n if (shouldBeUseWeb()) {\n if (!inputs.length && dependencies?.length) {\n // let web work without a Reanimated Babel plugin\n inputs = dependencies;\n }\n }\n\n if (dependencies === undefined) {\n dependencies = [\n ...Object.values(prepare.__closure ?? {}),\n ...Object.values(react.__closure ?? {}),\n prepare.__workletHash,\n react.__workletHash,\n ];\n } else {\n dependencies.push(prepare.__workletHash, react.__workletHash);\n }\n\n useEffect(() => {\n const fun = () => {\n 'worklet';\n const input = prepare();\n react(input, previous.value);\n previous.value = input;\n };\n const mapperId = startMapper(fun, inputs);\n return () => {\n stopMapper(mapperId);\n };\n }, dependencies);\n}\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,SAAS,QAAQ,OAAO;AAEjC,SAASC,WAAW,EAAEC,UAAU,QAAQ,SAAS;AAEjD,SAASC,cAAc,QAAQ,kBAAkB;AACjD,SAASC,cAAc,QAAQ,oBAAoB;;AAEnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAOA,OAAO,SAASC,mBAAmBA,CACjCC,OAA4C,EAC5CC,KAGC,EACDC,YAA6B,EAC7B;EACA,MAAMC,QAAQ,GAAGN,cAAc,CAAwB,IAAI,CAAC;EAE5D,IAAIO,MAAM,GAAGC,MAAM,CAACC,MAAM,CAACN,OAAO,CAACO,SAAS,IAAI,CAAC,CAAC,CAAC;EAEnD,IAAIT,cAAc,CAAC,CAAC,EAAE;IAAA,IAAAU,aAAA;IACpB,IAAI,CAACJ,MAAM,CAACK,MAAM,KAAAD,aAAA,GAAIN,YAAY,cAAAM,aAAA,eAAZA,aAAA,CAAcC,MAAM,EAAE;MAC1C;MACAL,MAAM,GAAGF,YAAY;IACvB;EACF;EAEA,IAAIA,YAAY,KAAKQ,SAAS,EAAE;IAC9BR,YAAY,GAAG,CACb,GAAGG,MAAM,CAACC,MAAM,CAACN,OAAO,CAACO,SAAS,IAAI,CAAC,CAAC,CAAC,EACzC,GAAGF,MAAM,CAACC,MAAM,CAACL,KAAK,CAACM,SAAS,IAAI,CAAC,CAAC,CAAC,EACvCP,OAAO,CAACW,aAAa,EACrBV,KAAK,CAACU,aAAa,CACpB;EACH,CAAC,MAAM;IACLT,YAAY,CAACU,IAAI,CAACZ,OAAO,CAACW,aAAa,EAAEV,KAAK,CAACU,aAAa,CAAC;EAC/D;EAEAjB,SAAS,CAAC,MAAM;IACd,MAAMmB,GAAG,GAAGA,CAAA,KAAM;MAChB,SAAS;;MACT,MAAMC,KAAK,GAAGd,OAAO,CAAC,CAAC;MACvBC,KAAK,CAACa,KAAK,EAAEX,QAAQ,CAACY,KAAK,CAAC;MAC5BZ,QAAQ,CAACY,KAAK,GAAGD,KAAK;IACxB,CAAC;IACD,MAAME,QAAQ,GAAGrB,WAAW,CAACkB,GAAG,EAAET,MAAM,CAAC;IACzC,OAAO,MAAM;MACXR,UAAU,CAACoB,QAAQ,CAAC;IACtB,CAAC;EACH,CAAC,EAAEd,YAAY,CAAC;AAClB","ignoreList":[]}

View File

@@ -0,0 +1,66 @@
'use strict';
import { useRef } from 'react';
import { useSharedValue } from './useSharedValue';
import { getShadowNodeWrapperFromRef } from '../fabricUtils';
import { makeShareableCloneRecursive } from '../shareables';
import { shareableMappingCache } from '../shareableMappingCache';
import { Platform, findNodeHandle } from 'react-native';
import { isFabric, isWeb } from '../PlatformChecker';
const IS_WEB = isWeb();
function getComponentOrScrollable(component) {
if (isFabric() && component.getNativeScrollRef) {
return component.getNativeScrollRef();
} else if (!isFabric() && component.getScrollableNode) {
return component.getScrollableNode();
}
return component;
}
/**
* Lets you get a reference of a view that you can use inside a worklet.
*
* @returns An object with a `.current` property which contains an instance of a component.
* @see https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedRef
*/
export function useAnimatedRef() {
const tag = useSharedValue(-1);
const viewName = useSharedValue(null);
const ref = useRef();
if (!ref.current) {
const fun = component => {
// enters when ref is set by attaching to a component
if (component) {
const getTagValueFunction = isFabric() ? getShadowNodeWrapperFromRef : findNodeHandle;
const getTagOrShadowNodeWrapper = () => {
return IS_WEB ? getComponentOrScrollable(component) : getTagValueFunction(getComponentOrScrollable(component));
};
tag.value = getTagOrShadowNodeWrapper();
// On Fabric we have to unwrap the tag from the shadow node wrapper
fun.getTag = isFabric() ? () => findNodeHandle(getComponentOrScrollable(component)) : getTagOrShadowNodeWrapper;
fun.current = component;
// viewName is required only on iOS with Paper
if (Platform.OS === 'ios' && !isFabric()) {
var _viewConfig;
viewName.value = (component === null || component === void 0 || (_viewConfig = component.viewConfig) === null || _viewConfig === void 0 ? void 0 : _viewConfig.uiViewClassName) || 'RCTView';
}
}
return tag.value;
};
fun.current = null;
const animatedRefShareableHandle = makeShareableCloneRecursive({
__init: () => {
'worklet';
const f = () => tag.value;
f.viewName = viewName;
return f;
}
});
shareableMappingCache.set(fun, animatedRefShareableHandle);
ref.current = fun;
}
return ref.current;
}
//# sourceMappingURL=useAnimatedRef.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,68 @@
'use strict';
import { useHandler } from './useHandler';
import { useEvent } from './useEvent';
/**
* Lets you run callbacks on ScrollView events. Supports `onScroll`, `onBeginDrag`, `onEndDrag`, `onMomentumBegin`, and `onMomentumEnd` events.
*
* These callbacks are automatically workletized and ran on the UI thread.
*
* @param handlers - An object containing event handlers.
* @param dependencies - An optional array of dependencies. Only relevant when using Reanimated without the Babel plugin on the Web.
* @returns An object you need to pass to `onScroll` prop on the `Animated.ScrollView` component.
* @see https://docs.swmansion.com/react-native-reanimated/docs/scroll/useAnimatedScrollHandler
*/
// @ts-expect-error This overload is required by our API.
export function useAnimatedScrollHandler(handlers, dependencies) {
// case when handlers is a function
const scrollHandlers = typeof handlers === 'function' ? {
onScroll: handlers
} : handlers;
const {
context,
doDependenciesDiffer
} = useHandler(scrollHandlers, dependencies);
// build event subscription array
const subscribeForEvents = ['onScroll'];
if (scrollHandlers.onBeginDrag !== undefined) {
subscribeForEvents.push('onScrollBeginDrag');
}
if (scrollHandlers.onEndDrag !== undefined) {
subscribeForEvents.push('onScrollEndDrag');
}
if (scrollHandlers.onMomentumBegin !== undefined) {
subscribeForEvents.push('onMomentumScrollBegin');
}
if (scrollHandlers.onMomentumEnd !== undefined) {
subscribeForEvents.push('onMomentumScrollEnd');
}
return useEvent(event => {
'worklet';
const {
onScroll,
onBeginDrag,
onEndDrag,
onMomentumBegin,
onMomentumEnd
} = scrollHandlers;
if (onScroll && event.eventName.endsWith('onScroll')) {
onScroll(event, context);
} else if (onBeginDrag && event.eventName.endsWith('onScrollBeginDrag')) {
onBeginDrag(event, context);
} else if (onEndDrag && event.eventName.endsWith('onScrollEndDrag')) {
onEndDrag(event, context);
} else if (onMomentumBegin && event.eventName.endsWith('onMomentumScrollBegin')) {
onMomentumBegin(event, context);
} else if (onMomentumEnd && event.eventName.endsWith('onMomentumScrollEnd')) {
onMomentumEnd(event, context);
}
}, subscribeForEvents, doDependenciesDiffer
// Read https://github.com/software-mansion/react-native-reanimated/pull/5056
// for more information about this cast.
);
}
//# sourceMappingURL=useAnimatedScrollHandler.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,144 @@
'use strict';
import { useEffect, useMemo, useRef } from 'react';
import { initializeSensor, registerSensor, unregisterSensor } from '../core';
import { SensorType, IOSReferenceFrame, InterfaceOrientation } from '../commonTypes';
import { callMicrotasks } from '../threads';
// euler angles are in order ZXY, z = yaw, x = pitch, y = roll
// https://github.com/mrdoob/three.js/blob/dev/src/math/Quaternion.js#L237
function eulerToQuaternion(pitch, roll, yaw) {
'worklet';
const c1 = Math.cos(pitch / 2);
const s1 = Math.sin(pitch / 2);
const c2 = Math.cos(roll / 2);
const s2 = Math.sin(roll / 2);
const c3 = Math.cos(yaw / 2);
const s3 = Math.sin(yaw / 2);
return [s1 * c2 * c3 - c1 * s2 * s3, c1 * s2 * c3 + s1 * c2 * s3, c1 * c2 * s3 + s1 * s2 * c3, c1 * c2 * c3 - s1 * s2 * s3];
}
function adjustRotationToInterfaceOrientation(data) {
'worklet';
const {
interfaceOrientation,
pitch,
roll,
yaw
} = data;
if (interfaceOrientation === InterfaceOrientation.ROTATION_90) {
data.pitch = roll;
data.roll = -pitch;
data.yaw = yaw - Math.PI / 2;
} else if (interfaceOrientation === InterfaceOrientation.ROTATION_270) {
data.pitch = -roll;
data.roll = pitch;
data.yaw = yaw + Math.PI / 2;
} else if (interfaceOrientation === InterfaceOrientation.ROTATION_180) {
data.pitch *= -1;
data.roll *= -1;
data.yaw *= -1;
}
const q = eulerToQuaternion(data.pitch, data.roll, data.yaw);
data.qx = q[0];
data.qy = q[1];
data.qz = q[2];
data.qw = q[3];
return data;
}
function adjustVectorToInterfaceOrientation(data) {
'worklet';
const {
interfaceOrientation,
x,
y
} = data;
if (interfaceOrientation === InterfaceOrientation.ROTATION_90) {
data.x = -y;
data.y = x;
} else if (interfaceOrientation === InterfaceOrientation.ROTATION_270) {
data.x = y;
data.y = -x;
} else if (interfaceOrientation === InterfaceOrientation.ROTATION_180) {
data.x *= -1;
data.y *= -1;
}
return data;
}
/**
* Lets you create animations based on data from the device's sensors.
*
* @param sensorType - Type of the sensor to use. Configured with {@link SensorType} enum.
* @param config - The sensor configuration - {@link SensorConfig}.
* @returns An object containing the sensor measurements [shared value](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#shared-value) and a function to unregister the sensor
* @see https://docs.swmansion.com/react-native-reanimated/docs/device/useAnimatedSensor
*/
export function useAnimatedSensor(sensorType, userConfig) {
var _userConfigRef$curren, _userConfigRef$curren2, _userConfigRef$curren3;
const userConfigRef = useRef(userConfig);
const hasConfigChanged = ((_userConfigRef$curren = userConfigRef.current) === null || _userConfigRef$curren === void 0 ? void 0 : _userConfigRef$curren.adjustToInterfaceOrientation) !== (userConfig === null || userConfig === void 0 ? void 0 : userConfig.adjustToInterfaceOrientation) || ((_userConfigRef$curren2 = userConfigRef.current) === null || _userConfigRef$curren2 === void 0 ? void 0 : _userConfigRef$curren2.interval) !== (userConfig === null || userConfig === void 0 ? void 0 : userConfig.interval) || ((_userConfigRef$curren3 = userConfigRef.current) === null || _userConfigRef$curren3 === void 0 ? void 0 : _userConfigRef$curren3.iosReferenceFrame) !== (userConfig === null || userConfig === void 0 ? void 0 : userConfig.iosReferenceFrame);
if (hasConfigChanged) {
userConfigRef.current = {
...userConfig
};
}
const config = useMemo(() => ({
interval: 'auto',
adjustToInterfaceOrientation: true,
iosReferenceFrame: IOSReferenceFrame.Auto,
...userConfigRef.current
}), [userConfigRef.current]);
const ref = useRef({
sensor: initializeSensor(sensorType, config),
unregister: () => {
// NOOP
},
isAvailable: false,
config
});
useEffect(() => {
ref.current = {
sensor: initializeSensor(sensorType, config),
unregister: () => {
// NOOP
},
isAvailable: false,
config
};
const sensorData = ref.current.sensor;
const adjustToInterfaceOrientation = ref.current.config.adjustToInterfaceOrientation;
const id = registerSensor(sensorType, config, data => {
'worklet';
if (adjustToInterfaceOrientation) {
if (sensorType === SensorType.ROTATION) {
data = adjustRotationToInterfaceOrientation(data);
} else {
data = adjustVectorToInterfaceOrientation(data);
}
}
sensorData.value = data;
callMicrotasks();
});
if (id !== -1) {
// if sensor is available
ref.current.unregister = () => unregisterSensor(id);
ref.current.isAvailable = true;
} else {
// if sensor is unavailable
ref.current.unregister = () => {
// NOOP
};
ref.current.isAvailable = false;
}
return () => {
ref.current.unregister();
};
}, [sensorType, config]);
return ref.current;
}
//# sourceMappingURL=useAnimatedSensor.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,384 @@
'use strict';
import { useEffect, useRef } from 'react';
import { makeShareable, startMapper, stopMapper } from '../core';
import updateProps, { updatePropsJestWrapper } from '../UpdateProps';
import { initialUpdaterRun } from '../animation';
import { useSharedValue } from './useSharedValue';
import { buildWorkletsHash, isAnimated, shallowEqual, validateAnimatedStyles } from './utils';
import { makeViewDescriptorsSet, useViewRefSet } from '../ViewDescriptorsSet';
import { isJest, shouldBeUseWeb } from '../PlatformChecker';
import { isWorkletFunction } from '../commonTypes';
const SHOULD_BE_USE_WEB = shouldBeUseWeb();
function prepareAnimation(frameTimestamp, animatedProp, lastAnimation, lastValue) {
'worklet';
if (Array.isArray(animatedProp)) {
animatedProp.forEach((prop, index) => {
prepareAnimation(frameTimestamp, prop, lastAnimation && lastAnimation[index], lastValue && lastValue[index]);
});
// return animatedProp;
}
if (typeof animatedProp === 'object' && animatedProp.onFrame) {
const animation = animatedProp;
let value = animation.current;
if (lastValue !== undefined && lastValue !== null) {
if (typeof lastValue === 'object') {
if (lastValue.value !== undefined) {
// previously it was a shared value
value = lastValue.value;
} else if (lastValue.onFrame !== undefined) {
if ((lastAnimation === null || lastAnimation === void 0 ? void 0 : lastAnimation.current) !== undefined) {
// it was an animation before, copy its state
value = lastAnimation.current;
} else if ((lastValue === null || lastValue === void 0 ? void 0 : lastValue.current) !== undefined) {
// it was initialized
value = lastValue.current;
}
}
} else {
// previously it was a plain value, just set it as starting point
value = lastValue;
}
}
animation.callStart = timestamp => {
animation.onStart(animation, value, timestamp, lastAnimation);
};
animation.callStart(frameTimestamp);
animation.callStart = null;
} else if (typeof animatedProp === 'object') {
// it is an object
Object.keys(animatedProp).forEach(key => prepareAnimation(frameTimestamp, animatedProp[key], lastAnimation && lastAnimation[key], lastValue && lastValue[key]));
}
}
function runAnimations(animation, timestamp, key, result, animationsActive) {
'worklet';
if (!animationsActive.value) {
return true;
}
if (Array.isArray(animation)) {
result[key] = [];
let allFinished = true;
animation.forEach((entry, index) => {
if (!runAnimations(entry, timestamp, index, result[key], animationsActive)) {
allFinished = false;
}
});
return allFinished;
} else if (typeof animation === 'object' && animation.onFrame) {
let finished = true;
if (!animation.finished) {
if (animation.callStart) {
animation.callStart(timestamp);
animation.callStart = null;
}
finished = animation.onFrame(animation, timestamp);
animation.timestamp = timestamp;
if (finished) {
animation.finished = true;
animation.callback && animation.callback(true /* finished */);
}
}
result[key] = animation.current;
return finished;
} else if (typeof animation === 'object') {
result[key] = {};
let allFinished = true;
Object.keys(animation).forEach(k => {
if (!runAnimations(animation[k], timestamp, k, result[key], animationsActive)) {
allFinished = false;
}
});
return allFinished;
} else {
result[key] = animation;
return true;
}
}
function styleUpdater(viewDescriptors, updater, state, maybeViewRef, animationsActive, isAnimatedProps = false) {
'worklet';
const animations = state.animations ?? {};
const newValues = updater() ?? {};
const oldValues = state.last;
const nonAnimatedNewValues = {};
let hasAnimations = false;
let frameTimestamp;
let hasNonAnimatedValues = false;
for (const key in newValues) {
const value = newValues[key];
if (isAnimated(value)) {
frameTimestamp = global.__frameTimestamp || global._getAnimationTimestamp();
prepareAnimation(frameTimestamp, value, animations[key], oldValues[key]);
animations[key] = value;
hasAnimations = true;
} else {
hasNonAnimatedValues = true;
nonAnimatedNewValues[key] = value;
delete animations[key];
}
}
if (hasAnimations) {
const frame = timestamp => {
// eslint-disable-next-line @typescript-eslint/no-shadow
const {
animations,
last,
isAnimationCancelled
} = state;
if (isAnimationCancelled) {
state.isAnimationRunning = false;
return;
}
const updates = {};
let allFinished = true;
for (const propName in animations) {
const finished = runAnimations(animations[propName], timestamp, propName, updates, animationsActive);
if (finished) {
last[propName] = updates[propName];
delete animations[propName];
} else {
allFinished = false;
}
}
if (updates) {
updateProps(viewDescriptors, updates, maybeViewRef);
}
if (!allFinished) {
requestAnimationFrame(frame);
} else {
state.isAnimationRunning = false;
}
};
state.animations = animations;
if (!state.isAnimationRunning) {
state.isAnimationCancelled = false;
state.isAnimationRunning = true;
frame(frameTimestamp);
}
if (hasNonAnimatedValues) {
updateProps(viewDescriptors, nonAnimatedNewValues, maybeViewRef);
}
} else {
state.isAnimationCancelled = true;
state.animations = [];
if (!shallowEqual(oldValues, newValues)) {
updateProps(viewDescriptors, newValues, maybeViewRef, isAnimatedProps);
}
}
state.last = newValues;
}
function jestStyleUpdater(viewDescriptors, updater, state, maybeViewRef, animationsActive, animatedStyle, adapters) {
'worklet';
const animations = state.animations ?? {};
const newValues = updater() ?? {};
const oldValues = state.last;
// extract animated props
let hasAnimations = false;
let frameTimestamp;
Object.keys(animations).forEach(key => {
const value = newValues[key];
if (!isAnimated(value)) {
delete animations[key];
}
});
Object.keys(newValues).forEach(key => {
const value = newValues[key];
if (isAnimated(value)) {
frameTimestamp = global.__frameTimestamp || global._getAnimationTimestamp();
prepareAnimation(frameTimestamp, value, animations[key], oldValues[key]);
animations[key] = value;
hasAnimations = true;
}
});
function frame(timestamp) {
// eslint-disable-next-line @typescript-eslint/no-shadow
const {
animations,
last,
isAnimationCancelled
} = state;
if (isAnimationCancelled) {
state.isAnimationRunning = false;
return;
}
const updates = {};
let allFinished = true;
Object.keys(animations).forEach(propName => {
const finished = runAnimations(animations[propName], timestamp, propName, updates, animationsActive);
if (finished) {
last[propName] = updates[propName];
delete animations[propName];
} else {
allFinished = false;
}
});
if (Object.keys(updates).length) {
updatePropsJestWrapper(viewDescriptors, updates, maybeViewRef, animatedStyle, adapters);
}
if (!allFinished) {
requestAnimationFrame(frame);
} else {
state.isAnimationRunning = false;
}
}
if (hasAnimations) {
state.animations = animations;
if (!state.isAnimationRunning) {
state.isAnimationCancelled = false;
state.isAnimationRunning = true;
frame(frameTimestamp);
}
} else {
state.isAnimationCancelled = true;
state.animations = [];
}
// calculate diff
state.last = newValues;
if (!shallowEqual(oldValues, newValues)) {
updatePropsJestWrapper(viewDescriptors, newValues, maybeViewRef, animatedStyle, adapters);
}
}
// check for invalid usage of shared values in returned object
function checkSharedValueUsage(prop, currentKey) {
if (Array.isArray(prop)) {
// if it's an array (i.ex. transform) validate all its elements
for (const element of prop) {
checkSharedValueUsage(element, currentKey);
}
} else if (typeof prop === 'object' && prop !== null && prop.value === undefined) {
// if it's a nested object, run validation for all its props
for (const key of Object.keys(prop)) {
checkSharedValueUsage(prop[key], key);
}
} else if (currentKey !== undefined && typeof prop === 'object' && prop !== null && prop.value !== undefined) {
// if shared value is passed insted of its value, throw an error
throw new Error(`[Reanimated] Invalid value passed to \`${currentKey}\`, maybe you forgot to use \`.value\`?`);
}
}
/**
* Lets you create a styles object, similar to StyleSheet styles, which can be animated using shared values.
*
* @param updater - A function returning an object with style properties you want to animate.
* @param dependencies - An optional array of dependencies. Only relevant when using Reanimated without the Babel plugin on the Web.
* @returns An animated style object which has to be passed to the `style` property of an Animated component you want to animate.
* @see https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedStyle
*/
// You cannot pass Shared Values to `useAnimatedStyle` directly.
// @ts-expect-error This overload is required by our API.
export function useAnimatedStyle(updater, dependencies, adapters, isAnimatedProps = false) {
const viewsRef = useViewRefSet();
const animatedUpdaterData = useRef();
let inputs = Object.values(updater.__closure ?? {});
if (SHOULD_BE_USE_WEB) {
var _dependencies;
if (!inputs.length && (_dependencies = dependencies) !== null && _dependencies !== void 0 && _dependencies.length) {
// let web work without a Babel plugin
inputs = dependencies;
}
if (__DEV__ && !inputs.length && !dependencies && !isWorkletFunction(updater)) {
throw new Error(`[Reanimated] \`useAnimatedStyle\` was used without a dependency array or Babel plugin. Please explicitly pass a dependency array, or enable the Babel plugin.
For more, see the docs: \`https://docs.swmansion.com/react-native-reanimated/docs/guides/web-support#web-without-the-babel-plugin\`.`);
}
}
const adaptersArray = adapters ? Array.isArray(adapters) ? adapters : [adapters] : [];
const adaptersHash = adapters ? buildWorkletsHash(adaptersArray) : null;
const areAnimationsActive = useSharedValue(true);
const jestAnimatedStyle = useRef({});
// build dependencies
if (!dependencies) {
dependencies = [...inputs, updater.__workletHash];
} else {
dependencies.push(updater.__workletHash);
}
adaptersHash && dependencies.push(adaptersHash);
if (!animatedUpdaterData.current) {
const initialStyle = initialUpdaterRun(updater);
if (__DEV__) {
validateAnimatedStyles(initialStyle);
}
animatedUpdaterData.current = {
initial: {
value: initialStyle,
updater
},
remoteState: makeShareable({
last: initialStyle,
animations: {},
isAnimationCancelled: false,
isAnimationRunning: false
}),
viewDescriptors: makeViewDescriptorsSet()
};
}
const {
initial,
remoteState,
viewDescriptors
} = animatedUpdaterData.current;
const shareableViewDescriptors = viewDescriptors.shareableViewDescriptors;
dependencies.push(shareableViewDescriptors);
useEffect(() => {
let fun;
let updaterFn = updater;
if (adapters) {
updaterFn = () => {
'worklet';
const newValues = updater();
adaptersArray.forEach(adapter => {
adapter(newValues);
});
return newValues;
};
}
if (isJest()) {
fun = () => {
'worklet';
jestStyleUpdater(shareableViewDescriptors, updater, remoteState, viewsRef, areAnimationsActive, jestAnimatedStyle, adaptersArray);
};
} else {
fun = () => {
'worklet';
styleUpdater(shareableViewDescriptors, updaterFn, remoteState, viewsRef, areAnimationsActive, isAnimatedProps);
};
}
const mapperId = startMapper(fun, inputs);
return () => {
stopMapper(mapperId);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, dependencies);
useEffect(() => {
areAnimationsActive.value = true;
return () => {
areAnimationsActive.value = false;
};
}, [areAnimationsActive]);
checkSharedValueUsage(initial.value);
const animatedStyleHandle = useRef(null);
if (!animatedStyleHandle.current) {
animatedStyleHandle.current = isJest() ? {
viewDescriptors,
initial,
viewsRef,
jestAnimatedStyle
} : {
initial,
viewsRef,
viewDescriptors
};
}
return animatedStyleHandle.current;
}
//# sourceMappingURL=useAnimatedStyle.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,57 @@
'use strict';
import { useEffect, useRef } from 'react';
import { initialUpdaterRun } from '../animation';
import { makeMutable, startMapper, stopMapper } from '../core';
import { shouldBeUseWeb } from '../PlatformChecker';
/**
* Lets you create new shared values based on existing ones while keeping them reactive.
*
* @param updater - A function called whenever at least one of the shared values or state used in the function body changes.
* @param dependencies - An optional array of dependencies. Only relevant when using Reanimated without the Babel plugin on the Web.
* @returns A new readonly shared value based on a value returned from the updater function
* @see https://docs.swmansion.com/react-native-reanimated/docs/core/useDerivedValue
*/
// @ts-expect-error This overload is required by our API.
export function useDerivedValue(updater, dependencies) {
const initRef = useRef(null);
let inputs = Object.values(updater.__closure ?? {});
if (shouldBeUseWeb()) {
var _dependencies;
if (!inputs.length && (_dependencies = dependencies) !== null && _dependencies !== void 0 && _dependencies.length) {
// let web work without a Babel/SWC plugin
inputs = dependencies;
}
}
// build dependencies
if (dependencies === undefined) {
dependencies = [...inputs, updater.__workletHash];
} else {
dependencies.push(updater.__workletHash);
}
if (initRef.current === null) {
initRef.current = makeMutable(initialUpdaterRun(updater));
}
const sharedValue = initRef.current;
useEffect(() => {
const fun = () => {
'worklet';
sharedValue.value = updater();
};
const mapperId = startMapper(fun, inputs, [sharedValue]);
return () => {
stopMapper(mapperId);
};
}, dependencies);
useEffect(() => {
return () => {
initRef.current = null;
};
}, []);
return sharedValue;
}
//# sourceMappingURL=useDerivedValue.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useEffect","useRef","initialUpdaterRun","makeMutable","startMapper","stopMapper","shouldBeUseWeb","useDerivedValue","updater","dependencies","initRef","inputs","Object","values","__closure","_dependencies","length","undefined","__workletHash","push","current","sharedValue","fun","value","mapperId"],"sources":["useDerivedValue.ts"],"sourcesContent":["'use strict';\nimport { useEffect, useRef } from 'react';\nimport { initialUpdaterRun } from '../animation';\nimport type { SharedValue, WorkletFunction } from '../commonTypes';\nimport { makeMutable, startMapper, stopMapper } from '../core';\nimport type { DependencyList } from './commonTypes';\nimport { shouldBeUseWeb } from '../PlatformChecker';\n\nexport type DerivedValue<Value> = Readonly<SharedValue<Value>>;\n\n/**\n * Lets you create new shared values based on existing ones while keeping them reactive.\n *\n * @param updater - A function called whenever at least one of the shared values or state used in the function body changes.\n * @param dependencies - An optional array of dependencies. Only relevant when using Reanimated without the Babel plugin on the Web.\n * @returns A new readonly shared value based on a value returned from the updater function\n * @see https://docs.swmansion.com/react-native-reanimated/docs/core/useDerivedValue\n */\n// @ts-expect-error This overload is required by our API.\nexport function useDerivedValue<Value>(\n updater: () => Value,\n dependencies?: DependencyList\n): DerivedValue<Value>;\n\nexport function useDerivedValue<Value>(\n updater: WorkletFunction<[], Value>,\n dependencies?: DependencyList\n): DerivedValue<Value> {\n const initRef = useRef<SharedValue<Value> | null>(null);\n let inputs = Object.values(updater.__closure ?? {});\n if (shouldBeUseWeb()) {\n if (!inputs.length && dependencies?.length) {\n // let web work without a Babel/SWC plugin\n inputs = dependencies;\n }\n }\n\n // build dependencies\n if (dependencies === undefined) {\n dependencies = [...inputs, updater.__workletHash];\n } else {\n dependencies.push(updater.__workletHash);\n }\n\n if (initRef.current === null) {\n initRef.current = makeMutable(initialUpdaterRun(updater));\n }\n\n const sharedValue: SharedValue<Value> = initRef.current;\n\n useEffect(() => {\n const fun = () => {\n 'worklet';\n sharedValue.value = updater();\n };\n const mapperId = startMapper(fun, inputs, [sharedValue]);\n return () => {\n stopMapper(mapperId);\n };\n }, dependencies);\n\n useEffect(() => {\n return () => {\n initRef.current = null;\n };\n }, []);\n\n return sharedValue;\n}\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,SAAS,EAAEC,MAAM,QAAQ,OAAO;AACzC,SAASC,iBAAiB,QAAQ,cAAc;AAEhD,SAASC,WAAW,EAAEC,WAAW,EAAEC,UAAU,QAAQ,SAAS;AAE9D,SAASC,cAAc,QAAQ,oBAAoB;;AAInD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAMA,OAAO,SAASC,eAAeA,CAC7BC,OAAmC,EACnCC,YAA6B,EACR;EACrB,MAAMC,OAAO,GAAGT,MAAM,CAA4B,IAAI,CAAC;EACvD,IAAIU,MAAM,GAAGC,MAAM,CAACC,MAAM,CAACL,OAAO,CAACM,SAAS,IAAI,CAAC,CAAC,CAAC;EACnD,IAAIR,cAAc,CAAC,CAAC,EAAE;IAAA,IAAAS,aAAA;IACpB,IAAI,CAACJ,MAAM,CAACK,MAAM,KAAAD,aAAA,GAAIN,YAAY,cAAAM,aAAA,eAAZA,aAAA,CAAcC,MAAM,EAAE;MAC1C;MACAL,MAAM,GAAGF,YAAY;IACvB;EACF;;EAEA;EACA,IAAIA,YAAY,KAAKQ,SAAS,EAAE;IAC9BR,YAAY,GAAG,CAAC,GAAGE,MAAM,EAAEH,OAAO,CAACU,aAAa,CAAC;EACnD,CAAC,MAAM;IACLT,YAAY,CAACU,IAAI,CAACX,OAAO,CAACU,aAAa,CAAC;EAC1C;EAEA,IAAIR,OAAO,CAACU,OAAO,KAAK,IAAI,EAAE;IAC5BV,OAAO,CAACU,OAAO,GAAGjB,WAAW,CAACD,iBAAiB,CAACM,OAAO,CAAC,CAAC;EAC3D;EAEA,MAAMa,WAA+B,GAAGX,OAAO,CAACU,OAAO;EAEvDpB,SAAS,CAAC,MAAM;IACd,MAAMsB,GAAG,GAAGA,CAAA,KAAM;MAChB,SAAS;;MACTD,WAAW,CAACE,KAAK,GAAGf,OAAO,CAAC,CAAC;IAC/B,CAAC;IACD,MAAMgB,QAAQ,GAAGpB,WAAW,CAACkB,GAAG,EAAEX,MAAM,EAAE,CAACU,WAAW,CAAC,CAAC;IACxD,OAAO,MAAM;MACXhB,UAAU,CAACmB,QAAQ,CAAC;IACtB,CAAC;EACH,CAAC,EAAEf,YAAY,CAAC;EAEhBT,SAAS,CAAC,MAAM;IACd,OAAO,MAAM;MACXU,OAAO,CAACU,OAAO,GAAG,IAAI;IACxB,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EAEN,OAAOC,WAAW;AACpB","ignoreList":[]}

View File

@@ -0,0 +1,41 @@
'use strict';
import { useRef } from 'react';
import { WorkletEventHandler } from '../WorkletEventHandler';
/**
* Worklet to provide as an argument to `useEvent` hook.
*/
/**
* Lets you run a function whenever a specified native event occurs.
*
* @param handler - A function that receives an event object with event data - {@link EventHandler}.
* @param eventNames - An array of event names the `handler` callback will react to.
* @param rebuild - Whether the event handler should be rebuilt. Defaults to `false`.
* @returns A function that will be called when the event occurs - {@link EventHandlerProcessed}.
* @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useEvent
*/
// @ts-expect-error This overload is required by our API.
// We don't know which properites of a component that is made into
// an AnimatedComponent are event handlers and we don't want to force the user to define it.
// Therefore we disguise `useEvent` return type as a simple function and we handle
// it being a React Ref in `createAnimatedComponent`.
export function useEvent(handler, eventNames = [], rebuild = false) {
const initRef = useRef(null);
if (initRef.current === null) {
const workletEventHandler = new WorkletEventHandler(handler, eventNames);
initRef.current = {
workletEventHandler
};
} else if (rebuild) {
const workletEventHandler = initRef.current.workletEventHandler;
workletEventHandler.updateEventHandler(handler, eventNames);
initRef.current = {
workletEventHandler
};
}
return initRef.current;
}
//# sourceMappingURL=useEvent.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useRef","WorkletEventHandler","useEvent","handler","eventNames","rebuild","initRef","current","workletEventHandler","updateEventHandler"],"sources":["useEvent.ts"],"sourcesContent":["'use strict';\nimport { useRef } from 'react';\nimport { WorkletEventHandler } from '../WorkletEventHandler';\nimport type { IWorkletEventHandler, ReanimatedEvent } from './commonTypes';\n\n/**\n * Worklet to provide as an argument to `useEvent` hook.\n */\nexport type EventHandler<\n Event extends object,\n Context extends Record<string, unknown> = never\n> = (event: ReanimatedEvent<Event>, context?: Context) => void;\n\nexport type EventHandlerProcessed<\n Event extends object,\n Context extends Record<string, unknown> = never\n> = (event: Event, context?: Context) => void;\n\nexport type EventHandlerInternal<Event extends object> = {\n workletEventHandler: IWorkletEventHandler<Event>;\n};\n\n/**\n * Lets you run a function whenever a specified native event occurs.\n *\n * @param handler - A function that receives an event object with event data - {@link EventHandler}.\n * @param eventNames - An array of event names the `handler` callback will react to.\n * @param rebuild - Whether the event handler should be rebuilt. Defaults to `false`.\n * @returns A function that will be called when the event occurs - {@link EventHandlerProcessed}.\n * @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useEvent\n */\n// @ts-expect-error This overload is required by our API.\n// We don't know which properites of a component that is made into\n// an AnimatedComponent are event handlers and we don't want to force the user to define it.\n// Therefore we disguise `useEvent` return type as a simple function and we handle\n// it being a React Ref in `createAnimatedComponent`.\nexport function useEvent<\n Event extends object,\n Context extends Record<string, unknown> = never\n>(\n handler: EventHandler<Event, Context>,\n eventNames?: string[],\n rebuild?: boolean\n): EventHandlerProcessed<Event, Context>;\n\nexport function useEvent<Event extends object, Context = never>(\n handler: (event: ReanimatedEvent<Event>, context?: Context) => void,\n eventNames: string[] = [],\n rebuild = false\n): EventHandlerInternal<Event> {\n const initRef = useRef<EventHandlerInternal<Event>>(null!);\n if (initRef.current === null) {\n const workletEventHandler = new WorkletEventHandler<Event>(\n handler,\n eventNames\n );\n initRef.current = { workletEventHandler };\n } else if (rebuild) {\n const workletEventHandler = initRef.current.workletEventHandler;\n workletEventHandler.updateEventHandler(handler, eventNames);\n initRef.current = { workletEventHandler };\n }\n\n return initRef.current;\n}\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,MAAM,QAAQ,OAAO;AAC9B,SAASC,mBAAmB,QAAQ,wBAAwB;;AAG5D;AACA;AACA;;AAeA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAUA,OAAO,SAASC,QAAQA,CACtBC,OAAmE,EACnEC,UAAoB,GAAG,EAAE,EACzBC,OAAO,GAAG,KAAK,EACc;EAC7B,MAAMC,OAAO,GAAGN,MAAM,CAA8B,IAAK,CAAC;EAC1D,IAAIM,OAAO,CAACC,OAAO,KAAK,IAAI,EAAE;IAC5B,MAAMC,mBAAmB,GAAG,IAAIP,mBAAmB,CACjDE,OAAO,EACPC,UACF,CAAC;IACDE,OAAO,CAACC,OAAO,GAAG;MAAEC;IAAoB,CAAC;EAC3C,CAAC,MAAM,IAAIH,OAAO,EAAE;IAClB,MAAMG,mBAAmB,GAAGF,OAAO,CAACC,OAAO,CAACC,mBAAmB;IAC/DA,mBAAmB,CAACC,kBAAkB,CAACN,OAAO,EAAEC,UAAU,CAAC;IAC3DE,OAAO,CAACC,OAAO,GAAG;MAAEC;IAAoB,CAAC;EAC3C;EAEA,OAAOF,OAAO,CAACC,OAAO;AACxB","ignoreList":[]}

View File

@@ -0,0 +1,42 @@
'use strict';
import { useEffect, useRef } from 'react';
import FrameCallbackRegistryJS from '../frameCallback/FrameCallbackRegistryJS';
/**
* @param setActive - A function that lets you start the frame callback or stop it from running.
* @param isActive - A boolean indicating whether a callback is running.
* @param callbackId - A number indicating a unique identifier of the frame callback.
* @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useFrameCallback#returns
*/
const frameCallbackRegistry = new FrameCallbackRegistryJS();
/**
* Lets you run a function on every frame update.
*
* @param callback - A function executed on every frame update.
* @param autostart - Whether the callback should start automatically. Defaults to `true`.
* @returns A frame callback object - {@link FrameCallback}.
* @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useFrameCallback
*/
export function useFrameCallback(callback, autostart = true) {
const ref = useRef({
setActive: isActive => {
frameCallbackRegistry.manageStateFrameCallback(ref.current.callbackId, isActive);
ref.current.isActive = isActive;
},
isActive: autostart,
callbackId: -1
});
useEffect(() => {
ref.current.callbackId = frameCallbackRegistry.registerFrameCallback(callback);
ref.current.setActive(ref.current.isActive);
return () => {
frameCallbackRegistry.unregisterFrameCallback(ref.current.callbackId);
ref.current.callbackId = -1;
};
}, [callback, autostart]);
return ref.current;
}
//# sourceMappingURL=useFrameCallback.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useEffect","useRef","FrameCallbackRegistryJS","frameCallbackRegistry","useFrameCallback","callback","autostart","ref","setActive","isActive","manageStateFrameCallback","current","callbackId","registerFrameCallback","unregisterFrameCallback"],"sources":["useFrameCallback.ts"],"sourcesContent":["'use strict';\nimport { useEffect, useRef } from 'react';\nimport FrameCallbackRegistryJS from '../frameCallback/FrameCallbackRegistryJS';\nimport type { FrameInfo } from '../frameCallback/FrameCallbackRegistryUI';\n\n/**\n * @param setActive - A function that lets you start the frame callback or stop it from running.\n * @param isActive - A boolean indicating whether a callback is running.\n * @param callbackId - A number indicating a unique identifier of the frame callback.\n * @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useFrameCallback#returns\n */\nexport type FrameCallback = {\n setActive: (isActive: boolean) => void;\n isActive: boolean;\n callbackId: number;\n};\nconst frameCallbackRegistry = new FrameCallbackRegistryJS();\n\n/**\n * Lets you run a function on every frame update.\n *\n * @param callback - A function executed on every frame update.\n * @param autostart - Whether the callback should start automatically. Defaults to `true`.\n * @returns A frame callback object - {@link FrameCallback}.\n * @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useFrameCallback\n */\nexport function useFrameCallback(\n callback: (frameInfo: FrameInfo) => void,\n autostart = true\n): FrameCallback {\n const ref = useRef<FrameCallback>({\n setActive: (isActive: boolean) => {\n frameCallbackRegistry.manageStateFrameCallback(\n ref.current.callbackId,\n isActive\n );\n ref.current.isActive = isActive;\n },\n isActive: autostart,\n callbackId: -1,\n });\n\n useEffect(() => {\n ref.current.callbackId =\n frameCallbackRegistry.registerFrameCallback(callback);\n ref.current.setActive(ref.current.isActive);\n\n return () => {\n frameCallbackRegistry.unregisterFrameCallback(ref.current.callbackId);\n ref.current.callbackId = -1;\n };\n }, [callback, autostart]);\n\n return ref.current;\n}\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,SAAS,EAAEC,MAAM,QAAQ,OAAO;AACzC,OAAOC,uBAAuB,MAAM,0CAA0C;;AAG9E;AACA;AACA;AACA;AACA;AACA;;AAMA,MAAMC,qBAAqB,GAAG,IAAID,uBAAuB,CAAC,CAAC;;AAE3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASE,gBAAgBA,CAC9BC,QAAwC,EACxCC,SAAS,GAAG,IAAI,EACD;EACf,MAAMC,GAAG,GAAGN,MAAM,CAAgB;IAChCO,SAAS,EAAGC,QAAiB,IAAK;MAChCN,qBAAqB,CAACO,wBAAwB,CAC5CH,GAAG,CAACI,OAAO,CAACC,UAAU,EACtBH,QACF,CAAC;MACDF,GAAG,CAACI,OAAO,CAACF,QAAQ,GAAGA,QAAQ;IACjC,CAAC;IACDA,QAAQ,EAAEH,SAAS;IACnBM,UAAU,EAAE,CAAC;EACf,CAAC,CAAC;EAEFZ,SAAS,CAAC,MAAM;IACdO,GAAG,CAACI,OAAO,CAACC,UAAU,GACpBT,qBAAqB,CAACU,qBAAqB,CAACR,QAAQ,CAAC;IACvDE,GAAG,CAACI,OAAO,CAACH,SAAS,CAACD,GAAG,CAACI,OAAO,CAACF,QAAQ,CAAC;IAE3C,OAAO,MAAM;MACXN,qBAAqB,CAACW,uBAAuB,CAACP,GAAG,CAACI,OAAO,CAACC,UAAU,CAAC;MACrEL,GAAG,CAACI,OAAO,CAACC,UAAU,GAAG,CAAC,CAAC;IAC7B,CAAC;EACH,CAAC,EAAE,CAACP,QAAQ,EAAEC,SAAS,CAAC,CAAC;EAEzB,OAAOC,GAAG,CAACI,OAAO;AACpB","ignoreList":[]}

View File

@@ -0,0 +1,46 @@
'use strict';
import { useEffect, useRef } from 'react';
import { isWeb, isJest } from '../PlatformChecker';
import { areDependenciesEqual, buildDependencies } from './utils';
import { makeShareable } from '../shareables';
/**
* Lets you find out whether the event handler dependencies have changed.
*
* @param handlers - An object of event handlers.
* @param dependencies - An optional array of dependencies.
* @returns An object containing a boolean indicating whether the dependencies have changed, and a boolean indicating whether the code is running on the web.
* @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useHandler
*/
// @ts-expect-error This overload is required by our API.
export function useHandler(handlers, dependencies) {
const initRef = useRef(null);
if (initRef.current === null) {
const context = makeShareable({});
initRef.current = {
context,
savedDependencies: []
};
}
useEffect(() => {
return () => {
initRef.current = null;
};
}, []);
const {
context,
savedDependencies
} = initRef.current;
dependencies = buildDependencies(dependencies, handlers);
const doDependenciesDiffer = !areDependenciesEqual(dependencies, savedDependencies);
initRef.current.savedDependencies = dependencies;
const useWeb = isWeb() || isJest();
return {
context,
doDependenciesDiffer,
useWeb
};
}
//# sourceMappingURL=useHandler.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useEffect","useRef","isWeb","isJest","areDependenciesEqual","buildDependencies","makeShareable","useHandler","handlers","dependencies","initRef","current","context","savedDependencies","doDependenciesDiffer","useWeb"],"sources":["useHandler.ts"],"sourcesContent":["'use strict';\nimport { useEffect, useRef } from 'react';\nimport type { WorkletFunction } from '../commonTypes';\nimport { isWeb, isJest } from '../PlatformChecker';\nimport type { DependencyList, ReanimatedEvent } from './commonTypes';\nimport { areDependenciesEqual, buildDependencies } from './utils';\nimport { makeShareable } from '../shareables';\n\ninterface GeneralHandler<\n Event extends object,\n Context extends Record<string, unknown>\n> {\n (event: ReanimatedEvent<Event>, context: Context): void;\n}\n\ntype GeneralWorkletHandler<\n Event extends object,\n Context extends Record<string, unknown>\n> = WorkletFunction<[event: ReanimatedEvent<Event>, context: Context]>;\n\ntype GeneralHandlers<\n Event extends object,\n Context extends Record<string, unknown>\n> = Record<string, GeneralHandler<Event, Context> | undefined>;\n\ntype GeneralWorkletHandlers<\n Event extends object,\n Context extends Record<string, unknown>\n> = Record<string, GeneralWorkletHandler<Event, Context> | undefined>;\n\ninterface ContextWithDependencies<Context extends Record<string, unknown>> {\n context: Context;\n savedDependencies: DependencyList;\n}\n\nexport interface UseHandlerContext<Context extends Record<string, unknown>> {\n context: Context;\n doDependenciesDiffer: boolean;\n useWeb: boolean;\n}\n\n/**\n * Lets you find out whether the event handler dependencies have changed.\n *\n * @param handlers - An object of event handlers.\n * @param dependencies - An optional array of dependencies.\n * @returns An object containing a boolean indicating whether the dependencies have changed, and a boolean indicating whether the code is running on the web.\n * @see https://docs.swmansion.com/react-native-reanimated/docs/advanced/useHandler\n */\n// @ts-expect-error This overload is required by our API.\nexport function useHandler<\n Event extends object,\n Context extends Record<string, unknown>\n>(\n handlers: GeneralHandlers<Event, Context>,\n dependencies?: DependencyList\n): UseHandlerContext<Context>;\n\nexport function useHandler<\n Event extends object,\n Context extends Record<string, unknown>\n>(\n handlers: GeneralWorkletHandlers<Event, Context>,\n dependencies?: DependencyList\n): UseHandlerContext<Context> {\n const initRef = useRef<ContextWithDependencies<Context> | null>(null);\n if (initRef.current === null) {\n const context = makeShareable({} as Context);\n initRef.current = {\n context,\n savedDependencies: [],\n };\n }\n\n useEffect(() => {\n return () => {\n initRef.current = null;\n };\n }, []);\n\n const { context, savedDependencies } = initRef.current;\n\n dependencies = buildDependencies(\n dependencies,\n handlers as Record<string, WorkletFunction | undefined>\n );\n\n const doDependenciesDiffer = !areDependenciesEqual(\n dependencies,\n savedDependencies\n );\n initRef.current.savedDependencies = dependencies;\n const useWeb = isWeb() || isJest();\n\n return { context, doDependenciesDiffer, useWeb };\n}\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,SAAS,EAAEC,MAAM,QAAQ,OAAO;AAEzC,SAASC,KAAK,EAAEC,MAAM,QAAQ,oBAAoB;AAElD,SAASC,oBAAoB,EAAEC,iBAAiB,QAAQ,SAAS;AACjE,SAASC,aAAa,QAAQ,eAAe;;AAmC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AASA,OAAO,SAASC,UAAUA,CAIxBC,QAAgD,EAChDC,YAA6B,EACD;EAC5B,MAAMC,OAAO,GAAGT,MAAM,CAA0C,IAAI,CAAC;EACrE,IAAIS,OAAO,CAACC,OAAO,KAAK,IAAI,EAAE;IAC5B,MAAMC,OAAO,GAAGN,aAAa,CAAC,CAAC,CAAY,CAAC;IAC5CI,OAAO,CAACC,OAAO,GAAG;MAChBC,OAAO;MACPC,iBAAiB,EAAE;IACrB,CAAC;EACH;EAEAb,SAAS,CAAC,MAAM;IACd,OAAO,MAAM;MACXU,OAAO,CAACC,OAAO,GAAG,IAAI;IACxB,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EAEN,MAAM;IAAEC,OAAO;IAAEC;EAAkB,CAAC,GAAGH,OAAO,CAACC,OAAO;EAEtDF,YAAY,GAAGJ,iBAAiB,CAC9BI,YAAY,EACZD,QACF,CAAC;EAED,MAAMM,oBAAoB,GAAG,CAACV,oBAAoB,CAChDK,YAAY,EACZI,iBACF,CAAC;EACDH,OAAO,CAACC,OAAO,CAACE,iBAAiB,GAAGJ,YAAY;EAChD,MAAMM,MAAM,GAAGb,KAAK,CAAC,CAAC,IAAIC,MAAM,CAAC,CAAC;EAElC,OAAO;IAAES,OAAO;IAAEE,oBAAoB;IAAEC;EAAO,CAAC;AAClD","ignoreList":[]}

View File

@@ -0,0 +1,17 @@
'use strict';
import { isReducedMotion } from '../PlatformChecker';
const IS_REDUCED_MOTION = isReducedMotion();
/**
* Lets you query the reduced motion system setting.
*
* Changing the reduced motion system setting doesn't cause your components to rerender.
*
* @returns A boolean indicating whether the reduced motion setting was enabled when the app started.
* @see https://docs.swmansion.com/react-native-reanimated/docs/device/useReducedMotion
*/
export function useReducedMotion() {
return IS_REDUCED_MOTION;
}
//# sourceMappingURL=useReducedMotion.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["isReducedMotion","IS_REDUCED_MOTION","useReducedMotion"],"sources":["useReducedMotion.ts"],"sourcesContent":["'use strict';\nimport { isReducedMotion } from '../PlatformChecker';\n\nconst IS_REDUCED_MOTION = isReducedMotion();\n\n/**\n * Lets you query the reduced motion system setting.\n *\n * Changing the reduced motion system setting doesn't cause your components to rerender.\n *\n * @returns A boolean indicating whether the reduced motion setting was enabled when the app started.\n * @see https://docs.swmansion.com/react-native-reanimated/docs/device/useReducedMotion\n */\nexport function useReducedMotion() {\n return IS_REDUCED_MOTION;\n}\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,eAAe,QAAQ,oBAAoB;AAEpD,MAAMC,iBAAiB,GAAGD,eAAe,CAAC,CAAC;;AAE3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASE,gBAAgBA,CAAA,EAAG;EACjC,OAAOD,iBAAiB;AAC1B","ignoreList":[]}

View File

@@ -0,0 +1,90 @@
'use strict';
import { useEffect, useRef, useCallback } from 'react';
import { useEvent } from './useEvent';
import { useSharedValue } from './useSharedValue';
import { isWeb } from '../PlatformChecker';
const IS_WEB = isWeb();
/**
* Lets you synchronously get the current offset of a `ScrollView`.
*
* @param animatedRef - An [animated ref](https://docs.swmansion.com/react-native-reanimated/docs/core/useAnimatedRef) attached to an Animated.ScrollView component.
* @returns A shared value which holds the current offset of the `ScrollView`.
* @see https://docs.swmansion.com/react-native-reanimated/docs/scroll/useScrollViewOffset
*/
export const useScrollViewOffset = IS_WEB ? useScrollViewOffsetWeb : useScrollViewOffsetNative;
function useScrollViewOffsetWeb(animatedRef, providedOffset) {
const internalOffset = useSharedValue(0);
const offset = useRef(providedOffset ?? internalOffset).current;
const scrollRef = useRef(null);
const eventHandler = useCallback(() => {
'worklet';
const element = getWebScrollableElement(animatedRef.current);
// scrollLeft is the X axis scrolled offset, works properly also with RTL layout
offset.value = element.scrollLeft === 0 ? element.scrollTop : element.scrollLeft;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [animatedRef, animatedRef.current]);
useEffect(() => {
// We need to make sure that listener for old animatedRef value is removed
if (scrollRef.current !== null) {
getWebScrollableElement(scrollRef.current).removeEventListener('scroll', eventHandler);
}
scrollRef.current = animatedRef.current;
const element = getWebScrollableElement(animatedRef.current);
element.addEventListener('scroll', eventHandler);
return () => {
element.removeEventListener('scroll', eventHandler);
};
// React here has a problem with `animatedRef.current` since a Ref .current
// field shouldn't be used as a dependency. However, in this case we have
// to do it this way.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [animatedRef, animatedRef.current, eventHandler]);
return offset;
}
function useScrollViewOffsetNative(animatedRef, providedOffset) {
const internalOffset = useSharedValue(0);
const offset = useRef(providedOffset ?? internalOffset).current;
const scrollRef = useRef(null);
const scrollRefTag = useRef(null);
const eventHandler = useEvent(event => {
'worklet';
offset.value = event.contentOffset.x === 0 ? event.contentOffset.y : event.contentOffset.x;
}, scrollNativeEventNames
// Read https://github.com/software-mansion/react-native-reanimated/pull/5056
// for more information about this cast.
);
useEffect(() => {
// We need to make sure that listener for old animatedRef value is removed
if (scrollRef.current !== null && scrollRefTag.current !== null) {
eventHandler.workletEventHandler.unregisterFromEvents(scrollRefTag.current);
}
// Store the ref and viewTag for future cleanup
scrollRef.current = animatedRef.current;
scrollRefTag.current = animatedRef.getTag();
if (scrollRefTag === null) {
console.warn('[Reanimated] ScrollViewOffset failed to resolve the view tag from animated ref. Did you forget to attach the ref to a component?');
} else {
eventHandler.workletEventHandler.registerForEvents(scrollRefTag.current);
}
return () => {
if (scrollRefTag.current !== null) {
eventHandler.workletEventHandler.unregisterFromEvents(scrollRefTag.current);
}
};
// React here has a problem with `animatedRef.current` since a Ref .current
// field shouldn't be used as a dependency. However, in this case we have
// to do it this way.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [animatedRef, animatedRef.current, eventHandler]);
return offset;
}
function getWebScrollableElement(scrollComponent) {
return (scrollComponent === null || scrollComponent === void 0 ? void 0 : scrollComponent.getScrollableNode()) ?? scrollComponent;
}
const scrollNativeEventNames = ['onScroll', 'onScrollBeginDrag', 'onScrollEndDrag', 'onMomentumScrollBegin', 'onMomentumScrollEnd'];
//# sourceMappingURL=useScrollViewOffset.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,23 @@
'use strict';
import { useEffect, useState } from 'react';
import { cancelAnimation } from '../animation';
import { makeMutable } from '../core';
/**
* Lets you define [shared values](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#shared-value) in your components.
*
* @param initialValue - The value you want to be initially stored to a `.value` property.
* @returns A shared value with a single `.value` property initially set to the `initialValue` - {@link SharedValue}.
* @see https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue
*/
export function useSharedValue(initialValue) {
const [mutable] = useState(() => makeMutable(initialValue));
useEffect(() => {
return () => {
cancelAnimation(mutable);
};
}, [mutable]);
return mutable;
}
//# sourceMappingURL=useSharedValue.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useEffect","useState","cancelAnimation","makeMutable","useSharedValue","initialValue","mutable"],"sources":["useSharedValue.ts"],"sourcesContent":["'use strict';\nimport { useEffect, useState } from 'react';\nimport { cancelAnimation } from '../animation';\nimport type { SharedValue } from '../commonTypes';\nimport { makeMutable } from '../core';\n\n/**\n * Lets you define [shared values](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/glossary#shared-value) in your components.\n *\n * @param initialValue - The value you want to be initially stored to a `.value` property.\n * @returns A shared value with a single `.value` property initially set to the `initialValue` - {@link SharedValue}.\n * @see https://docs.swmansion.com/react-native-reanimated/docs/core/useSharedValue\n */\nexport function useSharedValue<Value>(initialValue: Value): SharedValue<Value> {\n const [mutable] = useState(() => makeMutable(initialValue));\n useEffect(() => {\n return () => {\n cancelAnimation(mutable);\n };\n }, [mutable]);\n return mutable;\n}\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,SAAS,EAAEC,QAAQ,QAAQ,OAAO;AAC3C,SAASC,eAAe,QAAQ,cAAc;AAE9C,SAASC,WAAW,QAAQ,SAAS;;AAErC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAAQC,YAAmB,EAAsB;EAC7E,MAAM,CAACC,OAAO,CAAC,GAAGL,QAAQ,CAAC,MAAME,WAAW,CAACE,YAAY,CAAC,CAAC;EAC3DL,SAAS,CAAC,MAAM;IACd,OAAO,MAAM;MACXE,eAAe,CAACI,OAAO,CAAC;IAC1B,CAAC;EACH,CAAC,EAAE,CAACA,OAAO,CAAC,CAAC;EACb,OAAOA,OAAO;AAChB","ignoreList":[]}

View File

@@ -0,0 +1,10 @@
'use strict';
import { useCallback } from 'react';
/**
* @deprecated don't use
*/
export function useWorkletCallback(worklet, deps) {
return useCallback(worklet, deps ?? []);
}
//# sourceMappingURL=useWorkletCallback.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["useCallback","useWorkletCallback","worklet","deps"],"sources":["useWorkletCallback.ts"],"sourcesContent":["'use strict';\nimport { useCallback } from 'react';\nimport type { DependencyList } from './commonTypes';\n\n/**\n * @deprecated don't use\n */\nexport function useWorkletCallback<Args extends unknown[], ReturnValue>(\n worklet: (...args: Args) => ReturnValue,\n deps?: DependencyList\n) {\n return useCallback(worklet, deps ?? []);\n}\n"],"mappings":"AAAA,YAAY;;AACZ,SAASA,WAAW,QAAQ,OAAO;AAGnC;AACA;AACA;AACA,OAAO,SAASC,kBAAkBA,CAChCC,OAAuC,EACvCC,IAAqB,EACrB;EACA,OAAOH,WAAW,CAACE,OAAO,EAAEC,IAAI,IAAI,EAAE,CAAC;AACzC","ignoreList":[]}

View File

@@ -0,0 +1,86 @@
'use strict';
// Builds one big hash from multiple worklets' hashes.
export function buildWorkletsHash(worklets) {
// For arrays `Object.values` returns the array itself.
return Object.values(worklets).reduce((acc, worklet) => acc + worklet.__workletHash.toString(), '');
}
// Builds dependencies array for useEvent handlers.
export function buildDependencies(dependencies, handlers) {
const handlersList = Object.values(handlers).filter(handler => handler !== undefined);
if (!dependencies) {
dependencies = handlersList.map(handler => {
return {
workletHash: handler.__workletHash,
closure: handler.__closure
};
});
} else {
dependencies.push(buildWorkletsHash(handlersList));
}
return dependencies;
}
// This is supposed to work as useEffect comparison.
export function areDependenciesEqual(nextDependencies, prevDependencies) {
function is(x, y) {
return x === y && (x !== 0 || 1 / x === 1 / y) || Number.isNaN(x) && Number.isNaN(y);
}
const objectIs = typeof Object.is === 'function' ? Object.is : is;
function areHookInputsEqual(nextDeps, prevDeps) {
if (!nextDeps || !prevDeps || prevDeps.length !== nextDeps.length) {
return false;
}
for (let i = 0; i < prevDeps.length; ++i) {
if (!objectIs(nextDeps[i], prevDeps[i])) {
return false;
}
}
return true;
}
return areHookInputsEqual(nextDependencies, prevDependencies);
}
export function isAnimated(prop) {
'worklet';
if (Array.isArray(prop)) {
return prop.some(isAnimated);
} else if (typeof prop === 'object' && prop !== null) {
if (prop.onFrame !== undefined) {
return true;
} else {
return Object.values(prop).some(isAnimated);
}
}
return false;
}
// This function works because `Object.keys`
// return empty array of primitives and on arrays
// it returns array of its indices.
export function shallowEqual(a, b) {
'worklet';
const aKeys = Object.keys(a);
const bKeys = Object.keys(b);
if (aKeys.length !== bKeys.length) {
return false;
}
for (let i = 0; i < aKeys.length; i++) {
if (a[aKeys[i]] !== b[aKeys[i]]) {
return false;
}
}
return true;
}
export function validateAnimatedStyles(styles) {
'worklet';
if (typeof styles !== 'object') {
throw new Error(`[Reanimated] \`useAnimatedStyle\` has to return an object, found ${typeof styles} instead.`);
} else if (Array.isArray(styles)) {
throw new Error('[Reanimated] `useAnimatedStyle` has to return an object and cannot return static styles combined with dynamic ones. Please do merging where a component receives props.');
}
}
//# sourceMappingURL=utils.js.map

File diff suppressed because one or more lines are too long