panda-plugin-crv
Version:
A Panda CSS plugin for responsive variants
138 lines (114 loc) • 7.09 kB
JavaScript
import{ts as v}from"ts-morph";var k=`
const groupByBreakpoint = (variants) => {
const result = {};
for (const bp of crvBreakpoints) {
let renamed = {};
for (const [key, value] of Object.entries(variants)) {
renamed[makeKey(key, bp)] = value;
}
result[bp] = renamed;
}
return Object.entries(result);
};
export const ccv = (args) => {
const { css, ...variants } = args;
if (!variants || !css) return [];
const compoundVariants = [{ ...variants, css }];
for (const [bp, keys] of groupByBreakpoint(variants)) {
compoundVariants.push({ ...keys, css: { [bp]: css } });
}
return compoundVariants;
};`,P=`
/**
* Create compound variants
*
* @example
* variants: {
* crv({
* variants: {
* ...crv('prop', {
* variant1: { color: 'red' },
* variant2: { color: 'blue' }
* })
* })
* },
* compoundVariants: [
* ...ccv({
* variant1: 'red',
* variant2: 'blue',
* css: {
* bg: 'green'
* }
* })
* ]
*/
export declare const ccv: <T extends Record<any, any> & { css: SystemStyleObject }>(
args: T,
) => Array<{ css: T['css'] } & Record<keyof T, any>>;
`;var d=(t,e)=>`${t}_${e}`,T=t=>`
const crvBreakpoints = [${t.map(e=>`'${e}'`).join(", ")}];
const makeKey = (name, bp) => {
return \`\${name}_\${bp}\`;
}
const injectBreakpoint = (styles, breakpoint) => {
return Object.fromEntries(
Object.entries(styles).map(([key, css]) => [[key], { [breakpoint]: css }]),
);
};
export const crv = (name, styles) => {
if (!name) return;
const variants = {
[name]: styles,
};
for (const bp of crvBreakpoints) {
variants[makeKey(name, bp)] = injectBreakpoint(styles, bp);
}
return variants;
};
export const splitResponsiveVariant = (name, value) => {
if (typeof value !== 'object') {
return { [name]: value };
}
const { base, ...rest } = value;
let variants = { [name]: base };
for (const bp of crvBreakpoints) {
if (!(bp in rest)) continue;
variants[makeKey(name, bp)] = rest[bp];
}
return variants;
};
export const splitCrv = splitResponsiveVariant;
${k}
`,S=t=>`/* eslint-disable */
import type { SystemStyleObject } from '../types/system-types';
type CrvBreakpoints = ${t.map(e=>`'${e}'`).join(" | ")};
/**
* Create responsive variants
*
* @example
* cva({
* variants: {
* ...crv('prop', {
* variant1: { color: 'red' },
* variant2: { color: 'blue' }
* })
* })
*/
export declare const crv: <T extends string, P extends Record<any, SystemStyleObject>>(
name: T,
styles: P
) => Record<\`\${T}_\${CrvBreakpoints}\` | T, P>;
/**
* Splits responsive objects into \`crv\` variants
*/
type SplitResponsiveVariant = <T extends string>(
name: T,
value: any
) => Record<\`\${T}_\${CrvBreakpoints}\` | T, any>;
export declare const splitCrv: SplitResponsiveVariant;
export declare const splitResponsiveVariant: SplitResponsiveVariant;
export type ResponsiveVariant<T> = Partial<Record<'base' | CrvBreakpoints, T>> | T;
${P}
`;var $=t=>t.replace(/^\s+|\s+$|\s+(?=\s)/g,""),j=t=>{let{writer:e,key:i,value:n,bp:r}=t;e.write(`${i}: {`);for(let s of n.getProperties()){if(!s.isKind(v.SyntaxKind.PropertyAssignment))continue;let o=s.getInitializer()?.getText()??"";r?(e.write(`${s.getName()}: {`),e.write(`'${r}':`),e.write(`${$(o)},`),e.write("},")):e.write(`${$(s.getText())},`)}e.write("},")},C=(t,e,i,n="crv")=>{let{breakpoints:r,debug:s}=e,o=i.getDescendantsOfKind(v.SyntaxKind.CallExpression).filter(c=>c.getExpression().getText()===n);if(o.length){for(let c of o){let f=c.getArguments()[0],p=c.getArguments()[1],a=f?.getText()??"";f&&f.isKind(v.SyntaxKind.StringLiteral)&&(a=f.getLiteralValue()),!(!p||!p.isKind(v.SyntaxKind.ObjectLiteralExpression))&&(c.replaceWithText(l=>{l.write("{"),j({writer:l,key:a,value:p});for(let g of r)j({writer:l,key:d(a,g),value:p,bp:g});l.write("}")}),s?.("plugin:crv",`crv: '${a}': ${t.filePath.split("/").at(-1)}`))}return i.getText()}};import{ts as u}from"ts-morph";var x=t=>t.replace(/^\s+|\s+$|\s+(?=\s)/g,""),A=t=>{let{writer:e,variants:i,value:n,bp:r,isLast:s}=t;e.write("{");for(let o of i){if(!o.isKind(u.SyntaxKind.PropertyAssignment))continue;let c=o.getInitializer()?.getText()??"";r?(e.write(`${d(o.getName(),r)}: `),e.write(`${x(c)},`)):e.write(`${x(o.getText())},`)}e.write("css: {"),r&&e.write(`'${r}': {`);for(let o of n.getProperties())e.write(`${x(o.getText())},`);r&&e.write("}},"),r||e.write("},"),e.write(s?"}":"},")},K=(t,e,i,n="ccv")=>{let{breakpoints:r,debug:s}=e,o=i.getDescendantsOfKind(u.SyntaxKind.SpreadElement).filter(c=>c.getExpression()?.getText().startsWith(n));if(o.length){for(let c of o){let f=c.getExpressionIfKind(u.SyntaxKind.CallExpression);if(!f)continue;let p=f.getArguments().at(0);if(!p||!p.isKind(u.SyntaxKind.ObjectLiteralExpression))continue;let a=p.getProperties(),l,g=a.filter(m=>m.isKind(u.SyntaxKind.PropertyAssignment)?m.getName()!=="css":!1);for(let m of a)m.isKind(u.SyntaxKind.PropertyAssignment)&&m.getName()==="css"&&(l=m.getInitializer());if(!l||!l.isKind(u.SyntaxKind.ObjectLiteralExpression))continue;let w=c.replaceWithText(m=>{A({writer:m,variants:g,value:l});for(let[E,O]of r.entries())A({writer:m,variants:g,value:l,bp:O,isLast:E===r.length-1})});s?.("plugin:crv",`ccv: '${w.getText()}': ${t.filePath.split("/").at(-1)}`)}return i.getText()}};var y=["crv","ccv"],L=t=>{let e={};for(let i of t.getImportDeclarations())if(!(!i.getText().includes(y[0])&&!i.getText().includes(y[1])))for(let n of i.getNamedImports())for(let r of y)(n.getText()===r||n.getText().startsWith(`${r} as`))&&(e[r]=n.getAliasNode()?.getText()??r);return e},B=(t,e)=>{let{project:i}=e,n,r=i.createSourceFile("__crv-parser.tsx",t.content,{overwrite:!0}),s=L(r);if(s.crv&&(n=C(t,e,r,s.crv)),s.ccv&&(n=K(t,e,r,s.ccv)??n),!!n)return r.getText()};var F=(t,e)=>{let i=t.artifacts.find(a=>a.id==="css-fn"),n=t.artifacts.find(a=>a.id==="css-index"),r=n?.files.find(a=>a.file.match(/^index\.(mjs|js)/)),s=n?.files.find(a=>a.file.includes("index.d.")),o=r?.file.split(".").at(-1),c=s?.file.split(".").at(-1);if(!i||!r||!s)return t.artifacts;let f={file:`crv.${o}`,code:T(e.breakpoints)},p={file:`crv.d.${c}`,code:S(e.breakpoints)};return i.files.push(f,p),r.code+=`
export * from './crv.${o}';`,s.code+=`
export * from './crv';`,e.debug&&e.debug("plugin:crv","codegen complete"),t.artifacts};import{IndentationText as h,Project as V,ts as b}from"ts-morph";var R=()=>({project:new V({compilerOptions:{jsx:b.JsxEmit.React,jsxFactory:"React.createElement",jsxFragmentFactory:"React.Fragment",module:b.ModuleKind.ESNext,target:b.ScriptTarget.ESNext,noUnusedParameters:!1,noEmit:!0,useVirtualFileSystem:!0,allowJs:!0},skipAddingFilesFromTsConfig:!0,skipFileDependencyResolution:!0,skipLoadingLibFiles:!0,manipulationSettings:{indentationText:h.TwoSpaces}}),breakpoints:[]});var le=()=>{let t=R();return{name:"panda-plugin-crv",hooks:{"context:created":e=>{t.debug=e.logger?.debug,t.breakpoints=Object.keys(e.ctx.config.theme?.breakpoints??{})},"parser:before":e=>B(e,t),"codegen:prepare":e=>F(e,t)}}};export{le as pluginResponsiveVariants};