1 | 'use strict';
|
2 | import type { StyleProps } from '../reanimated2';
|
3 | import type {
|
4 | IAnimatedComponentInternal,
|
5 | AnimatedComponentProps,
|
6 | IInlinePropManager,
|
7 | ViewInfo,
|
8 | } from './commonTypes';
|
9 | import { flattenArray } from './utils';
|
10 | import { makeViewDescriptorsSet } from '../reanimated2/ViewDescriptorsSet';
|
11 | import type {
|
12 | ViewDescriptorsSet,
|
13 | ViewRefSet,
|
14 | } from '../reanimated2/ViewDescriptorsSet';
|
15 | import { adaptViewConfig } from '../ConfigHelper';
|
16 | import updateProps from '../reanimated2/UpdateProps';
|
17 | import { stopMapper, startMapper } from '../reanimated2/mappers';
|
18 | import { isSharedValue } from '../reanimated2/isSharedValue';
|
19 | import { shouldBeUseWeb } from '../reanimated2/PlatformChecker';
|
20 |
|
21 | const SHOULD_BE_USE_WEB = shouldBeUseWeb();
|
22 |
|
23 | function 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 |
|
31 | function 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 |
|
48 | function 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 |
|
67 | function extractSharedValuesMapFromProps(
|
68 | props: AnimatedComponentProps<
|
69 | Record<string, unknown>
|
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 |
|
101 | export 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 |
|
114 | export 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 |
|
133 | export 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>)
|
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 | }
|