fix: improvements to spreadProps with preview mode

This commit is contained in:
Mark Lawlor
2022-05-27 23:28:16 +10:00
parent 82f6419f7c
commit 3d4941ac9d
3 changed files with 50 additions and 20 deletions

View File

@@ -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];
}
}

View File

@@ -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;
}
}
}

View File

@@ -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>;
}