mirror of
https://github.com/zhigang1992/nativewind.git
synced 2026-06-16 02:34:28 +08:00
feat: add cva
This commit is contained in:
25
package-lock.json
generated
25
package-lock.json
generated
@@ -14632,6 +14632,22 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/class-variance-authority": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.2.4.tgz",
|
||||
"integrity": "sha512-JJKn9ESARiNEBBRdTSPB9/SwaPb+wi19DMX/r8BVSyp1dxHa3JyUxa2GQjEVag5rBi+O3pL64UZ0XhnQsMz+3w==",
|
||||
"funding": {
|
||||
"url": "https://joebell.co.uk"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">= 4.5.5 < 5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/clean-css": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz",
|
||||
@@ -34808,6 +34824,7 @@
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "7.18.6",
|
||||
"@babel/types": "7.19.4",
|
||||
"class-variance-authority": "^0.2.4",
|
||||
"css-tree": "^2.2.1",
|
||||
"find-cache-dir": "^3.3.2",
|
||||
"micromatch": "^4.0.5",
|
||||
@@ -45978,6 +45995,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"class-variance-authority": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.2.4.tgz",
|
||||
"integrity": "sha512-JJKn9ESARiNEBBRdTSPB9/SwaPb+wi19DMX/r8BVSyp1dxHa3JyUxa2GQjEVag5rBi+O3pL64UZ0XhnQsMz+3w=="
|
||||
},
|
||||
"clean-css": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz",
|
||||
@@ -54271,6 +54293,7 @@
|
||||
"@types/react-native": "0.70.6",
|
||||
"@types/use-sync-external-store": "0.0.3",
|
||||
"babel-plugin-tester": "10.1.0",
|
||||
"class-variance-authority": "*",
|
||||
"css-tree": "^2.2.1",
|
||||
"find-cache-dir": "^3.3.2",
|
||||
"jest": "29.2.1",
|
||||
@@ -60555,7 +60578,7 @@
|
||||
"clsx": "1.2.1",
|
||||
"dedent": "0.7.0",
|
||||
"docusaurus-plugin-sass": "0.2.2",
|
||||
"front-matter": "*",
|
||||
"front-matter": "^4.0.2",
|
||||
"lodash.debounce": "4.0.8",
|
||||
"nativewind": "^3.0.0-65eddcf.0",
|
||||
"prism-react-renderer": "1.3.3",
|
||||
|
||||
@@ -50,8 +50,9 @@
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": "7.18.6",
|
||||
"@babel/types": "7.19.4",
|
||||
"find-cache-dir": "^3.3.2",
|
||||
"class-variance-authority": "^0.2.4",
|
||||
"css-tree": "^2.2.1",
|
||||
"find-cache-dir": "^3.3.2",
|
||||
"micromatch": "^4.0.5",
|
||||
"react-is": "^18.1.0",
|
||||
"use-sync-external-store": "^1.1.0"
|
||||
|
||||
19
packages/nativewind/src/styled/cva.ts
Normal file
19
packages/nativewind/src/styled/cva.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type {
|
||||
StringToBoolean,
|
||||
ClassValue,
|
||||
ClassProp,
|
||||
} from "class-variance-authority/dist/types";
|
||||
|
||||
type ConfigSchema = Record<string, Record<string, ClassValue>>;
|
||||
type ConfigVariants<T extends ConfigSchema> = {
|
||||
[Variant in keyof T]?: StringToBoolean<keyof T[Variant]> | null;
|
||||
};
|
||||
export type CVAConfig<T> = T extends ConfigSchema
|
||||
? {
|
||||
variants?: T;
|
||||
defaultVariants?: ConfigVariants<T>;
|
||||
compoundVariants?: (T extends ConfigSchema
|
||||
? ConfigVariants<T> & ClassProp
|
||||
: ClassProp)[];
|
||||
}
|
||||
: never;
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ComponentType } from "react";
|
||||
import type { Style } from "../transform-css/types";
|
||||
import { CVAConfig } from "./cva";
|
||||
|
||||
export type PropsWithClassName<T> = T & {
|
||||
className?: string;
|
||||
@@ -8,11 +9,11 @@ export type PropsWithClassName<T> = T & {
|
||||
baseTw?: string;
|
||||
};
|
||||
|
||||
export interface StyledOptions<T, P extends keyof T> {
|
||||
export type StyledOptions<T, P extends keyof T> = CVAConfig<T> & {
|
||||
props?: Partial<Record<P, keyof Style | true>>;
|
||||
classProps?: (keyof T & string)[];
|
||||
baseClassName?: string;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Default
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
getStyleSet,
|
||||
subscribeToStyleSheet,
|
||||
} from "../../style-sheet/native/runtime";
|
||||
import { cva } from "class-variance-authority";
|
||||
|
||||
const stateInheritanceContent = createContext<ConditionalStateRecord>({});
|
||||
|
||||
@@ -33,30 +34,42 @@ export function styled(
|
||||
styledBaseClassNameOrOptions?:
|
||||
| string
|
||||
| StyledOptions<Record<string, unknown>, string>,
|
||||
maybeOptions: StyledOptions<Record<string, unknown>, string> = {}
|
||||
maybeOptions: StyledOptions<any, any> = {}
|
||||
) {
|
||||
const { props: propsToTransform, classProps } =
|
||||
typeof styledBaseClassNameOrOptions === "object"
|
||||
? styledBaseClassNameOrOptions
|
||||
: maybeOptions;
|
||||
const {
|
||||
classProps,
|
||||
baseClassName = "",
|
||||
props: propsToTransform,
|
||||
...cvaOptions
|
||||
} = typeof styledBaseClassNameOrOptions === "object"
|
||||
? styledBaseClassNameOrOptions
|
||||
: maybeOptions;
|
||||
|
||||
const baseClassName =
|
||||
const defaultClassName =
|
||||
typeof styledBaseClassNameOrOptions === "string"
|
||||
? styledBaseClassNameOrOptions
|
||||
: maybeOptions?.baseClassName;
|
||||
: baseClassName;
|
||||
|
||||
const Styled = forwardRef((props, ref) => {
|
||||
return (
|
||||
<StyledComponent
|
||||
ref={ref}
|
||||
component={component}
|
||||
propsToTransform={propsToTransform}
|
||||
classProps={classProps}
|
||||
baseClassName={baseClassName}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
});
|
||||
const classGenerator = cva(defaultClassName, cvaOptions);
|
||||
|
||||
const Styled = forwardRef<unknown, any>(
|
||||
({ className, tw, ...props }, ref) => {
|
||||
const generatedClassName = classGenerator({
|
||||
class: tw ?? className,
|
||||
...props,
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledComponent
|
||||
ref={ref}
|
||||
component={component}
|
||||
propsToTransform={propsToTransform}
|
||||
className={generatedClassName}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
if (typeof component !== "string") {
|
||||
Styled.displayName = `NativeWind.${
|
||||
component.displayName || component.name || "NoName"
|
||||
@@ -69,8 +82,7 @@ export function styled(
|
||||
export const StyledComponent = forwardRef(function NativeWindStyledComponent(
|
||||
{
|
||||
component: Component,
|
||||
baseClassName,
|
||||
tw: twClassName,
|
||||
tw,
|
||||
className: propClassName,
|
||||
propsToTransform,
|
||||
classProps,
|
||||
@@ -89,15 +101,11 @@ export const StyledComponent = forwardRef(function NativeWindStyledComponent(
|
||||
*/
|
||||
const [componentState, componentStateDispatch] = useComponentState();
|
||||
|
||||
const classNameWithDefaults = [baseClassName, twClassName ?? propClassName]
|
||||
.filter(Boolean)
|
||||
.join(" ");
|
||||
|
||||
/**
|
||||
* Resolve the props/classProps/spreadProps options
|
||||
*/
|
||||
const { styledProps, className } = withStyledProps({
|
||||
className: classNameWithDefaults,
|
||||
className: tw ?? propClassName,
|
||||
propsToTransform,
|
||||
classProps,
|
||||
componentState,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { ComponentType, ForwardedRef, forwardRef, useMemo } from "react";
|
||||
import { StyleProp } from "react-native";
|
||||
import { cva } from "class-variance-authority";
|
||||
import { Style } from "../../transform-css/types";
|
||||
import type { PropsWithClassName, StyledOptions } from "../index";
|
||||
|
||||
@@ -10,17 +11,19 @@ export function styled(
|
||||
ref: ForwardedRef<unknown>;
|
||||
}>,
|
||||
styledBaseClassNameOrOptions?: string | StyledOptions<unknown, never>,
|
||||
maybeOptions: StyledOptions<unknown, never> = {}
|
||||
maybeOptions: StyledOptions<any, any> = {}
|
||||
) {
|
||||
const { classProps } =
|
||||
const { classProps, baseClassName, props, ...cvaOptions } =
|
||||
typeof styledBaseClassNameOrOptions === "object"
|
||||
? styledBaseClassNameOrOptions
|
||||
: maybeOptions;
|
||||
|
||||
const baseClassName =
|
||||
const defaultClassName =
|
||||
typeof styledBaseClassNameOrOptions === "string"
|
||||
? styledBaseClassNameOrOptions
|
||||
: maybeOptions?.baseClassName;
|
||||
: baseClassName;
|
||||
|
||||
const classGenerator = cva(`${classProps} ${defaultClassName} `, cvaOptions);
|
||||
|
||||
return forwardRef(
|
||||
(
|
||||
@@ -32,17 +35,19 @@ export function styled(
|
||||
}: PropsWithClassName<{ style: Style }>,
|
||||
ref
|
||||
) => {
|
||||
let actualClassName = tw ?? className;
|
||||
|
||||
if (classProps) actualClassName = `${classProps} ${actualClassName}`;
|
||||
if (baseClassName)
|
||||
actualClassName = `${baseClassName} ${actualClassName}`;
|
||||
const generatedClassName = classGenerator({
|
||||
class: tw ?? className,
|
||||
...props,
|
||||
});
|
||||
|
||||
const style = useMemo(() => {
|
||||
return actualClassName
|
||||
? [{ $$css: true, tailwind: actualClassName } as Style, inlineStyle]
|
||||
return generatedClassName
|
||||
? [
|
||||
{ $$css: true, tailwind: generatedClassName } as Style,
|
||||
inlineStyle,
|
||||
]
|
||||
: inlineStyle;
|
||||
}, [inlineStyle, actualClassName]);
|
||||
}, [inlineStyle, generatedClassName]);
|
||||
|
||||
return <Component ref={ref} {...props} style={style} />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user