Skip to content

Commit 2e6159a

Browse files
committed
feat: component upgrading
1 parent f1988cf commit 2e6159a

File tree

7 files changed

+153
-150
lines changed

7 files changed

+153
-150
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ These are the features that are "done". Only basic testing as been performed.
2727
- [ ] Style target prop
2828
- [ ] Metro
2929
- [ ] Update compiler to new syntax
30-
- [ ] Upgrading elements
30+
- [x] Upgrading elements
3131
- [ ] Animations
3232
- [ ] Transitions
3333
- [ ] Important styles

src/components/Text/Text.native.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import { useId } from "react";
22
import { Text as RNText, type TextProps } from "react-native";
33

44
import { useRef } from "../../native/useRef";
5-
import { useStyled } from "../../native/useStyled";
5+
import { useStyledProps } from "../../native/useStyled";
66
import { StyleRegistry } from "../../specs/StyleRegistry";
77
import { copyComponentProperties, getDeepKeys } from "../../utils";
88

99
export const Text = copyComponentProperties(RNText, (props: TextProps) => {
1010
const componentId = useId();
1111

12-
const style = useStyled(
12+
const style = useStyledProps(
1313
componentId,
1414
(props as Record<string, string>).className,
1515
props,
Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,45 @@
11
import { useId } from "react";
2-
import { View as RNView, type ViewProps } from "react-native";
2+
import { Pressable, View as RNView, type ViewProps } from "react-native";
33

4+
import { useElement } from "../../native/useElement";
45
import { useRef } from "../../native/useRef";
5-
import { useStyled } from "../../native/useStyled";
6+
import { useStyledProps } from "../../native/useStyled";
67
import { StyleRegistry } from "../../specs/StyleRegistry";
78
import { copyComponentProperties, getDeepKeys } from "../../utils";
89

9-
export const View = copyComponentProperties(RNView, (props: ViewProps) => {
10-
const componentId = useId();
10+
export const View = copyComponentProperties(
11+
RNView,
12+
(originalProps: ViewProps) => {
13+
let p = originalProps as Record<string, any>;
14+
const componentId = useId();
15+
const ref = useRef(componentId, p.ref);
16+
const next = useStyledProps(componentId, p.className, p);
1117

12-
const style = useStyled(
13-
componentId,
14-
(props as Record<string, string>).className,
15-
props,
16-
);
18+
if (p.style) {
19+
StyleRegistry.updateComponentInlineStyleKeys(
20+
componentId,
21+
getDeepKeys(p.style),
22+
);
23+
}
1724

18-
const ref = useRef(componentId, (props as Record<string, any>).ref);
25+
p = {
26+
...next.props,
27+
...p,
28+
...next.importantProps,
29+
ref,
30+
style:
31+
next.style || next.importantStyle
32+
? [next.style, p.style, next.importantStyle]
33+
: p.style,
34+
};
1935

20-
if (props.style) {
21-
StyleRegistry.updateComponentInlineStyleKeys(
36+
return useElement(
37+
next.declarations.active || next.declarations.hover ? Pressable : RNView,
2238
componentId,
23-
getDeepKeys(props.style),
39+
next,
40+
p,
2441
);
25-
}
26-
27-
return (
28-
<RNView
29-
{...style.props}
30-
{...props}
31-
{...style.importantProps}
32-
ref={ref}
33-
style={
34-
style.style || style.importantStyle
35-
? [style.style, props.style, style.importantStyle]
36-
: props.style
37-
}
38-
/>
39-
);
40-
});
42+
},
43+
);
4144

4245
export default View;

src/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { Math } from "./specs/Math.nitro";
66
export { StyleRegistry } from "./specs/StyleRegistry";
77
export type * from "./specs/StyleRegistry";
88

9-
export { useStyled } from "./native/useStyled";
9+
export { useStyledProps as useStyled } from "./native/useStyled";
1010
export * from "./native/specificity";
1111

1212
const CssNitroHybridObject =

src/native/useElement.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { createElement, type ComponentType, type ExoticComponent } from "react";
2+
3+
import { StyleRegistry } from "../specs/StyleRegistry";
4+
import { ContainerContext, VariableContext } from "./contexts";
5+
import type { useStyledProps } from "./useStyled";
6+
7+
export function useElement(
8+
component: ComponentType | ExoticComponent<any>,
9+
componentId: string,
10+
next: ReturnType<typeof useStyledProps>,
11+
p: Record<string, any>,
12+
) {
13+
if (next.declarations.active) {
14+
p.onPress =
15+
p.onPress ??
16+
(() => {
17+
return;
18+
});
19+
p.onPressIn = onPressIn(componentId, p);
20+
p.onPressOut = onPressOut(componentId, p);
21+
}
22+
23+
if (next.declarations.hover) {
24+
p.onHoverIn = onHoverIn(componentId, p);
25+
p.onHoverOut = onHoverOut(componentId, p);
26+
}
27+
28+
if (next.declarations.focus) {
29+
p.onFocus = onFocus(componentId, p);
30+
p.onBlur = onBlur(componentId, p);
31+
}
32+
33+
if (next.declarations.animated) {
34+
component = getAnimatedComponent(component);
35+
}
36+
37+
if (next.containerScope === componentId) {
38+
p = {
39+
value: next.containerScope,
40+
children: createElement(component, p),
41+
};
42+
component = ContainerContext;
43+
}
44+
45+
if (next.variableScope === componentId) {
46+
p = {
47+
value: next.variableScope,
48+
children: createElement(component, p),
49+
};
50+
component = VariableContext;
51+
}
52+
53+
return createElement(component, p);
54+
}
55+
56+
const onPressIn = (id: string, props: Record<string, any>) => () => {
57+
props.onPressIn?.();
58+
StyleRegistry.updateComponentState(id, "active", true);
59+
};
60+
61+
const onPressOut = (id: string, props: Record<string, any>) => () => {
62+
props.onPressIn?.();
63+
StyleRegistry.updateComponentState(id, "active", false);
64+
};
65+
66+
const onHoverIn = (id: string, props: Record<string, any>) => () => {
67+
props.onHoverIn?.();
68+
StyleRegistry.updateComponentState(id, "hover", true);
69+
};
70+
71+
const onHoverOut = (id: string, props: Record<string, any>) => () => {
72+
props.onHoverOut?.();
73+
StyleRegistry.updateComponentState(id, "hover", false);
74+
};
75+
76+
const onFocus = (id: string, props: Record<string, any>) => () => {
77+
props.onFocus?.();
78+
StyleRegistry.updateComponentState(id, "focus", true);
79+
};
80+
81+
const onBlur = (id: string, props: Record<string, any>) => () => {
82+
props.onBlur?.();
83+
StyleRegistry.updateComponentState(id, "focus", false);
84+
};
85+
86+
const animatedCache = new WeakMap<ComponentType, ComponentType>();
87+
function getAnimatedComponent(component: ComponentType) {
88+
if (
89+
"displayName" in component &&
90+
component.displayName?.startsWith("Animated.")
91+
) {
92+
return component;
93+
}
94+
95+
const cached = animatedCache.get(component);
96+
if (cached) {
97+
return cached;
98+
}
99+
100+
// eslint-disable-next-line @typescript-eslint/no-require-imports
101+
const createAnimatedComponent = require("react-native-reanimated")
102+
.createAnimatedComponent as (component: ComponentType) => ComponentType;
103+
104+
const animatedComponent = createAnimatedComponent(component);
105+
animatedCache.set(component, animatedComponent);
106+
return animatedComponent;
107+
}

src/native/useHandlers.ts

Lines changed: 0 additions & 109 deletions
This file was deleted.

src/native/useStyled.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import type { AnyMap } from "react-native-nitro-modules";
44

55
import { StyleRegistry, type Declarations } from "../specs/StyleRegistry";
66
import { ContainerContext, VariableContext } from "./contexts";
7-
import { useHandlers } from "./useHandlers";
87

98
const EMPTY_DECLARATIONS: Declarations = { classNames: "" };
109

11-
export function useStyled(
10+
export function useStyledProps(
1211
componentId: string,
1312
className: string | undefined,
14-
props: Record<string, any>,
13+
originalProps: Record<string, any>,
1514
isDisabled = false,
1615
) {
1716
const [instance, rerender] = useReducer(() => ({}), {});
@@ -32,7 +31,7 @@ export function useStyled(
3231

3332
if (declarations.requiresRuntimeCheck) {
3433
for (const entry of declarations.requiresRuntimeCheck) {
35-
if (entry[1](componentId, props as AnyMap, isDisabled)) {
34+
if (entry[1](componentId, originalProps as AnyMap, isDisabled)) {
3635
validClassNames += " " + entry[0];
3736
}
3837
}
@@ -41,7 +40,7 @@ export function useStyled(
4140
// Update the variable scope after we have retrieved the declarations, so it uses its own scope
4241
variableScope = declarations.variableScope ?? variableScope;
4342

44-
let styled = useMemo(() => {
43+
const props = useMemo(() => {
4544
if (!validClassNames) {
4645
return {};
4746
}
@@ -65,7 +64,10 @@ export function useStyled(
6564
[componentId],
6665
);
6766

68-
styled = useHandlers(componentId, props, declarations, styled);
69-
70-
return styled;
67+
return {
68+
...props,
69+
declarations,
70+
variableScope: variableScope,
71+
containerScope,
72+
};
7173
}

0 commit comments

Comments
 (0)