mirror of
https://github.com/zhigang1992/nativewind.git
synced 2026-06-13 09:24:47 +08:00
fix: nesting platform functions in css variables
This commit is contained in:
@@ -16,8 +16,6 @@ const expectStyle = (style: string, config?: Partial<Config>, css?: string) => {
|
||||
`@tailwind components;@tailwind utilities;${css ?? ""}`
|
||||
);
|
||||
|
||||
console.log(createOptions);
|
||||
|
||||
return expect(createOptions);
|
||||
};
|
||||
|
||||
@@ -36,6 +34,68 @@ type OutputObject =
|
||||
type CaseOutput = Atom | CreateOptions | OutputObject;
|
||||
|
||||
const cases: Record<string, CaseOutput> = {
|
||||
"text-white": {
|
||||
css: `:root {
|
||||
--number: 255;
|
||||
--string: string;
|
||||
--unit: 123vw;
|
||||
--rgb: rgb(255, 255, 255);
|
||||
--default-value: var(--value, 2);
|
||||
--rgb-var: rgb(255, 255, var(--number));
|
||||
--inline-theme-value: var(--error-color,platformColor(ios__systemRed,android__colorError,default__red));
|
||||
font-size: 16;
|
||||
padding: 1px;
|
||||
}`,
|
||||
output: {
|
||||
":root": {
|
||||
variables: [
|
||||
{
|
||||
"--number": 255,
|
||||
"--string": "string",
|
||||
"--rem": 16,
|
||||
"--rgb": "rgb(255, 255, 255)",
|
||||
"--unit": {
|
||||
function: "vw",
|
||||
values: [123],
|
||||
},
|
||||
"--rgb-var": {
|
||||
function: "inbuilt",
|
||||
values: [
|
||||
"rgb",
|
||||
255,
|
||||
255,
|
||||
{
|
||||
function: "var",
|
||||
values: ["--number"],
|
||||
},
|
||||
],
|
||||
},
|
||||
"--default-value": {
|
||||
function: "var",
|
||||
values: ["--value", 2],
|
||||
},
|
||||
"--inline-theme-value": {
|
||||
function: "var",
|
||||
values: [
|
||||
"--error-color",
|
||||
{
|
||||
function: "platformColor",
|
||||
values: [
|
||||
"ios__systemRed",
|
||||
"android__colorError",
|
||||
"default__red",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
"text-white": {
|
||||
styles: [{ color: "#fff" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
// "text-apply": {
|
||||
// config: {
|
||||
// plugins: [
|
||||
@@ -95,30 +155,30 @@ const cases: Record<string, CaseOutput> = {
|
||||
// styles: [{ marginLeft: 8, marginTop: 8 }],
|
||||
// },
|
||||
// },
|
||||
"text-[color:hsl(var(--hue),var(--saturation),var(--lightness))]": {
|
||||
css: `:root { --hue: 255; }`,
|
||||
output: {
|
||||
":root": {
|
||||
variables: [{ "--hue": 255 }],
|
||||
},
|
||||
"text-[color:hsl(var(--hue),var(--saturation),var(--lightness))]": {
|
||||
styles: [
|
||||
{
|
||||
color: {
|
||||
function: "inbuilt",
|
||||
values: [
|
||||
"hsl",
|
||||
{ function: "var", values: ["--hue"] },
|
||||
{ function: "var", values: ["--saturation"] },
|
||||
{ function: "var", values: ["--lightness"] },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
topics: ["--hue", "--saturation", "--lightness"],
|
||||
},
|
||||
},
|
||||
},
|
||||
// "text-[color:hsl(var(--hue),var(--saturation),var(--lightness))]": {
|
||||
// css: `:root { --hue: 255; }`,
|
||||
// output: {
|
||||
// ":root": {
|
||||
// variables: [{ "--hue": 255 }],
|
||||
// },
|
||||
// "text-[color:hsl(var(--hue),var(--saturation),var(--lightness))]": {
|
||||
// styles: [
|
||||
// {
|
||||
// color: {
|
||||
// function: "inbuilt",
|
||||
// values: [
|
||||
// "hsl",
|
||||
// { function: "var", values: ["--hue"] },
|
||||
// { function: "var", values: ["--saturation"] },
|
||||
// { function: "var", values: ["--lightness"] },
|
||||
// ],
|
||||
// },
|
||||
// },
|
||||
// ],
|
||||
// topics: ["--hue", "--saturation", "--lightness"],
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// "w-screen": {
|
||||
// styles: [{ width: { function: "vw", values: [100] } }],
|
||||
// },
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/* eslint-disable unicorn/no-lonely-if */
|
||||
import { Block, CssNode, Declaration, walk } from "css-tree";
|
||||
import { Atom, AtomStyle, StyleWithFunction } from "../style-sheet";
|
||||
import { Block, CssNode, Declaration, walk, parse } from "css-tree";
|
||||
import { Atom, StyleWithFunction, VariableValue } from "../style-sheet";
|
||||
import { validProperties } from "./valid-styles";
|
||||
|
||||
import { TransformsStyle } from "react-native";
|
||||
import { flatten } from "./flatten";
|
||||
|
||||
export type StylesAndTopics = Required<
|
||||
Pick<Atom, "styles" | "topics" | "variables">
|
||||
@@ -58,7 +59,20 @@ export function getDeclarations(block: Block) {
|
||||
default: {
|
||||
if (node.value.type === "Raw") {
|
||||
if (node.property.startsWith("--")) {
|
||||
atom.variables.push({ [node.property]: node.value.value.trim() });
|
||||
const ast = parse(node.value.value.trim(), { context: "value" });
|
||||
|
||||
if (ast.type !== "Value") {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = parseStyleValue(ast.children.toArray()[0], []);
|
||||
if (typeof value === "object" && !("function" in value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value !== undefined) {
|
||||
atom.variables.push({ [node.property]: value });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return pushStyle(
|
||||
@@ -72,17 +86,9 @@ export function getDeclarations(block: Block) {
|
||||
},
|
||||
});
|
||||
|
||||
let styles: AtomStyle = {};
|
||||
|
||||
for (const style of atom.styles) {
|
||||
for (const [key, value] of Object.entries(style)) {
|
||||
styles = setValue(styles, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...atom,
|
||||
styles,
|
||||
styles: flatten(atom.styles),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -116,10 +122,11 @@ function parseStyleValue(
|
||||
node: StyleValue | null | undefined,
|
||||
topics: string[]
|
||||
): StyleValue | StyleValue[] | undefined {
|
||||
if (!node) return [];
|
||||
if (!node) return;
|
||||
|
||||
if (typeof node === "string") {
|
||||
return node;
|
||||
const maybeNumber = Number.parseFloat(node);
|
||||
return Number.isNaN(maybeNumber) ? node : maybeNumber;
|
||||
}
|
||||
|
||||
if (typeof node === "number") {
|
||||
@@ -163,16 +170,54 @@ function parseStyleValue(
|
||||
switch (node.name) {
|
||||
case "pixelRatio":
|
||||
return { function: "pixelRatio", values: [] };
|
||||
case "platformColor": {
|
||||
const children = node.children
|
||||
.toArray()
|
||||
.map((child) => parseStyleValue(child, topics))
|
||||
.filter((child) => Boolean(child));
|
||||
|
||||
return {
|
||||
function: "platformColor",
|
||||
values: children as unknown as VariableValue[],
|
||||
};
|
||||
}
|
||||
case "var": {
|
||||
const value = parseStyleValue(node.children.shift()?.data, topics);
|
||||
const children = node.children.toArray();
|
||||
const variableName = parseStyleValue(children[0], topics);
|
||||
|
||||
if (typeof value !== "string") return [];
|
||||
if (typeof variableName !== "string") return [];
|
||||
|
||||
topics.push(value);
|
||||
const values: StyleWithFunction["values"] = [variableName];
|
||||
topics.push(variableName);
|
||||
|
||||
if (children.length === 3) {
|
||||
const defaultChild = children[2];
|
||||
|
||||
if (defaultChild.type === "Raw") {
|
||||
const ast = parse(defaultChild.value, {
|
||||
context: "value",
|
||||
});
|
||||
|
||||
if (ast.type === "Value") {
|
||||
const defaultValue = parseStyleValue(
|
||||
ast.children.toArray()[0],
|
||||
[]
|
||||
);
|
||||
|
||||
if (typeof defaultValue === "object") {
|
||||
if ("function" in defaultValue) {
|
||||
values.push(defaultValue);
|
||||
}
|
||||
} else if (defaultValue) {
|
||||
values.push(defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
function: "var",
|
||||
values: [value],
|
||||
values,
|
||||
};
|
||||
}
|
||||
default: {
|
||||
@@ -204,26 +249,6 @@ function parseStyleValue(
|
||||
) as unknown as Transform;
|
||||
}
|
||||
|
||||
function setValue<T extends Record<string, unknown>>(
|
||||
object: T,
|
||||
is: string | string[],
|
||||
value: unknown
|
||||
): T {
|
||||
if (typeof is == "string") {
|
||||
return setValue<T>(object, is.split("."), value);
|
||||
} else if (is.length == 1) {
|
||||
(object as Record<string, unknown>)[is[0]] = value;
|
||||
return object;
|
||||
} else {
|
||||
(object as Record<string, unknown>)[is[0]] = setValue<T>(
|
||||
(object[is[0]] || {}) as T,
|
||||
is.slice(1),
|
||||
value
|
||||
);
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
function border(atom: StylesAndTopics, node: Declaration) {
|
||||
if (node.value.type !== "Value") {
|
||||
return;
|
||||
|
||||
@@ -8,6 +8,7 @@ import { CreateOptions } from "../style-sheet";
|
||||
import { parseMediaQuery, MediaQueryMeta } from "./media-query";
|
||||
import { getDeclarations } from "./declarations";
|
||||
import { getSelector } from "./selector";
|
||||
import { flatten } from "./flatten";
|
||||
|
||||
const skip = (walk as unknown as Record<string, unknown>).skip;
|
||||
|
||||
@@ -105,13 +106,11 @@ function addRule(
|
||||
// Invalid selector, skip it
|
||||
if (!selector) return;
|
||||
|
||||
if (selector === ":root") {
|
||||
createOptions[selector] ??= { variables };
|
||||
return;
|
||||
}
|
||||
|
||||
if (selector === "dark") {
|
||||
createOptions[selector] ??= { variables };
|
||||
if (selector === ":root" || selector === "dark") {
|
||||
if (styles.fontSize) {
|
||||
variables.push({ "--rem": styles.fontSize });
|
||||
}
|
||||
createOptions[selector] ??= { variables: [flatten(variables)] };
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
32
packages/nativewind/src/postcss/flatten.ts
Normal file
32
packages/nativewind/src/postcss/flatten.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
export function flatten<T extends Record<string, unknown>>(
|
||||
objectArray: T[]
|
||||
): T {
|
||||
let returnObject = {} as T;
|
||||
for (const object of objectArray) {
|
||||
for (const [key, value] of Object.entries(object)) {
|
||||
returnObject = setValue(returnObject, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return returnObject;
|
||||
}
|
||||
|
||||
function setValue<T extends Record<string, unknown>>(
|
||||
object: T,
|
||||
is: string | string[],
|
||||
value: unknown
|
||||
): T {
|
||||
if (typeof is == "string") {
|
||||
return setValue<T>(object, is.split("."), value);
|
||||
} else if (is.length == 1) {
|
||||
(object as Record<string, unknown>)[is[0]] = value;
|
||||
return object;
|
||||
} else {
|
||||
(object as Record<string, unknown>)[is[0]] = setValue<T>(
|
||||
(object[is[0]] || {}) as T,
|
||||
is.slice(1),
|
||||
value
|
||||
);
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ export type AtomStyle = {
|
||||
|
||||
export type StyleWithFunction = {
|
||||
function: string;
|
||||
values: Array<StyleWithFunction | string | number>;
|
||||
values: Array<VariableValue>;
|
||||
};
|
||||
|
||||
export type VariableValue =
|
||||
|
||||
Reference in New Issue
Block a user