From 822d0cc19f81cdf9cbd878c488d0083f58444536 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Mon, 20 Nov 2023 14:49:41 +0100 Subject: [PATCH 1/7] allow to reference components from the same file --- packages/example/app/Input.tsx | 10 +++- .../loaders/__tests__/cssloader.test.ts | 58 ++++++++++++++++++- .../loaders/__tests__/tsloader.test.ts | 53 +++++++++++++++-- .../next-yak/loaders/babel-yak-plugin.cjs | 39 ++++++++++++- packages/next-yak/loaders/cssloader.cjs | 27 ++++++++- .../loaders/lib/getStyledComponentName.cjs | 31 ++++++++++ .../lib/replaceQuasiExpressionTokens.cjs | 20 +++---- 7 files changed, 214 insertions(+), 24 deletions(-) create mode 100644 packages/next-yak/loaders/lib/getStyledComponentName.cjs diff --git a/packages/example/app/Input.tsx b/packages/example/app/Input.tsx index bf7f3a57..1bbd59d2 100644 --- a/packages/example/app/Input.tsx +++ b/packages/example/app/Input.tsx @@ -20,10 +20,14 @@ const PasswordInput = styled(Input).attrs({ border: 2px solid #167f8d; `; -const Centered = styled.div` +const Wrapper = styled.div` display: flex; flex-direction: column; align-items: center; + transition: background-color 0.5s ease-in-out; + &:has(${Input}:where(:hover, :focus), ${PasswordInput}:where(:hover, :focus)) { + background-color: #4c4c4cb9 + } `; const Headline = styled.h2` @@ -49,12 +53,12 @@ const Headline = styled.h2` export const Inputs = () => { return ( - + Styled Inputs - + ); }; diff --git a/packages/next-yak/loaders/__tests__/cssloader.test.ts b/packages/next-yak/loaders/__tests__/cssloader.test.ts index 7e4a324b..8332b104 100644 --- a/packages/next-yak/loaders/__tests__/cssloader.test.ts +++ b/packages/next-yak/loaders/__tests__/cssloader.test.ts @@ -193,7 +193,7 @@ const newHeadline = styled(headline).attrs({ color: red; } - .yak_1 { + .yak_2 { color: black; }" `); @@ -361,3 +361,59 @@ const FadeInButton = styled.button\` }" `); }); + + +it("should allow to target components", async () => { + expect( + await cssloader.call( + loaderContext, + ` +import { styled, keyframes } from "next-yak"; + +const Link = styled.a\` + color: palevioletred; +\` + +const Icon = styled.svg\` + fill: currentColor; + width: 1em; + height: 1em; + \${Link}:hover & { + color: red; + } + \${Link}:focus & { + color: red; + } +\` + +const Wrapper = styled.div\` + &:has(> \${Link}) { + padding: 10px; + } +\` +` + ) + ).toMatchInlineSnapshot(` + ".yak_0 { + color: palevioletred; + } + + .yak_2 { + fill: currentColor; + width: 1em; + height: 1em; + yak_1:hover & { + color: red; + } + yak_1:focus & { + color: red; + } + } + + .yak_4 { + &:has(> yak_1) { + padding: 10px; + } + }" + `); +}); diff --git a/packages/next-yak/loaders/__tests__/tsloader.test.ts b/packages/next-yak/loaders/__tests__/tsloader.test.ts index 6ef479ca..fa908d93 100644 --- a/packages/next-yak/loaders/__tests__/tsloader.test.ts +++ b/packages/next-yak/loaders/__tests__/tsloader.test.ts @@ -125,8 +125,8 @@ const FancyButton = styled(Button)\` import { styled, css } from \\"next-yak\\"; import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\"; const x = Math.random(); - const Button = styled.button(__styleYak.yak_0, x > 0.5 && css(__styleYak.yak_1)); - const FancyButton = styled(Button)(__styleYak.yak_2);" + const Button = styled.button(__styleYak.yak_0, x > 0.5 && css(__styleYak.yak_2)); + const FancyButton = styled(Button)(__styleYak.yak_3);" `); }); @@ -163,8 +163,8 @@ const FancyButton = styled(Button)\` const x = Math.random(); const Button = styled.button(__styleYak.yak_0, ({ theme - }) => theme.mode === \\"dark\\" && css(__styleYak.yak_1)); - const FancyButton = styled(Button)(__styleYak.yak_2);" + }) => theme.mode === \\"dark\\" && css(__styleYak.yak_2)); + const FancyButton = styled(Button)(__styleYak.yak_3);" `); }); }); @@ -216,7 +216,7 @@ const newHeadline = styled(headline).attrs({ const headline = styled.input(__styleYak.yak_0); const newHeadline = styled(headline).attrs({ type: \\"text\\" - })(__styleYak.yak_1);" + })(__styleYak.yak_2);" `); }); @@ -286,4 +286,45 @@ const FadeInButton = styled.button\` } });" `); -}); \ No newline at end of file +}); + + +it("should allow to target components", async () => { + expect( + await tsloader.call( + loaderContext, + ` +import { styled, keyframes } from "next-yak"; + +const Link = styled.a\` + color: palevioletred; +\` + +const Icon = styled.svg\` + fill: currentColor; + width: 1em; + height: 1em; + \${Link}:hover & { + color: red; + } + \${Link}:focus & { + color: red; + } +\` + +const Wrapper = styled.div\` + &:has(> \${Link}) { + padding: 10px; + } +\` + +` + ) + ).toMatchInlineSnapshot(` + "import { styled, keyframes } from \\"next-yak\\"; + import __styleYak from \\"./page.yak.module.css!=!./page?./page.yak.module.css\\"; + const Link = styled.a(__styleYak.yak_0, __styleYak.yak_1); + const Icon = styled.svg(__styleYak.yak_2); + const Wrapper = styled.div(__styleYak.yak_4);" + `); +}); diff --git a/packages/next-yak/loaders/babel-yak-plugin.cjs b/packages/next-yak/loaders/babel-yak-plugin.cjs index 60060bbd..ef660b15 100644 --- a/packages/next-yak/loaders/babel-yak-plugin.cjs +++ b/packages/next-yak/loaders/babel-yak-plugin.cjs @@ -4,6 +4,7 @@ const replaceQuasiExpressionTokens = require("./lib/replaceQuasiExpressionTokens const murmurhash2_32_gc = require("./lib/hash.cjs"); const { relative, resolve, basename } = require("path"); const localIdent = require("./lib/localIdent.cjs"); +const getStyledComponentName = require("./lib/getStyledComponentName.cjs"); /** @typedef {{replaces: Record, rootContext?: string}} YakBabelPluginOptions */ @@ -14,7 +15,7 @@ const localIdent = require("./lib/localIdent.cjs"); * * @param {import("@babel/core")} babel * @param {YakBabelPluginOptions} options - * @returns {babel.PluginObj} + * @returns {babel.PluginObj}>} */ module.exports = function (babel, options) { const { replaces } = options; @@ -36,6 +37,7 @@ module.exports = function (babel, options) { this.isImportedInCurrentFile = false; this.classNameCount = 0; this.varIndex = 0; + this.variableNameToStyledCall = new Map(); }, visitor: { /** @@ -143,7 +145,28 @@ module.exports = function (babel, options) { return; } - replaceQuasiExpressionTokens(path.node.quasi, replaces, t); + replaceQuasiExpressionTokens(path.node.quasi, (name) => { + if (name in replaces) { + return replaces[name]; + } + const styledCall = this.variableNameToStyledCall.get(name); + if (styledCall) { + const { wasAdded, className, astNode } = styledCall; + // on first usage of another styled component, add a + // the className to it so it can be targeted + if (!wasAdded) { + styledCall.wasAdded = true; + astNode.arguments.push( + t.memberExpression( + t.identifier("__styleYak"), + t.identifier(className) + ) + ); + } + return className; + } + return false; + }, t); // Keep the same selector for all quasis belonging to the same css block const classNameExpression = t.memberExpression( @@ -246,6 +269,18 @@ module.exports = function (babel, options) { const styledCall = t.callExpression(tag, [...newArguments]); path.replaceWith(styledCall); + + // Store reference to AST node to allow other components to target the styled literal inside css like + // e.g. `& ${Button} { ... }` + if (isStyledLiteral || isStyledCall || isAttrsCall) { + const variableName = getStyledComponentName(path); + // TODO: reuse existing class name if possible + this.variableNameToStyledCall.set(variableName, { + wasAdded: false, + className: localIdent(this.classNameCount++, "className"), + astNode: styledCall, + }); + } }, }, }; diff --git a/packages/next-yak/loaders/cssloader.cjs b/packages/next-yak/loaders/cssloader.cjs index 35ebbe18..e7fe97ec 100644 --- a/packages/next-yak/loaders/cssloader.cjs +++ b/packages/next-yak/loaders/cssloader.cjs @@ -4,6 +4,7 @@ const babel = require("@babel/core"); const quasiClassifier = require("./lib/quasiClassifier.cjs"); const localIdent = require("./lib/localIdent.cjs"); const replaceQuasiExpressionTokens = require("./lib/replaceQuasiExpressionTokens.cjs"); +const getStyledComponentName = require("./lib/getStyledComponentName.cjs"); const murmurhash2_32_gc = require("./lib/hash.cjs"); const { relative } = require("path"); @@ -65,6 +66,9 @@ module.exports = async function cssLoader(source) { /** @type {string | null} */ let hashedFile = null; + /** @type {Map} */ + const variableNameToStyledClassName = new Map(); + /** * find all css template literals in ast * @type {{ code: string, loc: number }[]} @@ -151,8 +155,15 @@ module.exports = async function cssLoader(source) { ) { return; } - - replaceQuasiExpressionTokens(path.node.quasi, replaces, t); + replaceQuasiExpressionTokens(path.node.quasi, (name) => { + if (name in replaces) { + return replaces[name]; + } + if (variableNameToStyledClassName.has(name)) { + return variableNameToStyledClassName.get(name) + } + return false; + }, t); // Keep the same selector for all quasis belonging to the same css block const literalSelector = localIdent( @@ -209,6 +220,18 @@ module.exports = async function cssLoader(source) { loc: quasi.loc?.start.line || 0, }); } + + // Store reference to AST node to allow other components to target the styled literal inside css like + // e.g. `& ${Button} { ... }` + if (isStyledLiteral || isStyledCall || isAttrsCall) { + const variableName = getStyledComponentName(path); + // TODO: reuse existing class name if possible + variableNameToStyledClassName.set(variableName, localIdent( + index++, + "selector" + )); + } + }, }); diff --git a/packages/next-yak/loaders/lib/getStyledComponentName.cjs b/packages/next-yak/loaders/lib/getStyledComponentName.cjs new file mode 100644 index 00000000..fcb60683 --- /dev/null +++ b/packages/next-yak/loaders/lib/getStyledComponentName.cjs @@ -0,0 +1,31 @@ +// @ts-check + +/** @typedef {import("@babel/types")} babel */ + +/** + * Try to get the name of a styled component from a call or member expression + * + * e.g. const MyButton = styled.div`...` -> "MyButton" + * e.g. const FancyButton = styled(MyButton)`...` -> "FancyButton" + * + * @param {babel.NodePath} taggedTemplateExpressionPath + * @returns {string} + */ +const getStyledComponentName = (taggedTemplateExpressionPath) => { + const variableDeclaratorPath = taggedTemplateExpressionPath.findParent( + (path) => path.isVariableDeclarator() + ); + if ( + !variableDeclaratorPath || + !("id" in variableDeclaratorPath.node) || + variableDeclaratorPath.node.id?.type !== "Identifier" + ) { + throw new Error( + "Could not find variable declaration for styled component at " + + taggedTemplateExpressionPath.node.loc + ); + } + return variableDeclaratorPath.node.id.name; +}; + +module.exports = getStyledComponentName; diff --git a/packages/next-yak/loaders/lib/replaceQuasiExpressionTokens.cjs b/packages/next-yak/loaders/lib/replaceQuasiExpressionTokens.cjs index 80b24815..9388026c 100644 --- a/packages/next-yak/loaders/lib/replaceQuasiExpressionTokens.cjs +++ b/packages/next-yak/loaders/lib/replaceQuasiExpressionTokens.cjs @@ -21,42 +21,42 @@ * ``` * * @param {import("@babel/types").TemplateLiteral} quasi - * @param {Record} replaces + * @param {(name: string) => unknown} replacer * @param {import("@babel/types")} t */ -module.exports = function replaceTokensInQuasiExpressions(quasi, replaces, t) { +module.exports = function replaceTokensInQuasiExpressions(quasi, replacer, t) { for (let i = 0; i < quasi.expressions.length; i++) { const expression = quasi.expressions[i]; // replace direct identifiers e.g. ${query} if (t.isIdentifier(expression)) { - if (!(expression.name in replaces)) { + const replacement = replacer(expression.name); + if (replacement === false) { continue; } - const replacement = replaces[expression.name]; replaceExpressionAndMergeQuasis(quasi, i, replacement); i--; } // replace member expressions e.g. ${query.xs} // replace deeply nested member expressions e.g. ${query.xs.min} else if (t.isMemberExpression(expression) && t.isIdentifier(expression.object)) { - if (!(expression.object.name in replaces)) { + /** @type {any} */ + let replacement = replacer(expression.object.name); + if (replacement === false) { continue; } /** @type {import("@babel/types").Expression} */ let object = expression; - /** @type {any} */ - let value = replaces[expression.object.name]; while (t.isMemberExpression(object)) { if (!t.isIdentifier(object.property)) { break; } - if (typeof value !== "object" || value === null) { + if (typeof replacement !== "object" || replacement === null) { break; } - value = value[object.property.name]; + replacement = replacement[object.property.name]; object = object.object; } - replaceExpressionAndMergeQuasis(quasi, i, value); + replaceExpressionAndMergeQuasis(quasi, i, replacement); i--; } } From 33aa7f53b03bf9addedc6e520fd46e7be2291910 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Mon, 20 Nov 2023 15:05:49 +0100 Subject: [PATCH 2/7] fix types --- packages/example/app/Input.tsx | 2 +- packages/next-yak/dist/index.cjs | 2 +- packages/next-yak/dist/index.cjs.map | 2 +- packages/next-yak/dist/index.d.cts | 16 +++++++--- packages/next-yak/dist/index.d.ts | 16 +++++++--- packages/next-yak/dist/index.js.map | 2 +- packages/next-yak/package.json | 2 +- packages/next-yak/runtime/cssLiteral.tsx | 5 ++++ packages/next-yak/runtime/styled.tsx | 38 +++++++++++++++--------- 9 files changed, 58 insertions(+), 27 deletions(-) diff --git a/packages/example/app/Input.tsx b/packages/example/app/Input.tsx index 1bbd59d2..c94dfe2f 100644 --- a/packages/example/app/Input.tsx +++ b/packages/example/app/Input.tsx @@ -25,7 +25,7 @@ const Wrapper = styled.div` flex-direction: column; align-items: center; transition: background-color 0.5s ease-in-out; - &:has(${Input}:where(:hover, :focus), ${PasswordInput}:where(:hover, :focus)) { + &:has(${Input}:where(:hover, :focus), ${PasswordInput}::where(:hover, :focus)) { background-color: #4c4c4cb9 } `; diff --git a/packages/next-yak/dist/index.cjs b/packages/next-yak/dist/index.cjs index 037700a2..7ec6b1b9 100644 --- a/packages/next-yak/dist/index.cjs +++ b/packages/next-yak/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";var b=Object.create;var l=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var F=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var O=(t,e)=>{for(var s in e)l(t,s,{get:e[s],enumerable:!0})},f=(t,e,s,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of N(e))!w.call(t,n)&&n!==s&&l(t,n,{get:()=>e[n],enumerable:!(o=h(e,n))||o.enumerable});return t};var R=(t,e,s)=>(s=t!=null?b(F(t)):{},f(e||!t||!t.__esModule?l(s,"default",{value:t,enumerable:!0}):s,t)),j=t=>f(l({},"__esModule",{value:!0}),t);var X={};O(X,{YakThemeProvider:()=>u.YakThemeProvider,atoms:()=>C,css:()=>y,keyframes:()=>I,styled:()=>k,useTheme:()=>u.useTheme});module.exports=j(X);var v=(...t)=>{let e=[],s=[],o={};for(let n of t)if(typeof n=="string")e.push(n);else if(typeof n=="function")s.push(n);else if(typeof n=="object"&&"style"in n)for(let r in n.style){let a=n.style[r];typeof a=="function"?s.push(i=>({style:{[r]:String(g(i,a))}})):o[r]=a}if(s.length===0){let n=e.join(" ");return()=>({className:n,style:o})}return n=>{let r=[...e],a={...o};for(let i=0;i{let n=e(t);for(;n;){if(typeof n=="function"){n=n(t);continue}else if(typeof n=="object"&&("className"in n&&n.className&&s.push(n.className),"style"in n&&n.style))for(let r in n.style)o[r]=n.style[r];break}},g=(t,e)=>{let s=e(t);if(typeof s=="function")return g(t,s);if(process.env.NODE_ENV==="development"&&typeof s!="string"&&typeof s!="number"&&!(s instanceof String))throw new Error(`Dynamic CSS functions must return a string or number but returned ${JSON.stringify(s)}`);return s},y=v;var p=R(require("react"),1),P=require("next-yak/context"),B=t=>Object.assign(p.default.forwardRef(t),{component:t}),M=t=>Object.assign(d(t),{attrs:e=>d(t,e)}),d=(t,e)=>(s,...o)=>{let n=y(s,...o),r=i=>J(i,typeof e=="function"?e(i):e);return B((i,S)=>{let c=r(Object.assign(e||n.length?{theme:(0,P.useTheme)()}:{},i)),m=n(c),T=typeof t=="string"?Y(c):c;return T.className=x(c.className,m.className),T.style="style"in c?{...c.style,...m.style}:m.style,typeof t!="string"&&"yak"in t?t.yak(T,S):(T.ref=S,p.default.createElement(t,{...T}))})},k=new Proxy(M,{get(t,e){return t(e)}});function Y(t){let e={};for(let s in t)!s.startsWith("$")&&s!=="theme"&&(e[s]=t[s]);return e}var x=(t,e)=>t?e?t+" "+e:t:e,A=t=>{let e={};for(let s in t)t[s]!==void 0&&(e[s]=t[s]);return e},J=(t,e)=>e?{..."$__attrs"in t?{...A(e),...t}:{...t,...A(e)},className:x(t.className,e.className),style:{...t.style||{},...e.style||{}},$__attrs:!0}:t;var C=(...t)=>{let e=t.join(" ");return()=>({className:e})};var I=(t,...e)=>t;var u=require("next-yak/context");0&&(module.exports={YakThemeProvider,atoms,css,keyframes,styled,useTheme}); +"use strict";var b=Object.create;var l=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var F=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var O=(t,e)=>{for(var s in e)l(t,s,{get:e[s],enumerable:!0})},f=(t,e,s,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of N(e))!w.call(t,n)&&n!==s&&l(t,n,{get:()=>e[n],enumerable:!(o=h(e,n))||o.enumerable});return t};var R=(t,e,s)=>(s=t!=null?b(F(t)):{},f(e||!t||!t.__esModule?l(s,"default",{value:t,enumerable:!0}):s,t)),j=t=>f(l({},"__esModule",{value:!0}),t);var J={};O(J,{YakThemeProvider:()=>u.YakThemeProvider,atoms:()=>C,css:()=>y,keyframes:()=>I,styled:()=>k,useTheme:()=>u.useTheme});module.exports=j(J);var v=(...t)=>{let e=[],s=[],o={};for(let n of t)if(typeof n=="string")e.push(n);else if(typeof n=="function")s.push(n);else if(typeof n=="object"&&"style"in n)for(let r in n.style){let a=n.style[r];typeof a=="function"?s.push(i=>({style:{[r]:String(g(i,a))}})):o[r]=a}if(s.length===0){let n=e.join(" ");return()=>({className:n,style:o})}return n=>{let r=[...e],a={...o};for(let i=0;i{let n=e(t);for(;n;){if(typeof n=="function"){n=n(t);continue}else if(typeof n=="object"&&("className"in n&&n.className&&s.push(n.className),"style"in n&&n.style))for(let r in n.style)o[r]=n.style[r];break}},g=(t,e)=>{let s=e(t);if(typeof s=="function")return g(t,s);if(process.env.NODE_ENV==="development"&&typeof s!="string"&&typeof s!="number"&&!(s instanceof String))throw new Error(`Dynamic CSS functions must return a string or number but returned ${JSON.stringify(s)}`);return s},y=v;var p=R(require("react"),1),P=require("next-yak/context"),_=t=>Object.assign(p.default.forwardRef(t),{component:t}),B=t=>Object.assign(d(t),{attrs:e=>d(t,e)}),d=(t,e)=>(s,...o)=>{let n=y(s,...o),r=i=>Y(i,typeof e=="function"?e(i):e);return _((i,S)=>{let c=r(Object.assign(e||n.length?{theme:(0,P.useTheme)()}:{},i)),m=n(c),T=typeof t=="string"?M(c):c;return T.className=x(c.className,m.className),T.style="style"in c?{...c.style,...m.style}:m.style,typeof t!="string"&&"yak"in t?t.yak(T,S):(T.ref=S,p.default.createElement(t,{...T}))})},k=new Proxy(B,{get(t,e){return t(e)}});function M(t){let e={};for(let s in t)!s.startsWith("$")&&s!=="theme"&&(e[s]=t[s]);return e}var x=(t,e)=>t?e?t+" "+e:t:e,A=t=>{let e={};for(let s in t)t[s]!==void 0&&(e[s]=t[s]);return e},Y=(t,e)=>e?{..."$__attrs"in t?{...A(e),...t}:{...t,...A(e)},className:x(t.className,e.className),style:{...t.style||{},...e.style||{}},$__attrs:!0}:t;var C=(...t)=>{let e=t.join(" ");return()=>({className:e})};var I=(t,...e)=>t;var u=require("next-yak/context");0&&(module.exports={YakThemeProvider,atoms,css,keyframes,styled,useTheme}); //# sourceMappingURL=index.cjs.map \ No newline at end of file diff --git a/packages/next-yak/dist/index.cjs.map b/packages/next-yak/dist/index.cjs.map index dde1677a..cb711414 100644 --- a/packages/next-yak/dist/index.cjs.map +++ b/packages/next-yak/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"sources":["../runtime/index.ts","../runtime/cssLiteral.tsx","../runtime/styled.tsx","../runtime/atoms.tsx","../runtime/keyframes.tsx"],"sourcesContent":["export { css } from \"./cssLiteral.js\";\nexport { styled } from \"./styled.js\";\nexport { atoms } from \"./atoms.js\";\nexport { keyframes } from \"./keyframes.js\";\n\n// the following export is not relative as \"next-yak/context\"\n// links to one file for react server components and\n// to another file for classic react components\nexport { useTheme, YakThemeProvider } from \"next-yak/context\";\n\nexport type { YakTheme } from \"./context/index.d.ts\";\n","import type { YakTheme } from \"./index.d.ts\";\n\ntype ComponentStyles = (props: TProps) => {\n className: string;\n style?: {\n [key: string]: string;\n };\n};\n\nexport type CSSInterpolation =\n | string\n | number\n | undefined\n | null\n | false\n | ComponentStyles\n | ((props: TProps) => CSSInterpolation);\n\ntype CSSStyles = {\n style: { [key: string]: string | ((props: TProps) => string) };\n};\n\ntype CSSFunction = (\n styles: TemplateStringsArray,\n ...values: CSSInterpolation[]\n) => ComponentStyles;\n\ntype PropsToClassNameFn = (props: unknown) =>\n | {\n className?: string;\n style?: Record;\n }\n | PropsToClassNameFn;\n\n/**\n * css() runtime factory of css``\n *\n * /!\\ next-yak transpiles css`` and styled``\n *\n * This changes the typings of the css`` and styled`` functions.\n * During development the user of next-yak wants to work with the\n * typings BEFORE compilation.\n *\n * Therefore this is only an internal function only and it must be cast to any\n * before exported to the user.\n */\nconst internalCssFactory = (\n ...args: Array>\n) => {\n const classNames: string[] = [];\n const dynamicCssFunctions: PropsToClassNameFn[] = [];\n const style: Record = {};\n for (const arg of args) {\n // A CSS-module class name which got auto generated during build from static css\n // e.g. css`color: red;` \n // compiled -> css(\"yak31e4\")\n if (typeof arg === \"string\") {\n classNames.push(arg);\n }\n // Dynamic CSS e.g.\n // css`${props => props.active && css`color: red;`}`\n // compiled -> css((props: { active: boolean }) => props.active && css(\"yak31e4\"))\n else if (typeof arg === \"function\") {\n dynamicCssFunctions.push(arg as unknown as PropsToClassNameFn);\n }\n // Dynamic CSS with css variables e.g.\n // css`transform: translate(${props => props.x}, ${props => props.y});`\n // compiled -> css(\"yak31e4\", { style: { \"--yakVarX\": props => props.x }, \"--yakVarY\": props => props.y }})\n else if (typeof arg === \"object\" && \"style\" in arg) {\n for (const key in arg.style) {\n const value = arg.style[key];\n if (typeof value === \"function\") {\n dynamicCssFunctions.push((props: unknown) => ({\n style: {\n [key]: String(\n // The value for a css value can be a theme dependent function e.g.:\n // const borderColor = (props: { theme: { mode: \"dark\" | \"light\" } }) => props.theme === \"dark\" ? \"black\" : \"white\";\n // css`border-color: ${borderColor};`\n // Therefore the value has to be extracted recursively\n recursivePropExecution(props, value),\n ),\n },\n }));\n } else {\n style[key] = value;\n }\n }\n }\n }\n\n // Non Dynamic CSS\n if (dynamicCssFunctions.length === 0) {\n const className = classNames.join(\" \");\n return () => ({ className, style });\n }\n\n return (props: unknown) => {\n const allClassNames: string[] = [...classNames];\n const allStyles: Record = { ...style };\n for (let i = 0; i < dynamicCssFunctions.length; i++) {\n unwrapProps(props, dynamicCssFunctions[i], allClassNames, allStyles);\n }\n return {\n className: allClassNames.join(\" \"),\n style: allStyles,\n };\n };\n};\n\n// Dynamic CSS with runtime logic\nconst unwrapProps = (\n props: unknown,\n fn: PropsToClassNameFn,\n classNames: string[],\n style: Record,\n) => {\n let result = fn(props);\n while (result) {\n if (typeof result === \"function\") {\n result = result(props);\n continue;\n } else if (typeof result === \"object\") {\n if (\"className\" in result && result.className) {\n classNames.push(result.className);\n }\n if (\"style\" in result && result.style) {\n for (const key in result.style) {\n style[key] = result.style[key];\n }\n }\n }\n break;\n }\n};\n\nconst recursivePropExecution = (\n props: unknown,\n fn: (props: unknown) => any,\n): string | number => {\n const result = fn(props);\n if (typeof result === \"function\") {\n return recursivePropExecution(props, result);\n }\n if (process.env.NODE_ENV === \"development\") {\n if (\n typeof result !== \"string\" &&\n typeof result !== \"number\" &&\n !(result instanceof String)\n ) {\n throw new Error(\n `Dynamic CSS functions must return a string or number but returned ${JSON.stringify(\n result,\n )}`,\n );\n }\n }\n return result;\n};\n\nexport const css = internalCssFactory as any as CSSFunction;\n","import { ForwardRefRenderFunction, FunctionComponent } from \"react\";\nimport { CSSInterpolation, css } from \"./cssLiteral.js\";\nimport React from \"react\";\n\n// the following export is not relative as \"next-yak/context\"\n// links to one file for react server components and\n// to another file for classic react components\nimport { useTheme } from \"next-yak/context\";\nimport type { YakTheme } from \"./context/index.d.ts\";\n\n/**\n * Hack to hide .yak from the type definition and to deal with ExoticComponents\n */\nconst yakForwardRef: (\n component: ForwardRefRenderFunction,\n) => FunctionComponent = (component) =>\n Object.assign(React.forwardRef(component), { component }) as any;\n\n/**\n * All valid html tags\n */\ntype HtmlTags = keyof JSX.IntrinsicElements;\n\n/**\n * Return type of the provided props merged with the initial props\n * where the specified props are optional\n */\ntype AttrsMerged = Substitute<\n TBaseProps & { theme: YakTheme },\n TIn\n>;\n\n/**\n * The attrs function allows to add additional props to a styled component.\n * The props can be specified as an object or as a function that receives the\n * current props as argument.\n */\ntype Attrs<\n TBaseProps,\n TIn extends object = {},\n TOut extends AttrsMerged = AttrsMerged,\n> =\n | Partial\n | ((p: Substitute) => Partial);\n\n//\n// The `styled()` and `styled.` API\n//\n// The API design is inspired by styled-components:\n// https://github.com/styled-components/styled-components/blob/main/packages/styled-components/src/constructors/styled.tsx\n// https://github.com/styled-components/styled-components/blob/main/packages/styled-components/src/models/StyledComponent.ts\n//\n\nconst StyledFactory = (Component: HtmlTags | FunctionComponent) =>\n Object.assign(yakStyled(Component), {\n attrs: <\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged = AttrsMerged,\n >(\n attrs: Attrs,\n ) => yakStyled(Component, attrs),\n });\n\nconst yakStyled = <\n T,\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged = AttrsMerged,\n>(\n Component: FunctionComponent | HtmlTags,\n attrs?: Attrs,\n) => {\n return = {}>(\n styles: TemplateStringsArray,\n ...values: Array>\n ) => {\n const getRuntimeStyles = css(styles, ...values);\n const processAttrs = (props: Substitute) =>\n combineProps(\n props,\n typeof attrs === \"function\" ? (attrs as Function)(props) : attrs,\n );\n const yak = (props: Substitute, ref: unknown) => {\n /** The combined props are passed into the styled`` literal functions */\n const combinedProps: Substitute = processAttrs(\n Object.assign(\n // if the css component does not require arguments\n // it can be call without arguments and skip calling useTheme()\n //\n // this is NOT against the rule of hooks as\n // getRuntimeStyles is a constant defined outside of the component\n //\n // for example\n //\n // const Button = styled.button`color: red;`\n // ^ does not need to have access to theme\n //\n // const Button = styled.button`${({ theme }) => css`color: ${theme.color};`}`\n // ^ must be have acces to theme\n attrs || getRuntimeStyles.length ? { theme: useTheme() } : {},\n props,\n ) as Substitute,\n );\n // execute all functions inside the style literal\n // e.g. styled.button`color: ${props => props.color};`\n const runtimeStyles = getRuntimeStyles(combinedProps as any);\n\n // remove all props that start with a $ sign for string components e.g. \"button\" or \"div\"\n // so that they are not passed to the DOM element\n const filteredProps =\n typeof Component === \"string\"\n ? removePrefixedProperties(combinedProps)\n : combinedProps;\n\n // yak provides a className and style prop that needs to be merged with the\n // user provided className and style prop\n (filteredProps as { className?: string }).className = mergeClassNames(\n (combinedProps as { className?: string }).className,\n runtimeStyles.className as string,\n );\n (filteredProps as { style?: React.CSSProperties }).style =\n \"style\" in combinedProps\n ? {\n ...(combinedProps as { style?: React.CSSProperties }).style,\n ...runtimeStyles.style,\n }\n : runtimeStyles.style;\n // if the styled(Component) syntax is used and the component is a yak component\n // we can call the yak function directly to avoid an unnecessary wrapper with an additional\n // forwardRef call\n if (typeof Component !== \"string\" && \"yak\" in Component) {\n return (\n Component as typeof Component & {\n yak: FunctionComponent;\n }\n ).yak(filteredProps, ref);\n }\n\n (filteredProps as { ref?: unknown }).ref = ref;\n return ;\n };\n return yakForwardRef(yak);\n };\n};\n\n/**\n * Type for the proxy object returned by `styled` that allows to\n * access all html tags as properties.\n */\ntype StyledLiteral = = {}>(\n styles: TemplateStringsArray,\n ...values: Array>\n) => FunctionComponent;\n\n/**\n * The `styled` method works perfectly on all of your own or any third-party component,\n * as long as they attach the passed className prop to a DOM element.\n *\n * @usage\n *\n * ```tsx\n * const StyledLink = styled(Link)`\n * color: #BF4F74;\n * font-weight: bold;\n * `;\n * ```\n */\nexport const styled = new Proxy(\n StyledFactory as typeof StyledFactory & {\n [Tag in HtmlTags]: StyledLiteral & {\n attrs: <\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged<\n JSX.IntrinsicElements[Tag],\n TAttrsIn\n > = AttrsMerged,\n >(\n attrs: Attrs,\n ) => StyledLiteral>;\n };\n },\n {\n get(target, TagName: keyof JSX.IntrinsicElements) {\n return target(TagName);\n },\n },\n);\n\n// Remove all entries that start with a $ sign\nfunction removePrefixedProperties>(obj: T) {\n const result = {} as T;\n for (const key in obj) {\n if (!key.startsWith(\"$\") && key !== \"theme\") {\n result[key] = obj[key];\n }\n }\n return result;\n}\n\nconst mergeClassNames = (a?: string, b?: string) => {\n if (!a) return b;\n if (!b) return a;\n return a + \" \" + b;\n};\n\nconst removeUndefined = (obj: T) => {\n const result = {} as T;\n for (const key in obj) {\n if (obj[key] !== undefined) {\n result[key] = obj[key];\n }\n }\n return result;\n};\n\nconst combineProps = <\n T extends {\n className?: string;\n style?: React.CSSProperties;\n },\n>(\n props: T,\n newProps: T,\n) => {\n if (!newProps) return props;\n const combinedProps: T =\n \"$__attrs\" in props\n ? // allow overriding props when attrs was used previously\n {\n ...removeUndefined(newProps),\n ...props,\n }\n : {\n ...props,\n ...removeUndefined(newProps),\n };\n return {\n ...combinedProps,\n className: mergeClassNames(\n props.className as string,\n newProps.className as string,\n ),\n style: { ...(props.style || {}), ...(newProps.style || {}) },\n $__attrs: true,\n };\n};\n\n// util type to remove properties from an object\ntype FastOmit = {\n [K in keyof T as K extends U ? never : K]: T[K];\n};\n\n// util type to merge two objects\n// if a property is present in both objects the property from B is used\nexport type Substitute = FastOmit<\n A,\n keyof B\n> &\n B;\n","/**\n * Allows to use atomic CSS classes in a styled or css block\n *\n * @usage\n *\n * ```tsx\n * import { styled, atoms } from \"next-yak\";\n *\n * const Button = styled.button<{ $primary?: boolean }>`\n * ${atoms(\"text-teal-600\", \"text-base\", \"rounded-md\")}\n * ${props => props.$primary && atoms(\"shadow-md\")}\n * `;\n * ```\n */\nexport const atoms = (...atoms: string[]) => {\n const className = atoms.join(\" \");\n return () => ({ className });\n};\n","/**\n * Allows to use CSS keyframe animations in a styled or css block\n *\n * @usage\n *\n * ```tsx\n * import { styled, keyframes } from \"next-yak\";\n *\n * const rotate = keyframes`\n * from {\n * transform: rotate(0deg);\n * }\n * to {\n * transform: rotate(360deg);\n * }\n * `;\n *\n * const Spinner = styled.div`\n * animation: ${rotate} 1s linear infinite;\n * `;\n * ```\n */\nexport const keyframes = (\n styles: TemplateStringsArray,\n ...dynamic: never[]\n): string => {\n // during compilation all args of keyframe are compiled\n // to a string which references the animation name\n return styles as any as string;\n};\n"],"mappings":"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","names":["runtime_exports","__export","atoms","css","keyframes","styled","__toCommonJS","internalCssFactory","args","classNames","dynamicCssFunctions","style","arg","key","value","props","recursivePropExecution","className","allClassNames","allStyles","unwrapProps","fn","result","css","import_react","import_context","yakForwardRef","component","React","StyledFactory","Component","yakStyled","attrs","styles","values","getRuntimeStyles","css","processAttrs","props","combineProps","ref","combinedProps","runtimeStyles","filteredProps","removePrefixedProperties","mergeClassNames","styled","target","TagName","obj","result","key","a","b","removeUndefined","newProps","atoms","className","keyframes","styles","dynamic","import_context"]} \ No newline at end of file +{"version":3,"sources":["../runtime/index.ts","../runtime/cssLiteral.tsx","../runtime/styled.tsx","../runtime/atoms.tsx","../runtime/keyframes.tsx"],"sourcesContent":["export { css } from \"./cssLiteral.js\";\nexport { styled } from \"./styled.js\";\nexport { atoms } from \"./atoms.js\";\nexport { keyframes } from \"./keyframes.js\";\n\n// the following export is not relative as \"next-yak/context\"\n// links to one file for react server components and\n// to another file for classic react components\nexport { useTheme, YakThemeProvider } from \"next-yak/context\";\n\nexport type { YakTheme } from \"./context/index.d.ts\";\n","import type { YakTheme } from \"./index.d.ts\";\n\ntype ComponentStyles = (props: TProps) => {\n className: string;\n style?: {\n [key: string]: string;\n };\n};\n\nexport type CSSInterpolation =\n | string\n | number\n | undefined\n | null\n | false\n | ComponentStyles\n | { \n // type only identifier to allow targeting components\n // e.g. styled.svg`${Button}:hover & { fill: red; }`\n __yak: true \n }\n | ((props: TProps) => CSSInterpolation);\n\ntype CSSStyles = {\n style: { [key: string]: string | ((props: TProps) => string) };\n};\n\ntype CSSFunction = (\n styles: TemplateStringsArray,\n ...values: CSSInterpolation[]\n) => ComponentStyles;\n\ntype PropsToClassNameFn = (props: unknown) =>\n | {\n className?: string;\n style?: Record;\n }\n | PropsToClassNameFn;\n\n/**\n * css() runtime factory of css``\n *\n * /!\\ next-yak transpiles css`` and styled``\n *\n * This changes the typings of the css`` and styled`` functions.\n * During development the user of next-yak wants to work with the\n * typings BEFORE compilation.\n *\n * Therefore this is only an internal function only and it must be cast to any\n * before exported to the user.\n */\nconst internalCssFactory = (\n ...args: Array>\n) => {\n const classNames: string[] = [];\n const dynamicCssFunctions: PropsToClassNameFn[] = [];\n const style: Record = {};\n for (const arg of args) {\n // A CSS-module class name which got auto generated during build from static css\n // e.g. css`color: red;`\n // compiled -> css(\"yak31e4\")\n if (typeof arg === \"string\") {\n classNames.push(arg);\n }\n // Dynamic CSS e.g.\n // css`${props => props.active && css`color: red;`}`\n // compiled -> css((props: { active: boolean }) => props.active && css(\"yak31e4\"))\n else if (typeof arg === \"function\") {\n dynamicCssFunctions.push(arg as unknown as PropsToClassNameFn);\n }\n // Dynamic CSS with css variables e.g.\n // css`transform: translate(${props => props.x}, ${props => props.y});`\n // compiled -> css(\"yak31e4\", { style: { \"--yakVarX\": props => props.x }, \"--yakVarY\": props => props.y }})\n else if (typeof arg === \"object\" && \"style\" in arg) {\n for (const key in arg.style) {\n const value = arg.style[key];\n if (typeof value === \"function\") {\n dynamicCssFunctions.push((props: unknown) => ({\n style: {\n [key]: String(\n // The value for a css value can be a theme dependent function e.g.:\n // const borderColor = (props: { theme: { mode: \"dark\" | \"light\" } }) => props.theme === \"dark\" ? \"black\" : \"white\";\n // css`border-color: ${borderColor};`\n // Therefore the value has to be extracted recursively\n recursivePropExecution(props, value),\n ),\n },\n }));\n } else {\n style[key] = value;\n }\n }\n }\n }\n\n // Non Dynamic CSS\n if (dynamicCssFunctions.length === 0) {\n const className = classNames.join(\" \");\n return () => ({ className, style });\n }\n\n return (props: unknown) => {\n const allClassNames: string[] = [...classNames];\n const allStyles: Record = { ...style };\n for (let i = 0; i < dynamicCssFunctions.length; i++) {\n unwrapProps(props, dynamicCssFunctions[i], allClassNames, allStyles);\n }\n return {\n className: allClassNames.join(\" \"),\n style: allStyles,\n };\n };\n};\n\n// Dynamic CSS with runtime logic\nconst unwrapProps = (\n props: unknown,\n fn: PropsToClassNameFn,\n classNames: string[],\n style: Record,\n) => {\n let result = fn(props);\n while (result) {\n if (typeof result === \"function\") {\n result = result(props);\n continue;\n } else if (typeof result === \"object\") {\n if (\"className\" in result && result.className) {\n classNames.push(result.className);\n }\n if (\"style\" in result && result.style) {\n for (const key in result.style) {\n style[key] = result.style[key];\n }\n }\n }\n break;\n }\n};\n\nconst recursivePropExecution = (\n props: unknown,\n fn: (props: unknown) => any,\n): string | number => {\n const result = fn(props);\n if (typeof result === \"function\") {\n return recursivePropExecution(props, result);\n }\n if (process.env.NODE_ENV === \"development\") {\n if (\n typeof result !== \"string\" &&\n typeof result !== \"number\" &&\n !(result instanceof String)\n ) {\n throw new Error(\n `Dynamic CSS functions must return a string or number but returned ${JSON.stringify(\n result,\n )}`,\n );\n }\n }\n return result;\n};\n\nexport const css = internalCssFactory as any as CSSFunction;\n","import { ForwardRefRenderFunction, FunctionComponent } from \"react\";\nimport { CSSInterpolation, css } from \"./cssLiteral.js\";\nimport React from \"react\";\n\n// the following export is not relative as \"next-yak/context\"\n// links to one file for react server components and\n// to another file for classic react components\nimport { useTheme } from \"next-yak/context\";\nimport type { YakTheme } from \"./context/index.d.ts\";\n\n/**\n * Hack to hide .yak from the type definition and to deal with ExoticComponents\n */\nconst yakForwardRef: (\n component: ForwardRefRenderFunction\n) => FunctionComponent & {\n // type only identifier to allow targeting components\n // e.g. styled.svg`${Button}:hover & { fill: red; }`\n // warning: `__yak` is undefined during runtime\n __yak: true;\n} = (component) =>\n Object.assign(React.forwardRef(component), { component }) as any;\n\n/**\n * All valid html tags\n */\ntype HtmlTags = keyof JSX.IntrinsicElements;\n\n/**\n * Return type of the provided props merged with the initial props\n * where the specified props are optional\n */\ntype AttrsMerged = Substitute<\n TBaseProps & { theme: YakTheme },\n TIn\n>;\n\n/**\n * The attrs function allows to add additional props to a styled component.\n * The props can be specified as an object or as a function that receives the\n * current props as argument.\n */\ntype Attrs<\n TBaseProps,\n TIn extends object = {},\n TOut extends AttrsMerged = AttrsMerged,\n> =\n | Partial\n | ((p: Substitute) => Partial);\n\n//\n// The `styled()` and `styled.` API\n//\n// The API design is inspired by styled-components:\n// https://github.com/styled-components/styled-components/blob/main/packages/styled-components/src/constructors/styled.tsx\n// https://github.com/styled-components/styled-components/blob/main/packages/styled-components/src/models/StyledComponent.ts\n//\n\nconst StyledFactory = (Component: HtmlTags | FunctionComponent) =>\n Object.assign(yakStyled(Component), {\n attrs: <\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged = AttrsMerged,\n >(\n attrs: Attrs\n ) => yakStyled(Component, attrs),\n });\n\nconst yakStyled = <\n T,\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged = AttrsMerged,\n>(\n Component: FunctionComponent | HtmlTags,\n attrs?: Attrs\n) => {\n return = {}>(\n styles: TemplateStringsArray,\n ...values: Array>\n ) => {\n const getRuntimeStyles = css(styles, ...values);\n const processAttrs = (props: Substitute) =>\n combineProps(\n props,\n typeof attrs === \"function\" ? (attrs as Function)(props) : attrs\n );\n const yak = (props: Substitute, ref: unknown) => {\n /** The combined props are passed into the styled`` literal functions */\n const combinedProps: Substitute = processAttrs(\n Object.assign(\n // if the css component does not require arguments\n // it can be call without arguments and skip calling useTheme()\n //\n // `__yak` is NOT against the rule of hooks as\n // getRuntimeStyles is a constant defined outside of the component\n //\n // for example\n //\n // const Button = styled.button`color: red;`\n // ^ does not need to have access to theme\n //\n // const Button = styled.button`${({ theme }) => css`color: ${theme.color};`}`\n // ^ must be have acces to theme\n attrs || getRuntimeStyles.length ? { theme: useTheme() } : {},\n props\n ) as Substitute\n );\n // execute all functions inside the style literal\n // e.g. styled.button`color: ${props => props.color};`\n const runtimeStyles = getRuntimeStyles(combinedProps as any);\n\n // remove all props that start with a $ sign for string components e.g. \"button\" or \"div\"\n // so that they are not passed to the DOM element\n const filteredProps =\n typeof Component === \"string\"\n ? removePrefixedProperties(combinedProps)\n : combinedProps;\n\n // yak provides a className and style prop that needs to be merged with the\n // user provided className and style prop\n (filteredProps as { className?: string }).className = mergeClassNames(\n (combinedProps as { className?: string }).className,\n runtimeStyles.className as string\n );\n (filteredProps as { style?: React.CSSProperties }).style =\n \"style\" in combinedProps\n ? {\n ...(combinedProps as { style?: React.CSSProperties }).style,\n ...runtimeStyles.style,\n }\n : runtimeStyles.style;\n // if the styled(Component) syntax is used and the component is a yak component\n // we can call the yak function directly to avoid an unnecessary wrapper with an additional\n // forwardRef call\n if (typeof Component !== \"string\" && \"yak\" in Component) {\n return (\n Component as typeof Component & {\n yak: FunctionComponent;\n }\n ).yak(filteredProps, ref);\n }\n\n (filteredProps as { ref?: unknown }).ref = ref;\n return ;\n };\n return yakForwardRef(yak);\n };\n};\n\n/**\n * Type for the proxy object returned by `styled` that allows to\n * access all html tags as properties.\n */\ntype StyledLiteral = = {}>(\n styles: TemplateStringsArray,\n ...values: Array>\n) => FunctionComponent & {\n // type only identifier to allow targeting components\n // e.g. styled.svg`${Button}:hover & { fill: red; }`\n // warning: this is undefined during runtime\n __yak: true;\n};\n\n/**\n * The `styled` method works perfectly on all of your own or any third-party component,\n * as long as they attach the passed className prop to a DOM element.\n *\n * @usage\n *\n * ```tsx\n * const StyledLink = styled(Link)`\n * color: #BF4F74;\n * font-weight: bold;\n * `;\n * ```\n */\nexport const styled = new Proxy(\n StyledFactory as typeof StyledFactory & {\n [Tag in HtmlTags]: StyledLiteral & {\n attrs: <\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged<\n JSX.IntrinsicElements[Tag],\n TAttrsIn\n > = AttrsMerged,\n >(\n attrs: Attrs\n ) => StyledLiteral>;\n };\n },\n {\n get(target, TagName: keyof JSX.IntrinsicElements) {\n return target(TagName);\n },\n }\n);\n\n// Remove all entries that start with a $ sign\nfunction removePrefixedProperties>(obj: T) {\n const result = {} as T;\n for (const key in obj) {\n if (!key.startsWith(\"$\") && key !== \"theme\") {\n result[key] = obj[key];\n }\n }\n return result;\n}\n\nconst mergeClassNames = (a?: string, b?: string) => {\n if (!a) return b;\n if (!b) return a;\n return a + \" \" + b;\n};\n\nconst removeUndefined = (obj: T) => {\n const result = {} as T;\n for (const key in obj) {\n if (obj[key] !== undefined) {\n result[key] = obj[key];\n }\n }\n return result;\n};\n\nconst combineProps = <\n T extends {\n className?: string;\n style?: React.CSSProperties;\n },\n>(\n props: T,\n newProps: T\n) => {\n if (!newProps) return props;\n const combinedProps: T =\n \"$__attrs\" in props\n ? // allow overriding props when attrs was used previously\n {\n ...removeUndefined(newProps),\n ...props,\n }\n : {\n ...props,\n ...removeUndefined(newProps),\n };\n return {\n ...combinedProps,\n className: mergeClassNames(\n props.className as string,\n newProps.className as string\n ),\n style: { ...(props.style || {}), ...(newProps.style || {}) },\n $__attrs: true,\n };\n};\n\n// util type to remove properties from an object\ntype FastOmit = {\n [K in keyof T as K extends U ? never : K]: T[K];\n};\n\n// util type to merge two objects\n// if a property is present in both objects the property from B is used\nexport type Substitute = FastOmit<\n A,\n keyof B\n> &\n B;\n","/**\n * Allows to use atomic CSS classes in a styled or css block\n *\n * @usage\n *\n * ```tsx\n * import { styled, atoms } from \"next-yak\";\n *\n * const Button = styled.button<{ $primary?: boolean }>`\n * ${atoms(\"text-teal-600\", \"text-base\", \"rounded-md\")}\n * ${props => props.$primary && atoms(\"shadow-md\")}\n * `;\n * ```\n */\nexport const atoms = (...atoms: string[]) => {\n const className = atoms.join(\" \");\n return () => ({ className });\n};\n","/**\n * Allows to use CSS keyframe animations in a styled or css block\n *\n * @usage\n *\n * ```tsx\n * import { styled, keyframes } from \"next-yak\";\n *\n * const rotate = keyframes`\n * from {\n * transform: rotate(0deg);\n * }\n * to {\n * transform: rotate(360deg);\n * }\n * `;\n *\n * const Spinner = styled.div`\n * animation: ${rotate} 1s linear infinite;\n * `;\n * ```\n */\nexport const keyframes = (\n styles: TemplateStringsArray,\n ...dynamic: never[]\n): string => {\n // during compilation all args of keyframe are compiled\n // to a string which references the animation name\n return styles as any as string;\n};\n"],"mappings":"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","names":["runtime_exports","__export","atoms","css","keyframes","styled","__toCommonJS","internalCssFactory","args","classNames","dynamicCssFunctions","style","arg","key","value","props","recursivePropExecution","className","allClassNames","allStyles","unwrapProps","fn","result","css","import_react","import_context","yakForwardRef","component","React","StyledFactory","Component","yakStyled","attrs","styles","values","getRuntimeStyles","css","processAttrs","props","combineProps","ref","combinedProps","runtimeStyles","filteredProps","removePrefixedProperties","mergeClassNames","styled","target","TagName","obj","result","key","a","b","removeUndefined","newProps","atoms","className","keyframes","styles","dynamic","import_context"]} \ No newline at end of file diff --git a/packages/next-yak/dist/index.d.cts b/packages/next-yak/dist/index.d.cts index 3a91b84f..d82389ad 100644 --- a/packages/next-yak/dist/index.d.cts +++ b/packages/next-yak/dist/index.d.cts @@ -6,7 +6,9 @@ type ComponentStyles = (props: TProps) => { [key: string]: string; }; }; -type CSSInterpolation = string | number | undefined | null | false | ComponentStyles | ((props: TProps) => CSSInterpolation); +type CSSInterpolation = string | number | undefined | null | false | ComponentStyles | { + __yak: true; +} | ((props: TProps) => CSSInterpolation); type CSSFunction = (styles: TemplateStringsArray, ...values: CSSInterpolation[]) => ComponentStyles; @@ -51,7 +53,9 @@ type Attrs = = {}>(styles: TemplateStringsArray, ...values: Array>) => FunctionComponent; +}>>) => FunctionComponent & { + __yak: true; +}; /** * The `styled` method works perfectly on all of your own or any third-party component, * as long as they attach the passed className prop to a DOM element. @@ -67,10 +71,14 @@ type StyledLiteral = = {}>(styles: */ declare const styled: ((Component: keyof JSX.IntrinsicElements | FunctionComponent) => ( = {}>(styles: TemplateStringsArray, ...values: CSSInterpolation[]) => FunctionComponent>) & { +}>[]) => FunctionComponent> & { + __yak: true; +}) & { attrs: = AttrsMerged>(attrs: Attrs) => = {}>(styles: TemplateStringsArray, ...values: CSSInterpolation[]) => FunctionComponent>; + }>[]) => FunctionComponent> & { + __yak: true; + }; }) & { symbol: StyledLiteral> & { attrs: , TAttrsIn_1> = AttrsMerged, TAttrsIn_1>>(attrs: Attrs, TAttrsIn_1, TAttrsOut_1>) => StyledLiteral, TAttrsIn_1>>; diff --git a/packages/next-yak/dist/index.d.ts b/packages/next-yak/dist/index.d.ts index 3a91b84f..d82389ad 100644 --- a/packages/next-yak/dist/index.d.ts +++ b/packages/next-yak/dist/index.d.ts @@ -6,7 +6,9 @@ type ComponentStyles = (props: TProps) => { [key: string]: string; }; }; -type CSSInterpolation = string | number | undefined | null | false | ComponentStyles | ((props: TProps) => CSSInterpolation); +type CSSInterpolation = string | number | undefined | null | false | ComponentStyles | { + __yak: true; +} | ((props: TProps) => CSSInterpolation); type CSSFunction = (styles: TemplateStringsArray, ...values: CSSInterpolation[]) => ComponentStyles; @@ -51,7 +53,9 @@ type Attrs = = {}>(styles: TemplateStringsArray, ...values: Array>) => FunctionComponent; +}>>) => FunctionComponent & { + __yak: true; +}; /** * The `styled` method works perfectly on all of your own or any third-party component, * as long as they attach the passed className prop to a DOM element. @@ -67,10 +71,14 @@ type StyledLiteral = = {}>(styles: */ declare const styled: ((Component: keyof JSX.IntrinsicElements | FunctionComponent) => ( = {}>(styles: TemplateStringsArray, ...values: CSSInterpolation[]) => FunctionComponent>) & { +}>[]) => FunctionComponent> & { + __yak: true; +}) & { attrs: = AttrsMerged>(attrs: Attrs) => = {}>(styles: TemplateStringsArray, ...values: CSSInterpolation[]) => FunctionComponent>; + }>[]) => FunctionComponent> & { + __yak: true; + }; }) & { symbol: StyledLiteral> & { attrs: , TAttrsIn_1> = AttrsMerged, TAttrsIn_1>>(attrs: Attrs, TAttrsIn_1, TAttrsOut_1>) => StyledLiteral, TAttrsIn_1>>; diff --git a/packages/next-yak/dist/index.js.map b/packages/next-yak/dist/index.js.map index c3f18f5c..80f41373 100644 --- a/packages/next-yak/dist/index.js.map +++ b/packages/next-yak/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../runtime/cssLiteral.tsx","../runtime/styled.tsx","../runtime/atoms.tsx","../runtime/keyframes.tsx","../runtime/index.ts"],"sourcesContent":["import type { YakTheme } from \"./index.d.ts\";\n\ntype ComponentStyles = (props: TProps) => {\n className: string;\n style?: {\n [key: string]: string;\n };\n};\n\nexport type CSSInterpolation =\n | string\n | number\n | undefined\n | null\n | false\n | ComponentStyles\n | ((props: TProps) => CSSInterpolation);\n\ntype CSSStyles = {\n style: { [key: string]: string | ((props: TProps) => string) };\n};\n\ntype CSSFunction = (\n styles: TemplateStringsArray,\n ...values: CSSInterpolation[]\n) => ComponentStyles;\n\ntype PropsToClassNameFn = (props: unknown) =>\n | {\n className?: string;\n style?: Record;\n }\n | PropsToClassNameFn;\n\n/**\n * css() runtime factory of css``\n *\n * /!\\ next-yak transpiles css`` and styled``\n *\n * This changes the typings of the css`` and styled`` functions.\n * During development the user of next-yak wants to work with the\n * typings BEFORE compilation.\n *\n * Therefore this is only an internal function only and it must be cast to any\n * before exported to the user.\n */\nconst internalCssFactory = (\n ...args: Array>\n) => {\n const classNames: string[] = [];\n const dynamicCssFunctions: PropsToClassNameFn[] = [];\n const style: Record = {};\n for (const arg of args) {\n // A CSS-module class name which got auto generated during build from static css\n // e.g. css`color: red;` \n // compiled -> css(\"yak31e4\")\n if (typeof arg === \"string\") {\n classNames.push(arg);\n }\n // Dynamic CSS e.g.\n // css`${props => props.active && css`color: red;`}`\n // compiled -> css((props: { active: boolean }) => props.active && css(\"yak31e4\"))\n else if (typeof arg === \"function\") {\n dynamicCssFunctions.push(arg as unknown as PropsToClassNameFn);\n }\n // Dynamic CSS with css variables e.g.\n // css`transform: translate(${props => props.x}, ${props => props.y});`\n // compiled -> css(\"yak31e4\", { style: { \"--yakVarX\": props => props.x }, \"--yakVarY\": props => props.y }})\n else if (typeof arg === \"object\" && \"style\" in arg) {\n for (const key in arg.style) {\n const value = arg.style[key];\n if (typeof value === \"function\") {\n dynamicCssFunctions.push((props: unknown) => ({\n style: {\n [key]: String(\n // The value for a css value can be a theme dependent function e.g.:\n // const borderColor = (props: { theme: { mode: \"dark\" | \"light\" } }) => props.theme === \"dark\" ? \"black\" : \"white\";\n // css`border-color: ${borderColor};`\n // Therefore the value has to be extracted recursively\n recursivePropExecution(props, value),\n ),\n },\n }));\n } else {\n style[key] = value;\n }\n }\n }\n }\n\n // Non Dynamic CSS\n if (dynamicCssFunctions.length === 0) {\n const className = classNames.join(\" \");\n return () => ({ className, style });\n }\n\n return (props: unknown) => {\n const allClassNames: string[] = [...classNames];\n const allStyles: Record = { ...style };\n for (let i = 0; i < dynamicCssFunctions.length; i++) {\n unwrapProps(props, dynamicCssFunctions[i], allClassNames, allStyles);\n }\n return {\n className: allClassNames.join(\" \"),\n style: allStyles,\n };\n };\n};\n\n// Dynamic CSS with runtime logic\nconst unwrapProps = (\n props: unknown,\n fn: PropsToClassNameFn,\n classNames: string[],\n style: Record,\n) => {\n let result = fn(props);\n while (result) {\n if (typeof result === \"function\") {\n result = result(props);\n continue;\n } else if (typeof result === \"object\") {\n if (\"className\" in result && result.className) {\n classNames.push(result.className);\n }\n if (\"style\" in result && result.style) {\n for (const key in result.style) {\n style[key] = result.style[key];\n }\n }\n }\n break;\n }\n};\n\nconst recursivePropExecution = (\n props: unknown,\n fn: (props: unknown) => any,\n): string | number => {\n const result = fn(props);\n if (typeof result === \"function\") {\n return recursivePropExecution(props, result);\n }\n if (process.env.NODE_ENV === \"development\") {\n if (\n typeof result !== \"string\" &&\n typeof result !== \"number\" &&\n !(result instanceof String)\n ) {\n throw new Error(\n `Dynamic CSS functions must return a string or number but returned ${JSON.stringify(\n result,\n )}`,\n );\n }\n }\n return result;\n};\n\nexport const css = internalCssFactory as any as CSSFunction;\n","import { ForwardRefRenderFunction, FunctionComponent } from \"react\";\nimport { CSSInterpolation, css } from \"./cssLiteral.js\";\nimport React from \"react\";\n\n// the following export is not relative as \"next-yak/context\"\n// links to one file for react server components and\n// to another file for classic react components\nimport { useTheme } from \"next-yak/context\";\nimport type { YakTheme } from \"./context/index.d.ts\";\n\n/**\n * Hack to hide .yak from the type definition and to deal with ExoticComponents\n */\nconst yakForwardRef: (\n component: ForwardRefRenderFunction,\n) => FunctionComponent = (component) =>\n Object.assign(React.forwardRef(component), { component }) as any;\n\n/**\n * All valid html tags\n */\ntype HtmlTags = keyof JSX.IntrinsicElements;\n\n/**\n * Return type of the provided props merged with the initial props\n * where the specified props are optional\n */\ntype AttrsMerged = Substitute<\n TBaseProps & { theme: YakTheme },\n TIn\n>;\n\n/**\n * The attrs function allows to add additional props to a styled component.\n * The props can be specified as an object or as a function that receives the\n * current props as argument.\n */\ntype Attrs<\n TBaseProps,\n TIn extends object = {},\n TOut extends AttrsMerged = AttrsMerged,\n> =\n | Partial\n | ((p: Substitute) => Partial);\n\n//\n// The `styled()` and `styled.` API\n//\n// The API design is inspired by styled-components:\n// https://github.com/styled-components/styled-components/blob/main/packages/styled-components/src/constructors/styled.tsx\n// https://github.com/styled-components/styled-components/blob/main/packages/styled-components/src/models/StyledComponent.ts\n//\n\nconst StyledFactory = (Component: HtmlTags | FunctionComponent) =>\n Object.assign(yakStyled(Component), {\n attrs: <\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged = AttrsMerged,\n >(\n attrs: Attrs,\n ) => yakStyled(Component, attrs),\n });\n\nconst yakStyled = <\n T,\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged = AttrsMerged,\n>(\n Component: FunctionComponent | HtmlTags,\n attrs?: Attrs,\n) => {\n return = {}>(\n styles: TemplateStringsArray,\n ...values: Array>\n ) => {\n const getRuntimeStyles = css(styles, ...values);\n const processAttrs = (props: Substitute) =>\n combineProps(\n props,\n typeof attrs === \"function\" ? (attrs as Function)(props) : attrs,\n );\n const yak = (props: Substitute, ref: unknown) => {\n /** The combined props are passed into the styled`` literal functions */\n const combinedProps: Substitute = processAttrs(\n Object.assign(\n // if the css component does not require arguments\n // it can be call without arguments and skip calling useTheme()\n //\n // this is NOT against the rule of hooks as\n // getRuntimeStyles is a constant defined outside of the component\n //\n // for example\n //\n // const Button = styled.button`color: red;`\n // ^ does not need to have access to theme\n //\n // const Button = styled.button`${({ theme }) => css`color: ${theme.color};`}`\n // ^ must be have acces to theme\n attrs || getRuntimeStyles.length ? { theme: useTheme() } : {},\n props,\n ) as Substitute,\n );\n // execute all functions inside the style literal\n // e.g. styled.button`color: ${props => props.color};`\n const runtimeStyles = getRuntimeStyles(combinedProps as any);\n\n // remove all props that start with a $ sign for string components e.g. \"button\" or \"div\"\n // so that they are not passed to the DOM element\n const filteredProps =\n typeof Component === \"string\"\n ? removePrefixedProperties(combinedProps)\n : combinedProps;\n\n // yak provides a className and style prop that needs to be merged with the\n // user provided className and style prop\n (filteredProps as { className?: string }).className = mergeClassNames(\n (combinedProps as { className?: string }).className,\n runtimeStyles.className as string,\n );\n (filteredProps as { style?: React.CSSProperties }).style =\n \"style\" in combinedProps\n ? {\n ...(combinedProps as { style?: React.CSSProperties }).style,\n ...runtimeStyles.style,\n }\n : runtimeStyles.style;\n // if the styled(Component) syntax is used and the component is a yak component\n // we can call the yak function directly to avoid an unnecessary wrapper with an additional\n // forwardRef call\n if (typeof Component !== \"string\" && \"yak\" in Component) {\n return (\n Component as typeof Component & {\n yak: FunctionComponent;\n }\n ).yak(filteredProps, ref);\n }\n\n (filteredProps as { ref?: unknown }).ref = ref;\n return ;\n };\n return yakForwardRef(yak);\n };\n};\n\n/**\n * Type for the proxy object returned by `styled` that allows to\n * access all html tags as properties.\n */\ntype StyledLiteral = = {}>(\n styles: TemplateStringsArray,\n ...values: Array>\n) => FunctionComponent;\n\n/**\n * The `styled` method works perfectly on all of your own or any third-party component,\n * as long as they attach the passed className prop to a DOM element.\n *\n * @usage\n *\n * ```tsx\n * const StyledLink = styled(Link)`\n * color: #BF4F74;\n * font-weight: bold;\n * `;\n * ```\n */\nexport const styled = new Proxy(\n StyledFactory as typeof StyledFactory & {\n [Tag in HtmlTags]: StyledLiteral & {\n attrs: <\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged<\n JSX.IntrinsicElements[Tag],\n TAttrsIn\n > = AttrsMerged,\n >(\n attrs: Attrs,\n ) => StyledLiteral>;\n };\n },\n {\n get(target, TagName: keyof JSX.IntrinsicElements) {\n return target(TagName);\n },\n },\n);\n\n// Remove all entries that start with a $ sign\nfunction removePrefixedProperties>(obj: T) {\n const result = {} as T;\n for (const key in obj) {\n if (!key.startsWith(\"$\") && key !== \"theme\") {\n result[key] = obj[key];\n }\n }\n return result;\n}\n\nconst mergeClassNames = (a?: string, b?: string) => {\n if (!a) return b;\n if (!b) return a;\n return a + \" \" + b;\n};\n\nconst removeUndefined = (obj: T) => {\n const result = {} as T;\n for (const key in obj) {\n if (obj[key] !== undefined) {\n result[key] = obj[key];\n }\n }\n return result;\n};\n\nconst combineProps = <\n T extends {\n className?: string;\n style?: React.CSSProperties;\n },\n>(\n props: T,\n newProps: T,\n) => {\n if (!newProps) return props;\n const combinedProps: T =\n \"$__attrs\" in props\n ? // allow overriding props when attrs was used previously\n {\n ...removeUndefined(newProps),\n ...props,\n }\n : {\n ...props,\n ...removeUndefined(newProps),\n };\n return {\n ...combinedProps,\n className: mergeClassNames(\n props.className as string,\n newProps.className as string,\n ),\n style: { ...(props.style || {}), ...(newProps.style || {}) },\n $__attrs: true,\n };\n};\n\n// util type to remove properties from an object\ntype FastOmit = {\n [K in keyof T as K extends U ? never : K]: T[K];\n};\n\n// util type to merge two objects\n// if a property is present in both objects the property from B is used\nexport type Substitute = FastOmit<\n A,\n keyof B\n> &\n B;\n","/**\n * Allows to use atomic CSS classes in a styled or css block\n *\n * @usage\n *\n * ```tsx\n * import { styled, atoms } from \"next-yak\";\n *\n * const Button = styled.button<{ $primary?: boolean }>`\n * ${atoms(\"text-teal-600\", \"text-base\", \"rounded-md\")}\n * ${props => props.$primary && atoms(\"shadow-md\")}\n * `;\n * ```\n */\nexport const atoms = (...atoms: string[]) => {\n const className = atoms.join(\" \");\n return () => ({ className });\n};\n","/**\n * Allows to use CSS keyframe animations in a styled or css block\n *\n * @usage\n *\n * ```tsx\n * import { styled, keyframes } from \"next-yak\";\n *\n * const rotate = keyframes`\n * from {\n * transform: rotate(0deg);\n * }\n * to {\n * transform: rotate(360deg);\n * }\n * `;\n *\n * const Spinner = styled.div`\n * animation: ${rotate} 1s linear infinite;\n * `;\n * ```\n */\nexport const keyframes = (\n styles: TemplateStringsArray,\n ...dynamic: never[]\n): string => {\n // during compilation all args of keyframe are compiled\n // to a string which references the animation name\n return styles as any as string;\n};\n","export { css } from \"./cssLiteral.js\";\nexport { styled } from \"./styled.js\";\nexport { atoms } from \"./atoms.js\";\nexport { keyframes } from \"./keyframes.js\";\n\n// the following export is not relative as \"next-yak/context\"\n// links to one file for react server components and\n// to another file for classic react components\nexport { useTheme, YakThemeProvider } from \"next-yak/context\";\n\nexport type { YakTheme } from \"./context/index.d.ts\";\n"],"mappings":"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","names":["internalCssFactory","args","classNames","dynamicCssFunctions","style","arg","key","value","props","recursivePropExecution","className","allClassNames","allStyles","i","unwrapProps","fn","result","css","React","useTheme","yakForwardRef","component","StyledFactory","Component","yakStyled","attrs","styles","values","getRuntimeStyles","css","processAttrs","props","combineProps","ref","combinedProps","runtimeStyles","filteredProps","removePrefixedProperties","mergeClassNames","styled","target","TagName","obj","result","key","a","b","removeUndefined","newProps","atoms","className","keyframes","styles","dynamic","useTheme","YakThemeProvider"]} \ No newline at end of file +{"version":3,"sources":["../runtime/cssLiteral.tsx","../runtime/styled.tsx","../runtime/atoms.tsx","../runtime/keyframes.tsx","../runtime/index.ts"],"sourcesContent":["import type { YakTheme } from \"./index.d.ts\";\n\ntype ComponentStyles = (props: TProps) => {\n className: string;\n style?: {\n [key: string]: string;\n };\n};\n\nexport type CSSInterpolation =\n | string\n | number\n | undefined\n | null\n | false\n | ComponentStyles\n | { \n // type only identifier to allow targeting components\n // e.g. styled.svg`${Button}:hover & { fill: red; }`\n __yak: true \n }\n | ((props: TProps) => CSSInterpolation);\n\ntype CSSStyles = {\n style: { [key: string]: string | ((props: TProps) => string) };\n};\n\ntype CSSFunction = (\n styles: TemplateStringsArray,\n ...values: CSSInterpolation[]\n) => ComponentStyles;\n\ntype PropsToClassNameFn = (props: unknown) =>\n | {\n className?: string;\n style?: Record;\n }\n | PropsToClassNameFn;\n\n/**\n * css() runtime factory of css``\n *\n * /!\\ next-yak transpiles css`` and styled``\n *\n * This changes the typings of the css`` and styled`` functions.\n * During development the user of next-yak wants to work with the\n * typings BEFORE compilation.\n *\n * Therefore this is only an internal function only and it must be cast to any\n * before exported to the user.\n */\nconst internalCssFactory = (\n ...args: Array>\n) => {\n const classNames: string[] = [];\n const dynamicCssFunctions: PropsToClassNameFn[] = [];\n const style: Record = {};\n for (const arg of args) {\n // A CSS-module class name which got auto generated during build from static css\n // e.g. css`color: red;`\n // compiled -> css(\"yak31e4\")\n if (typeof arg === \"string\") {\n classNames.push(arg);\n }\n // Dynamic CSS e.g.\n // css`${props => props.active && css`color: red;`}`\n // compiled -> css((props: { active: boolean }) => props.active && css(\"yak31e4\"))\n else if (typeof arg === \"function\") {\n dynamicCssFunctions.push(arg as unknown as PropsToClassNameFn);\n }\n // Dynamic CSS with css variables e.g.\n // css`transform: translate(${props => props.x}, ${props => props.y});`\n // compiled -> css(\"yak31e4\", { style: { \"--yakVarX\": props => props.x }, \"--yakVarY\": props => props.y }})\n else if (typeof arg === \"object\" && \"style\" in arg) {\n for (const key in arg.style) {\n const value = arg.style[key];\n if (typeof value === \"function\") {\n dynamicCssFunctions.push((props: unknown) => ({\n style: {\n [key]: String(\n // The value for a css value can be a theme dependent function e.g.:\n // const borderColor = (props: { theme: { mode: \"dark\" | \"light\" } }) => props.theme === \"dark\" ? \"black\" : \"white\";\n // css`border-color: ${borderColor};`\n // Therefore the value has to be extracted recursively\n recursivePropExecution(props, value),\n ),\n },\n }));\n } else {\n style[key] = value;\n }\n }\n }\n }\n\n // Non Dynamic CSS\n if (dynamicCssFunctions.length === 0) {\n const className = classNames.join(\" \");\n return () => ({ className, style });\n }\n\n return (props: unknown) => {\n const allClassNames: string[] = [...classNames];\n const allStyles: Record = { ...style };\n for (let i = 0; i < dynamicCssFunctions.length; i++) {\n unwrapProps(props, dynamicCssFunctions[i], allClassNames, allStyles);\n }\n return {\n className: allClassNames.join(\" \"),\n style: allStyles,\n };\n };\n};\n\n// Dynamic CSS with runtime logic\nconst unwrapProps = (\n props: unknown,\n fn: PropsToClassNameFn,\n classNames: string[],\n style: Record,\n) => {\n let result = fn(props);\n while (result) {\n if (typeof result === \"function\") {\n result = result(props);\n continue;\n } else if (typeof result === \"object\") {\n if (\"className\" in result && result.className) {\n classNames.push(result.className);\n }\n if (\"style\" in result && result.style) {\n for (const key in result.style) {\n style[key] = result.style[key];\n }\n }\n }\n break;\n }\n};\n\nconst recursivePropExecution = (\n props: unknown,\n fn: (props: unknown) => any,\n): string | number => {\n const result = fn(props);\n if (typeof result === \"function\") {\n return recursivePropExecution(props, result);\n }\n if (process.env.NODE_ENV === \"development\") {\n if (\n typeof result !== \"string\" &&\n typeof result !== \"number\" &&\n !(result instanceof String)\n ) {\n throw new Error(\n `Dynamic CSS functions must return a string or number but returned ${JSON.stringify(\n result,\n )}`,\n );\n }\n }\n return result;\n};\n\nexport const css = internalCssFactory as any as CSSFunction;\n","import { ForwardRefRenderFunction, FunctionComponent } from \"react\";\nimport { CSSInterpolation, css } from \"./cssLiteral.js\";\nimport React from \"react\";\n\n// the following export is not relative as \"next-yak/context\"\n// links to one file for react server components and\n// to another file for classic react components\nimport { useTheme } from \"next-yak/context\";\nimport type { YakTheme } from \"./context/index.d.ts\";\n\n/**\n * Hack to hide .yak from the type definition and to deal with ExoticComponents\n */\nconst yakForwardRef: (\n component: ForwardRefRenderFunction\n) => FunctionComponent & {\n // type only identifier to allow targeting components\n // e.g. styled.svg`${Button}:hover & { fill: red; }`\n // warning: `__yak` is undefined during runtime\n __yak: true;\n} = (component) =>\n Object.assign(React.forwardRef(component), { component }) as any;\n\n/**\n * All valid html tags\n */\ntype HtmlTags = keyof JSX.IntrinsicElements;\n\n/**\n * Return type of the provided props merged with the initial props\n * where the specified props are optional\n */\ntype AttrsMerged = Substitute<\n TBaseProps & { theme: YakTheme },\n TIn\n>;\n\n/**\n * The attrs function allows to add additional props to a styled component.\n * The props can be specified as an object or as a function that receives the\n * current props as argument.\n */\ntype Attrs<\n TBaseProps,\n TIn extends object = {},\n TOut extends AttrsMerged = AttrsMerged,\n> =\n | Partial\n | ((p: Substitute) => Partial);\n\n//\n// The `styled()` and `styled.` API\n//\n// The API design is inspired by styled-components:\n// https://github.com/styled-components/styled-components/blob/main/packages/styled-components/src/constructors/styled.tsx\n// https://github.com/styled-components/styled-components/blob/main/packages/styled-components/src/models/StyledComponent.ts\n//\n\nconst StyledFactory = (Component: HtmlTags | FunctionComponent) =>\n Object.assign(yakStyled(Component), {\n attrs: <\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged = AttrsMerged,\n >(\n attrs: Attrs\n ) => yakStyled(Component, attrs),\n });\n\nconst yakStyled = <\n T,\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged = AttrsMerged,\n>(\n Component: FunctionComponent | HtmlTags,\n attrs?: Attrs\n) => {\n return = {}>(\n styles: TemplateStringsArray,\n ...values: Array>\n ) => {\n const getRuntimeStyles = css(styles, ...values);\n const processAttrs = (props: Substitute) =>\n combineProps(\n props,\n typeof attrs === \"function\" ? (attrs as Function)(props) : attrs\n );\n const yak = (props: Substitute, ref: unknown) => {\n /** The combined props are passed into the styled`` literal functions */\n const combinedProps: Substitute = processAttrs(\n Object.assign(\n // if the css component does not require arguments\n // it can be call without arguments and skip calling useTheme()\n //\n // `__yak` is NOT against the rule of hooks as\n // getRuntimeStyles is a constant defined outside of the component\n //\n // for example\n //\n // const Button = styled.button`color: red;`\n // ^ does not need to have access to theme\n //\n // const Button = styled.button`${({ theme }) => css`color: ${theme.color};`}`\n // ^ must be have acces to theme\n attrs || getRuntimeStyles.length ? { theme: useTheme() } : {},\n props\n ) as Substitute\n );\n // execute all functions inside the style literal\n // e.g. styled.button`color: ${props => props.color};`\n const runtimeStyles = getRuntimeStyles(combinedProps as any);\n\n // remove all props that start with a $ sign for string components e.g. \"button\" or \"div\"\n // so that they are not passed to the DOM element\n const filteredProps =\n typeof Component === \"string\"\n ? removePrefixedProperties(combinedProps)\n : combinedProps;\n\n // yak provides a className and style prop that needs to be merged with the\n // user provided className and style prop\n (filteredProps as { className?: string }).className = mergeClassNames(\n (combinedProps as { className?: string }).className,\n runtimeStyles.className as string\n );\n (filteredProps as { style?: React.CSSProperties }).style =\n \"style\" in combinedProps\n ? {\n ...(combinedProps as { style?: React.CSSProperties }).style,\n ...runtimeStyles.style,\n }\n : runtimeStyles.style;\n // if the styled(Component) syntax is used and the component is a yak component\n // we can call the yak function directly to avoid an unnecessary wrapper with an additional\n // forwardRef call\n if (typeof Component !== \"string\" && \"yak\" in Component) {\n return (\n Component as typeof Component & {\n yak: FunctionComponent;\n }\n ).yak(filteredProps, ref);\n }\n\n (filteredProps as { ref?: unknown }).ref = ref;\n return ;\n };\n return yakForwardRef(yak);\n };\n};\n\n/**\n * Type for the proxy object returned by `styled` that allows to\n * access all html tags as properties.\n */\ntype StyledLiteral = = {}>(\n styles: TemplateStringsArray,\n ...values: Array>\n) => FunctionComponent & {\n // type only identifier to allow targeting components\n // e.g. styled.svg`${Button}:hover & { fill: red; }`\n // warning: this is undefined during runtime\n __yak: true;\n};\n\n/**\n * The `styled` method works perfectly on all of your own or any third-party component,\n * as long as they attach the passed className prop to a DOM element.\n *\n * @usage\n *\n * ```tsx\n * const StyledLink = styled(Link)`\n * color: #BF4F74;\n * font-weight: bold;\n * `;\n * ```\n */\nexport const styled = new Proxy(\n StyledFactory as typeof StyledFactory & {\n [Tag in HtmlTags]: StyledLiteral & {\n attrs: <\n TAttrsIn extends object = {},\n TAttrsOut extends AttrsMerged<\n JSX.IntrinsicElements[Tag],\n TAttrsIn\n > = AttrsMerged,\n >(\n attrs: Attrs\n ) => StyledLiteral>;\n };\n },\n {\n get(target, TagName: keyof JSX.IntrinsicElements) {\n return target(TagName);\n },\n }\n);\n\n// Remove all entries that start with a $ sign\nfunction removePrefixedProperties>(obj: T) {\n const result = {} as T;\n for (const key in obj) {\n if (!key.startsWith(\"$\") && key !== \"theme\") {\n result[key] = obj[key];\n }\n }\n return result;\n}\n\nconst mergeClassNames = (a?: string, b?: string) => {\n if (!a) return b;\n if (!b) return a;\n return a + \" \" + b;\n};\n\nconst removeUndefined = (obj: T) => {\n const result = {} as T;\n for (const key in obj) {\n if (obj[key] !== undefined) {\n result[key] = obj[key];\n }\n }\n return result;\n};\n\nconst combineProps = <\n T extends {\n className?: string;\n style?: React.CSSProperties;\n },\n>(\n props: T,\n newProps: T\n) => {\n if (!newProps) return props;\n const combinedProps: T =\n \"$__attrs\" in props\n ? // allow overriding props when attrs was used previously\n {\n ...removeUndefined(newProps),\n ...props,\n }\n : {\n ...props,\n ...removeUndefined(newProps),\n };\n return {\n ...combinedProps,\n className: mergeClassNames(\n props.className as string,\n newProps.className as string\n ),\n style: { ...(props.style || {}), ...(newProps.style || {}) },\n $__attrs: true,\n };\n};\n\n// util type to remove properties from an object\ntype FastOmit = {\n [K in keyof T as K extends U ? never : K]: T[K];\n};\n\n// util type to merge two objects\n// if a property is present in both objects the property from B is used\nexport type Substitute = FastOmit<\n A,\n keyof B\n> &\n B;\n","/**\n * Allows to use atomic CSS classes in a styled or css block\n *\n * @usage\n *\n * ```tsx\n * import { styled, atoms } from \"next-yak\";\n *\n * const Button = styled.button<{ $primary?: boolean }>`\n * ${atoms(\"text-teal-600\", \"text-base\", \"rounded-md\")}\n * ${props => props.$primary && atoms(\"shadow-md\")}\n * `;\n * ```\n */\nexport const atoms = (...atoms: string[]) => {\n const className = atoms.join(\" \");\n return () => ({ className });\n};\n","/**\n * Allows to use CSS keyframe animations in a styled or css block\n *\n * @usage\n *\n * ```tsx\n * import { styled, keyframes } from \"next-yak\";\n *\n * const rotate = keyframes`\n * from {\n * transform: rotate(0deg);\n * }\n * to {\n * transform: rotate(360deg);\n * }\n * `;\n *\n * const Spinner = styled.div`\n * animation: ${rotate} 1s linear infinite;\n * `;\n * ```\n */\nexport const keyframes = (\n styles: TemplateStringsArray,\n ...dynamic: never[]\n): string => {\n // during compilation all args of keyframe are compiled\n // to a string which references the animation name\n return styles as any as string;\n};\n","export { css } from \"./cssLiteral.js\";\nexport { styled } from \"./styled.js\";\nexport { atoms } from \"./atoms.js\";\nexport { keyframes } from \"./keyframes.js\";\n\n// the following export is not relative as \"next-yak/context\"\n// links to one file for react server components and\n// to another file for classic react components\nexport { useTheme, YakThemeProvider } from \"next-yak/context\";\n\nexport type { YakTheme } from \"./context/index.d.ts\";\n"],"mappings":"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","names":["internalCssFactory","args","classNames","dynamicCssFunctions","style","arg","key","value","props","recursivePropExecution","className","allClassNames","allStyles","i","unwrapProps","fn","result","css","React","useTheme","yakForwardRef","component","StyledFactory","Component","yakStyled","attrs","styles","values","getRuntimeStyles","css","processAttrs","props","combineProps","ref","combinedProps","runtimeStyles","filteredProps","removePrefixedProperties","mergeClassNames","styled","target","TagName","obj","result","key","a","b","removeUndefined","newProps","atoms","className","keyframes","styles","dynamic","useTheme","YakThemeProvider"]} \ No newline at end of file diff --git a/packages/next-yak/package.json b/packages/next-yak/package.json index ee89b102..51830b2f 100644 --- a/packages/next-yak/package.json +++ b/packages/next-yak/package.json @@ -1,6 +1,6 @@ { "name": "next-yak", - "version": "0.0.16", + "version": "0.0.17", "type": "module", "types": "./dist/", "exports": { diff --git a/packages/next-yak/runtime/cssLiteral.tsx b/packages/next-yak/runtime/cssLiteral.tsx index ceefe869..22aa254c 100644 --- a/packages/next-yak/runtime/cssLiteral.tsx +++ b/packages/next-yak/runtime/cssLiteral.tsx @@ -14,6 +14,11 @@ export type CSSInterpolation = | null | false | ComponentStyles + | { + // type only identifier to allow targeting components + // e.g. styled.svg`${Button}:hover & { fill: red; }` + __yak: true + } | ((props: TProps) => CSSInterpolation); type CSSStyles = { diff --git a/packages/next-yak/runtime/styled.tsx b/packages/next-yak/runtime/styled.tsx index 6af49fc2..4754025b 100644 --- a/packages/next-yak/runtime/styled.tsx +++ b/packages/next-yak/runtime/styled.tsx @@ -12,8 +12,13 @@ import type { YakTheme } from "./context/index.d.ts"; * Hack to hide .yak from the type definition and to deal with ExoticComponents */ const yakForwardRef: ( - component: ForwardRefRenderFunction, -) => FunctionComponent = (component) => + component: ForwardRefRenderFunction +) => FunctionComponent & { + // type only identifier to allow targeting components + // e.g. styled.svg`${Button}:hover & { fill: red; }` + // warning: `__yak` is undefined during runtime + __yak: true; +} = (component) => Object.assign(React.forwardRef(component), { component }) as any; /** @@ -57,7 +62,7 @@ const StyledFactory = (Component: HtmlTags | FunctionComponent) => TAttrsIn extends object = {}, TAttrsOut extends AttrsMerged = AttrsMerged, >( - attrs: Attrs, + attrs: Attrs ) => yakStyled(Component, attrs), }); @@ -67,7 +72,7 @@ const yakStyled = < TAttrsOut extends AttrsMerged = AttrsMerged, >( Component: FunctionComponent | HtmlTags, - attrs?: Attrs, + attrs?: Attrs ) => { return = {}>( styles: TemplateStringsArray, @@ -77,7 +82,7 @@ const yakStyled = < const processAttrs = (props: Substitute) => combineProps( props, - typeof attrs === "function" ? (attrs as Function)(props) : attrs, + typeof attrs === "function" ? (attrs as Function)(props) : attrs ); const yak = (props: Substitute, ref: unknown) => { /** The combined props are passed into the styled`` literal functions */ @@ -86,7 +91,7 @@ const yakStyled = < // if the css component does not require arguments // it can be call without arguments and skip calling useTheme() // - // this is NOT against the rule of hooks as + // `__yak` is NOT against the rule of hooks as // getRuntimeStyles is a constant defined outside of the component // // for example @@ -97,8 +102,8 @@ const yakStyled = < // const Button = styled.button`${({ theme }) => css`color: ${theme.color};`}` // ^ must be have acces to theme attrs || getRuntimeStyles.length ? { theme: useTheme() } : {}, - props, - ) as Substitute, + props + ) as Substitute ); // execute all functions inside the style literal // e.g. styled.button`color: ${props => props.color};` @@ -115,7 +120,7 @@ const yakStyled = < // user provided className and style prop (filteredProps as { className?: string }).className = mergeClassNames( (combinedProps as { className?: string }).className, - runtimeStyles.className as string, + runtimeStyles.className as string ); (filteredProps as { style?: React.CSSProperties }).style = "style" in combinedProps @@ -149,7 +154,12 @@ const yakStyled = < type StyledLiteral = = {}>( styles: TemplateStringsArray, ...values: Array> -) => FunctionComponent; +) => FunctionComponent & { + // type only identifier to allow targeting components + // e.g. styled.svg`${Button}:hover & { fill: red; }` + // warning: this is undefined during runtime + __yak: true; +}; /** * The `styled` method works perfectly on all of your own or any third-party component, @@ -174,7 +184,7 @@ export const styled = new Proxy( TAttrsIn > = AttrsMerged, >( - attrs: Attrs, + attrs: Attrs ) => StyledLiteral>; }; }, @@ -182,7 +192,7 @@ export const styled = new Proxy( get(target, TagName: keyof JSX.IntrinsicElements) { return target(TagName); }, - }, + } ); // Remove all entries that start with a $ sign @@ -219,7 +229,7 @@ const combineProps = < }, >( props: T, - newProps: T, + newProps: T ) => { if (!newProps) return props; const combinedProps: T = @@ -237,7 +247,7 @@ const combineProps = < ...combinedProps, className: mergeClassNames( props.className as string, - newProps.className as string, + newProps.className as string ), style: { ...(props.style || {}), ...(newProps.style || {}) }, $__attrs: true, From 18c9ab4b4f17c39802817cf4b4c6dc8d8944b30d Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:06:42 +0000 Subject: [PATCH 3/7] [autofix.ci] apply automated fixes --- packages/example/app/Input.tsx | 7 +++++-- packages/next-yak/runtime/cssLiteral.tsx | 10 +++++----- packages/next-yak/runtime/styled.tsx | 22 +++++++++++----------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/packages/example/app/Input.tsx b/packages/example/app/Input.tsx index c94dfe2f..ee7f466e 100644 --- a/packages/example/app/Input.tsx +++ b/packages/example/app/Input.tsx @@ -25,8 +25,11 @@ const Wrapper = styled.div` flex-direction: column; align-items: center; transition: background-color 0.5s ease-in-out; - &:has(${Input}:where(:hover, :focus), ${PasswordInput}::where(:hover, :focus)) { - background-color: #4c4c4cb9 + &:has( + ${Input}:where(:hover, :focus), + ${PasswordInput}::where(:hover, :focus) + ) { + background-color: #4c4c4cb9; } `; diff --git a/packages/next-yak/runtime/cssLiteral.tsx b/packages/next-yak/runtime/cssLiteral.tsx index 22aa254c..315d6ec0 100644 --- a/packages/next-yak/runtime/cssLiteral.tsx +++ b/packages/next-yak/runtime/cssLiteral.tsx @@ -14,11 +14,11 @@ export type CSSInterpolation = | null | false | ComponentStyles - | { - // type only identifier to allow targeting components - // e.g. styled.svg`${Button}:hover & { fill: red; }` - __yak: true - } + | { + // type only identifier to allow targeting components + // e.g. styled.svg`${Button}:hover & { fill: red; }` + __yak: true; + } | ((props: TProps) => CSSInterpolation); type CSSStyles = { diff --git a/packages/next-yak/runtime/styled.tsx b/packages/next-yak/runtime/styled.tsx index 4754025b..588bed06 100644 --- a/packages/next-yak/runtime/styled.tsx +++ b/packages/next-yak/runtime/styled.tsx @@ -12,7 +12,7 @@ import type { YakTheme } from "./context/index.d.ts"; * Hack to hide .yak from the type definition and to deal with ExoticComponents */ const yakForwardRef: ( - component: ForwardRefRenderFunction + component: ForwardRefRenderFunction, ) => FunctionComponent & { // type only identifier to allow targeting components // e.g. styled.svg`${Button}:hover & { fill: red; }` @@ -62,7 +62,7 @@ const StyledFactory = (Component: HtmlTags | FunctionComponent) => TAttrsIn extends object = {}, TAttrsOut extends AttrsMerged = AttrsMerged, >( - attrs: Attrs + attrs: Attrs, ) => yakStyled(Component, attrs), }); @@ -72,7 +72,7 @@ const yakStyled = < TAttrsOut extends AttrsMerged = AttrsMerged, >( Component: FunctionComponent | HtmlTags, - attrs?: Attrs + attrs?: Attrs, ) => { return = {}>( styles: TemplateStringsArray, @@ -82,7 +82,7 @@ const yakStyled = < const processAttrs = (props: Substitute) => combineProps( props, - typeof attrs === "function" ? (attrs as Function)(props) : attrs + typeof attrs === "function" ? (attrs as Function)(props) : attrs, ); const yak = (props: Substitute, ref: unknown) => { /** The combined props are passed into the styled`` literal functions */ @@ -102,8 +102,8 @@ const yakStyled = < // const Button = styled.button`${({ theme }) => css`color: ${theme.color};`}` // ^ must be have acces to theme attrs || getRuntimeStyles.length ? { theme: useTheme() } : {}, - props - ) as Substitute + props, + ) as Substitute, ); // execute all functions inside the style literal // e.g. styled.button`color: ${props => props.color};` @@ -120,7 +120,7 @@ const yakStyled = < // user provided className and style prop (filteredProps as { className?: string }).className = mergeClassNames( (combinedProps as { className?: string }).className, - runtimeStyles.className as string + runtimeStyles.className as string, ); (filteredProps as { style?: React.CSSProperties }).style = "style" in combinedProps @@ -184,7 +184,7 @@ export const styled = new Proxy( TAttrsIn > = AttrsMerged, >( - attrs: Attrs + attrs: Attrs, ) => StyledLiteral>; }; }, @@ -192,7 +192,7 @@ export const styled = new Proxy( get(target, TagName: keyof JSX.IntrinsicElements) { return target(TagName); }, - } + }, ); // Remove all entries that start with a $ sign @@ -229,7 +229,7 @@ const combineProps = < }, >( props: T, - newProps: T + newProps: T, ) => { if (!newProps) return props; const combinedProps: T = @@ -247,7 +247,7 @@ const combineProps = < ...combinedProps, className: mergeClassNames( props.className as string, - newProps.className as string + newProps.className as string, ), style: { ...(props.style || {}), ...(newProps.style || {}) }, $__attrs: true, From 1b4be847691ee0ddbbda04bb3d131174c63bcbf7 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Mon, 20 Nov 2023 15:07:31 +0100 Subject: [PATCH 4/7] add dot --- packages/next-yak/loaders/__tests__/cssloader.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/next-yak/loaders/__tests__/cssloader.test.ts b/packages/next-yak/loaders/__tests__/cssloader.test.ts index 8332b104..ad80508e 100644 --- a/packages/next-yak/loaders/__tests__/cssloader.test.ts +++ b/packages/next-yak/loaders/__tests__/cssloader.test.ts @@ -402,16 +402,16 @@ const Wrapper = styled.div\` fill: currentColor; width: 1em; height: 1em; - yak_1:hover & { + .yak_1:hover & { color: red; } - yak_1:focus & { + .yak_1:focus & { color: red; } } .yak_4 { - &:has(> yak_1) { + &:has(> .yak_1) { padding: 10px; } }" From eff9499b40a64c06630e6df309afe623401df24a Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Mon, 20 Nov 2023 15:13:14 +0100 Subject: [PATCH 5/7] fix css --- packages/example/app/Input.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/example/app/Input.tsx b/packages/example/app/Input.tsx index ee7f466e..40513d1a 100644 --- a/packages/example/app/Input.tsx +++ b/packages/example/app/Input.tsx @@ -27,7 +27,7 @@ const Wrapper = styled.div` transition: background-color 0.5s ease-in-out; &:has( ${Input}:where(:hover, :focus), - ${PasswordInput}::where(:hover, :focus) + ${PasswordInput}:where(:hover, :focus) ) { background-color: #4c4c4cb9; } From dbf616a35725e5218f501452da93bb04805836bd Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Tue, 21 Nov 2023 09:08:13 +0100 Subject: [PATCH 6/7] Update packages/next-yak/loaders/cssloader.cjs Co-authored-by: Luca Schneider <7972860+Mad-Kat@users.noreply.github.com> --- packages/next-yak/loaders/cssloader.cjs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/next-yak/loaders/cssloader.cjs b/packages/next-yak/loaders/cssloader.cjs index e7fe97ec..2ad3b9c9 100644 --- a/packages/next-yak/loaders/cssloader.cjs +++ b/packages/next-yak/loaders/cssloader.cjs @@ -221,8 +221,7 @@ module.exports = async function cssLoader(source) { }); } - // Store reference to AST node to allow other components to target the styled literal inside css like - // e.g. `& ${Button} { ... }` + // Store class name of the created variable if (isStyledLiteral || isStyledCall || isAttrsCall) { const variableName = getStyledComponentName(path); // TODO: reuse existing class name if possible From b4b65a0b4750d326676ae64f0b9faaeb665dbfcb Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Tue, 21 Nov 2023 09:09:37 +0100 Subject: [PATCH 7/7] improve comments --- packages/next-yak/loaders/cssloader.cjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/next-yak/loaders/cssloader.cjs b/packages/next-yak/loaders/cssloader.cjs index 2ad3b9c9..dd8690dc 100644 --- a/packages/next-yak/loaders/cssloader.cjs +++ b/packages/next-yak/loaders/cssloader.cjs @@ -221,7 +221,9 @@ module.exports = async function cssLoader(source) { }); } - // Store class name of the created variable + // Store class name for the created variable for later replacements + // e.g. const MyStyledDiv = styled.div`color: red;` + // "MyStyledDiv" -> "selector-0" if (isStyledLiteral || isStyledCall || isAttrsCall) { const variableName = getStyledComponentName(path); // TODO: reuse existing class name if possible