mirror of
https://github.com/zhigang1992/nativewind.git
synced 2026-06-15 10:17:54 +08:00
fix: improvements to spreadProps with preview mode
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { UseTailwindOptions } from "./use-tailwind";
|
||||
|
||||
const cacheKey = Symbol("tailwind-cache-key");
|
||||
|
||||
let stylesheet: CSSStyleSheet & {
|
||||
@@ -12,13 +14,16 @@ let stylesheet: CSSStyleSheet & {
|
||||
* This hasn't been benched-marked, but is assumed to be slow and unreliable.
|
||||
* This is why we recommend people avoid using useTailwind()/spreadProps for runtime values.
|
||||
*/
|
||||
export function classNameToInlineStyle(className: string) {
|
||||
export function classNameToInlineStyle(
|
||||
className: string,
|
||||
options: UseTailwindOptions = {}
|
||||
) {
|
||||
if (!stylesheet) findStyleSheet(className);
|
||||
|
||||
const styles = {};
|
||||
for (const name of className.split(/\s+/)) {
|
||||
if (!name) continue;
|
||||
Object.assign(styles, getStyles(name));
|
||||
Object.assign(styles, getStyles(CSS.escape(name), options));
|
||||
}
|
||||
|
||||
return styles;
|
||||
@@ -28,8 +33,9 @@ export function classNameToInlineStyle(className: string) {
|
||||
* Finds a stylesheet that includes this css selector
|
||||
*/
|
||||
function findStyleSheet(className: string) {
|
||||
const firstClassName = className.split(/\s+/).find(Boolean);
|
||||
if (stylesheet) return stylesheet;
|
||||
|
||||
const firstClassName = className.split(/\s+/).find(Boolean) as string;
|
||||
const maybeStyleSheet = [
|
||||
...(document.styleSheets as unknown as CSSStyleSheet[]),
|
||||
].find((stylesheet) => {
|
||||
@@ -37,7 +43,7 @@ function findStyleSheet(className: string) {
|
||||
(cssRule) => {
|
||||
return (
|
||||
isCSSStyleRule(cssRule) &&
|
||||
cssRule.selectorText.includes(`.${firstClassName}`)
|
||||
cssRule.selectorText.includes(`.${CSS.escape(firstClassName)}`)
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -48,27 +54,45 @@ function findStyleSheet(className: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function getStyles(className: string) {
|
||||
if (stylesheet[cacheKey][className]) {
|
||||
return stylesheet[cacheKey][className];
|
||||
function getStyles(
|
||||
className: string,
|
||||
{ active, focus, hover }: UseTailwindOptions
|
||||
) {
|
||||
const classNameCacheKey = `${className}:${active}:${focus}:${hover}`;
|
||||
|
||||
if (stylesheet[cacheKey][classNameCacheKey]) {
|
||||
return stylesheet[cacheKey][classNameCacheKey];
|
||||
}
|
||||
|
||||
const rule = [
|
||||
...(stylesheet.cssRules as unknown as CSSRule[]),
|
||||
].find<CSSStyleRule>((cssRule): cssRule is CSSStyleRule => {
|
||||
return (
|
||||
isCSSStyleRule(cssRule) && cssRule.selectorText.includes(`.${className}`)
|
||||
);
|
||||
if (
|
||||
isCSSStyleRule(cssRule) &&
|
||||
cssRule.selectorText.includes(`.${className}`)
|
||||
) {
|
||||
const states = [];
|
||||
|
||||
// We cannot just test for `:active` as it will match hover\\:active-foobar:hover
|
||||
// Due to how classNames are escaped, we can just check for :active and ensure
|
||||
// it doesn't have an escape character before it.
|
||||
if (/(?<!\\):active/.test(cssRule.selectorText)) states.push(active);
|
||||
if (/(?<!\\):focus/.test(cssRule.selectorText)) states.push(focus);
|
||||
if (/(?<!\\):hover/.test(cssRule.selectorText)) states.push(hover);
|
||||
|
||||
return states.every(Boolean);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
stylesheet[cacheKey][className] = {};
|
||||
stylesheet[cacheKey][classNameCacheKey] = {};
|
||||
|
||||
if (rule) {
|
||||
for (const key of rule.style as unknown as string[]) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
stylesheet[cacheKey][className][toCamelCase(key)] = (rule.style as any)[
|
||||
key
|
||||
];
|
||||
stylesheet[cacheKey][classNameCacheKey][toCamelCase(key)] =
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(rule.style as any)[key];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ export interface Interaction extends PressableProps {
|
||||
active: boolean;
|
||||
hover: boolean;
|
||||
focus: boolean;
|
||||
onMouseDown?: PressableProps["onPressIn"];
|
||||
onMouseUp?: PressableProps["onPressOut"];
|
||||
onPointerDown?: PressableProps["onPressIn"];
|
||||
onPointerUp?: PressableProps["onPressOut"];
|
||||
}
|
||||
|
||||
export interface UseInteractionOptions extends PressableProps {
|
||||
@@ -33,6 +33,7 @@ export function useInteraction({
|
||||
onHoverOut,
|
||||
onPressIn,
|
||||
onPressOut,
|
||||
platform,
|
||||
className = "",
|
||||
}: UseInteractionOptions) {
|
||||
const [hover, setHover] = useState(false);
|
||||
@@ -157,8 +158,13 @@ export function useInteraction({
|
||||
interaction.onHoverOut = handleHoverOut;
|
||||
}
|
||||
if (className.includes("active:")) {
|
||||
interaction.onPressIn = handlePressIn;
|
||||
interaction.onPressOut = handlePressOut;
|
||||
if (platform === "web") {
|
||||
interaction.onPointerDown = handlePressIn;
|
||||
interaction.onPointerUp = handlePressOut;
|
||||
} else {
|
||||
interaction.onPressIn = handlePressIn;
|
||||
interaction.onPressOut = handlePressOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export function useTailwind<
|
||||
{ flatten = true }: UseTailwindCallbackOptions<F> = {}
|
||||
) => {
|
||||
return flatten
|
||||
? classNameToInlineStyle(className)
|
||||
? classNameToInlineStyle(className, useTailwindOptions)
|
||||
: { $$css: true, tailwindClassName: className };
|
||||
}) as UseTailwindCallback<P>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user