Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
export class Screen extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {};
}
render() {
return (
<CView classNames={['a']}>
<CView classNames={['b']}>
<CView classNames={['c']} />
</CView>
</CView>
);
}
}
const styles = {
a: {
backgroundColor: 'red',
width: 400,
height: 400,
},
b: {
backgroundColor: 'blue',
width: 200,
height: 200,
},
c: {
backgroundColor: 'yellow',
width: 100,
height: 100,
},
'a c': {
borderRadius: 10,
},
};
interface WithClassProps {
classNames: string[];
componentTree?: ComponentTree;
style: StyleProp<ViewStyle>;
}
type ComponentTree = {
classNames: string[];
parent?: ComponentTree;
};
const satisfiesStyle = (styleKey: string, componentTree: ComponentTree) => {
const keys = styleKey.split(' ');
let currentComponentTree = componentTree;
let i: number;
for (i = keys.length - 1; i >= 0; ) {
const key = keys[i];
if (!currentComponentTree) {
return false;
}
if (currentComponentTree.classNames.includes(key)) {
i--;
}
currentComponentTree = currentComponentTree.parent;
}
return i === -1;
};
const deriveStyles = (componentTree: ComponentTree) => {
const dStyles: ViewStyle[] = [];
if (componentTree.classNames) {
for (const styleKey of Object.keys(styles)) {
if (satisfiesStyle(styleKey, componentTree)) {
dStyles.push((styles as any)[styleKey]);
}
}
}
return dStyles;
};
function withClass<P extends ViewProps>(
WrappedComponent: React.ComponentClass<P> | React.FunctionComponent<P>
): React.ComponentClass<P & WithClassProps> {
return class extends React.Component<P & WithClassProps> {
constructor(props: P & WithClassProps) {
super(props);
this.state = {};
}
componentTree: ComponentTree;
componentWillMount() {
this.componentTree = {
parent: this.props.componentTree,
classNames: this.props.classNames,
};
}
componentDidMount() {
this.componentTree.parent = this.props.componentTree;
this.componentTree.classNames = this.props.classNames;
}
componentWillUpdate(nextProps: Readonly<P & WithClassProps>): void {
this.componentTree.classNames = nextProps.classNames;
}
componentWillUnmount() {}
render() {
const derivedStyles = deriveStyles(this.componentTree);
const {style, ...props} = this.props;
return <WrappedComponent style={[derivedStyles, style]} {...props} componentTree={this.componentTree} />;
}
};
}
const CView = withClass(View);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment