Skip to content

Commit

Permalink
fix: various fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
marklawlor committed Jul 24, 2023
1 parent 95b71d1 commit 28651d9
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 88 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { render } from "@testing-library/react-native";
import { StyleSheet as RNStyleSheet } from "react-native";

import { StyleSheet } from "../runtime/native/stylesheet";
import { createMockComponent, registerCSS } from "../testing-library";
Expand All @@ -23,4 +24,17 @@ describe("functions - ios", () => {

expect(A).styleToEqual({ color: "black" });
});

test("hairlineWidth", () => {
registerCSS(
`.my-class {
--test: hairlineWidth();
width: var(--test);
}`,
);

render(<A className="my-class" />);

expect(A).styleToEqual({ width: RNStyleSheet.hairlineWidth });
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ test("inherit variables", () => {
expect(B).styleToEqual({ width: 20 });
});

test.only(":root variables", () => {
test(":root variables", () => {
registerCSS(`
:root { --my-var: red; }
.my-class { color: var(--my-var); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1515,8 +1515,22 @@ function parseUnparsed(
case "scaleX":
case "scaleY":
return unparsedFunction(tokenOrValue, options);
case "platformColor":
case "getPixelSizeForLayoutSize":
case "roundToNearestPixel":
case "getfontScale":
case "getPixelRatio":
return unparsedFunction(tokenOrValue, options);
case "hairlineWidth":
return {
type: "runtime",
name: tokenOrValue.value.name,
arguments: [],
};
case "platformSelect":
return parseReactNativeFunction(
case "fontScaleSelect":
case "pixelScaleSelect":
return parseRNRuntimeSpecificsFunction(
tokenOrValue.value.name,
tokenOrValue.value.arguments,
options,
Expand Down Expand Up @@ -2232,7 +2246,7 @@ function parseGap(
return parseLength(value.value, options);
}

function parseReactNativeFunction(
function parseRNRuntimeSpecificsFunction(
name: string,
args: TokenOrValue[],
options: ParseDeclarationOptionsWithValueWarning,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ import {
} from "react";
import { View, Pressable } from "react-native";

import {
ContainerRuntime,
CssInteropPropMapping,
InteropMeta,
StyleMeta,
} from "../../types";
import { ContainerRuntime, InteropMeta, StyleMeta } from "../../types";
import { AnimationInterop } from "./animations";
import { flattenStyle } from "./flatten-style";
import { ContainerContext, globalStyles, styleMetaMap } from "./globals";
Expand All @@ -24,6 +19,7 @@ import { StyleSheet, VariableContext, useVariables } from "./stylesheet";

type CSSInteropWrapperProps = {
__component: ComponentType<any>;
__jsx: Function;
} & Record<string, any>;

/**
Expand Down Expand Up @@ -53,7 +49,7 @@ export function defaultCSSInterop(
if (styles.some((s) => s && styleMetaMap.has(s))) {
return jsx(
CSSInteropWrapper,
{ ...props, className: classNames, __component: type },
{ ...props, className: classNames, __component: type, __jsx: jsx },
key,
);
}
Expand Down Expand Up @@ -86,7 +82,12 @@ export function defaultCSSInterop(
* @param ref - Ref to the component
*/
const CSSInteropWrapper = forwardRef(function CSSInteropWrapper(
{ __component: Component, className, ...$props }: CSSInteropWrapperProps,
{
__component: component,
__jsx: jsx,
className,
...$props
}: CSSInteropWrapperProps,
ref,
) {
const rerender = useRerender();
Expand Down Expand Up @@ -261,10 +262,10 @@ const CSSInteropWrapper = forwardRef(function CSSInteropWrapper(
}

if (
Component === View &&
component === View &&
(interopMeta.hasActive || interopMeta.hasHover || interopMeta.hasFocus)
) {
Component = Pressable;
component = Pressable;
}

const variables = useMemo(
Expand All @@ -286,44 +287,32 @@ const CSSInteropWrapper = forwardRef(function CSSInteropWrapper(

let children: JSX.Element = props.children;

// Call `jsx` directly so we can bypass the polyfill render method
if (interopMeta.hasInlineVariables) {
children = (
<VariableContext.Provider value={variables}>
{children}
</VariableContext.Provider>
);
children = jsx(VariableContext.Provider, { value: variables, children });
}

if (interopMeta.hasInlineContainers) {
children = (
<ContainerContext.Provider value={containers}>
{children}
</ContainerContext.Provider>
);
children = jsx(ContainerContext.Provider, { value: containers, children });
}

if (interopMeta.animationInteropKey) {
return (
<AnimationInterop
{...props}
ref={ref}
key={interopMeta.animationInteropKey}
__component={Component}
__variables={variables}
__containers={inheritedContainers}
__interaction={interaction}
__interopMeta={interopMeta}
__skipCssInterop
>
{children}
</AnimationInterop>
return jsx(
AnimationInterop,
{
...props,
ref,
children,
__component: component,
__variables: variables,
__containers: inheritedContainers,
__interaction: interaction,
__interopMeta: interopMeta,
},
interopMeta.animationInteropKey,
);
} else {
return (
<Component {...props} ref={ref} __skipCssInterop>
{children}
</Component>
);
return jsx(component, { ...props, ref, children });
}
});

Expand Down
100 changes: 76 additions & 24 deletions packages/react-native-css-interop/src/runtime/native/flatten-style.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Platform } from "react-native";
import { Platform, PlatformColor, StyleSheet } from "react-native";
import { isRuntimeValue } from "../../shared";
import {
Interaction,
Expand Down Expand Up @@ -381,64 +381,116 @@ function extractValue(
case "scaleX":
case "scaleY":
case "scale":
return extractRuntimeFunction(value, flatStyle, flatStyleMeta, options, {
shouldRunwrap: true,
shouldParseFloat: true,
return createRuntimeFunction(value, flatStyle, flatStyleMeta, options, {
wrap: false,
parseFloat: true,
});
case "rotate":
case "rotateX":
case "rotateY":
case "rotateZ":
case "skewX":
case "skewY":
return extractRuntimeFunction(value, flatStyle, flatStyleMeta, options, {
shouldRunwrap: true,
return createRuntimeFunction(value, flatStyle, flatStyleMeta, options, {
wrap: false,
});
case "hairlineWidth":
return StyleSheet.hairlineWidth;
case "platformSelect":
return extractValue(
Platform.select(value.arguments[0]),
return createRuntimeFunction(
{
...value,
arguments: [Platform.select(value.arguments[0])],
},
flatStyle,
flatStyleMeta,
options,
{
wrap: false,
},
);
case "platformColor":
return createRuntimeFunction(value, flatStyle, flatStyleMeta, options, {
wrap: false,
joinArgs: false,
callback: PlatformColor,
spreadCallbackArgs: true,
});
default: {
return extractRuntimeFunction(value, flatStyle, flatStyleMeta, options);
return createRuntimeFunction(value, flatStyle, flatStyleMeta, options);
}
}
}

function extractRuntimeFunction(
interface CreateRuntimeFunctionOptions {
wrap?: boolean;
parseFloat?: boolean;
joinArgs?: boolean;
callback?: Function;
spreadCallbackArgs?: boolean;
}

/**
* TODO: This function is overloaded with functionality
*/
function createRuntimeFunction(
value: RuntimeValue,
flatStyle: Style,
flatStyleMeta: StyleMeta,
options: FlattenStyleOptions,
{ shouldRunwrap = false, shouldParseFloat = false } = {},
{
wrap = true,
parseFloat: shouldParseFloat = false,
joinArgs = true,
spreadCallbackArgs = false,
callback,
}: CreateRuntimeFunctionOptions = {},
) {
let isStatic = true;
const args: unknown[] = [];

for (const arg of value.arguments) {
const getterOrValue = extractValue(arg, flatStyle, flatStyleMeta, options);
if (value.arguments) {
for (const arg of value.arguments) {
const getterOrValue = extractValue(
arg,
flatStyle,
flatStyleMeta,
options,
);

if (typeof getterOrValue === "function") {
isStatic = false;
}
if (typeof getterOrValue === "function") {
isStatic = false;
}

args.push(getterOrValue);
args.push(getterOrValue);
}
}

const valueFn = () => {
const $args = args
let $args: any = args
.map((a) => (typeof a === "function" ? a() : a))
.filter((a) => a !== undefined)
.join(", ");
.filter((a) => a !== undefined);

if (joinArgs) {
$args = $args.join(", ");

if ($args === "") {
return;
}
}

let result = wrap ? `${value.name}(${$args})` : $args;
result = shouldParseFloat ? parseFloat(result) : result;

if ($args === "") {
return;
if (callback) {
if (spreadCallbackArgs && Array.isArray(result)) {
return callback(...result);
} else {
return callback(result);
}
}

const result = shouldRunwrap ? $args : `${value.name}(${$args})`;
return shouldParseFloat ? parseFloat(result) : result;
return result;
};

return isStatic ? valueFn() : valueFn;
Expand Down
36 changes: 19 additions & 17 deletions packages/react-native-css-interop/src/runtime/native/stylesheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
StyleSheet as RNStyleSheet,
Appearance,
} from "react-native";
import { createContext, useContext } from "react";
import { createContext, useContext, useMemo } from "react";

import {
StyleSheetRegisterOptions,
Expand Down Expand Up @@ -211,20 +211,22 @@ let defaultDarkVariables: Record<string, unknown> = {};
export function useVariables() {
let $variables = useContext(VariableContext);

// $variables will be null if this is a top-level component
if ($variables === null) {
return Appearance.getColorScheme() === "light"
? rootVariables
: rootDarkVariables;
} else {
return Appearance.getColorScheme() === "light"
? {
...$variables,
...defaultVariables,
}
: {
...$variables,
...defaultDarkVariables,
};
}
return useMemo(() => {
// $variables will be null if this is a top-level component
if ($variables === null) {
return Appearance.getColorScheme() === "light"
? rootVariables
: rootDarkVariables;
} else {
return Appearance.getColorScheme() === "light"
? {
...$variables,
...defaultVariables,
}
: {
...$variables,
...defaultDarkVariables,
};
}
}, [$variables]);
}
6 changes: 1 addition & 5 deletions packages/react-native-css-interop/src/runtime/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,5 @@ export function render(
key: string,
) {
const cssInterop = polyfillMapping.get(type);
if (cssInterop && !props.__skipCssInterop) {
return cssInterop(jsx, type, props, key);
} else {
return jsx(type, props, key);
}
return cssInterop ? cssInterop(jsx, type, props, key) : jsx(type, props, key);
}

0 comments on commit 28651d9

Please sign in to comment.