UNPKG

4.21 kBPlain TextView Raw
1'use strict';
2import type { NativeSyntheticEvent } from 'react-native';
3import { registerEventHandler, unregisterEventHandler } from './core';
4import type {
5 EventPayload,
6 ReanimatedEvent,
7 IWorkletEventHandler,
8} from './hook/commonTypes';
9import { shouldBeUseWeb } from './PlatformChecker';
10
11const SHOULD_BE_USE_WEB = shouldBeUseWeb();
12
13type JSEvent<Event extends object> = NativeSyntheticEvent<EventPayload<Event>>;
14
15// In JS implementation (e.g. for web) we don't use Reanimated's
16// event emitter, therefore we have to handle here
17// the event that came from React Native and convert it.
18function jsListener<Event extends object>(
19 eventName: string,
20 handler: (event: ReanimatedEvent<Event>) => void
21) {
22 return (evt: JSEvent<Event>) => {
23 handler({ ...evt.nativeEvent, eventName } as ReanimatedEvent<Event>);
24 };
25}
26
27class WorkletEventHandlerNative<Event extends object>
28 implements IWorkletEventHandler<Event>
29{
30 eventNames: string[];
31 worklet: (event: ReanimatedEvent<Event>) => void;
32 #viewTags: Set<number>;
33 #registrations: Map<number, number[]>; // keys are viewTags, values are arrays of registration ID's for each viewTag
34 constructor(
35 worklet: (event: ReanimatedEvent<Event>) => void,
36 eventNames: string[]
37 ) {
38 this.worklet = worklet;
39 this.eventNames = eventNames;
40 this.#viewTags = new Set<number>();
41 this.#registrations = new Map<number, number[]>();
42 }
43
44 updateEventHandler(
45 newWorklet: (event: ReanimatedEvent<Event>) => void,
46 newEvents: string[]
47 ): void {
48 // Update worklet and event names
49 this.worklet = newWorklet;
50 this.eventNames = newEvents;
51
52 // Detach all events
53 this.#registrations.forEach((registrationIDs) => {
54 registrationIDs.forEach((id) => unregisterEventHandler(id));
55 // No need to remove registrationIDs from map, since it gets overwritten when attaching
56 });
57
58 // Attach new events with new worklet
59 Array.from(this.#viewTags).forEach((tag) => {
60 const newRegistrations = this.eventNames.map((eventName) =>
61 registerEventHandler(this.worklet, eventName, tag)
62 );
63 this.#registrations.set(tag, newRegistrations);
64 });
65 }
66
67 registerForEvents(viewTag: number, fallbackEventName?: string): void {
68 this.#viewTags.add(viewTag);
69
70 const newRegistrations = this.eventNames.map((eventName) =>
71 registerEventHandler(this.worklet, eventName, viewTag)
72 );
73 this.#registrations.set(viewTag, newRegistrations);
74
75 if (this.eventNames.length === 0 && fallbackEventName) {
76 const newRegistration = registerEventHandler(
77 this.worklet,
78 fallbackEventName,
79 viewTag
80 );
81 this.#registrations.set(viewTag, [newRegistration]);
82 }
83 }
84
85 unregisterFromEvents(viewTag: number): void {
86 this.#viewTags.delete(viewTag);
87 this.#registrations.get(viewTag)?.forEach((id) => {
88 unregisterEventHandler(id);
89 });
90 this.#registrations.delete(viewTag);
91 }
92}
93
94class WorkletEventHandlerWeb<Event extends object>
95 implements IWorkletEventHandler<Event>
96{
97 eventNames: string[];
98 listeners:
99 | Record<string, (event: ReanimatedEvent<ReanimatedEvent<Event>>) => void>
100 | Record<string, (event: JSEvent<Event>) => void>;
101
102 worklet: (event: ReanimatedEvent<Event>) => void;
103
104 constructor(
105 worklet: (event: ReanimatedEvent<Event>) => void,
106 eventNames: string[] = []
107 ) {
108 this.worklet = worklet;
109 this.eventNames = eventNames;
110 this.listeners = {};
111 this.setupWebListeners();
112 }
113
114 setupWebListeners() {
115 this.listeners = {};
116 this.eventNames.forEach((eventName) => {
117 this.listeners[eventName] = jsListener(eventName, this.worklet);
118 });
119 }
120
121 updateEventHandler(
122 newWorklet: (event: ReanimatedEvent<Event>) => void,
123 newEvents: string[]
124 ): void {
125 // Update worklet and event names
126 this.worklet = newWorklet;
127 this.eventNames = newEvents;
128 this.setupWebListeners();
129 }
130
131 registerForEvents(_viewTag: number, _fallbackEventName?: string): void {
132 // noop
133 }
134
135 unregisterFromEvents(_viewTag: number): void {
136 // noop
137 }
138}
139
140export const WorkletEventHandler = SHOULD_BE_USE_WEB
141 ? WorkletEventHandlerWeb
142 : WorkletEventHandlerNative;