Skip to content

Commit ae78700

Browse files
committed
Add coumpund registry keys
1 parent 98028b0 commit ae78700

File tree

8 files changed

+191
-24
lines changed

8 files changed

+191
-24
lines changed

packages/react-native-reanimated/src/common/style/registry.ts

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,21 @@ import {
1010
} from './propsBuilder';
1111

1212
export const ERROR_MESSAGES = {
13-
propsBuilderNotFound: (componentName: string) =>
14-
`CSS props builder for component ${componentName} was not found`,
13+
propsBuilderNotFound: (
14+
componentName: string,
15+
componentChildName?: string
16+
) => {
17+
const compoundComponentName = getCompoundComponentName(
18+
componentName,
19+
componentChildName
20+
);
21+
22+
const namesPart = componentChildName
23+
? `${compoundComponentName} or ${componentName}`
24+
: componentName;
25+
26+
return `CSS props builder for component ${namesPart} was not found`;
27+
},
1528
};
1629

1730
const DEFAULT_SEPARATELY_INTERPOLATED_NESTED_PROPERTIES = new Set<string>([
@@ -28,14 +41,34 @@ const COMPONENT_SEPARATELY_INTERPOLATED_NESTED_PROPERTIES = new Map<
2841

2942
const PROPS_BUILDERS = new Map<string, NativePropsBuilder>();
3043

31-
export function hasPropsBuilder(componentName: string): boolean {
44+
export function hasPropsBuilder(
45+
componentName: string,
46+
componentChildName?: string
47+
): boolean {
48+
const compoundComponentName = getCompoundComponentName(
49+
componentName,
50+
componentChildName
51+
);
52+
3253
return (
33-
!!PROPS_BUILDERS.get(componentName) || isReactNativeViewName(componentName)
54+
!!PROPS_BUILDERS.get(compoundComponentName) ||
55+
!!PROPS_BUILDERS.get(componentName) ||
56+
isReactNativeViewName(componentName)
3457
);
3558
}
3659

37-
export function getPropsBuilder(componentName: string): NativePropsBuilder {
38-
const componentPropsBuilder = PROPS_BUILDERS.get(componentName);
60+
export function getPropsBuilder(
61+
componentName: string,
62+
componentChildName?: string
63+
): NativePropsBuilder {
64+
const compoundComponentName = getCompoundComponentName(
65+
componentName,
66+
componentChildName
67+
);
68+
69+
const componentPropsBuilder =
70+
PROPS_BUILDERS.get(compoundComponentName) ??
71+
PROPS_BUILDERS.get(componentName);
3972

4073
if (componentPropsBuilder) {
4174
return componentPropsBuilder;
@@ -46,31 +79,61 @@ export function getPropsBuilder(componentName: string): NativePropsBuilder {
4679
return stylePropsBuilder;
4780
}
4881

49-
throw new ReanimatedError(ERROR_MESSAGES.propsBuilderNotFound(componentName));
82+
throw new ReanimatedError(
83+
ERROR_MESSAGES.propsBuilderNotFound(componentName, componentChildName)
84+
);
5085
}
5186

5287
export function registerComponentPropsBuilder<P extends UnknownRecord>(
5388
componentName: string,
5489
config: PropsBuilderConfig<P>,
5590
options: {
5691
separatelyInterpolatedNestedProperties?: readonly string[];
92+
componentChildName?: string;
5793
} = {}
5894
) {
59-
PROPS_BUILDERS.set(componentName, createNativePropsBuilder(config));
95+
const compoundComponentName = getCompoundComponentName(
96+
componentName,
97+
options.componentChildName
98+
);
99+
PROPS_BUILDERS.set(compoundComponentName, createNativePropsBuilder(config));
100+
101+
// If the generalized version is missing but a specialization is provided,
102+
// initialize the generalization with the default config.
103+
if (options.componentChildName && !hasPropsBuilder(componentName)) {
104+
PROPS_BUILDERS.set(componentName, createNativePropsBuilder(config));
105+
}
60106

61107
if (options.separatelyInterpolatedNestedProperties?.length) {
62108
COMPONENT_SEPARATELY_INTERPOLATED_NESTED_PROPERTIES.set(
63-
componentName,
109+
compoundComponentName,
64110
new Set(options.separatelyInterpolatedNestedProperties)
65111
);
66112
}
67113
}
68114

69115
export function getSeparatelyInterpolatedNestedProperties(
70-
componentName: string
116+
componentName: string,
117+
componentChildName?: string
71118
): ReadonlySet<string> {
119+
const compoundComponentName = getCompoundComponentName(
120+
componentName,
121+
componentChildName
122+
);
72123
return (
124+
COMPONENT_SEPARATELY_INTERPOLATED_NESTED_PROPERTIES.get(
125+
compoundComponentName
126+
) ??
73127
COMPONENT_SEPARATELY_INTERPOLATED_NESTED_PROPERTIES.get(componentName) ??
74128
DEFAULT_SEPARATELY_INTERPOLATED_NESTED_PROPERTIES
75129
);
76130
}
131+
132+
function getCompoundComponentName(
133+
componentName: string,
134+
componentChildName?: string
135+
): string {
136+
return componentChildName
137+
? `${componentName}$${componentChildName}`
138+
: componentName;
139+
}

packages/react-native-reanimated/src/css/component/AnimatedComponent.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,10 @@ export default class AnimatedComponent<
167167
}
168168

169169
if (!IS_JEST) {
170-
this._CSSManager ??= new CSSManager(this._getViewInfo());
170+
this._CSSManager ??= new CSSManager(
171+
this._getViewInfo(),
172+
this.ChildComponent.displayName
173+
);
171174
this._CSSManager?.update(this._cssStyle);
172175
}
173176

packages/react-native-reanimated/src/css/native/__tests__/registry.test.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,30 @@ describe('registry', () => {
1818
expect(hasPropsBuilder(componentName)).toBe(true);
1919
});
2020

21+
test('returns true for registered compound component names', () => {
22+
const componentName = 'CustomComponent';
23+
const componentChildName = 'CustomComponentChild';
24+
const config = { width: true, height: true };
25+
26+
registerComponentPropsBuilder(componentName, config, {
27+
componentChildName: componentChildName,
28+
});
29+
30+
expect(hasPropsBuilder(componentName, componentChildName)).toBe(true);
31+
});
32+
33+
test('returns true for component names if compound component was registered ', () => {
34+
const componentName = 'CustomComponent';
35+
const componentChildName = 'CustomComponentChild';
36+
const config = { width: true, height: true };
37+
38+
registerComponentPropsBuilder(componentName, config, {
39+
componentChildName: componentChildName,
40+
});
41+
42+
expect(hasPropsBuilder(componentName)).toBe(true);
43+
});
44+
2145
test('returns true for RCT prefixed component names', () => {
2246
expect(hasPropsBuilder('RCTView')).toBe(true);
2347
expect(hasPropsBuilder('RCTText')).toBe(true);
@@ -40,6 +64,52 @@ describe('registry', () => {
4064
expect(typeof propsBuilder.build).toBe('function');
4165
});
4266

67+
test('returns registered props builder for custom compound component', () => {
68+
const componentName = 'CustomComponent';
69+
const componentChildName = 'CustomComponentChild';
70+
const config = { width: true, height: true };
71+
72+
registerComponentPropsBuilder(componentName, config, {
73+
componentChildName: componentChildName,
74+
});
75+
const propsBuilder = getPropsBuilder(componentName, componentChildName);
76+
77+
expect(propsBuilder).toBeDefined();
78+
expect(typeof propsBuilder.build).toBe('function');
79+
});
80+
81+
test('returns registered props builder for component if custom compound component was registered', () => {
82+
const componentName = 'CustomComponent';
83+
const componentChildName = 'CustomComponentChild';
84+
const config = { width: true, height: true };
85+
86+
registerComponentPropsBuilder(componentName, config, {
87+
componentChildName: componentChildName,
88+
});
89+
const propsBuilder = getPropsBuilder(componentName);
90+
91+
expect(propsBuilder).toBeDefined();
92+
expect(typeof propsBuilder.build).toBe('function');
93+
});
94+
95+
test('returns registered props builder for component different than for the compound component', () => {
96+
const componentName = 'CustomComponent';
97+
const componentChildName = 'CustomComponentChild';
98+
const config = { width: true, height: true };
99+
const config2 = { width: true, height: true, length: true };
100+
101+
registerComponentPropsBuilder(componentName, config);
102+
registerComponentPropsBuilder(componentName, config2, {
103+
componentChildName: componentChildName,
104+
});
105+
const propsBuilder = getPropsBuilder(componentName);
106+
const propsBuilder2 = getPropsBuilder(componentName, componentChildName);
107+
108+
expect(propsBuilder).toBeDefined();
109+
expect(typeof propsBuilder.build).toBe('function');
110+
expect(propsBuilder == propsBuilder2).toBe(false);
111+
});
112+
43113
test('returns base props builder for RCT prefixed components', () => {
44114
const propsBuilder = getPropsBuilder('RCTView');
45115

@@ -52,6 +122,17 @@ describe('registry', () => {
52122
getPropsBuilder('UnregisteredComponent');
53123
}).toThrow(ERROR_MESSAGES.propsBuilderNotFound('UnregisteredComponent'));
54124
});
125+
126+
test('throws error for unregistered component names for compound component', () => {
127+
expect(() => {
128+
getPropsBuilder('UnregisteredComponent', 'UnregisteredComponentChild');
129+
}).toThrow(
130+
ERROR_MESSAGES.propsBuilderNotFound(
131+
'UnregisteredComponent',
132+
'UnregisteredComponentChild'
133+
)
134+
);
135+
});
55136
});
56137

57138
describe('registerComponentPropsBuilder', () => {

packages/react-native-reanimated/src/css/native/keyframes/CSSKeyframesRegistry.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ class CSSKeyframesRegistry {
3030
}
3131
}
3232

33-
add(keyframesRule: CSSKeyframesRuleImpl, viewName: string, viewTag: number) {
33+
add(
34+
keyframesRule: CSSKeyframesRuleImpl,
35+
viewName: string,
36+
viewTag: number,
37+
componentChildName?: string
38+
) {
3439
const existingKeyframesEntry = this.nameToKeyframes_.get(
3540
keyframesRule.name
3641
);
@@ -64,7 +69,7 @@ class CSSKeyframesRegistry {
6469
registerCSSKeyframes(
6570
keyframesRule.name,
6671
viewName,
67-
keyframesRule.getNormalizedKeyframesConfig(viewName)
72+
keyframesRule.getNormalizedKeyframesConfig(viewName, componentChildName)
6873
);
6974
}
7075

packages/react-native-reanimated/src/css/native/keyframes/CSSKeyframesRuleImpl.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ export default class CSSKeyframesRuleImpl<
1818
}
1919

2020
getNormalizedKeyframesConfig(
21-
viewName: string
21+
viewName: string,
22+
componentChildName?: string
2223
): NormalizedCSSAnimationKeyframesConfig {
2324
if (!this.normalizedKeyframesCache_[viewName]) {
2425
this.normalizedKeyframesCache_[viewName] = normalizeAnimationKeyframes(
2526
this.cssRules,
26-
viewName
27+
viewName,
28+
componentChildName
2729
);
2830
}
2931

packages/react-native-reanimated/src/css/native/managers/CSSAnimationsManager.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,20 @@ export default class CSSAnimationsManager implements ICSSAnimationsManager {
2626
private readonly shadowNodeWrapper: ShadowNodeWrapper;
2727
private readonly viewName: string;
2828
private readonly viewTag: number;
29+
private readonly componentChildName?: string;
2930

3031
private attachedAnimations: ProcessedAnimation[] = [];
3132

3233
constructor(
3334
shadowNodeWrapper: ShadowNodeWrapper,
3435
viewName: string,
35-
viewTag: number
36+
viewTag: number,
37+
componentChildName?: string
3638
) {
3739
this.shadowNodeWrapper = shadowNodeWrapper;
3840
this.viewName = viewName;
3941
this.viewTag = viewTag;
42+
this.componentChildName = componentChildName;
4043
}
4144

4245
update(animationProperties: ExistingCSSAnimationProperties | null): void {
@@ -81,7 +84,12 @@ export default class CSSAnimationsManager implements ICSSAnimationsManager {
8184

8285
// Register keyframes for all new animations
8386
processedAnimations.forEach(({ keyframesRule }) => {
84-
cssKeyframesRegistry.add(keyframesRule, this.viewName, this.viewTag);
87+
cssKeyframesRegistry.add(
88+
keyframesRule,
89+
this.viewName,
90+
this.viewTag,
91+
this.componentChildName
92+
);
8593
newAnimationNames.add(keyframesRule.name);
8694
});
8795

packages/react-native-reanimated/src/css/native/managers/CSSManager.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,22 @@ export default class CSSManager implements ICSSManager {
2222
null;
2323
private isFirstUpdate: boolean = true;
2424

25-
constructor({ shadowNodeWrapper, viewTag, viewName = 'RCTView' }: ViewInfo) {
25+
constructor(
26+
{ shadowNodeWrapper, viewTag, viewName = 'RCTView' }: ViewInfo,
27+
componentChildName?: string
28+
) {
2629
const tag = (this.viewTag = viewTag as number);
2730
const wrapper = shadowNodeWrapper as ShadowNodeWrapper;
2831

2932
this.viewName = viewName;
30-
this.propsBuilder = hasPropsBuilder(viewName)
31-
? getPropsBuilder(viewName)
33+
this.propsBuilder = hasPropsBuilder(viewName, componentChildName)
34+
? getPropsBuilder(viewName, componentChildName)
3235
: null;
3336
this.cssAnimationsManager = new CSSAnimationsManager(
3437
wrapper,
3538
viewName,
36-
tag
39+
tag,
40+
componentChildName
3741
);
3842
this.cssTransitionsManager = new CSSTransitionsManager(wrapper, tag);
3943
}

packages/react-native-reanimated/src/css/native/normalization/animation/keyframes.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,12 @@ function processProps(
144144

145145
export function normalizeAnimationKeyframes(
146146
keyframes: CSSAnimationKeyframes,
147-
viewName: string
147+
viewName: string,
148+
componentChildName?: string
148149
): NormalizedCSSAnimationKeyframesConfig {
149-
const propsBuilder = getPropsBuilder(viewName);
150+
const propsBuilder = getPropsBuilder(viewName, componentChildName);
150151
const separatelyInterpolatedNestedProperties =
151-
getSeparatelyInterpolatedNestedProperties(viewName);
152+
getSeparatelyInterpolatedNestedProperties(viewName, componentChildName);
152153
const propKeyframes: PropsWithKeyframes = {};
153154
const timingFunctions: NormalizedCSSKeyframeTimingFunctions = {};
154155

0 commit comments

Comments
 (0)