UNPKG

5.6 kBPlain TextView Raw
1'use strict';
2import type { StyleProps } from '../reanimated2';
3import type {
4 IAnimatedComponentInternal,
5 AnimatedComponentProps,
6 IInlinePropManager,
7 ViewInfo,
8} from './commonTypes';
9import { flattenArray } from './utils';
10import { makeViewDescriptorsSet } from '../reanimated2/ViewDescriptorsSet';
11import type {
12 ViewDescriptorsSet,
13 ViewRefSet,
14} from '../reanimated2/ViewDescriptorsSet';
15import { adaptViewConfig } from '../ConfigHelper';
16import updateProps from '../reanimated2/UpdateProps';
17import { stopMapper, startMapper } from '../reanimated2/mappers';
18import { isSharedValue } from '../reanimated2/isSharedValue';
19import { shouldBeUseWeb } from '../reanimated2/PlatformChecker';
20
21const SHOULD_BE_USE_WEB = shouldBeUseWeb();
22
23function isInlineStyleTransform(transform: unknown): boolean {
24 if (!Array.isArray(transform)) {
25 return false;
26 }
27
28 return transform.some((t: Record<string, unknown>) => hasInlineStyles(t));
29}
30
31function inlinePropsHasChanged(
32 styles1: StyleProps,
33 styles2: StyleProps
34): boolean {
35 if (Object.keys(styles1).length !== Object.keys(styles2).length) {
36 return true;
37 }
38
39 for (const key of Object.keys(styles1)) {
40 if (styles1[key] !== styles2[key]) {
41 return true;
42 }
43 }
44
45 return false;
46}
47
48function getInlinePropsUpdate(inlineProps: Record<string, unknown>) {
49 'worklet';
50 const update: Record<string, unknown> = {};
51 for (const [key, styleValue] of Object.entries(inlineProps)) {
52 if (isSharedValue(styleValue)) {
53 update[key] = styleValue.value;
54 } else if (Array.isArray(styleValue)) {
55 update[key] = styleValue.map((item) => {
56 return getInlinePropsUpdate(item);
57 });
58 } else if (typeof styleValue === 'object') {
59 update[key] = getInlinePropsUpdate(styleValue as Record<string, unknown>);
60 } else {
61 update[key] = styleValue;
62 }
63 }
64 return update;
65}
66
67function extractSharedValuesMapFromProps(
68 props: AnimatedComponentProps<
69 Record<string, unknown> /* Initial component props */
70 >
71): Record<string, unknown> {
72 const inlineProps: Record<string, unknown> = {};
73
74 for (const key in props) {
75 const value = props[key];
76 if (key === 'style') {
77 const styles = flattenArray<StyleProps>(props.style ?? []);
78 styles.forEach((style) => {
79 if (!style) {
80 return;
81 }
82 for (const [styleKey, styleValue] of Object.entries(style)) {
83 if (isSharedValue(styleValue)) {
84 inlineProps[styleKey] = styleValue;
85 } else if (
86 styleKey === 'transform' &&
87 isInlineStyleTransform(styleValue)
88 ) {
89 inlineProps[styleKey] = styleValue;
90 }
91 }
92 });
93 } else if (isSharedValue(value)) {
94 inlineProps[key] = value;
95 }
96 }
97
98 return inlineProps;
99}
100
101export function hasInlineStyles(style: StyleProps): boolean {
102 if (!style) {
103 return false;
104 }
105 return Object.keys(style).some((key) => {
106 const styleValue = style[key];
107 return (
108 isSharedValue(styleValue) ||
109 (key === 'transform' && isInlineStyleTransform(styleValue))
110 );
111 });
112}
113
114export function getInlineStyle(
115 style: Record<string, unknown>,
116 shouldGetInitialStyle: boolean
117) {
118 if (shouldGetInitialStyle) {
119 return getInlinePropsUpdate(style);
120 }
121 const newStyle: StyleProps = {};
122 for (const [key, styleValue] of Object.entries(style)) {
123 if (
124 !isSharedValue(styleValue) &&
125 !(key === 'transform' && isInlineStyleTransform(styleValue))
126 ) {
127 newStyle[key] = styleValue;
128 }
129 }
130 return newStyle;
131}
132
133export class InlinePropManager implements IInlinePropManager {
134 _inlinePropsViewDescriptors: ViewDescriptorsSet | null = null;
135 _inlinePropsMapperId: number | null = null;
136 _inlineProps: StyleProps = {};
137
138 public attachInlineProps(
139 animatedComponent: React.Component<unknown, unknown> &
140 IAnimatedComponentInternal,
141 viewInfo: ViewInfo
142 ) {
143 const newInlineProps: Record<string, unknown> =
144 extractSharedValuesMapFromProps(animatedComponent.props);
145 const hasChanged = inlinePropsHasChanged(newInlineProps, this._inlineProps);
146
147 if (hasChanged) {
148 if (!this._inlinePropsViewDescriptors) {
149 this._inlinePropsViewDescriptors = makeViewDescriptorsSet();
150
151 const { viewTag, viewName, shadowNodeWrapper, viewConfig } = viewInfo;
152
153 if (Object.keys(newInlineProps).length && viewConfig) {
154 adaptViewConfig(viewConfig);
155 }
156
157 this._inlinePropsViewDescriptors.add({
158 tag: viewTag as number,
159 name: viewName!,
160 shadowNodeWrapper: shadowNodeWrapper!,
161 });
162 }
163 const shareableViewDescriptors =
164 this._inlinePropsViewDescriptors.shareableViewDescriptors;
165
166 const maybeViewRef = SHOULD_BE_USE_WEB
167 ? ({ items: new Set([animatedComponent]) } as ViewRefSet<unknown>) // see makeViewsRefSet
168 : undefined;
169 const updaterFunction = () => {
170 'worklet';
171 const update = getInlinePropsUpdate(newInlineProps);
172 updateProps(shareableViewDescriptors, update, maybeViewRef);
173 };
174 this._inlineProps = newInlineProps;
175 if (this._inlinePropsMapperId) {
176 stopMapper(this._inlinePropsMapperId);
177 }
178 this._inlinePropsMapperId = null;
179 if (Object.keys(newInlineProps).length) {
180 this._inlinePropsMapperId = startMapper(
181 updaterFunction,
182 Object.values(newInlineProps)
183 );
184 }
185 }
186 }
187
188 public detachInlineProps() {
189 if (this._inlinePropsMapperId) {
190 stopMapper(this._inlinePropsMapperId);
191 }
192 }
193}