🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

tailwindcss

Package Overview
Dependencies
Maintainers
3
Versions
2617
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tailwindcss - npm Package Compare versions

Comparing version
0.0.0-insiders.b52a78b
to
0.0.0-insiders.b53fa09
+1
dist/chunk-5JIJA4QV.mjs
function h(n){if(arguments.length===0)throw new TypeError("`CSS.escape` requires an argument.");let e=String(n),i=e.length,r=-1,t,s="",l=e.charCodeAt(0);if(i===1&&l===45)return"\\"+e;for(;++r<i;){if(t=e.charCodeAt(r),t===0){s+="\uFFFD";continue}if(t>=1&&t<=31||t===127||r===0&&t>=48&&t<=57||r===1&&t>=48&&t<=57&&l===45){s+="\\"+t.toString(16)+" ";continue}if(t>=128||t===45||t===95||t>=48&&t<=57||t>=65&&t<=90||t>=97&&t<=122){s+=e.charAt(r);continue}s+="\\"+e.charAt(r)}return s}function a(n){return n.replace(/\\([\dA-Fa-f]{1,6}[\t\n\f\r ]?|[\S\s])/g,e=>{if(e.length<=2)return e[1];let i=Number.parseInt(e.slice(1).trim(),16);return i===0||i>1114111||i>=55296&&i<=57343?"\uFFFD":String.fromCodePoint(i)})}var c=new Map([["--font",["--font-weight","--font-size"]],["--inset",["--inset-shadow","--inset-ring"]],["--text",["--text-color","--text-decoration-color","--text-decoration-thickness","--text-indent","--text-shadow","--text-underline-offset"]],["--grid-column",["--grid-column-start","--grid-column-end"]],["--grid-row",["--grid-row-start","--grid-row-end"]]]);function g(n,e){return(c.get(e)??[]).some(i=>n===i||n.startsWith(`${i}-`))}var p=class{constructor(e=new Map,i=new Set([])){this.values=e;this.keyframes=i}values;keyframes;prefix=null;get size(){return this.values.size}add(e,i,r=0,t){if(e.endsWith("-*")){if(i!=="initial")throw new Error(`Invalid theme value \`${i}\` for namespace \`${e}\``);e==="--*"?this.values.clear():this.clearNamespace(e.slice(0,-2),0)}if(r&4){let s=this.values.get(e);if(s&&!(s.options&4))return}i==="initial"?this.values.delete(e):this.values.set(e,{value:i,options:r,src:t})}keysInNamespaces(e){let i=[];for(let r of e){let t=`${r}-`;for(let s of this.values.keys())s.startsWith(t)&&s.indexOf("--",2)===-1&&(g(s,r)||i.push(s.slice(t.length)))}return i}get(e){for(let i of e){let r=this.values.get(i);if(r)return r.value}return null}hasDefault(e){return(this.getOptions(e)&4)===4}getOptions(e){return e=a(this.#i(e)),this.values.get(e)?.options??0}entries(){return this.prefix?Array.from(this.values,e=>(e[0]=this.prefixKey(e[0]),e)):this.values.entries()}prefixKey(e){return this.prefix?`--${this.prefix}-${e.slice(2)}`:e}#i(e){return this.prefix?`--${e.slice(3+this.prefix.length)}`:e}clearNamespace(e,i){let r=c.get(e)??[];e:for(let t of this.values.keys())if(t.startsWith(e)){if(i!==0&&(this.getOptions(t)&i)!==i)continue;for(let s of r)if(t.startsWith(s))continue e;this.values.delete(t)}}#e(e,i){for(let r of i){let t=e!==null?`${r}-${e}`:r;if(!this.values.has(t))if(e!==null&&e.includes(".")){if(t=`${r}-${e.replaceAll(".","_")}`,!this.values.has(t))continue}else continue;if(!g(t,r))return t}return null}#t(e){let i=this.values.get(e);if(!i)return null;let r=null;return i.options&2&&(r=i.value),`var(${h(this.prefixKey(e))}${r?`, ${r}`:""})`}markUsedVariable(e){let i=a(this.#i(e)),r=this.values.get(i);if(!r)return!1;let t=r.options&16;return r.options|=16,!t}resolve(e,i,r=0){let t=this.#e(e,i);if(!t)return null;let s=this.values.get(t);return(r|s.options)&1?s.value:this.#t(t)}resolveValue(e,i){let r=this.#e(e,i);return r?this.values.get(r).value:null}resolveWith(e,i,r=[]){let t=this.#e(e,i);if(!t)return null;let s={};for(let u of r){let f=`${t}${u}`,o=this.values.get(f);o&&(o.options&1?s[u]=o.value:s[u]=this.#t(f))}let l=this.values.get(t);return l.options&1?[l.value,s]:[this.#t(t),s]}namespace(e){let i=new Map,r=`${e}-`;for(let[t,s]of this.values)t===e?i.set(null,s.value):t.startsWith(`${r}-`)?i.set(t.slice(e.length),s.value):t.startsWith(r)&&i.set(t.slice(r.length),s.value);return i}addKeyframes(e){this.keyframes.add(e)}getKeyframes(){return Array.from(this.keyframes)}};export{h as a,a as b,p as c};
import{a as k}from"./chunk-X4GG3EDV.mjs";var S=new Set(["black","silver","gray","white","maroon","red","purple","fuchsia","green","lime","olive","yellow","navy","blue","teal","aqua","aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen","transparent","currentcolor","canvas","canvastext","linktext","visitedtext","activetext","buttonface","buttontext","buttonborder","field","fieldtext","highlight","highlighttext","selecteditem","selecteditemtext","mark","marktext","graytext","accentcolor","accentcolortext"]),U=/^(rgba?|hsla?|hwb|color|(ok)?(lab|lch)|light-dark|color-mix|--alpha)\(/i;function N(e){return e.charCodeAt(0)===35||U.test(e)||S.has(e.toLowerCase())}function oe(e){return S.has(e.toLowerCase())}var A=["calc","min","max","clamp","mod","rem","sin","cos","tan","asin","acos","atan","atan2","pow","sqrt","hypot","log","exp","round"];function b(e){return e.indexOf("(")!==-1&&A.some(t=>e.includes(`${t}(`))}function ae(e){if(!A.some(n=>e.includes(n)))return e;let t="",r=[],s=null,m=null;for(let n=0;n<e.length;n++){let a=e.charCodeAt(n);if(a>=48&&a<=57||s!==null&&(a===37||a>=97&&a<=122||a>=65&&a<=90)?s=n:(m=s,s=null),a===40){t+=e[n];let i=n;for(let p=n-1;p>=0;p--){let c=e.charCodeAt(p);if(c>=48&&c<=57)i=p;else if(c>=97&&c<=122)i=p;else break}let o=e.slice(i,n);if(A.includes(o)){r.unshift(!0);continue}else if(r[0]&&o===""){r.unshift(!0);continue}r.unshift(!1);continue}else if(a===41)t+=e[n],r.shift();else if(a===44&&r[0]){t+=", ";continue}else{if(a===32&&r[0]&&t.charCodeAt(t.length-1)===32)continue;if((a===43||a===42||a===47||a===45)&&r[0]){let i=t.trimEnd(),o=i.charCodeAt(i.length-1),p=i.charCodeAt(i.length-2),c=e.charCodeAt(n+1);if((o===101||o===69)&&p>=48&&p<=57){t+=e[n];continue}else if(o===43||o===42||o===47||o===45){t+=e[n];continue}else if(o===40||o===44){t+=e[n];continue}else e.charCodeAt(n-1)===32?t+=`${e[n]} `:o>=48&&o<=57||c>=48&&c<=57||o===41||c===40||c===43||c===42||c===47||c===45||m!==null&&m===n-1?t+=` ${e[n]} `:t+=e[n]}else t+=e[n]}}return t}var E=new Uint8Array(256);function d(e,t){let r=0,s=[],m=0,n=e.length,a=t.charCodeAt(0);for(let i=0;i<n;i++){let o=e.charCodeAt(i);if(r===0&&o===a){s.push(e.slice(m,i)),m=i+1;continue}switch(o){case 92:i+=1;break;case 39:case 34:for(;++i<n;){let p=e.charCodeAt(i);if(p===92){i+=1;continue}if(p===o)break}break;case 40:E[r]=41,r++;break;case 91:E[r]=93,r++;break;case 123:E[r]=125,r++;break;case 93:case 125:case 41:r>0&&o===E[r-1]&&r--;break}}return s.push(e.slice(m)),s}var P={color:N,length:y,percentage:C,ratio:G,number:v,integer:u,url:R,position:Y,"bg-size":Q,"line-width":T,image:F,"family-name":M,"generic-name":H,"absolute-size":$,"relative-size":W,angle:ee,vector:re};function ge(e,t){if(e.startsWith("var("))return null;for(let r of t)if(P[r]?.(e))return r;return null}var z=/^url\(.*\)$/;function R(e){return z.test(e)}function T(e){return d(e," ").every(t=>y(t)||v(t)||t==="thin"||t==="medium"||t==="thick")}var D=/^(?:element|image|cross-fade|image-set)\(/,I=/^(repeating-)?(conic|linear|radial)-gradient\(/;function F(e){let t=0;for(let r of d(e,","))if(!r.startsWith("var(")){if(R(r)){t+=1;continue}if(I.test(r)){t+=1;continue}if(D.test(r)){t+=1;continue}return!1}return t>0}function H(e){return e==="serif"||e==="sans-serif"||e==="monospace"||e==="cursive"||e==="fantasy"||e==="system-ui"||e==="ui-serif"||e==="ui-sans-serif"||e==="ui-monospace"||e==="ui-rounded"||e==="math"||e==="emoji"||e==="fangsong"}function M(e){let t=0;for(let r of d(e,",")){let s=r.charCodeAt(0);if(s>=48&&s<=57)return!1;r.startsWith("var(")||(t+=1)}return t>0}function $(e){return e==="xx-small"||e==="x-small"||e==="small"||e==="medium"||e==="large"||e==="x-large"||e==="xx-large"||e==="xxx-large"}function W(e){return e==="larger"||e==="smaller"}var x=/[+-]?\d*\.?\d+(?:[eE][+-]?\d+)?/,B=new RegExp(`^${x.source}$`);function v(e){return B.test(e)||b(e)}var q=new RegExp(`^${x.source}%$`);function C(e){return q.test(e)||b(e)}var V=new RegExp(`^${x.source}\\s*/\\s*${x.source}$`);function G(e){return V.test(e)||b(e)}var Z=["cm","mm","Q","in","pc","pt","px","em","ex","ch","rem","lh","rlh","vw","vh","vmin","vmax","vb","vi","svw","svh","lvw","lvh","dvw","dvh","cqw","cqh","cqi","cqb","cqmin","cqmax"],j=new RegExp(`^${x.source}(${Z.join("|")})$`),K=/^(--spacing)\(/i;function y(e){return j.test(e)||K.test(e)||b(e)}function Y(e){let t=0;for(let r of d(e," ")){if(r==="center"||r==="top"||r==="right"||r==="bottom"||r==="left"){t+=1;continue}if(!r.startsWith("var(")){if(y(r)||C(r)){t+=1;continue}return!1}}return t>0}function Q(e){let t=0;for(let r of d(e,",")){if(r==="cover"||r==="contain"){t+=1;continue}let s=d(r," ");if(s.length!==1&&s.length!==2)return!1;if(s.every(m=>m==="auto"||y(m)||C(m))){t+=1;continue}}return t>0}var J=["deg","rad","grad","turn"],X=new RegExp(`^${x.source}(${J.join("|")})$`);function ee(e){return X.test(e)}var te=new RegExp(`^${x.source} +${x.source} +${x.source}$`);function re(e){return te.test(e)}function u(e){let t=Number(e);return Number.isInteger(t)&&t>=0&&String(t)===String(e)}function ue(e){let t=Number(e);return Number.isInteger(t)&&t>0&&String(t)===String(e)}function de(e){return O(e,.25)}function xe(e){return O(e,.25)}function O(e,t){let r=Number(e);return r>=0&&r%t===0&&String(r)===String(e)}function h(e){return{__BARE_VALUE__:e}}var g=h(e=>{if(u(e.value))return e.value}),l=h(e=>{if(u(e.value))return`${e.value}%`}),f=h(e=>{if(u(e.value))return`${e.value}px`}),L=h(e=>{if(u(e.value))return`${e.value}ms`}),w=h(e=>{if(u(e.value))return`${e.value}deg`}),ne=h(e=>{if(e.fraction===null)return;let[t,r]=d(e.fraction,"/");if(!(!u(t)||!u(r)))return e.fraction}),_=h(e=>{if(u(Number(e.value)))return`repeat(${e.value}, minmax(0, 1fr))`}),ye={accentColor:({theme:e})=>e("colors"),animation:{none:"none",spin:"spin 1s linear infinite",ping:"ping 1s cubic-bezier(0, 0, 0.2, 1) infinite",pulse:"pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",bounce:"bounce 1s infinite"},aria:{busy:'busy="true"',checked:'checked="true"',disabled:'disabled="true"',expanded:'expanded="true"',hidden:'hidden="true"',pressed:'pressed="true"',readonly:'readonly="true"',required:'required="true"',selected:'selected="true"'},aspectRatio:{auto:"auto",square:"1 / 1",video:"16 / 9",...ne},backdropBlur:({theme:e})=>e("blur"),backdropBrightness:({theme:e})=>({...e("brightness"),...l}),backdropContrast:({theme:e})=>({...e("contrast"),...l}),backdropGrayscale:({theme:e})=>({...e("grayscale"),...l}),backdropHueRotate:({theme:e})=>({...e("hueRotate"),...w}),backdropInvert:({theme:e})=>({...e("invert"),...l}),backdropOpacity:({theme:e})=>({...e("opacity"),...l}),backdropSaturate:({theme:e})=>({...e("saturate"),...l}),backdropSepia:({theme:e})=>({...e("sepia"),...l}),backgroundColor:({theme:e})=>e("colors"),backgroundImage:{none:"none","gradient-to-t":"linear-gradient(to top, var(--tw-gradient-stops))","gradient-to-tr":"linear-gradient(to top right, var(--tw-gradient-stops))","gradient-to-r":"linear-gradient(to right, var(--tw-gradient-stops))","gradient-to-br":"linear-gradient(to bottom right, var(--tw-gradient-stops))","gradient-to-b":"linear-gradient(to bottom, var(--tw-gradient-stops))","gradient-to-bl":"linear-gradient(to bottom left, var(--tw-gradient-stops))","gradient-to-l":"linear-gradient(to left, var(--tw-gradient-stops))","gradient-to-tl":"linear-gradient(to top left, var(--tw-gradient-stops))"},backgroundOpacity:({theme:e})=>e("opacity"),backgroundPosition:{bottom:"bottom",center:"center",left:"left","left-bottom":"left bottom","left-top":"left top",right:"right","right-bottom":"right bottom","right-top":"right top",top:"top"},backgroundSize:{auto:"auto",cover:"cover",contain:"contain"},blur:{0:"0",none:"",sm:"4px",DEFAULT:"8px",md:"12px",lg:"16px",xl:"24px","2xl":"40px","3xl":"64px"},borderColor:({theme:e})=>({DEFAULT:"currentcolor",...e("colors")}),borderOpacity:({theme:e})=>e("opacity"),borderRadius:{none:"0px",sm:"0.125rem",DEFAULT:"0.25rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem","3xl":"1.5rem",full:"9999px"},borderSpacing:({theme:e})=>e("spacing"),borderWidth:{DEFAULT:"1px",0:"0px",2:"2px",4:"4px",8:"8px",...f},boxShadow:{sm:"0 1px 2px 0 rgb(0 0 0 / 0.05)",DEFAULT:"0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",md:"0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",lg:"0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",xl:"0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)","2xl":"0 25px 50px -12px rgb(0 0 0 / 0.25)",inner:"inset 0 2px 4px 0 rgb(0 0 0 / 0.05)",none:"none"},boxShadowColor:({theme:e})=>e("colors"),brightness:{0:"0",50:".5",75:".75",90:".9",95:".95",100:"1",105:"1.05",110:"1.1",125:"1.25",150:"1.5",200:"2",...l},caretColor:({theme:e})=>e("colors"),colors:()=>({...k}),columns:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12","3xs":"16rem","2xs":"18rem",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem",...g},container:{},content:{none:"none"},contrast:{0:"0",50:".5",75:".75",100:"1",125:"1.25",150:"1.5",200:"2",...l},cursor:{auto:"auto",default:"default",pointer:"pointer",wait:"wait",text:"text",move:"move",help:"help","not-allowed":"not-allowed",none:"none","context-menu":"context-menu",progress:"progress",cell:"cell",crosshair:"crosshair","vertical-text":"vertical-text",alias:"alias",copy:"copy","no-drop":"no-drop",grab:"grab",grabbing:"grabbing","all-scroll":"all-scroll","col-resize":"col-resize","row-resize":"row-resize","n-resize":"n-resize","e-resize":"e-resize","s-resize":"s-resize","w-resize":"w-resize","ne-resize":"ne-resize","nw-resize":"nw-resize","se-resize":"se-resize","sw-resize":"sw-resize","ew-resize":"ew-resize","ns-resize":"ns-resize","nesw-resize":"nesw-resize","nwse-resize":"nwse-resize","zoom-in":"zoom-in","zoom-out":"zoom-out"},divideColor:({theme:e})=>e("borderColor"),divideOpacity:({theme:e})=>e("borderOpacity"),divideWidth:({theme:e})=>({...e("borderWidth"),...f}),dropShadow:{sm:"0 1px 1px rgb(0 0 0 / 0.05)",DEFAULT:["0 1px 2px rgb(0 0 0 / 0.1)","0 1px 1px rgb(0 0 0 / 0.06)"],md:["0 4px 3px rgb(0 0 0 / 0.07)","0 2px 2px rgb(0 0 0 / 0.06)"],lg:["0 10px 8px rgb(0 0 0 / 0.04)","0 4px 3px rgb(0 0 0 / 0.1)"],xl:["0 20px 13px rgb(0 0 0 / 0.03)","0 8px 5px rgb(0 0 0 / 0.08)"],"2xl":"0 25px 25px rgb(0 0 0 / 0.15)",none:"0 0 #0000"},fill:({theme:e})=>e("colors"),flex:{1:"1 1 0%",auto:"1 1 auto",initial:"0 1 auto",none:"none"},flexBasis:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",...e("spacing")}),flexGrow:{0:"0",DEFAULT:"1",...g},flexShrink:{0:"0",DEFAULT:"1",...g},fontFamily:{sans:["ui-sans-serif","system-ui","sans-serif",'"Apple Color Emoji"','"Segoe UI Emoji"','"Segoe UI Symbol"','"Noto Color Emoji"'],serif:["ui-serif","Georgia","Cambria",'"Times New Roman"',"Times","serif"],mono:["ui-monospace","SFMono-Regular","Menlo","Monaco","Consolas",'"Liberation Mono"','"Courier New"',"monospace"]},fontSize:{xs:["0.75rem",{lineHeight:"1rem"}],sm:["0.875rem",{lineHeight:"1.25rem"}],base:["1rem",{lineHeight:"1.5rem"}],lg:["1.125rem",{lineHeight:"1.75rem"}],xl:["1.25rem",{lineHeight:"1.75rem"}],"2xl":["1.5rem",{lineHeight:"2rem"}],"3xl":["1.875rem",{lineHeight:"2.25rem"}],"4xl":["2.25rem",{lineHeight:"2.5rem"}],"5xl":["3rem",{lineHeight:"1"}],"6xl":["3.75rem",{lineHeight:"1"}],"7xl":["4.5rem",{lineHeight:"1"}],"8xl":["6rem",{lineHeight:"1"}],"9xl":["8rem",{lineHeight:"1"}]},fontWeight:{thin:"100",extralight:"200",light:"300",normal:"400",medium:"500",semibold:"600",bold:"700",extrabold:"800",black:"900"},gap:({theme:e})=>e("spacing"),gradientColorStops:({theme:e})=>e("colors"),gradientColorStopPositions:{"0%":"0%","5%":"5%","10%":"10%","15%":"15%","20%":"20%","25%":"25%","30%":"30%","35%":"35%","40%":"40%","45%":"45%","50%":"50%","55%":"55%","60%":"60%","65%":"65%","70%":"70%","75%":"75%","80%":"80%","85%":"85%","90%":"90%","95%":"95%","100%":"100%",...l},grayscale:{0:"0",DEFAULT:"100%",...l},gridAutoColumns:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0, 1fr)"},gridAutoRows:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0, 1fr)"},gridColumn:{auto:"auto","span-1":"span 1 / span 1","span-2":"span 2 / span 2","span-3":"span 3 / span 3","span-4":"span 4 / span 4","span-5":"span 5 / span 5","span-6":"span 6 / span 6","span-7":"span 7 / span 7","span-8":"span 8 / span 8","span-9":"span 9 / span 9","span-10":"span 10 / span 10","span-11":"span 11 / span 11","span-12":"span 12 / span 12","span-full":"1 / -1"},gridColumnEnd:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...g},gridColumnStart:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...g},gridRow:{auto:"auto","span-1":"span 1 / span 1","span-2":"span 2 / span 2","span-3":"span 3 / span 3","span-4":"span 4 / span 4","span-5":"span 5 / span 5","span-6":"span 6 / span 6","span-7":"span 7 / span 7","span-8":"span 8 / span 8","span-9":"span 9 / span 9","span-10":"span 10 / span 10","span-11":"span 11 / span 11","span-12":"span 12 / span 12","span-full":"1 / -1"},gridRowEnd:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...g},gridRowStart:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...g},gridTemplateColumns:{none:"none",subgrid:"subgrid",1:"repeat(1, minmax(0, 1fr))",2:"repeat(2, minmax(0, 1fr))",3:"repeat(3, minmax(0, 1fr))",4:"repeat(4, minmax(0, 1fr))",5:"repeat(5, minmax(0, 1fr))",6:"repeat(6, minmax(0, 1fr))",7:"repeat(7, minmax(0, 1fr))",8:"repeat(8, minmax(0, 1fr))",9:"repeat(9, minmax(0, 1fr))",10:"repeat(10, minmax(0, 1fr))",11:"repeat(11, minmax(0, 1fr))",12:"repeat(12, minmax(0, 1fr))",..._},gridTemplateRows:{none:"none",subgrid:"subgrid",1:"repeat(1, minmax(0, 1fr))",2:"repeat(2, minmax(0, 1fr))",3:"repeat(3, minmax(0, 1fr))",4:"repeat(4, minmax(0, 1fr))",5:"repeat(5, minmax(0, 1fr))",6:"repeat(6, minmax(0, 1fr))",7:"repeat(7, minmax(0, 1fr))",8:"repeat(8, minmax(0, 1fr))",9:"repeat(9, minmax(0, 1fr))",10:"repeat(10, minmax(0, 1fr))",11:"repeat(11, minmax(0, 1fr))",12:"repeat(12, minmax(0, 1fr))",..._},height:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%",full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),hueRotate:{0:"0deg",15:"15deg",30:"30deg",60:"60deg",90:"90deg",180:"180deg",...w},inset:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%",full:"100%",...e("spacing")}),invert:{0:"0",DEFAULT:"100%",...l},keyframes:{spin:{to:{transform:"rotate(360deg)"}},ping:{"75%, 100%":{transform:"scale(2)",opacity:"0"}},pulse:{"50%":{opacity:".5"}},bounce:{"0%, 100%":{transform:"translateY(-25%)",animationTimingFunction:"cubic-bezier(0.8,0,1,1)"},"50%":{transform:"none",animationTimingFunction:"cubic-bezier(0,0,0.2,1)"}}},letterSpacing:{tighter:"-0.05em",tight:"-0.025em",normal:"0em",wide:"0.025em",wider:"0.05em",widest:"0.1em"},lineHeight:{none:"1",tight:"1.25",snug:"1.375",normal:"1.5",relaxed:"1.625",loose:"2",3:".75rem",4:"1rem",5:"1.25rem",6:"1.5rem",7:"1.75rem",8:"2rem",9:"2.25rem",10:"2.5rem"},listStyleType:{none:"none",disc:"disc",decimal:"decimal"},listStyleImage:{none:"none"},margin:({theme:e})=>({auto:"auto",...e("spacing")}),lineClamp:{1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",...g},maxHeight:({theme:e})=>({none:"none",full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),maxWidth:({theme:e})=>({none:"none",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",prose:"65ch",...e("spacing")}),minHeight:({theme:e})=>({full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),minWidth:({theme:e})=>({full:"100%",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),objectPosition:{bottom:"bottom",center:"center",left:"left","left-bottom":"left bottom","left-top":"left top",right:"right","right-bottom":"right bottom","right-top":"right top",top:"top"},opacity:{0:"0",5:"0.05",10:"0.1",15:"0.15",20:"0.2",25:"0.25",30:"0.3",35:"0.35",40:"0.4",45:"0.45",50:"0.5",55:"0.55",60:"0.6",65:"0.65",70:"0.7",75:"0.75",80:"0.8",85:"0.85",90:"0.9",95:"0.95",100:"1",...l},order:{first:"-9999",last:"9999",none:"0",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",...g},outlineColor:({theme:e})=>e("colors"),outlineOffset:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...f},outlineWidth:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...f},padding:({theme:e})=>e("spacing"),placeholderColor:({theme:e})=>e("colors"),placeholderOpacity:({theme:e})=>e("opacity"),ringColor:({theme:e})=>({DEFAULT:"currentcolor",...e("colors")}),ringOffsetColor:({theme:e})=>e("colors"),ringOffsetWidth:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...f},ringOpacity:({theme:e})=>({DEFAULT:"0.5",...e("opacity")}),ringWidth:{DEFAULT:"3px",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...f},rotate:{0:"0deg",1:"1deg",2:"2deg",3:"3deg",6:"6deg",12:"12deg",45:"45deg",90:"90deg",180:"180deg",...w},saturate:{0:"0",50:".5",100:"1",150:"1.5",200:"2",...l},scale:{0:"0",50:".5",75:".75",90:".9",95:".95",100:"1",105:"1.05",110:"1.1",125:"1.25",150:"1.5",...l},screens:{sm:"40rem",md:"48rem",lg:"64rem",xl:"80rem","2xl":"96rem"},scrollMargin:({theme:e})=>e("spacing"),scrollPadding:({theme:e})=>e("spacing"),sepia:{0:"0",DEFAULT:"100%",...l},skew:{0:"0deg",1:"1deg",2:"2deg",3:"3deg",6:"6deg",12:"12deg",...w},space:({theme:e})=>e("spacing"),spacing:{px:"1px",0:"0px",.5:"0.125rem",1:"0.25rem",1.5:"0.375rem",2:"0.5rem",2.5:"0.625rem",3:"0.75rem",3.5:"0.875rem",4:"1rem",5:"1.25rem",6:"1.5rem",7:"1.75rem",8:"2rem",9:"2.25rem",10:"2.5rem",11:"2.75rem",12:"3rem",14:"3.5rem",16:"4rem",20:"5rem",24:"6rem",28:"7rem",32:"8rem",36:"9rem",40:"10rem",44:"11rem",48:"12rem",52:"13rem",56:"14rem",60:"15rem",64:"16rem",72:"18rem",80:"20rem",96:"24rem"},stroke:({theme:e})=>({none:"none",...e("colors")}),strokeWidth:{0:"0",1:"1",2:"2",...g},supports:{},data:{},textColor:({theme:e})=>e("colors"),textDecorationColor:({theme:e})=>e("colors"),textDecorationThickness:{auto:"auto","from-font":"from-font",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...f},textIndent:({theme:e})=>e("spacing"),textOpacity:({theme:e})=>e("opacity"),textUnderlineOffset:{auto:"auto",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...f},transformOrigin:{center:"center",top:"top","top-right":"top right",right:"right","bottom-right":"bottom right",bottom:"bottom","bottom-left":"bottom left",left:"left","top-left":"top left"},transitionDelay:{0:"0s",75:"75ms",100:"100ms",150:"150ms",200:"200ms",300:"300ms",500:"500ms",700:"700ms",1e3:"1000ms",...L},transitionDuration:{DEFAULT:"150ms",0:"0s",75:"75ms",100:"100ms",150:"150ms",200:"200ms",300:"300ms",500:"500ms",700:"700ms",1e3:"1000ms",...L},transitionProperty:{none:"none",all:"all",DEFAULT:"color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter",colors:"color, background-color, border-color, outline-color, text-decoration-color, fill, stroke",opacity:"opacity",shadow:"box-shadow",transform:"transform"},transitionTimingFunction:{DEFAULT:"cubic-bezier(0.4, 0, 0.2, 1)",linear:"linear",in:"cubic-bezier(0.4, 0, 1, 1)",out:"cubic-bezier(0, 0, 0.2, 1)","in-out":"cubic-bezier(0.4, 0, 0.2, 1)"},translate:({theme:e})=>({"1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%",full:"100%",...e("spacing")}),size:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),width:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",screen:"100vw",svw:"100svw",lvw:"100lvw",dvw:"100dvw",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),willChange:{auto:"auto",scroll:"scroll-position",contents:"contents",transform:"transform"},zIndex:{auto:"auto",0:"0",10:"10",20:"20",30:"30",40:"40",50:"50",...g}};export{ae as a,d as b,oe as c,ge as d,y as e,u as f,ue as g,de as h,xe as i,ye as j};
var l={inherit:"inherit",current:"currentcolor",transparent:"transparent",black:"#000",white:"#fff",slate:{50:"oklch(98.4% 0.003 247.858)",100:"oklch(96.8% 0.007 247.896)",200:"oklch(92.9% 0.013 255.508)",300:"oklch(86.9% 0.022 252.894)",400:"oklch(70.4% 0.04 256.788)",500:"oklch(55.4% 0.046 257.417)",600:"oklch(44.6% 0.043 257.281)",700:"oklch(37.2% 0.044 257.287)",800:"oklch(27.9% 0.041 260.031)",900:"oklch(20.8% 0.042 265.755)",950:"oklch(12.9% 0.042 264.695)"},gray:{50:"oklch(98.5% 0.002 247.839)",100:"oklch(96.7% 0.003 264.542)",200:"oklch(92.8% 0.006 264.531)",300:"oklch(87.2% 0.01 258.338)",400:"oklch(70.7% 0.022 261.325)",500:"oklch(55.1% 0.027 264.364)",600:"oklch(44.6% 0.03 256.802)",700:"oklch(37.3% 0.034 259.733)",800:"oklch(27.8% 0.033 256.848)",900:"oklch(21% 0.034 264.665)",950:"oklch(13% 0.028 261.692)"},zinc:{50:"oklch(98.5% 0 0)",100:"oklch(96.7% 0.001 286.375)",200:"oklch(92% 0.004 286.32)",300:"oklch(87.1% 0.006 286.286)",400:"oklch(70.5% 0.015 286.067)",500:"oklch(55.2% 0.016 285.938)",600:"oklch(44.2% 0.017 285.786)",700:"oklch(37% 0.013 285.805)",800:"oklch(27.4% 0.006 286.033)",900:"oklch(21% 0.006 285.885)",950:"oklch(14.1% 0.005 285.823)"},neutral:{50:"oklch(98.5% 0 0)",100:"oklch(97% 0 0)",200:"oklch(92.2% 0 0)",300:"oklch(87% 0 0)",400:"oklch(70.8% 0 0)",500:"oklch(55.6% 0 0)",600:"oklch(43.9% 0 0)",700:"oklch(37.1% 0 0)",800:"oklch(26.9% 0 0)",900:"oklch(20.5% 0 0)",950:"oklch(14.5% 0 0)"},stone:{50:"oklch(98.5% 0.001 106.423)",100:"oklch(97% 0.001 106.424)",200:"oklch(92.3% 0.003 48.717)",300:"oklch(86.9% 0.005 56.366)",400:"oklch(70.9% 0.01 56.259)",500:"oklch(55.3% 0.013 58.071)",600:"oklch(44.4% 0.011 73.639)",700:"oklch(37.4% 0.01 67.558)",800:"oklch(26.8% 0.007 34.298)",900:"oklch(21.6% 0.006 56.043)",950:"oklch(14.7% 0.004 49.25)"},mauve:{50:"oklch(98.5% 0 0)",100:"oklch(96% 0.003 325.6)",200:"oklch(92.2% 0.005 325.62)",300:"oklch(86.5% 0.012 325.68)",400:"oklch(71.1% 0.019 323.02)",500:"oklch(54.2% 0.034 322.5)",600:"oklch(43.5% 0.029 321.78)",700:"oklch(36.4% 0.029 323.89)",800:"oklch(26.3% 0.024 320.12)",900:"oklch(21.2% 0.019 322.12)",950:"oklch(14.5% 0.008 326)"},olive:{50:"oklch(98.8% 0.003 106.5)",100:"oklch(96.6% 0.005 106.5)",200:"oklch(93% 0.007 106.5)",300:"oklch(88% 0.011 106.6)",400:"oklch(73.7% 0.021 106.9)",500:"oklch(58% 0.031 107.3)",600:"oklch(46.6% 0.025 107.3)",700:"oklch(39.4% 0.023 107.4)",800:"oklch(28.6% 0.016 107.4)",900:"oklch(22.8% 0.013 107.4)",950:"oklch(15.3% 0.006 107.1)"},mist:{50:"oklch(98.7% 0.002 197.1)",100:"oklch(96.3% 0.002 197.1)",200:"oklch(92.5% 0.005 214.3)",300:"oklch(87.2% 0.007 219.6)",400:"oklch(72.3% 0.014 214.4)",500:"oklch(56% 0.021 213.5)",600:"oklch(45% 0.017 213.2)",700:"oklch(37.8% 0.015 216)",800:"oklch(27.5% 0.011 216.9)",900:"oklch(21.8% 0.008 223.9)",950:"oklch(14.8% 0.004 228.8)"},taupe:{50:"oklch(98.6% 0.002 67.8)",100:"oklch(96% 0.002 17.2)",200:"oklch(92.2% 0.005 34.3)",300:"oklch(86.8% 0.007 39.5)",400:"oklch(71.4% 0.014 41.2)",500:"oklch(54.7% 0.021 43.1)",600:"oklch(43.8% 0.017 39.3)",700:"oklch(36.7% 0.016 35.7)",800:"oklch(26.8% 0.011 36.5)",900:"oklch(21.4% 0.009 43.1)",950:"oklch(14.7% 0.004 49.3)"},red:{50:"oklch(97.1% 0.013 17.38)",100:"oklch(93.6% 0.032 17.717)",200:"oklch(88.5% 0.062 18.334)",300:"oklch(80.8% 0.114 19.571)",400:"oklch(70.4% 0.191 22.216)",500:"oklch(63.7% 0.237 25.331)",600:"oklch(57.7% 0.245 27.325)",700:"oklch(50.5% 0.213 27.518)",800:"oklch(44.4% 0.177 26.899)",900:"oklch(39.6% 0.141 25.723)",950:"oklch(25.8% 0.092 26.042)"},orange:{50:"oklch(98% 0.016 73.684)",100:"oklch(95.4% 0.038 75.164)",200:"oklch(90.1% 0.076 70.697)",300:"oklch(83.7% 0.128 66.29)",400:"oklch(75% 0.183 55.934)",500:"oklch(70.5% 0.213 47.604)",600:"oklch(64.6% 0.222 41.116)",700:"oklch(55.3% 0.195 38.402)",800:"oklch(47% 0.157 37.304)",900:"oklch(40.8% 0.123 38.172)",950:"oklch(26.6% 0.079 36.259)"},amber:{50:"oklch(98.7% 0.022 95.277)",100:"oklch(96.2% 0.059 95.617)",200:"oklch(92.4% 0.12 95.746)",300:"oklch(87.9% 0.169 91.605)",400:"oklch(82.8% 0.189 84.429)",500:"oklch(76.9% 0.188 70.08)",600:"oklch(66.6% 0.179 58.318)",700:"oklch(55.5% 0.163 48.998)",800:"oklch(47.3% 0.137 46.201)",900:"oklch(41.4% 0.112 45.904)",950:"oklch(27.9% 0.077 45.635)"},yellow:{50:"oklch(98.7% 0.026 102.212)",100:"oklch(97.3% 0.071 103.193)",200:"oklch(94.5% 0.129 101.54)",300:"oklch(90.5% 0.182 98.111)",400:"oklch(85.2% 0.199 91.936)",500:"oklch(79.5% 0.184 86.047)",600:"oklch(68.1% 0.162 75.834)",700:"oklch(55.4% 0.135 66.442)",800:"oklch(47.6% 0.114 61.907)",900:"oklch(42.1% 0.095 57.708)",950:"oklch(28.6% 0.066 53.813)"},lime:{50:"oklch(98.6% 0.031 120.757)",100:"oklch(96.7% 0.067 122.328)",200:"oklch(93.8% 0.127 124.321)",300:"oklch(89.7% 0.196 126.665)",400:"oklch(84.1% 0.238 128.85)",500:"oklch(76.8% 0.233 130.85)",600:"oklch(64.8% 0.2 131.684)",700:"oklch(53.2% 0.157 131.589)",800:"oklch(45.3% 0.124 130.933)",900:"oklch(40.5% 0.101 131.063)",950:"oklch(27.4% 0.072 132.109)"},green:{50:"oklch(98.2% 0.018 155.826)",100:"oklch(96.2% 0.044 156.743)",200:"oklch(92.5% 0.084 155.995)",300:"oklch(87.1% 0.15 154.449)",400:"oklch(79.2% 0.209 151.711)",500:"oklch(72.3% 0.219 149.579)",600:"oklch(62.7% 0.194 149.214)",700:"oklch(52.7% 0.154 150.069)",800:"oklch(44.8% 0.119 151.328)",900:"oklch(39.3% 0.095 152.535)",950:"oklch(26.6% 0.065 152.934)"},emerald:{50:"oklch(97.9% 0.021 166.113)",100:"oklch(95% 0.052 163.051)",200:"oklch(90.5% 0.093 164.15)",300:"oklch(84.5% 0.143 164.978)",400:"oklch(76.5% 0.177 163.223)",500:"oklch(69.6% 0.17 162.48)",600:"oklch(59.6% 0.145 163.225)",700:"oklch(50.8% 0.118 165.612)",800:"oklch(43.2% 0.095 166.913)",900:"oklch(37.8% 0.077 168.94)",950:"oklch(26.2% 0.051 172.552)"},teal:{50:"oklch(98.4% 0.014 180.72)",100:"oklch(95.3% 0.051 180.801)",200:"oklch(91% 0.096 180.426)",300:"oklch(85.5% 0.138 181.071)",400:"oklch(77.7% 0.152 181.912)",500:"oklch(70.4% 0.14 182.503)",600:"oklch(60% 0.118 184.704)",700:"oklch(51.1% 0.096 186.391)",800:"oklch(43.7% 0.078 188.216)",900:"oklch(38.6% 0.063 188.416)",950:"oklch(27.7% 0.046 192.524)"},cyan:{50:"oklch(98.4% 0.019 200.873)",100:"oklch(95.6% 0.045 203.388)",200:"oklch(91.7% 0.08 205.041)",300:"oklch(86.5% 0.127 207.078)",400:"oklch(78.9% 0.154 211.53)",500:"oklch(71.5% 0.143 215.221)",600:"oklch(60.9% 0.126 221.723)",700:"oklch(52% 0.105 223.128)",800:"oklch(45% 0.085 224.283)",900:"oklch(39.8% 0.07 227.392)",950:"oklch(30.2% 0.056 229.695)"},sky:{50:"oklch(97.7% 0.013 236.62)",100:"oklch(95.1% 0.026 236.824)",200:"oklch(90.1% 0.058 230.902)",300:"oklch(82.8% 0.111 230.318)",400:"oklch(74.6% 0.16 232.661)",500:"oklch(68.5% 0.169 237.323)",600:"oklch(58.8% 0.158 241.966)",700:"oklch(50% 0.134 242.749)",800:"oklch(44.3% 0.11 240.79)",900:"oklch(39.1% 0.09 240.876)",950:"oklch(29.3% 0.066 243.157)"},blue:{50:"oklch(97% 0.014 254.604)",100:"oklch(93.2% 0.032 255.585)",200:"oklch(88.2% 0.059 254.128)",300:"oklch(80.9% 0.105 251.813)",400:"oklch(70.7% 0.165 254.624)",500:"oklch(62.3% 0.214 259.815)",600:"oklch(54.6% 0.245 262.881)",700:"oklch(48.8% 0.243 264.376)",800:"oklch(42.4% 0.199 265.638)",900:"oklch(37.9% 0.146 265.522)",950:"oklch(28.2% 0.091 267.935)"},indigo:{50:"oklch(96.2% 0.018 272.314)",100:"oklch(93% 0.034 272.788)",200:"oklch(87% 0.065 274.039)",300:"oklch(78.5% 0.115 274.713)",400:"oklch(67.3% 0.182 276.935)",500:"oklch(58.5% 0.233 277.117)",600:"oklch(51.1% 0.262 276.966)",700:"oklch(45.7% 0.24 277.023)",800:"oklch(39.8% 0.195 277.366)",900:"oklch(35.9% 0.144 278.697)",950:"oklch(25.7% 0.09 281.288)"},violet:{50:"oklch(96.9% 0.016 293.756)",100:"oklch(94.3% 0.029 294.588)",200:"oklch(89.4% 0.057 293.283)",300:"oklch(81.1% 0.111 293.571)",400:"oklch(70.2% 0.183 293.541)",500:"oklch(60.6% 0.25 292.717)",600:"oklch(54.1% 0.281 293.009)",700:"oklch(49.1% 0.27 292.581)",800:"oklch(43.2% 0.232 292.759)",900:"oklch(38% 0.189 293.745)",950:"oklch(28.3% 0.141 291.089)"},purple:{50:"oklch(97.7% 0.014 308.299)",100:"oklch(94.6% 0.033 307.174)",200:"oklch(90.2% 0.063 306.703)",300:"oklch(82.7% 0.119 306.383)",400:"oklch(71.4% 0.203 305.504)",500:"oklch(62.7% 0.265 303.9)",600:"oklch(55.8% 0.288 302.321)",700:"oklch(49.6% 0.265 301.924)",800:"oklch(43.8% 0.218 303.724)",900:"oklch(38.1% 0.176 304.987)",950:"oklch(29.1% 0.149 302.717)"},fuchsia:{50:"oklch(97.7% 0.017 320.058)",100:"oklch(95.2% 0.037 318.852)",200:"oklch(90.3% 0.076 319.62)",300:"oklch(83.3% 0.145 321.434)",400:"oklch(74% 0.238 322.16)",500:"oklch(66.7% 0.295 322.15)",600:"oklch(59.1% 0.293 322.896)",700:"oklch(51.8% 0.253 323.949)",800:"oklch(45.2% 0.211 324.591)",900:"oklch(40.1% 0.17 325.612)",950:"oklch(29.3% 0.136 325.661)"},pink:{50:"oklch(97.1% 0.014 343.198)",100:"oklch(94.8% 0.028 342.258)",200:"oklch(89.9% 0.061 343.231)",300:"oklch(82.3% 0.12 346.018)",400:"oklch(71.8% 0.202 349.761)",500:"oklch(65.6% 0.241 354.308)",600:"oklch(59.2% 0.249 0.584)",700:"oklch(52.5% 0.223 3.958)",800:"oklch(45.9% 0.187 3.815)",900:"oklch(40.8% 0.153 2.432)",950:"oklch(28.4% 0.109 3.907)"},rose:{50:"oklch(96.9% 0.015 12.422)",100:"oklch(94.1% 0.03 12.58)",200:"oklch(89.2% 0.058 10.001)",300:"oklch(81% 0.117 11.638)",400:"oklch(71.2% 0.194 13.428)",500:"oklch(64.5% 0.246 16.439)",600:"oklch(58.6% 0.253 17.585)",700:"oklch(51.4% 0.222 16.935)",800:"oklch(45.5% 0.188 13.697)",900:"oklch(41% 0.159 10.272)",950:"oklch(27.1% 0.105 12.094)"}};export{l as a};
declare const _default: {
inherit: string;
current: string;
transparent: string;
black: string;
white: string;
slate: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
gray: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
zinc: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
neutral: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
stone: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
mauve: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
olive: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
mist: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
taupe: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
red: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
orange: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
amber: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
yellow: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
lime: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
green: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
emerald: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
teal: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
cyan: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
sky: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
blue: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
indigo: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
violet: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
purple: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
fuchsia: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
pink: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
rose: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
};
export { _default as _ };
declare const _default: {
inherit: string;
current: string;
transparent: string;
black: string;
white: string;
slate: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
gray: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
zinc: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
neutral: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
stone: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
mauve: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
olive: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
mist: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
taupe: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
red: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
orange: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
amber: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
yellow: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
lime: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
green: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
emerald: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
teal: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
cyan: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
sky: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
blue: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
indigo: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
violet: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
purple: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
fuchsia: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
pink: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
rose: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
};
export { _default as default };
import { _ as _default } from './colors-C__qRT83.js';
export { _default as default };
"use strict";var l={inherit:"inherit",current:"currentcolor",transparent:"transparent",black:"#000",white:"#fff",slate:{50:"oklch(98.4% 0.003 247.858)",100:"oklch(96.8% 0.007 247.896)",200:"oklch(92.9% 0.013 255.508)",300:"oklch(86.9% 0.022 252.894)",400:"oklch(70.4% 0.04 256.788)",500:"oklch(55.4% 0.046 257.417)",600:"oklch(44.6% 0.043 257.281)",700:"oklch(37.2% 0.044 257.287)",800:"oklch(27.9% 0.041 260.031)",900:"oklch(20.8% 0.042 265.755)",950:"oklch(12.9% 0.042 264.695)"},gray:{50:"oklch(98.5% 0.002 247.839)",100:"oklch(96.7% 0.003 264.542)",200:"oklch(92.8% 0.006 264.531)",300:"oklch(87.2% 0.01 258.338)",400:"oklch(70.7% 0.022 261.325)",500:"oklch(55.1% 0.027 264.364)",600:"oklch(44.6% 0.03 256.802)",700:"oklch(37.3% 0.034 259.733)",800:"oklch(27.8% 0.033 256.848)",900:"oklch(21% 0.034 264.665)",950:"oklch(13% 0.028 261.692)"},zinc:{50:"oklch(98.5% 0 0)",100:"oklch(96.7% 0.001 286.375)",200:"oklch(92% 0.004 286.32)",300:"oklch(87.1% 0.006 286.286)",400:"oklch(70.5% 0.015 286.067)",500:"oklch(55.2% 0.016 285.938)",600:"oklch(44.2% 0.017 285.786)",700:"oklch(37% 0.013 285.805)",800:"oklch(27.4% 0.006 286.033)",900:"oklch(21% 0.006 285.885)",950:"oklch(14.1% 0.005 285.823)"},neutral:{50:"oklch(98.5% 0 0)",100:"oklch(97% 0 0)",200:"oklch(92.2% 0 0)",300:"oklch(87% 0 0)",400:"oklch(70.8% 0 0)",500:"oklch(55.6% 0 0)",600:"oklch(43.9% 0 0)",700:"oklch(37.1% 0 0)",800:"oklch(26.9% 0 0)",900:"oklch(20.5% 0 0)",950:"oklch(14.5% 0 0)"},stone:{50:"oklch(98.5% 0.001 106.423)",100:"oklch(97% 0.001 106.424)",200:"oklch(92.3% 0.003 48.717)",300:"oklch(86.9% 0.005 56.366)",400:"oklch(70.9% 0.01 56.259)",500:"oklch(55.3% 0.013 58.071)",600:"oklch(44.4% 0.011 73.639)",700:"oklch(37.4% 0.01 67.558)",800:"oklch(26.8% 0.007 34.298)",900:"oklch(21.6% 0.006 56.043)",950:"oklch(14.7% 0.004 49.25)"},mauve:{50:"oklch(98.5% 0 0)",100:"oklch(96% 0.003 325.6)",200:"oklch(92.2% 0.005 325.62)",300:"oklch(86.5% 0.012 325.68)",400:"oklch(71.1% 0.019 323.02)",500:"oklch(54.2% 0.034 322.5)",600:"oklch(43.5% 0.029 321.78)",700:"oklch(36.4% 0.029 323.89)",800:"oklch(26.3% 0.024 320.12)",900:"oklch(21.2% 0.019 322.12)",950:"oklch(14.5% 0.008 326)"},olive:{50:"oklch(98.8% 0.003 106.5)",100:"oklch(96.6% 0.005 106.5)",200:"oklch(93% 0.007 106.5)",300:"oklch(88% 0.011 106.6)",400:"oklch(73.7% 0.021 106.9)",500:"oklch(58% 0.031 107.3)",600:"oklch(46.6% 0.025 107.3)",700:"oklch(39.4% 0.023 107.4)",800:"oklch(28.6% 0.016 107.4)",900:"oklch(22.8% 0.013 107.4)",950:"oklch(15.3% 0.006 107.1)"},mist:{50:"oklch(98.7% 0.002 197.1)",100:"oklch(96.3% 0.002 197.1)",200:"oklch(92.5% 0.005 214.3)",300:"oklch(87.2% 0.007 219.6)",400:"oklch(72.3% 0.014 214.4)",500:"oklch(56% 0.021 213.5)",600:"oklch(45% 0.017 213.2)",700:"oklch(37.8% 0.015 216)",800:"oklch(27.5% 0.011 216.9)",900:"oklch(21.8% 0.008 223.9)",950:"oklch(14.8% 0.004 228.8)"},taupe:{50:"oklch(98.6% 0.002 67.8)",100:"oklch(96% 0.002 17.2)",200:"oklch(92.2% 0.005 34.3)",300:"oklch(86.8% 0.007 39.5)",400:"oklch(71.4% 0.014 41.2)",500:"oklch(54.7% 0.021 43.1)",600:"oklch(43.8% 0.017 39.3)",700:"oklch(36.7% 0.016 35.7)",800:"oklch(26.8% 0.011 36.5)",900:"oklch(21.4% 0.009 43.1)",950:"oklch(14.7% 0.004 49.3)"},red:{50:"oklch(97.1% 0.013 17.38)",100:"oklch(93.6% 0.032 17.717)",200:"oklch(88.5% 0.062 18.334)",300:"oklch(80.8% 0.114 19.571)",400:"oklch(70.4% 0.191 22.216)",500:"oklch(63.7% 0.237 25.331)",600:"oklch(57.7% 0.245 27.325)",700:"oklch(50.5% 0.213 27.518)",800:"oklch(44.4% 0.177 26.899)",900:"oklch(39.6% 0.141 25.723)",950:"oklch(25.8% 0.092 26.042)"},orange:{50:"oklch(98% 0.016 73.684)",100:"oklch(95.4% 0.038 75.164)",200:"oklch(90.1% 0.076 70.697)",300:"oklch(83.7% 0.128 66.29)",400:"oklch(75% 0.183 55.934)",500:"oklch(70.5% 0.213 47.604)",600:"oklch(64.6% 0.222 41.116)",700:"oklch(55.3% 0.195 38.402)",800:"oklch(47% 0.157 37.304)",900:"oklch(40.8% 0.123 38.172)",950:"oklch(26.6% 0.079 36.259)"},amber:{50:"oklch(98.7% 0.022 95.277)",100:"oklch(96.2% 0.059 95.617)",200:"oklch(92.4% 0.12 95.746)",300:"oklch(87.9% 0.169 91.605)",400:"oklch(82.8% 0.189 84.429)",500:"oklch(76.9% 0.188 70.08)",600:"oklch(66.6% 0.179 58.318)",700:"oklch(55.5% 0.163 48.998)",800:"oklch(47.3% 0.137 46.201)",900:"oklch(41.4% 0.112 45.904)",950:"oklch(27.9% 0.077 45.635)"},yellow:{50:"oklch(98.7% 0.026 102.212)",100:"oklch(97.3% 0.071 103.193)",200:"oklch(94.5% 0.129 101.54)",300:"oklch(90.5% 0.182 98.111)",400:"oklch(85.2% 0.199 91.936)",500:"oklch(79.5% 0.184 86.047)",600:"oklch(68.1% 0.162 75.834)",700:"oklch(55.4% 0.135 66.442)",800:"oklch(47.6% 0.114 61.907)",900:"oklch(42.1% 0.095 57.708)",950:"oklch(28.6% 0.066 53.813)"},lime:{50:"oklch(98.6% 0.031 120.757)",100:"oklch(96.7% 0.067 122.328)",200:"oklch(93.8% 0.127 124.321)",300:"oklch(89.7% 0.196 126.665)",400:"oklch(84.1% 0.238 128.85)",500:"oklch(76.8% 0.233 130.85)",600:"oklch(64.8% 0.2 131.684)",700:"oklch(53.2% 0.157 131.589)",800:"oklch(45.3% 0.124 130.933)",900:"oklch(40.5% 0.101 131.063)",950:"oklch(27.4% 0.072 132.109)"},green:{50:"oklch(98.2% 0.018 155.826)",100:"oklch(96.2% 0.044 156.743)",200:"oklch(92.5% 0.084 155.995)",300:"oklch(87.1% 0.15 154.449)",400:"oklch(79.2% 0.209 151.711)",500:"oklch(72.3% 0.219 149.579)",600:"oklch(62.7% 0.194 149.214)",700:"oklch(52.7% 0.154 150.069)",800:"oklch(44.8% 0.119 151.328)",900:"oklch(39.3% 0.095 152.535)",950:"oklch(26.6% 0.065 152.934)"},emerald:{50:"oklch(97.9% 0.021 166.113)",100:"oklch(95% 0.052 163.051)",200:"oklch(90.5% 0.093 164.15)",300:"oklch(84.5% 0.143 164.978)",400:"oklch(76.5% 0.177 163.223)",500:"oklch(69.6% 0.17 162.48)",600:"oklch(59.6% 0.145 163.225)",700:"oklch(50.8% 0.118 165.612)",800:"oklch(43.2% 0.095 166.913)",900:"oklch(37.8% 0.077 168.94)",950:"oklch(26.2% 0.051 172.552)"},teal:{50:"oklch(98.4% 0.014 180.72)",100:"oklch(95.3% 0.051 180.801)",200:"oklch(91% 0.096 180.426)",300:"oklch(85.5% 0.138 181.071)",400:"oklch(77.7% 0.152 181.912)",500:"oklch(70.4% 0.14 182.503)",600:"oklch(60% 0.118 184.704)",700:"oklch(51.1% 0.096 186.391)",800:"oklch(43.7% 0.078 188.216)",900:"oklch(38.6% 0.063 188.416)",950:"oklch(27.7% 0.046 192.524)"},cyan:{50:"oklch(98.4% 0.019 200.873)",100:"oklch(95.6% 0.045 203.388)",200:"oklch(91.7% 0.08 205.041)",300:"oklch(86.5% 0.127 207.078)",400:"oklch(78.9% 0.154 211.53)",500:"oklch(71.5% 0.143 215.221)",600:"oklch(60.9% 0.126 221.723)",700:"oklch(52% 0.105 223.128)",800:"oklch(45% 0.085 224.283)",900:"oklch(39.8% 0.07 227.392)",950:"oklch(30.2% 0.056 229.695)"},sky:{50:"oklch(97.7% 0.013 236.62)",100:"oklch(95.1% 0.026 236.824)",200:"oklch(90.1% 0.058 230.902)",300:"oklch(82.8% 0.111 230.318)",400:"oklch(74.6% 0.16 232.661)",500:"oklch(68.5% 0.169 237.323)",600:"oklch(58.8% 0.158 241.966)",700:"oklch(50% 0.134 242.749)",800:"oklch(44.3% 0.11 240.79)",900:"oklch(39.1% 0.09 240.876)",950:"oklch(29.3% 0.066 243.157)"},blue:{50:"oklch(97% 0.014 254.604)",100:"oklch(93.2% 0.032 255.585)",200:"oklch(88.2% 0.059 254.128)",300:"oklch(80.9% 0.105 251.813)",400:"oklch(70.7% 0.165 254.624)",500:"oklch(62.3% 0.214 259.815)",600:"oklch(54.6% 0.245 262.881)",700:"oklch(48.8% 0.243 264.376)",800:"oklch(42.4% 0.199 265.638)",900:"oklch(37.9% 0.146 265.522)",950:"oklch(28.2% 0.091 267.935)"},indigo:{50:"oklch(96.2% 0.018 272.314)",100:"oklch(93% 0.034 272.788)",200:"oklch(87% 0.065 274.039)",300:"oklch(78.5% 0.115 274.713)",400:"oklch(67.3% 0.182 276.935)",500:"oklch(58.5% 0.233 277.117)",600:"oklch(51.1% 0.262 276.966)",700:"oklch(45.7% 0.24 277.023)",800:"oklch(39.8% 0.195 277.366)",900:"oklch(35.9% 0.144 278.697)",950:"oklch(25.7% 0.09 281.288)"},violet:{50:"oklch(96.9% 0.016 293.756)",100:"oklch(94.3% 0.029 294.588)",200:"oklch(89.4% 0.057 293.283)",300:"oklch(81.1% 0.111 293.571)",400:"oklch(70.2% 0.183 293.541)",500:"oklch(60.6% 0.25 292.717)",600:"oklch(54.1% 0.281 293.009)",700:"oklch(49.1% 0.27 292.581)",800:"oklch(43.2% 0.232 292.759)",900:"oklch(38% 0.189 293.745)",950:"oklch(28.3% 0.141 291.089)"},purple:{50:"oklch(97.7% 0.014 308.299)",100:"oklch(94.6% 0.033 307.174)",200:"oklch(90.2% 0.063 306.703)",300:"oklch(82.7% 0.119 306.383)",400:"oklch(71.4% 0.203 305.504)",500:"oklch(62.7% 0.265 303.9)",600:"oklch(55.8% 0.288 302.321)",700:"oklch(49.6% 0.265 301.924)",800:"oklch(43.8% 0.218 303.724)",900:"oklch(38.1% 0.176 304.987)",950:"oklch(29.1% 0.149 302.717)"},fuchsia:{50:"oklch(97.7% 0.017 320.058)",100:"oklch(95.2% 0.037 318.852)",200:"oklch(90.3% 0.076 319.62)",300:"oklch(83.3% 0.145 321.434)",400:"oklch(74% 0.238 322.16)",500:"oklch(66.7% 0.295 322.15)",600:"oklch(59.1% 0.293 322.896)",700:"oklch(51.8% 0.253 323.949)",800:"oklch(45.2% 0.211 324.591)",900:"oklch(40.1% 0.17 325.612)",950:"oklch(29.3% 0.136 325.661)"},pink:{50:"oklch(97.1% 0.014 343.198)",100:"oklch(94.8% 0.028 342.258)",200:"oklch(89.9% 0.061 343.231)",300:"oklch(82.3% 0.12 346.018)",400:"oklch(71.8% 0.202 349.761)",500:"oklch(65.6% 0.241 354.308)",600:"oklch(59.2% 0.249 0.584)",700:"oklch(52.5% 0.223 3.958)",800:"oklch(45.9% 0.187 3.815)",900:"oklch(40.8% 0.153 2.432)",950:"oklch(28.4% 0.109 3.907)"},rose:{50:"oklch(96.9% 0.015 12.422)",100:"oklch(94.1% 0.03 12.58)",200:"oklch(89.2% 0.058 10.001)",300:"oklch(81% 0.117 11.638)",400:"oklch(71.2% 0.194 13.428)",500:"oklch(64.5% 0.246 16.439)",600:"oklch(58.6% 0.253 17.585)",700:"oklch(51.4% 0.222 16.935)",800:"oklch(45.5% 0.188 13.697)",900:"oklch(41% 0.159 10.272)",950:"oklch(27.1% 0.105 12.094)"}};module.exports=l;
import{a}from"./chunk-X4GG3EDV.mjs";export{a as default};
import { P as PluginUtils, N as NamedUtilityValue } from './resolve-config-QUZ9b-Gn.mjs';
import './colors.mjs';
declare const _default: {
accentColor: ({ theme }: PluginUtils) => any;
animation: {
none: string;
spin: string;
ping: string;
pulse: string;
bounce: string;
};
aria: {
busy: string;
checked: string;
disabled: string;
expanded: string;
hidden: string;
pressed: string;
readonly: string;
required: string;
selected: string;
};
aspectRatio: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
square: string;
video: string;
};
backdropBlur: ({ theme }: PluginUtils) => any;
backdropBrightness: ({ theme }: PluginUtils) => any;
backdropContrast: ({ theme }: PluginUtils) => any;
backdropGrayscale: ({ theme }: PluginUtils) => any;
backdropHueRotate: ({ theme }: PluginUtils) => any;
backdropInvert: ({ theme }: PluginUtils) => any;
backdropOpacity: ({ theme }: PluginUtils) => any;
backdropSaturate: ({ theme }: PluginUtils) => any;
backdropSepia: ({ theme }: PluginUtils) => any;
backgroundColor: ({ theme }: PluginUtils) => any;
backgroundImage: {
none: string;
'gradient-to-t': string;
'gradient-to-tr': string;
'gradient-to-r': string;
'gradient-to-br': string;
'gradient-to-b': string;
'gradient-to-bl': string;
'gradient-to-l': string;
'gradient-to-tl': string;
};
backgroundOpacity: ({ theme }: PluginUtils) => any;
backgroundPosition: {
bottom: string;
center: string;
left: string;
'left-bottom': string;
'left-top': string;
right: string;
'right-bottom': string;
'right-top': string;
top: string;
};
backgroundSize: {
auto: string;
cover: string;
contain: string;
};
blur: {
0: string;
none: string;
sm: string;
DEFAULT: string;
md: string;
lg: string;
xl: string;
'2xl': string;
'3xl': string;
};
borderColor: ({ theme }: PluginUtils) => any;
borderOpacity: ({ theme }: PluginUtils) => any;
borderRadius: {
none: string;
sm: string;
DEFAULT: string;
md: string;
lg: string;
xl: string;
'2xl': string;
'3xl': string;
full: string;
};
borderSpacing: ({ theme }: PluginUtils) => any;
borderWidth: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
DEFAULT: string;
0: string;
2: string;
4: string;
8: string;
};
boxShadow: {
sm: string;
DEFAULT: string;
md: string;
lg: string;
xl: string;
'2xl': string;
inner: string;
none: string;
};
boxShadowColor: ({ theme }: PluginUtils) => any;
brightness: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
50: string;
75: string;
90: string;
95: string;
100: string;
105: string;
110: string;
125: string;
150: string;
200: string;
};
caretColor: ({ theme }: PluginUtils) => any;
colors: () => {
inherit: string;
current: string;
transparent: string;
black: string;
white: string;
slate: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
gray: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
zinc: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
neutral: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
stone: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
mauve: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
olive: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
mist: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
taupe: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
red: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
orange: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
amber: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
yellow: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
lime: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
green: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
emerald: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
teal: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
cyan: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
sky: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
blue: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
indigo: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
violet: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
purple: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
fuchsia: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
pink: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
rose: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
};
columns: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
'3xs': string;
'2xs': string;
xs: string;
sm: string;
md: string;
lg: string;
xl: string;
'2xl': string;
'3xl': string;
'4xl': string;
'5xl': string;
'6xl': string;
'7xl': string;
};
container: {};
content: {
none: string;
};
contrast: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
50: string;
75: string;
100: string;
125: string;
150: string;
200: string;
};
cursor: {
auto: string;
default: string;
pointer: string;
wait: string;
text: string;
move: string;
help: string;
'not-allowed': string;
none: string;
'context-menu': string;
progress: string;
cell: string;
crosshair: string;
'vertical-text': string;
alias: string;
copy: string;
'no-drop': string;
grab: string;
grabbing: string;
'all-scroll': string;
'col-resize': string;
'row-resize': string;
'n-resize': string;
'e-resize': string;
's-resize': string;
'w-resize': string;
'ne-resize': string;
'nw-resize': string;
'se-resize': string;
'sw-resize': string;
'ew-resize': string;
'ns-resize': string;
'nesw-resize': string;
'nwse-resize': string;
'zoom-in': string;
'zoom-out': string;
};
divideColor: ({ theme }: PluginUtils) => any;
divideOpacity: ({ theme }: PluginUtils) => any;
divideWidth: ({ theme }: PluginUtils) => any;
dropShadow: {
sm: string;
DEFAULT: string[];
md: string[];
lg: string[];
xl: string[];
'2xl': string;
none: string;
};
fill: ({ theme }: PluginUtils) => any;
flex: {
1: string;
auto: string;
initial: string;
none: string;
};
flexBasis: ({ theme }: PluginUtils) => any;
flexGrow: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
DEFAULT: string;
};
flexShrink: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
DEFAULT: string;
};
fontFamily: {
sans: string[];
serif: string[];
mono: string[];
};
fontSize: {
xs: (string | {
lineHeight: string;
})[];
sm: (string | {
lineHeight: string;
})[];
base: (string | {
lineHeight: string;
})[];
lg: (string | {
lineHeight: string;
})[];
xl: (string | {
lineHeight: string;
})[];
'2xl': (string | {
lineHeight: string;
})[];
'3xl': (string | {
lineHeight: string;
})[];
'4xl': (string | {
lineHeight: string;
})[];
'5xl': (string | {
lineHeight: string;
})[];
'6xl': (string | {
lineHeight: string;
})[];
'7xl': (string | {
lineHeight: string;
})[];
'8xl': (string | {
lineHeight: string;
})[];
'9xl': (string | {
lineHeight: string;
})[];
};
fontWeight: {
thin: string;
extralight: string;
light: string;
normal: string;
medium: string;
semibold: string;
bold: string;
extrabold: string;
black: string;
};
gap: ({ theme }: PluginUtils) => any;
gradientColorStops: ({ theme }: PluginUtils) => any;
gradientColorStopPositions: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
'0%': string;
'5%': string;
'10%': string;
'15%': string;
'20%': string;
'25%': string;
'30%': string;
'35%': string;
'40%': string;
'45%': string;
'50%': string;
'55%': string;
'60%': string;
'65%': string;
'70%': string;
'75%': string;
'80%': string;
'85%': string;
'90%': string;
'95%': string;
'100%': string;
};
grayscale: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
DEFAULT: string;
};
gridAutoColumns: {
auto: string;
min: string;
max: string;
fr: string;
};
gridAutoRows: {
auto: string;
min: string;
max: string;
fr: string;
};
gridColumn: {
auto: string;
'span-1': string;
'span-2': string;
'span-3': string;
'span-4': string;
'span-5': string;
'span-6': string;
'span-7': string;
'span-8': string;
'span-9': string;
'span-10': string;
'span-11': string;
'span-12': string;
'span-full': string;
};
gridColumnEnd: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
13: string;
};
gridColumnStart: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
13: string;
};
gridRow: {
auto: string;
'span-1': string;
'span-2': string;
'span-3': string;
'span-4': string;
'span-5': string;
'span-6': string;
'span-7': string;
'span-8': string;
'span-9': string;
'span-10': string;
'span-11': string;
'span-12': string;
'span-full': string;
};
gridRowEnd: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
13: string;
};
gridRowStart: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
13: string;
};
gridTemplateColumns: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
none: string;
subgrid: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
};
gridTemplateRows: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
none: string;
subgrid: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
};
height: ({ theme }: PluginUtils) => any;
hueRotate: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
15: string;
30: string;
60: string;
90: string;
180: string;
};
inset: ({ theme }: PluginUtils) => any;
invert: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
DEFAULT: string;
};
keyframes: {
spin: {
to: {
transform: string;
};
};
ping: {
'75%, 100%': {
transform: string;
opacity: string;
};
};
pulse: {
'50%': {
opacity: string;
};
};
bounce: {
'0%, 100%': {
transform: string;
animationTimingFunction: string;
};
'50%': {
transform: string;
animationTimingFunction: string;
};
};
};
letterSpacing: {
tighter: string;
tight: string;
normal: string;
wide: string;
wider: string;
widest: string;
};
lineHeight: {
none: string;
tight: string;
snug: string;
normal: string;
relaxed: string;
loose: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
};
listStyleType: {
none: string;
disc: string;
decimal: string;
};
listStyleImage: {
none: string;
};
margin: ({ theme }: PluginUtils) => any;
lineClamp: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
};
maxHeight: ({ theme }: PluginUtils) => any;
maxWidth: ({ theme }: PluginUtils) => any;
minHeight: ({ theme }: PluginUtils) => any;
minWidth: ({ theme }: PluginUtils) => any;
objectPosition: {
bottom: string;
center: string;
left: string;
'left-bottom': string;
'left-top': string;
right: string;
'right-bottom': string;
'right-top': string;
top: string;
};
opacity: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
5: string;
10: string;
15: string;
20: string;
25: string;
30: string;
35: string;
40: string;
45: string;
50: string;
55: string;
60: string;
65: string;
70: string;
75: string;
80: string;
85: string;
90: string;
95: string;
100: string;
};
order: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
first: string;
last: string;
none: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
};
outlineColor: ({ theme }: PluginUtils) => any;
outlineOffset: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
4: string;
8: string;
};
outlineWidth: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
4: string;
8: string;
};
padding: ({ theme }: PluginUtils) => any;
placeholderColor: ({ theme }: PluginUtils) => any;
placeholderOpacity: ({ theme }: PluginUtils) => any;
ringColor: ({ theme }: PluginUtils) => any;
ringOffsetColor: ({ theme }: PluginUtils) => any;
ringOffsetWidth: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
4: string;
8: string;
};
ringOpacity: ({ theme }: PluginUtils) => any;
ringWidth: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
DEFAULT: string;
0: string;
1: string;
2: string;
4: string;
8: string;
};
rotate: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
3: string;
6: string;
12: string;
45: string;
90: string;
180: string;
};
saturate: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
50: string;
100: string;
150: string;
200: string;
};
scale: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
50: string;
75: string;
90: string;
95: string;
100: string;
105: string;
110: string;
125: string;
150: string;
};
screens: {
sm: string;
md: string;
lg: string;
xl: string;
'2xl': string;
};
scrollMargin: ({ theme }: PluginUtils) => any;
scrollPadding: ({ theme }: PluginUtils) => any;
sepia: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
DEFAULT: string;
};
skew: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
3: string;
6: string;
12: string;
};
space: ({ theme }: PluginUtils) => any;
spacing: {
px: string;
0: string;
0.5: string;
1: string;
1.5: string;
2: string;
2.5: string;
3: string;
3.5: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
14: string;
16: string;
20: string;
24: string;
28: string;
32: string;
36: string;
40: string;
44: string;
48: string;
52: string;
56: string;
60: string;
64: string;
72: string;
80: string;
96: string;
};
stroke: ({ theme }: PluginUtils) => any;
strokeWidth: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
};
supports: {};
data: {};
textColor: ({ theme }: PluginUtils) => any;
textDecorationColor: ({ theme }: PluginUtils) => any;
textDecorationThickness: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
'from-font': string;
0: string;
1: string;
2: string;
4: string;
8: string;
};
textIndent: ({ theme }: PluginUtils) => any;
textOpacity: ({ theme }: PluginUtils) => any;
textUnderlineOffset: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
0: string;
1: string;
2: string;
4: string;
8: string;
};
transformOrigin: {
center: string;
top: string;
'top-right': string;
right: string;
'bottom-right': string;
bottom: string;
'bottom-left': string;
left: string;
'top-left': string;
};
transitionDelay: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
75: string;
100: string;
150: string;
200: string;
300: string;
500: string;
700: string;
1000: string;
};
transitionDuration: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
DEFAULT: string;
0: string;
75: string;
100: string;
150: string;
200: string;
300: string;
500: string;
700: string;
1000: string;
};
transitionProperty: {
none: string;
all: string;
DEFAULT: string;
colors: string;
opacity: string;
shadow: string;
transform: string;
};
transitionTimingFunction: {
DEFAULT: string;
linear: string;
in: string;
out: string;
'in-out': string;
};
translate: ({ theme }: PluginUtils) => any;
size: ({ theme }: PluginUtils) => any;
width: ({ theme }: PluginUtils) => any;
willChange: {
auto: string;
scroll: string;
contents: string;
transform: string;
};
zIndex: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
0: string;
10: string;
20: string;
30: string;
40: string;
50: string;
};
};
export { _default as default };
import { P as PluginUtils, N as NamedUtilityValue } from './resolve-config-B4yBzhca.js';
import './colors-C__qRT83.js';
declare const _default: {
accentColor: ({ theme }: PluginUtils) => any;
animation: {
none: string;
spin: string;
ping: string;
pulse: string;
bounce: string;
};
aria: {
busy: string;
checked: string;
disabled: string;
expanded: string;
hidden: string;
pressed: string;
readonly: string;
required: string;
selected: string;
};
aspectRatio: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
square: string;
video: string;
};
backdropBlur: ({ theme }: PluginUtils) => any;
backdropBrightness: ({ theme }: PluginUtils) => any;
backdropContrast: ({ theme }: PluginUtils) => any;
backdropGrayscale: ({ theme }: PluginUtils) => any;
backdropHueRotate: ({ theme }: PluginUtils) => any;
backdropInvert: ({ theme }: PluginUtils) => any;
backdropOpacity: ({ theme }: PluginUtils) => any;
backdropSaturate: ({ theme }: PluginUtils) => any;
backdropSepia: ({ theme }: PluginUtils) => any;
backgroundColor: ({ theme }: PluginUtils) => any;
backgroundImage: {
none: string;
'gradient-to-t': string;
'gradient-to-tr': string;
'gradient-to-r': string;
'gradient-to-br': string;
'gradient-to-b': string;
'gradient-to-bl': string;
'gradient-to-l': string;
'gradient-to-tl': string;
};
backgroundOpacity: ({ theme }: PluginUtils) => any;
backgroundPosition: {
bottom: string;
center: string;
left: string;
'left-bottom': string;
'left-top': string;
right: string;
'right-bottom': string;
'right-top': string;
top: string;
};
backgroundSize: {
auto: string;
cover: string;
contain: string;
};
blur: {
0: string;
none: string;
sm: string;
DEFAULT: string;
md: string;
lg: string;
xl: string;
'2xl': string;
'3xl': string;
};
borderColor: ({ theme }: PluginUtils) => any;
borderOpacity: ({ theme }: PluginUtils) => any;
borderRadius: {
none: string;
sm: string;
DEFAULT: string;
md: string;
lg: string;
xl: string;
'2xl': string;
'3xl': string;
full: string;
};
borderSpacing: ({ theme }: PluginUtils) => any;
borderWidth: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
DEFAULT: string;
0: string;
2: string;
4: string;
8: string;
};
boxShadow: {
sm: string;
DEFAULT: string;
md: string;
lg: string;
xl: string;
'2xl': string;
inner: string;
none: string;
};
boxShadowColor: ({ theme }: PluginUtils) => any;
brightness: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
50: string;
75: string;
90: string;
95: string;
100: string;
105: string;
110: string;
125: string;
150: string;
200: string;
};
caretColor: ({ theme }: PluginUtils) => any;
colors: () => {
inherit: string;
current: string;
transparent: string;
black: string;
white: string;
slate: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
gray: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
zinc: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
neutral: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
stone: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
mauve: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
olive: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
mist: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
taupe: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
red: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
orange: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
amber: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
yellow: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
lime: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
green: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
emerald: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
teal: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
cyan: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
sky: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
blue: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
indigo: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
violet: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
purple: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
fuchsia: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
pink: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
rose: {
'50': string;
'100': string;
'200': string;
'300': string;
'400': string;
'500': string;
'600': string;
'700': string;
'800': string;
'900': string;
'950': string;
};
};
columns: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
'3xs': string;
'2xs': string;
xs: string;
sm: string;
md: string;
lg: string;
xl: string;
'2xl': string;
'3xl': string;
'4xl': string;
'5xl': string;
'6xl': string;
'7xl': string;
};
container: {};
content: {
none: string;
};
contrast: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
50: string;
75: string;
100: string;
125: string;
150: string;
200: string;
};
cursor: {
auto: string;
default: string;
pointer: string;
wait: string;
text: string;
move: string;
help: string;
'not-allowed': string;
none: string;
'context-menu': string;
progress: string;
cell: string;
crosshair: string;
'vertical-text': string;
alias: string;
copy: string;
'no-drop': string;
grab: string;
grabbing: string;
'all-scroll': string;
'col-resize': string;
'row-resize': string;
'n-resize': string;
'e-resize': string;
's-resize': string;
'w-resize': string;
'ne-resize': string;
'nw-resize': string;
'se-resize': string;
'sw-resize': string;
'ew-resize': string;
'ns-resize': string;
'nesw-resize': string;
'nwse-resize': string;
'zoom-in': string;
'zoom-out': string;
};
divideColor: ({ theme }: PluginUtils) => any;
divideOpacity: ({ theme }: PluginUtils) => any;
divideWidth: ({ theme }: PluginUtils) => any;
dropShadow: {
sm: string;
DEFAULT: string[];
md: string[];
lg: string[];
xl: string[];
'2xl': string;
none: string;
};
fill: ({ theme }: PluginUtils) => any;
flex: {
1: string;
auto: string;
initial: string;
none: string;
};
flexBasis: ({ theme }: PluginUtils) => any;
flexGrow: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
DEFAULT: string;
};
flexShrink: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
DEFAULT: string;
};
fontFamily: {
sans: string[];
serif: string[];
mono: string[];
};
fontSize: {
xs: (string | {
lineHeight: string;
})[];
sm: (string | {
lineHeight: string;
})[];
base: (string | {
lineHeight: string;
})[];
lg: (string | {
lineHeight: string;
})[];
xl: (string | {
lineHeight: string;
})[];
'2xl': (string | {
lineHeight: string;
})[];
'3xl': (string | {
lineHeight: string;
})[];
'4xl': (string | {
lineHeight: string;
})[];
'5xl': (string | {
lineHeight: string;
})[];
'6xl': (string | {
lineHeight: string;
})[];
'7xl': (string | {
lineHeight: string;
})[];
'8xl': (string | {
lineHeight: string;
})[];
'9xl': (string | {
lineHeight: string;
})[];
};
fontWeight: {
thin: string;
extralight: string;
light: string;
normal: string;
medium: string;
semibold: string;
bold: string;
extrabold: string;
black: string;
};
gap: ({ theme }: PluginUtils) => any;
gradientColorStops: ({ theme }: PluginUtils) => any;
gradientColorStopPositions: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
'0%': string;
'5%': string;
'10%': string;
'15%': string;
'20%': string;
'25%': string;
'30%': string;
'35%': string;
'40%': string;
'45%': string;
'50%': string;
'55%': string;
'60%': string;
'65%': string;
'70%': string;
'75%': string;
'80%': string;
'85%': string;
'90%': string;
'95%': string;
'100%': string;
};
grayscale: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
DEFAULT: string;
};
gridAutoColumns: {
auto: string;
min: string;
max: string;
fr: string;
};
gridAutoRows: {
auto: string;
min: string;
max: string;
fr: string;
};
gridColumn: {
auto: string;
'span-1': string;
'span-2': string;
'span-3': string;
'span-4': string;
'span-5': string;
'span-6': string;
'span-7': string;
'span-8': string;
'span-9': string;
'span-10': string;
'span-11': string;
'span-12': string;
'span-full': string;
};
gridColumnEnd: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
13: string;
};
gridColumnStart: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
13: string;
};
gridRow: {
auto: string;
'span-1': string;
'span-2': string;
'span-3': string;
'span-4': string;
'span-5': string;
'span-6': string;
'span-7': string;
'span-8': string;
'span-9': string;
'span-10': string;
'span-11': string;
'span-12': string;
'span-full': string;
};
gridRowEnd: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
13: string;
};
gridRowStart: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
13: string;
};
gridTemplateColumns: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
none: string;
subgrid: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
};
gridTemplateRows: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
none: string;
subgrid: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
};
height: ({ theme }: PluginUtils) => any;
hueRotate: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
15: string;
30: string;
60: string;
90: string;
180: string;
};
inset: ({ theme }: PluginUtils) => any;
invert: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
DEFAULT: string;
};
keyframes: {
spin: {
to: {
transform: string;
};
};
ping: {
'75%, 100%': {
transform: string;
opacity: string;
};
};
pulse: {
'50%': {
opacity: string;
};
};
bounce: {
'0%, 100%': {
transform: string;
animationTimingFunction: string;
};
'50%': {
transform: string;
animationTimingFunction: string;
};
};
};
letterSpacing: {
tighter: string;
tight: string;
normal: string;
wide: string;
wider: string;
widest: string;
};
lineHeight: {
none: string;
tight: string;
snug: string;
normal: string;
relaxed: string;
loose: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
};
listStyleType: {
none: string;
disc: string;
decimal: string;
};
listStyleImage: {
none: string;
};
margin: ({ theme }: PluginUtils) => any;
lineClamp: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
};
maxHeight: ({ theme }: PluginUtils) => any;
maxWidth: ({ theme }: PluginUtils) => any;
minHeight: ({ theme }: PluginUtils) => any;
minWidth: ({ theme }: PluginUtils) => any;
objectPosition: {
bottom: string;
center: string;
left: string;
'left-bottom': string;
'left-top': string;
right: string;
'right-bottom': string;
'right-top': string;
top: string;
};
opacity: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
5: string;
10: string;
15: string;
20: string;
25: string;
30: string;
35: string;
40: string;
45: string;
50: string;
55: string;
60: string;
65: string;
70: string;
75: string;
80: string;
85: string;
90: string;
95: string;
100: string;
};
order: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
first: string;
last: string;
none: string;
1: string;
2: string;
3: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
};
outlineColor: ({ theme }: PluginUtils) => any;
outlineOffset: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
4: string;
8: string;
};
outlineWidth: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
4: string;
8: string;
};
padding: ({ theme }: PluginUtils) => any;
placeholderColor: ({ theme }: PluginUtils) => any;
placeholderOpacity: ({ theme }: PluginUtils) => any;
ringColor: ({ theme }: PluginUtils) => any;
ringOffsetColor: ({ theme }: PluginUtils) => any;
ringOffsetWidth: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
4: string;
8: string;
};
ringOpacity: ({ theme }: PluginUtils) => any;
ringWidth: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
DEFAULT: string;
0: string;
1: string;
2: string;
4: string;
8: string;
};
rotate: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
3: string;
6: string;
12: string;
45: string;
90: string;
180: string;
};
saturate: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
50: string;
100: string;
150: string;
200: string;
};
scale: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
50: string;
75: string;
90: string;
95: string;
100: string;
105: string;
110: string;
125: string;
150: string;
};
screens: {
sm: string;
md: string;
lg: string;
xl: string;
'2xl': string;
};
scrollMargin: ({ theme }: PluginUtils) => any;
scrollPadding: ({ theme }: PluginUtils) => any;
sepia: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
DEFAULT: string;
};
skew: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
3: string;
6: string;
12: string;
};
space: ({ theme }: PluginUtils) => any;
spacing: {
px: string;
0: string;
0.5: string;
1: string;
1.5: string;
2: string;
2.5: string;
3: string;
3.5: string;
4: string;
5: string;
6: string;
7: string;
8: string;
9: string;
10: string;
11: string;
12: string;
14: string;
16: string;
20: string;
24: string;
28: string;
32: string;
36: string;
40: string;
44: string;
48: string;
52: string;
56: string;
60: string;
64: string;
72: string;
80: string;
96: string;
};
stroke: ({ theme }: PluginUtils) => any;
strokeWidth: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
1: string;
2: string;
};
supports: {};
data: {};
textColor: ({ theme }: PluginUtils) => any;
textDecorationColor: ({ theme }: PluginUtils) => any;
textDecorationThickness: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
'from-font': string;
0: string;
1: string;
2: string;
4: string;
8: string;
};
textIndent: ({ theme }: PluginUtils) => any;
textOpacity: ({ theme }: PluginUtils) => any;
textUnderlineOffset: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
0: string;
1: string;
2: string;
4: string;
8: string;
};
transformOrigin: {
center: string;
top: string;
'top-right': string;
right: string;
'bottom-right': string;
bottom: string;
'bottom-left': string;
left: string;
'top-left': string;
};
transitionDelay: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
0: string;
75: string;
100: string;
150: string;
200: string;
300: string;
500: string;
700: string;
1000: string;
};
transitionDuration: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
DEFAULT: string;
0: string;
75: string;
100: string;
150: string;
200: string;
300: string;
500: string;
700: string;
1000: string;
};
transitionProperty: {
none: string;
all: string;
DEFAULT: string;
colors: string;
opacity: string;
shadow: string;
transform: string;
};
transitionTimingFunction: {
DEFAULT: string;
linear: string;
in: string;
out: string;
'in-out': string;
};
translate: ({ theme }: PluginUtils) => any;
size: ({ theme }: PluginUtils) => any;
width: ({ theme }: PluginUtils) => any;
willChange: {
auto: string;
scroll: string;
contents: string;
transform: string;
};
zIndex: {
__BARE_VALUE__: (value: NamedUtilityValue) => string | undefined;
auto: string;
0: string;
10: string;
20: string;
30: string;
40: string;
50: string;
};
};
export { _default as default };
"use strict";var m=new Uint8Array(256);function u(e,c){let t=0,g=[],k=0,d=e.length,w=c.charCodeAt(0);for(let n=0;n<d;n++){let h=e.charCodeAt(n);if(t===0&&h===w){g.push(e.slice(k,n)),k=n+1;continue}switch(h){case 92:n+=1;break;case 39:case 34:for(;++n<d;){let x=e.charCodeAt(n);if(x===92){n+=1;continue}if(x===h)break}break;case 40:m[t]=41,t++;break;case 91:m[t]=93,t++;break;case 123:m[t]=125,t++;break;case 93:case 125:case 41:t>0&&h===m[t-1]&&t--;break}}return g.push(e.slice(k)),g}var l=/[+-]?\d*\.?\d+(?:[eE][+-]?\d+)?/,z=new RegExp(`^${l.source}$`);var T=new RegExp(`^${l.source}%$`);var D=new RegExp(`^${l.source}\\s*/\\s*${l.source}$`);var A=["cm","mm","Q","in","pc","pt","px","em","ex","ch","rem","lh","rlh","vw","vh","vmin","vmax","vb","vi","svw","svh","lvw","lvh","dvw","dvh","cqw","cqh","cqi","cqb","cqmin","cqmax"],I=new RegExp(`^${l.source}(${A.join("|")})$`);var C=["deg","rad","grad","turn"],F=new RegExp(`^${l.source}(${C.join("|")})$`);var H=new RegExp(`^${l.source} +${l.source} +${l.source}$`);function i(e){let c=Number(e);return Number.isInteger(c)&&c>=0&&String(c)===String(e)}var f={inherit:"inherit",current:"currentcolor",transparent:"transparent",black:"#000",white:"#fff",slate:{50:"oklch(98.4% 0.003 247.858)",100:"oklch(96.8% 0.007 247.896)",200:"oklch(92.9% 0.013 255.508)",300:"oklch(86.9% 0.022 252.894)",400:"oklch(70.4% 0.04 256.788)",500:"oklch(55.4% 0.046 257.417)",600:"oklch(44.6% 0.043 257.281)",700:"oklch(37.2% 0.044 257.287)",800:"oklch(27.9% 0.041 260.031)",900:"oklch(20.8% 0.042 265.755)",950:"oklch(12.9% 0.042 264.695)"},gray:{50:"oklch(98.5% 0.002 247.839)",100:"oklch(96.7% 0.003 264.542)",200:"oklch(92.8% 0.006 264.531)",300:"oklch(87.2% 0.01 258.338)",400:"oklch(70.7% 0.022 261.325)",500:"oklch(55.1% 0.027 264.364)",600:"oklch(44.6% 0.03 256.802)",700:"oklch(37.3% 0.034 259.733)",800:"oklch(27.8% 0.033 256.848)",900:"oklch(21% 0.034 264.665)",950:"oklch(13% 0.028 261.692)"},zinc:{50:"oklch(98.5% 0 0)",100:"oklch(96.7% 0.001 286.375)",200:"oklch(92% 0.004 286.32)",300:"oklch(87.1% 0.006 286.286)",400:"oklch(70.5% 0.015 286.067)",500:"oklch(55.2% 0.016 285.938)",600:"oklch(44.2% 0.017 285.786)",700:"oklch(37% 0.013 285.805)",800:"oklch(27.4% 0.006 286.033)",900:"oklch(21% 0.006 285.885)",950:"oklch(14.1% 0.005 285.823)"},neutral:{50:"oklch(98.5% 0 0)",100:"oklch(97% 0 0)",200:"oklch(92.2% 0 0)",300:"oklch(87% 0 0)",400:"oklch(70.8% 0 0)",500:"oklch(55.6% 0 0)",600:"oklch(43.9% 0 0)",700:"oklch(37.1% 0 0)",800:"oklch(26.9% 0 0)",900:"oklch(20.5% 0 0)",950:"oklch(14.5% 0 0)"},stone:{50:"oklch(98.5% 0.001 106.423)",100:"oklch(97% 0.001 106.424)",200:"oklch(92.3% 0.003 48.717)",300:"oklch(86.9% 0.005 56.366)",400:"oklch(70.9% 0.01 56.259)",500:"oklch(55.3% 0.013 58.071)",600:"oklch(44.4% 0.011 73.639)",700:"oklch(37.4% 0.01 67.558)",800:"oklch(26.8% 0.007 34.298)",900:"oklch(21.6% 0.006 56.043)",950:"oklch(14.7% 0.004 49.25)"},mauve:{50:"oklch(98.5% 0 0)",100:"oklch(96% 0.003 325.6)",200:"oklch(92.2% 0.005 325.62)",300:"oklch(86.5% 0.012 325.68)",400:"oklch(71.1% 0.019 323.02)",500:"oklch(54.2% 0.034 322.5)",600:"oklch(43.5% 0.029 321.78)",700:"oklch(36.4% 0.029 323.89)",800:"oklch(26.3% 0.024 320.12)",900:"oklch(21.2% 0.019 322.12)",950:"oklch(14.5% 0.008 326)"},olive:{50:"oklch(98.8% 0.003 106.5)",100:"oklch(96.6% 0.005 106.5)",200:"oklch(93% 0.007 106.5)",300:"oklch(88% 0.011 106.6)",400:"oklch(73.7% 0.021 106.9)",500:"oklch(58% 0.031 107.3)",600:"oklch(46.6% 0.025 107.3)",700:"oklch(39.4% 0.023 107.4)",800:"oklch(28.6% 0.016 107.4)",900:"oklch(22.8% 0.013 107.4)",950:"oklch(15.3% 0.006 107.1)"},mist:{50:"oklch(98.7% 0.002 197.1)",100:"oklch(96.3% 0.002 197.1)",200:"oklch(92.5% 0.005 214.3)",300:"oklch(87.2% 0.007 219.6)",400:"oklch(72.3% 0.014 214.4)",500:"oklch(56% 0.021 213.5)",600:"oklch(45% 0.017 213.2)",700:"oklch(37.8% 0.015 216)",800:"oklch(27.5% 0.011 216.9)",900:"oklch(21.8% 0.008 223.9)",950:"oklch(14.8% 0.004 228.8)"},taupe:{50:"oklch(98.6% 0.002 67.8)",100:"oklch(96% 0.002 17.2)",200:"oklch(92.2% 0.005 34.3)",300:"oklch(86.8% 0.007 39.5)",400:"oklch(71.4% 0.014 41.2)",500:"oklch(54.7% 0.021 43.1)",600:"oklch(43.8% 0.017 39.3)",700:"oklch(36.7% 0.016 35.7)",800:"oklch(26.8% 0.011 36.5)",900:"oklch(21.4% 0.009 43.1)",950:"oklch(14.7% 0.004 49.3)"},red:{50:"oklch(97.1% 0.013 17.38)",100:"oklch(93.6% 0.032 17.717)",200:"oklch(88.5% 0.062 18.334)",300:"oklch(80.8% 0.114 19.571)",400:"oklch(70.4% 0.191 22.216)",500:"oklch(63.7% 0.237 25.331)",600:"oklch(57.7% 0.245 27.325)",700:"oklch(50.5% 0.213 27.518)",800:"oklch(44.4% 0.177 26.899)",900:"oklch(39.6% 0.141 25.723)",950:"oklch(25.8% 0.092 26.042)"},orange:{50:"oklch(98% 0.016 73.684)",100:"oklch(95.4% 0.038 75.164)",200:"oklch(90.1% 0.076 70.697)",300:"oklch(83.7% 0.128 66.29)",400:"oklch(75% 0.183 55.934)",500:"oklch(70.5% 0.213 47.604)",600:"oklch(64.6% 0.222 41.116)",700:"oklch(55.3% 0.195 38.402)",800:"oklch(47% 0.157 37.304)",900:"oklch(40.8% 0.123 38.172)",950:"oklch(26.6% 0.079 36.259)"},amber:{50:"oklch(98.7% 0.022 95.277)",100:"oklch(96.2% 0.059 95.617)",200:"oklch(92.4% 0.12 95.746)",300:"oklch(87.9% 0.169 91.605)",400:"oklch(82.8% 0.189 84.429)",500:"oklch(76.9% 0.188 70.08)",600:"oklch(66.6% 0.179 58.318)",700:"oklch(55.5% 0.163 48.998)",800:"oklch(47.3% 0.137 46.201)",900:"oklch(41.4% 0.112 45.904)",950:"oklch(27.9% 0.077 45.635)"},yellow:{50:"oklch(98.7% 0.026 102.212)",100:"oklch(97.3% 0.071 103.193)",200:"oklch(94.5% 0.129 101.54)",300:"oklch(90.5% 0.182 98.111)",400:"oklch(85.2% 0.199 91.936)",500:"oklch(79.5% 0.184 86.047)",600:"oklch(68.1% 0.162 75.834)",700:"oklch(55.4% 0.135 66.442)",800:"oklch(47.6% 0.114 61.907)",900:"oklch(42.1% 0.095 57.708)",950:"oklch(28.6% 0.066 53.813)"},lime:{50:"oklch(98.6% 0.031 120.757)",100:"oklch(96.7% 0.067 122.328)",200:"oklch(93.8% 0.127 124.321)",300:"oklch(89.7% 0.196 126.665)",400:"oklch(84.1% 0.238 128.85)",500:"oklch(76.8% 0.233 130.85)",600:"oklch(64.8% 0.2 131.684)",700:"oklch(53.2% 0.157 131.589)",800:"oklch(45.3% 0.124 130.933)",900:"oklch(40.5% 0.101 131.063)",950:"oklch(27.4% 0.072 132.109)"},green:{50:"oklch(98.2% 0.018 155.826)",100:"oklch(96.2% 0.044 156.743)",200:"oklch(92.5% 0.084 155.995)",300:"oklch(87.1% 0.15 154.449)",400:"oklch(79.2% 0.209 151.711)",500:"oklch(72.3% 0.219 149.579)",600:"oklch(62.7% 0.194 149.214)",700:"oklch(52.7% 0.154 150.069)",800:"oklch(44.8% 0.119 151.328)",900:"oklch(39.3% 0.095 152.535)",950:"oklch(26.6% 0.065 152.934)"},emerald:{50:"oklch(97.9% 0.021 166.113)",100:"oklch(95% 0.052 163.051)",200:"oklch(90.5% 0.093 164.15)",300:"oklch(84.5% 0.143 164.978)",400:"oklch(76.5% 0.177 163.223)",500:"oklch(69.6% 0.17 162.48)",600:"oklch(59.6% 0.145 163.225)",700:"oklch(50.8% 0.118 165.612)",800:"oklch(43.2% 0.095 166.913)",900:"oklch(37.8% 0.077 168.94)",950:"oklch(26.2% 0.051 172.552)"},teal:{50:"oklch(98.4% 0.014 180.72)",100:"oklch(95.3% 0.051 180.801)",200:"oklch(91% 0.096 180.426)",300:"oklch(85.5% 0.138 181.071)",400:"oklch(77.7% 0.152 181.912)",500:"oklch(70.4% 0.14 182.503)",600:"oklch(60% 0.118 184.704)",700:"oklch(51.1% 0.096 186.391)",800:"oklch(43.7% 0.078 188.216)",900:"oklch(38.6% 0.063 188.416)",950:"oklch(27.7% 0.046 192.524)"},cyan:{50:"oklch(98.4% 0.019 200.873)",100:"oklch(95.6% 0.045 203.388)",200:"oklch(91.7% 0.08 205.041)",300:"oklch(86.5% 0.127 207.078)",400:"oklch(78.9% 0.154 211.53)",500:"oklch(71.5% 0.143 215.221)",600:"oklch(60.9% 0.126 221.723)",700:"oklch(52% 0.105 223.128)",800:"oklch(45% 0.085 224.283)",900:"oklch(39.8% 0.07 227.392)",950:"oklch(30.2% 0.056 229.695)"},sky:{50:"oklch(97.7% 0.013 236.62)",100:"oklch(95.1% 0.026 236.824)",200:"oklch(90.1% 0.058 230.902)",300:"oklch(82.8% 0.111 230.318)",400:"oklch(74.6% 0.16 232.661)",500:"oklch(68.5% 0.169 237.323)",600:"oklch(58.8% 0.158 241.966)",700:"oklch(50% 0.134 242.749)",800:"oklch(44.3% 0.11 240.79)",900:"oklch(39.1% 0.09 240.876)",950:"oklch(29.3% 0.066 243.157)"},blue:{50:"oklch(97% 0.014 254.604)",100:"oklch(93.2% 0.032 255.585)",200:"oklch(88.2% 0.059 254.128)",300:"oklch(80.9% 0.105 251.813)",400:"oklch(70.7% 0.165 254.624)",500:"oklch(62.3% 0.214 259.815)",600:"oklch(54.6% 0.245 262.881)",700:"oklch(48.8% 0.243 264.376)",800:"oklch(42.4% 0.199 265.638)",900:"oklch(37.9% 0.146 265.522)",950:"oklch(28.2% 0.091 267.935)"},indigo:{50:"oklch(96.2% 0.018 272.314)",100:"oklch(93% 0.034 272.788)",200:"oklch(87% 0.065 274.039)",300:"oklch(78.5% 0.115 274.713)",400:"oklch(67.3% 0.182 276.935)",500:"oklch(58.5% 0.233 277.117)",600:"oklch(51.1% 0.262 276.966)",700:"oklch(45.7% 0.24 277.023)",800:"oklch(39.8% 0.195 277.366)",900:"oklch(35.9% 0.144 278.697)",950:"oklch(25.7% 0.09 281.288)"},violet:{50:"oklch(96.9% 0.016 293.756)",100:"oklch(94.3% 0.029 294.588)",200:"oklch(89.4% 0.057 293.283)",300:"oklch(81.1% 0.111 293.571)",400:"oklch(70.2% 0.183 293.541)",500:"oklch(60.6% 0.25 292.717)",600:"oklch(54.1% 0.281 293.009)",700:"oklch(49.1% 0.27 292.581)",800:"oklch(43.2% 0.232 292.759)",900:"oklch(38% 0.189 293.745)",950:"oklch(28.3% 0.141 291.089)"},purple:{50:"oklch(97.7% 0.014 308.299)",100:"oklch(94.6% 0.033 307.174)",200:"oklch(90.2% 0.063 306.703)",300:"oklch(82.7% 0.119 306.383)",400:"oklch(71.4% 0.203 305.504)",500:"oklch(62.7% 0.265 303.9)",600:"oklch(55.8% 0.288 302.321)",700:"oklch(49.6% 0.265 301.924)",800:"oklch(43.8% 0.218 303.724)",900:"oklch(38.1% 0.176 304.987)",950:"oklch(29.1% 0.149 302.717)"},fuchsia:{50:"oklch(97.7% 0.017 320.058)",100:"oklch(95.2% 0.037 318.852)",200:"oklch(90.3% 0.076 319.62)",300:"oklch(83.3% 0.145 321.434)",400:"oklch(74% 0.238 322.16)",500:"oklch(66.7% 0.295 322.15)",600:"oklch(59.1% 0.293 322.896)",700:"oklch(51.8% 0.253 323.949)",800:"oklch(45.2% 0.211 324.591)",900:"oklch(40.1% 0.17 325.612)",950:"oklch(29.3% 0.136 325.661)"},pink:{50:"oklch(97.1% 0.014 343.198)",100:"oklch(94.8% 0.028 342.258)",200:"oklch(89.9% 0.061 343.231)",300:"oklch(82.3% 0.12 346.018)",400:"oklch(71.8% 0.202 349.761)",500:"oklch(65.6% 0.241 354.308)",600:"oklch(59.2% 0.249 0.584)",700:"oklch(52.5% 0.223 3.958)",800:"oklch(45.9% 0.187 3.815)",900:"oklch(40.8% 0.153 2.432)",950:"oklch(28.4% 0.109 3.907)"},rose:{50:"oklch(96.9% 0.015 12.422)",100:"oklch(94.1% 0.03 12.58)",200:"oklch(89.2% 0.058 10.001)",300:"oklch(81% 0.117 11.638)",400:"oklch(71.2% 0.194 13.428)",500:"oklch(64.5% 0.246 16.439)",600:"oklch(58.6% 0.253 17.585)",700:"oklch(51.4% 0.222 16.935)",800:"oklch(45.5% 0.188 13.697)",900:"oklch(41% 0.159 10.272)",950:"oklch(27.1% 0.105 12.094)"}};function s(e){return{__BARE_VALUE__:e}}var r=s(e=>{if(i(e.value))return e.value}),o=s(e=>{if(i(e.value))return`${e.value}%`}),a=s(e=>{if(i(e.value))return`${e.value}px`}),b=s(e=>{if(i(e.value))return`${e.value}ms`}),p=s(e=>{if(i(e.value))return`${e.value}deg`}),S=s(e=>{if(e.fraction===null)return;let[c,t]=u(e.fraction,"/");if(!(!i(c)||!i(t)))return e.fraction}),E=s(e=>{if(i(Number(e.value)))return`repeat(${e.value}, minmax(0, 1fr))`}),y={accentColor:({theme:e})=>e("colors"),animation:{none:"none",spin:"spin 1s linear infinite",ping:"ping 1s cubic-bezier(0, 0, 0.2, 1) infinite",pulse:"pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",bounce:"bounce 1s infinite"},aria:{busy:'busy="true"',checked:'checked="true"',disabled:'disabled="true"',expanded:'expanded="true"',hidden:'hidden="true"',pressed:'pressed="true"',readonly:'readonly="true"',required:'required="true"',selected:'selected="true"'},aspectRatio:{auto:"auto",square:"1 / 1",video:"16 / 9",...S},backdropBlur:({theme:e})=>e("blur"),backdropBrightness:({theme:e})=>({...e("brightness"),...o}),backdropContrast:({theme:e})=>({...e("contrast"),...o}),backdropGrayscale:({theme:e})=>({...e("grayscale"),...o}),backdropHueRotate:({theme:e})=>({...e("hueRotate"),...p}),backdropInvert:({theme:e})=>({...e("invert"),...o}),backdropOpacity:({theme:e})=>({...e("opacity"),...o}),backdropSaturate:({theme:e})=>({...e("saturate"),...o}),backdropSepia:({theme:e})=>({...e("sepia"),...o}),backgroundColor:({theme:e})=>e("colors"),backgroundImage:{none:"none","gradient-to-t":"linear-gradient(to top, var(--tw-gradient-stops))","gradient-to-tr":"linear-gradient(to top right, var(--tw-gradient-stops))","gradient-to-r":"linear-gradient(to right, var(--tw-gradient-stops))","gradient-to-br":"linear-gradient(to bottom right, var(--tw-gradient-stops))","gradient-to-b":"linear-gradient(to bottom, var(--tw-gradient-stops))","gradient-to-bl":"linear-gradient(to bottom left, var(--tw-gradient-stops))","gradient-to-l":"linear-gradient(to left, var(--tw-gradient-stops))","gradient-to-tl":"linear-gradient(to top left, var(--tw-gradient-stops))"},backgroundOpacity:({theme:e})=>e("opacity"),backgroundPosition:{bottom:"bottom",center:"center",left:"left","left-bottom":"left bottom","left-top":"left top",right:"right","right-bottom":"right bottom","right-top":"right top",top:"top"},backgroundSize:{auto:"auto",cover:"cover",contain:"contain"},blur:{0:"0",none:"",sm:"4px",DEFAULT:"8px",md:"12px",lg:"16px",xl:"24px","2xl":"40px","3xl":"64px"},borderColor:({theme:e})=>({DEFAULT:"currentcolor",...e("colors")}),borderOpacity:({theme:e})=>e("opacity"),borderRadius:{none:"0px",sm:"0.125rem",DEFAULT:"0.25rem",md:"0.375rem",lg:"0.5rem",xl:"0.75rem","2xl":"1rem","3xl":"1.5rem",full:"9999px"},borderSpacing:({theme:e})=>e("spacing"),borderWidth:{DEFAULT:"1px",0:"0px",2:"2px",4:"4px",8:"8px",...a},boxShadow:{sm:"0 1px 2px 0 rgb(0 0 0 / 0.05)",DEFAULT:"0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",md:"0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",lg:"0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",xl:"0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)","2xl":"0 25px 50px -12px rgb(0 0 0 / 0.25)",inner:"inset 0 2px 4px 0 rgb(0 0 0 / 0.05)",none:"none"},boxShadowColor:({theme:e})=>e("colors"),brightness:{0:"0",50:".5",75:".75",90:".9",95:".95",100:"1",105:"1.05",110:"1.1",125:"1.25",150:"1.5",200:"2",...o},caretColor:({theme:e})=>e("colors"),colors:()=>({...f}),columns:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12","3xs":"16rem","2xs":"18rem",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem",...r},container:{},content:{none:"none"},contrast:{0:"0",50:".5",75:".75",100:"1",125:"1.25",150:"1.5",200:"2",...o},cursor:{auto:"auto",default:"default",pointer:"pointer",wait:"wait",text:"text",move:"move",help:"help","not-allowed":"not-allowed",none:"none","context-menu":"context-menu",progress:"progress",cell:"cell",crosshair:"crosshair","vertical-text":"vertical-text",alias:"alias",copy:"copy","no-drop":"no-drop",grab:"grab",grabbing:"grabbing","all-scroll":"all-scroll","col-resize":"col-resize","row-resize":"row-resize","n-resize":"n-resize","e-resize":"e-resize","s-resize":"s-resize","w-resize":"w-resize","ne-resize":"ne-resize","nw-resize":"nw-resize","se-resize":"se-resize","sw-resize":"sw-resize","ew-resize":"ew-resize","ns-resize":"ns-resize","nesw-resize":"nesw-resize","nwse-resize":"nwse-resize","zoom-in":"zoom-in","zoom-out":"zoom-out"},divideColor:({theme:e})=>e("borderColor"),divideOpacity:({theme:e})=>e("borderOpacity"),divideWidth:({theme:e})=>({...e("borderWidth"),...a}),dropShadow:{sm:"0 1px 1px rgb(0 0 0 / 0.05)",DEFAULT:["0 1px 2px rgb(0 0 0 / 0.1)","0 1px 1px rgb(0 0 0 / 0.06)"],md:["0 4px 3px rgb(0 0 0 / 0.07)","0 2px 2px rgb(0 0 0 / 0.06)"],lg:["0 10px 8px rgb(0 0 0 / 0.04)","0 4px 3px rgb(0 0 0 / 0.1)"],xl:["0 20px 13px rgb(0 0 0 / 0.03)","0 8px 5px rgb(0 0 0 / 0.08)"],"2xl":"0 25px 25px rgb(0 0 0 / 0.15)",none:"0 0 #0000"},fill:({theme:e})=>e("colors"),flex:{1:"1 1 0%",auto:"1 1 auto",initial:"0 1 auto",none:"none"},flexBasis:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",...e("spacing")}),flexGrow:{0:"0",DEFAULT:"1",...r},flexShrink:{0:"0",DEFAULT:"1",...r},fontFamily:{sans:["ui-sans-serif","system-ui","sans-serif",'"Apple Color Emoji"','"Segoe UI Emoji"','"Segoe UI Symbol"','"Noto Color Emoji"'],serif:["ui-serif","Georgia","Cambria",'"Times New Roman"',"Times","serif"],mono:["ui-monospace","SFMono-Regular","Menlo","Monaco","Consolas",'"Liberation Mono"','"Courier New"',"monospace"]},fontSize:{xs:["0.75rem",{lineHeight:"1rem"}],sm:["0.875rem",{lineHeight:"1.25rem"}],base:["1rem",{lineHeight:"1.5rem"}],lg:["1.125rem",{lineHeight:"1.75rem"}],xl:["1.25rem",{lineHeight:"1.75rem"}],"2xl":["1.5rem",{lineHeight:"2rem"}],"3xl":["1.875rem",{lineHeight:"2.25rem"}],"4xl":["2.25rem",{lineHeight:"2.5rem"}],"5xl":["3rem",{lineHeight:"1"}],"6xl":["3.75rem",{lineHeight:"1"}],"7xl":["4.5rem",{lineHeight:"1"}],"8xl":["6rem",{lineHeight:"1"}],"9xl":["8rem",{lineHeight:"1"}]},fontWeight:{thin:"100",extralight:"200",light:"300",normal:"400",medium:"500",semibold:"600",bold:"700",extrabold:"800",black:"900"},gap:({theme:e})=>e("spacing"),gradientColorStops:({theme:e})=>e("colors"),gradientColorStopPositions:{"0%":"0%","5%":"5%","10%":"10%","15%":"15%","20%":"20%","25%":"25%","30%":"30%","35%":"35%","40%":"40%","45%":"45%","50%":"50%","55%":"55%","60%":"60%","65%":"65%","70%":"70%","75%":"75%","80%":"80%","85%":"85%","90%":"90%","95%":"95%","100%":"100%",...o},grayscale:{0:"0",DEFAULT:"100%",...o},gridAutoColumns:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0, 1fr)"},gridAutoRows:{auto:"auto",min:"min-content",max:"max-content",fr:"minmax(0, 1fr)"},gridColumn:{auto:"auto","span-1":"span 1 / span 1","span-2":"span 2 / span 2","span-3":"span 3 / span 3","span-4":"span 4 / span 4","span-5":"span 5 / span 5","span-6":"span 6 / span 6","span-7":"span 7 / span 7","span-8":"span 8 / span 8","span-9":"span 9 / span 9","span-10":"span 10 / span 10","span-11":"span 11 / span 11","span-12":"span 12 / span 12","span-full":"1 / -1"},gridColumnEnd:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...r},gridColumnStart:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...r},gridRow:{auto:"auto","span-1":"span 1 / span 1","span-2":"span 2 / span 2","span-3":"span 3 / span 3","span-4":"span 4 / span 4","span-5":"span 5 / span 5","span-6":"span 6 / span 6","span-7":"span 7 / span 7","span-8":"span 8 / span 8","span-9":"span 9 / span 9","span-10":"span 10 / span 10","span-11":"span 11 / span 11","span-12":"span 12 / span 12","span-full":"1 / -1"},gridRowEnd:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...r},gridRowStart:{auto:"auto",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",13:"13",...r},gridTemplateColumns:{none:"none",subgrid:"subgrid",1:"repeat(1, minmax(0, 1fr))",2:"repeat(2, minmax(0, 1fr))",3:"repeat(3, minmax(0, 1fr))",4:"repeat(4, minmax(0, 1fr))",5:"repeat(5, minmax(0, 1fr))",6:"repeat(6, minmax(0, 1fr))",7:"repeat(7, minmax(0, 1fr))",8:"repeat(8, minmax(0, 1fr))",9:"repeat(9, minmax(0, 1fr))",10:"repeat(10, minmax(0, 1fr))",11:"repeat(11, minmax(0, 1fr))",12:"repeat(12, minmax(0, 1fr))",...E},gridTemplateRows:{none:"none",subgrid:"subgrid",1:"repeat(1, minmax(0, 1fr))",2:"repeat(2, minmax(0, 1fr))",3:"repeat(3, minmax(0, 1fr))",4:"repeat(4, minmax(0, 1fr))",5:"repeat(5, minmax(0, 1fr))",6:"repeat(6, minmax(0, 1fr))",7:"repeat(7, minmax(0, 1fr))",8:"repeat(8, minmax(0, 1fr))",9:"repeat(9, minmax(0, 1fr))",10:"repeat(10, minmax(0, 1fr))",11:"repeat(11, minmax(0, 1fr))",12:"repeat(12, minmax(0, 1fr))",...E},height:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%",full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),hueRotate:{0:"0deg",15:"15deg",30:"30deg",60:"60deg",90:"90deg",180:"180deg",...p},inset:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%",full:"100%",...e("spacing")}),invert:{0:"0",DEFAULT:"100%",...o},keyframes:{spin:{to:{transform:"rotate(360deg)"}},ping:{"75%, 100%":{transform:"scale(2)",opacity:"0"}},pulse:{"50%":{opacity:".5"}},bounce:{"0%, 100%":{transform:"translateY(-25%)",animationTimingFunction:"cubic-bezier(0.8,0,1,1)"},"50%":{transform:"none",animationTimingFunction:"cubic-bezier(0,0,0.2,1)"}}},letterSpacing:{tighter:"-0.05em",tight:"-0.025em",normal:"0em",wide:"0.025em",wider:"0.05em",widest:"0.1em"},lineHeight:{none:"1",tight:"1.25",snug:"1.375",normal:"1.5",relaxed:"1.625",loose:"2",3:".75rem",4:"1rem",5:"1.25rem",6:"1.5rem",7:"1.75rem",8:"2rem",9:"2.25rem",10:"2.5rem"},listStyleType:{none:"none",disc:"disc",decimal:"decimal"},listStyleImage:{none:"none"},margin:({theme:e})=>({auto:"auto",...e("spacing")}),lineClamp:{1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",...r},maxHeight:({theme:e})=>({none:"none",full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),maxWidth:({theme:e})=>({none:"none",xs:"20rem",sm:"24rem",md:"28rem",lg:"32rem",xl:"36rem","2xl":"42rem","3xl":"48rem","4xl":"56rem","5xl":"64rem","6xl":"72rem","7xl":"80rem",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",prose:"65ch",...e("spacing")}),minHeight:({theme:e})=>({full:"100%",screen:"100vh",svh:"100svh",lvh:"100lvh",dvh:"100dvh",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),minWidth:({theme:e})=>({full:"100%",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),objectPosition:{bottom:"bottom",center:"center",left:"left","left-bottom":"left bottom","left-top":"left top",right:"right","right-bottom":"right bottom","right-top":"right top",top:"top"},opacity:{0:"0",5:"0.05",10:"0.1",15:"0.15",20:"0.2",25:"0.25",30:"0.3",35:"0.35",40:"0.4",45:"0.45",50:"0.5",55:"0.55",60:"0.6",65:"0.65",70:"0.7",75:"0.75",80:"0.8",85:"0.85",90:"0.9",95:"0.95",100:"1",...o},order:{first:"-9999",last:"9999",none:"0",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",10:"10",11:"11",12:"12",...r},outlineColor:({theme:e})=>e("colors"),outlineOffset:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},outlineWidth:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},padding:({theme:e})=>e("spacing"),placeholderColor:({theme:e})=>e("colors"),placeholderOpacity:({theme:e})=>e("opacity"),ringColor:({theme:e})=>({DEFAULT:"currentcolor",...e("colors")}),ringOffsetColor:({theme:e})=>e("colors"),ringOffsetWidth:{0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},ringOpacity:({theme:e})=>({DEFAULT:"0.5",...e("opacity")}),ringWidth:{DEFAULT:"3px",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},rotate:{0:"0deg",1:"1deg",2:"2deg",3:"3deg",6:"6deg",12:"12deg",45:"45deg",90:"90deg",180:"180deg",...p},saturate:{0:"0",50:".5",100:"1",150:"1.5",200:"2",...o},scale:{0:"0",50:".5",75:".75",90:".9",95:".95",100:"1",105:"1.05",110:"1.1",125:"1.25",150:"1.5",...o},screens:{sm:"40rem",md:"48rem",lg:"64rem",xl:"80rem","2xl":"96rem"},scrollMargin:({theme:e})=>e("spacing"),scrollPadding:({theme:e})=>e("spacing"),sepia:{0:"0",DEFAULT:"100%",...o},skew:{0:"0deg",1:"1deg",2:"2deg",3:"3deg",6:"6deg",12:"12deg",...p},space:({theme:e})=>e("spacing"),spacing:{px:"1px",0:"0px",.5:"0.125rem",1:"0.25rem",1.5:"0.375rem",2:"0.5rem",2.5:"0.625rem",3:"0.75rem",3.5:"0.875rem",4:"1rem",5:"1.25rem",6:"1.5rem",7:"1.75rem",8:"2rem",9:"2.25rem",10:"2.5rem",11:"2.75rem",12:"3rem",14:"3.5rem",16:"4rem",20:"5rem",24:"6rem",28:"7rem",32:"8rem",36:"9rem",40:"10rem",44:"11rem",48:"12rem",52:"13rem",56:"14rem",60:"15rem",64:"16rem",72:"18rem",80:"20rem",96:"24rem"},stroke:({theme:e})=>({none:"none",...e("colors")}),strokeWidth:{0:"0",1:"1",2:"2",...r},supports:{},data:{},textColor:({theme:e})=>e("colors"),textDecorationColor:({theme:e})=>e("colors"),textDecorationThickness:{auto:"auto","from-font":"from-font",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},textIndent:({theme:e})=>e("spacing"),textOpacity:({theme:e})=>e("opacity"),textUnderlineOffset:{auto:"auto",0:"0px",1:"1px",2:"2px",4:"4px",8:"8px",...a},transformOrigin:{center:"center",top:"top","top-right":"top right",right:"right","bottom-right":"bottom right",bottom:"bottom","bottom-left":"bottom left",left:"left","top-left":"top left"},transitionDelay:{0:"0s",75:"75ms",100:"100ms",150:"150ms",200:"200ms",300:"300ms",500:"500ms",700:"700ms",1e3:"1000ms",...b},transitionDuration:{DEFAULT:"150ms",0:"0s",75:"75ms",100:"100ms",150:"150ms",200:"200ms",300:"300ms",500:"500ms",700:"700ms",1e3:"1000ms",...b},transitionProperty:{none:"none",all:"all",DEFAULT:"color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter",colors:"color, background-color, border-color, outline-color, text-decoration-color, fill, stroke",opacity:"opacity",shadow:"box-shadow",transform:"transform"},transitionTimingFunction:{DEFAULT:"cubic-bezier(0.4, 0, 0.2, 1)",linear:"linear",in:"cubic-bezier(0.4, 0, 1, 1)",out:"cubic-bezier(0, 0, 0.2, 1)","in-out":"cubic-bezier(0.4, 0, 0.2, 1)"},translate:({theme:e})=>({"1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%",full:"100%",...e("spacing")}),size:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),width:({theme:e})=>({auto:"auto","1/2":"50%","1/3":"33.333333%","2/3":"66.666667%","1/4":"25%","2/4":"50%","3/4":"75%","1/5":"20%","2/5":"40%","3/5":"60%","4/5":"80%","1/6":"16.666667%","2/6":"33.333333%","3/6":"50%","4/6":"66.666667%","5/6":"83.333333%","1/12":"8.333333%","2/12":"16.666667%","3/12":"25%","4/12":"33.333333%","5/12":"41.666667%","6/12":"50%","7/12":"58.333333%","8/12":"66.666667%","9/12":"75%","10/12":"83.333333%","11/12":"91.666667%",full:"100%",screen:"100vw",svw:"100svw",lvw:"100lvw",dvw:"100dvw",min:"min-content",max:"max-content",fit:"fit-content",...e("spacing")}),willChange:{auto:"auto",scroll:"scroll-position",contents:"contents",transform:"transform"},zIndex:{auto:"auto",0:"0",10:"10",20:"20",30:"30",40:"40",50:"50",...r}};module.exports=y;
import{j as a}from"./chunk-HMCCH6MG.mjs";import"./chunk-X4GG3EDV.mjs";export{a as default};
type Colors = {
[key: string | number]: string | Colors;
};
declare function flattenColorPalette(colors: Colors): Record<string, string>;
export { flattenColorPalette as default };
type Colors = {
[key: string | number]: string | Colors;
};
declare function flattenColorPalette(colors: Colors): Record<string, string>;
export { flattenColorPalette as default };
"use strict";function n(r){let i={};for(let[e,t]of Object.entries(r??{}))if(e!=="__CSS_VALUES__")if(typeof t=="object"&&t!==null)for(let[s,l]of Object.entries(n(t)))i[`${e}${s==="DEFAULT"?"":`-${s}`}`]=l;else i[e]=t;if("__CSS_VALUES__"in r)for(let[e,t]of Object.entries(r.__CSS_VALUES__))(Number(t)&4)===0&&(i[e]=r[e]);return i}module.exports=n;
import"./chunk-5JIJA4QV.mjs";function i(r){let n={};for(let[e,t]of Object.entries(r??{}))if(e!=="__CSS_VALUES__")if(typeof t=="object"&&t!==null)for(let[o,f]of Object.entries(i(t)))n[`${e}${o==="DEFAULT"?"":`-${o}`}`]=f;else n[e]=t;if("__CSS_VALUES__"in r)for(let[e,t]of Object.entries(r.__CSS_VALUES__))(Number(t)&4)===0&&(n[e]=r[e]);return n}export{i as default};
import { S as SourceLocation, U as UserConfig, P as Plugin } from './types-DWdTiksJ.mjs';
import { V as Variant, C as Candidate } from './resolve-config-QUZ9b-Gn.mjs';
import './colors.mjs';
declare const enum ThemeOptions {
NONE = 0,
INLINE = 1,
REFERENCE = 2,
DEFAULT = 4,
STATIC = 8,
USED = 16
}
declare class Theme {
#private;
private values;
private keyframes;
prefix: string | null;
constructor(values?: Map<string, {
value: string;
options: ThemeOptions;
src: Declaration["src"];
}>, keyframes?: Set<AtRule>);
get size(): number;
add(key: string, value: string, options?: ThemeOptions, src?: Declaration['src']): void;
keysInNamespaces(themeKeys: Iterable<ThemeKey>): string[];
get(themeKeys: ThemeKey[]): string | null;
hasDefault(key: string): boolean;
getOptions(key: string): ThemeOptions;
entries(): MapIterator<[string, {
value: string;
options: ThemeOptions;
src: Declaration["src"];
}]> | [string, {
value: string;
options: ThemeOptions;
src: Declaration["src"];
}][];
prefixKey(key: string): string;
clearNamespace(namespace: string, clearOptions: ThemeOptions): void;
markUsedVariable(themeKey: string): boolean;
resolve(candidateValue: string | null, themeKeys: ThemeKey[], options?: ThemeOptions): string | null;
resolveValue(candidateValue: string | null, themeKeys: ThemeKey[]): string | null;
resolveWith(candidateValue: string, themeKeys: ThemeKey[], nestedKeys?: `--${string}`[]): [string, Record<string, string>] | null;
namespace(namespace: string): Map<string | null, string>;
addKeyframes(value: AtRule): void;
getKeyframes(): AtRule[];
}
type ThemeKey = `--${string}`;
type VariantFn<T extends Variant['kind']> = (rule: Rule, variant: Extract<Variant, {
kind: T;
}>) => null | void;
type CompareFn = (a: Variant, z: Variant) => number;
declare const enum Compounds {
Never = 0,
AtRules = 1,
StyleRules = 2
}
declare class Variants {
compareFns: Map<number, CompareFn>;
variants: Map<string, {
kind: Variant["kind"];
order: number;
applyFn: VariantFn<any>;
compoundsWith: Compounds;
compounds: Compounds;
}>;
private completions;
/**
* Registering a group of variants should result in the same sort number for
* all the variants. This is to ensure that the variants are applied in the
* correct order.
*/
private groupOrder;
/**
* Keep track of the last sort order instead of using the size of the map to
* avoid unnecessarily skipping order numbers.
*/
private lastOrder;
static(name: string, applyFn: VariantFn<'static'>, { compounds, order }?: {
compounds?: Compounds;
order?: number;
}): void;
fromAst(name: string, ast: AstNode[], designSystem: DesignSystem): void;
functional(name: string, applyFn: VariantFn<'functional'>, { compounds, order }?: {
compounds?: Compounds;
order?: number;
}): void;
compound(name: string, compoundsWith: Compounds, applyFn: VariantFn<'compound'>, { compounds, order }?: {
compounds?: Compounds;
order?: number;
}): void;
group(fn: () => void, compareFn?: CompareFn): void;
has(name: string): boolean;
get(name: string): {
kind: Variant["kind"];
order: number;
applyFn: VariantFn<any>;
compoundsWith: Compounds;
compounds: Compounds;
} | undefined;
kind(name: string): "arbitrary" | "static" | "functional" | "compound";
compoundsWith(parent: string, child: string | Variant): boolean;
suggest(name: string, suggestions: () => string[]): void;
getCompletions(name: string): string[];
compare(a: Variant | null, z: Variant | null): number;
keys(): MapIterator<string>;
entries(): MapIterator<[string, {
kind: Variant["kind"];
order: number;
applyFn: VariantFn<any>;
compoundsWith: Compounds;
compounds: Compounds;
}]>;
private set;
private nextOrder;
}
declare function compileAstNodes(candidate: Candidate, designSystem: DesignSystem, flags: CompileAstFlags): {
node: AstNode;
propertySort: {
order: number[];
count: number;
};
}[];
interface CanonicalizeOptions {
/**
* The root font size in pixels. If provided, `rem` values will be normalized
* to `px` values.
*
* E.g.: `mt-[16px]` with `rem: 16` will become `mt-4` (assuming `--spacing: 0.25rem`).
*/
rem?: number;
/**
* Whether to collapse multiple utilities into a single utility if possible.
*
* E.g.: `mt-2 mr-2 mb-2 ml-2` → `m-2`
*/
collapse?: boolean;
/**
* Whether to convert between logical and physical properties when collapsing
* utilities.
*
* E.g.: `mr-2 ml-2` → `mx-2`
*/
logicalToPhysical?: boolean;
}
interface ClassMetadata {
modifiers: string[];
}
type ClassEntry = [string, ClassMetadata];
interface SelectorOptions {
modifier?: string;
value?: string;
}
interface VariantEntry {
name: string;
isArbitrary: boolean;
values: string[];
hasDash: boolean;
selectors: (options: SelectorOptions) => string[];
}
type CompileFn<T extends Candidate['kind']> = (value: Extract<Candidate, {
kind: T;
}>) => AstNode[] | undefined | null;
interface SuggestionGroup {
supportsNegative?: boolean;
values: (string | null)[];
modifiers: string[];
}
type UtilityOptions = {
types: string[];
};
type Utility = {
kind: 'static' | 'functional';
compileFn: CompileFn<any>;
options?: UtilityOptions;
};
declare class Utilities {
private utilities;
private completions;
static(name: string, compileFn: CompileFn<'static'>): void;
functional(name: string, compileFn: CompileFn<'functional'>, options?: UtilityOptions): void;
has(name: string, kind: 'static' | 'functional'): boolean;
get(name: string): Utility[];
getCompletions(name: string): SuggestionGroup[];
suggest(name: string, groups: () => SuggestionGroup[]): void;
keys(kind: 'static' | 'functional'): string[];
}
declare const enum CompileAstFlags {
None = 0,
RespectImportant = 1
}
type DesignSystem = {
theme: Theme;
utilities: Utilities;
variants: Variants;
invalidCandidates: Set<string>;
important: boolean;
getClassOrder(classes: string[]): [string, bigint | null][];
getClassList(): ClassEntry[];
getVariants(): VariantEntry[];
parseCandidate(candidate: string): Readonly<Candidate>[];
parseVariant(variant: string): Readonly<Variant> | null;
compileAstNodes(candidate: Candidate, flags?: CompileAstFlags): ReturnType<typeof compileAstNodes>;
printCandidate(candidate: Candidate): string;
printVariant(variant: Variant): string;
getVariantOrder(): Map<Variant, number>;
resolveThemeValue(path: string, forceInline?: boolean): string | undefined;
trackUsedVariables(raw: string): void;
canonicalizeCandidates(candidates: string[], options?: CanonicalizeOptions): string[];
candidatesToCss(classes: string[]): (string | null)[];
candidatesToAst(classes: string[]): AstNode[][];
storage: Record<symbol, unknown>;
};
type StyleRule = {
kind: 'rule';
selector: string;
nodes: AstNode[];
src?: SourceLocation;
dst?: SourceLocation;
};
type AtRule = {
kind: 'at-rule';
name: string;
params: string;
nodes: AstNode[];
src?: SourceLocation;
dst?: SourceLocation;
};
type Declaration = {
kind: 'declaration';
property: string;
value: string | undefined;
important: boolean;
src?: SourceLocation;
dst?: SourceLocation;
};
type Comment = {
kind: 'comment';
value: string;
src?: SourceLocation;
dst?: SourceLocation;
};
type Context = {
kind: 'context';
context: Record<string, string | boolean>;
nodes: AstNode[];
src?: undefined;
dst?: undefined;
};
type AtRoot = {
kind: 'at-root';
nodes: AstNode[];
src?: undefined;
dst?: undefined;
};
type Rule = StyleRule | AtRule;
type AstNode = StyleRule | AtRule | Declaration | Comment | Context | AtRoot;
/**
* Line offset tables are the key to generating our source maps. They allow us
* to store indexes with our AST nodes and later convert them into positions as
* when given the source that the indexes refer to.
*/
/**
* A position in source code
*
* https://tc39.es/ecma426/#sec-position-record-type
*/
interface Position {
/** The line number, one-based */
line: number;
/** The column/character number, one-based */
column: number;
}
interface OriginalPosition extends Position {
source: DecodedSource;
}
/**
* A "decoded" sourcemap
*
* @see https://tc39.es/ecma426/#decoded-source-map-record
*/
interface DecodedSourceMap {
file: string | null;
sources: DecodedSource[];
mappings: DecodedMapping[];
}
/**
* A "decoded" source
*
* @see https://tc39.es/ecma426/#decoded-source-record
*/
interface DecodedSource {
url: string | null;
content: string | null;
ignore: boolean;
}
/**
* A "decoded" mapping
*
* @see https://tc39.es/ecma426/#decoded-mapping-record
*/
interface DecodedMapping {
originalPosition: OriginalPosition | null;
generatedPosition: Position;
name: string | null;
}
interface Config extends UserConfig {
}
declare const enum Polyfills {
None = 0,
AtProperty = 1,
ColorMix = 2,
All = 3
}
type CompileOptions = {
base?: string;
from?: string;
polyfills?: Polyfills;
loadModule?: (id: string, base: string, resourceHint: 'plugin' | 'config') => Promise<{
path: string;
base: string;
module: Plugin | Config;
}>;
loadStylesheet?: (id: string, base: string) => Promise<{
path: string;
base: string;
content: string;
}>;
};
type Root = null | 'none' | {
base: string;
pattern: string;
};
declare const enum Features {
None = 0,
AtApply = 1,
AtImport = 2,
JsPluginCompat = 4,
ThemeFunction = 8,
Utilities = 16,
Variants = 32,
AtTheme = 64
}
declare function compileAst(input: AstNode[], opts?: CompileOptions): Promise<{
sources: {
base: string;
pattern: string;
negated: boolean;
}[];
root: Root;
features: Features;
build(candidates: string[]): AstNode[];
}>;
declare function compile(css: string, opts?: CompileOptions): Promise<{
sources: {
base: string;
pattern: string;
negated: boolean;
}[];
root: Root;
features: Features;
build(candidates: string[]): string;
buildSourceMap(): DecodedSourceMap;
}>;
declare function __unstable__loadDesignSystem(css: string, opts?: CompileOptions): Promise<DesignSystem>;
declare function postcssPluginWarning(): void;
export { type Config, type DecodedSourceMap, Features, Polyfills, __unstable__loadDesignSystem, compile, compileAst, postcssPluginWarning as default };
declare function postcssPluginWarning(): void;
export { postcssPluginWarning as default };

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

export { P as PluginUtils } from './resolve-config-QUZ9b-Gn.mjs';
import { b as PluginFn, C as Config, c as PluginWithConfig, d as PluginWithOptions } from './types-DWdTiksJ.mjs';
export { a as PluginAPI, P as PluginsConfig, T as ThemeConfig } from './types-DWdTiksJ.mjs';
import './colors.mjs';
declare function createPlugin(handler: PluginFn, config?: Partial<Config>): PluginWithConfig;
declare namespace createPlugin {
var withOptions: <T>(pluginFunction: (options?: T) => PluginFn, configFunction?: (options?: T) => Partial<Config>) => PluginWithOptions<T>;
}
export { Config, PluginFn as PluginCreator, PluginWithConfig, createPlugin as default };
import { N as NamedUtilityValue, P as PluginUtils } from './resolve-config-B4yBzhca.js';
import './colors-C__qRT83.js';
/**
* The source code for one or more nodes in the AST
*
* This generally corresponds to a stylesheet
*/
interface Source {
/**
* The path to the file that contains the referenced source code
*
* If this references the *output* source code, this is `null`.
*/
file: string | null;
/**
* The referenced source code
*/
code: string;
}
/**
* The file and offsets within it that this node covers
*
* This can represent either:
* - A location in the original CSS which caused this node to be created
* - A location in the output CSS where this node resides
*/
type SourceLocation = [source: Source, start: number, end: number];
type Config = UserConfig;
type PluginFn = (api: PluginAPI) => void;
type PluginWithConfig = {
handler: PluginFn;
config?: UserConfig;
/** @internal */
reference?: boolean;
src?: SourceLocation | undefined;
};
type PluginWithOptions<T> = {
(options?: T): PluginWithConfig;
__isOptionsFunction: true;
};
type Plugin = PluginFn | PluginWithConfig | PluginWithOptions<any>;
type PluginAPI = {
addBase(base: CssInJs): void;
addVariant(name: string, variant: string | string[] | CssInJs): void;
matchVariant<T = string>(name: string, cb: (value: T | string, extra: {
modifier: string | null;
}) => string | string[], options?: {
values?: Record<string, T>;
sort?(a: {
value: T | string;
modifier: string | null;
}, b: {
value: T | string;
modifier: string | null;
}): number;
}): void;
addUtilities(utilities: Record<string, CssInJs | CssInJs[]> | Record<string, CssInJs | CssInJs[]>[], options?: {}): void;
matchUtilities(utilities: Record<string, (value: string, extra: {
modifier: string | null;
}) => CssInJs | CssInJs[]>, options?: Partial<{
type: string | string[];
supportsNegativeValues: boolean;
values: Record<string, string> & {
__BARE_VALUE__?: (value: NamedUtilityValue) => string | undefined;
};
modifiers: 'any' | Record<string, string>;
}>): void;
addComponents(utilities: Record<string, CssInJs> | Record<string, CssInJs>[], options?: {}): void;
matchComponents(utilities: Record<string, (value: string, extra: {
modifier: string | null;
}) => CssInJs>, options?: Partial<{
type: string | string[];
supportsNegativeValues: boolean;
values: Record<string, string> & {
__BARE_VALUE__?: (value: NamedUtilityValue) => string | undefined;
};
modifiers: 'any' | Record<string, string>;
}>): void;
theme(path: string, defaultValue?: any): any;
config(path?: string, defaultValue?: any): any;
prefix(className: string): string;
};
type CssInJs = {
[key: string]: string | string[] | CssInJs | CssInJs[];
};
type ResolvableTo<T> = T | ((utils: PluginUtils) => T);
type ThemeValue = ResolvableTo<Record<string, unknown>> | null | undefined;
type ThemeConfig = Record<string, ThemeValue> & {
extend?: Record<string, ThemeValue>;
};
type ContentFile = string | {
raw: string;
extension?: string;
};
type DarkModeStrategy = false | 'media' | 'class' | ['class', string] | 'selector' | ['selector', string] | ['variant', string | string[]];
interface UserConfig {
presets?: UserConfig[];
theme?: ThemeConfig;
plugins?: Plugin[];
}
interface UserConfig {
content?: ContentFile[] | {
relative?: boolean;
files: ContentFile[];
};
}
interface UserConfig {
darkMode?: DarkModeStrategy;
}
interface UserConfig {
prefix?: string;
}
interface UserConfig {
blocklist?: string[];
}
interface UserConfig {
important?: boolean | string;
}
interface UserConfig {
future?: 'all' | Record<string, boolean>;
}
interface UserConfig {
experimental?: 'all' | Record<string, boolean>;
}
declare function createPlugin(handler: PluginFn, config?: Partial<Config>): PluginWithConfig;
declare namespace createPlugin {
var withOptions: <T>(pluginFunction: (options?: T) => PluginFn, configFunction?: (options?: T) => Partial<Config>) => PluginWithOptions<T>;
}
export { createPlugin as default };
"use strict";function g(i,n){return{handler:i,config:n}}g.withOptions=function(i,n=()=>({})){function t(o){return{handler:i(o),config:n(o)}}return t.__isOptionsFunction=!0,t};var u=g;module.exports=u;
function g(i,n){return{handler:i,config:n}}g.withOptions=function(i,n=()=>({})){function t(o){return{handler:i(o),config:n(o)}}return t.__isOptionsFunction=!0,t};var u=g;export{u as default};
import { _ as _default } from './colors-C__qRT83.js';
type NamedUtilityValue = {
kind: 'named';
/**
* ```
* bg-red-500
* ^^^^^^^
*
* w-1/2
* ^
* ```
*/
value: string;
/**
* ```
* w-1/2
* ^^^
* ```
*/
fraction: string | null;
};
type PluginUtils = {
theme: (keypath: string, defaultValue?: any) => any;
colors: typeof _default;
};
export type { NamedUtilityValue as N, PluginUtils as P };
import _default from './colors.mjs';
type ArbitraryUtilityValue = {
kind: 'arbitrary';
/**
* ```
* bg-[color:var(--my-color)]
* ^^^^^
*
* bg-(color:--my-color)
* ^^^^^
* ```
*/
dataType: string | null;
/**
* ```
* bg-[#0088cc]
* ^^^^^^^
*
* bg-[var(--my_variable)]
* ^^^^^^^^^^^^^^^^^^
*
* bg-(--my_variable)
* ^^^^^^^^^^^^^^
* ```
*/
value: string;
};
type NamedUtilityValue = {
kind: 'named';
/**
* ```
* bg-red-500
* ^^^^^^^
*
* w-1/2
* ^
* ```
*/
value: string;
/**
* ```
* w-1/2
* ^^^
* ```
*/
fraction: string | null;
};
type ArbitraryModifier = {
kind: 'arbitrary';
/**
* ```
* bg-red-500/[50%]
* ^^^
* ```
*/
value: string;
};
type NamedModifier = {
kind: 'named';
/**
* ```
* bg-red-500/50
* ^^
* ```
*/
value: string;
};
type ArbitraryVariantValue = {
kind: 'arbitrary';
value: string;
};
type NamedVariantValue = {
kind: 'named';
value: string;
};
type Variant =
/**
* Arbitrary variants are variants that take a selector and generate a variant
* on the fly.
*
* E.g.: `[&_p]`
*/
{
kind: 'arbitrary';
selector: string;
relative: boolean;
}
/**
* Static variants are variants that don't take any arguments.
*
* E.g.: `hover`
*/
| {
kind: 'static';
root: string;
}
/**
* Functional variants are variants that can take an argument. The argument is
* either a named variant value or an arbitrary variant value.
*
* E.g.:
*
* - `aria-disabled`
* - `aria-[disabled]`
* - `@container-size` -> @container, with named value `size`
* - `@container-[inline-size]` -> @container, with arbitrary variant value `inline-size`
* - `@container` -> @container, with no value
*/
| {
kind: 'functional';
root: string;
value: ArbitraryVariantValue | NamedVariantValue | null;
modifier: ArbitraryModifier | NamedModifier | null;
}
/**
* Compound variants are variants that take another variant as an argument.
*
* E.g.:
*
* - `has-[&_p]`
* - `group-*`
* - `peer-*`
*/
| {
kind: 'compound';
root: string;
modifier: ArbitraryModifier | NamedModifier | null;
variant: Variant;
};
type Candidate =
/**
* Arbitrary candidates are candidates that register utilities on the fly with
* a property and a value.
*
* E.g.:
*
* - `[color:red]`
* - `[color:red]/50`
* - `[color:red]/50!`
*/
{
kind: 'arbitrary';
property: string;
value: string;
modifier: ArbitraryModifier | NamedModifier | null;
variants: Variant[];
important: boolean;
raw: string;
}
/**
* Static candidates are candidates that don't take any arguments.
*
* E.g.:
*
* - `underline`
* - `box-border`
*/
| {
kind: 'static';
root: string;
variants: Variant[];
important: boolean;
raw: string;
}
/**
* Functional candidates are candidates that can take an argument.
*
* E.g.:
*
* - `bg-red-500`
* - `bg-[#0088cc]`
* - `w-1/2`
*/
| {
kind: 'functional';
root: string;
value: ArbitraryUtilityValue | NamedUtilityValue | null;
modifier: ArbitraryModifier | NamedModifier | null;
variants: Variant[];
important: boolean;
raw: string;
};
type PluginUtils = {
theme: (keypath: string, defaultValue?: any) => any;
colors: typeof _default;
};
export type { Candidate as C, NamedUtilityValue as N, PluginUtils as P, Variant as V };
import { N as NamedUtilityValue, P as PluginUtils } from './resolve-config-QUZ9b-Gn.mjs';
/**
* The source code for one or more nodes in the AST
*
* This generally corresponds to a stylesheet
*/
interface Source {
/**
* The path to the file that contains the referenced source code
*
* If this references the *output* source code, this is `null`.
*/
file: string | null;
/**
* The referenced source code
*/
code: string;
}
/**
* The file and offsets within it that this node covers
*
* This can represent either:
* - A location in the original CSS which caused this node to be created
* - A location in the output CSS where this node resides
*/
type SourceLocation = [source: Source, start: number, end: number];
type Config = UserConfig;
type PluginFn = (api: PluginAPI) => void;
type PluginWithConfig = {
handler: PluginFn;
config?: UserConfig;
/** @internal */
reference?: boolean;
src?: SourceLocation | undefined;
};
type PluginWithOptions<T> = {
(options?: T): PluginWithConfig;
__isOptionsFunction: true;
};
type Plugin = PluginFn | PluginWithConfig | PluginWithOptions<any>;
type PluginAPI = {
addBase(base: CssInJs): void;
addVariant(name: string, variant: string | string[] | CssInJs): void;
matchVariant<T = string>(name: string, cb: (value: T | string, extra: {
modifier: string | null;
}) => string | string[], options?: {
values?: Record<string, T>;
sort?(a: {
value: T | string;
modifier: string | null;
}, b: {
value: T | string;
modifier: string | null;
}): number;
}): void;
addUtilities(utilities: Record<string, CssInJs | CssInJs[]> | Record<string, CssInJs | CssInJs[]>[], options?: {}): void;
matchUtilities(utilities: Record<string, (value: string, extra: {
modifier: string | null;
}) => CssInJs | CssInJs[]>, options?: Partial<{
type: string | string[];
supportsNegativeValues: boolean;
values: Record<string, string> & {
__BARE_VALUE__?: (value: NamedUtilityValue) => string | undefined;
};
modifiers: 'any' | Record<string, string>;
}>): void;
addComponents(utilities: Record<string, CssInJs> | Record<string, CssInJs>[], options?: {}): void;
matchComponents(utilities: Record<string, (value: string, extra: {
modifier: string | null;
}) => CssInJs>, options?: Partial<{
type: string | string[];
supportsNegativeValues: boolean;
values: Record<string, string> & {
__BARE_VALUE__?: (value: NamedUtilityValue) => string | undefined;
};
modifiers: 'any' | Record<string, string>;
}>): void;
theme(path: string, defaultValue?: any): any;
config(path?: string, defaultValue?: any): any;
prefix(className: string): string;
};
type CssInJs = {
[key: string]: string | string[] | CssInJs | CssInJs[];
};
type ResolvableTo<T> = T | ((utils: PluginUtils) => T);
type ThemeValue = ResolvableTo<Record<string, unknown>> | null | undefined;
type ThemeConfig = Record<string, ThemeValue> & {
extend?: Record<string, ThemeValue>;
};
type ContentFile = string | {
raw: string;
extension?: string;
};
type DarkModeStrategy = false | 'media' | 'class' | ['class', string] | 'selector' | ['selector', string] | ['variant', string | string[]];
interface UserConfig {
presets?: UserConfig[];
theme?: ThemeConfig;
plugins?: Plugin[];
}
interface UserConfig {
content?: ContentFile[] | {
relative?: boolean;
files: ContentFile[];
};
}
interface UserConfig {
darkMode?: DarkModeStrategy;
}
interface UserConfig {
prefix?: string;
}
interface UserConfig {
blocklist?: string[];
}
interface UserConfig {
important?: boolean | string;
}
interface UserConfig {
future?: 'all' | Record<string, boolean>;
}
interface UserConfig {
experimental?: 'all' | Record<string, boolean>;
}
export type { Config as C, Plugin as P, SourceLocation as S, ThemeConfig as T, UserConfig as U, PluginAPI as a, PluginFn as b, PluginWithConfig as c, PluginWithOptions as d };
/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Remove default margins and padding
3. Reset all borders.
*/
*,
::after,
::before,
::backdrop,
::file-selector-button {
box-sizing: border-box; /* 1 */
margin: 0; /* 2 */
padding: 0; /* 2 */
border: 0 solid; /* 3 */
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
7. Disable tap highlights on iOS.
*/
html,
:host {
line-height: 1.5; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
tab-size: 4; /* 3 */
font-family: --theme(
--default-font-family,
ui-sans-serif,
system-ui,
sans-serif,
'Apple Color Emoji',
'Segoe UI Emoji',
'Segoe UI Symbol',
'Noto Color Emoji'
); /* 4 */
font-feature-settings: --theme(--default-font-feature-settings, normal); /* 5 */
font-variation-settings: --theme(--default-font-variation-settings, normal); /* 6 */
-webkit-tap-highlight-color: transparent; /* 7 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Reset the default border style to a 1px solid border.
*/
hr {
height: 0; /* 1 */
color: inherit; /* 2 */
border-top-width: 1px; /* 3 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
-webkit-text-decoration: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the user's configured `mono` font-family by default.
2. Use the user's configured `mono` font-feature-settings by default.
3. Use the user's configured `mono` font-variation-settings by default.
4. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: --theme(
--default-mono-font-family,
ui-monospace,
SFMono-Regular,
Menlo,
Monaco,
Consolas,
'Liberation Mono',
'Courier New',
monospace
); /* 1 */
font-feature-settings: --theme(--default-mono-font-feature-settings, normal); /* 2 */
font-variation-settings: --theme(--default-mono-font-variation-settings, normal); /* 3 */
font-size: 1em; /* 4 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
text-indent: 0; /* 1 */
border-color: inherit; /* 2 */
border-collapse: collapse; /* 3 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring:where(:not(iframe)) {
outline: auto;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Make lists unstyled by default.
*/
ol,
ul,
menu {
list-style: none;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block; /* 1 */
vertical-align: middle; /* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
/*
1. Inherit font styles in all browsers.
2. Remove border radius in all browsers.
3. Remove background color in all browsers.
4. Ensure consistent opacity for disabled states in all browsers.
*/
button,
input,
select,
optgroup,
textarea,
::file-selector-button {
font: inherit; /* 1 */
font-feature-settings: inherit; /* 1 */
font-variation-settings: inherit; /* 1 */
letter-spacing: inherit; /* 1 */
color: inherit; /* 1 */
border-radius: 0; /* 2 */
background-color: transparent; /* 3 */
opacity: 1; /* 4 */
}
/*
Restore default font weight.
*/
:where(select:is([multiple], [size])) optgroup {
font-weight: bolder;
}
/*
Restore indentation.
*/
:where(select:is([multiple], [size])) optgroup option {
padding-inline-start: 20px;
}
/*
Restore space after button.
*/
::file-selector-button {
margin-inline-end: 4px;
}
/*
Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
*/
::placeholder {
opacity: 1;
}
/*
Set the default placeholder color to a semi-transparent version of the current text color in browsers that do not
crash when using `color-mix(…)` with `currentcolor`. (https://github.com/tailwindlabs/tailwindcss/issues/17194)
*/
@supports (not (-webkit-appearance: -apple-pay-button)) /* Not Safari */ or
(contain-intrinsic-size: 1px) /* Safari 17+ */ {
::placeholder {
color: color-mix(in oklab, currentcolor 50%, transparent);
}
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
1. Ensure date/time inputs have the same height when empty in iOS Safari.
2. Ensure text alignment can be changed on date/time inputs in iOS Safari.
*/
::-webkit-date-and-time-value {
min-height: 1lh; /* 1 */
text-align: inherit; /* 2 */
}
/*
Prevent height from changing on date/time inputs in macOS Safari when the input is set to `display: block`.
*/
::-webkit-datetime-edit {
display: inline-flex;
}
/*
Remove excess padding from pseudo-elements in date/time inputs to ensure consistent height across browsers.
*/
::-webkit-datetime-edit-fields-wrapper {
padding: 0;
}
::-webkit-datetime-edit,
::-webkit-datetime-edit-year-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-minute-field,
::-webkit-datetime-edit-second-field,
::-webkit-datetime-edit-millisecond-field,
::-webkit-datetime-edit-meridiem-field {
padding-block: 0;
}
/*
Center dropdown marker shown on inputs with paired `<datalist>`s in Chrome. (https://github.com/tailwindlabs/tailwindcss/issues/18499)
*/
::-webkit-calendar-picker-indicator {
line-height: 1;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Correct the inability to style the border radius in iOS Safari.
*/
button,
input:where([type='button'], [type='reset'], [type='submit']),
::file-selector-button {
appearance: button;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
Make elements with the HTML hidden attribute stay hidden by default.
*/
[hidden]:where(:not([hidden='until-found'])) {
display: none !important;
}
@theme default {
--font-sans:
ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
--font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
--font-mono:
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New',
monospace;
--color-red-50: oklch(97.1% 0.013 17.38);
--color-red-100: oklch(93.6% 0.032 17.717);
--color-red-200: oklch(88.5% 0.062 18.334);
--color-red-300: oklch(80.8% 0.114 19.571);
--color-red-400: oklch(70.4% 0.191 22.216);
--color-red-500: oklch(63.7% 0.237 25.331);
--color-red-600: oklch(57.7% 0.245 27.325);
--color-red-700: oklch(50.5% 0.213 27.518);
--color-red-800: oklch(44.4% 0.177 26.899);
--color-red-900: oklch(39.6% 0.141 25.723);
--color-red-950: oklch(25.8% 0.092 26.042);
--color-orange-50: oklch(98% 0.016 73.684);
--color-orange-100: oklch(95.4% 0.038 75.164);
--color-orange-200: oklch(90.1% 0.076 70.697);
--color-orange-300: oklch(83.7% 0.128 66.29);
--color-orange-400: oklch(75% 0.183 55.934);
--color-orange-500: oklch(70.5% 0.213 47.604);
--color-orange-600: oklch(64.6% 0.222 41.116);
--color-orange-700: oklch(55.3% 0.195 38.402);
--color-orange-800: oklch(47% 0.157 37.304);
--color-orange-900: oklch(40.8% 0.123 38.172);
--color-orange-950: oklch(26.6% 0.079 36.259);
--color-amber-50: oklch(98.7% 0.022 95.277);
--color-amber-100: oklch(96.2% 0.059 95.617);
--color-amber-200: oklch(92.4% 0.12 95.746);
--color-amber-300: oklch(87.9% 0.169 91.605);
--color-amber-400: oklch(82.8% 0.189 84.429);
--color-amber-500: oklch(76.9% 0.188 70.08);
--color-amber-600: oklch(66.6% 0.179 58.318);
--color-amber-700: oklch(55.5% 0.163 48.998);
--color-amber-800: oklch(47.3% 0.137 46.201);
--color-amber-900: oklch(41.4% 0.112 45.904);
--color-amber-950: oklch(27.9% 0.077 45.635);
--color-yellow-50: oklch(98.7% 0.026 102.212);
--color-yellow-100: oklch(97.3% 0.071 103.193);
--color-yellow-200: oklch(94.5% 0.129 101.54);
--color-yellow-300: oklch(90.5% 0.182 98.111);
--color-yellow-400: oklch(85.2% 0.199 91.936);
--color-yellow-500: oklch(79.5% 0.184 86.047);
--color-yellow-600: oklch(68.1% 0.162 75.834);
--color-yellow-700: oklch(55.4% 0.135 66.442);
--color-yellow-800: oklch(47.6% 0.114 61.907);
--color-yellow-900: oklch(42.1% 0.095 57.708);
--color-yellow-950: oklch(28.6% 0.066 53.813);
--color-lime-50: oklch(98.6% 0.031 120.757);
--color-lime-100: oklch(96.7% 0.067 122.328);
--color-lime-200: oklch(93.8% 0.127 124.321);
--color-lime-300: oklch(89.7% 0.196 126.665);
--color-lime-400: oklch(84.1% 0.238 128.85);
--color-lime-500: oklch(76.8% 0.233 130.85);
--color-lime-600: oklch(64.8% 0.2 131.684);
--color-lime-700: oklch(53.2% 0.157 131.589);
--color-lime-800: oklch(45.3% 0.124 130.933);
--color-lime-900: oklch(40.5% 0.101 131.063);
--color-lime-950: oklch(27.4% 0.072 132.109);
--color-green-50: oklch(98.2% 0.018 155.826);
--color-green-100: oklch(96.2% 0.044 156.743);
--color-green-200: oklch(92.5% 0.084 155.995);
--color-green-300: oklch(87.1% 0.15 154.449);
--color-green-400: oklch(79.2% 0.209 151.711);
--color-green-500: oklch(72.3% 0.219 149.579);
--color-green-600: oklch(62.7% 0.194 149.214);
--color-green-700: oklch(52.7% 0.154 150.069);
--color-green-800: oklch(44.8% 0.119 151.328);
--color-green-900: oklch(39.3% 0.095 152.535);
--color-green-950: oklch(26.6% 0.065 152.934);
--color-emerald-50: oklch(97.9% 0.021 166.113);
--color-emerald-100: oklch(95% 0.052 163.051);
--color-emerald-200: oklch(90.5% 0.093 164.15);
--color-emerald-300: oklch(84.5% 0.143 164.978);
--color-emerald-400: oklch(76.5% 0.177 163.223);
--color-emerald-500: oklch(69.6% 0.17 162.48);
--color-emerald-600: oklch(59.6% 0.145 163.225);
--color-emerald-700: oklch(50.8% 0.118 165.612);
--color-emerald-800: oklch(43.2% 0.095 166.913);
--color-emerald-900: oklch(37.8% 0.077 168.94);
--color-emerald-950: oklch(26.2% 0.051 172.552);
--color-teal-50: oklch(98.4% 0.014 180.72);
--color-teal-100: oklch(95.3% 0.051 180.801);
--color-teal-200: oklch(91% 0.096 180.426);
--color-teal-300: oklch(85.5% 0.138 181.071);
--color-teal-400: oklch(77.7% 0.152 181.912);
--color-teal-500: oklch(70.4% 0.14 182.503);
--color-teal-600: oklch(60% 0.118 184.704);
--color-teal-700: oklch(51.1% 0.096 186.391);
--color-teal-800: oklch(43.7% 0.078 188.216);
--color-teal-900: oklch(38.6% 0.063 188.416);
--color-teal-950: oklch(27.7% 0.046 192.524);
--color-cyan-50: oklch(98.4% 0.019 200.873);
--color-cyan-100: oklch(95.6% 0.045 203.388);
--color-cyan-200: oklch(91.7% 0.08 205.041);
--color-cyan-300: oklch(86.5% 0.127 207.078);
--color-cyan-400: oklch(78.9% 0.154 211.53);
--color-cyan-500: oklch(71.5% 0.143 215.221);
--color-cyan-600: oklch(60.9% 0.126 221.723);
--color-cyan-700: oklch(52% 0.105 223.128);
--color-cyan-800: oklch(45% 0.085 224.283);
--color-cyan-900: oklch(39.8% 0.07 227.392);
--color-cyan-950: oklch(30.2% 0.056 229.695);
--color-sky-50: oklch(97.7% 0.013 236.62);
--color-sky-100: oklch(95.1% 0.026 236.824);
--color-sky-200: oklch(90.1% 0.058 230.902);
--color-sky-300: oklch(82.8% 0.111 230.318);
--color-sky-400: oklch(74.6% 0.16 232.661);
--color-sky-500: oklch(68.5% 0.169 237.323);
--color-sky-600: oklch(58.8% 0.158 241.966);
--color-sky-700: oklch(50% 0.134 242.749);
--color-sky-800: oklch(44.3% 0.11 240.79);
--color-sky-900: oklch(39.1% 0.09 240.876);
--color-sky-950: oklch(29.3% 0.066 243.157);
--color-blue-50: oklch(97% 0.014 254.604);
--color-blue-100: oklch(93.2% 0.032 255.585);
--color-blue-200: oklch(88.2% 0.059 254.128);
--color-blue-300: oklch(80.9% 0.105 251.813);
--color-blue-400: oklch(70.7% 0.165 254.624);
--color-blue-500: oklch(62.3% 0.214 259.815);
--color-blue-600: oklch(54.6% 0.245 262.881);
--color-blue-700: oklch(48.8% 0.243 264.376);
--color-blue-800: oklch(42.4% 0.199 265.638);
--color-blue-900: oklch(37.9% 0.146 265.522);
--color-blue-950: oklch(28.2% 0.091 267.935);
--color-indigo-50: oklch(96.2% 0.018 272.314);
--color-indigo-100: oklch(93% 0.034 272.788);
--color-indigo-200: oklch(87% 0.065 274.039);
--color-indigo-300: oklch(78.5% 0.115 274.713);
--color-indigo-400: oklch(67.3% 0.182 276.935);
--color-indigo-500: oklch(58.5% 0.233 277.117);
--color-indigo-600: oklch(51.1% 0.262 276.966);
--color-indigo-700: oklch(45.7% 0.24 277.023);
--color-indigo-800: oklch(39.8% 0.195 277.366);
--color-indigo-900: oklch(35.9% 0.144 278.697);
--color-indigo-950: oklch(25.7% 0.09 281.288);
--color-violet-50: oklch(96.9% 0.016 293.756);
--color-violet-100: oklch(94.3% 0.029 294.588);
--color-violet-200: oklch(89.4% 0.057 293.283);
--color-violet-300: oklch(81.1% 0.111 293.571);
--color-violet-400: oklch(70.2% 0.183 293.541);
--color-violet-500: oklch(60.6% 0.25 292.717);
--color-violet-600: oklch(54.1% 0.281 293.009);
--color-violet-700: oklch(49.1% 0.27 292.581);
--color-violet-800: oklch(43.2% 0.232 292.759);
--color-violet-900: oklch(38% 0.189 293.745);
--color-violet-950: oklch(28.3% 0.141 291.089);
--color-purple-50: oklch(97.7% 0.014 308.299);
--color-purple-100: oklch(94.6% 0.033 307.174);
--color-purple-200: oklch(90.2% 0.063 306.703);
--color-purple-300: oklch(82.7% 0.119 306.383);
--color-purple-400: oklch(71.4% 0.203 305.504);
--color-purple-500: oklch(62.7% 0.265 303.9);
--color-purple-600: oklch(55.8% 0.288 302.321);
--color-purple-700: oklch(49.6% 0.265 301.924);
--color-purple-800: oklch(43.8% 0.218 303.724);
--color-purple-900: oklch(38.1% 0.176 304.987);
--color-purple-950: oklch(29.1% 0.149 302.717);
--color-fuchsia-50: oklch(97.7% 0.017 320.058);
--color-fuchsia-100: oklch(95.2% 0.037 318.852);
--color-fuchsia-200: oklch(90.3% 0.076 319.62);
--color-fuchsia-300: oklch(83.3% 0.145 321.434);
--color-fuchsia-400: oklch(74% 0.238 322.16);
--color-fuchsia-500: oklch(66.7% 0.295 322.15);
--color-fuchsia-600: oklch(59.1% 0.293 322.896);
--color-fuchsia-700: oklch(51.8% 0.253 323.949);
--color-fuchsia-800: oklch(45.2% 0.211 324.591);
--color-fuchsia-900: oklch(40.1% 0.17 325.612);
--color-fuchsia-950: oklch(29.3% 0.136 325.661);
--color-pink-50: oklch(97.1% 0.014 343.198);
--color-pink-100: oklch(94.8% 0.028 342.258);
--color-pink-200: oklch(89.9% 0.061 343.231);
--color-pink-300: oklch(82.3% 0.12 346.018);
--color-pink-400: oklch(71.8% 0.202 349.761);
--color-pink-500: oklch(65.6% 0.241 354.308);
--color-pink-600: oklch(59.2% 0.249 0.584);
--color-pink-700: oklch(52.5% 0.223 3.958);
--color-pink-800: oklch(45.9% 0.187 3.815);
--color-pink-900: oklch(40.8% 0.153 2.432);
--color-pink-950: oklch(28.4% 0.109 3.907);
--color-rose-50: oklch(96.9% 0.015 12.422);
--color-rose-100: oklch(94.1% 0.03 12.58);
--color-rose-200: oklch(89.2% 0.058 10.001);
--color-rose-300: oklch(81% 0.117 11.638);
--color-rose-400: oklch(71.2% 0.194 13.428);
--color-rose-500: oklch(64.5% 0.246 16.439);
--color-rose-600: oklch(58.6% 0.253 17.585);
--color-rose-700: oklch(51.4% 0.222 16.935);
--color-rose-800: oklch(45.5% 0.188 13.697);
--color-rose-900: oklch(41% 0.159 10.272);
--color-rose-950: oklch(27.1% 0.105 12.094);
--color-slate-50: oklch(98.4% 0.003 247.858);
--color-slate-100: oklch(96.8% 0.007 247.896);
--color-slate-200: oklch(92.9% 0.013 255.508);
--color-slate-300: oklch(86.9% 0.022 252.894);
--color-slate-400: oklch(70.4% 0.04 256.788);
--color-slate-500: oklch(55.4% 0.046 257.417);
--color-slate-600: oklch(44.6% 0.043 257.281);
--color-slate-700: oklch(37.2% 0.044 257.287);
--color-slate-800: oklch(27.9% 0.041 260.031);
--color-slate-900: oklch(20.8% 0.042 265.755);
--color-slate-950: oklch(12.9% 0.042 264.695);
--color-gray-50: oklch(98.5% 0.002 247.839);
--color-gray-100: oklch(96.7% 0.003 264.542);
--color-gray-200: oklch(92.8% 0.006 264.531);
--color-gray-300: oklch(87.2% 0.01 258.338);
--color-gray-400: oklch(70.7% 0.022 261.325);
--color-gray-500: oklch(55.1% 0.027 264.364);
--color-gray-600: oklch(44.6% 0.03 256.802);
--color-gray-700: oklch(37.3% 0.034 259.733);
--color-gray-800: oklch(27.8% 0.033 256.848);
--color-gray-900: oklch(21% 0.034 264.665);
--color-gray-950: oklch(13% 0.028 261.692);
--color-zinc-50: oklch(98.5% 0 0);
--color-zinc-100: oklch(96.7% 0.001 286.375);
--color-zinc-200: oklch(92% 0.004 286.32);
--color-zinc-300: oklch(87.1% 0.006 286.286);
--color-zinc-400: oklch(70.5% 0.015 286.067);
--color-zinc-500: oklch(55.2% 0.016 285.938);
--color-zinc-600: oklch(44.2% 0.017 285.786);
--color-zinc-700: oklch(37% 0.013 285.805);
--color-zinc-800: oklch(27.4% 0.006 286.033);
--color-zinc-900: oklch(21% 0.006 285.885);
--color-zinc-950: oklch(14.1% 0.005 285.823);
--color-neutral-50: oklch(98.5% 0 0);
--color-neutral-100: oklch(97% 0 0);
--color-neutral-200: oklch(92.2% 0 0);
--color-neutral-300: oklch(87% 0 0);
--color-neutral-400: oklch(70.8% 0 0);
--color-neutral-500: oklch(55.6% 0 0);
--color-neutral-600: oklch(43.9% 0 0);
--color-neutral-700: oklch(37.1% 0 0);
--color-neutral-800: oklch(26.9% 0 0);
--color-neutral-900: oklch(20.5% 0 0);
--color-neutral-950: oklch(14.5% 0 0);
--color-stone-50: oklch(98.5% 0.001 106.423);
--color-stone-100: oklch(97% 0.001 106.424);
--color-stone-200: oklch(92.3% 0.003 48.717);
--color-stone-300: oklch(86.9% 0.005 56.366);
--color-stone-400: oklch(70.9% 0.01 56.259);
--color-stone-500: oklch(55.3% 0.013 58.071);
--color-stone-600: oklch(44.4% 0.011 73.639);
--color-stone-700: oklch(37.4% 0.01 67.558);
--color-stone-800: oklch(26.8% 0.007 34.298);
--color-stone-900: oklch(21.6% 0.006 56.043);
--color-stone-950: oklch(14.7% 0.004 49.25);
--color-mauve-50: oklch(98.5% 0 0);
--color-mauve-100: oklch(96% 0.003 325.6);
--color-mauve-200: oklch(92.2% 0.005 325.62);
--color-mauve-300: oklch(86.5% 0.012 325.68);
--color-mauve-400: oklch(71.1% 0.019 323.02);
--color-mauve-500: oklch(54.2% 0.034 322.5);
--color-mauve-600: oklch(43.5% 0.029 321.78);
--color-mauve-700: oklch(36.4% 0.029 323.89);
--color-mauve-800: oklch(26.3% 0.024 320.12);
--color-mauve-900: oklch(21.2% 0.019 322.12);
--color-mauve-950: oklch(14.5% 0.008 326);
--color-olive-50: oklch(98.8% 0.003 106.5);
--color-olive-100: oklch(96.6% 0.005 106.5);
--color-olive-200: oklch(93% 0.007 106.5);
--color-olive-300: oklch(88% 0.011 106.6);
--color-olive-400: oklch(73.7% 0.021 106.9);
--color-olive-500: oklch(58% 0.031 107.3);
--color-olive-600: oklch(46.6% 0.025 107.3);
--color-olive-700: oklch(39.4% 0.023 107.4);
--color-olive-800: oklch(28.6% 0.016 107.4);
--color-olive-900: oklch(22.8% 0.013 107.4);
--color-olive-950: oklch(15.3% 0.006 107.1);
--color-mist-50: oklch(98.7% 0.002 197.1);
--color-mist-100: oklch(96.3% 0.002 197.1);
--color-mist-200: oklch(92.5% 0.005 214.3);
--color-mist-300: oklch(87.2% 0.007 219.6);
--color-mist-400: oklch(72.3% 0.014 214.4);
--color-mist-500: oklch(56% 0.021 213.5);
--color-mist-600: oklch(45% 0.017 213.2);
--color-mist-700: oklch(37.8% 0.015 216);
--color-mist-800: oklch(27.5% 0.011 216.9);
--color-mist-900: oklch(21.8% 0.008 223.9);
--color-mist-950: oklch(14.8% 0.004 228.8);
--color-taupe-50: oklch(98.6% 0.002 67.8);
--color-taupe-100: oklch(96% 0.002 17.2);
--color-taupe-200: oklch(92.2% 0.005 34.3);
--color-taupe-300: oklch(86.8% 0.007 39.5);
--color-taupe-400: oklch(71.4% 0.014 41.2);
--color-taupe-500: oklch(54.7% 0.021 43.1);
--color-taupe-600: oklch(43.8% 0.017 39.3);
--color-taupe-700: oklch(36.7% 0.016 35.7);
--color-taupe-800: oklch(26.8% 0.011 36.5);
--color-taupe-900: oklch(21.4% 0.009 43.1);
--color-taupe-950: oklch(14.7% 0.004 49.3);
--color-black: #000;
--color-white: #fff;
--spacing: 0.25rem;
--breakpoint-sm: 40rem;
--breakpoint-md: 48rem;
--breakpoint-lg: 64rem;
--breakpoint-xl: 80rem;
--breakpoint-2xl: 96rem;
--container-3xs: 16rem;
--container-2xs: 18rem;
--container-xs: 20rem;
--container-sm: 24rem;
--container-md: 28rem;
--container-lg: 32rem;
--container-xl: 36rem;
--container-2xl: 42rem;
--container-3xl: 48rem;
--container-4xl: 56rem;
--container-5xl: 64rem;
--container-6xl: 72rem;
--container-7xl: 80rem;
--text-xs: 0.75rem;
--text-xs--line-height: calc(1 / 0.75);
--text-sm: 0.875rem;
--text-sm--line-height: calc(1.25 / 0.875);
--text-base: 1rem;
--text-base--line-height: calc(1.5 / 1);
--text-lg: 1.125rem;
--text-lg--line-height: calc(1.75 / 1.125);
--text-xl: 1.25rem;
--text-xl--line-height: calc(1.75 / 1.25);
--text-2xl: 1.5rem;
--text-2xl--line-height: calc(2 / 1.5);
--text-3xl: 1.875rem;
--text-3xl--line-height: calc(2.25 / 1.875);
--text-4xl: 2.25rem;
--text-4xl--line-height: calc(2.5 / 2.25);
--text-5xl: 3rem;
--text-5xl--line-height: 1;
--text-6xl: 3.75rem;
--text-6xl--line-height: 1;
--text-7xl: 4.5rem;
--text-7xl--line-height: 1;
--text-8xl: 6rem;
--text-8xl--line-height: 1;
--text-9xl: 8rem;
--text-9xl--line-height: 1;
--font-weight-thin: 100;
--font-weight-extralight: 200;
--font-weight-light: 300;
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
--font-weight-extrabold: 800;
--font-weight-black: 900;
--tracking-tighter: -0.05em;
--tracking-tight: -0.025em;
--tracking-normal: 0em;
--tracking-wide: 0.025em;
--tracking-wider: 0.05em;
--tracking-widest: 0.1em;
--leading-tight: 1.25;
--leading-snug: 1.375;
--leading-normal: 1.5;
--leading-relaxed: 1.625;
--leading-loose: 2;
--radius-xs: 0.125rem;
--radius-sm: 0.25rem;
--radius-md: 0.375rem;
--radius-lg: 0.5rem;
--radius-xl: 0.75rem;
--radius-2xl: 1rem;
--radius-3xl: 1.5rem;
--radius-4xl: 2rem;
--shadow-2xs: 0 1px rgb(0 0 0 / 0.05);
--shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
--inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05);
--inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05);
--inset-shadow-sm: inset 0 2px 4px rgb(0 0 0 / 0.05);
--drop-shadow-xs: 0 1px 1px rgb(0 0 0 / 0.05);
--drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15);
--drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12);
--drop-shadow-lg: 0 4px 4px rgb(0 0 0 / 0.15);
--drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1);
--drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15);
--text-shadow-2xs: 0px 1px 0px rgb(0 0 0 / 0.15);
--text-shadow-xs: 0px 1px 1px rgb(0 0 0 / 0.2);
--text-shadow-sm:
0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075), 0px 2px 2px rgb(0 0 0 / 0.075);
--text-shadow-md:
0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1), 0px 2px 4px rgb(0 0 0 / 0.1);
--text-shadow-lg:
0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1);
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--animate-spin: spin 1s linear infinite;
--animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
--animate-bounce: bounce 1s infinite;
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@keyframes ping {
75%,
100% {
transform: scale(2);
opacity: 0;
}
}
@keyframes pulse {
50% {
opacity: 0.5;
}
}
@keyframes bounce {
0%,
100% {
transform: translateY(-25%);
animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
}
50% {
transform: none;
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
}
--blur-xs: 4px;
--blur-sm: 8px;
--blur-md: 12px;
--blur-lg: 16px;
--blur-xl: 24px;
--blur-2xl: 40px;
--blur-3xl: 64px;
--perspective-dramatic: 100px;
--perspective-near: 300px;
--perspective-normal: 500px;
--perspective-midrange: 800px;
--perspective-distant: 1200px;
--aspect-video: 16 / 9;
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: --theme(--font-sans, initial);
--default-font-feature-settings: --theme(--font-sans--font-feature-settings, initial);
--default-font-variation-settings: --theme(--font-sans--font-variation-settings, initial);
--default-mono-font-family: --theme(--font-mono, initial);
--default-mono-font-feature-settings: --theme(--font-mono--font-feature-settings, initial);
--default-mono-font-variation-settings: --theme(--font-mono--font-variation-settings, initial);
}
/* Deprecated */
@theme default inline reference {
--blur: 8px;
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
--drop-shadow: 0 1px 2px rgb(0 0 0 / 0.1), 0 1px 1px rgb(0 0 0 / 0.06);
--radius: 0.25rem;
--max-width-prose: 65ch;
}
+942
-3

@@ -1,5 +0,944 @@

@tailwind base;
@layer theme, base, components, utilities;
@tailwind components;
@layer theme {
@theme default {
--font-sans:
ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
--font-mono:
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
"Courier New", monospace;
@tailwind utilities;
--color-red-50: oklch(97.1% 0.013 17.38);
--color-red-100: oklch(93.6% 0.032 17.717);
--color-red-200: oklch(88.5% 0.062 18.334);
--color-red-300: oklch(80.8% 0.114 19.571);
--color-red-400: oklch(70.4% 0.191 22.216);
--color-red-500: oklch(63.7% 0.237 25.331);
--color-red-600: oklch(57.7% 0.245 27.325);
--color-red-700: oklch(50.5% 0.213 27.518);
--color-red-800: oklch(44.4% 0.177 26.899);
--color-red-900: oklch(39.6% 0.141 25.723);
--color-red-950: oklch(25.8% 0.092 26.042);
--color-orange-50: oklch(98% 0.016 73.684);
--color-orange-100: oklch(95.4% 0.038 75.164);
--color-orange-200: oklch(90.1% 0.076 70.697);
--color-orange-300: oklch(83.7% 0.128 66.29);
--color-orange-400: oklch(75% 0.183 55.934);
--color-orange-500: oklch(70.5% 0.213 47.604);
--color-orange-600: oklch(64.6% 0.222 41.116);
--color-orange-700: oklch(55.3% 0.195 38.402);
--color-orange-800: oklch(47% 0.157 37.304);
--color-orange-900: oklch(40.8% 0.123 38.172);
--color-orange-950: oklch(26.6% 0.079 36.259);
--color-amber-50: oklch(98.7% 0.022 95.277);
--color-amber-100: oklch(96.2% 0.059 95.617);
--color-amber-200: oklch(92.4% 0.12 95.746);
--color-amber-300: oklch(87.9% 0.169 91.605);
--color-amber-400: oklch(82.8% 0.189 84.429);
--color-amber-500: oklch(76.9% 0.188 70.08);
--color-amber-600: oklch(66.6% 0.179 58.318);
--color-amber-700: oklch(55.5% 0.163 48.998);
--color-amber-800: oklch(47.3% 0.137 46.201);
--color-amber-900: oklch(41.4% 0.112 45.904);
--color-amber-950: oklch(27.9% 0.077 45.635);
--color-yellow-50: oklch(98.7% 0.026 102.212);
--color-yellow-100: oklch(97.3% 0.071 103.193);
--color-yellow-200: oklch(94.5% 0.129 101.54);
--color-yellow-300: oklch(90.5% 0.182 98.111);
--color-yellow-400: oklch(85.2% 0.199 91.936);
--color-yellow-500: oklch(79.5% 0.184 86.047);
--color-yellow-600: oklch(68.1% 0.162 75.834);
--color-yellow-700: oklch(55.4% 0.135 66.442);
--color-yellow-800: oklch(47.6% 0.114 61.907);
--color-yellow-900: oklch(42.1% 0.095 57.708);
--color-yellow-950: oklch(28.6% 0.066 53.813);
--color-lime-50: oklch(98.6% 0.031 120.757);
--color-lime-100: oklch(96.7% 0.067 122.328);
--color-lime-200: oklch(93.8% 0.127 124.321);
--color-lime-300: oklch(89.7% 0.196 126.665);
--color-lime-400: oklch(84.1% 0.238 128.85);
--color-lime-500: oklch(76.8% 0.233 130.85);
--color-lime-600: oklch(64.8% 0.2 131.684);
--color-lime-700: oklch(53.2% 0.157 131.589);
--color-lime-800: oklch(45.3% 0.124 130.933);
--color-lime-900: oklch(40.5% 0.101 131.063);
--color-lime-950: oklch(27.4% 0.072 132.109);
--color-green-50: oklch(98.2% 0.018 155.826);
--color-green-100: oklch(96.2% 0.044 156.743);
--color-green-200: oklch(92.5% 0.084 155.995);
--color-green-300: oklch(87.1% 0.15 154.449);
--color-green-400: oklch(79.2% 0.209 151.711);
--color-green-500: oklch(72.3% 0.219 149.579);
--color-green-600: oklch(62.7% 0.194 149.214);
--color-green-700: oklch(52.7% 0.154 150.069);
--color-green-800: oklch(44.8% 0.119 151.328);
--color-green-900: oklch(39.3% 0.095 152.535);
--color-green-950: oklch(26.6% 0.065 152.934);
--color-emerald-50: oklch(97.9% 0.021 166.113);
--color-emerald-100: oklch(95% 0.052 163.051);
--color-emerald-200: oklch(90.5% 0.093 164.15);
--color-emerald-300: oklch(84.5% 0.143 164.978);
--color-emerald-400: oklch(76.5% 0.177 163.223);
--color-emerald-500: oklch(69.6% 0.17 162.48);
--color-emerald-600: oklch(59.6% 0.145 163.225);
--color-emerald-700: oklch(50.8% 0.118 165.612);
--color-emerald-800: oklch(43.2% 0.095 166.913);
--color-emerald-900: oklch(37.8% 0.077 168.94);
--color-emerald-950: oklch(26.2% 0.051 172.552);
--color-teal-50: oklch(98.4% 0.014 180.72);
--color-teal-100: oklch(95.3% 0.051 180.801);
--color-teal-200: oklch(91% 0.096 180.426);
--color-teal-300: oklch(85.5% 0.138 181.071);
--color-teal-400: oklch(77.7% 0.152 181.912);
--color-teal-500: oklch(70.4% 0.14 182.503);
--color-teal-600: oklch(60% 0.118 184.704);
--color-teal-700: oklch(51.1% 0.096 186.391);
--color-teal-800: oklch(43.7% 0.078 188.216);
--color-teal-900: oklch(38.6% 0.063 188.416);
--color-teal-950: oklch(27.7% 0.046 192.524);
--color-cyan-50: oklch(98.4% 0.019 200.873);
--color-cyan-100: oklch(95.6% 0.045 203.388);
--color-cyan-200: oklch(91.7% 0.08 205.041);
--color-cyan-300: oklch(86.5% 0.127 207.078);
--color-cyan-400: oklch(78.9% 0.154 211.53);
--color-cyan-500: oklch(71.5% 0.143 215.221);
--color-cyan-600: oklch(60.9% 0.126 221.723);
--color-cyan-700: oklch(52% 0.105 223.128);
--color-cyan-800: oklch(45% 0.085 224.283);
--color-cyan-900: oklch(39.8% 0.07 227.392);
--color-cyan-950: oklch(30.2% 0.056 229.695);
--color-sky-50: oklch(97.7% 0.013 236.62);
--color-sky-100: oklch(95.1% 0.026 236.824);
--color-sky-200: oklch(90.1% 0.058 230.902);
--color-sky-300: oklch(82.8% 0.111 230.318);
--color-sky-400: oklch(74.6% 0.16 232.661);
--color-sky-500: oklch(68.5% 0.169 237.323);
--color-sky-600: oklch(58.8% 0.158 241.966);
--color-sky-700: oklch(50% 0.134 242.749);
--color-sky-800: oklch(44.3% 0.11 240.79);
--color-sky-900: oklch(39.1% 0.09 240.876);
--color-sky-950: oklch(29.3% 0.066 243.157);
--color-blue-50: oklch(97% 0.014 254.604);
--color-blue-100: oklch(93.2% 0.032 255.585);
--color-blue-200: oklch(88.2% 0.059 254.128);
--color-blue-300: oklch(80.9% 0.105 251.813);
--color-blue-400: oklch(70.7% 0.165 254.624);
--color-blue-500: oklch(62.3% 0.214 259.815);
--color-blue-600: oklch(54.6% 0.245 262.881);
--color-blue-700: oklch(48.8% 0.243 264.376);
--color-blue-800: oklch(42.4% 0.199 265.638);
--color-blue-900: oklch(37.9% 0.146 265.522);
--color-blue-950: oklch(28.2% 0.091 267.935);
--color-indigo-50: oklch(96.2% 0.018 272.314);
--color-indigo-100: oklch(93% 0.034 272.788);
--color-indigo-200: oklch(87% 0.065 274.039);
--color-indigo-300: oklch(78.5% 0.115 274.713);
--color-indigo-400: oklch(67.3% 0.182 276.935);
--color-indigo-500: oklch(58.5% 0.233 277.117);
--color-indigo-600: oklch(51.1% 0.262 276.966);
--color-indigo-700: oklch(45.7% 0.24 277.023);
--color-indigo-800: oklch(39.8% 0.195 277.366);
--color-indigo-900: oklch(35.9% 0.144 278.697);
--color-indigo-950: oklch(25.7% 0.09 281.288);
--color-violet-50: oklch(96.9% 0.016 293.756);
--color-violet-100: oklch(94.3% 0.029 294.588);
--color-violet-200: oklch(89.4% 0.057 293.283);
--color-violet-300: oklch(81.1% 0.111 293.571);
--color-violet-400: oklch(70.2% 0.183 293.541);
--color-violet-500: oklch(60.6% 0.25 292.717);
--color-violet-600: oklch(54.1% 0.281 293.009);
--color-violet-700: oklch(49.1% 0.27 292.581);
--color-violet-800: oklch(43.2% 0.232 292.759);
--color-violet-900: oklch(38% 0.189 293.745);
--color-violet-950: oklch(28.3% 0.141 291.089);
--color-purple-50: oklch(97.7% 0.014 308.299);
--color-purple-100: oklch(94.6% 0.033 307.174);
--color-purple-200: oklch(90.2% 0.063 306.703);
--color-purple-300: oklch(82.7% 0.119 306.383);
--color-purple-400: oklch(71.4% 0.203 305.504);
--color-purple-500: oklch(62.7% 0.265 303.9);
--color-purple-600: oklch(55.8% 0.288 302.321);
--color-purple-700: oklch(49.6% 0.265 301.924);
--color-purple-800: oklch(43.8% 0.218 303.724);
--color-purple-900: oklch(38.1% 0.176 304.987);
--color-purple-950: oklch(29.1% 0.149 302.717);
--color-fuchsia-50: oklch(97.7% 0.017 320.058);
--color-fuchsia-100: oklch(95.2% 0.037 318.852);
--color-fuchsia-200: oklch(90.3% 0.076 319.62);
--color-fuchsia-300: oklch(83.3% 0.145 321.434);
--color-fuchsia-400: oklch(74% 0.238 322.16);
--color-fuchsia-500: oklch(66.7% 0.295 322.15);
--color-fuchsia-600: oklch(59.1% 0.293 322.896);
--color-fuchsia-700: oklch(51.8% 0.253 323.949);
--color-fuchsia-800: oklch(45.2% 0.211 324.591);
--color-fuchsia-900: oklch(40.1% 0.17 325.612);
--color-fuchsia-950: oklch(29.3% 0.136 325.661);
--color-pink-50: oklch(97.1% 0.014 343.198);
--color-pink-100: oklch(94.8% 0.028 342.258);
--color-pink-200: oklch(89.9% 0.061 343.231);
--color-pink-300: oklch(82.3% 0.12 346.018);
--color-pink-400: oklch(71.8% 0.202 349.761);
--color-pink-500: oklch(65.6% 0.241 354.308);
--color-pink-600: oklch(59.2% 0.249 0.584);
--color-pink-700: oklch(52.5% 0.223 3.958);
--color-pink-800: oklch(45.9% 0.187 3.815);
--color-pink-900: oklch(40.8% 0.153 2.432);
--color-pink-950: oklch(28.4% 0.109 3.907);
--color-rose-50: oklch(96.9% 0.015 12.422);
--color-rose-100: oklch(94.1% 0.03 12.58);
--color-rose-200: oklch(89.2% 0.058 10.001);
--color-rose-300: oklch(81% 0.117 11.638);
--color-rose-400: oklch(71.2% 0.194 13.428);
--color-rose-500: oklch(64.5% 0.246 16.439);
--color-rose-600: oklch(58.6% 0.253 17.585);
--color-rose-700: oklch(51.4% 0.222 16.935);
--color-rose-800: oklch(45.5% 0.188 13.697);
--color-rose-900: oklch(41% 0.159 10.272);
--color-rose-950: oklch(27.1% 0.105 12.094);
--color-slate-50: oklch(98.4% 0.003 247.858);
--color-slate-100: oklch(96.8% 0.007 247.896);
--color-slate-200: oklch(92.9% 0.013 255.508);
--color-slate-300: oklch(86.9% 0.022 252.894);
--color-slate-400: oklch(70.4% 0.04 256.788);
--color-slate-500: oklch(55.4% 0.046 257.417);
--color-slate-600: oklch(44.6% 0.043 257.281);
--color-slate-700: oklch(37.2% 0.044 257.287);
--color-slate-800: oklch(27.9% 0.041 260.031);
--color-slate-900: oklch(20.8% 0.042 265.755);
--color-slate-950: oklch(12.9% 0.042 264.695);
--color-gray-50: oklch(98.5% 0.002 247.839);
--color-gray-100: oklch(96.7% 0.003 264.542);
--color-gray-200: oklch(92.8% 0.006 264.531);
--color-gray-300: oklch(87.2% 0.01 258.338);
--color-gray-400: oklch(70.7% 0.022 261.325);
--color-gray-500: oklch(55.1% 0.027 264.364);
--color-gray-600: oklch(44.6% 0.03 256.802);
--color-gray-700: oklch(37.3% 0.034 259.733);
--color-gray-800: oklch(27.8% 0.033 256.848);
--color-gray-900: oklch(21% 0.034 264.665);
--color-gray-950: oklch(13% 0.028 261.692);
--color-zinc-50: oklch(98.5% 0 0);
--color-zinc-100: oklch(96.7% 0.001 286.375);
--color-zinc-200: oklch(92% 0.004 286.32);
--color-zinc-300: oklch(87.1% 0.006 286.286);
--color-zinc-400: oklch(70.5% 0.015 286.067);
--color-zinc-500: oklch(55.2% 0.016 285.938);
--color-zinc-600: oklch(44.2% 0.017 285.786);
--color-zinc-700: oklch(37% 0.013 285.805);
--color-zinc-800: oklch(27.4% 0.006 286.033);
--color-zinc-900: oklch(21% 0.006 285.885);
--color-zinc-950: oklch(14.1% 0.005 285.823);
--color-neutral-50: oklch(98.5% 0 0);
--color-neutral-100: oklch(97% 0 0);
--color-neutral-200: oklch(92.2% 0 0);
--color-neutral-300: oklch(87% 0 0);
--color-neutral-400: oklch(70.8% 0 0);
--color-neutral-500: oklch(55.6% 0 0);
--color-neutral-600: oklch(43.9% 0 0);
--color-neutral-700: oklch(37.1% 0 0);
--color-neutral-800: oklch(26.9% 0 0);
--color-neutral-900: oklch(20.5% 0 0);
--color-neutral-950: oklch(14.5% 0 0);
--color-stone-50: oklch(98.5% 0.001 106.423);
--color-stone-100: oklch(97% 0.001 106.424);
--color-stone-200: oklch(92.3% 0.003 48.717);
--color-stone-300: oklch(86.9% 0.005 56.366);
--color-stone-400: oklch(70.9% 0.01 56.259);
--color-stone-500: oklch(55.3% 0.013 58.071);
--color-stone-600: oklch(44.4% 0.011 73.639);
--color-stone-700: oklch(37.4% 0.01 67.558);
--color-stone-800: oklch(26.8% 0.007 34.298);
--color-stone-900: oklch(21.6% 0.006 56.043);
--color-stone-950: oklch(14.7% 0.004 49.25);
--color-mauve-50: oklch(98.5% 0 0);
--color-mauve-100: oklch(96% 0.003 325.6);
--color-mauve-200: oklch(92.2% 0.005 325.62);
--color-mauve-300: oklch(86.5% 0.012 325.68);
--color-mauve-400: oklch(71.1% 0.019 323.02);
--color-mauve-500: oklch(54.2% 0.034 322.5);
--color-mauve-600: oklch(43.5% 0.029 321.78);
--color-mauve-700: oklch(36.4% 0.029 323.89);
--color-mauve-800: oklch(26.3% 0.024 320.12);
--color-mauve-900: oklch(21.2% 0.019 322.12);
--color-mauve-950: oklch(14.5% 0.008 326);
--color-olive-50: oklch(98.8% 0.003 106.5);
--color-olive-100: oklch(96.6% 0.005 106.5);
--color-olive-200: oklch(93% 0.007 106.5);
--color-olive-300: oklch(88% 0.011 106.6);
--color-olive-400: oklch(73.7% 0.021 106.9);
--color-olive-500: oklch(58% 0.031 107.3);
--color-olive-600: oklch(46.6% 0.025 107.3);
--color-olive-700: oklch(39.4% 0.023 107.4);
--color-olive-800: oklch(28.6% 0.016 107.4);
--color-olive-900: oklch(22.8% 0.013 107.4);
--color-olive-950: oklch(15.3% 0.006 107.1);
--color-mist-50: oklch(98.7% 0.002 197.1);
--color-mist-100: oklch(96.3% 0.002 197.1);
--color-mist-200: oklch(92.5% 0.005 214.3);
--color-mist-300: oklch(87.2% 0.007 219.6);
--color-mist-400: oklch(72.3% 0.014 214.4);
--color-mist-500: oklch(56% 0.021 213.5);
--color-mist-600: oklch(45% 0.017 213.2);
--color-mist-700: oklch(37.8% 0.015 216);
--color-mist-800: oklch(27.5% 0.011 216.9);
--color-mist-900: oklch(21.8% 0.008 223.9);
--color-mist-950: oklch(14.8% 0.004 228.8);
--color-taupe-50: oklch(98.6% 0.002 67.8);
--color-taupe-100: oklch(96% 0.002 17.2);
--color-taupe-200: oklch(92.2% 0.005 34.3);
--color-taupe-300: oklch(86.8% 0.007 39.5);
--color-taupe-400: oklch(71.4% 0.014 41.2);
--color-taupe-500: oklch(54.7% 0.021 43.1);
--color-taupe-600: oklch(43.8% 0.017 39.3);
--color-taupe-700: oklch(36.7% 0.016 35.7);
--color-taupe-800: oklch(26.8% 0.011 36.5);
--color-taupe-900: oklch(21.4% 0.009 43.1);
--color-taupe-950: oklch(14.7% 0.004 49.3);
--color-black: #000;
--color-white: #fff;
--spacing: 0.25rem;
--breakpoint-sm: 40rem;
--breakpoint-md: 48rem;
--breakpoint-lg: 64rem;
--breakpoint-xl: 80rem;
--breakpoint-2xl: 96rem;
--container-3xs: 16rem;
--container-2xs: 18rem;
--container-xs: 20rem;
--container-sm: 24rem;
--container-md: 28rem;
--container-lg: 32rem;
--container-xl: 36rem;
--container-2xl: 42rem;
--container-3xl: 48rem;
--container-4xl: 56rem;
--container-5xl: 64rem;
--container-6xl: 72rem;
--container-7xl: 80rem;
--text-xs: 0.75rem;
--text-xs--line-height: calc(1 / 0.75);
--text-sm: 0.875rem;
--text-sm--line-height: calc(1.25 / 0.875);
--text-base: 1rem;
--text-base--line-height: calc(1.5 / 1);
--text-lg: 1.125rem;
--text-lg--line-height: calc(1.75 / 1.125);
--text-xl: 1.25rem;
--text-xl--line-height: calc(1.75 / 1.25);
--text-2xl: 1.5rem;
--text-2xl--line-height: calc(2 / 1.5);
--text-3xl: 1.875rem;
--text-3xl--line-height: calc(2.25 / 1.875);
--text-4xl: 2.25rem;
--text-4xl--line-height: calc(2.5 / 2.25);
--text-5xl: 3rem;
--text-5xl--line-height: 1;
--text-6xl: 3.75rem;
--text-6xl--line-height: 1;
--text-7xl: 4.5rem;
--text-7xl--line-height: 1;
--text-8xl: 6rem;
--text-8xl--line-height: 1;
--text-9xl: 8rem;
--text-9xl--line-height: 1;
--font-weight-thin: 100;
--font-weight-extralight: 200;
--font-weight-light: 300;
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
--font-weight-extrabold: 800;
--font-weight-black: 900;
--tracking-tighter: -0.05em;
--tracking-tight: -0.025em;
--tracking-normal: 0em;
--tracking-wide: 0.025em;
--tracking-wider: 0.05em;
--tracking-widest: 0.1em;
--leading-tight: 1.25;
--leading-snug: 1.375;
--leading-normal: 1.5;
--leading-relaxed: 1.625;
--leading-loose: 2;
--radius-xs: 0.125rem;
--radius-sm: 0.25rem;
--radius-md: 0.375rem;
--radius-lg: 0.5rem;
--radius-xl: 0.75rem;
--radius-2xl: 1rem;
--radius-3xl: 1.5rem;
--radius-4xl: 2rem;
--shadow-2xs: 0 1px rgb(0 0 0 / 0.05);
--shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--shadow-md:
0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--shadow-lg:
0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--shadow-xl:
0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
--inset-shadow-2xs: inset 0 1px rgb(0 0 0 / 0.05);
--inset-shadow-xs: inset 0 1px 1px rgb(0 0 0 / 0.05);
--inset-shadow-sm: inset 0 2px 4px rgb(0 0 0 / 0.05);
--drop-shadow-xs: 0 1px 1px rgb(0 0 0 / 0.05);
--drop-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.15);
--drop-shadow-md: 0 3px 3px rgb(0 0 0 / 0.12);
--drop-shadow-lg: 0 4px 4px rgb(0 0 0 / 0.15);
--drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1);
--drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15);
--text-shadow-2xs: 0px 1px 0px rgb(0 0 0 / 0.15);
--text-shadow-xs: 0px 1px 1px rgb(0 0 0 / 0.2);
--text-shadow-sm:
0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075),
0px 2px 2px rgb(0 0 0 / 0.075);
--text-shadow-md:
0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1),
0px 2px 4px rgb(0 0 0 / 0.1);
--text-shadow-lg:
0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1),
0px 4px 8px rgb(0 0 0 / 0.1);
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--animate-spin: spin 1s linear infinite;
--animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
--animate-bounce: bounce 1s infinite;
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@keyframes ping {
75%,
100% {
transform: scale(2);
opacity: 0;
}
}
@keyframes pulse {
50% {
opacity: 0.5;
}
}
@keyframes bounce {
0%,
100% {
transform: translateY(-25%);
animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
}
50% {
transform: none;
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
}
--blur-xs: 4px;
--blur-sm: 8px;
--blur-md: 12px;
--blur-lg: 16px;
--blur-xl: 24px;
--blur-2xl: 40px;
--blur-3xl: 64px;
--perspective-dramatic: 100px;
--perspective-near: 300px;
--perspective-normal: 500px;
--perspective-midrange: 800px;
--perspective-distant: 1200px;
--aspect-video: 16 / 9;
--default-transition-duration: 150ms;
--default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
--default-font-family: --theme(--font-sans, initial);
--default-font-feature-settings: --theme(
--font-sans--font-feature-settings,
initial
);
--default-font-variation-settings: --theme(
--font-sans--font-variation-settings,
initial
);
--default-mono-font-family: --theme(--font-mono, initial);
--default-mono-font-feature-settings: --theme(
--font-mono--font-feature-settings,
initial
);
--default-mono-font-variation-settings: --theme(
--font-mono--font-variation-settings,
initial
);
}
/* Deprecated */
@theme default inline reference {
--blur: 8px;
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
--drop-shadow: 0 1px 2px rgb(0 0 0 / 0.1), 0 1px 1px rgb(0 0 0 / 0.06);
--radius: 0.25rem;
--max-width-prose: 65ch;
}
}
@layer base {
/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Remove default margins and padding
3. Reset all borders.
*/
*,
::after,
::before,
::backdrop,
::file-selector-button {
box-sizing: border-box; /* 1 */
margin: 0; /* 2 */
padding: 0; /* 2 */
border: 0 solid; /* 3 */
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
7. Disable tap highlights on iOS.
*/
html,
:host {
line-height: 1.5; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
tab-size: 4; /* 3 */
font-family: --theme(
--default-font-family,
ui-sans-serif,
system-ui,
sans-serif,
"Apple Color Emoji",
"Segoe UI Emoji",
"Segoe UI Symbol",
"Noto Color Emoji"
); /* 4 */
font-feature-settings: --theme(
--default-font-feature-settings,
normal
); /* 5 */
font-variation-settings: --theme(
--default-font-variation-settings,
normal
); /* 6 */
-webkit-tap-highlight-color: transparent; /* 7 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Reset the default border style to a 1px solid border.
*/
hr {
height: 0; /* 1 */
color: inherit; /* 2 */
border-top-width: 1px; /* 3 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
-webkit-text-decoration: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the user's configured `mono` font-family by default.
2. Use the user's configured `mono` font-feature-settings by default.
3. Use the user's configured `mono` font-variation-settings by default.
4. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: --theme(
--default-mono-font-family,
ui-monospace,
SFMono-Regular,
Menlo,
Monaco,
Consolas,
"Liberation Mono",
"Courier New",
monospace
); /* 1 */
font-feature-settings: --theme(
--default-mono-font-feature-settings,
normal
); /* 2 */
font-variation-settings: --theme(
--default-mono-font-variation-settings,
normal
); /* 3 */
font-size: 1em; /* 4 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
text-indent: 0; /* 1 */
border-color: inherit; /* 2 */
border-collapse: collapse; /* 3 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring:where(:not(iframe)) {
outline: auto;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Make lists unstyled by default.
*/
ol,
ul,
menu {
list-style: none;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block; /* 1 */
vertical-align: middle; /* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
/*
1. Inherit font styles in all browsers.
2. Remove border radius in all browsers.
3. Remove background color in all browsers.
4. Ensure consistent opacity for disabled states in all browsers.
*/
button,
input,
select,
optgroup,
textarea,
::file-selector-button {
font: inherit; /* 1 */
font-feature-settings: inherit; /* 1 */
font-variation-settings: inherit; /* 1 */
letter-spacing: inherit; /* 1 */
color: inherit; /* 1 */
border-radius: 0; /* 2 */
background-color: transparent; /* 3 */
opacity: 1; /* 4 */
}
/*
Restore default font weight.
*/
:where(select:is([multiple], [size])) optgroup {
font-weight: bolder;
}
/*
Restore indentation.
*/
:where(select:is([multiple], [size])) optgroup option {
padding-inline-start: 20px;
}
/*
Restore space after button.
*/
::file-selector-button {
margin-inline-end: 4px;
}
/*
Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
*/
::placeholder {
opacity: 1;
}
/*
Set the default placeholder color to a semi-transparent version of the current text color in browsers that do not
crash when using `color-mix(…)` with `currentcolor`. (https://github.com/tailwindlabs/tailwindcss/issues/17194)
*/
@supports (not (-webkit-appearance: -apple-pay-button)) /* Not Safari */ or
(contain-intrinsic-size: 1px) /* Safari 17+ */ {
::placeholder {
color: color-mix(in oklab, currentcolor 50%, transparent);
}
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
1. Ensure date/time inputs have the same height when empty in iOS Safari.
2. Ensure text alignment can be changed on date/time inputs in iOS Safari.
*/
::-webkit-date-and-time-value {
min-height: 1lh; /* 1 */
text-align: inherit; /* 2 */
}
/*
Prevent height from changing on date/time inputs in macOS Safari when the input is set to `display: block`.
*/
::-webkit-datetime-edit {
display: inline-flex;
}
/*
Remove excess padding from pseudo-elements in date/time inputs to ensure consistent height across browsers.
*/
::-webkit-datetime-edit-fields-wrapper {
padding: 0;
}
::-webkit-datetime-edit,
::-webkit-datetime-edit-year-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-minute-field,
::-webkit-datetime-edit-second-field,
::-webkit-datetime-edit-millisecond-field,
::-webkit-datetime-edit-meridiem-field {
padding-block: 0;
}
/*
Center dropdown marker shown on inputs with paired `<datalist>`s in Chrome. (https://github.com/tailwindlabs/tailwindcss/issues/18499)
*/
::-webkit-calendar-picker-indicator {
line-height: 1;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Correct the inability to style the border radius in iOS Safari.
*/
button,
input:where([type="button"], [type="reset"], [type="submit"]),
::file-selector-button {
appearance: button;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
Make elements with the HTML hidden attribute stay hidden by default.
*/
[hidden]:where(:not([hidden="until-found"])) {
display: none !important;
}
}
@layer utilities {
@tailwind utilities;
}
+76
-101
{
"name": "tailwindcss",
"version": "0.0.0-insiders.b52a78b",
"version": "0.0.0-insiders.b53fa09",
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
"license": "MIT",
"main": "lib/index.js",
"types": "types/index.d.ts",
"repository": "https://github.com/tailwindlabs/tailwindcss.git",
"repository": {
"type": "git",
"url": "https://github.com/tailwindlabs/tailwindcss.git",
"directory": "packages/tailwindcss"
},
"bugs": "https://github.com/tailwindlabs/tailwindcss/issues",
"homepage": "https://tailwindcss.com",
"bin": {
"tailwind": "lib/cli.js",
"tailwindcss": "lib/cli.js"
"exports": {
".": {
"types": "./dist/lib.d.mts",
"style": "./index.css",
"require": "./dist/lib.js",
"import": "./dist/lib.mjs"
},
"./plugin": {
"require": "./dist/plugin.js",
"import": "./dist/plugin.mjs"
},
"./plugin.js": {
"require": "./dist/plugin.js",
"import": "./dist/plugin.mjs"
},
"./defaultTheme": {
"require": "./dist/default-theme.js",
"import": "./dist/default-theme.mjs"
},
"./defaultTheme.js": {
"require": "./dist/default-theme.js",
"import": "./dist/default-theme.mjs"
},
"./colors": {
"require": "./dist/colors.js",
"import": "./dist/colors.mjs"
},
"./colors.js": {
"require": "./dist/colors.js",
"import": "./dist/colors.mjs"
},
"./lib/util/flattenColorPalette": {
"require": "./dist/flatten-color-palette.js",
"import": "./dist/flatten-color-palette.mjs"
},
"./lib/util/flattenColorPalette.js": {
"require": "./dist/flatten-color-palette.js",
"import": "./dist/flatten-color-palette.mjs"
},
"./package.json": "./package.json",
"./index.css": "./index.css",
"./index": "./index.css",
"./preflight.css": "./preflight.css",
"./preflight": "./preflight.css",
"./theme.css": "./theme.css",
"./theme": "./theme.css",
"./utilities.css": "./utilities.css",
"./utilities": "./utilities.css"
},
"workspaces": [
"integrations/*",
"oxide/crates/node"
],
"scripts": {
"dev": "concurrently -n tailwind,oxide-node -c green,yellow 'npm run dev:js' 'npm run dev:rust'",
"build": "npm run build:rust && npm run build:js",
"test": "jest",
"test:integrations": "npm run test -w ./integrations",
"style": "eslint .",
"prepublishOnly": "npm install --force && npm run build && npm run generate:types",
"dev:rust": "npm run --prefix ./oxide dev:node",
"dev:js": "npm run build:js -- --watch",
"build:rust": "npm run --prefix ./oxide build:node",
"build:js": "npm run generate:plugin-list && swc src --out-dir lib --copy-files --delete-dir-on-start",
"generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js",
"generate:types": "node -r @swc/register scripts/generate-types.js"
"publishConfig": {
"provenance": true,
"access": "public"
},
"style": "index.css",
"files": [
"src/*",
"cli/*",
"lib/*",
"scripts/*.js",
"stubs/*",
"nesting/*",
"types/**/*",
"*.d.ts",
"*.css",
"*.js"
"dist",
"index.css",
"preflight.css",
"theme.css",
"utilities.css"
],
"devDependencies": {
"@swc/cli": "^0.1.63",
"@swc/core": "^1.3.101",
"@swc/jest": "^0.2.29",
"@swc/register": "^0.1.10",
"concurrently": "^8.0.1",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.7.0",
"jest-diff": "^29.7.0",
"prettier": "^2.8.8",
"rimraf": "^5.0.0",
"source-map-js": "^1.0.2",
"turbo": "^1.11.2"
"@jridgewell/remapping": "^2.3.5",
"@types/node": "22.19.21",
"dedent": "1.7.2",
"lightningcss": "1.32.0",
"magic-string": "^0.30.21",
"source-map-js": "^1.2.1",
"@tailwindcss/oxide": "0.0.0-insiders.b53fa09"
},
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"@tailwindcss/oxide": "0.0.0-insiders.b52a78b",
"arg": "^5.0.2",
"browserslist": "^4.22.2",
"chokidar": "^3.5.3",
"didyoumean": "^1.2.2",
"dlv": "^1.1.3",
"fast-glob": "^3.3.2",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
"jiti": "^1.21.0",
"lightningcss": "^1.22.1",
"lilconfig": "^3.0.0",
"micromatch": "^4.0.5",
"normalize-path": "^3.0.0",
"object-hash": "^3.0.0",
"picocolors": "^1.0.0",
"postcss": "^8.4.31",
"postcss-import": "^15.1.0",
"postcss-js": "^4.0.1",
"postcss-load-config": "^4.0.2",
"postcss-nested": "^6.0.1",
"postcss-selector-parser": "^6.0.15",
"postcss-value-parser": "^4.2.0",
"resolve": "^1.22.8",
"sucrase": "^3.35.0"
},
"browserslist": [
"defaults and supports css-variables and supports css-matches-pseudo",
"not android <= 117",
"safari >= 14"
],
"jest": {
"testTimeout": 30000,
"globalSetup": "<rootDir>/jest/global-setup.js",
"setupFilesAfterEnv": [
"<rootDir>/jest/customMatchers.js"
],
"testPathIgnorePatterns": [
"/node_modules/",
"/integrations/",
"/standalone-cli/",
"\\.test\\.skip\\.js$"
],
"transform": {
"\\.js$": "@swc/jest",
"\\.ts$": "@swc/jest"
}
},
"engines": {
"node": ">=16.0.0"
"scripts": {
"lint": "tsc --noEmit",
"build": "tsup-node --env.NODE_ENV production",
"dev": "tsup-node --env.NODE_ENV development --watch",
"test:ui": "playwright test"
}
}
}

@@ -15,28 +15,23 @@ <p align="center">

<p align="center">
<a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/actions/workflow/status/tailwindlabs/tailwindcss/ci.yml?branch=master" alt="Build Status"></a>
<a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/actions/workflow/status/tailwindlabs/tailwindcss/ci.yml?branch=main" alt="Build Status"></a>
<a href="https://www.npmjs.com/package/tailwindcss"><img src="https://img.shields.io/npm/dt/tailwindcss.svg" alt="Total Downloads"></a>
<a href="https://github.com/tailwindcss/tailwindcss/releases"><img src="https://img.shields.io/npm/v/tailwindcss.svg" alt="Latest Release"></a>
<a href="https://github.com/tailwindcss/tailwindcss/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/tailwindcss.svg" alt="License"></a>
<a href="https://github.com/tailwindlabs/tailwindcss/releases"><img src="https://img.shields.io/npm/v/tailwindcss.svg" alt="Latest Release"></a>
<a href="https://github.com/tailwindlabs/tailwindcss/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/tailwindcss.svg" alt="License"></a>
</p>
------
---
## Documentation
For full documentation, visit [tailwindcss.com](https://tailwindcss.com/).
For full documentation, visit [tailwindcss.com](https://tailwindcss.com).
## Community
For help, discussion about best practices, or any other conversation that would benefit from being searchable:
For help, discussion about best practices, or feature ideas:
[Discuss Tailwind CSS on GitHub](https://github.com/tailwindcss/tailwindcss/discussions)
[Discuss Tailwind CSS on GitHub](https://github.com/tailwindlabs/tailwindcss/discussions)
For casual chit-chat with others using the framework:
[Join the Tailwind CSS Discord Server](https://discord.gg/7NF8GNe)
## Contributing
If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindcss/tailwindcss/blob/master/.github/CONTRIBUTING.md) **before submitting a pull request**.
If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**.
@tailwind base;
import type { DefaultColors } from './types/generated/colors'
declare const colors: DefaultColors
export = colors
let colors = require('./lib/public/colors')
module.exports = (colors.__esModule ? colors : { default: colors }).default
@tailwind components;
import type { Config } from './types/config'
declare const config: Config
export = config
let defaultConfig = require('./lib/public/default-config')
module.exports = (defaultConfig.__esModule ? defaultConfig : { default: defaultConfig }).default
import type { Config } from './types/config'
import { DefaultTheme } from './types/generated/default-theme'
declare const theme: Config['theme'] & DefaultTheme
export = theme
let defaultTheme = require('./lib/public/default-theme')
module.exports = (defaultTheme.__esModule ? defaultTheme : { default: defaultTheme }).default
#!/usr/bin/env node
"use strict";
module.exports = require('./cli/index');
// @ts-check
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "build", {
enumerable: true,
get: function() {
return build;
}
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _resolveConfigPath = require("../../util/resolveConfigPath.js");
const _plugin = require("./plugin.js");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
async function build(args) {
let input = args['--input'];
let shouldWatch = args['--watch'];
// TODO: Deprecate this in future versions
if (!input && args['_'][1]) {
console.error('[deprecation] Running tailwindcss without -i, please provide an input file.');
input = args['--input'] = args['_'][1];
}
if (input && input !== '-' && !_fs.default.existsSync(input = _path.default.resolve(input))) {
console.error(`Specified input file ${args['--input']} does not exist.`);
process.exit(9);
}
if (args['--config'] && !_fs.default.existsSync(args['--config'] = _path.default.resolve(args['--config']))) {
console.error(`Specified config file ${args['--config']} does not exist.`);
process.exit(9);
}
if (args['--no-autoprefixer']) {
console.error('[deprecation] The --no-autoprefixer flag is deprecated and has no effect.');
}
// TODO: Reference the @config path here if exists
let configPath = args['--config'] ? args['--config'] : (0, _resolveConfigPath.resolveDefaultConfigPath)();
let processor = await (0, _plugin.createProcessor)(args, configPath);
if (shouldWatch) {
// Abort the watcher if stdin is closed to avoid zombie processes
// You can disable this behavior with --watch=always
if (args['--watch'] !== 'always') {
process.stdin.on('end', ()=>process.exit(0));
}
process.stdin.resume();
await processor.watch();
} else {
await processor.build().catch((e)=>{
console.error(e);
process.exit(1);
});
}
}
// @ts-check
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "createProcessor", {
enumerable: true,
get: function() {
return createProcessor;
}
});
const _packagejson = /*#__PURE__*/ _interop_require_default(require("../../../package.json"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _postcssloadconfig = /*#__PURE__*/ _interop_require_default(require("postcss-load-config"));
const _browserslist = /*#__PURE__*/ _interop_require_default(require("browserslist"));
const _lightningcss = /*#__PURE__*/ _interop_require_wildcard(require("lightningcss"));
const _lilconfig = require("lilconfig");
const _plugins = /*#__PURE__*/ _interop_require_default(require("postcss-load-config/src/plugins" // Little bit scary, looking at private/internal API
));
const _options = /*#__PURE__*/ _interop_require_default(require("postcss-load-config/src/options" // Little bit scary, looking at private/internal API
));
const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("../../processTailwindFeatures"));
const _utils = require("./utils");
const _sharedState = require("../../lib/sharedState");
const _resolveConfig = /*#__PURE__*/ _interop_require_default(require("../../../resolveConfig.js"));
const _content = require("../../lib/content.js");
const _watching = require("./watching.js");
const _fastglob = /*#__PURE__*/ _interop_require_default(require("fast-glob"));
const _findAtConfigPath = require("../../lib/findAtConfigPath.js");
const _log = /*#__PURE__*/ _interop_require_default(require("../../util/log"));
const _loadconfig = require("../../lib/load-config");
const _getModuleDependencies = /*#__PURE__*/ _interop_require_default(require("../../lib/getModuleDependencies"));
const _validateConfig = require("../../util/validateConfig");
const _handleImportAtRules = require("../../lib/handleImportAtRules");
const _featureFlags = require("../../featureFlags");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
function license() {
return `/* ! tailwindcss v${_packagejson.default.version} | MIT License | https://tailwindcss.com */\n`;
}
async function lightningcss(result, { map = true, minify = true } = {}) {
try {
var _browserslist_findConfig;
var _result_opts_from;
let resolvedBrowsersListConfig = (_browserslist_findConfig = _browserslist.default.findConfig((_result_opts_from = result.opts.from) !== null && _result_opts_from !== void 0 ? _result_opts_from : process.cwd())) === null || _browserslist_findConfig === void 0 ? void 0 : _browserslist_findConfig.defaults;
let defaultBrowsersListConfig = _packagejson.default.browserslist;
let browsersListConfig = resolvedBrowsersListConfig !== null && resolvedBrowsersListConfig !== void 0 ? resolvedBrowsersListConfig : defaultBrowsersListConfig;
let transformed = _lightningcss.default.transform({
filename: result.opts.from || 'input.css',
code: Buffer.from(result.css, 'utf-8'),
minify,
sourceMap: result.map === undefined ? map : !!result.map,
inputSourceMap: result.map ? result.map.toString() : undefined,
targets: _lightningcss.default.browserslistToTargets((0, _browserslist.default)(browsersListConfig)),
include: _lightningcss.Features.Nesting,
exclude: _lightningcss.Features.LogicalProperties
});
return Object.assign(result, {
css: transformed.code.toString(),
map: result.map ? Object.assign(result.map, {
toString () {
var _transformed_map;
return (_transformed_map = transformed.map) === null || _transformed_map === void 0 ? void 0 : _transformed_map.toString();
}
}) : result.map
});
} catch (err) {
console.error('Unable to use Lightning CSS. Using raw version instead.');
console.error(err);
return result;
}
}
/**
*
* @param {string} [customPostCssPath ]
* @returns
*/ async function loadPostCssPlugins(customPostCssPath) {
let config = customPostCssPath ? await (async ()=>{
let file = _path.default.resolve(customPostCssPath);
// Implementation, see: https://unpkg.com/browse/postcss-load-config@3.1.0/src/index.js
// @ts-ignore
let { config = {} } = await (0, _lilconfig.lilconfig)('postcss').load(file);
if (typeof config === 'function') {
config = config();
} else {
config = Object.assign({}, config);
}
if (!config.plugins) {
config.plugins = [];
}
return {
file,
plugins: (0, _plugins.default)(config, file),
options: (0, _options.default)(config, file)
};
})() : await (0, _postcssloadconfig.default)();
let configPlugins = config.plugins;
let configPluginTailwindIdx = configPlugins.findIndex((plugin)=>{
if (typeof plugin === 'function' && plugin.name === 'tailwindcss') {
return true;
}
if (typeof plugin === 'object' && plugin !== null && plugin.postcssPlugin === 'tailwindcss') {
return true;
}
return false;
});
let beforePlugins = configPluginTailwindIdx === -1 ? [] : configPlugins.slice(0, configPluginTailwindIdx);
let afterPlugins = configPluginTailwindIdx === -1 ? configPlugins : configPlugins.slice(configPluginTailwindIdx + 1);
return [
beforePlugins,
afterPlugins,
config.options
];
}
let state = {
/** @type {any} */ context: null,
/** @type {ReturnType<typeof createWatcher> | null} */ watcher: null,
/** @type {{content: string, extension: string}[]} */ changedContent: [],
/** @type {{config: import('../../../types').Config, dependencies: Set<string>, dispose: Function } | null} */ configBag: null,
contextDependencies: new Set(),
/** @type {import('../../lib/content.js').ContentPath[]} */ contentPaths: [],
refreshContentPaths () {
var _this_context;
this.contentPaths = (0, _content.parseCandidateFiles)(this.context, (_this_context = this.context) === null || _this_context === void 0 ? void 0 : _this_context.tailwindConfig);
},
get config () {
return this.context.tailwindConfig;
},
get contentPatterns () {
return {
all: this.contentPaths.map((contentPath)=>contentPath.pattern),
dynamic: this.contentPaths.filter((contentPath)=>contentPath.glob !== undefined).map((contentPath)=>contentPath.pattern)
};
},
loadConfig (configPath, content) {
if (this.watcher && configPath) {
this.refreshConfigDependencies();
}
let config = (0, _loadconfig.loadConfig)(configPath);
let dependencies = (0, _getModuleDependencies.default)(configPath);
this.configBag = {
config,
dependencies,
dispose () {
for (let file of dependencies){
delete require.cache[require.resolve(file)];
}
}
};
this.configBag.config = (0, _validateConfig.validateConfig)((0, _resolveConfig.default)(this.configBag.config));
// Override content files if `--content` has been passed explicitly
if ((content === null || content === void 0 ? void 0 : content.length) > 0) {
this.configBag.config.content.files = content;
}
return this.configBag.config;
},
refreshConfigDependencies () {
var _this_configBag;
_sharedState.env.DEBUG && console.time('Module dependencies');
(_this_configBag = this.configBag) === null || _this_configBag === void 0 ? void 0 : _this_configBag.dispose();
_sharedState.env.DEBUG && console.timeEnd('Module dependencies');
},
readContentPaths () {
let content = [];
// Resolve globs from the content config
// TODO: When we make the postcss plugin async-capable this can become async
let files = _fastglob.default.sync(this.contentPatterns.all);
for (let file of files){
if ((0, _featureFlags.flagEnabled)(this.config, 'oxideParser')) {
content.push({
file,
extension: _path.default.extname(file).slice(1)
});
} else {
content.push({
content: _fs.default.readFileSync(_path.default.resolve(file), 'utf8'),
extension: _path.default.extname(file).slice(1)
});
}
}
// Resolve raw content in the tailwind config
let rawContent = this.config.content.files.filter((file)=>{
return file !== null && typeof file === 'object';
});
for (let { raw: htmlContent, extension = 'html' } of rawContent){
content.push({
content: htmlContent,
extension
});
}
return content;
},
getContext ({ createContext, cliConfigPath, root, result, content }) {
_sharedState.env.DEBUG && console.time('Searching for config');
var _findAtConfigPath1;
let configPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : cliConfigPath;
_sharedState.env.DEBUG && console.timeEnd('Searching for config');
if (this.context) {
this.context.changedContent = this.changedContent.splice(0);
return this.context;
}
_sharedState.env.DEBUG && console.time('Loading config');
let config = this.loadConfig(configPath, content);
_sharedState.env.DEBUG && console.timeEnd('Loading config');
_sharedState.env.DEBUG && console.time('Creating context');
this.context = createContext(config, []);
Object.assign(this.context, {
userConfigPath: configPath
});
_sharedState.env.DEBUG && console.timeEnd('Creating context');
_sharedState.env.DEBUG && console.time('Resolving content paths');
this.refreshContentPaths();
_sharedState.env.DEBUG && console.timeEnd('Resolving content paths');
if (this.watcher) {
_sharedState.env.DEBUG && console.time('Watch new files');
this.watcher.refreshWatchedFiles();
_sharedState.env.DEBUG && console.timeEnd('Watch new files');
}
for (let file of this.readContentPaths()){
this.context.changedContent.push(file);
}
return this.context;
}
};
async function createProcessor(args, cliConfigPath) {
var _args_content;
let input = args['--input'];
let output = args['--output'];
let includePostCss = args['--postcss'];
let customPostCssPath = typeof args['--postcss'] === 'string' ? args['--postcss'] : undefined;
let [beforePlugins, afterPlugins, postcssOptions] = includePostCss ? await loadPostCssPlugins(customPostCssPath) : [
[],
[],
{}
];
beforePlugins.unshift(...(0, _handleImportAtRules.handleImportAtRules)());
if (args['--purge']) {
_log.default.warn('purge-flag-deprecated', [
'The `--purge` flag has been deprecated.',
'Please use `--content` instead.'
]);
if (!args['--content']) {
args['--content'] = args['--purge'];
}
}
var _args_content_split;
let content = (_args_content_split = (_args_content = args['--content']) === null || _args_content === void 0 ? void 0 : _args_content.split(RegExp("(?<!{[^}]+),"))) !== null && _args_content_split !== void 0 ? _args_content_split : [];
let tailwindPlugin = ()=>{
return {
postcssPlugin: 'tailwindcss',
async Once (root, { result }) {
_sharedState.env.DEBUG && console.time('Compiling CSS');
await (0, _processTailwindFeatures.default)(({ createContext })=>{
console.error();
console.error('Rebuilding...');
return ()=>{
return state.getContext({
createContext,
cliConfigPath,
root,
result,
content
});
};
})(root, result);
_sharedState.env.DEBUG && console.timeEnd('Compiling CSS');
}
};
};
tailwindPlugin.postcss = true;
let plugins = [
...beforePlugins,
tailwindPlugin,
!args['--minify'] && _utils.formatNodes,
...afterPlugins
].filter(Boolean);
/** @type {import('postcss').Processor} */ // @ts-ignore
let processor = (0, _postcss.default)(plugins);
async function readInput() {
// Piping in data, let's drain the stdin
if (input === '-') {
return (0, _utils.drainStdin)();
}
// Input file has been provided
if (input) {
return _fs.default.promises.readFile(_path.default.resolve(input), 'utf8');
}
// No input file provided, fallback to default atrules
return '@tailwind base; @tailwind components; @tailwind utilities';
}
async function build() {
let start = process.hrtime.bigint();
let options = {
...postcssOptions,
from: input,
to: output
};
return readInput().then((css)=>processor.process(css, options)).then((result)=>lightningcss(result, {
...options,
minify: !!args['--minify']
})).then((result)=>{
if (!state.watcher) {
return result;
}
_sharedState.env.DEBUG && console.time('Recording PostCSS dependencies');
for (let message of result.messages){
if (message.type === 'dependency') {
state.contextDependencies.add(message.file);
}
}
_sharedState.env.DEBUG && console.timeEnd('Recording PostCSS dependencies');
// TODO: This needs to be in a different spot
_sharedState.env.DEBUG && console.time('Watch new files');
state.watcher.refreshWatchedFiles();
_sharedState.env.DEBUG && console.timeEnd('Watch new files');
return result;
}).then((result)=>{
if (!output) {
process.stdout.write(license() + result.css);
return;
}
return Promise.all([
(0, _utils.outputFile)(result.opts.to, license() + result.css),
result.map && (0, _utils.outputFile)(result.opts.to + '.map', result.map.toString())
]);
}).then(()=>{
let end = process.hrtime.bigint();
console.error();
console.error('Done in', (end - start) / BigInt(1e6) + 'ms.');
}).then(()=>{}, (err)=>{
// TODO: If an initial build fails we can't easily pick up any PostCSS dependencies
// that were collected before the error occurred
// The result is not stored on the error so we have to store it externally
// and pull the messages off of it here somehow
// This results in a less than ideal DX because the watcher will not pick up
// changes to imported CSS if one of them caused an error during the initial build
// If you fix it and then save the main CSS file so there's no error
// The watcher will start watching the imported CSS files and will be
// resilient to future errors.
if (state.watcher) {
console.error(err);
} else {
return Promise.reject(err);
}
});
}
/**
* @param {{file: string, content(): Promise<string>, extension: string}[]} changes
*/ async function parseChanges(changes) {
return Promise.all(changes.map(async (change)=>({
content: await change.content(),
extension: change.extension
})));
}
if (input !== undefined && input !== '-') {
state.contextDependencies.add(_path.default.resolve(input));
}
return {
build,
watch: async ()=>{
state.watcher = (0, _watching.createWatcher)(args, {
state,
/**
* @param {{file: string, content(): Promise<string>, extension: string}[]} changes
*/ async rebuild (changes) {
let needsNewContext = changes.some((change)=>{
var _state_configBag;
return ((_state_configBag = state.configBag) === null || _state_configBag === void 0 ? void 0 : _state_configBag.dependencies.has(change.file)) || state.contextDependencies.has(change.file);
});
if (needsNewContext) {
state.context = null;
} else {
for (let change of (await parseChanges(changes))){
state.changedContent.push(change);
}
}
return build();
}
});
await build();
}
};
}
// @ts-check
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
drainStdin: function() {
return drainStdin;
},
formatNodes: function() {
return formatNodes;
},
indentRecursive: function() {
return indentRecursive;
},
outputFile: function() {
return outputFile;
},
readFileWithRetries: function() {
return readFileWithRetries;
}
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function indentRecursive(node, indent = 0) {
node.each && node.each((child, i)=>{
if (!child.raws.before || !child.raws.before.trim() || child.raws.before.includes('\n')) {
child.raws.before = `\n${node.type !== 'rule' && i > 0 ? '\n' : ''}${' '.repeat(indent)}`;
}
child.raws.after = `\n${' '.repeat(indent)}`;
indentRecursive(child, indent + 1);
});
}
function formatNodes(root) {
indentRecursive(root);
if (root.first) {
root.first.raws.before = '';
}
}
async function readFileWithRetries(path, tries = 5) {
for(let n = 0; n <= tries; n++){
try {
return await _fs.default.promises.readFile(path, 'utf8');
} catch (err) {
if (n !== tries) {
if (err.code === 'ENOENT' || err.code === 'EBUSY') {
await new Promise((resolve)=>setTimeout(resolve, 10));
continue;
}
}
throw err;
}
}
}
function drainStdin() {
return new Promise((resolve, reject)=>{
let result = '';
process.stdin.on('data', (chunk)=>{
result += chunk;
});
process.stdin.on('end', ()=>resolve(result));
process.stdin.on('error', (err)=>reject(err));
});
}
async function outputFile(file, newContents) {
try {
let currentContents = await _fs.default.promises.readFile(file, 'utf8');
if (currentContents === newContents) {
return; // Skip writing the file
}
} catch (e) {}
// Write the file
await _fs.default.promises.mkdir(_path.default.dirname(file), {
recursive: true
});
await _fs.default.promises.writeFile(file, newContents, 'utf8');
}
// @ts-check
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "createWatcher", {
enumerable: true,
get: function() {
return createWatcher;
}
});
const _chokidar = /*#__PURE__*/ _interop_require_default(require("chokidar"));
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _micromatch = /*#__PURE__*/ _interop_require_default(require("micromatch"));
const _normalizepath = /*#__PURE__*/ _interop_require_default(require("normalize-path"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _utils = require("./utils.js");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function createWatcher(args, { state, rebuild }) {
let shouldPoll = args['--poll'];
let shouldCoalesceWriteEvents = shouldPoll || process.platform === 'win32';
// Polling interval in milliseconds
// Used only when polling or coalescing add/change events on Windows
let pollInterval = 10;
let watcher = _chokidar.default.watch([], {
// Force checking for atomic writes in all situations
// This causes chokidar to wait up to 100ms for a file to re-added after it's been unlinked
// This only works when watching directories though
atomic: true,
usePolling: shouldPoll,
interval: shouldPoll ? pollInterval : undefined,
ignoreInitial: true,
awaitWriteFinish: shouldCoalesceWriteEvents ? {
stabilityThreshold: 50,
pollInterval: pollInterval
} : false
});
// A queue of rebuilds, file reads, etc… to run
let chain = Promise.resolve();
/**
* A list of files that have been changed since the last rebuild
*
* @type {{file: string, content: () => Promise<string>, extension: string}[]}
*/ let changedContent = [];
/**
* A list of files for which a rebuild has already been queued.
* This is used to prevent duplicate rebuilds when multiple events are fired for the same file.
* The rebuilt file is cleared from this list when it's associated rebuild has _started_
* This is because if the file is changed during a rebuild it won't trigger a new rebuild which it should
**/ let pendingRebuilds = new Set();
let _timer;
let _reject;
/**
* Rebuilds the changed files and resolves when the rebuild is
* complete regardless of whether it was successful or not
*/ async function rebuildAndContinue() {
let changes = changedContent.splice(0);
// There are no changes to rebuild so we can just do nothing
if (changes.length === 0) {
return Promise.resolve();
}
// Clear all pending rebuilds for the about-to-be-built files
changes.forEach((change)=>pendingRebuilds.delete(change.file));
// Resolve the promise even when the rebuild fails
return rebuild(changes).then(()=>{}, (e)=>{
console.error(e.toString());
});
}
/**
*
* @param {*} file
* @param {(() => Promise<string>) | null} content
* @param {boolean} skipPendingCheck
* @returns {Promise<void>}
*/ function recordChangedFile(file, content = null, skipPendingCheck = false) {
file = _path.default.resolve(file);
// Applications like Vim/Neovim fire both rename and change events in succession for atomic writes
// In that case rebuild has already been queued by rename, so can be skipped in change
if (pendingRebuilds.has(file) && !skipPendingCheck) {
return Promise.resolve();
}
// Mark that a rebuild of this file is going to happen
// It MUST happen synchronously before the rebuild is queued for this to be effective
pendingRebuilds.add(file);
changedContent.push({
file,
content: content !== null && content !== void 0 ? content : ()=>_fs.default.promises.readFile(file, 'utf8'),
extension: _path.default.extname(file).slice(1)
});
if (_timer) {
clearTimeout(_timer);
_reject();
}
// If a rebuild is already in progress we don't want to start another one until the 10ms timer has expired
chain = chain.then(()=>new Promise((resolve, reject)=>{
_timer = setTimeout(resolve, 10);
_reject = reject;
}));
// Resolves once this file has been rebuilt (or the rebuild for this file has failed)
// This queues as many rebuilds as there are changed files
// But those rebuilds happen after some delay
// And will immediately resolve if there are no changes
chain = chain.then(rebuildAndContinue, rebuildAndContinue);
return chain;
}
watcher.on('change', (file)=>recordChangedFile(file));
watcher.on('add', (file)=>recordChangedFile(file));
// Restore watching any files that are "removed"
// This can happen when a file is pseudo-atomically replaced (a copy is created, overwritten, the old one is unlinked, and the new one is renamed)
// TODO: An an optimization we should allow removal when the config changes
watcher.on('unlink', (file)=>{
file = (0, _normalizepath.default)(file);
// Only re-add the file if it's not covered by a dynamic pattern
if (!_micromatch.default.some([
file
], state.contentPatterns.dynamic)) {
watcher.add(file);
}
});
// Some applications such as Visual Studio (but not VS Code)
// will only fire a rename event for atomic writes and not a change event
// This is very likely a chokidar bug but it's one we need to work around
// We treat this as a change event and rebuild the CSS
watcher.on('raw', (evt, filePath, meta)=>{
if (evt !== 'rename' || filePath === null) {
return;
}
let watchedPath = meta.watchedPath;
// Watched path might be the file itself
// Or the directory it is in
filePath = watchedPath.endsWith(filePath) ? watchedPath : _path.default.join(watchedPath, filePath);
// Skip this event since the files it is for does not match any of the registered content globs
if (!_micromatch.default.some([
filePath
], state.contentPatterns.all)) {
return;
}
// Skip since we've already queued a rebuild for this file that hasn't happened yet
if (pendingRebuilds.has(filePath)) {
return;
}
// We'll go ahead and add the file to the pending rebuilds list here
// It'll be removed when the rebuild starts unless the read fails
// which will be taken care of as well
pendingRebuilds.add(filePath);
async function enqueue() {
try {
// We need to read the file as early as possible outside of the chain
// because it may be gone by the time we get to it. doing the read
// immediately increases the chance that the file is still there
let content = await (0, _utils.readFileWithRetries)(_path.default.resolve(filePath));
if (content === undefined) {
return;
}
// This will push the rebuild onto the chain
// We MUST skip the rebuild check here otherwise the rebuild will never happen on Linux
// This is because the order of events and timing is different on Linux
// @ts-ignore: TypeScript isn't picking up that content is a string here
await recordChangedFile(filePath, ()=>content, true);
} catch (e) {
// If reading the file fails, it's was probably a deleted temporary file
// So we can ignore it and no rebuild is needed
}
}
enqueue().then(()=>{
// If the file read fails we still need to make sure the file isn't stuck in the pending rebuilds list
pendingRebuilds.delete(filePath);
});
});
return {
fswatcher: watcher,
refreshWatchedFiles () {
watcher.add(Array.from(state.contextDependencies));
watcher.add(Array.from(state.configBag.dependencies));
watcher.add(state.contentPatterns.all);
}
};
}
// @ts-check
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "help", {
enumerable: true,
get: function() {
return help;
}
});
const _packagejson = /*#__PURE__*/ _interop_require_default(require("../../../package.json"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function help({ message, usage, commands, options }) {
let indent = 2;
// Render header
console.log();
console.log(`${_packagejson.default.name} v${_packagejson.default.version}`);
// Render message
if (message) {
console.log();
for (let msg of message.split('\n')){
console.log(msg);
}
}
// Render usage
if (usage && usage.length > 0) {
console.log();
console.log('Usage:');
for (let example of usage){
console.log(' '.repeat(indent), example);
}
}
// Render commands
if (commands && commands.length > 0) {
console.log();
console.log('Commands:');
for (let command of commands){
console.log(' '.repeat(indent), command);
}
}
// Render options
if (options) {
let groupedOptions = {};
for (let [key, value] of Object.entries(options)){
if (typeof value === 'object') {
groupedOptions[key] = {
...value,
flags: [
key
]
};
} else {
groupedOptions[value].flags.push(key);
}
}
console.log();
console.log('Options:');
for (let { flags, description, deprecated } of Object.values(groupedOptions)){
if (deprecated) continue;
if (flags.length === 1) {
console.log(' '.repeat(indent + 4 /* 4 = "-i, ".length */ ), flags.slice().reverse().join(', ').padEnd(20, ' '), description);
} else {
console.log(' '.repeat(indent), flags.slice().reverse().join(', ').padEnd(24, ' '), description);
}
}
}
console.log();
}
#!/usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _arg = /*#__PURE__*/ _interop_require_default(require("arg"));
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _build = require("./build");
const _help = require("./help");
const _init = require("./init");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function oneOf(...options) {
return Object.assign((value = true)=>{
for (let option of options){
let parsed = option(value);
if (parsed === value) {
return parsed;
}
}
throw new Error('...');
}, {
manualParsing: true
});
}
let commands = {
init: {
run: _init.init,
args: {
'--esm': {
type: Boolean,
description: `Initialize configuration file as ESM`
},
'--ts': {
type: Boolean,
description: `Initialize configuration file as TypeScript`
},
'--postcss': {
type: Boolean,
description: `Initialize a \`postcss.config.js\` file`
},
'--full': {
type: Boolean,
description: `Include the default values for all options in the generated configuration file`
},
'-f': '--full',
'-p': '--postcss'
}
},
build: {
run: _build.build,
args: {
'--input': {
type: String,
description: 'Input file'
},
'--output': {
type: String,
description: 'Output file'
},
'--watch': {
type: oneOf(String, Boolean),
description: 'Watch for changes and rebuild as needed'
},
'--poll': {
type: Boolean,
description: 'Use polling instead of filesystem events when watching'
},
'--content': {
type: String,
description: 'Content paths to use for removing unused classes'
},
'--purge': {
type: String,
deprecated: true
},
'--postcss': {
type: oneOf(String, Boolean),
description: 'Load custom PostCSS configuration'
},
'--minify': {
type: Boolean,
description: 'Minify the output'
},
'--config': {
type: String,
description: 'Path to a custom config file'
},
'--no-autoprefixer': {
deprecated: true,
type: Boolean,
description: 'Disable autoprefixer'
},
'-c': '--config',
'-i': '--input',
'-o': '--output',
'-m': '--minify',
'-w': '--watch',
'-p': '--poll'
}
}
};
let sharedFlags = {
'--help': {
type: Boolean,
description: 'Display usage information'
},
'-h': '--help'
};
if (process.stdout.isTTY /* Detect redirecting output to a file */ && (process.argv[2] === undefined || process.argv.slice(2).every((flag)=>sharedFlags[flag] !== undefined))) {
(0, _help.help)({
usage: [
'tailwindcss [--input input.css] [--output output.css] [--watch] [options...]',
'tailwindcss init [--full] [--postcss] [options...]'
],
commands: Object.keys(commands).filter((command)=>command !== 'build').map((command)=>`${command} [options]`),
options: {
...commands.build.args,
...sharedFlags
}
});
process.exit(0);
}
let command = ((arg = '')=>arg.startsWith('-') ? undefined : arg)(process.argv[2]) || 'build';
if (commands[command] === undefined) {
if (_fs.default.existsSync(_path.default.resolve(command))) {
// TODO: Deprecate this in future versions
// Check if non-existing command, might be a file.
command = 'build';
} else {
(0, _help.help)({
message: `Invalid command: ${command}`,
usage: [
'tailwindcss <command> [options]'
],
commands: Object.keys(commands).filter((command)=>command !== 'build').map((command)=>`${command} [options]`),
options: sharedFlags
});
process.exit(1);
}
}
// Execute command
let { args: flags, run } = commands[command];
let args = (()=>{
try {
let result = (0, _arg.default)(Object.fromEntries(Object.entries({
...flags,
...sharedFlags
}).filter(([_key, value])=>{
var _value_type;
return !(value === null || value === void 0 ? void 0 : (_value_type = value.type) === null || _value_type === void 0 ? void 0 : _value_type.manualParsing);
}).map(([key, value])=>[
key,
typeof value === 'object' ? value.type : value
])), {
permissive: true
});
// Manual parsing of flags to allow for special flags like oneOf(Boolean, String)
for(let i = result['_'].length - 1; i >= 0; --i){
let flag = result['_'][i];
if (!flag.startsWith('-')) continue;
let [flagName, flagValue] = flag.split('=');
let handler = flags[flagName];
// Resolve flagName & handler
while(typeof handler === 'string'){
flagName = handler;
handler = flags[handler];
}
if (!handler) continue;
let args = [];
let offset = i + 1;
// --flag value syntax was used so we need to pull `value` from `args`
if (flagValue === undefined) {
// Parse args for current flag
while(result['_'][offset] && !result['_'][offset].startsWith('-')){
args.push(result['_'][offset++]);
}
// Cleanup manually parsed flags + args
result['_'].splice(i, 1 + args.length);
// No args were provided, use default value defined in handler
// One arg was provided, use that directly
// Multiple args were provided so pass them all in an array
flagValue = args.length === 0 ? undefined : args.length === 1 ? args[0] : args;
} else {
// Remove the whole flag from the args array
result['_'].splice(i, 1);
}
// Set the resolved value in the `result` object
result[flagName] = handler.type(flagValue, flagName);
}
// Ensure that the `command` is always the first argument in the `args`.
// This is important so that we don't have to check if a default command
// (build) was used or not from within each plugin.
//
// E.g.: tailwindcss input.css -> _: ['build', 'input.css']
// E.g.: tailwindcss build input.css -> _: ['build', 'input.css']
if (result['_'][0] !== command) {
result['_'].unshift(command);
}
return result;
} catch (err) {
if (err.code === 'ARG_UNKNOWN_OPTION') {
(0, _help.help)({
message: err.message,
usage: [
'tailwindcss <command> [options]'
],
options: sharedFlags
});
process.exit(1);
}
throw err;
}
})();
if (args['--help']) {
(0, _help.help)({
options: {
...flags,
...sharedFlags
},
usage: [
`tailwindcss ${command} [options]`
]
});
process.exit(0);
}
run(args);
// @ts-check
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "init", {
enumerable: true,
get: function() {
return init;
}
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function isESM() {
const pkgPath = _path.default.resolve('./package.json');
try {
let pkg = JSON.parse(_fs.default.readFileSync(pkgPath, 'utf8'));
return pkg.type && pkg.type === 'module';
} catch (err) {
return false;
}
}
function init(args) {
let messages = [];
let isProjectESM = args['--ts'] || args['--esm'] || isESM();
let syntax = args['--ts'] ? 'ts' : isProjectESM ? 'js' : 'cjs';
let extension = args['--ts'] ? 'ts' : 'js';
var _args___;
let tailwindConfigLocation = _path.default.resolve((_args___ = args['_'][1]) !== null && _args___ !== void 0 ? _args___ : `./tailwind.config.${extension}`);
if (_fs.default.existsSync(tailwindConfigLocation)) {
messages.push(`${_path.default.basename(tailwindConfigLocation)} already exists.`);
} else {
let stubContentsFile = _fs.default.readFileSync(args['--full'] ? _path.default.resolve(__dirname, '../../../stubs/config.full.js') : _path.default.resolve(__dirname, '../../../stubs/config.simple.js'), 'utf8');
let stubFile = _fs.default.readFileSync(_path.default.resolve(__dirname, `../../../stubs/tailwind.config.${syntax}`), 'utf8');
// Change colors import
stubContentsFile = stubContentsFile.replace('../colors', 'tailwindcss/colors');
// Replace contents of {ts,js,cjs} file with the stub {simple,full}.
stubFile = stubFile.replace('__CONFIG__', stubContentsFile.replace('module.exports =', '').trim()).trim() + '\n\n';
_fs.default.writeFileSync(tailwindConfigLocation, stubFile, 'utf8');
messages.push(`Created Tailwind CSS config file: ${_path.default.basename(tailwindConfigLocation)}`);
}
if (args['--postcss']) {
let postcssConfigLocation = _path.default.resolve('./postcss.config.js');
if (_fs.default.existsSync(postcssConfigLocation)) {
messages.push(`${_path.default.basename(postcssConfigLocation)} already exists.`);
} else {
let stubFile = _fs.default.readFileSync(isProjectESM ? _path.default.resolve(__dirname, '../../../stubs/postcss.config.js') : _path.default.resolve(__dirname, '../../../stubs/postcss.config.cjs'), 'utf8');
_fs.default.writeFileSync(postcssConfigLocation, stubFile, 'utf8');
messages.push(`Created PostCSS config file: ${_path.default.basename(postcssConfigLocation)}`);
}
}
if (messages.length > 0) {
console.log();
for (let message of messages){
console.log(message);
}
}
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _default = [
"preflight",
"container",
"accessibility",
"pointerEvents",
"visibility",
"position",
"inset",
"isolation",
"zIndex",
"order",
"gridColumn",
"gridColumnStart",
"gridColumnEnd",
"gridRow",
"gridRowStart",
"gridRowEnd",
"float",
"clear",
"margin",
"boxSizing",
"lineClamp",
"display",
"aspectRatio",
"size",
"height",
"maxHeight",
"minHeight",
"width",
"minWidth",
"maxWidth",
"flex",
"flexShrink",
"flexGrow",
"flexBasis",
"tableLayout",
"captionSide",
"borderCollapse",
"borderSpacing",
"transformOrigin",
"translate",
"rotate",
"skew",
"scale",
"transform",
"animation",
"cursor",
"touchAction",
"userSelect",
"resize",
"scrollSnapType",
"scrollSnapAlign",
"scrollSnapStop",
"scrollMargin",
"scrollPadding",
"listStylePosition",
"listStyleType",
"listStyleImage",
"appearance",
"columns",
"breakBefore",
"breakInside",
"breakAfter",
"gridAutoColumns",
"gridAutoFlow",
"gridAutoRows",
"gridTemplateColumns",
"gridTemplateRows",
"flexDirection",
"flexWrap",
"placeContent",
"placeItems",
"alignContent",
"alignItems",
"justifyContent",
"justifyItems",
"gap",
"space",
"divideWidth",
"divideStyle",
"divideColor",
"divideOpacity",
"placeSelf",
"alignSelf",
"justifySelf",
"overflow",
"overscrollBehavior",
"scrollBehavior",
"textOverflow",
"hyphens",
"whitespace",
"textWrap",
"wordBreak",
"borderRadius",
"borderWidth",
"borderStyle",
"borderColor",
"borderOpacity",
"backgroundColor",
"backgroundOpacity",
"backgroundImage",
"gradientColorStops",
"boxDecorationBreak",
"backgroundSize",
"backgroundAttachment",
"backgroundClip",
"backgroundPosition",
"backgroundRepeat",
"backgroundOrigin",
"fill",
"stroke",
"strokeWidth",
"objectFit",
"objectPosition",
"padding",
"textAlign",
"textIndent",
"verticalAlign",
"fontFamily",
"fontSize",
"fontWeight",
"textTransform",
"fontStyle",
"fontVariantNumeric",
"lineHeight",
"letterSpacing",
"textColor",
"textOpacity",
"textDecoration",
"textDecorationColor",
"textDecorationStyle",
"textDecorationThickness",
"textUnderlineOffset",
"fontSmoothing",
"placeholderColor",
"placeholderOpacity",
"caretColor",
"accentColor",
"opacity",
"backgroundBlendMode",
"mixBlendMode",
"boxShadow",
"boxShadowColor",
"outlineStyle",
"outlineWidth",
"outlineOffset",
"outlineColor",
"ringWidth",
"ringColor",
"ringOpacity",
"ringOffsetWidth",
"ringOffsetColor",
"blur",
"brightness",
"contrast",
"dropShadow",
"grayscale",
"hueRotate",
"invert",
"saturate",
"sepia",
"filter",
"backdropBlur",
"backdropBrightness",
"backdropContrast",
"backdropGrayscale",
"backdropHueRotate",
"backdropInvert",
"backdropOpacity",
"backdropSaturate",
"backdropSepia",
"backdropFilter",
"transitionProperty",
"transitionDelay",
"transitionDuration",
"transitionTimingFunction",
"willChange",
"content",
"forcedColorAdjust"
];

Sorry, the diff of this file is too big to display

MIT License
Copyright (c) Nicolas Gallagher
Copyright (c) Jonathan Neal
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Copyright (c) Adam Wathan
Copyright (c) Jonathan Reinink
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/
*,
::before,
::after {
box-sizing: border-box; /* 1 */
border-width: 0; /* 2 */
border-style: solid; /* 2 */
border-color: theme('borderColor.DEFAULT', currentColor); /* 2 */
}
::before,
::after {
--tw-content: '';
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
7. Disable tap highlights on iOS.
*/
html,
:host {
line-height: 1.5; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-moz-tab-size: 4; /* 3 */
tab-size: 4; /* 3 */
font-family: theme('fontFamily.sans', ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); /* 4 */
font-feature-settings: theme('fontFamily.sans[1].fontFeatureSettings', normal); /* 5 */
font-variation-settings: theme('fontFamily.sans[1].fontVariationSettings', normal); /* 6 */
-webkit-tap-highlight-color: transparent; /* 7 */
}
/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/
body {
margin: 0; /* 1 */
line-height: inherit; /* 2 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/
hr {
height: 0; /* 1 */
color: inherit; /* 2 */
border-top-width: 1px; /* 3 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the user's configured `mono` font-family by default.
2. Use the user's configured `mono` font-feature-settings by default.
3. Use the user's configured `mono` font-variation-settings by default.
4. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: theme('fontFamily.mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace); /* 1 */
font-feature-settings: theme('fontFamily.mono[1].fontFeatureSettings', normal); /* 2 */
font-variation-settings: theme('fontFamily.mono[1].fontVariationSettings', normal); /* 3 */
font-size: 1em; /* 4 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
text-indent: 0; /* 1 */
border-color: inherit; /* 2 */
border-collapse: collapse; /* 3 */
}
/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-feature-settings: inherit; /* 1 */
font-variation-settings: inherit; /* 1 */
font-size: 100%; /* 1 */
font-weight: inherit; /* 1 */
line-height: inherit; /* 1 */
color: inherit; /* 1 */
margin: 0; /* 2 */
padding: 0; /* 3 */
}
/*
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button; /* 1 */
background-color: transparent; /* 2 */
background-image: none; /* 2 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring {
outline: auto;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
[type='search'] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Removes the default spacing for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
list-style: none;
margin: 0;
padding: 0;
}
dialog {
padding: 0;
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/
input::placeholder,
textarea::placeholder {
opacity: 1; /* 1 */
color: theme('colors.gray.400', #9ca3af); /* 2 */
}
/*
Set the default cursor for buttons.
*/
button,
[role="button"] {
cursor: pointer;
}
/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block; /* 1 */
vertical-align: middle; /* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
/*
Make elements with the HTML hidden attribute stay hidden by default.
*/
[hidden] {
display: none;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
default: function() {
return _default;
},
featureFlags: function() {
return featureFlags;
},
flagEnabled: function() {
return flagEnabled;
},
issueFlagNotices: function() {
return issueFlagNotices;
}
});
const _picocolors = /*#__PURE__*/ _interop_require_default(require("picocolors"));
const _log = /*#__PURE__*/ _interop_require_default(require("./util/log"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let defaults = {
optimizeUniversalDefaults: false,
disableColorOpacityUtilitiesByDefault: false,
relativeContentPathsByDefault: false,
oxideParser: true,
logicalSiblingUtilities: false
};
let featureFlags = {
future: [
'hoverOnlyWhenSupported',
'respectDefaultRingColorOpacity',
'disableColorOpacityUtilitiesByDefault',
'relativeContentPathsByDefault',
'logicalSiblingUtilities'
],
experimental: [
'optimizeUniversalDefaults',
'oxideParser'
]
};
function flagEnabled(config, flag) {
if (featureFlags.future.includes(flag)) {
var _config_future;
var _config_future_flag, _ref;
return config.future === 'all' || ((_ref = (_config_future_flag = config === null || config === void 0 ? void 0 : (_config_future = config.future) === null || _config_future === void 0 ? void 0 : _config_future[flag]) !== null && _config_future_flag !== void 0 ? _config_future_flag : defaults[flag]) !== null && _ref !== void 0 ? _ref : false);
}
if (featureFlags.experimental.includes(flag)) {
var _config_experimental;
var _config_experimental_flag, _ref1;
return config.experimental === 'all' || ((_ref1 = (_config_experimental_flag = config === null || config === void 0 ? void 0 : (_config_experimental = config.experimental) === null || _config_experimental === void 0 ? void 0 : _config_experimental[flag]) !== null && _config_experimental_flag !== void 0 ? _config_experimental_flag : defaults[flag]) !== null && _ref1 !== void 0 ? _ref1 : false);
}
return false;
}
function experimentalFlagsEnabled(config) {
if (config.experimental === 'all') {
return featureFlags.experimental;
}
var _config_experimental;
return Object.keys((_config_experimental = config === null || config === void 0 ? void 0 : config.experimental) !== null && _config_experimental !== void 0 ? _config_experimental : {}).filter((flag)=>featureFlags.experimental.includes(flag) && config.experimental[flag]);
}
function issueFlagNotices(config) {
if (process.env.JEST_WORKER_ID !== undefined) {
return;
}
if (experimentalFlagsEnabled(config).length > 0) {
let changes = experimentalFlagsEnabled(config).map((s)=>_picocolors.default.yellow(s)).join(', ');
_log.default.warn('experimental-flags-enabled', [
`You have enabled experimental features: ${changes}`,
'Experimental features in Tailwind CSS are not covered by semver, may introduce breaking changes, and can change at any time.'
]);
}
}
const _default = featureFlags;
"use strict";
module.exports = require('./plugin');
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "hasContentChanged", {
enumerable: true,
get: function() {
return hasContentChanged;
}
});
const _crypto = /*#__PURE__*/ _interop_require_default(require("crypto"));
const _sharedState = /*#__PURE__*/ _interop_require_wildcard(require("./sharedState"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
/**
* Calculate the hash of a string.
*
* This doesn't need to be cryptographically secure or
* anything like that since it's used only to detect
* when the CSS changes to invalidate the context.
*
* This is wrapped in a try/catch because it's really dependent
* on how Node itself is build and the environment and OpenSSL
* version / build that is installed on the user's machine.
*
* Based on the environment this can just outright fail.
*
* See https://github.com/nodejs/node/issues/40455
*
* @param {string} str
*/ function getHash(str) {
try {
return _crypto.default.createHash('md5').update(str, 'utf-8').digest('binary');
} catch (err) {
return '';
}
}
function hasContentChanged(sourcePath, root) {
let css = root.toString();
// We only care about files with @tailwind directives
// Other files use an existing context
if (!css.includes('@tailwind')) {
return false;
}
let existingHash = _sharedState.sourceHashMap.get(sourcePath);
let rootHash = getHash(css);
let didChange = existingHash !== rootHash;
_sharedState.sourceHashMap.set(sourcePath, rootHash);
return didChange;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return collapseAdjacentRules;
}
});
let comparisonMap = {
atrule: [
'name',
'params'
],
rule: [
'selector'
]
};
let types = new Set(Object.keys(comparisonMap));
function collapseAdjacentRules() {
function collapseRulesIn(root) {
let currentRule = null;
root.each((node)=>{
if (!types.has(node.type)) {
currentRule = null;
return;
}
if (currentRule === null) {
currentRule = node;
return;
}
let properties = comparisonMap[node.type];
if (node.type === 'atrule' && node.name === 'font-face') {
currentRule = node;
} else if (properties.every((property)=>{
var _node_property, _currentRule_property;
return ((_node_property = node[property]) !== null && _node_property !== void 0 ? _node_property : '').replace(/\s+/g, ' ') === ((_currentRule_property = currentRule[property]) !== null && _currentRule_property !== void 0 ? _currentRule_property : '').replace(/\s+/g, ' ');
})) {
// An AtRule may not have children (for example if we encounter duplicate @import url(…) rules)
if (node.nodes) {
currentRule.append(node.nodes);
}
node.remove();
} else {
currentRule = node;
}
});
// After we've collapsed adjacent rules & at-rules, we need to collapse
// adjacent rules & at-rules that are children of at-rules.
// We do not care about nesting rules because Tailwind CSS
// explicitly does not handle rule nesting on its own as
// the user is expected to use a nesting plugin
root.each((node)=>{
if (node.type === 'atrule') {
collapseRulesIn(node);
}
});
}
return (root)=>{
collapseRulesIn(root);
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return collapseDuplicateDeclarations;
}
});
function collapseDuplicateDeclarations() {
return (root)=>{
root.walkRules((node)=>{
let seen = new Map();
let droppable = new Set([]);
let byProperty = new Map();
node.walkDecls((decl)=>{
// This could happen if we have nested selectors. In that case the
// parent will loop over all its declarations but also the declarations
// of nested rules. With this we ensure that we are shallowly checking
// declarations.
if (decl.parent !== node) {
return;
}
if (seen.has(decl.prop)) {
// Exact same value as what we have seen so far
if (seen.get(decl.prop).value === decl.value) {
// Keep the last one, drop the one we've seen so far
droppable.add(seen.get(decl.prop));
// Override the existing one with the new value. This is necessary
// so that if we happen to have more than one declaration with the
// same value, that we keep removing the previous one. Otherwise we
// will only remove the *first* one.
seen.set(decl.prop, decl);
return;
}
// Not the same value, so we need to check if we can merge it so
// let's collect it first.
if (!byProperty.has(decl.prop)) {
byProperty.set(decl.prop, new Set());
}
byProperty.get(decl.prop).add(seen.get(decl.prop));
byProperty.get(decl.prop).add(decl);
}
seen.set(decl.prop, decl);
});
// Drop all the duplicate declarations with the exact same value we've
// already seen so far.
for (let decl of droppable){
decl.remove();
}
// Analyze the declarations based on its unit, drop all the declarations
// with the same unit but the last one in the list.
for (let declarations of byProperty.values()){
let byUnit = new Map();
for (let decl of declarations){
let unit = resolveUnit(decl.value);
if (unit === null) {
continue;
}
if (!byUnit.has(unit)) {
byUnit.set(unit, new Set());
}
byUnit.get(unit).add(decl);
}
for (let declarations of byUnit.values()){
// Get all but the last one
let removableDeclarations = Array.from(declarations).slice(0, -1);
for (let decl of removableDeclarations){
decl.remove();
}
}
}
});
};
}
let UNITLESS_NUMBER = Symbol('unitless-number');
function resolveUnit(input) {
let result = /^-?\d*.?\d+([\w%]+)?$/g.exec(input);
if (result) {
var _result_;
return (_result_ = result[1]) !== null && _result_ !== void 0 ? _result_ : UNITLESS_NUMBER;
}
return null;
}
// @ts-check
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
parseCandidateFiles: function() {
return parseCandidateFiles;
},
resolvedChangedContent: function() {
return resolvedChangedContent;
}
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _isglob = /*#__PURE__*/ _interop_require_default(require("is-glob"));
const _fastglob = /*#__PURE__*/ _interop_require_default(require("fast-glob"));
const _normalizepath = /*#__PURE__*/ _interop_require_default(require("normalize-path"));
const _parseGlob = require("../util/parseGlob");
const _sharedState = require("./sharedState");
const _oxide = require("@tailwindcss/oxide");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
/** @typedef {import('../../types/config.js').RawFile} RawFile */ /** @typedef {import('../../types/config.js').FilePath} FilePath */ /*
* @param {import('tailwindcss').Config} tailwindConfig
* @param {{skip:string[]}} options
* @returns {ContentPath[]}
*/ function resolveContentFiles(tailwindConfig, { skip = [] } = {}) {
if (Array.isArray(tailwindConfig.content.files) && tailwindConfig.content.files.includes('auto')) {
let idx = tailwindConfig.content.files.indexOf('auto');
if (idx !== -1) {
_sharedState.env.DEBUG && console.time('Calculating resolve content paths');
let resolved = (0, _oxide.resolveContentPaths)({
base: process.cwd()
});
_sharedState.env.DEBUG && console.timeEnd('Calculating resolve content paths');
tailwindConfig.content.files.splice(idx, 1, ...resolved);
}
}
if (skip.length > 0) {
tailwindConfig.content.files = tailwindConfig.content.files.filter((filePath)=>!skip.includes(filePath));
}
return tailwindConfig.content.files;
}
function parseCandidateFiles(context, tailwindConfig) {
let files = resolveContentFiles(tailwindConfig, {
skip: [
context.userConfigPath
]
});
// Normalize the file globs
files = files.filter((filePath)=>typeof filePath === 'string');
files = files.map(_normalizepath.default);
// Split into included and excluded globs
let tasks = _fastglob.default.generateTasks(files);
/** @type {ContentPath[]} */ let included = [];
/** @type {ContentPath[]} */ let excluded = [];
for (const task of tasks){
included.push(...task.positive.map((filePath)=>parseFilePath(filePath, false)));
excluded.push(...task.negative.map((filePath)=>parseFilePath(filePath, true)));
}
let paths = [
...included,
...excluded
];
// Resolve paths relative to the config file or cwd
paths = resolveRelativePaths(context, paths);
// Resolve symlinks if possible
paths = paths.flatMap(resolvePathSymlinks);
// Update cached patterns
paths = paths.map(resolveGlobPattern);
return paths;
}
/**
*
* @param {string} filePath
* @param {boolean} ignore
* @returns {ContentPath}
*/ function parseFilePath(filePath, ignore) {
let contentPath = {
original: filePath,
base: filePath,
ignore,
pattern: filePath,
glob: null
};
if ((0, _isglob.default)(filePath)) {
Object.assign(contentPath, (0, _parseGlob.parseGlob)(filePath));
}
return contentPath;
}
/**
*
* @param {ContentPath} contentPath
* @returns {ContentPath}
*/ function resolveGlobPattern(contentPath) {
// This is required for Windows support to properly pick up Glob paths.
// Afaik, this technically shouldn't be needed but there's probably
// some internal, direct path matching with a normalized path in
// a package which can't handle mixed directory separators
let base = (0, _normalizepath.default)(contentPath.base);
// If the user's file path contains any special characters (like parens) for instance fast-glob
// is like "OOOH SHINY" and treats them as such. So we have to escape the base path to fix this
base = _fastglob.default.escapePath(base);
contentPath.pattern = contentPath.glob ? `${base}/${contentPath.glob}` : base;
contentPath.pattern = contentPath.ignore ? `!${contentPath.pattern}` : contentPath.pattern;
return contentPath;
}
/**
* Resolve each path relative to the config file (when possible) if the experimental flag is enabled
* Otherwise, resolve relative to the current working directory
*
* @param {any} context
* @param {ContentPath[]} contentPaths
* @returns {ContentPath[]}
*/ function resolveRelativePaths(context, contentPaths) {
let resolveFrom = [];
// Resolve base paths relative to the config file (when possible) if the experimental flag is enabled
if (context.userConfigPath && context.tailwindConfig.content.relative) {
resolveFrom = [
_path.default.dirname(context.userConfigPath)
];
}
return contentPaths.map((contentPath)=>{
contentPath.base = _path.default.resolve(...resolveFrom, contentPath.base);
return contentPath;
});
}
/**
* Resolve the symlink for the base directory / file in each path
* These are added as additional dependencies to watch for changes because
* some tools (like webpack) will only watch the actual file or directory
* but not the symlink itself even in projects that use monorepos.
*
* @param {ContentPath} contentPath
* @returns {ContentPath[]}
*/ function resolvePathSymlinks(contentPath) {
let paths = [
contentPath
];
try {
let resolvedPath = _fs.default.realpathSync(contentPath.base);
if (resolvedPath !== contentPath.base) {
paths.push({
...contentPath,
base: resolvedPath
});
}
} catch (e) {
// TODO: log this?
}
return paths;
}
function resolvedChangedContent(context, candidateFiles, fileModifiedMap) {
let changedContent = context.tailwindConfig.content.files.filter((item)=>typeof item.raw === 'string').map(({ raw, extension = 'html' })=>({
content: raw,
extension
}));
let [changedFiles, mTimesToCommit] = resolveChangedFiles(candidateFiles, fileModifiedMap);
for (let changedFile of changedFiles){
let extension = _path.default.extname(changedFile).slice(1);
changedContent.push({
file: changedFile,
extension
});
}
return [
changedContent,
mTimesToCommit
];
}
/**
*
* @param {ContentPath[]} candidateFiles
* @param {Map<string, number>} fileModifiedMap
* @returns {[Set<string>, Map<string, number>]}
*/ function resolveChangedFiles(candidateFiles, fileModifiedMap) {
let paths = candidateFiles.map((contentPath)=>contentPath.pattern);
let mTimesToCommit = new Map();
let changedFiles = new Set();
_sharedState.env.DEBUG && console.time('Finding changed files');
let files = _fastglob.default.sync(paths, {
absolute: true
});
for (let file of files){
let prevModified = fileModifiedMap.get(file) || -Infinity;
let modified = _fs.default.statSync(file).mtimeMs;
if (modified > prevModified) {
changedFiles.add(file);
mTimesToCommit.set(file, modified);
}
}
_sharedState.env.DEBUG && console.timeEnd('Finding changed files');
return [
changedFiles,
mTimesToCommit
];
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "defaultExtractor", {
enumerable: true,
get: function() {
return defaultExtractor;
}
});
const _regex = /*#__PURE__*/ _interop_require_wildcard(require("./regex"));
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
function defaultExtractor(context) {
let patterns = Array.from(buildRegExps(context));
/**
* @param {string} content
*/ return (content)=>{
/** @type {(string|string)[]} */ let results = [];
for (let pattern of patterns){
var _content_match;
for (let result of (_content_match = content.match(pattern)) !== null && _content_match !== void 0 ? _content_match : []){
results.push(clipAtBalancedParens(result));
}
}
return results;
};
}
function* buildRegExps(context) {
let separator = context.tailwindConfig.separator;
let prefix = context.tailwindConfig.prefix !== '' ? _regex.optional(_regex.pattern([
/-?/,
_regex.escape(context.tailwindConfig.prefix)
])) : '';
let utility = _regex.any([
// Arbitrary properties (without square brackets)
/\[[^\s:'"`]+:[^\s\[\]]+\]/,
// Arbitrary properties with balanced square brackets
// This is a targeted fix to continue to allow theme()
// with square brackets to work in arbitrary properties
// while fixing a problem with the regex matching too much
/\[[^\s:'"`\]]+:[^\s]+?\[[^\s]+\][^\s]+?\]/,
// Utilities
_regex.pattern([
// Utility Name / Group Name
_regex.any([
/-?(?:\w+)/,
// This is here to make sure @container supports everything that other utilities do
/@(?:\w+)/
]),
// Normal/Arbitrary values
_regex.optional(_regex.any([
_regex.pattern([
// Arbitrary values
_regex.any([
/-(?:\w+-)*\['[^\s]+'\]/,
/-(?:\w+-)*\["[^\s]+"\]/,
/-(?:\w+-)*\[`[^\s]+`\]/,
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s:\[\]]+\]/
]),
// Not immediately followed by an `{[(`
/(?![{([]])/,
// optionally followed by an opacity modifier
/(?:\/[^\s'"`\\><$]*)?/
]),
_regex.pattern([
// Arbitrary values
_regex.any([
/-(?:\w+-)*\['[^\s]+'\]/,
/-(?:\w+-)*\["[^\s]+"\]/,
/-(?:\w+-)*\[`[^\s]+`\]/,
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s\[\]]+\]/
]),
// Not immediately followed by an `{[(`
/(?![{([]])/,
// optionally followed by an opacity modifier
/(?:\/[^\s'"`\\$]*)?/
]),
// Normal values w/o quotes — may include an opacity modifier
/[-\/][^\s'"`\\$={><]*/
]))
])
]);
let variantPatterns = [
// Without quotes
_regex.any([
// This is here to provide special support for the `@` variant
_regex.pattern([
/@\[[^\s"'`]+\](\/[^\s"'`]+)?/,
separator
]),
// With variant modifier (e.g.: group-[..]/modifier)
_regex.pattern([
/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]\/\w+/,
separator
]),
_regex.pattern([
/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/,
separator
]),
_regex.pattern([
/[^\s"'`\[\\]+/,
separator
])
]),
// With quotes allowed
_regex.any([
// With variant modifier (e.g.: group-[..]/modifier)
_regex.pattern([
/([^\s"'`\[\\]+-)?\[[^\s`]+\]\/\w+/,
separator
]),
_regex.pattern([
/([^\s"'`\[\\]+-)?\[[^\s`]+\]/,
separator
]),
_regex.pattern([
/[^\s`\[\\]+/,
separator
])
])
];
for (const variantPattern of variantPatterns){
yield _regex.pattern([
// Variants
'((?=((',
variantPattern,
')+))\\2)?',
// Important (optional)
/!?/,
prefix,
utility
]);
}
// 5. Inner matches
yield /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g;
}
// We want to capture any "special" characters
// AND the characters immediately following them (if there is one)
let SPECIALS = /([\[\]'"`])([^\[\]'"`])?/g;
let ALLOWED_CLASS_CHARACTERS = /[^"'`\s<>\]]+/;
/**
* Clips a string ensuring that parentheses, quotes, etc… are balanced
* Used for arbitrary values only
*
* We will go past the end of the balanced parens until we find a non-class character
*
* Depth matching behavior:
* w-[calc(100%-theme('spacing[some_key][1.5]'))]']
* ┬ ┬ ┬┬ ┬ ┬┬ ┬┬┬┬┬┬┬
* 1 2 3 4 34 3 210 END
* ╰────┴──────────┴────────┴────────┴┴───┴─┴┴┴
*
* @param {string} input
*/ function clipAtBalancedParens(input) {
// We are care about this for arbitrary values
if (!input.includes('-[')) {
return input;
}
let depth = 0;
let openStringTypes = [];
// Find all parens, brackets, quotes, etc
// Stop when we end at a balanced pair
// This is naive and will treat mismatched parens as balanced
// This shouldn't be a problem in practice though
let matches = input.matchAll(SPECIALS);
// We can't use lookbehind assertions because we have to support Safari
// So, instead, we've emulated it using capture groups and we'll re-work the matches to accommodate
matches = Array.from(matches).flatMap((match)=>{
const [, ...groups] = match;
return groups.map((group, idx)=>Object.assign([], match, {
index: match.index + idx,
0: group
}));
});
for (let match of matches){
let char = match[0];
let inStringType = openStringTypes[openStringTypes.length - 1];
if (char === inStringType) {
openStringTypes.pop();
} else if (char === "'" || char === '"' || char === '`') {
openStringTypes.push(char);
}
if (inStringType) {
continue;
} else if (char === '[') {
depth++;
continue;
} else if (char === ']') {
depth--;
continue;
}
// We've gone one character past the point where we should stop
// This means that there was an extra closing `]`
// We'll clip to just before it
if (depth < 0) {
return input.substring(0, match.index - 1);
}
// We've finished balancing the brackets but there still may be characters that can be included
// For example in the class `text-[#336699]/[.35]`
// The depth goes to `0` at the closing `]` but goes up again at the `[`
// If we're at zero and encounter a non-class character then we clip the class there
if (depth === 0 && !ALLOWED_CLASS_CHARACTERS.test(char)) {
return input.substring(0, match.index);
}
}
return input;
} // Regular utilities
// {{modifier}:}*{namespace}{-{suffix}}*{/{opacityModifier}}?
// Arbitrary values
// {{modifier}:}*{namespace}-[{arbitraryValue}]{/{opacityModifier}}?
// arbitraryValue: no whitespace, balanced quotes unless within quotes, balanced brackets unless within quotes
// Arbitrary properties
// {{modifier}:}*[{validCssPropertyName}:{arbitraryValue}]
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
function isRoot(node) {
return node.type === 'root';
}
function isAtLayer(node) {
return node.type === 'atrule' && node.name === 'layer';
}
function _default(_context) {
return (root, result)=>{
let found = false;
root.walkAtRules('tailwind', (node)=>{
if (found) return false;
if (node.parent && !(isRoot(node.parent) || isAtLayer(node.parent))) {
found = true;
node.warn(result, [
'Nested @tailwind rules were detected, but are not supported.',
"Consider using a prefix to scope Tailwind's classes: https://tailwindcss.com/docs/configuration#prefix",
'Alternatively, use the important selector strategy: https://tailwindcss.com/docs/configuration#selector-strategy'
].join('\n'));
return false;
}
});
root.walkRules((rule)=>{
if (found) return false;
rule.walkRules((nestedRule)=>{
found = true;
nestedRule.warn(result, [
'Nested CSS was detected, but CSS nesting has not been configured correctly.',
'Please enable a CSS nesting plugin *before* Tailwind in your configuration.',
'See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting'
].join('\n'));
return false;
});
});
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _dlv = /*#__PURE__*/ _interop_require_default(require("dlv"));
const _didyoumean = /*#__PURE__*/ _interop_require_default(require("didyoumean"));
const _transformThemeValue = /*#__PURE__*/ _interop_require_default(require("../util/transformThemeValue"));
const _index = /*#__PURE__*/ _interop_require_default(require("../value-parser/index"));
const _normalizeScreens = require("../util/normalizeScreens");
const _buildMediaQuery = /*#__PURE__*/ _interop_require_default(require("../util/buildMediaQuery"));
const _toPath = require("../util/toPath");
const _withAlphaVariable = require("../util/withAlphaVariable");
const _pluginUtils = require("../util/pluginUtils");
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function isObject(input) {
return typeof input === 'object' && input !== null;
}
function findClosestExistingPath(theme, path) {
let parts = (0, _toPath.toPath)(path);
do {
parts.pop();
if ((0, _dlv.default)(theme, parts) !== undefined) break;
}while (parts.length)
return parts.length ? parts : undefined;
}
function pathToString(path) {
if (typeof path === 'string') return path;
return path.reduce((acc, cur, i)=>{
if (cur.includes('.')) return `${acc}[${cur}]`;
return i === 0 ? cur : `${acc}.${cur}`;
}, '');
}
function list(items) {
return items.map((key)=>`'${key}'`).join(', ');
}
function listKeys(obj) {
return list(Object.keys(obj));
}
function validatePath(config, path, defaultValue, themeOpts = {}) {
const pathString = Array.isArray(path) ? pathToString(path) : path.replace(/^['"]+|['"]+$/g, '');
const pathSegments = Array.isArray(path) ? path : (0, _toPath.toPath)(pathString);
const value = (0, _dlv.default)(config.theme, pathSegments, defaultValue);
if (value === undefined) {
let error = `'${pathString}' does not exist in your theme config.`;
const parentSegments = pathSegments.slice(0, -1);
const parentValue = (0, _dlv.default)(config.theme, parentSegments);
if (isObject(parentValue)) {
const validKeys = Object.keys(parentValue).filter((key)=>validatePath(config, [
...parentSegments,
key
]).isValid);
const suggestion = (0, _didyoumean.default)(pathSegments[pathSegments.length - 1], validKeys);
if (suggestion) {
error += ` Did you mean '${pathToString([
...parentSegments,
suggestion
])}'?`;
} else if (validKeys.length > 0) {
error += ` '${pathToString(parentSegments)}' has the following valid keys: ${list(validKeys)}`;
}
} else {
const closestPath = findClosestExistingPath(config.theme, pathString);
if (closestPath) {
const closestValue = (0, _dlv.default)(config.theme, closestPath);
if (isObject(closestValue)) {
error += ` '${pathToString(closestPath)}' has the following keys: ${listKeys(closestValue)}`;
} else {
error += ` '${pathToString(closestPath)}' is not an object.`;
}
} else {
error += ` Your theme has the following top-level keys: ${listKeys(config.theme)}`;
}
}
return {
isValid: false,
error
};
}
if (!(typeof value === 'string' || typeof value === 'number' || typeof value === 'function' || value instanceof String || value instanceof Number || Array.isArray(value))) {
let error = `'${pathString}' was found but does not resolve to a string.`;
if (isObject(value)) {
let validKeys = Object.keys(value).filter((key)=>validatePath(config, [
...pathSegments,
key
]).isValid);
if (validKeys.length) {
error += ` Did you mean something like '${pathToString([
...pathSegments,
validKeys[0]
])}'?`;
}
}
return {
isValid: false,
error
};
}
const [themeSection] = pathSegments;
return {
isValid: true,
value: (0, _transformThemeValue.default)(themeSection)(value, themeOpts)
};
}
function extractArgs(node, vNodes, functions) {
vNodes = vNodes.map((vNode)=>resolveVNode(node, vNode, functions));
let args = [
''
];
for (let vNode of vNodes){
if (vNode.type === 'div' && vNode.value === ',') {
args.push('');
} else {
args[args.length - 1] += _index.default.stringify(vNode);
}
}
return args;
}
function resolveVNode(node, vNode, functions) {
if (vNode.type === 'function' && functions[vNode.value] !== undefined) {
let args = extractArgs(node, vNode.nodes, functions);
vNode.type = 'word';
vNode.value = functions[vNode.value](node, ...args);
}
return vNode;
}
function resolveFunctions(node, input, functions) {
let hasAnyFn = Object.keys(functions).some((fn)=>input.includes(`${fn}(`));
if (!hasAnyFn) return input;
return (0, _index.default)(input).walk((vNode)=>{
resolveVNode(node, vNode, functions);
}).toString();
}
let nodeTypePropertyMap = {
atrule: 'params',
decl: 'value'
};
/**
* @param {string} path
* @returns {Iterable<[path: string, alpha: string|undefined]>}
*/ function* toPaths(path) {
// Strip quotes from beginning and end of string
// This allows the alpha value to be present inside of quotes
path = path.replace(/^['"]+|['"]+$/g, '');
let matches = path.match(/^([^\s]+)(?![^\[]*\])(?:\s*\/\s*([^\/\s]+))$/);
let alpha = undefined;
yield [
path,
undefined
];
if (matches) {
path = matches[1];
alpha = matches[2];
yield [
path,
alpha
];
}
}
/**
*
* @param {any} config
* @param {string} path
* @param {any} defaultValue
*/ function resolvePath(config, path, defaultValue) {
const results = Array.from(toPaths(path)).map(([path, alpha])=>{
return Object.assign(validatePath(config, path, defaultValue, {
opacityValue: alpha
}), {
resolvedPath: path,
alpha
});
});
var _results_find;
return (_results_find = results.find((result)=>result.isValid)) !== null && _results_find !== void 0 ? _results_find : results[0];
}
function _default(context) {
let config = context.tailwindConfig;
let functions = {
theme: (node, path, ...defaultValue)=>{
let { isValid, value, error, alpha } = resolvePath(config, path, defaultValue.length ? defaultValue : undefined);
if (!isValid) {
var _parentNode_raws_tailwind;
let parentNode = node.parent;
let candidate = parentNode === null || parentNode === void 0 ? void 0 : (_parentNode_raws_tailwind = parentNode.raws.tailwind) === null || _parentNode_raws_tailwind === void 0 ? void 0 : _parentNode_raws_tailwind.candidate;
if (parentNode && candidate !== undefined) {
// Remove this utility from any caches
context.markInvalidUtilityNode(parentNode);
// Remove the CSS node from the markup
parentNode.remove();
// Show a warning
_log.default.warn('invalid-theme-key-in-class', [
`The utility \`${candidate}\` contains an invalid theme value and was not generated.`
]);
return;
}
throw node.error(error);
}
let maybeColor = (0, _pluginUtils.parseColorFormat)(value);
let isColorFunction = maybeColor !== undefined && typeof maybeColor === 'function';
if (alpha !== undefined || isColorFunction) {
if (alpha === undefined) {
alpha = 1.0;
}
value = (0, _withAlphaVariable.withAlphaValue)(maybeColor, alpha, maybeColor);
}
return value;
},
screen: (node, screen)=>{
screen = screen.replace(/^['"]+/g, '').replace(/['"]+$/g, '');
let screens = (0, _normalizeScreens.normalizeScreens)(config.theme.screens);
let screenDefinition = screens.find(({ name })=>name === screen);
if (!screenDefinition) {
throw node.error(`The '${screen}' screen does not exist in your theme.`);
}
return (0, _buildMediaQuery.default)(screenDefinition);
}
};
return (root)=>{
root.walk((node)=>{
let property = nodeTypePropertyMap[node.type];
if (property === undefined) {
return;
}
node[property] = resolveFunctions(node, node[property], functions);
});
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return expandApplyAtRules;
}
});
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
const _generateRules = require("./generateRules");
const _escapeClassName = /*#__PURE__*/ _interop_require_default(require("../util/escapeClassName"));
const _applyImportantSelector = require("../util/applyImportantSelector");
const _pseudoElements = require("../util/pseudoElements");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
/** @typedef {Map<string, [any, import('postcss').Rule[]]>} ApplyCache */ function extractClasses(node) {
/** @type {Map<string, Set<string>>} */ let groups = new Map();
let container = _postcss.default.root({
nodes: [
node.clone()
]
});
container.walkRules((rule)=>{
(0, _postcssselectorparser.default)((selectors)=>{
selectors.walkClasses((classSelector)=>{
let parentSelector = classSelector.parent.toString();
let classes = groups.get(parentSelector);
if (!classes) {
groups.set(parentSelector, classes = new Set());
}
classes.add(classSelector.value);
});
}).processSync(rule.selector);
});
let normalizedGroups = Array.from(groups.values(), (classes)=>Array.from(classes));
let classes = normalizedGroups.flat();
return Object.assign(classes, {
groups: normalizedGroups
});
}
let selectorExtractor = (0, _postcssselectorparser.default)();
/**
* @param {string} ruleSelectors
*/ function extractSelectors(ruleSelectors) {
return selectorExtractor.astSync(ruleSelectors);
}
function extractBaseCandidates(candidates, separator) {
let baseClasses = new Set();
for (let candidate of candidates){
baseClasses.add(candidate.split(separator).pop());
}
return Array.from(baseClasses);
}
function prefix(context, selector) {
let prefix = context.tailwindConfig.prefix;
return typeof prefix === 'function' ? prefix(selector) : prefix + selector;
}
function* pathToRoot(node) {
yield node;
while(node.parent){
yield node.parent;
node = node.parent;
}
}
/**
* Only clone the node itself and not its children
*
* @param {*} node
* @param {*} overrides
* @returns
*/ function shallowClone(node, overrides = {}) {
let children = node.nodes;
node.nodes = [];
let tmp = node.clone(overrides);
node.nodes = children;
return tmp;
}
/**
* Clone just the nodes all the way to the top that are required to represent
* this singular rule in the tree.
*
* For example, if we have CSS like this:
* ```css
* @media (min-width: 768px) {
* @supports (display: grid) {
* .foo {
* display: grid;
* grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
* }
* }
*
* @supports (backdrop-filter: blur(1px)) {
* .bar {
* backdrop-filter: blur(1px);
* }
* }
*
* .baz {
* color: orange;
* }
* }
* ```
*
* And we're cloning `.bar` it'll return a cloned version of what's required for just that single node:
*
* ```css
* @media (min-width: 768px) {
* @supports (backdrop-filter: blur(1px)) {
* .bar {
* backdrop-filter: blur(1px);
* }
* }
* }
* ```
*
* @param {import('postcss').Node} node
*/ function nestedClone(node) {
for (let parent of pathToRoot(node)){
if (node === parent) {
continue;
}
if (parent.type === 'root') {
break;
}
node = shallowClone(parent, {
nodes: [
node
]
});
}
return node;
}
/**
* @param {import('postcss').Root} root
*/ function buildLocalApplyCache(root, context) {
/** @type {ApplyCache} */ let cache = new Map();
root.walkRules((rule)=>{
// Ignore rules generated by Tailwind
for (let node of pathToRoot(rule)){
var _node_raws_tailwind;
if (((_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.layer) !== undefined) {
return;
}
}
// Clone what's required to represent this singular rule in the tree
let container = nestedClone(rule);
let sort = context.offsets.create('user');
for (let className of extractClasses(rule)){
let list = cache.get(className) || [];
cache.set(className, list);
list.push([
{
layer: 'user',
sort,
important: false
},
container
]);
}
});
return cache;
}
/**
* @returns {ApplyCache}
*/ function buildApplyCache(applyCandidates, context) {
for (let candidate of applyCandidates){
if (context.notClassCache.has(candidate) || context.applyClassCache.has(candidate)) {
continue;
}
if (context.classCache.has(candidate)) {
context.applyClassCache.set(candidate, context.classCache.get(candidate).map(([meta, rule])=>[
meta,
rule.clone()
]));
continue;
}
let matches = Array.from((0, _generateRules.resolveMatches)(candidate, context));
if (matches.length === 0) {
context.notClassCache.add(candidate);
continue;
}
context.applyClassCache.set(candidate, matches);
}
return context.applyClassCache;
}
/**
* Build a cache only when it's first used
*
* @param {() => ApplyCache} buildCacheFn
* @returns {ApplyCache}
*/ function lazyCache(buildCacheFn) {
let cache = null;
return {
get: (name)=>{
cache = cache || buildCacheFn();
return cache.get(name);
},
has: (name)=>{
cache = cache || buildCacheFn();
return cache.has(name);
}
};
}
/**
* Take a series of multiple caches and merge
* them so they act like one large cache
*
* @param {ApplyCache[]} caches
* @returns {ApplyCache}
*/ function combineCaches(caches) {
return {
get: (name)=>caches.flatMap((cache)=>cache.get(name) || []),
has: (name)=>caches.some((cache)=>cache.has(name))
};
}
function extractApplyCandidates(params) {
let candidates = params.split(/[\s\t\n]+/g);
if (candidates[candidates.length - 1] === '!important') {
return [
candidates.slice(0, -1),
true
];
}
return [
candidates,
false
];
}
function processApply(root, context, localCache) {
let applyCandidates = new Set();
// Collect all @apply rules and candidates
let applies = [];
root.walkAtRules('apply', (rule)=>{
let [candidates] = extractApplyCandidates(rule.params);
for (let util of candidates){
applyCandidates.add(util);
}
applies.push(rule);
});
// Start the @apply process if we have rules with @apply in them
if (applies.length === 0) {
return;
}
// Fill up some caches!
let applyClassCache = combineCaches([
localCache,
buildApplyCache(applyCandidates, context)
]);
/**
* When we have an apply like this:
*
* .abc {
* @apply hover:font-bold;
* }
*
* What we essentially will do is resolve to this:
*
* .abc {
* @apply .hover\:font-bold:hover {
* font-weight: 500;
* }
* }
*
* Notice that the to-be-applied class is `.hover\:font-bold:hover` and that the utility candidate was `hover:font-bold`.
* What happens in this function is that we prepend a `.` and escape the candidate.
* This will result in `.hover\:font-bold`
* Which means that we can replace `.hover\:font-bold` with `.abc` in `.hover\:font-bold:hover` resulting in `.abc:hover`
*
* @param {string} selector
* @param {string} utilitySelectors
* @param {string} candidate
*/ function replaceSelector(selector, utilitySelectors, candidate) {
let selectorList = extractSelectors(selector);
let utilitySelectorsList = extractSelectors(utilitySelectors);
let candidateList = extractSelectors(`.${(0, _escapeClassName.default)(candidate)}`);
let candidateClass = candidateList.nodes[0].nodes[0];
selectorList.each((sel)=>{
/** @type {Set<import('postcss-selector-parser').Selector>} */ let replaced = new Set();
utilitySelectorsList.each((utilitySelector)=>{
let hasReplaced = false;
utilitySelector = utilitySelector.clone();
utilitySelector.walkClasses((node)=>{
if (node.value !== candidateClass.value) {
return;
}
// Don't replace multiple instances of the same class
// This is theoretically correct but only partially
// We'd need to generate every possible permutation of the replacement
// For example with `.foo + .foo { … }` and `section { @apply foo; }`
// We'd need to generate all of these:
// - `.foo + .foo`
// - `.foo + section`
// - `section + .foo`
// - `section + section`
if (hasReplaced) {
return;
}
// Since you can only `@apply` class names this is sufficient
// We want to replace the matched class name with the selector the user is using
// Ex: Replace `.text-blue-500` with `.foo.bar:is(.something-cool)`
node.replaceWith(...sel.nodes.map((node)=>node.clone()));
// Record that we did something and we want to use this new selector
replaced.add(utilitySelector);
hasReplaced = true;
});
});
// Sort tag names before class names (but only sort each group (separated by a combinator)
// separately and not in total)
// This happens when replacing `.bar` in `.foo.bar` with a tag like `section`
for (let sel of replaced){
let groups = [
[]
];
for (let node of sel.nodes){
if (node.type === 'combinator') {
groups.push(node);
groups.push([]);
} else {
let last = groups[groups.length - 1];
last.push(node);
}
}
sel.nodes = [];
for (let group of groups){
if (Array.isArray(group)) {
group.sort((a, b)=>{
if (a.type === 'tag' && b.type === 'class') {
return -1;
} else if (a.type === 'class' && b.type === 'tag') {
return 1;
} else if (a.type === 'class' && b.type === 'pseudo' && b.value.startsWith('::')) {
return -1;
} else if (a.type === 'pseudo' && a.value.startsWith('::') && b.type === 'class') {
return 1;
}
return 0;
});
}
sel.nodes = sel.nodes.concat(group);
}
}
sel.replaceWith(...replaced);
});
return selectorList.toString();
}
let perParentApplies = new Map();
// Collect all apply candidates and their rules
for (let apply of applies){
let [candidates] = perParentApplies.get(apply.parent) || [
[],
apply.source
];
perParentApplies.set(apply.parent, [
candidates,
apply.source
]);
let [applyCandidates, important] = extractApplyCandidates(apply.params);
if (apply.parent.type === 'atrule') {
if (apply.parent.name === 'screen') {
let screenType = apply.parent.params;
throw apply.error(`@apply is not supported within nested at-rules like @screen. We suggest you write this as @apply ${applyCandidates.map((c)=>`${screenType}:${c}`).join(' ')} instead.`);
}
throw apply.error(`@apply is not supported within nested at-rules like @${apply.parent.name}. You can fix this by un-nesting @${apply.parent.name}.`);
}
for (let applyCandidate of applyCandidates){
if ([
prefix(context, 'group'),
prefix(context, 'peer')
].includes(applyCandidate)) {
// TODO: Link to specific documentation page with error code.
throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`);
}
if (!applyClassCache.has(applyCandidate)) {
throw apply.error(`The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.`);
}
let rules = applyClassCache.get(applyCandidate);
candidates.push([
applyCandidate,
important,
rules
]);
}
}
for (let [parent, [candidates, atApplySource]] of perParentApplies){
let siblings = [];
for (let [applyCandidate, important, rules] of candidates){
let potentialApplyCandidates = [
applyCandidate,
...extractBaseCandidates([
applyCandidate
], context.tailwindConfig.separator)
];
for (let [meta, node] of rules){
let parentClasses = extractClasses(parent);
let nodeClasses = extractClasses(node);
// When we encounter a rule like `.dark .a, .b { … }` we only want to be left with `[.dark, .a]` if the base applyCandidate is `.a` or with `[.b]` if the base applyCandidate is `.b`
// So we've split them into groups
nodeClasses = nodeClasses.groups.filter((classList)=>classList.some((className)=>potentialApplyCandidates.includes(className))).flat();
// Add base utility classes from the @apply node to the list of
// classes to check whether it intersects and therefore results in a
// circular dependency or not.
//
// E.g.:
// .foo {
// @apply hover:a; // This applies "a" but with a modifier
// }
//
// We only have to do that with base classes of the `node`, not of the `parent`
// E.g.:
// .hover\:foo {
// @apply bar;
// }
// .bar {
// @apply foo;
// }
//
// This should not result in a circular dependency because we are
// just applying `.foo` and the rule above is `.hover\:foo` which is
// unrelated. However, if we were to apply `hover:foo` then we _did_
// have to include this one.
nodeClasses = nodeClasses.concat(extractBaseCandidates(nodeClasses, context.tailwindConfig.separator));
let intersects = parentClasses.some((selector)=>nodeClasses.includes(selector));
if (intersects) {
throw node.error(`You cannot \`@apply\` the \`${applyCandidate}\` utility here because it creates a circular dependency.`);
}
let root = _postcss.default.root({
nodes: [
node.clone()
]
});
// Make sure every node in the entire tree points back at the @apply rule that generated it
root.walk((node)=>{
node.source = atApplySource;
});
let canRewriteSelector = node.type !== 'atrule' || node.type === 'atrule' && node.name !== 'keyframes';
if (canRewriteSelector) {
root.walkRules((rule)=>{
// Let's imagine you have the following structure:
//
// .foo {
// @apply bar;
// }
//
// @supports (a: b) {
// .bar {
// color: blue
// }
//
// .something-unrelated {}
// }
//
// In this case we want to apply `.bar` but it happens to be in
// an atrule node. We clone that node instead of the nested one
// because we still want that @supports rule to be there once we
// applied everything.
//
// However it happens to be that the `.something-unrelated` is
// also in that same shared @supports atrule. This is not good,
// and this should not be there. The good part is that this is
// a clone already and it can be safely removed. The question is
// how do we know we can remove it. Basically what we can do is
// match it against the applyCandidate that you want to apply. If
// it doesn't match the we can safely delete it.
//
// If we didn't do this, then the `replaceSelector` function
// would have replaced this with something that didn't exist and
// therefore it removed the selector altogether. In this specific
// case it would result in `{}` instead of `.something-unrelated {}`
if (!extractClasses(rule).some((candidate)=>candidate === applyCandidate)) {
rule.remove();
return;
}
// Strip the important selector from the parent selector if at the beginning
let importantSelector = typeof context.tailwindConfig.important === 'string' ? context.tailwindConfig.important : null;
// We only want to move the "important" selector if this is a Tailwind-generated utility
// We do *not* want to do this for user CSS that happens to be structured the same
let isGenerated = parent.raws.tailwind !== undefined;
let parentSelector = isGenerated && importantSelector && parent.selector.indexOf(importantSelector) === 0 ? parent.selector.slice(importantSelector.length) : parent.selector;
// If the selector becomes empty after replacing the important selector
// This means that it's the same as the parent selector and we don't want to replace it
// Otherwise we'll crash
if (parentSelector === '') {
parentSelector = parent.selector;
}
rule.selector = replaceSelector(parentSelector, rule.selector, applyCandidate);
// And then re-add it if it was removed
if (importantSelector && parentSelector !== parent.selector) {
rule.selector = (0, _applyImportantSelector.applyImportantSelector)(rule.selector, importantSelector);
}
rule.walkDecls((d)=>{
d.important = meta.important || important;
});
// Move pseudo elements to the end of the selector (if necessary)
let selector = (0, _postcssselectorparser.default)().astSync(rule.selector);
selector.each((sel)=>(0, _pseudoElements.movePseudos)(sel));
rule.selector = selector.toString();
});
}
// It could be that the node we were inserted was removed because the class didn't match
// If that was the *only* rule in the parent, then we have nothing add so we skip it
if (!root.nodes[0]) {
continue;
}
// Insert it
siblings.push([
meta.sort,
root.nodes[0]
]);
}
}
// Inject the rules, sorted, correctly
let nodes = context.offsets.sort(siblings).map((s)=>s[1]);
// `parent` refers to the node at `.abc` in: .abc { @apply mt-2 }
parent.after(nodes);
}
for (let apply of applies){
// If there are left-over declarations, just remove the @apply
if (apply.parent.nodes.length > 1) {
apply.remove();
} else {
// The node is empty, drop the full node
apply.parent.remove();
}
}
// Do it again, in case we have other `@apply` rules
processApply(root, context, localCache);
}
function expandApplyAtRules(context) {
return (root)=>{
// Build a cache of the user's CSS so we can use it to resolve classes used by @apply
let localCache = lazyCache(()=>buildLocalApplyCache(root, context));
processApply(root, context, localCache);
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return expandTailwindAtRules;
}
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _quicklru = /*#__PURE__*/ _interop_require_default(require("@alloc/quick-lru"));
const _oxide = require("@tailwindcss/oxide");
const _sharedState = /*#__PURE__*/ _interop_require_wildcard(require("./sharedState"));
const _generateRules = require("./generateRules");
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log"));
const _cloneNodes = /*#__PURE__*/ _interop_require_default(require("../util/cloneNodes"));
const _defaultExtractor = require("./defaultExtractor");
const _featureFlags = require("../featureFlags");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
let env = _sharedState.env;
const builtInExtractors = {
DEFAULT: _defaultExtractor.defaultExtractor
};
const builtInTransformers = {
DEFAULT: (content)=>content,
svelte: (content)=>content.replace(/(?:^|\s)class:/g, ' ')
};
function getExtractor(context, fileExtension) {
let extractors = context.tailwindConfig.content.extract;
return extractors[fileExtension] || extractors.DEFAULT || builtInExtractors[fileExtension] || // Because we call `DEFAULT(context)`, the returning function is always a new function without a
// stable identity. Marking it with `DEFAULT_EXTRACTOR` allows us to check if it is the default
// extractor without relying on the function identity.
Object.assign(builtInExtractors.DEFAULT(context), {
DEFAULT_EXTRACTOR: true
});
}
function getTransformer(tailwindConfig, fileExtension) {
let transformers = tailwindConfig.content.transform;
return transformers[fileExtension] || transformers.DEFAULT || builtInTransformers[fileExtension] || builtInTransformers.DEFAULT;
}
let extractorCache = new WeakMap();
// Scans template contents for possible classes. This is a hot path on initial build but
// not too important for subsequent builds. The faster the better though — if we can speed
// up these regexes by 50% that could cut initial build time by like 20%.
function getClassCandidates(content, extractor, candidates, seen) {
if (!extractorCache.has(extractor)) {
extractorCache.set(extractor, new _quicklru.default({
maxSize: 25000
}));
}
for (let line of content.split('\n')){
line = line.trim();
if (seen.has(line)) {
continue;
}
seen.add(line);
if (extractorCache.get(extractor).has(line)) {
for (let match of extractorCache.get(extractor).get(line)){
candidates.add(match);
}
} else {
let extractorMatches = extractor(line).filter((s)=>s !== '!*');
let lineMatchesSet = new Set(extractorMatches);
for (let match of lineMatchesSet){
candidates.add(match);
}
extractorCache.get(extractor).set(line, lineMatchesSet);
}
}
}
/**
*
* @param {[import('./offsets.js').RuleOffset, import('postcss').Node][]} rules
* @param {*} context
*/ function buildStylesheet(rules, context) {
let sortedRules = context.offsets.sort(rules);
let returnValue = {
base: new Set(),
defaults: new Set(),
components: new Set(),
utilities: new Set(),
variants: new Set()
};
for (let [sort, rule] of sortedRules){
returnValue[sort.layer].add(rule);
}
return returnValue;
}
function expandTailwindAtRules(context) {
return async (root)=>{
let layerNodes = {
base: null,
components: null,
utilities: null,
variants: null
};
root.walkAtRules((rule)=>{
// Make sure this file contains Tailwind directives. If not, we can save
// a lot of work and bail early. Also we don't have to register our touch
// file as a dependency since the output of this CSS does not depend on
// the source of any templates. Think Vue <style> blocks for example.
if (rule.name === 'tailwind') {
if (Object.keys(layerNodes).includes(rule.params)) {
layerNodes[rule.params] = rule;
}
}
});
if (Object.values(layerNodes).every((n)=>n === null)) {
return root;
}
var _context_candidates;
// ---
// Find potential rules in changed files
let candidates = new Set([
...(_context_candidates = context.candidates) !== null && _context_candidates !== void 0 ? _context_candidates : [],
_sharedState.NOT_ON_DEMAND
]);
let seen = new Set();
env.DEBUG && console.time('Reading changed files');
/** @type {[item: {file?: string, content?: string}, meta: {transformer: any, extractor: any}][]} */ let regexParserContent = [];
/** @type {{file?: string, content?: string}[]} */ let rustParserContent = [];
for (let item of context.changedContent){
let transformer = getTransformer(context.tailwindConfig, item.extension);
let extractor = getExtractor(context, item.extension);
if ((0, _featureFlags.flagEnabled)(context.tailwindConfig, 'oxideParser') && transformer === builtInTransformers.DEFAULT && (extractor === null || extractor === void 0 ? void 0 : extractor.DEFAULT_EXTRACTOR) === true) {
rustParserContent.push(item);
} else {
regexParserContent.push([
item,
{
transformer,
extractor
}
]);
}
}
// Read files using our newer, faster parser when:
// - Oxide is enabled; AND
// - The file is using default transfomers and extractors
if (rustParserContent.length > 0) {
for (let candidate of (0, _oxide.parseCandidateStrings)(rustParserContent, _oxide.IO.Parallel | _oxide.Parsing.Parallel)){
candidates.add(candidate);
}
}
// Otherwise, read any files in node and parse with regexes
const BATCH_SIZE = 500;
for(let i = 0; i < regexParserContent.length; i += BATCH_SIZE){
let batch = regexParserContent.slice(i, i + BATCH_SIZE);
await Promise.all(batch.map(async ([{ file, content }, { transformer, extractor }])=>{
content = file ? await _fs.default.promises.readFile(file, 'utf8') : content;
getClassCandidates(transformer(content), extractor, candidates, seen);
}));
}
env.DEBUG && console.timeEnd('Reading changed files');
// ---
// Generate the actual CSS
let classCacheCount = context.classCache.size;
env.DEBUG && console.time('Generate rules');
env.DEBUG && console.time('Sorting candidates');
// TODO: only sort if we are not using the oxide parser (flagEnabled(context.tailwindConfig,
// 'oxideParser')) AND if we got all the candidates form the oxideParser alone. This will not
// be the case currently if you have custom transformers / extractors.
let sortedCandidates = new Set([
...candidates
].sort((a, z)=>{
if (a === z) return 0;
if (a < z) return -1;
return 1;
}));
env.DEBUG && console.timeEnd('Sorting candidates');
(0, _generateRules.generateRules)(sortedCandidates, context);
env.DEBUG && console.timeEnd('Generate rules');
// We only ever add to the classCache, so if it didn't grow, there is nothing new.
env.DEBUG && console.time('Build stylesheet');
if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
context.stylesheetCache = buildStylesheet([
...context.ruleCache
], context);
}
env.DEBUG && console.timeEnd('Build stylesheet');
let { defaults: defaultNodes, base: baseNodes, components: componentNodes, utilities: utilityNodes, variants: screenNodes } = context.stylesheetCache;
// ---
// Replace any Tailwind directives with generated CSS
if (layerNodes.base) {
layerNodes.base.before((0, _cloneNodes.default)([
...baseNodes,
...defaultNodes
], layerNodes.base.source, {
layer: 'base'
}));
layerNodes.base.remove();
}
if (layerNodes.components) {
layerNodes.components.before((0, _cloneNodes.default)([
...componentNodes
], layerNodes.components.source, {
layer: 'components'
}));
layerNodes.components.remove();
}
if (layerNodes.utilities) {
layerNodes.utilities.before((0, _cloneNodes.default)([
...utilityNodes
], layerNodes.utilities.source, {
layer: 'utilities'
}));
layerNodes.utilities.remove();
}
// We do post-filtering to not alter the emitted order of the variants
const variantNodes = Array.from(screenNodes).filter((node)=>{
var _node_raws_tailwind;
const parentLayer = (_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.parentLayer;
if (parentLayer === 'components') {
return layerNodes.components !== null;
}
if (parentLayer === 'utilities') {
return layerNodes.utilities !== null;
}
return true;
});
if (layerNodes.variants) {
layerNodes.variants.before((0, _cloneNodes.default)(variantNodes, layerNodes.variants.source, {
layer: 'variants'
}));
layerNodes.variants.remove();
} else if (variantNodes.length > 0) {
let cloned = (0, _cloneNodes.default)(variantNodes, undefined, {
layer: 'variants'
});
cloned.forEach((node)=>{
var _node_raws_tailwind;
var _node_raws_tailwind_parentLayer;
let parentLayer = (_node_raws_tailwind_parentLayer = (_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.parentLayer) !== null && _node_raws_tailwind_parentLayer !== void 0 ? _node_raws_tailwind_parentLayer : null;
node.walk((n)=>{
if (!n.source) {
n.source = layerNodes[parentLayer].source;
}
});
});
root.append(cloned);
}
var _root_source_end;
// TODO: Why is the root node having no source location for `end` possible?
root.source.end = (_root_source_end = root.source.end) !== null && _root_source_end !== void 0 ? _root_source_end : root.source.start;
// If we've got a utility layer and no utilities are generated there's likely something wrong
const hasUtilityVariants = variantNodes.some((node)=>{
var _node_raws_tailwind;
return ((_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.parentLayer) === 'utilities';
});
if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
_log.default.warn('content-problems', [
'No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.',
'https://tailwindcss.com/docs/content-configuration'
]);
}
// ---
if (env.DEBUG) {
console.log('Potential classes: ', candidates.size);
console.log('Active contexts: ', _sharedState.contextSourcesMap.size);
}
// Clear the cache for the changed files
context.changedContent = [];
// Cleanup any leftover @layer atrules
root.walkAtRules('layer', (rule)=>{
if (Object.keys(layerNodes).includes(rule.params)) {
rule.remove();
}
});
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "findAtConfigPath", {
enumerable: true,
get: function() {
return findAtConfigPath;
}
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function findAtConfigPath(root, result) {
let configPath = null;
let relativeTo = null;
root.walkAtRules('config', (rule)=>{
var _rule_source;
var _rule_source_input_file, _ref;
relativeTo = (_ref = (_rule_source_input_file = (_rule_source = rule.source) === null || _rule_source === void 0 ? void 0 : _rule_source.input.file) !== null && _rule_source_input_file !== void 0 ? _rule_source_input_file : result.opts.from) !== null && _ref !== void 0 ? _ref : null;
if (relativeTo === null) {
throw rule.error('The `@config` directive cannot be used without setting `from` in your PostCSS config.');
}
if (configPath) {
throw rule.error('Only one `@config` directive is allowed per file.');
}
let matches = rule.params.match(/(['"])(.*?)\1/);
if (!matches) {
throw rule.error('A path is required when using the `@config` directive.');
}
let inputPath = matches[2];
if (_path.default.isAbsolute(inputPath)) {
throw rule.error('The `@config` directive cannot be used with an absolute path.');
}
configPath = _path.default.resolve(_path.default.dirname(relativeTo), inputPath);
if (!_fs.default.existsSync(configPath)) {
throw rule.error(`The config file at "${inputPath}" does not exist. Make sure the path is correct and the file exists.`);
}
rule.remove();
});
return configPath ? configPath : null;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
generateRules: function() {
return generateRules;
},
getClassNameFromSelector: function() {
return getClassNameFromSelector;
},
resolveMatches: function() {
return resolveMatches;
}
});
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
const _parseObjectStyles = /*#__PURE__*/ _interop_require_default(require("../util/parseObjectStyles"));
const _isPlainObject = /*#__PURE__*/ _interop_require_default(require("../util/isPlainObject"));
const _prefixSelector = /*#__PURE__*/ _interop_require_default(require("../util/prefixSelector"));
const _pluginUtils = require("../util/pluginUtils");
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log"));
const _sharedState = /*#__PURE__*/ _interop_require_wildcard(require("./sharedState"));
const _formatVariantSelector = require("../util/formatVariantSelector");
const _nameClass = require("../util/nameClass");
const _dataTypes = require("../util/dataTypes");
const _setupContextUtils = require("./setupContextUtils");
const _isSyntacticallyValidPropertyValue = /*#__PURE__*/ _interop_require_default(require("../util/isSyntacticallyValidPropertyValue"));
const _splitAtTopLevelOnly = require("../util/splitAtTopLevelOnly.js");
const _applyImportantSelector = require("../util/applyImportantSelector");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
let classNameParser = (0, _postcssselectorparser.default)((selectors)=>{
return selectors.first.filter(({ type })=>type === 'class').pop().value;
});
function getClassNameFromSelector(selector) {
return classNameParser.transformSync(selector);
}
// Generate match permutations for a class candidate, like:
// ['ring-offset-blue', '100']
// ['ring-offset', 'blue-100']
// ['ring', 'offset-blue-100']
// Example with dynamic classes:
// ['grid-cols', '[[linename],1fr,auto]']
// ['grid', 'cols-[[linename],1fr,auto]']
function* candidatePermutations(candidate) {
let lastIndex = Infinity;
while(lastIndex >= 0){
let dashIdx;
let wasSlash = false;
if (lastIndex === Infinity && candidate.endsWith(']')) {
let bracketIdx = candidate.indexOf('[');
// If character before `[` isn't a dash or a slash, this isn't a dynamic class
// e.g. string[]
if (candidate[bracketIdx - 1] === '-') {
dashIdx = bracketIdx - 1;
} else if (candidate[bracketIdx - 1] === '/') {
dashIdx = bracketIdx - 1;
wasSlash = true;
} else {
dashIdx = -1;
}
} else if (lastIndex === Infinity && candidate.includes('/')) {
dashIdx = candidate.lastIndexOf('/');
wasSlash = true;
} else {
dashIdx = candidate.lastIndexOf('-', lastIndex);
}
if (dashIdx < 0) {
break;
}
let prefix = candidate.slice(0, dashIdx);
let modifier = candidate.slice(wasSlash ? dashIdx : dashIdx + 1);
lastIndex = dashIdx - 1;
// TODO: This feels a bit hacky
if (prefix === '' || modifier === '/') {
continue;
}
yield [
prefix,
modifier
];
}
}
function applyPrefix(matches, context) {
if (matches.length === 0 || context.tailwindConfig.prefix === '') {
return matches;
}
for (let match of matches){
let [meta] = match;
if (meta.options.respectPrefix) {
let container = _postcss.default.root({
nodes: [
match[1].clone()
]
});
let classCandidate = match[1].raws.tailwind.classCandidate;
container.walkRules((r)=>{
// If this is a negative utility with a dash *before* the prefix we
// have to ensure that the generated selector matches the candidate
// Not doing this will cause `-tw-top-1` to generate the class `.tw--top-1`
// The disconnect between candidate <-> class can cause @apply to hard crash.
let shouldPrependNegative = classCandidate.startsWith('-');
r.selector = (0, _prefixSelector.default)(context.tailwindConfig.prefix, r.selector, shouldPrependNegative);
});
match[1] = container.nodes[0];
}
}
return matches;
}
function applyImportant(matches, classCandidate) {
if (matches.length === 0) {
return matches;
}
let result = [];
function isInKeyframes(rule) {
return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === 'keyframes';
}
for (let [meta, rule] of matches){
let container = _postcss.default.root({
nodes: [
rule.clone()
]
});
container.walkRules((r)=>{
// Declarations inside keyframes cannot be marked as important
// They will be ignored by the browser
if (isInKeyframes(r)) {
return;
}
let ast = (0, _postcssselectorparser.default)().astSync(r.selector);
// Remove extraneous selectors that do not include the base candidate
ast.each((sel)=>(0, _formatVariantSelector.eliminateIrrelevantSelectors)(sel, classCandidate));
// Update all instances of the base candidate to include the important marker
(0, _pluginUtils.updateAllClasses)(ast, (className)=>className === classCandidate ? `!${className}` : className);
r.selector = ast.toString();
r.walkDecls((d)=>d.important = true);
});
result.push([
{
...meta,
important: true
},
container.nodes[0]
]);
}
return result;
}
// Takes a list of rule tuples and applies a variant like `hover`, sm`,
// whatever to it. We used to do some extra caching here to avoid generating
// a variant of the same rule more than once, but this was never hit because
// we cache at the entire selector level further up the tree.
//
// Technically you can get a cache hit if you have `hover:focus:text-center`
// and `focus:hover:text-center` in the same project, but it doesn't feel
// worth the complexity for that case.
function applyVariant(variant, matches, context) {
if (matches.length === 0) {
return matches;
}
/** @type {{modifier: string | null, value: string | null}} */ let args = {
modifier: null,
value: _sharedState.NONE
};
// Retrieve "modifier"
{
let [baseVariant, ...modifiers] = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(variant, '/');
// This is a hack to support variants with `/` in them, like `ar-1/10/20:text-red-500`
// In this case 1/10 is a value but /20 is a modifier
if (modifiers.length > 1) {
baseVariant = baseVariant + '/' + modifiers.slice(0, -1).join('/');
modifiers = modifiers.slice(-1);
}
if (modifiers.length && !context.variantMap.has(variant)) {
variant = baseVariant;
args.modifier = modifiers[0];
}
}
// Retrieve "arbitrary value"
if (variant.endsWith(']') && !variant.startsWith('[')) {
// We either have:
// @[200px]
// group-[:hover]
//
// But we don't want:
// @-[200px] (`-` is incorrect)
// group[:hover] (`-` is missing)
let match = /(.)(-?)\[(.*)\]/g.exec(variant);
if (match) {
let [, char, separator, value] = match;
// @-[200px] case
if (char === '@' && separator === '-') return [];
// group[:hover] case
if (char !== '@' && separator === '') return [];
variant = variant.replace(`${separator}[${value}]`, '');
args.value = value;
}
}
// Register arbitrary variants
if (isArbitraryValue(variant) && !context.variantMap.has(variant)) {
let sort = context.offsets.recordVariant(variant);
let selector = (0, _dataTypes.normalize)(variant.slice(1, -1));
let selectors = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(selector, ',');
// We do not support multiple selectors for arbitrary variants
if (selectors.length > 1) {
return [];
}
if (!selectors.every(_setupContextUtils.isValidVariantFormatString)) {
return [];
}
let records = selectors.map((sel, idx)=>[
context.offsets.applyParallelOffset(sort, idx),
(0, _setupContextUtils.parseVariant)(sel.trim())
]);
context.variantMap.set(variant, records);
}
if (context.variantMap.has(variant)) {
var _context_variantOptions_get;
let isArbitraryVariant = isArbitraryValue(variant);
var _context_variantOptions_get_INTERNAL_FEATURES;
let internalFeatures = (_context_variantOptions_get_INTERNAL_FEATURES = (_context_variantOptions_get = context.variantOptions.get(variant)) === null || _context_variantOptions_get === void 0 ? void 0 : _context_variantOptions_get[_setupContextUtils.INTERNAL_FEATURES]) !== null && _context_variantOptions_get_INTERNAL_FEATURES !== void 0 ? _context_variantOptions_get_INTERNAL_FEATURES : {};
let variantFunctionTuples = context.variantMap.get(variant).slice();
let result = [];
let respectPrefix = (()=>{
if (isArbitraryVariant) return false;
if (internalFeatures.respectPrefix === false) return false;
return true;
})();
for (let [meta, rule] of matches){
// Don't generate variants for user css
if (meta.layer === 'user') {
continue;
}
let container = _postcss.default.root({
nodes: [
rule.clone()
]
});
for (let [variantSort, variantFunction, containerFromArray] of variantFunctionTuples){
let clone = (containerFromArray !== null && containerFromArray !== void 0 ? containerFromArray : container).clone();
let collectedFormats = [];
function prepareBackup() {
// Already prepared, chicken out
if (clone.raws.neededBackup) {
return;
}
clone.raws.neededBackup = true;
clone.walkRules((rule)=>rule.raws.originalSelector = rule.selector);
}
function modifySelectors(modifierFunction) {
prepareBackup();
clone.each((rule)=>{
if (rule.type !== 'rule') {
return;
}
rule.selectors = rule.selectors.map((selector)=>{
return modifierFunction({
get className () {
return getClassNameFromSelector(selector);
},
selector
});
});
});
return clone;
}
let ruleWithVariant = variantFunction({
// Public API
get container () {
prepareBackup();
return clone;
},
separator: context.tailwindConfig.separator,
modifySelectors,
// Private API for now
wrap (wrapper) {
let nodes = clone.nodes;
clone.removeAll();
wrapper.append(nodes);
clone.append(wrapper);
},
format (selectorFormat) {
collectedFormats.push({
format: selectorFormat,
respectPrefix
});
},
args
});
// It can happen that a list of format strings is returned from within the function. In that
// case, we have to process them as well. We can use the existing `variantSort`.
if (Array.isArray(ruleWithVariant)) {
for (let [idx, variantFunction] of ruleWithVariant.entries()){
// This is a little bit scary since we are pushing to an array of items that we are
// currently looping over. However, you can also think of it like a processing queue
// where you keep handling jobs until everything is done and each job can queue more
// jobs if needed.
variantFunctionTuples.push([
context.offsets.applyParallelOffset(variantSort, idx),
variantFunction,
// If the clone has been modified we have to pass that back
// though so each rule can use the modified container
clone.clone()
]);
}
continue;
}
if (typeof ruleWithVariant === 'string') {
collectedFormats.push({
format: ruleWithVariant,
respectPrefix
});
}
if (ruleWithVariant === null) {
continue;
}
// We had to backup selectors, therefore we assume that somebody touched
// `container` or `modifySelectors`. Let's see if they did, so that we
// can restore the selectors, and collect the format strings.
if (clone.raws.neededBackup) {
delete clone.raws.neededBackup;
clone.walkRules((rule)=>{
let before = rule.raws.originalSelector;
if (!before) return;
delete rule.raws.originalSelector;
if (before === rule.selector) return; // No mutation happened
let modified = rule.selector;
// Rebuild the base selector, this is what plugin authors would do
// as well. E.g.: `${variant}${separator}${className}`.
// However, plugin authors probably also prepend or append certain
// classes, pseudos, ids, ...
let rebuiltBase = (0, _postcssselectorparser.default)((selectors)=>{
selectors.walkClasses((classNode)=>{
classNode.value = `${variant}${context.tailwindConfig.separator}${classNode.value}`;
});
}).processSync(before);
// Now that we know the original selector, the new selector, and
// the rebuild part in between, we can replace the part that plugin
// authors need to rebuild with `&`, and eventually store it in the
// collectedFormats. Similar to what `format('...')` would do.
//
// E.g.:
// variant: foo
// selector: .markdown > p
// modified (by plugin): .foo .foo\\:markdown > p
// rebuiltBase (internal): .foo\\:markdown > p
// format: .foo &
collectedFormats.push({
format: modified.replace(rebuiltBase, '&'),
respectPrefix
});
rule.selector = before;
});
}
// This tracks the originating layer for the variant
// For example:
// .sm:underline {} is a variant of something in the utilities layer
// .sm:container {} is a variant of the container component
clone.nodes[0].raws.tailwind = {
...clone.nodes[0].raws.tailwind,
parentLayer: meta.layer
};
var _meta_collectedFormats;
let withOffset = [
{
...meta,
sort: context.offsets.applyVariantOffset(meta.sort, variantSort, Object.assign(args, context.variantOptions.get(variant))),
collectedFormats: ((_meta_collectedFormats = meta.collectedFormats) !== null && _meta_collectedFormats !== void 0 ? _meta_collectedFormats : []).concat(collectedFormats)
},
clone.nodes[0]
];
result.push(withOffset);
}
}
return result;
}
return [];
}
function parseRules(rule, cache, options = {}) {
// PostCSS node
if (!(0, _isPlainObject.default)(rule) && !Array.isArray(rule)) {
return [
[
rule
],
options
];
}
// Tuple
if (Array.isArray(rule)) {
return parseRules(rule[0], cache, rule[1]);
}
// Simple object
if (!cache.has(rule)) {
cache.set(rule, (0, _parseObjectStyles.default)(rule));
}
return [
cache.get(rule),
options
];
}
const IS_VALID_PROPERTY_NAME = /^[a-z_-]/;
function isValidPropName(name) {
return IS_VALID_PROPERTY_NAME.test(name);
}
/**
* @param {string} declaration
* @returns {boolean}
*/ function looksLikeUri(declaration) {
// Quick bailout for obvious non-urls
// This doesn't support schemes that don't use a leading // but that's unlikely to be a problem
if (!declaration.includes('://')) {
return false;
}
try {
const url = new URL(declaration);
return url.scheme !== '' && url.host !== '';
} catch (err) {
// Definitely not a valid url
return false;
}
}
function isParsableNode(node) {
let isParsable = true;
node.walkDecls((decl)=>{
if (!isParsableCssValue(decl.prop, decl.value)) {
isParsable = false;
return false;
}
});
return isParsable;
}
function isParsableCssValue(property, value) {
// We don't want to treat [https://example.com] as a custom property
// Even though, according to the CSS grammar, it's a totally valid CSS declaration
// So we short-circuit here by checking if the custom property looks like a URL
if (looksLikeUri(`${property}:${value}`)) {
return false;
}
try {
_postcss.default.parse(`a{${property}:${value}}`).toResult();
return true;
} catch (err) {
return false;
}
}
function extractArbitraryProperty(classCandidate, context) {
var _classCandidate_match;
let [, property, value] = (_classCandidate_match = classCandidate.match(/^\[([a-zA-Z0-9-_]+):(\S+)\]$/)) !== null && _classCandidate_match !== void 0 ? _classCandidate_match : [];
if (value === undefined) {
return null;
}
if (!isValidPropName(property)) {
return null;
}
if (!(0, _isSyntacticallyValidPropertyValue.default)(value)) {
return null;
}
let normalized = (0, _dataTypes.normalize)(value, {
property
});
if (!isParsableCssValue(property, normalized)) {
return null;
}
let sort = context.offsets.arbitraryProperty();
return [
[
{
sort,
layer: 'utilities'
},
()=>({
[(0, _nameClass.asClass)(classCandidate)]: {
[property]: normalized
}
})
]
];
}
function* resolveMatchedPlugins(classCandidate, context) {
if (context.candidateRuleMap.has(classCandidate)) {
yield [
context.candidateRuleMap.get(classCandidate),
'DEFAULT'
];
}
yield* function*(arbitraryPropertyRule) {
if (arbitraryPropertyRule !== null) {
yield [
arbitraryPropertyRule,
'DEFAULT'
];
}
}(extractArbitraryProperty(classCandidate, context));
let candidatePrefix = classCandidate;
let negative = false;
const twConfigPrefix = context.tailwindConfig.prefix;
const twConfigPrefixLen = twConfigPrefix.length;
const hasMatchingPrefix = candidatePrefix.startsWith(twConfigPrefix) || candidatePrefix.startsWith(`-${twConfigPrefix}`);
if (candidatePrefix[twConfigPrefixLen] === '-' && hasMatchingPrefix) {
negative = true;
candidatePrefix = twConfigPrefix + candidatePrefix.slice(twConfigPrefixLen + 1);
}
if (negative && context.candidateRuleMap.has(candidatePrefix)) {
yield [
context.candidateRuleMap.get(candidatePrefix),
'-DEFAULT'
];
}
for (let [prefix, modifier] of candidatePermutations(candidatePrefix)){
if (context.candidateRuleMap.has(prefix)) {
yield [
context.candidateRuleMap.get(prefix),
negative ? `-${modifier}` : modifier
];
}
}
}
function splitWithSeparator(input, separator) {
if (input === _sharedState.NOT_ON_DEMAND) {
return [
_sharedState.NOT_ON_DEMAND
];
}
return (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(input, separator);
}
function* recordCandidates(matches, classCandidate) {
for (const match of matches){
var _match__options;
var _match__options_preserveSource;
match[1].raws.tailwind = {
...match[1].raws.tailwind,
classCandidate,
preserveSource: (_match__options_preserveSource = (_match__options = match[0].options) === null || _match__options === void 0 ? void 0 : _match__options.preserveSource) !== null && _match__options_preserveSource !== void 0 ? _match__options_preserveSource : false
};
yield match;
}
}
function* resolveMatches(candidate, context) {
let separator = context.tailwindConfig.separator;
let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse();
let important = false;
if (classCandidate.startsWith('!')) {
important = true;
classCandidate = classCandidate.slice(1);
}
// TODO: Reintroduce this in ways that doesn't break on false positives
// function sortAgainst(toSort, against) {
// return toSort.slice().sort((a, z) => {
// return bigSign(against.get(a)[0] - against.get(z)[0])
// })
// }
// let sorted = sortAgainst(variants, context.variantMap)
// if (sorted.toString() !== variants.toString()) {
// let corrected = sorted.reverse().concat(classCandidate).join(':')
// throw new Error(`Class ${candidate} should be written as ${corrected}`)
// }
for (let matchedPlugins of resolveMatchedPlugins(classCandidate, context)){
let matches = [];
let typesByMatches = new Map();
let [plugins, modifier] = matchedPlugins;
let isOnlyPlugin = plugins.length === 1;
for (let [sort, plugin] of plugins){
let matchesPerPlugin = [];
if (typeof plugin === 'function') {
for (let ruleSet of [].concat(plugin(modifier, {
isOnlyPlugin
}))){
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache);
for (let rule of rules){
matchesPerPlugin.push([
{
...sort,
options: {
...sort.options,
...options
}
},
rule
]);
}
}
} else if (modifier === 'DEFAULT' || modifier === '-DEFAULT') {
let ruleSet = plugin;
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache);
for (let rule of rules){
matchesPerPlugin.push([
{
...sort,
options: {
...sort.options,
...options
}
},
rule
]);
}
}
if (matchesPerPlugin.length > 0) {
var _sort_options;
var _sort_options_types, _sort_options1;
let matchingTypes = Array.from((0, _pluginUtils.getMatchingTypes)((_sort_options_types = (_sort_options = sort.options) === null || _sort_options === void 0 ? void 0 : _sort_options.types) !== null && _sort_options_types !== void 0 ? _sort_options_types : [], modifier, (_sort_options1 = sort.options) !== null && _sort_options1 !== void 0 ? _sort_options1 : {}, context.tailwindConfig)).map(([_, type])=>type);
if (matchingTypes.length > 0) {
typesByMatches.set(matchesPerPlugin, matchingTypes);
}
matches.push(matchesPerPlugin);
}
}
if (isArbitraryValue(modifier)) {
if (matches.length > 1) {
// Partition plugins in 2 categories so that we can start searching in the plugins that
// don't have `any` as a type first.
let [withAny, withoutAny] = matches.reduce((group, plugin)=>{
let hasAnyType = plugin.some(([{ options }])=>options.types.some(({ type })=>type === 'any'));
if (hasAnyType) {
group[0].push(plugin);
} else {
group[1].push(plugin);
}
return group;
}, [
[],
[]
]);
function findFallback(matches) {
// If only a single plugin matches, let's take that one
if (matches.length === 1) {
return matches[0];
}
// Otherwise, find the plugin that creates a valid rule given the arbitrary value, and
// also has the correct type which preferOnConflicts the plugin in case of clashes.
return matches.find((rules)=>{
let matchingTypes = typesByMatches.get(rules);
return rules.some(([{ options }, rule])=>{
if (!isParsableNode(rule)) {
return false;
}
return options.types.some(({ type, preferOnConflict })=>matchingTypes.includes(type) && preferOnConflict);
});
});
}
var _findFallback;
// Try to find a fallback plugin, because we already know that multiple plugins matched for
// the given arbitrary value.
let fallback = (_findFallback = findFallback(withoutAny)) !== null && _findFallback !== void 0 ? _findFallback : findFallback(withAny);
if (fallback) {
matches = [
fallback
];
} else {
let typesPerPlugin = matches.map((match)=>{
var _typesByMatches_get;
return new Set([
...(_typesByMatches_get = typesByMatches.get(match)) !== null && _typesByMatches_get !== void 0 ? _typesByMatches_get : []
]);
});
// Remove duplicates, so that we can detect proper unique types for each plugin.
for (let pluginTypes of typesPerPlugin){
for (let type of pluginTypes){
let removeFromOwnGroup = false;
for (let otherGroup of typesPerPlugin){
if (pluginTypes === otherGroup) continue;
if (otherGroup.has(type)) {
otherGroup.delete(type);
removeFromOwnGroup = true;
}
}
if (removeFromOwnGroup) pluginTypes.delete(type);
}
}
let messages = [];
for (let [idx, group] of typesPerPlugin.entries()){
for (let type of group){
let rules = matches[idx].map(([, rule])=>rule).flat().map((rule)=>rule.toString().split('\n').slice(1, -1) // Remove selector and closing '}'
.map((line)=>line.trim()).map((x)=>` ${x}`) // Re-indent
.join('\n')).join('\n\n');
messages.push(` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\``);
break;
}
}
_log.default.warn([
`The class \`${candidate}\` is ambiguous and matches multiple utilities.`,
...messages,
`If this is content and not a class, replace it with \`${candidate.replace('[', '&lsqb;').replace(']', '&rsqb;')}\` to silence this warning.`
]);
continue;
}
}
matches = matches.map((list)=>list.filter((match)=>isParsableNode(match[1])));
}
matches = matches.flat();
matches = Array.from(recordCandidates(matches, classCandidate));
matches = applyPrefix(matches, context);
if (important) {
matches = applyImportant(matches, classCandidate);
}
for (let variant of variants){
matches = applyVariant(variant, matches, context);
}
for (let match of matches){
match[1].raws.tailwind = {
...match[1].raws.tailwind,
candidate
};
// Apply final format selector
match = applyFinalFormat(match, {
context,
candidate
});
// Skip rules with invalid selectors
// This will cause the candidate to be added to the "not class"
// cache skipping it entirely for future builds
if (match === null) {
continue;
}
yield match;
}
}
}
function applyFinalFormat(match, { context, candidate }) {
if (!match[0].collectedFormats) {
return match;
}
let isValid = true;
let finalFormat;
try {
finalFormat = (0, _formatVariantSelector.formatVariantSelector)(match[0].collectedFormats, {
context,
candidate
});
} catch (e) {
// The format selector we produced is invalid
// This could be because:
// - A bug exists
// - A plugin introduced an invalid variant selector (ex: `addVariant('foo', '&;foo')`)
// - The user used an invalid arbitrary variant (ex: `[&;foo]:underline`)
// Either way the build will fail because of this
// We would rather that the build pass "silently" given that this could
// happen because of picking up invalid things when scanning content
// So we'll throw out the candidate instead
return null;
}
let container = _postcss.default.root({
nodes: [
match[1].clone()
]
});
container.walkRules((rule)=>{
if (inKeyframes(rule)) {
return;
}
try {
let selector = (0, _formatVariantSelector.finalizeSelector)(rule.selector, finalFormat, {
candidate,
context
});
// Finalize Selector determined that this candidate is irrelevant
// TODO: This elimination should happen earlier so this never happens
if (selector === null) {
rule.remove();
return;
}
rule.selector = selector;
} catch (e) {
// If this selector is invalid we also want to skip it
// But it's likely that being invalid here means there's a bug in a plugin rather than too loosely matching content
isValid = false;
return false;
}
});
if (!isValid) {
return null;
}
// If all rules have been eliminated we can skip this candidate entirely
if (container.nodes.length === 0) {
return null;
}
match[1] = container.nodes[0];
return match;
}
function inKeyframes(rule) {
return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === 'keyframes';
}
function getImportantStrategy(important) {
if (important === true) {
return (rule)=>{
if (inKeyframes(rule)) {
return;
}
rule.walkDecls((d)=>{
if (d.parent.type === 'rule' && !inKeyframes(d.parent)) {
d.important = true;
}
});
};
}
if (typeof important === 'string') {
return (rule)=>{
if (inKeyframes(rule)) {
return;
}
rule.selectors = rule.selectors.map((selector)=>{
return (0, _applyImportantSelector.applyImportantSelector)(selector, important);
});
};
}
}
function generateRules(candidates, context, isSorting = false) {
let allRules = [];
let strategy = getImportantStrategy(context.tailwindConfig.important);
for (let candidate of candidates){
if (context.notClassCache.has(candidate)) {
continue;
}
if (context.candidateRuleCache.has(candidate)) {
allRules = allRules.concat(Array.from(context.candidateRuleCache.get(candidate)));
continue;
}
let matches = Array.from(resolveMatches(candidate, context));
if (matches.length === 0) {
context.notClassCache.add(candidate);
continue;
}
context.classCache.set(candidate, matches);
var _context_candidateRuleCache_get;
let rules = (_context_candidateRuleCache_get = context.candidateRuleCache.get(candidate)) !== null && _context_candidateRuleCache_get !== void 0 ? _context_candidateRuleCache_get : new Set();
context.candidateRuleCache.set(candidate, rules);
for (const match of matches){
let [{ sort, options }, rule] = match;
if (options.respectImportant && strategy) {
let container = _postcss.default.root({
nodes: [
rule.clone()
]
});
container.walkRules(strategy);
rule = container.nodes[0];
}
// Note: We have to clone rules during sorting
// so we eliminate some shared mutable state
let newEntry = [
sort,
isSorting ? rule.clone() : rule
];
rules.add(newEntry);
context.ruleCache.add(newEntry);
allRules.push(newEntry);
}
}
return allRules;
}
function isArbitraryValue(input) {
return input.startsWith('[') && input.endsWith(']');
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return getModuleDependencies;
}
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let jsExtensions = [
'.js',
'.cjs',
'.mjs'
];
// Given the current file `a.ts`, we want to make sure that when importing `b` that we resolve
// `b.ts` before `b.js`
//
// E.g.:
//
// a.ts
// b // .ts
// c // .ts
// a.js
// b // .js or .ts
let jsResolutionOrder = [
'',
'.js',
'.cjs',
'.mjs',
'.ts',
'.cts',
'.mts',
'.jsx',
'.tsx'
];
let tsResolutionOrder = [
'',
'.ts',
'.cts',
'.mts',
'.tsx',
'.js',
'.cjs',
'.mjs',
'.jsx'
];
function resolveWithExtension(file, extensions) {
// Try to find `./a.ts`, `./a.ts`, ... from `./a`
for (let ext of extensions){
let full = `${file}${ext}`;
if (_fs.default.existsSync(full) && _fs.default.statSync(full).isFile()) {
return full;
}
}
// Try to find `./a/index.js` from `./a`
for (let ext of extensions){
let full = `${file}/index${ext}`;
if (_fs.default.existsSync(full)) {
return full;
}
}
return null;
}
function* _getModuleDependencies(filename, base, seen, ext = _path.default.extname(filename)) {
// Try to find the file
let absoluteFile = resolveWithExtension(_path.default.resolve(base, filename), jsExtensions.includes(ext) ? jsResolutionOrder : tsResolutionOrder);
if (absoluteFile === null) return; // File doesn't exist
// Prevent infinite loops when there are circular dependencies
if (seen.has(absoluteFile)) return; // Already seen
seen.add(absoluteFile);
// Mark the file as a dependency
yield absoluteFile;
// Resolve new base for new imports/requires
base = _path.default.dirname(absoluteFile);
ext = _path.default.extname(absoluteFile);
let contents = _fs.default.readFileSync(absoluteFile, 'utf-8');
// Find imports/requires
for (let match of [
...contents.matchAll(/import[\s\S]*?['"](.{3,}?)['"]/gi),
...contents.matchAll(/import[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi),
...contents.matchAll(/require\(['"`](.+)['"`]\)/gi)
]){
// Bail out if it's not a relative file
if (!match[1].startsWith('.')) continue;
yield* _getModuleDependencies(match[1], base, seen, ext);
}
}
function getModuleDependencies(absoluteFilePath) {
if (absoluteFilePath === null) return new Set();
return new Set(_getModuleDependencies(absoluteFilePath, _path.default.dirname(absoluteFilePath), new Set()));
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "handleImportAtRules", {
enumerable: true,
get: function() {
return handleImportAtRules;
}
});
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _postcssimport = /*#__PURE__*/ _interop_require_default(require("postcss-import"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const TAILWIND = Symbol();
function handleImportAtRules() {
let RESTORE_ATRULE_COMMENT = '__TAILWIND_RESTORE__';
let atRulesToRestore = [
'tailwind',
'config'
];
return [
(root)=>{
root.walkAtRules((rule)=>{
if (!atRulesToRestore.includes(rule.name)) return rule;
rule.after(_postcss.default.comment({
text: RESTORE_ATRULE_COMMENT,
raws: {
[TAILWIND]: {
rule
}
}
}));
rule.remove();
});
},
(0, _postcssimport.default)(),
(root)=>{
root.walkComments((rule)=>{
if (rule.text === RESTORE_ATRULE_COMMENT) {
rule.after(rule.raws[TAILWIND].rule);
rule.remove();
}
});
}
];
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
loadConfig: function() {
return loadConfig;
},
useCustomJiti: function() {
return useCustomJiti;
}
});
const _jiti = /*#__PURE__*/ _interop_require_default(require("jiti"));
const _sucrase = require("sucrase");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let jiti = null;
function useCustomJiti(_jiti) {
jiti = _jiti();
}
function lazyJiti() {
return jiti !== null && jiti !== void 0 ? jiti : jiti = (0, _jiti.default)(__filename, {
interopDefault: true,
transform: (opts)=>{
return (0, _sucrase.transform)(opts.source, {
transforms: [
'typescript',
'imports'
]
});
}
});
}
function loadConfig(path) {
let config = function() {
try {
return path ? require(path) : {};
} catch (e) {
return lazyJiti()(path);
}
}();
var _config_default;
return (_config_default = config.default) !== null && _config_default !== void 0 ? _config_default : config;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return normalizeTailwindDirectives;
}
});
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function normalizeTailwindDirectives(root) {
let tailwindDirectives = new Set();
let layerDirectives = new Set();
let applyDirectives = new Set();
root.walkAtRules((atRule)=>{
if (atRule.name === 'apply') {
applyDirectives.add(atRule);
}
if (atRule.name === 'tailwind') {
if (atRule.params === 'screens') {
atRule.params = 'variants';
}
tailwindDirectives.add(atRule.params);
}
if ([
'layer',
'responsive',
'variants'
].includes(atRule.name)) {
if ([
'responsive',
'variants'
].includes(atRule.name)) {
_log.default.warn(`${atRule.name}-at-rule-deprecated`, [
`The \`@${atRule.name}\` directive has been deprecated in Tailwind CSS v3.0.`,
`Use \`@layer utilities\` or \`@layer components\` instead.`,
'https://tailwindcss.com/docs/upgrade-guide#replace-variants-with-layer'
]);
}
layerDirectives.add(atRule);
}
});
if (!tailwindDirectives.has('base') || !tailwindDirectives.has('components') || !tailwindDirectives.has('utilities')) {
for (let rule of layerDirectives){
if (rule.name === 'layer' && [
'base',
'components',
'utilities'
].includes(rule.params)) {
if (!tailwindDirectives.has(rule.params)) {
throw rule.error(`\`@layer ${rule.params}\` is used but no matching \`@tailwind ${rule.params}\` directive is present.`);
}
} else if (rule.name === 'responsive') {
if (!tailwindDirectives.has('utilities')) {
throw rule.error('`@responsive` is used but `@tailwind utilities` is missing.');
}
} else if (rule.name === 'variants') {
if (!tailwindDirectives.has('utilities')) {
throw rule.error('`@variants` is used but `@tailwind utilities` is missing.');
}
}
}
}
return {
tailwindDirectives,
applyDirectives
};
}
// @ts-check
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "Offsets", {
enumerable: true,
get: function() {
return Offsets;
}
});
const _bigSign = /*#__PURE__*/ _interop_require_default(require("../util/bigSign"));
const _remapbitfield = require("./remap-bitfield.js");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
class Offsets {
/**
* @param {Layer} layer
* @returns {RuleOffset}
*/ create(layer) {
return {
layer,
parentLayer: layer,
arbitrary: 0n,
variants: 0n,
parallelIndex: 0n,
index: this.offsets[layer]++,
options: []
};
}
/**
* @returns {RuleOffset}
*/ arbitraryProperty() {
return {
...this.create('utilities'),
arbitrary: 1n
};
}
/**
* Get the offset for a variant
*
* @param {string} variant
* @param {number} index
* @returns {RuleOffset}
*/ forVariant(variant, index = 0) {
let offset = this.variantOffsets.get(variant);
if (offset === undefined) {
throw new Error(`Cannot find offset for unknown variant ${variant}`);
}
return {
...this.create('variants'),
variants: offset << BigInt(index)
};
}
/**
* @param {RuleOffset} rule
* @param {RuleOffset} variant
* @param {VariantOption} options
* @returns {RuleOffset}
*/ applyVariantOffset(rule, variant, options) {
options.variant = variant.variants;
return {
...rule,
layer: 'variants',
parentLayer: rule.layer === 'variants' ? rule.parentLayer : rule.layer,
variants: rule.variants | variant.variants,
options: options.sort ? [].concat(options, rule.options) : rule.options,
// TODO: Technically this is wrong. We should be handling parallel index on a per variant basis.
// We'll take the max of all the parallel indexes for now.
// @ts-ignore
parallelIndex: max([
rule.parallelIndex,
variant.parallelIndex
])
};
}
/**
* @param {RuleOffset} offset
* @param {number} parallelIndex
* @returns {RuleOffset}
*/ applyParallelOffset(offset, parallelIndex) {
return {
...offset,
parallelIndex: BigInt(parallelIndex)
};
}
/**
* Each variant gets 1 bit per function / rule registered.
* This is because multiple variants can be applied to a single rule and we need to know which ones are present and which ones are not.
* Additionally, every unique group of variants is grouped together in the stylesheet.
*
* This grouping is order-independent. For instance, we do not differentiate between `hover:focus` and `focus:hover`.
*
* @param {string[]} variants
* @param {(name: string) => number} getLength
*/ recordVariants(variants, getLength) {
for (let variant of variants){
this.recordVariant(variant, getLength(variant));
}
}
/**
* The same as `recordVariants` but for a single arbitrary variant at runtime.
* @param {string} variant
* @param {number} fnCount
*
* @returns {RuleOffset} The highest offset for this variant
*/ recordVariant(variant, fnCount = 1) {
this.variantOffsets.set(variant, 1n << this.reservedVariantBits);
// Ensure space is reserved for each "function" in the parallel variant
// by offsetting the next variant by the number of parallel variants
// in the one we just added.
// Single functions that return parallel variants are NOT handled separately here
// They're offset by 1 (or the number of functions) as usual
// And each rule returned is tracked separately since the functions are evaluated lazily.
// @see `RuleOffset.parallelIndex`
this.reservedVariantBits += BigInt(fnCount);
return {
...this.create('variants'),
variants: this.variantOffsets.get(variant)
};
}
/**
* @param {RuleOffset} a
* @param {RuleOffset} b
* @returns {bigint}
*/ compare(a, b) {
// Sort layers together
if (a.layer !== b.layer) {
return this.layerPositions[a.layer] - this.layerPositions[b.layer];
}
// When sorting the `variants` layer, we need to sort based on the parent layer as well within
// this variants layer.
if (a.parentLayer !== b.parentLayer) {
return this.layerPositions[a.parentLayer] - this.layerPositions[b.parentLayer];
}
// Sort based on the sorting function
for (let aOptions of a.options){
for (let bOptions of b.options){
if (aOptions.id !== bOptions.id) continue;
if (!aOptions.sort || !bOptions.sort) continue;
var _max;
let maxFnVariant = (_max = max([
aOptions.variant,
bOptions.variant
])) !== null && _max !== void 0 ? _max : 0n;
// Create a mask of 0s from bits 1..N where N represents the mask of the Nth bit
let mask = ~(maxFnVariant | maxFnVariant - 1n);
let aVariantsAfterFn = a.variants & mask;
let bVariantsAfterFn = b.variants & mask;
// If the variants the same, we _can_ sort them
if (aVariantsAfterFn !== bVariantsAfterFn) {
continue;
}
let result = aOptions.sort({
value: aOptions.value,
modifier: aOptions.modifier
}, {
value: bOptions.value,
modifier: bOptions.modifier
});
if (result !== 0) return result;
}
}
// Sort variants in the order they were registered
if (a.variants !== b.variants) {
return a.variants - b.variants;
}
// Make sure each rule returned by a parallel variant is sorted in ascending order
if (a.parallelIndex !== b.parallelIndex) {
return a.parallelIndex - b.parallelIndex;
}
// Always sort arbitrary properties after other utilities
if (a.arbitrary !== b.arbitrary) {
return a.arbitrary - b.arbitrary;
}
// Sort utilities, components, etc… in the order they were registered
return a.index - b.index;
}
/**
* Arbitrary variants are recorded in the order they're encountered.
* This means that the order is not stable between environments and sets of content files.
*
* In order to make the order stable, we need to remap the arbitrary variant offsets to
* be in alphabetical order starting from the offset of the first arbitrary variant.
*/ recalculateVariantOffsets() {
// Sort the variants by their name
let variants = Array.from(this.variantOffsets.entries()).filter(([v])=>v.startsWith('[')).sort(([a], [z])=>fastCompare(a, z));
// Sort the list of offsets
// This is not necessarily a discrete range of numbers which is why
// we're using sort instead of creating a range from min/max
let newOffsets = variants.map(([, offset])=>offset).sort((a, z)=>(0, _bigSign.default)(a - z));
// Create a map from the old offsets to the new offsets in the new sort order
/** @type {[bigint, bigint][]} */ let mapping = variants.map(([, oldOffset], i)=>[
oldOffset,
newOffsets[i]
]);
// Remove any variants that will not move letting us skip
// remapping if everything happens to be in order
return mapping.filter(([a, z])=>a !== z);
}
/**
* @template T
* @param {[RuleOffset, T][]} list
* @returns {[RuleOffset, T][]}
*/ remapArbitraryVariantOffsets(list) {
let mapping = this.recalculateVariantOffsets();
// No arbitrary variants? Nothing to do.
// Everything already in order? Nothing to do.
if (mapping.length === 0) {
return list;
}
// Remap every variant offset in the list
return list.map((item)=>{
let [offset, rule] = item;
offset = {
...offset,
variants: (0, _remapbitfield.remapBitfield)(offset.variants, mapping)
};
return [
offset,
rule
];
});
}
/**
* @template T
* @param {[RuleOffset, T][]} list
* @returns {[RuleOffset, T][]}
*/ sort(list) {
list = this.remapArbitraryVariantOffsets(list);
return list.sort(([a], [b])=>(0, _bigSign.default)(this.compare(a, b)));
}
constructor(){
/**
* Offsets for the next rule in a given layer
*
* @type {Record<Layer, bigint>}
*/ this.offsets = {
defaults: 0n,
base: 0n,
components: 0n,
utilities: 0n,
variants: 0n,
user: 0n
};
/**
* Positions for a given layer
*
* @type {Record<Layer, bigint>}
*/ this.layerPositions = {
defaults: 0n,
base: 1n,
components: 2n,
utilities: 3n,
// There isn't technically a "user" layer, but we need to give it a position
// Because it's used for ordering user-css from @apply
user: 4n,
variants: 5n
};
/**
* The total number of functions currently registered across all variants (including arbitrary variants)
*
* @type {bigint}
*/ this.reservedVariantBits = 0n;
/**
* Positions for a given variant
*
* @type {Map<string, bigint>}
*/ this.variantOffsets = new Map();
}
}
/**
*
* @param {bigint[]} nums
* @returns {bigint|null}
*/ function max(nums) {
let max = null;
for (const num of nums){
max = max !== null && max !== void 0 ? max : num;
max = max > num ? max : num;
}
return max;
}
/**
* A fast ASCII order string comparison function.
*
* Using `.sort()` without a custom compare function is faster
* But you can only use that if you're sorting an array of
* only strings. If you're sorting strings inside objects
* or arrays, you need to use a custom compare function.
*
* @param {string} a
* @param {string} b
*/ function fastCompare(a, b) {
let aLen = a.length;
let bLen = b.length;
let minLen = aLen < bLen ? aLen : bLen;
for(let i = 0; i < minLen; i++){
let cmp = a.charCodeAt(i) - b.charCodeAt(i);
if (cmp !== 0) return cmp;
}
return aLen - bLen;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return expandApplyAtRules;
}
});
function partitionRules(root) {
if (!root.walkAtRules) return;
let applyParents = new Set();
root.walkAtRules('apply', (rule)=>{
applyParents.add(rule.parent);
});
if (applyParents.size === 0) {
return;
}
for (let rule of applyParents){
let nodeGroups = [];
let lastGroup = [];
for (let node of rule.nodes){
if (node.type === 'atrule' && node.name === 'apply') {
if (lastGroup.length > 0) {
nodeGroups.push(lastGroup);
lastGroup = [];
}
nodeGroups.push([
node
]);
} else {
lastGroup.push(node);
}
}
if (lastGroup.length > 0) {
nodeGroups.push(lastGroup);
}
if (nodeGroups.length === 1) {
continue;
}
for (let group of [
...nodeGroups
].reverse()){
let clone = rule.clone({
nodes: []
});
clone.append(group);
rule.after(clone);
}
rule.remove();
}
}
function expandApplyAtRules() {
return (root)=>{
partitionRules(root);
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
any: function() {
return any;
},
escape: function() {
return escape;
},
nestedBrackets: function() {
return nestedBrackets;
},
optional: function() {
return optional;
},
pattern: function() {
return pattern;
},
withoutCapturing: function() {
return withoutCapturing;
},
zeroOrMore: function() {
return zeroOrMore;
}
});
const REGEX_SPECIAL = /[\\^$.*+?()[\]{}|]/g;
const REGEX_HAS_SPECIAL = RegExp(REGEX_SPECIAL.source);
/**
* @param {string|RegExp|Array<string|RegExp>} source
*/ function toSource(source) {
source = Array.isArray(source) ? source : [
source
];
source = source.map((item)=>item instanceof RegExp ? item.source : item);
return source.join('');
}
function pattern(source) {
return new RegExp(toSource(source), 'g');
}
function withoutCapturing(source) {
return new RegExp(`(?:${toSource(source)})`, 'g');
}
function any(sources) {
return `(?:${sources.map(toSource).join('|')})`;
}
function optional(source) {
return `(?:${toSource(source)})?`;
}
function zeroOrMore(source) {
return `(?:${toSource(source)})*`;
}
function nestedBrackets(open, close, depth = 1) {
return withoutCapturing([
escape(open),
/[^\s]*/,
depth === 1 ? `[^${escape(open)}${escape(close)}\s]*` : any([
`[^${escape(open)}${escape(close)}\s]*`,
nestedBrackets(open, close, depth - 1)
]),
/[^\s]*/,
escape(close)
]);
}
function escape(string) {
return string && REGEX_HAS_SPECIAL.test(string) ? string.replace(REGEX_SPECIAL, '\\$&') : string || '';
}
// @ts-check
/**
* We must remap all the old bits to new bits for each set variant
* Only arbitrary variants are considered as those are the only
* ones that need to be re-sorted at this time
*
* An iterated process that removes and sets individual bits simultaneously
* will not work because we may have a new bit that is also a later old bit
* This means that we would be removing a previously set bit which we don't
* want to do
*
* For example (assume `bN` = `1<<N`)
* Given the "total" mapping `[[b1, b3], [b2, b4], [b3, b1], [b4, b2]]`
* The mapping is "total" because:
* 1. Every input and output is accounted for
* 2. All combinations are unique
* 3. No one input maps to multiple outputs and vice versa
* And, given an offset with all bits set:
* V = b1 | b2 | b3 | b4
*
* Let's explore the issue with removing and setting bits simultaneously:
* V & ~b1 | b3 = b2 | b3 | b4
* V & ~b2 | b4 = b3 | b4
* V & ~b3 | b1 = b1 | b4
* V & ~b4 | b2 = b1 | b2
*
* As you can see, we end up with the wrong result.
* This is because we're removing a bit that was previously set.
* And, thus the final result is missing b3 and b4.
*
* Now, let's explore the issue with removing the bits first:
* V & ~b1 = b2 | b3 | b4
* V & ~b2 = b3 | b4
* V & ~b3 = b4
* V & ~b4 = 0
*
* And then setting the bits:
* V | b3 = b3
* V | b4 = b3 | b4
* V | b1 = b1 | b3 | b4
* V | b2 = b1 | b2 | b3 | b4
*
* We get the correct result because we're not removing any bits that were
* previously set thus properly remapping the bits to the new order
*
* To collect this into a single operation that can be done simultaneously
* we must first create a mask for the old bits that are set and a mask for
* the new bits that are set. Then we can remove the old bits and set the new
* bits simultaneously in a "single" operation like so:
* OldMask = b1 | b2 | b3 | b4
* NewMask = b3 | b4 | b1 | b2
*
* So this:
* V & ~oldMask | newMask
*
* Expands to this:
* V & ~b1 & ~b2 & ~b3 & ~b4 | b3 | b4 | b1 | b2
*
* Which becomes this:
* b1 | b2 | b3 | b4
*
* Which is the correct result!
*
* @param {bigint} num
* @param {[bigint, bigint][]} mapping
*/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "remapBitfield", {
enumerable: true,
get: function() {
return remapBitfield;
}
});
function remapBitfield(num, mapping) {
// Create masks for the old and new bits that are set
let oldMask = 0n;
let newMask = 0n;
for (let [oldBit, newBit] of mapping){
if (num & oldBit) {
oldMask = oldMask | oldBit;
newMask = newMask | newBit;
}
}
// Remove all old bits
// Set all new bits
return num & ~oldMask | newMask;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
default: function() {
return resolveDefaultsAtRules;
},
elementSelectorParser: function() {
return elementSelectorParser;
}
});
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
const _featureFlags = require("../featureFlags");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let getNode = {
id (node) {
return _postcssselectorparser.default.attribute({
attribute: 'id',
operator: '=',
value: node.value,
quoteMark: '"'
});
}
};
function minimumImpactSelector(nodes) {
let rest = nodes.filter((node)=>{
// Keep non-pseudo nodes
if (node.type !== 'pseudo') return true;
// Keep pseudo nodes that have subnodes
// E.g.: `:not()` contains subnodes inside the parentheses
if (node.nodes.length > 0) return true;
// Keep pseudo `elements`
// This implicitly means that we ignore pseudo `classes`
return node.value.startsWith('::') || [
':before',
':after',
':first-line',
':first-letter'
].includes(node.value);
}).reverse();
let searchFor = new Set([
'tag',
'class',
'id',
'attribute'
]);
let splitPointIdx = rest.findIndex((n)=>searchFor.has(n.type));
if (splitPointIdx === -1) return rest.reverse().join('').trim();
let node = rest[splitPointIdx];
let bestNode = getNode[node.type] ? getNode[node.type](node) : node;
rest = rest.slice(0, splitPointIdx);
let combinatorIdx = rest.findIndex((n)=>n.type === 'combinator' && n.value === '>');
if (combinatorIdx !== -1) {
rest.splice(0, combinatorIdx);
rest.unshift(_postcssselectorparser.default.universal());
}
return [
bestNode,
...rest.reverse()
].join('').trim();
}
let elementSelectorParser = (0, _postcssselectorparser.default)((selectors)=>{
return selectors.map((s)=>{
let nodes = s.split((n)=>n.type === 'combinator' && n.value === ' ').pop();
return minimumImpactSelector(nodes);
});
});
let cache = new Map();
function extractElementSelector(selector) {
if (!cache.has(selector)) {
cache.set(selector, elementSelectorParser.transformSync(selector));
}
return cache.get(selector);
}
function resolveDefaultsAtRules({ tailwindConfig }) {
return (root)=>{
let variableNodeMap = new Map();
/** @type {Set<import('postcss').AtRule>} */ let universals = new Set();
root.walkAtRules('defaults', (rule)=>{
if (rule.nodes && rule.nodes.length > 0) {
universals.add(rule);
return;
}
let variable = rule.params;
if (!variableNodeMap.has(variable)) {
variableNodeMap.set(variable, new Set());
}
variableNodeMap.get(variable).add(rule.parent);
rule.remove();
});
if ((0, _featureFlags.flagEnabled)(tailwindConfig, 'optimizeUniversalDefaults')) {
for (let universal of universals){
/** @type {Map<string, Set<string>>} */ let selectorGroups = new Map();
var _variableNodeMap_get;
let rules = (_variableNodeMap_get = variableNodeMap.get(universal.params)) !== null && _variableNodeMap_get !== void 0 ? _variableNodeMap_get : [];
for (let rule of rules){
for (let selector of extractElementSelector(rule.selector)){
// If selector contains a vendor prefix after a pseudo element or class,
// we consider them separately because merging the declarations into
// a single rule will cause browsers that do not understand the
// vendor prefix to throw out the whole rule
let selectorGroupName = selector.includes(':-') || selector.includes('::-') ? selector : '__DEFAULT__';
var _selectorGroups_get;
let selectors = (_selectorGroups_get = selectorGroups.get(selectorGroupName)) !== null && _selectorGroups_get !== void 0 ? _selectorGroups_get : new Set();
selectorGroups.set(selectorGroupName, selectors);
selectors.add(selector);
}
}
if ((0, _featureFlags.flagEnabled)(tailwindConfig, 'optimizeUniversalDefaults')) {
if (selectorGroups.size === 0) {
universal.remove();
continue;
}
for (let [, selectors] of selectorGroups){
let universalRule = _postcss.default.rule({
source: universal.source
});
universalRule.selectors = [
...selectors
];
universalRule.append(universal.nodes.map((node)=>node.clone()));
universal.before(universalRule);
}
}
universal.remove();
}
} else if (universals.size) {
let universalRule = _postcss.default.rule({
selectors: [
'*',
'::before',
'::after'
]
});
for (let universal of universals){
universalRule.append(universal.nodes);
if (!universalRule.parent) {
universal.before(universalRule);
}
if (!universalRule.source) {
universalRule.source = universal.source;
}
universal.remove();
}
let backdropRule = universalRule.clone({
selectors: [
'::backdrop'
]
});
universalRule.after(backdropRule);
}
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
INTERNAL_FEATURES: function() {
return INTERNAL_FEATURES;
},
createContext: function() {
return createContext;
},
getContext: function() {
return getContext;
},
getFileModifiedMap: function() {
return getFileModifiedMap;
},
isValidVariantFormatString: function() {
return isValidVariantFormatString;
},
parseVariant: function() {
return parseVariant;
}
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _url = /*#__PURE__*/ _interop_require_default(require("url"));
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _dlv = /*#__PURE__*/ _interop_require_default(require("dlv"));
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
const _transformThemeValue = /*#__PURE__*/ _interop_require_default(require("../util/transformThemeValue"));
const _parseObjectStyles = /*#__PURE__*/ _interop_require_default(require("../util/parseObjectStyles"));
const _prefixSelector = /*#__PURE__*/ _interop_require_default(require("../util/prefixSelector"));
const _isPlainObject = /*#__PURE__*/ _interop_require_default(require("../util/isPlainObject"));
const _escapeClassName = /*#__PURE__*/ _interop_require_default(require("../util/escapeClassName"));
const _nameClass = /*#__PURE__*/ _interop_require_wildcard(require("../util/nameClass"));
const _pluginUtils = require("../util/pluginUtils");
const _corePlugins = require("../corePlugins");
const _sharedState = /*#__PURE__*/ _interop_require_wildcard(require("./sharedState"));
const _toPath = require("../util/toPath");
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log"));
const _negateValue = /*#__PURE__*/ _interop_require_default(require("../util/negateValue"));
const _isSyntacticallyValidPropertyValue = /*#__PURE__*/ _interop_require_default(require("../util/isSyntacticallyValidPropertyValue"));
const _generateRules = require("./generateRules");
const _cacheInvalidation = require("./cacheInvalidation.js");
const _offsets = require("./offsets.js");
const _formatVariantSelector = require("../util/formatVariantSelector");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
const INTERNAL_FEATURES = Symbol();
const VARIANT_TYPES = {
AddVariant: Symbol.for('ADD_VARIANT'),
MatchVariant: Symbol.for('MATCH_VARIANT')
};
const VARIANT_INFO = {
Base: 1 << 0,
Dynamic: 1 << 1
};
function prefix(context, selector) {
let prefix = context.tailwindConfig.prefix;
return typeof prefix === 'function' ? prefix(selector) : prefix + selector;
}
function normalizeOptionTypes({ type = 'any', ...options }) {
let types = [].concat(type);
return {
...options,
types: types.map((type)=>{
if (Array.isArray(type)) {
return {
type: type[0],
...type[1]
};
}
return {
type,
preferOnConflict: false
};
})
};
}
function parseVariantFormatString(input) {
/** @type {string[]} */ let parts = [];
// When parsing whitespace around special characters are insignificant
// However, _inside_ of a variant they could be
// Because the selector could look like this
// @media { &[data-name="foo bar"] }
// This is why we do not skip whitespace
let current = '';
let depth = 0;
for(let idx = 0; idx < input.length; idx++){
let char = input[idx];
if (char === '\\') {
// Escaped characters are not special
current += '\\' + input[++idx];
} else if (char === '{') {
// Nested rule: start
++depth;
parts.push(current.trim());
current = '';
} else if (char === '}') {
// Nested rule: end
if (--depth < 0) {
throw new Error(`Your { and } are unbalanced.`);
}
parts.push(current.trim());
current = '';
} else {
// Normal character
current += char;
}
}
if (current.length > 0) {
parts.push(current.trim());
}
parts = parts.filter((part)=>part !== '');
return parts;
}
function insertInto(list, value, { before = [] } = {}) {
before = [].concat(before);
if (before.length <= 0) {
list.push(value);
return;
}
let idx = list.length - 1;
for (let other of before){
let iidx = list.indexOf(other);
if (iidx === -1) continue;
idx = Math.min(idx, iidx);
}
list.splice(idx, 0, value);
}
function parseStyles(styles) {
if (!Array.isArray(styles)) {
return parseStyles([
styles
]);
}
return styles.flatMap((style)=>{
let isNode = !Array.isArray(style) && !(0, _isPlainObject.default)(style);
return isNode ? style : (0, _parseObjectStyles.default)(style);
});
}
function getClasses(selector, mutate) {
let parser = (0, _postcssselectorparser.default)((selectors)=>{
let allClasses = [];
if (mutate) {
mutate(selectors);
}
selectors.walkClasses((classNode)=>{
allClasses.push(classNode.value);
});
return allClasses;
});
return parser.transformSync(selector);
}
/**
* Ignore everything inside a :not(...). This allows you to write code like
* `div:not(.foo)`. If `.foo` is never found in your code, then we used to
* not generated it. But now we will ignore everything inside a `:not`, so
* that it still gets generated.
*
* @param {selectorParser.Root} selectors
*/ function ignoreNot(selectors) {
selectors.walkPseudos((pseudo)=>{
if (pseudo.value === ':not') {
pseudo.remove();
}
});
}
function extractCandidates(node, state = {
containsNonOnDemandable: false
}, depth = 0) {
let classes = [];
let selectors = [];
if (node.type === 'rule') {
// Handle normal rules
selectors.push(...node.selectors);
} else if (node.type === 'atrule') {
// Handle at-rules (which contains nested rules)
node.walkRules((rule)=>selectors.push(...rule.selectors));
}
for (let selector of selectors){
let classCandidates = getClasses(selector, ignoreNot);
// At least one of the selectors contains non-"on-demandable" candidates.
if (classCandidates.length === 0) {
state.containsNonOnDemandable = true;
}
for (let classCandidate of classCandidates){
classes.push(classCandidate);
}
}
if (depth === 0) {
return [
state.containsNonOnDemandable || classes.length === 0,
classes
];
}
return classes;
}
function withIdentifiers(styles) {
return parseStyles(styles).flatMap((node)=>{
let nodeMap = new Map();
let [containsNonOnDemandableSelectors, candidates] = extractCandidates(node);
// If this isn't "on-demandable", assign it a universal candidate to always include it.
if (containsNonOnDemandableSelectors) {
candidates.unshift(_sharedState.NOT_ON_DEMAND);
}
// However, it could be that it also contains "on-demandable" candidates.
// E.g.: `span, .foo {}`, in that case it should still be possible to use
// `@apply foo` for example.
return candidates.map((c)=>{
if (!nodeMap.has(node)) {
nodeMap.set(node, node);
}
return [
c,
nodeMap.get(node)
];
});
});
}
function isValidVariantFormatString(format) {
return format.startsWith('@') || format.includes('&');
}
function parseVariant(variant) {
variant = variant.replace(/\n+/g, '').replace(/\s{1,}/g, ' ').trim();
let fns = parseVariantFormatString(variant).map((str)=>{
if (!str.startsWith('@')) {
return ({ format })=>format(str);
}
let [, name, params] = /@(\S*)( .+|[({].*)?/g.exec(str);
return ({ wrap })=>{
var _params_trim;
return wrap(_postcss.default.atRule({
name,
params: (_params_trim = params === null || params === void 0 ? void 0 : params.trim()) !== null && _params_trim !== void 0 ? _params_trim : ''
}));
};
}).reverse();
return (api)=>{
for (let fn of fns){
fn(api);
}
};
}
/**
*
* @param {any} tailwindConfig
* @param {any} context
* @param {object} param2
* @param {Offsets} param2.offsets
*/ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offsets, classList }) {
function getConfigValue(path, defaultValue) {
return path ? (0, _dlv.default)(tailwindConfig, path, defaultValue) : tailwindConfig;
}
function applyConfiguredPrefix(selector) {
return (0, _prefixSelector.default)(tailwindConfig.prefix, selector);
}
function prefixIdentifier(identifier, options) {
if (identifier === _sharedState.NOT_ON_DEMAND) {
return _sharedState.NOT_ON_DEMAND;
}
if (!options.respectPrefix) {
return identifier;
}
return context.tailwindConfig.prefix + identifier;
}
function resolveThemeValue(path, defaultValue, opts = {}) {
let parts = (0, _toPath.toPath)(path);
let value = getConfigValue([
'theme',
...parts
], defaultValue);
return (0, _transformThemeValue.default)(parts[0])(value, opts);
}
let variantIdentifier = 0;
let api = {
postcss: _postcss.default,
prefix: applyConfiguredPrefix,
e: _escapeClassName.default,
config: getConfigValue,
theme: resolveThemeValue,
corePlugins: (path)=>{
if (Array.isArray(tailwindConfig.corePlugins)) {
return tailwindConfig.corePlugins.includes(path);
}
return getConfigValue([
'corePlugins',
path
], true);
},
variants: ()=>{
// Preserved for backwards compatibility but not used in v3.0+
return [];
},
addBase (base) {
for (let [identifier, rule] of withIdentifiers(base)){
let prefixedIdentifier = prefixIdentifier(identifier, {});
let offset = offsets.create('base');
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, []);
}
context.candidateRuleMap.get(prefixedIdentifier).push([
{
sort: offset,
layer: 'base'
},
rule
]);
}
},
/**
* @param {string} group
* @param {Record<string, string | string[]>} declarations
*/ addDefaults (group, declarations) {
const groups = {
[`@defaults ${group}`]: declarations
};
for (let [identifier, rule] of withIdentifiers(groups)){
let prefixedIdentifier = prefixIdentifier(identifier, {});
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, []);
}
context.candidateRuleMap.get(prefixedIdentifier).push([
{
sort: offsets.create('defaults'),
layer: 'defaults'
},
rule
]);
}
},
addComponents (components, options) {
let defaultOptions = {
preserveSource: false,
respectPrefix: true,
respectImportant: false
};
options = Object.assign({}, defaultOptions, Array.isArray(options) ? {} : options);
for (let [identifier, rule] of withIdentifiers(components)){
let prefixedIdentifier = prefixIdentifier(identifier, options);
classList.add(prefixedIdentifier);
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, []);
}
context.candidateRuleMap.get(prefixedIdentifier).push([
{
sort: offsets.create('components'),
layer: 'components',
options
},
rule
]);
}
},
addUtilities (utilities, options) {
let defaultOptions = {
preserveSource: false,
respectPrefix: true,
respectImportant: true
};
options = Object.assign({}, defaultOptions, Array.isArray(options) ? {} : options);
for (let [identifier, rule] of withIdentifiers(utilities)){
let prefixedIdentifier = prefixIdentifier(identifier, options);
classList.add(prefixedIdentifier);
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, []);
}
context.candidateRuleMap.get(prefixedIdentifier).push([
{
sort: offsets.create('utilities'),
layer: 'utilities',
options
},
rule
]);
}
},
matchUtilities: function(utilities, options) {
let defaultOptions = {
respectPrefix: true,
respectImportant: true,
modifiers: false
};
options = normalizeOptionTypes({
...defaultOptions,
...options
});
let offset = offsets.create('utilities');
for(let identifier in utilities){
let prefixedIdentifier = prefixIdentifier(identifier, options);
let rule = utilities[identifier];
classList.add([
prefixedIdentifier,
options
]);
function wrapped(modifier, { isOnlyPlugin }) {
let [value, coercedType, utilityModifier] = (0, _pluginUtils.coerceValue)(options.types, modifier, options, tailwindConfig);
if (value === undefined) {
return [];
}
if (!options.types.some(({ type })=>type === coercedType)) {
if (isOnlyPlugin) {
_log.default.warn([
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
`You can safely update it to \`${identifier}-${modifier.replace(coercedType + ':', '')}\`.`
]);
} else {
return [];
}
}
if (!(0, _isSyntacticallyValidPropertyValue.default)(value)) {
return [];
}
let extras = {
get modifier () {
if (!options.modifiers) {
_log.default.warn(`modifier-used-without-options-for-${identifier}`, [
'Your plugin must set `modifiers: true` in its options to support modifiers.'
]);
}
return utilityModifier;
}
};
let ruleSets = [].concat(rule(value, extras)).filter(Boolean).map((declaration)=>({
[(0, _nameClass.default)(identifier, modifier)]: declaration
}));
return ruleSets;
}
let withOffsets = [
{
sort: offset,
layer: 'utilities',
options
},
wrapped
];
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, []);
}
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets);
}
},
matchComponents: function(components, options) {
let defaultOptions = {
respectPrefix: true,
respectImportant: false,
modifiers: false
};
options = normalizeOptionTypes({
...defaultOptions,
...options
});
let offset = offsets.create('components');
for(let identifier in components){
let prefixedIdentifier = prefixIdentifier(identifier, options);
let rule = components[identifier];
classList.add([
prefixedIdentifier,
options
]);
function wrapped(modifier, { isOnlyPlugin }) {
let [value, coercedType, utilityModifier] = (0, _pluginUtils.coerceValue)(options.types, modifier, options, tailwindConfig);
if (value === undefined) {
return [];
}
if (!options.types.some(({ type })=>type === coercedType)) {
if (isOnlyPlugin) {
_log.default.warn([
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
`You can safely update it to \`${identifier}-${modifier.replace(coercedType + ':', '')}\`.`
]);
} else {
return [];
}
}
if (!(0, _isSyntacticallyValidPropertyValue.default)(value)) {
return [];
}
let extras = {
get modifier () {
if (!options.modifiers) {
_log.default.warn(`modifier-used-without-options-for-${identifier}`, [
'Your plugin must set `modifiers: true` in its options to support modifiers.'
]);
}
return utilityModifier;
}
};
let ruleSets = [].concat(rule(value, extras)).filter(Boolean).map((declaration)=>({
[(0, _nameClass.default)(identifier, modifier)]: declaration
}));
return ruleSets;
}
let withOffsets = [
{
sort: offset,
layer: 'components',
options
},
wrapped
];
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, []);
}
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets);
}
},
addVariant (variantName, variantFunctions, options = {}) {
variantFunctions = [].concat(variantFunctions).map((variantFunction)=>{
if (typeof variantFunction !== 'string') {
// Safelist public API functions
return (api = {})=>{
let { args, modifySelectors, container, separator, wrap, format } = api;
let result = variantFunction(Object.assign({
modifySelectors,
container,
separator
}, options.type === VARIANT_TYPES.MatchVariant && {
args,
wrap,
format
}));
if (typeof result === 'string' && !isValidVariantFormatString(result)) {
throw new Error(`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`);
}
if (Array.isArray(result)) {
return result.filter((variant)=>typeof variant === 'string').map((variant)=>parseVariant(variant));
}
// result may be undefined with legacy variants that use APIs like `modifySelectors`
// result may also be a postcss node if someone was returning the result from `modifySelectors`
return result && typeof result === 'string' && parseVariant(result)(api);
};
}
if (!isValidVariantFormatString(variantFunction)) {
throw new Error(`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`);
}
return parseVariant(variantFunction);
});
insertInto(variantList, variantName, options);
variantMap.set(variantName, variantFunctions);
context.variantOptions.set(variantName, options);
},
matchVariant (variant, variantFn, options) {
var _options_id;
// A unique identifier that "groups" these variants together.
// This is for internal use only which is why it is not present in the types
let id = (_options_id = options === null || options === void 0 ? void 0 : options.id) !== null && _options_id !== void 0 ? _options_id : ++variantIdentifier;
let isSpecial = variant === '@';
var _options_values;
for (let [key, value] of Object.entries((_options_values = options === null || options === void 0 ? void 0 : options.values) !== null && _options_values !== void 0 ? _options_values : {})){
if (key === 'DEFAULT') continue;
api.addVariant(isSpecial ? `${variant}${key}` : `${variant}-${key}`, ({ args, container })=>{
return variantFn(value, {
modifier: args === null || args === void 0 ? void 0 : args.modifier,
container
});
}, {
...options,
value,
id,
type: VARIANT_TYPES.MatchVariant,
variantInfo: VARIANT_INFO.Base
});
}
var _options_values1;
let hasDefault = 'DEFAULT' in ((_options_values1 = options === null || options === void 0 ? void 0 : options.values) !== null && _options_values1 !== void 0 ? _options_values1 : {});
api.addVariant(variant, ({ args, container })=>{
if ((args === null || args === void 0 ? void 0 : args.value) === _sharedState.NONE && !hasDefault) {
return null;
}
var // (JetBrains) plugins.
_args_value;
return variantFn((args === null || args === void 0 ? void 0 : args.value) === _sharedState.NONE ? options.values.DEFAULT : (_args_value = args === null || args === void 0 ? void 0 : args.value) !== null && _args_value !== void 0 ? _args_value : typeof args === 'string' ? args : '', {
modifier: args === null || args === void 0 ? void 0 : args.modifier,
container
});
}, {
...options,
id,
type: VARIANT_TYPES.MatchVariant,
variantInfo: VARIANT_INFO.Dynamic
});
}
};
return api;
}
let fileModifiedMapCache = new WeakMap();
function getFileModifiedMap(context) {
if (!fileModifiedMapCache.has(context)) {
fileModifiedMapCache.set(context, new Map());
}
return fileModifiedMapCache.get(context);
}
function trackModified(files, fileModifiedMap) {
let changed = false;
let mtimesToCommit = new Map();
for (let file of files){
var _fs_statSync;
if (!file) continue;
let parsed = _url.default.parse(file);
let pathname = parsed.hash ? parsed.href.replace(parsed.hash, '') : parsed.href;
pathname = parsed.search ? pathname.replace(parsed.search, '') : pathname;
let newModified = (_fs_statSync = _fs.default.statSync(decodeURIComponent(pathname), {
throwIfNoEntry: false
})) === null || _fs_statSync === void 0 ? void 0 : _fs_statSync.mtimeMs;
if (!newModified) {
continue;
}
if (!fileModifiedMap.has(file) || newModified > fileModifiedMap.get(file)) {
changed = true;
}
mtimesToCommit.set(file, newModified);
}
return [
changed,
mtimesToCommit
];
}
function extractVariantAtRules(node) {
node.walkAtRules((atRule)=>{
if ([
'responsive',
'variants'
].includes(atRule.name)) {
extractVariantAtRules(atRule);
atRule.before(atRule.nodes);
atRule.remove();
}
});
}
function collectLayerPlugins(root) {
let layerPlugins = [];
root.each((node)=>{
if (node.type === 'atrule' && [
'responsive',
'variants'
].includes(node.name)) {
node.name = 'layer';
node.params = 'utilities';
}
});
// Walk @layer rules and treat them like plugins
root.walkAtRules('layer', (layerRule)=>{
extractVariantAtRules(layerRule);
if (layerRule.params === 'base') {
for (let node of layerRule.nodes){
layerPlugins.push(function({ addBase }) {
addBase(node, {
respectPrefix: false
});
});
}
layerRule.remove();
} else if (layerRule.params === 'components') {
for (let node of layerRule.nodes){
layerPlugins.push(function({ addComponents }) {
addComponents(node, {
respectPrefix: false,
preserveSource: true
});
});
}
layerRule.remove();
} else if (layerRule.params === 'utilities') {
for (let node of layerRule.nodes){
layerPlugins.push(function({ addUtilities }) {
addUtilities(node, {
respectPrefix: false,
preserveSource: true
});
});
}
layerRule.remove();
}
});
return layerPlugins;
}
function resolvePlugins(context, root) {
let corePluginList = Object.entries(_corePlugins.corePlugins).map(([name, plugin])=>{
if (!context.tailwindConfig.corePlugins.includes(name)) {
return null;
}
return plugin;
}).filter(Boolean);
let userPlugins = context.tailwindConfig.plugins.map((plugin)=>{
if (plugin.__isOptionsFunction) {
plugin = plugin();
}
return typeof plugin === 'function' ? plugin : plugin.handler;
});
let layerPlugins = collectLayerPlugins(root);
// TODO: This is a workaround for backwards compatibility, since custom variants
// were historically sorted before screen/stackable variants.
let beforeVariants = [
_corePlugins.variantPlugins['childVariant'],
_corePlugins.variantPlugins['pseudoElementVariants'],
_corePlugins.variantPlugins['pseudoClassVariants'],
_corePlugins.variantPlugins['hasVariants'],
_corePlugins.variantPlugins['ariaVariants'],
_corePlugins.variantPlugins['dataVariants']
];
let afterVariants = [
_corePlugins.variantPlugins['supportsVariants'],
_corePlugins.variantPlugins['reducedMotionVariants'],
_corePlugins.variantPlugins['prefersContrastVariants'],
_corePlugins.variantPlugins['printVariant'],
_corePlugins.variantPlugins['screenVariants'],
_corePlugins.variantPlugins['orientationVariants'],
_corePlugins.variantPlugins['directionVariants'],
_corePlugins.variantPlugins['darkVariants'],
_corePlugins.variantPlugins['forcedColorsVariants']
];
return [
...corePluginList,
...beforeVariants,
...userPlugins,
...afterVariants,
...layerPlugins
];
}
function registerPlugins(plugins, context) {
let variantList = [];
let variantMap = new Map();
context.variantMap = variantMap;
let offsets = new _offsets.Offsets();
context.offsets = offsets;
let classList = new Set();
let pluginApi = buildPluginApi(context.tailwindConfig, context, {
variantList,
variantMap,
offsets,
classList
});
for (let plugin of plugins){
if (Array.isArray(plugin)) {
for (let pluginItem of plugin){
pluginItem(pluginApi);
}
} else {
plugin === null || plugin === void 0 ? void 0 : plugin(pluginApi);
}
}
// Make sure to record bit masks for every variant
offsets.recordVariants(variantList, (variant)=>variantMap.get(variant).length);
// Build variantMap
for (let [variantName, variantFunctions] of variantMap.entries()){
context.variantMap.set(variantName, variantFunctions.map((variantFunction, idx)=>[
offsets.forVariant(variantName, idx),
variantFunction
]));
}
var _context_tailwindConfig_safelist;
let safelist = ((_context_tailwindConfig_safelist = context.tailwindConfig.safelist) !== null && _context_tailwindConfig_safelist !== void 0 ? _context_tailwindConfig_safelist : []).filter(Boolean);
if (safelist.length > 0) {
let checks = [];
for (let value of safelist){
if (typeof value === 'string') {
context.changedContent.push({
content: value,
extension: 'html'
});
continue;
}
if (value instanceof RegExp) {
_log.default.warn('root-regex', [
'Regular expressions in `safelist` work differently in Tailwind CSS v3.0.',
'Update your `safelist` configuration to eliminate this warning.',
'https://tailwindcss.com/docs/content-configuration#safelisting-classes'
]);
continue;
}
checks.push(value);
}
if (checks.length > 0) {
let patternMatchingCount = new Map();
let prefixLength = context.tailwindConfig.prefix.length;
let checkImportantUtils = checks.some((check)=>check.pattern.source.includes('!'));
for (let util of classList){
let utils = Array.isArray(util) ? (()=>{
let [utilName, options] = util;
var _options_values;
let values = Object.keys((_options_values = options === null || options === void 0 ? void 0 : options.values) !== null && _options_values !== void 0 ? _options_values : {});
let classes = values.map((value)=>(0, _nameClass.formatClass)(utilName, value));
if (options === null || options === void 0 ? void 0 : options.supportsNegativeValues) {
// This is the normal negated version
// e.g. `-inset-1` or `-tw-inset-1`
classes = [
...classes,
...classes.map((cls)=>'-' + cls)
];
// This is the negated version *after* the prefix
// e.g. `tw--inset-1`
// The prefix is already attached to util name
// So we add the negative after the prefix
classes = [
...classes,
...classes.map((cls)=>cls.slice(0, prefixLength) + '-' + cls.slice(prefixLength))
];
}
if (options.types.some(({ type })=>type === 'color')) {
classes = [
...classes,
...classes.flatMap((cls)=>Object.keys(context.tailwindConfig.theme.opacity).map((opacity)=>`${cls}/${opacity}`))
];
}
if (checkImportantUtils && (options === null || options === void 0 ? void 0 : options.respectImportant)) {
classes = [
...classes,
...classes.map((cls)=>'!' + cls)
];
}
return classes;
})() : [
util
];
for (let util of utils){
for (let { pattern, variants = [] } of checks){
// RegExp with the /g flag are stateful, so let's reset the last
// index pointer to reset the state.
pattern.lastIndex = 0;
if (!patternMatchingCount.has(pattern)) {
patternMatchingCount.set(pattern, 0);
}
if (!pattern.test(util)) continue;
patternMatchingCount.set(pattern, patternMatchingCount.get(pattern) + 1);
context.changedContent.push({
content: util,
extension: 'html'
});
for (let variant of variants){
context.changedContent.push({
content: variant + context.tailwindConfig.separator + util,
extension: 'html'
});
}
}
}
}
for (let [regex, count] of patternMatchingCount.entries()){
if (count !== 0) continue;
_log.default.warn([
`The safelist pattern \`${regex}\` doesn't match any Tailwind CSS classes.`,
'Fix this pattern or remove it from your `safelist` configuration.',
'https://tailwindcss.com/docs/content-configuration#safelisting-classes'
]);
}
}
}
var _context_tailwindConfig_darkMode, _concat_;
let darkClassName = (_concat_ = [].concat((_context_tailwindConfig_darkMode = context.tailwindConfig.darkMode) !== null && _context_tailwindConfig_darkMode !== void 0 ? _context_tailwindConfig_darkMode : 'media')[1]) !== null && _concat_ !== void 0 ? _concat_ : 'dark';
// A list of utilities that are used by certain Tailwind CSS utilities but
// that don't exist on their own. This will result in them "not existing" and
// sorting could be weird since you still require them in order to make the
// host utilities work properly. (Thanks Biology)
let parasiteUtilities = [
prefix(context, darkClassName),
prefix(context, 'group'),
prefix(context, 'peer')
];
context.getClassOrder = function getClassOrder(classes) {
// Sort classes so they're ordered in a deterministic manner
let sorted = [
...classes
].sort((a, z)=>{
if (a === z) return 0;
if (a < z) return -1;
return 1;
});
// Non-util classes won't be generated, so we default them to null
let sortedClassNames = new Map(sorted.map((className)=>[
className,
null
]));
// Sort all classes in order
// Non-tailwind classes won't be generated and will be left as `null`
let rules = (0, _generateRules.generateRules)(new Set(sorted), context, true);
rules = context.offsets.sort(rules);
let idx = BigInt(parasiteUtilities.length);
for (const [, rule] of rules){
let candidate = rule.raws.tailwind.candidate;
var _sortedClassNames_get;
// When multiple rules match a candidate
// always take the position of the first one
sortedClassNames.set(candidate, (_sortedClassNames_get = sortedClassNames.get(candidate)) !== null && _sortedClassNames_get !== void 0 ? _sortedClassNames_get : idx++);
}
return classes.map((className)=>{
var _sortedClassNames_get;
let order = (_sortedClassNames_get = sortedClassNames.get(className)) !== null && _sortedClassNames_get !== void 0 ? _sortedClassNames_get : null;
let parasiteIndex = parasiteUtilities.indexOf(className);
if (order === null && parasiteIndex !== -1) {
// This will make sure that it is at the very beginning of the
// `components` layer which technically means 'before any
// components'.
order = BigInt(parasiteIndex);
}
return [
className,
order
];
});
};
// Generate a list of strings for autocompletion purposes, e.g.
// ['uppercase', 'lowercase', ...]
context.getClassList = function getClassList(options = {}) {
let output = [];
for (let util of classList){
if (Array.isArray(util)) {
var _utilOptions_types;
let [utilName, utilOptions] = util;
let negativeClasses = [];
var _utilOptions_modifiers;
let modifiers = Object.keys((_utilOptions_modifiers = utilOptions === null || utilOptions === void 0 ? void 0 : utilOptions.modifiers) !== null && _utilOptions_modifiers !== void 0 ? _utilOptions_modifiers : {});
if (utilOptions === null || utilOptions === void 0 ? void 0 : (_utilOptions_types = utilOptions.types) === null || _utilOptions_types === void 0 ? void 0 : _utilOptions_types.some(({ type })=>type === 'color')) {
var _context_tailwindConfig_theme_opacity;
modifiers.push(...Object.keys((_context_tailwindConfig_theme_opacity = context.tailwindConfig.theme.opacity) !== null && _context_tailwindConfig_theme_opacity !== void 0 ? _context_tailwindConfig_theme_opacity : {}));
}
let metadata = {
modifiers
};
let includeMetadata = options.includeMetadata && modifiers.length > 0;
var _utilOptions_values;
for (let [key, value] of Object.entries((_utilOptions_values = utilOptions === null || utilOptions === void 0 ? void 0 : utilOptions.values) !== null && _utilOptions_values !== void 0 ? _utilOptions_values : {})){
// Ignore undefined and null values
if (value == null) {
continue;
}
let cls = (0, _nameClass.formatClass)(utilName, key);
output.push(includeMetadata ? [
cls,
metadata
] : cls);
if ((utilOptions === null || utilOptions === void 0 ? void 0 : utilOptions.supportsNegativeValues) && (0, _negateValue.default)(value)) {
let cls = (0, _nameClass.formatClass)(utilName, `-${key}`);
negativeClasses.push(includeMetadata ? [
cls,
metadata
] : cls);
}
}
output.push(...negativeClasses);
} else {
output.push(util);
}
}
return output;
};
// Generate a list of available variants with meta information of the type of variant.
context.getVariants = function getVariants() {
let result = [];
for (let [name, options] of context.variantOptions.entries()){
if (options.variantInfo === VARIANT_INFO.Base) continue;
var _options_values;
result.push({
name,
isArbitrary: options.type === Symbol.for('MATCH_VARIANT'),
values: Object.keys((_options_values = options.values) !== null && _options_values !== void 0 ? _options_values : {}),
hasDash: name !== '@',
selectors ({ modifier, value } = {}) {
let candidate = '__TAILWIND_PLACEHOLDER__';
let rule = _postcss.default.rule({
selector: `.${candidate}`
});
let container = _postcss.default.root({
nodes: [
rule.clone()
]
});
let before = container.toString();
var _context_variantMap_get;
let fns = ((_context_variantMap_get = context.variantMap.get(name)) !== null && _context_variantMap_get !== void 0 ? _context_variantMap_get : []).flatMap(([_, fn])=>fn);
let formatStrings = [];
for (let fn of fns){
var _options_values;
let localFormatStrings = [];
var _options_values_value;
let api = {
args: {
modifier,
value: (_options_values_value = (_options_values = options.values) === null || _options_values === void 0 ? void 0 : _options_values[value]) !== null && _options_values_value !== void 0 ? _options_values_value : value
},
separator: context.tailwindConfig.separator,
modifySelectors (modifierFunction) {
// Run the modifierFunction over each rule
container.each((rule)=>{
if (rule.type !== 'rule') {
return;
}
rule.selectors = rule.selectors.map((selector)=>{
return modifierFunction({
get className () {
return (0, _generateRules.getClassNameFromSelector)(selector);
},
selector
});
});
});
return container;
},
format (str) {
localFormatStrings.push(str);
},
wrap (wrapper) {
localFormatStrings.push(`@${wrapper.name} ${wrapper.params} { & }`);
},
container
};
let ruleWithVariant = fn(api);
if (localFormatStrings.length > 0) {
formatStrings.push(localFormatStrings);
}
if (Array.isArray(ruleWithVariant)) {
for (let variantFunction of ruleWithVariant){
localFormatStrings = [];
variantFunction(api);
formatStrings.push(localFormatStrings);
}
}
}
// Reverse engineer the result of the `container`
let manualFormatStrings = [];
let after = container.toString();
if (before !== after) {
// Figure out all selectors
container.walkRules((rule)=>{
let modified = rule.selector;
// Rebuild the base selector, this is what plugin authors would do
// as well. E.g.: `${variant}${separator}${className}`.
// However, plugin authors probably also prepend or append certain
// classes, pseudos, ids, ...
let rebuiltBase = (0, _postcssselectorparser.default)((selectors)=>{
selectors.walkClasses((classNode)=>{
classNode.value = `${name}${context.tailwindConfig.separator}${classNode.value}`;
});
}).processSync(modified);
// Now that we know the original selector, the new selector, and
// the rebuild part in between, we can replace the part that plugin
// authors need to rebuild with `&`, and eventually store it in the
// collectedFormats. Similar to what `format('...')` would do.
//
// E.g.:
// variant: foo
// selector: .markdown > p
// modified (by plugin): .foo .foo\\:markdown > p
// rebuiltBase (internal): .foo\\:markdown > p
// format: .foo &
manualFormatStrings.push(modified.replace(rebuiltBase, '&').replace(candidate, '&'));
});
// Figure out all atrules
container.walkAtRules((atrule)=>{
manualFormatStrings.push(`@${atrule.name} (${atrule.params}) { & }`);
});
}
var _options_values1;
let isArbitraryVariant = !(value in ((_options_values1 = options.values) !== null && _options_values1 !== void 0 ? _options_values1 : {}));
var _options_INTERNAL_FEATURES;
let internalFeatures = (_options_INTERNAL_FEATURES = options[INTERNAL_FEATURES]) !== null && _options_INTERNAL_FEATURES !== void 0 ? _options_INTERNAL_FEATURES : {};
let respectPrefix = (()=>{
if (isArbitraryVariant) return false;
if (internalFeatures.respectPrefix === false) return false;
return true;
})();
formatStrings = formatStrings.map((format)=>format.map((str)=>({
format: str,
respectPrefix
})));
manualFormatStrings = manualFormatStrings.map((format)=>({
format,
respectPrefix
}));
let opts = {
candidate,
context
};
let result = formatStrings.map((formats)=>(0, _formatVariantSelector.finalizeSelector)(`.${candidate}`, (0, _formatVariantSelector.formatVariantSelector)(formats, opts), opts).replace(`.${candidate}`, '&').replace('{ & }', '').trim());
if (manualFormatStrings.length > 0) {
result.push((0, _formatVariantSelector.formatVariantSelector)(manualFormatStrings, opts).toString().replace(`.${candidate}`, '&'));
}
return result;
}
});
}
return result;
};
}
/**
* Mark as class as retroactively invalid
*
*
* @param {string} candidate
*/ function markInvalidUtilityCandidate(context, candidate) {
if (!context.classCache.has(candidate)) {
return;
}
// Mark this as not being a real utility
context.notClassCache.add(candidate);
// Remove it from any candidate-specific caches
context.classCache.delete(candidate);
context.applyClassCache.delete(candidate);
context.candidateRuleMap.delete(candidate);
context.candidateRuleCache.delete(candidate);
// Ensure the stylesheet gets rebuilt
context.stylesheetCache = null;
}
/**
* Mark as class as retroactively invalid
*
* @param {import('postcss').Node} node
*/ function markInvalidUtilityNode(context, node) {
let candidate = node.raws.tailwind.candidate;
if (!candidate) {
return;
}
for (const entry of context.ruleCache){
if (entry[1].raws.tailwind.candidate === candidate) {
context.ruleCache.delete(entry);
// context.postCssNodeCache.delete(node)
}
}
markInvalidUtilityCandidate(context, candidate);
}
function createContext(tailwindConfig, changedContent = [], root = _postcss.default.root()) {
var _tailwindConfig_blocklist;
let context = {
disposables: [],
ruleCache: new Set(),
candidateRuleCache: new Map(),
classCache: new Map(),
applyClassCache: new Map(),
// Seed the not class cache with the blocklist (which is only strings)
notClassCache: new Set((_tailwindConfig_blocklist = tailwindConfig.blocklist) !== null && _tailwindConfig_blocklist !== void 0 ? _tailwindConfig_blocklist : []),
postCssNodeCache: new Map(),
candidateRuleMap: new Map(),
tailwindConfig,
changedContent: changedContent,
variantMap: new Map(),
stylesheetCache: null,
variantOptions: new Map(),
markInvalidUtilityCandidate: (candidate)=>markInvalidUtilityCandidate(context, candidate),
markInvalidUtilityNode: (node)=>markInvalidUtilityNode(context, node)
};
let resolvedPlugins = resolvePlugins(context, root);
registerPlugins(resolvedPlugins, context);
return context;
}
let contextMap = _sharedState.contextMap;
let configContextMap = _sharedState.configContextMap;
let contextSourcesMap = _sharedState.contextSourcesMap;
function getContext(root, result, tailwindConfig, userConfigPath, tailwindConfigHash, contextDependencies) {
let sourcePath = result.opts.from;
let isConfigFile = userConfigPath !== null;
_sharedState.env.DEBUG && console.log('Source path:', sourcePath);
let existingContext;
if (isConfigFile && contextMap.has(sourcePath)) {
existingContext = contextMap.get(sourcePath);
} else if (configContextMap.has(tailwindConfigHash)) {
let context = configContextMap.get(tailwindConfigHash);
contextSourcesMap.get(context).add(sourcePath);
contextMap.set(sourcePath, context);
existingContext = context;
}
let cssDidChange = (0, _cacheInvalidation.hasContentChanged)(sourcePath, root);
// If there's already a context in the cache and we don't need to
// reset the context, return the cached context.
if (existingContext) {
let [contextDependenciesChanged, mtimesToCommit] = trackModified([
...contextDependencies
], getFileModifiedMap(existingContext));
if (!contextDependenciesChanged && !cssDidChange) {
return [
existingContext,
false,
mtimesToCommit
];
}
}
// If this source is in the context map, get the old context.
// Remove this source from the context sources for the old context,
// and clean up that context if no one else is using it. This can be
// called by many processes in rapid succession, so we check for presence
// first because the first process to run this code will wipe it out first.
if (contextMap.has(sourcePath)) {
let oldContext = contextMap.get(sourcePath);
if (contextSourcesMap.has(oldContext)) {
contextSourcesMap.get(oldContext).delete(sourcePath);
if (contextSourcesMap.get(oldContext).size === 0) {
contextSourcesMap.delete(oldContext);
for (let [tailwindConfigHash, context] of configContextMap){
if (context === oldContext) {
configContextMap.delete(tailwindConfigHash);
}
}
for (let disposable of oldContext.disposables.splice(0)){
disposable(oldContext);
}
}
}
}
_sharedState.env.DEBUG && console.log('Setting up new context...');
let context = createContext(tailwindConfig, [], root);
Object.assign(context, {
userConfigPath
});
let [, mtimesToCommit] = trackModified([
...contextDependencies
], getFileModifiedMap(context));
// ---
// Update all context tracking state
configContextMap.set(tailwindConfigHash, context);
contextMap.set(sourcePath, context);
if (!contextSourcesMap.has(context)) {
contextSourcesMap.set(context, new Set());
}
contextSourcesMap.get(context).add(sourcePath);
return [
context,
true,
mtimesToCommit
];
}
// @ts-check
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, // DISABLE_TOUCH = TRUE
// Retrieve an existing context from cache if possible (since contexts are unique per
// source path), or set up a new one (including setting up watchers and registering
// plugins) then return it
"default", {
enumerable: true,
get: function() {
return setupTrackingContext;
}
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _quicklru = /*#__PURE__*/ _interop_require_default(require("@alloc/quick-lru"));
const _hashConfig = /*#__PURE__*/ _interop_require_default(require("../util/hashConfig"));
const _resolveconfig = /*#__PURE__*/ _interop_require_default(require("../public/resolve-config"));
const _resolveConfigPath = /*#__PURE__*/ _interop_require_default(require("../util/resolveConfigPath"));
const _setupContextUtils = require("./setupContextUtils");
const _parseDependency = /*#__PURE__*/ _interop_require_default(require("../util/parseDependency"));
const _validateConfig = require("../util/validateConfig.js");
const _content = require("./content.js");
const _loadconfig = require("../lib/load-config");
const _getModuleDependencies = /*#__PURE__*/ _interop_require_default(require("./getModuleDependencies"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let configPathCache = new _quicklru.default({
maxSize: 100
});
let candidateFilesCache = new WeakMap();
function getCandidateFiles(context, tailwindConfig) {
if (candidateFilesCache.has(context)) {
return candidateFilesCache.get(context);
}
let candidateFiles = (0, _content.parseCandidateFiles)(context, tailwindConfig);
return candidateFilesCache.set(context, candidateFiles).get(context);
}
// Get the config object based on a path
function getTailwindConfig(configOrPath) {
let userConfigPath = (0, _resolveConfigPath.default)(configOrPath);
if (userConfigPath !== null) {
let [prevConfig, prevConfigHash, prevDeps, prevModified] = configPathCache.get(userConfigPath) || [];
let newDeps = (0, _getModuleDependencies.default)(userConfigPath);
let modified = false;
let newModified = new Map();
for (let file of newDeps){
let time = _fs.default.statSync(file).mtimeMs;
newModified.set(file, time);
if (!prevModified || !prevModified.has(file) || time > prevModified.get(file)) {
modified = true;
}
}
// It hasn't changed (based on timestamps)
if (!modified) {
return [
prevConfig,
userConfigPath,
prevConfigHash,
prevDeps
];
}
// It has changed (based on timestamps), or first run
for (let file of newDeps){
delete require.cache[file];
}
let newConfig = (0, _validateConfig.validateConfig)((0, _resolveconfig.default)((0, _loadconfig.loadConfig)(userConfigPath)));
let newHash = (0, _hashConfig.default)(newConfig);
configPathCache.set(userConfigPath, [
newConfig,
newHash,
newDeps,
newModified
]);
return [
newConfig,
userConfigPath,
newHash,
newDeps
];
}
var _configOrPath_config, _ref;
// It's a plain object, not a path
let newConfig = (0, _resolveconfig.default)((_ref = (_configOrPath_config = configOrPath === null || configOrPath === void 0 ? void 0 : configOrPath.config) !== null && _configOrPath_config !== void 0 ? _configOrPath_config : configOrPath) !== null && _ref !== void 0 ? _ref : {});
newConfig = (0, _validateConfig.validateConfig)(newConfig);
return [
newConfig,
null,
(0, _hashConfig.default)(newConfig),
[]
];
}
function setupTrackingContext(configOrPath) {
return ({ tailwindDirectives, registerDependency })=>{
return (root, result)=>{
let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] = getTailwindConfig(configOrPath);
let contextDependencies = new Set(configDependencies);
// If there are no @tailwind or @apply rules, we don't consider this CSS
// file or its dependencies to be dependencies of the context. Can reuse
// the context even if they change. We may want to think about `@layer`
// being part of this trigger too, but it's tough because it's impossible
// for a layer in one file to end up in the actual @tailwind rule in
// another file since independent sources are effectively isolated.
if (tailwindDirectives.size > 0) {
// Add current css file as a context dependencies.
contextDependencies.add(result.opts.from);
// Add all css @import dependencies as context dependencies.
for (let message of result.messages){
if (message.type === 'dependency') {
contextDependencies.add(message.file);
}
}
}
let [context, , mTimesToCommit] = (0, _setupContextUtils.getContext)(root, result, tailwindConfig, userConfigPath, tailwindConfigHash, contextDependencies);
let fileModifiedMap = (0, _setupContextUtils.getFileModifiedMap)(context);
let candidateFiles = getCandidateFiles(context, tailwindConfig);
// If there are no @tailwind or @apply rules, we don't consider this CSS file or it's
// dependencies to be dependencies of the context. Can reuse the context even if they change.
// We may want to think about `@layer` being part of this trigger too, but it's tough
// because it's impossible for a layer in one file to end up in the actual @tailwind rule
// in another file since independent sources are effectively isolated.
if (tailwindDirectives.size > 0) {
// Add template paths as postcss dependencies.
for (let contentPath of candidateFiles){
for (let dependency of (0, _parseDependency.default)(contentPath)){
registerDependency(dependency);
}
}
let [changedContent, contentMTimesToCommit] = (0, _content.resolvedChangedContent)(context, candidateFiles, fileModifiedMap);
for (let content of changedContent){
context.changedContent.push(content);
}
// Add the mtimes of the content files to the commit list
// We can overwrite the existing values because unconditionally
// This is because:
// 1. Most of the files here won't be in the map yet
// 2. If they are that means it's a context dependency
// and we're reading this after the context. This means
// that the mtime we just read is strictly >= the context
// mtime. Unless the user / os is doing something weird
// in which the mtime would be going backwards. If that
// happens there's already going to be problems.
for (let [path, mtime] of contentMTimesToCommit.entries()){
mTimesToCommit.set(path, mtime);
}
}
for (let file of configDependencies){
registerDependency({
type: 'dependency',
file
});
}
// "commit" the new modified time for all context deps
// We do this here because we want content tracking to
// read the "old" mtime even when it's a context dependency.
for (let [path, mtime] of mTimesToCommit.entries()){
fileModifiedMap.set(path, mtime);
}
return context;
};
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
NONE: function() {
return NONE;
},
NOT_ON_DEMAND: function() {
return NOT_ON_DEMAND;
},
configContextMap: function() {
return configContextMap;
},
contextMap: function() {
return contextMap;
},
contextSourcesMap: function() {
return contextSourcesMap;
},
env: function() {
return env;
},
resolveDebug: function() {
return resolveDebug;
},
sourceHashMap: function() {
return sourceHashMap;
}
});
const env = typeof process !== 'undefined' ? {
NODE_ENV: process.env.NODE_ENV,
DEBUG: resolveDebug(process.env.DEBUG)
} : {
NODE_ENV: 'production',
DEBUG: false
};
const contextMap = new Map();
const configContextMap = new Map();
const contextSourcesMap = new Map();
const sourceHashMap = new Map();
const NOT_ON_DEMAND = new String('*');
const NONE = Symbol('__NONE__');
function resolveDebug(debug) {
if (debug === undefined) {
return false;
}
// Environment variables are strings, so convert to boolean
if (debug === 'true' || debug === '1') {
return true;
}
if (debug === 'false' || debug === '0') {
return false;
}
// Keep the debug convention into account:
// DEBUG=* -> This enables all debug modes
// DEBUG=projectA,projectB,projectC -> This enables debug for projectA, projectB and projectC
// DEBUG=projectA:* -> This enables all debug modes for projectA (if you have sub-types)
// DEBUG=projectA,-projectB -> This enables debug for projectA and explicitly disables it for projectB
if (debug === '*') {
return true;
}
let debuggers = debug.split(',').map((d)=>d.split(':')[0]);
// Ignoring tailwindcss
if (debuggers.includes('-tailwindcss')) {
return false;
}
// Including tailwindcss
if (debuggers.includes('tailwindcss')) {
return true;
}
return false;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _normalizeScreens = require("../util/normalizeScreens");
const _buildMediaQuery = /*#__PURE__*/ _interop_require_default(require("../util/buildMediaQuery"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _default({ tailwindConfig: { theme } }) {
return function(css) {
css.walkAtRules('screen', (atRule)=>{
let screen = atRule.params;
let screens = (0, _normalizeScreens.normalizeScreens)(theme.screens);
let screenDefinition = screens.find(({ name })=>name === screen);
if (!screenDefinition) {
throw atRule.error(`No \`${screen}\` screen found.`);
}
atRule.name = 'media';
atRule.params = (0, _buildMediaQuery.default)(screenDefinition);
});
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _lightningcss = /*#__PURE__*/ _interop_require_wildcard(require("lightningcss"));
const _browserslist = /*#__PURE__*/ _interop_require_default(require("browserslist"));
const _setupTrackingContext = /*#__PURE__*/ _interop_require_default(require("./lib/setupTrackingContext"));
const _processTailwindFeatures = /*#__PURE__*/ _interop_require_default(require("./processTailwindFeatures"));
const _sharedState = require("./lib/sharedState");
const _findAtConfigPath = require("./lib/findAtConfigPath");
const _handleImportAtRules = require("./lib/handleImportAtRules");
const _packagejson = require("../package.json");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
function license() {
return `/* ! tailwindcss v${_packagejson.version} | MIT License | https://tailwindcss.com */\n`;
}
module.exports = function tailwindcss(configOrPath) {
return {
postcssPlugin: 'tailwindcss',
plugins: [
_sharedState.env.DEBUG && function(root) {
console.log('\n');
console.time('JIT TOTAL');
return root;
},
...(0, _handleImportAtRules.handleImportAtRules)(),
async function(root, result) {
var _findAtConfigPath1;
// Use the path for the `@config` directive if it exists, otherwise use the
// path for the file being processed
configOrPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : configOrPath;
let context = (0, _setupTrackingContext.default)(configOrPath);
if (root.type === 'document') {
let roots = root.nodes.filter((node)=>node.type === 'root');
for (const root of roots){
if (root.type === 'root') {
await (0, _processTailwindFeatures.default)(context)(root, result);
}
}
return;
}
await (0, _processTailwindFeatures.default)(context)(root, result);
},
function lightningCssPlugin(_root, result) {
var _intermediateResult_map_toJSON, _intermediateResult_map;
var _result_map;
let map = (_result_map = result.map) !== null && _result_map !== void 0 ? _result_map : result.opts.map;
let intermediateResult = result.root.toResult({
map: map ? {
inline: true
} : false
});
var _intermediateResult_map_toJSON1;
let intermediateMap = (_intermediateResult_map_toJSON1 = (_intermediateResult_map = intermediateResult.map) === null || _intermediateResult_map === void 0 ? void 0 : (_intermediateResult_map_toJSON = _intermediateResult_map.toJSON) === null || _intermediateResult_map_toJSON === void 0 ? void 0 : _intermediateResult_map_toJSON.call(_intermediateResult_map)) !== null && _intermediateResult_map_toJSON1 !== void 0 ? _intermediateResult_map_toJSON1 : map;
try {
var _browserslist_findConfig;
var _result_opts_from;
let resolvedBrowsersListConfig = (_browserslist_findConfig = _browserslist.default.findConfig((_result_opts_from = result.opts.from) !== null && _result_opts_from !== void 0 ? _result_opts_from : process.cwd())) === null || _browserslist_findConfig === void 0 ? void 0 : _browserslist_findConfig.defaults;
let defaultBrowsersListConfig = require('../package.json').browserslist;
let browsersListConfig = resolvedBrowsersListConfig !== null && resolvedBrowsersListConfig !== void 0 ? resolvedBrowsersListConfig : defaultBrowsersListConfig;
let transformed = _lightningcss.default.transform({
filename: result.opts.from,
code: Buffer.from(intermediateResult.css),
minify: false,
sourceMap: !!intermediateMap,
targets: _lightningcss.default.browserslistToTargets((0, _browserslist.default)(browsersListConfig)),
errorRecovery: true,
drafts: {
customMedia: true
},
nonStandard: {
deepSelectorCombinator: true
},
include: _lightningcss.Features.Nesting,
exclude: _lightningcss.Features.LogicalProperties
});
let code = transformed.code.toString();
// https://postcss.org/api/#sourcemapoptions
if (intermediateMap && transformed.map != null) {
let prev = transformed.map.toString();
if (typeof intermediateMap === 'object') {
intermediateMap.prev = prev;
} else {
code = `${code}\n/*# sourceMappingURL=data:application/json;base64,${Buffer.from(prev).toString('base64')} */`;
}
}
result.root = _postcss.default.parse(license() + code, {
...result.opts,
map: intermediateMap
});
} catch (err) {
if (err.source && typeof process !== 'undefined' && process.env.JEST_WORKER_ID) {
let lines = err.source.split('\n');
err = new Error([
'Error formatting using Lightning CSS:',
'',
...[
'```css',
...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line),
' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(),
...lines.slice(err.loc.line, err.loc.line + 2),
'```'
]
].join('\n'));
}
if (Error.captureStackTrace) {
Error.captureStackTrace(err, lightningCssPlugin);
}
throw err;
}
},
_sharedState.env.DEBUG && function(root) {
console.timeEnd('JIT TOTAL');
console.log('\n');
return root;
}
].filter(Boolean)
};
};
module.exports.postcss = true;
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _plugin = require("./plugin");
const _default = Object.assign(function(opts) {
return {
postcssPlugin: 'tailwindcss/nesting',
Once (root, { result }) {
return (0, _plugin.nesting)(opts)(root, result);
}
};
}, {
postcss: true
});
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "nesting", {
enumerable: true,
get: function() {
return nesting;
}
});
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _postcssnested = /*#__PURE__*/ _interop_require_default(require("postcss-nested"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function nesting(opts = _postcssnested.default) {
return (root, result)=>{
root.walkAtRules('screen', (rule)=>{
rule.name = 'media';
rule.params = `screen(${rule.params})`;
});
root.walkAtRules('apply', (rule)=>{
rule.before(_postcss.default.decl({
prop: '__apply',
value: rule.params,
source: rule.source
}));
rule.remove();
});
let plugin = (()=>{
var _opts_hasOwnProperty;
if (typeof opts === 'function' || typeof opts === 'object' && (opts === null || opts === void 0 ? void 0 : (_opts_hasOwnProperty = opts.hasOwnProperty) === null || _opts_hasOwnProperty === void 0 ? void 0 : _opts_hasOwnProperty.call(opts, 'postcssPlugin'))) {
return opts;
}
if (typeof opts === 'string') {
return require(opts);
}
if (Object.keys(opts).length <= 0) {
return _postcssnested.default;
}
throw new Error('tailwindcss/nesting should be loaded with a nesting plugin.');
})();
(0, _postcss.default)([
plugin
]).process(root, result.opts).sync();
root.walkDecls('__apply', (decl)=>{
decl.before(_postcss.default.atRule({
name: 'apply',
params: decl.value,
source: decl.source
}));
decl.remove();
});
/**
* Use a private PostCSS API to remove the "clean" flag from the entire AST.
* This is done because running process() on the AST will set the "clean"
* flag on all nodes, which we don't want.
*
* This causes downstream plugins using the visitor API to be skipped.
*
* This is guarded because the PostCSS API is not public
* and may change in future versions of PostCSS.
*
* See https://github.com/postcss/postcss/issues/1712 for more details
*
* @param {import('postcss').Node} node
*/ function markDirty(node) {
if (!('markDirty' in node)) {
return;
}
// Traverse the tree down to the leaf nodes
if (node.nodes) {
node.nodes.forEach((n)=>markDirty(n));
}
// If it's a leaf node mark it as dirty
// We do this here because marking a node as dirty
// will walk up the tree and mark all parents as dirty
// resulting in a lot of unnecessary work if we did this
// for every single node
if (!node.nodes) {
node.markDirty();
}
}
markDirty(root);
return root;
};
}
# tailwindcss/nesting
This is a PostCSS plugin that wraps [postcss-nested](https://github.com/postcss/postcss-nested) or [postcss-nesting](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting) and acts as a compatibility layer to make sure your nesting plugin of choice properly understands Tailwind's custom syntax like `@apply` and `@screen`.
Add it to your PostCSS configuration, somewhere before Tailwind itself:
```js
// postcss.config.js
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss/nesting'),
require('tailwindcss'),
require('autoprefixer'),
]
}
```
By default, it uses the [postcss-nested](https://github.com/postcss/postcss-nested) plugin under the hood, which uses a Sass-like syntax and is the plugin that powers nesting support in the [Tailwind CSS plugin API](https://tailwindcss.com/docs/plugins#css-in-js-syntax).
If you'd rather use [postcss-nesting](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting) (which is based on the work-in-progress [CSS Nesting](https://drafts.csswg.org/css-nesting-1/) specification), first install the plugin alongside:
```shell
npm install postcss-nesting
```
Then pass the plugin itself as an argument to `tailwindcss/nesting` in your PostCSS configuration:
```js
// postcss.config.js
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss/nesting')(require('postcss-nesting')),
require('tailwindcss'),
require('autoprefixer'),
]
}
```
This can also be helpful if for whatever reason you need to use a very specific version of `postcss-nested` and want to override the version we bundle with `tailwindcss/nesting` itself.
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return processTailwindFeatures;
}
});
const _normalizeTailwindDirectives = /*#__PURE__*/ _interop_require_default(require("./lib/normalizeTailwindDirectives"));
const _expandTailwindAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandTailwindAtRules"));
const _expandApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/expandApplyAtRules"));
const _evaluateTailwindFunctions = /*#__PURE__*/ _interop_require_default(require("./lib/evaluateTailwindFunctions"));
const _substituteScreenAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/substituteScreenAtRules"));
const _resolveDefaultsAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/resolveDefaultsAtRules"));
const _collapseAdjacentRules = /*#__PURE__*/ _interop_require_default(require("./lib/collapseAdjacentRules"));
const _collapseDuplicateDeclarations = /*#__PURE__*/ _interop_require_default(require("./lib/collapseDuplicateDeclarations"));
const _partitionApplyAtRules = /*#__PURE__*/ _interop_require_default(require("./lib/partitionApplyAtRules"));
const _detectNesting = /*#__PURE__*/ _interop_require_default(require("./lib/detectNesting"));
const _setupContextUtils = require("./lib/setupContextUtils");
const _featureFlags = require("./featureFlags");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function processTailwindFeatures(setupContext) {
return async function(root, result) {
let { tailwindDirectives, applyDirectives } = (0, _normalizeTailwindDirectives.default)(root);
(0, _detectNesting.default)()(root, result);
// Partition apply rules that are found in the css
// itself.
(0, _partitionApplyAtRules.default)()(root, result);
let context = setupContext({
tailwindDirectives,
applyDirectives,
registerDependency (dependency) {
result.messages.push({
plugin: 'tailwindcss',
parent: result.opts.from,
...dependency
});
},
createContext (tailwindConfig, changedContent) {
return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root);
}
})(root, result);
if (context.tailwindConfig.separator === '-') {
throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead.");
}
(0, _featureFlags.issueFlagNotices)(context.tailwindConfig);
await (0, _expandTailwindAtRules.default)(context)(root, result);
// Partition apply rules that are generated by
// addComponents, addUtilities and so on.
(0, _partitionApplyAtRules.default)()(root, result);
(0, _expandApplyAtRules.default)(context)(root, result);
(0, _evaluateTailwindFunctions.default)(context)(root, result);
(0, _substituteScreenAtRules.default)(context)(root, result);
(0, _resolveDefaultsAtRules.default)(context)(root, result);
(0, _collapseAdjacentRules.default)(context)(root, result);
(0, _collapseDuplicateDeclarations.default)(context)(root, result);
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function warn({ version, from, to }) {
_log.default.warn(`${from}-color-renamed`, [
`As of Tailwind CSS ${version}, \`${from}\` has been renamed to \`${to}\`.`,
'Update your configuration file to silence this warning.'
]);
}
const _default = {
inherit: 'inherit',
current: 'currentColor',
transparent: 'transparent',
black: '#000',
white: '#fff',
slate: {
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a',
950: '#020617'
},
gray: {
50: '#f9fafb',
100: '#f3f4f6',
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827',
950: '#030712'
},
zinc: {
50: '#fafafa',
100: '#f4f4f5',
200: '#e4e4e7',
300: '#d4d4d8',
400: '#a1a1aa',
500: '#71717a',
600: '#52525b',
700: '#3f3f46',
800: '#27272a',
900: '#18181b',
950: '#09090b'
},
neutral: {
50: '#fafafa',
100: '#f5f5f5',
200: '#e5e5e5',
300: '#d4d4d4',
400: '#a3a3a3',
500: '#737373',
600: '#525252',
700: '#404040',
800: '#262626',
900: '#171717',
950: '#0a0a0a'
},
stone: {
50: '#fafaf9',
100: '#f5f5f4',
200: '#e7e5e4',
300: '#d6d3d1',
400: '#a8a29e',
500: '#78716c',
600: '#57534e',
700: '#44403c',
800: '#292524',
900: '#1c1917',
950: '#0c0a09'
},
red: {
50: '#fef2f2',
100: '#fee2e2',
200: '#fecaca',
300: '#fca5a5',
400: '#f87171',
500: '#ef4444',
600: '#dc2626',
700: '#b91c1c',
800: '#991b1b',
900: '#7f1d1d',
950: '#450a0a'
},
orange: {
50: '#fff7ed',
100: '#ffedd5',
200: '#fed7aa',
300: '#fdba74',
400: '#fb923c',
500: '#f97316',
600: '#ea580c',
700: '#c2410c',
800: '#9a3412',
900: '#7c2d12',
950: '#431407'
},
amber: {
50: '#fffbeb',
100: '#fef3c7',
200: '#fde68a',
300: '#fcd34d',
400: '#fbbf24',
500: '#f59e0b',
600: '#d97706',
700: '#b45309',
800: '#92400e',
900: '#78350f',
950: '#451a03'
},
yellow: {
50: '#fefce8',
100: '#fef9c3',
200: '#fef08a',
300: '#fde047',
400: '#facc15',
500: '#eab308',
600: '#ca8a04',
700: '#a16207',
800: '#854d0e',
900: '#713f12',
950: '#422006'
},
lime: {
50: '#f7fee7',
100: '#ecfccb',
200: '#d9f99d',
300: '#bef264',
400: '#a3e635',
500: '#84cc16',
600: '#65a30d',
700: '#4d7c0f',
800: '#3f6212',
900: '#365314',
950: '#1a2e05'
},
green: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d',
950: '#052e16'
},
emerald: {
50: '#ecfdf5',
100: '#d1fae5',
200: '#a7f3d0',
300: '#6ee7b7',
400: '#34d399',
500: '#10b981',
600: '#059669',
700: '#047857',
800: '#065f46',
900: '#064e3b',
950: '#022c22'
},
teal: {
50: '#f0fdfa',
100: '#ccfbf1',
200: '#99f6e4',
300: '#5eead4',
400: '#2dd4bf',
500: '#14b8a6',
600: '#0d9488',
700: '#0f766e',
800: '#115e59',
900: '#134e4a',
950: '#042f2e'
},
cyan: {
50: '#ecfeff',
100: '#cffafe',
200: '#a5f3fc',
300: '#67e8f9',
400: '#22d3ee',
500: '#06b6d4',
600: '#0891b2',
700: '#0e7490',
800: '#155e75',
900: '#164e63',
950: '#083344'
},
sky: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
950: '#082f49'
},
blue: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
950: '#172554'
},
indigo: {
50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1',
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81',
950: '#1e1b4b'
},
violet: {
50: '#f5f3ff',
100: '#ede9fe',
200: '#ddd6fe',
300: '#c4b5fd',
400: '#a78bfa',
500: '#8b5cf6',
600: '#7c3aed',
700: '#6d28d9',
800: '#5b21b6',
900: '#4c1d95',
950: '#2e1065'
},
purple: {
50: '#faf5ff',
100: '#f3e8ff',
200: '#e9d5ff',
300: '#d8b4fe',
400: '#c084fc',
500: '#a855f7',
600: '#9333ea',
700: '#7e22ce',
800: '#6b21a8',
900: '#581c87',
950: '#3b0764'
},
fuchsia: {
50: '#fdf4ff',
100: '#fae8ff',
200: '#f5d0fe',
300: '#f0abfc',
400: '#e879f9',
500: '#d946ef',
600: '#c026d3',
700: '#a21caf',
800: '#86198f',
900: '#701a75',
950: '#4a044e'
},
pink: {
50: '#fdf2f8',
100: '#fce7f3',
200: '#fbcfe8',
300: '#f9a8d4',
400: '#f472b6',
500: '#ec4899',
600: '#db2777',
700: '#be185d',
800: '#9d174d',
900: '#831843',
950: '#500724'
},
rose: {
50: '#fff1f2',
100: '#ffe4e6',
200: '#fecdd3',
300: '#fda4af',
400: '#fb7185',
500: '#f43f5e',
600: '#e11d48',
700: '#be123c',
800: '#9f1239',
900: '#881337',
950: '#4c0519'
},
get lightBlue () {
warn({
version: 'v2.2',
from: 'lightBlue',
to: 'sky'
});
return this.sky;
},
get warmGray () {
warn({
version: 'v3.0',
from: 'warmGray',
to: 'stone'
});
return this.stone;
},
get trueGray () {
warn({
version: 'v3.0',
from: 'trueGray',
to: 'neutral'
});
return this.neutral;
},
get coolGray () {
warn({
version: 'v3.0',
from: 'coolGray',
to: 'gray'
});
return this.gray;
},
get blueGray () {
warn({
version: 'v3.0',
from: 'blueGray',
to: 'slate'
});
return this.slate;
}
};
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _createPlugin = /*#__PURE__*/ _interop_require_default(require("../util/createPlugin"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const _default = _createPlugin.default;
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _cloneDeep = require("../util/cloneDeep");
const _configfull = /*#__PURE__*/ _interop_require_default(require("../../stubs/config.full"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const _default = (0, _cloneDeep.cloneDeep)(_configfull.default);
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _cloneDeep = require("../util/cloneDeep");
const _configfull = /*#__PURE__*/ _interop_require_default(require("../../stubs/config.full"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const _default = (0, _cloneDeep.cloneDeep)(_configfull.default.theme);
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _loadconfig = require("../lib/load-config");
const _default = _loadconfig.loadConfig;
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return resolveConfig;
}
});
const _resolveConfig = /*#__PURE__*/ _interop_require_default(require("../util/resolveConfig"));
const _getAllConfigs = /*#__PURE__*/ _interop_require_default(require("../util/getAllConfigs"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function resolveConfig(...configs) {
let [, ...defaultConfigs] = (0, _getAllConfigs.default)(configs[0]);
return (0, _resolveConfig.default)([
...configs,
...defaultConfigs
]);
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "applyImportantSelector", {
enumerable: true,
get: function() {
return applyImportantSelector;
}
});
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
const _pseudoElements = require("./pseudoElements");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function applyImportantSelector(selector, important) {
let sel = (0, _postcssselectorparser.default)().astSync(selector);
sel.each((sel)=>{
// Wrap with :is if it's not already wrapped
let isWrapped = sel.nodes[0].type === 'pseudo' && sel.nodes[0].value === ':is' && sel.nodes.every((node)=>node.type !== 'combinator');
if (!isWrapped) {
sel.nodes = [
_postcssselectorparser.default.pseudo({
value: ':is',
nodes: [
sel.clone()
]
})
];
}
(0, _pseudoElements.movePseudos)(sel);
});
return `${important} ${sel.toString()}`;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return bigSign;
}
});
function bigSign(bigIntValue) {
return (bigIntValue > 0n) - (bigIntValue < 0n);
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return buildMediaQuery;
}
});
function buildMediaQuery(screens) {
screens = Array.isArray(screens) ? screens : [
screens
];
return screens.map((screen)=>{
let values = screen.values.map((screen)=>{
if (screen.raw !== undefined) {
return screen.raw;
}
return [
screen.min && `(min-width: ${screen.min})`,
screen.max && `(max-width: ${screen.max})`
].filter(Boolean).join(' and ');
});
return screen.not ? `not all and ${values}` : values;
}).join(', ');
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "cloneDeep", {
enumerable: true,
get: function() {
return cloneDeep;
}
});
function cloneDeep(value) {
if (Array.isArray(value)) {
return value.map((child)=>cloneDeep(child));
}
if (typeof value === 'object' && value !== null) {
return Object.fromEntries(Object.entries(value).map(([k, v])=>[
k,
cloneDeep(v)
]));
}
return value;
}
/**
* @param {import('postcss').Container[]} nodes
* @param {any} source
* @param {any} raws
* @returns {import('postcss').Container[]}
*/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return cloneNodes;
}
});
function cloneNodes(nodes, source = undefined, raws = undefined) {
return nodes.map((node)=>{
let cloned = node.clone();
if (raws !== undefined) {
cloned.raws.tailwind = {
...cloned.raws.tailwind,
...raws
};
}
if (source !== undefined) {
traverse(cloned, (node)=>{
var _node_raws_tailwind;
// Do not traverse nodes that have opted
// to preserve their original source
let shouldPreserveSource = ((_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.preserveSource) === true && node.source;
if (shouldPreserveSource) {
return false;
}
// Otherwise we can safely replace the source
// And continue traversing
node.source = source;
});
}
return cloned;
});
}
/**
* Traverse a tree of nodes and don't traverse children if the callback
* returns false. Ideally we'd use Container#walk instead of this
* function but it stops traversing siblings too.
*
* @param {import('postcss').Container} node
* @param {(node: import('postcss').Container) => boolean} onNode
*/ function traverse(node, onNode) {
if (onNode(node) !== false) {
var _node_each;
(_node_each = node.each) === null || _node_each === void 0 ? void 0 : _node_each.call(node, (child)=>traverse(child, onNode));
}
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
formatColor: function() {
return formatColor;
},
parseColor: function() {
return parseColor;
}
});
const _colorNames = /*#__PURE__*/ _interop_require_default(require("./colorNames"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let HEX = /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i;
let SHORT_HEX = /^#([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i;
let VALUE = /(?:\d+|\d*\.\d+)%?/;
let SEP = /(?:\s*,\s*|\s+)/;
let ALPHA_SEP = /\s*[,/]\s*/;
let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)(?:,(?:[^ )]*?|var\(--[^ )]*?\)))?\)/;
let RGB = new RegExp(`^(rgba?)\\(\\s*(${VALUE.source}|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$`);
let HSL = new RegExp(`^(hsla?)\\(\\s*((?:${VALUE.source})(?:deg|rad|grad|turn)?|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$`);
function parseColor(value, { loose = false } = {}) {
var _match__toString, _match_;
if (typeof value !== 'string') {
return null;
}
value = value.trim();
if (value === 'transparent') {
return {
mode: 'rgb',
color: [
'0',
'0',
'0'
],
alpha: '0'
};
}
if (value in _colorNames.default) {
return {
mode: 'rgb',
color: _colorNames.default[value].map((v)=>v.toString())
};
}
let hex = value.replace(SHORT_HEX, (_, r, g, b, a)=>[
'#',
r,
r,
g,
g,
b,
b,
a ? a + a : ''
].join('')).match(HEX);
if (hex !== null) {
return {
mode: 'rgb',
color: [
parseInt(hex[1], 16),
parseInt(hex[2], 16),
parseInt(hex[3], 16)
].map((v)=>v.toString()),
alpha: hex[4] ? (parseInt(hex[4], 16) / 255).toString() : undefined
};
}
var _value_match;
let match = (_value_match = value.match(RGB)) !== null && _value_match !== void 0 ? _value_match : value.match(HSL);
if (match === null) {
return null;
}
let color = [
match[2],
match[3],
match[4]
].filter(Boolean).map((v)=>v.toString());
// rgba(var(--my-color), 0.1)
// hsla(var(--my-color), 0.1)
if (color.length === 2 && color[0].startsWith('var(')) {
return {
mode: match[1],
color: [
color[0]
],
alpha: color[1]
};
}
if (!loose && color.length !== 3) {
return null;
}
if (color.length < 3 && !color.some((part)=>/^var\(.*?\)$/.test(part))) {
return null;
}
return {
mode: match[1],
color,
alpha: (_match_ = match[5]) === null || _match_ === void 0 ? void 0 : (_match__toString = _match_.toString) === null || _match__toString === void 0 ? void 0 : _match__toString.call(_match_)
};
}
function formatColor({ mode, color, alpha }) {
let hasAlpha = alpha !== undefined;
if (mode === 'rgba' || mode === 'hsla') {
return `${mode}(${color.join(', ')}${hasAlpha ? `, ${alpha}` : ''})`;
}
return `${mode}(${color.join(' ')}${hasAlpha ? ` / ${alpha}` : ''})`;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _default = {
aliceblue: [
240,
248,
255
],
antiquewhite: [
250,
235,
215
],
aqua: [
0,
255,
255
],
aquamarine: [
127,
255,
212
],
azure: [
240,
255,
255
],
beige: [
245,
245,
220
],
bisque: [
255,
228,
196
],
black: [
0,
0,
0
],
blanchedalmond: [
255,
235,
205
],
blue: [
0,
0,
255
],
blueviolet: [
138,
43,
226
],
brown: [
165,
42,
42
],
burlywood: [
222,
184,
135
],
cadetblue: [
95,
158,
160
],
chartreuse: [
127,
255,
0
],
chocolate: [
210,
105,
30
],
coral: [
255,
127,
80
],
cornflowerblue: [
100,
149,
237
],
cornsilk: [
255,
248,
220
],
crimson: [
220,
20,
60
],
cyan: [
0,
255,
255
],
darkblue: [
0,
0,
139
],
darkcyan: [
0,
139,
139
],
darkgoldenrod: [
184,
134,
11
],
darkgray: [
169,
169,
169
],
darkgreen: [
0,
100,
0
],
darkgrey: [
169,
169,
169
],
darkkhaki: [
189,
183,
107
],
darkmagenta: [
139,
0,
139
],
darkolivegreen: [
85,
107,
47
],
darkorange: [
255,
140,
0
],
darkorchid: [
153,
50,
204
],
darkred: [
139,
0,
0
],
darksalmon: [
233,
150,
122
],
darkseagreen: [
143,
188,
143
],
darkslateblue: [
72,
61,
139
],
darkslategray: [
47,
79,
79
],
darkslategrey: [
47,
79,
79
],
darkturquoise: [
0,
206,
209
],
darkviolet: [
148,
0,
211
],
deeppink: [
255,
20,
147
],
deepskyblue: [
0,
191,
255
],
dimgray: [
105,
105,
105
],
dimgrey: [
105,
105,
105
],
dodgerblue: [
30,
144,
255
],
firebrick: [
178,
34,
34
],
floralwhite: [
255,
250,
240
],
forestgreen: [
34,
139,
34
],
fuchsia: [
255,
0,
255
],
gainsboro: [
220,
220,
220
],
ghostwhite: [
248,
248,
255
],
gold: [
255,
215,
0
],
goldenrod: [
218,
165,
32
],
gray: [
128,
128,
128
],
green: [
0,
128,
0
],
greenyellow: [
173,
255,
47
],
grey: [
128,
128,
128
],
honeydew: [
240,
255,
240
],
hotpink: [
255,
105,
180
],
indianred: [
205,
92,
92
],
indigo: [
75,
0,
130
],
ivory: [
255,
255,
240
],
khaki: [
240,
230,
140
],
lavender: [
230,
230,
250
],
lavenderblush: [
255,
240,
245
],
lawngreen: [
124,
252,
0
],
lemonchiffon: [
255,
250,
205
],
lightblue: [
173,
216,
230
],
lightcoral: [
240,
128,
128
],
lightcyan: [
224,
255,
255
],
lightgoldenrodyellow: [
250,
250,
210
],
lightgray: [
211,
211,
211
],
lightgreen: [
144,
238,
144
],
lightgrey: [
211,
211,
211
],
lightpink: [
255,
182,
193
],
lightsalmon: [
255,
160,
122
],
lightseagreen: [
32,
178,
170
],
lightskyblue: [
135,
206,
250
],
lightslategray: [
119,
136,
153
],
lightslategrey: [
119,
136,
153
],
lightsteelblue: [
176,
196,
222
],
lightyellow: [
255,
255,
224
],
lime: [
0,
255,
0
],
limegreen: [
50,
205,
50
],
linen: [
250,
240,
230
],
magenta: [
255,
0,
255
],
maroon: [
128,
0,
0
],
mediumaquamarine: [
102,
205,
170
],
mediumblue: [
0,
0,
205
],
mediumorchid: [
186,
85,
211
],
mediumpurple: [
147,
112,
219
],
mediumseagreen: [
60,
179,
113
],
mediumslateblue: [
123,
104,
238
],
mediumspringgreen: [
0,
250,
154
],
mediumturquoise: [
72,
209,
204
],
mediumvioletred: [
199,
21,
133
],
midnightblue: [
25,
25,
112
],
mintcream: [
245,
255,
250
],
mistyrose: [
255,
228,
225
],
moccasin: [
255,
228,
181
],
navajowhite: [
255,
222,
173
],
navy: [
0,
0,
128
],
oldlace: [
253,
245,
230
],
olive: [
128,
128,
0
],
olivedrab: [
107,
142,
35
],
orange: [
255,
165,
0
],
orangered: [
255,
69,
0
],
orchid: [
218,
112,
214
],
palegoldenrod: [
238,
232,
170
],
palegreen: [
152,
251,
152
],
paleturquoise: [
175,
238,
238
],
palevioletred: [
219,
112,
147
],
papayawhip: [
255,
239,
213
],
peachpuff: [
255,
218,
185
],
peru: [
205,
133,
63
],
pink: [
255,
192,
203
],
plum: [
221,
160,
221
],
powderblue: [
176,
224,
230
],
purple: [
128,
0,
128
],
rebeccapurple: [
102,
51,
153
],
red: [
255,
0,
0
],
rosybrown: [
188,
143,
143
],
royalblue: [
65,
105,
225
],
saddlebrown: [
139,
69,
19
],
salmon: [
250,
128,
114
],
sandybrown: [
244,
164,
96
],
seagreen: [
46,
139,
87
],
seashell: [
255,
245,
238
],
sienna: [
160,
82,
45
],
silver: [
192,
192,
192
],
skyblue: [
135,
206,
235
],
slateblue: [
106,
90,
205
],
slategray: [
112,
128,
144
],
slategrey: [
112,
128,
144
],
snow: [
255,
250,
250
],
springgreen: [
0,
255,
127
],
steelblue: [
70,
130,
180
],
tan: [
210,
180,
140
],
teal: [
0,
128,
128
],
thistle: [
216,
191,
216
],
tomato: [
255,
99,
71
],
turquoise: [
64,
224,
208
],
violet: [
238,
130,
238
],
wheat: [
245,
222,
179
],
white: [
255,
255,
255
],
whitesmoke: [
245,
245,
245
],
yellow: [
255,
255,
0
],
yellowgreen: [
154,
205,
50
]
};
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
function _default(pluginConfig, plugins) {
if (pluginConfig === undefined) {
return plugins;
}
const pluginNames = Array.isArray(pluginConfig) ? pluginConfig : [
...new Set(plugins.filter((pluginName)=>{
return pluginConfig !== false && pluginConfig[pluginName] !== false;
}).concat(Object.keys(pluginConfig).filter((pluginName)=>{
return pluginConfig[pluginName] !== false;
})))
];
return pluginNames;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
function createPlugin(plugin, config) {
return {
handler: plugin,
config
};
}
createPlugin.withOptions = function(pluginFunction, configFunction = ()=>({})) {
const optionsFunction = function(options) {
return {
__options: options,
handler: pluginFunction(options),
config: configFunction(options)
};
};
optionsFunction.__isOptionsFunction = true;
// Expose plugin dependencies so that `object-hash` returns a different
// value if anything here changes, to ensure a rebuild is triggered.
optionsFunction.__pluginFunction = pluginFunction;
optionsFunction.__configFunction = configFunction;
return optionsFunction;
};
const _default = createPlugin;
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return createUtilityPlugin;
}
});
const _transformThemeValue = /*#__PURE__*/ _interop_require_default(require("./transformThemeValue"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function createUtilityPlugin(themeKey, utilityVariations = [
[
themeKey,
[
themeKey
]
]
], { filterDefault = false, ...options } = {}) {
let transformValue = (0, _transformThemeValue.default)(themeKey);
return function({ matchUtilities, theme }) {
for (let utilityVariation of utilityVariations){
let group = Array.isArray(utilityVariation[0]) ? utilityVariation : [
utilityVariation
];
var _theme;
matchUtilities(group.reduce((obj, [classPrefix, properties])=>{
return Object.assign(obj, {
[classPrefix]: (value)=>{
return properties.reduce((obj, name)=>{
if (Array.isArray(name)) {
return Object.assign(obj, {
[name[0]]: name[1]
});
}
return Object.assign(obj, {
[name]: transformValue(value)
});
}, {});
}
});
}, {}), {
...options,
values: filterDefault ? Object.fromEntries(Object.entries((_theme = theme(themeKey)) !== null && _theme !== void 0 ? _theme : {}).filter(([modifier])=>modifier !== 'DEFAULT')) : theme(themeKey)
});
}
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
absoluteSize: function() {
return absoluteSize;
},
color: function() {
return color;
},
familyName: function() {
return familyName;
},
genericName: function() {
return genericName;
},
gradient: function() {
return gradient;
},
image: function() {
return image;
},
length: function() {
return length;
},
lineWidth: function() {
return lineWidth;
},
normalize: function() {
return normalize;
},
number: function() {
return number;
},
percentage: function() {
return percentage;
},
position: function() {
return position;
},
relativeSize: function() {
return relativeSize;
},
shadow: function() {
return shadow;
},
url: function() {
return url;
}
});
const _color = require("./color");
const _parseBoxShadowValue = require("./parseBoxShadowValue");
const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly");
let cssFunctions = [
'min',
'max',
'clamp',
'calc'
];
let IS_CSS_FN = new RegExp(`^(${cssFunctions.join('|')})\\(.*\\)`);
// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
function isCSSFunction(value) {
return IS_CSS_FN.test(value);
}
// These properties accept a `<dashed-ident>` as one of the values. This means that you can use them
// as: `timeline-scope: --tl;`
//
// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add
// the `var()` yourself.
//
// More info:
// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope
// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident
//
const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([
// Concrete properties
'scroll-timeline-name',
'timeline-scope',
'view-timeline-name',
'font-palette',
// Shorthand properties
'scroll-timeline',
'animation-timeline',
'view-timeline'
]);
function normalize(value, context = null, isRoot = true) {
let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property);
if (value.startsWith('--') && !isVarException) {
return `var(${value})`;
}
// Keep raw strings if it starts with `url(`
if (value.includes('url(')) {
return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{
if (/^url\(.*?\)$/.test(part)) {
return part;
}
return normalize(part, context, false);
}).join('');
}
// Convert `_` to ` `, except for escaped underscores `\_`
value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + ' '.repeat(fullMatch.length - 1)).replace(/^_/g, ' ').replace(/\\_/g, '_');
// Remove leftover whitespace
if (isRoot) {
value = value.trim();
}
value = normalizeMathOperatorSpacing(value);
return value;
}
/**
* Add spaces around operators inside math functions
* like calc() that do not follow an operator, '(', or `,`.
*
* @param {string} value
* @returns {string}
*/ function normalizeMathOperatorSpacing(value) {
let preventFormattingInFunctions = [
'theme'
];
let preventFormattingKeywords = [
'min-content',
'max-content',
'fit-content',
// Env
'safe-area-inset-top',
'safe-area-inset-right',
'safe-area-inset-bottom',
'safe-area-inset-left',
'titlebar-area-x',
'titlebar-area-y',
'titlebar-area-width',
'titlebar-area-height',
'keyboard-inset-top',
'keyboard-inset-right',
'keyboard-inset-bottom',
'keyboard-inset-left',
'keyboard-inset-width',
'keyboard-inset-height'
];
return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{
let result = '';
function lastChar() {
let char = result.trimEnd();
return char[char.length - 1];
}
for(let i = 0; i < match.length; i++){
function peek(word) {
return word.split('').every((char, j)=>match[i + j] === char);
}
function consumeUntil(chars) {
let minIndex = Infinity;
for (let char of chars){
let index = match.indexOf(char, i);
if (index !== -1 && index < minIndex) {
minIndex = index;
}
}
let result = match.slice(i, minIndex);
i += result.length - 1;
return result;
}
let char = match[i];
// Handle `var(--variable)`
if (peek('var')) {
// When we consume until `)`, then we are dealing with this scenario:
// `var(--example)`
//
// When we consume until `,`, then we are dealing with this scenario:
// `var(--example, 1rem)`
//
// In this case we do want to "format", the default value as well
result += consumeUntil([
')',
','
]);
} else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) {
let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword));
result += keyword;
i += keyword.length - 1;
} else if (preventFormattingInFunctions.some((fn)=>peek(fn))) {
result += consumeUntil([
')'
]);
} else if ([
'+',
'-',
'*',
'/'
].includes(char) && ![
'(',
'+',
'-',
'*',
'/',
','
].includes(lastChar())) {
result += ` ${char} `;
} else {
result += char;
}
}
// Simplify multiple spaces
return result.replace(/\s+/g, ' ');
});
}
function url(value) {
return value.startsWith('url(');
}
function number(value) {
return !isNaN(Number(value)) || isCSSFunction(value);
}
function percentage(value) {
return value.endsWith('%') && number(value.slice(0, -1)) || isCSSFunction(value);
}
// Please refer to MDN when updating this list:
// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units
// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units
let lengthUnits = [
'cm',
'mm',
'Q',
'in',
'pc',
'pt',
'px',
'em',
'ex',
'ch',
'rem',
'lh',
'rlh',
'vw',
'vh',
'vmin',
'vmax',
'vb',
'vi',
'svw',
'svh',
'lvw',
'lvh',
'dvw',
'dvh',
'cqw',
'cqh',
'cqi',
'cqb',
'cqmin',
'cqmax'
];
let lengthUnitsPattern = `(?:${lengthUnits.join('|')})`;
let lengthRegExp = new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`);
function length(value) {
return value === '0' || lengthRegExp.test(value) || isCSSFunction(value);
}
let lineWidths = new Set([
'thin',
'medium',
'thick'
]);
function lineWidth(value) {
return lineWidths.has(value);
}
function shadow(value) {
let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value));
for (let parsedShadow of parsedShadows){
if (!parsedShadow.valid) {
return false;
}
}
return true;
}
function color(value) {
let colors = 0;
let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, '_').every((part)=>{
part = normalize(part);
if (part.startsWith('var(')) return true;
if ((0, _color.parseColor)(part, {
loose: true
}) !== null) return colors++, true;
return false;
});
if (!result) return false;
return colors > 0;
}
function image(value) {
let images = 0;
let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ',').every((part)=>{
part = normalize(part);
if (part.startsWith('var(')) return true;
if (url(part) || gradient(part) || [
'element(',
'image(',
'cross-fade(',
'image-set('
].some((fn)=>part.startsWith(fn))) {
images++;
return true;
}
return false;
});
if (!result) return false;
return images > 0;
}
let gradientTypes = new Set([
'conic-gradient',
'linear-gradient',
'radial-gradient',
'repeating-conic-gradient',
'repeating-linear-gradient',
'repeating-radial-gradient'
]);
function gradient(value) {
value = normalize(value);
for (let type of gradientTypes){
if (value.startsWith(`${type}(`)) {
return true;
}
}
return false;
}
let validPositions = new Set([
'center',
'top',
'right',
'bottom',
'left'
]);
function position(value) {
let positions = 0;
let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, '_').every((part)=>{
part = normalize(part);
if (part.startsWith('var(')) return true;
if (validPositions.has(part) || length(part) || percentage(part)) {
positions++;
return true;
}
return false;
});
if (!result) return false;
return positions > 0;
}
function familyName(value) {
let fonts = 0;
let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ',').every((part)=>{
part = normalize(part);
if (part.startsWith('var(')) return true;
// If it contains spaces, then it should be quoted
if (part.includes(' ')) {
if (!/(['"])([^"']+)\1/g.test(part)) {
return false;
}
}
// If it starts with a number, it's invalid
if (/^\d/g.test(part)) {
return false;
}
fonts++;
return true;
});
if (!result) return false;
return fonts > 0;
}
let genericNames = new Set([
'serif',
'sans-serif',
'monospace',
'cursive',
'fantasy',
'system-ui',
'ui-serif',
'ui-sans-serif',
'ui-monospace',
'ui-rounded',
'math',
'emoji',
'fangsong'
]);
function genericName(value) {
return genericNames.has(value);
}
let absoluteSizes = new Set([
'xx-small',
'x-small',
'small',
'medium',
'large',
'x-large',
'x-large',
'xxx-large'
]);
function absoluteSize(value) {
return absoluteSizes.has(value);
}
let relativeSizes = new Set([
'larger',
'smaller'
]);
function relativeSize(value) {
return relativeSizes.has(value);
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "defaults", {
enumerable: true,
get: function() {
return defaults;
}
});
function defaults(target, ...sources) {
for (let source of sources){
for(let k in source){
var _target_hasOwnProperty;
if (!(target === null || target === void 0 ? void 0 : (_target_hasOwnProperty = target.hasOwnProperty) === null || _target_hasOwnProperty === void 0 ? void 0 : _target_hasOwnProperty.call(target, k))) {
target[k] = source[k];
}
}
for (let k of Object.getOwnPropertySymbols(source)){
var _target_hasOwnProperty1;
if (!(target === null || target === void 0 ? void 0 : (_target_hasOwnProperty1 = target.hasOwnProperty) === null || _target_hasOwnProperty1 === void 0 ? void 0 : _target_hasOwnProperty1.call(target, k))) {
target[k] = source[k];
}
}
}
return target;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return escapeClassName;
}
});
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
const _escapeCommas = /*#__PURE__*/ _interop_require_default(require("./escapeCommas"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function escapeClassName(className) {
var _node_raws;
let node = _postcssselectorparser.default.className();
node.value = className;
var _node_raws_value;
return (0, _escapeCommas.default)((_node_raws_value = node === null || node === void 0 ? void 0 : (_node_raws = node.raws) === null || _node_raws === void 0 ? void 0 : _node_raws.value) !== null && _node_raws_value !== void 0 ? _node_raws_value : node.value);
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return escapeCommas;
}
});
function escapeCommas(className) {
return className.replace(/\\,/g, '\\2c ');
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const flattenColorPalette = (colors)=>Object.assign({}, ...Object.entries(colors !== null && colors !== void 0 ? colors : {}).flatMap(([color, values])=>typeof values == 'object' ? Object.entries(flattenColorPalette(values)).map(([number, hex])=>({
[color + (number === 'DEFAULT' ? '' : `-${number}`)]: hex
})) : [
{
[`${color}`]: values
}
]));
const _default = flattenColorPalette;
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
eliminateIrrelevantSelectors: function() {
return eliminateIrrelevantSelectors;
},
finalizeSelector: function() {
return finalizeSelector;
},
formatVariantSelector: function() {
return formatVariantSelector;
},
handleMergePseudo: function() {
return handleMergePseudo;
}
});
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
const _unesc = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser/dist/util/unesc"));
const _escapeClassName = /*#__PURE__*/ _interop_require_default(require("../util/escapeClassName"));
const _prefixSelector = /*#__PURE__*/ _interop_require_default(require("../util/prefixSelector"));
const _pseudoElements = require("./pseudoElements");
const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
/** @typedef {import('postcss-selector-parser').Root} Root */ /** @typedef {import('postcss-selector-parser').Selector} Selector */ /** @typedef {import('postcss-selector-parser').Pseudo} Pseudo */ /** @typedef {import('postcss-selector-parser').Node} Node */ /** @typedef {{format: string, respectPrefix: boolean}[]} RawFormats */ /** @typedef {import('postcss-selector-parser').Root} ParsedFormats */ /** @typedef {RawFormats | ParsedFormats} AcceptedFormats */ let MERGE = ':merge';
function formatVariantSelector(formats, { context, candidate }) {
var _context_tailwindConfig_prefix;
let prefix = (_context_tailwindConfig_prefix = context === null || context === void 0 ? void 0 : context.tailwindConfig.prefix) !== null && _context_tailwindConfig_prefix !== void 0 ? _context_tailwindConfig_prefix : '';
// Parse the format selector into an AST
let parsedFormats = formats.map((format)=>{
let ast = (0, _postcssselectorparser.default)().astSync(format.format);
return {
...format,
ast: format.respectPrefix ? (0, _prefixSelector.default)(prefix, ast) : ast
};
});
// We start with the candidate selector
let formatAst = _postcssselectorparser.default.root({
nodes: [
_postcssselectorparser.default.selector({
nodes: [
_postcssselectorparser.default.className({
value: (0, _escapeClassName.default)(candidate)
})
]
})
]
});
// And iteratively merge each format selector into the candidate selector
for (let { ast } of parsedFormats){
[formatAst, ast] = handleMergePseudo(formatAst, ast);
// 2. Merge the format selector into the current selector AST
ast.walkNesting((nesting)=>nesting.replaceWith(...formatAst.nodes[0].nodes));
// 3. Keep going!
formatAst = ast;
}
return formatAst;
}
/**
* Given any node in a selector this gets the "simple" selector it's a part of
* A simple selector is just a list of nodes without any combinators
* Technically :is(), :not(), :has(), etc… can have combinators but those are nested
* inside the relevant node and won't be picked up so they're fine to ignore
*
* @param {Node} node
* @returns {Node[]}
**/ function simpleSelectorForNode(node) {
/** @type {Node[]} */ let nodes = [];
// Walk backwards until we hit a combinator node (or the start)
while(node.prev() && node.prev().type !== 'combinator'){
node = node.prev();
}
// Now record all non-combinator nodes until we hit one (or the end)
while(node && node.type !== 'combinator'){
nodes.push(node);
node = node.next();
}
return nodes;
}
/**
* Resorts the nodes in a selector to ensure they're in the correct order
* Tags go before classes, and pseudo classes go after classes
*
* @param {Selector} sel
* @returns {Selector}
**/ function resortSelector(sel) {
sel.sort((a, b)=>{
if (a.type === 'tag' && b.type === 'class') {
return -1;
} else if (a.type === 'class' && b.type === 'tag') {
return 1;
} else if (a.type === 'class' && b.type === 'pseudo' && b.value.startsWith('::')) {
return -1;
} else if (a.type === 'pseudo' && a.value.startsWith('::') && b.type === 'class') {
return 1;
}
return sel.index(a) - sel.index(b);
});
return sel;
}
function eliminateIrrelevantSelectors(sel, base) {
let hasClassesMatchingCandidate = false;
sel.walk((child)=>{
if (child.type === 'class' && child.value === base) {
hasClassesMatchingCandidate = true;
return false // Stop walking
;
}
});
if (!hasClassesMatchingCandidate) {
sel.remove();
}
// We do NOT recursively eliminate sub selectors that don't have the base class
// as this is NOT a safe operation. For example, if we have:
// `.space-x-2 > :not([hidden]) ~ :not([hidden])`
// We cannot remove the [hidden] from the :not() because it would change the
// meaning of the selector.
// TODO: Can we do this for :matches, :is, and :where?
}
function finalizeSelector(current, formats, { context, candidate, base }) {
var _context_tailwindConfig;
var _context_tailwindConfig_separator;
let separator = (_context_tailwindConfig_separator = context === null || context === void 0 ? void 0 : (_context_tailwindConfig = context.tailwindConfig) === null || _context_tailwindConfig === void 0 ? void 0 : _context_tailwindConfig.separator) !== null && _context_tailwindConfig_separator !== void 0 ? _context_tailwindConfig_separator : ':';
// Split by the separator, but ignore the separator inside square brackets:
//
// E.g.: dark:lg:hover:[paint-order:markers]
// ┬ ┬ ┬ ┬
// │ │ │ ╰── We will not split here
// ╰──┴─────┴─────────────── We will split here
//
base = base !== null && base !== void 0 ? base : (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(candidate, separator).pop();
// Parse the selector into an AST
let selector = (0, _postcssselectorparser.default)().astSync(current);
// Normalize escaped classes, e.g.:
//
// The idea would be to replace the escaped `base` in the selector with the
// `format`. However, in css you can escape the same selector in a few
// different ways. This would result in different strings and therefore we
// can't replace it properly.
//
// base: bg-[rgb(255,0,0)]
// base in selector: bg-\\[rgb\\(255\\,0\\,0\\)\\]
// escaped base: bg-\\[rgb\\(255\\2c 0\\2c 0\\)\\]
//
selector.walkClasses((node)=>{
if (node.raws && node.value.includes(base)) {
node.raws.value = (0, _escapeClassName.default)((0, _unesc.default)(node.raws.value));
}
});
// Remove extraneous selectors that do not include the base candidate
selector.each((sel)=>eliminateIrrelevantSelectors(sel, base));
// If after eliminating irrelevant selectors, we end up with nothing
// Then the whole "rule" this is associated with does not need to exist
// We use `null` as a marker value for that case
if (selector.length === 0) {
return null;
}
// If there are no formats that means there were no variants added to the candidate
// so we can just return the selector as-is
let formatAst = Array.isArray(formats) ? formatVariantSelector(formats, {
context,
candidate
}) : formats;
if (formatAst === null) {
return selector.toString();
}
let simpleStart = _postcssselectorparser.default.comment({
value: '/*__simple__*/'
});
let simpleEnd = _postcssselectorparser.default.comment({
value: '/*__simple__*/'
});
// We can safely replace the escaped base now, since the `base` section is
// now in a normalized escaped value.
selector.walkClasses((node)=>{
if (node.value !== base) {
return;
}
let parent = node.parent;
let formatNodes = formatAst.nodes[0].nodes;
// Perf optimization: if the parent is a single class we can just replace it and be done
if (parent.nodes.length === 1) {
node.replaceWith(...formatNodes);
return;
}
let simpleSelector = simpleSelectorForNode(node);
parent.insertBefore(simpleSelector[0], simpleStart);
parent.insertAfter(simpleSelector[simpleSelector.length - 1], simpleEnd);
for (let child of formatNodes){
parent.insertBefore(simpleSelector[0], child.clone());
}
node.remove();
// Re-sort the simple selector to ensure it's in the correct order
simpleSelector = simpleSelectorForNode(simpleStart);
let firstNode = parent.index(simpleStart);
parent.nodes.splice(firstNode, simpleSelector.length, ...resortSelector(_postcssselectorparser.default.selector({
nodes: simpleSelector
})).nodes);
simpleStart.remove();
simpleEnd.remove();
});
// Remove unnecessary pseudo selectors that we used as placeholders
selector.walkPseudos((p)=>{
if (p.value === MERGE) {
p.replaceWith(p.nodes);
}
});
// Move pseudo elements to the end of the selector (if necessary)
selector.each((sel)=>(0, _pseudoElements.movePseudos)(sel));
return selector.toString();
}
function handleMergePseudo(selector, format) {
/** @type {{pseudo: Pseudo, value: string}[]} */ let merges = [];
// Find all :merge() pseudo-classes in `selector`
selector.walkPseudos((pseudo)=>{
if (pseudo.value === MERGE) {
merges.push({
pseudo,
value: pseudo.nodes[0].toString()
});
}
});
// Find all :merge() "attachments" in `format` and attach them to the matching selector in `selector`
format.walkPseudos((pseudo)=>{
if (pseudo.value !== MERGE) {
return;
}
let value = pseudo.nodes[0].toString();
// Does `selector` contain a :merge() pseudo-class with the same value?
let existing = merges.find((merge)=>merge.value === value);
// Nope so there's nothing to do
if (!existing) {
return;
}
// Everything after `:merge()` up to the next combinator is what is attached to the merged selector
let attachments = [];
let next = pseudo.next();
while(next && next.type !== 'combinator'){
attachments.push(next);
next = next.next();
}
let combinator = next;
existing.pseudo.parent.insertAfter(existing.pseudo, _postcssselectorparser.default.selector({
nodes: attachments.map((node)=>node.clone())
}));
pseudo.remove();
attachments.forEach((node)=>node.remove());
// What about this case:
// :merge(.group):focus > &
// :merge(.group):hover &
if (combinator && combinator.type === 'combinator') {
combinator.remove();
}
});
return [
selector,
format
];
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return getAllConfigs;
}
});
const _configfull = /*#__PURE__*/ _interop_require_default(require("../../stubs/config.full.js"));
const _featureFlags = require("../featureFlags");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function getAllConfigs(config) {
var _config_presets;
const configs = ((_config_presets = config === null || config === void 0 ? void 0 : config.presets) !== null && _config_presets !== void 0 ? _config_presets : [
_configfull.default
]).slice().reverse().flatMap((preset)=>getAllConfigs(preset instanceof Function ? preset() : preset));
const features = {
// Add experimental configs here...
respectDefaultRingColorOpacity: {
theme: {
ringColor: ({ theme })=>({
DEFAULT: '#3b82f67f',
...theme('colors')
})
}
},
disableColorOpacityUtilitiesByDefault: {
corePlugins: {
backgroundOpacity: false,
borderOpacity: false,
divideOpacity: false,
placeholderOpacity: false,
ringOpacity: false,
textOpacity: false
}
}
};
const experimentals = Object.keys(features).filter((feature)=>(0, _featureFlags.flagEnabled)(config, feature)).map((feature)=>features[feature]);
return [
config,
...experimentals,
...configs
];
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return hashConfig;
}
});
const _objecthash = /*#__PURE__*/ _interop_require_default(require("object-hash"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function hashConfig(config) {
return (0, _objecthash.default)(config, {
ignoreUnknown: true
});
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return isKeyframeRule;
}
});
function isKeyframeRule(rule) {
return rule.parent && rule.parent.type === 'atrule' && /keyframes$/.test(rule.parent.name);
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return isPlainObject;
}
});
function isPlainObject(value) {
if (Object.prototype.toString.call(value) !== '[object Object]') {
return false;
}
const prototype = Object.getPrototypeOf(value);
return prototype === null || Object.getPrototypeOf(prototype) === null;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, // Arbitrary values must contain balanced brackets (), [] and {}. Escaped
// values don't count, and brackets inside quotes also don't count.
//
// E.g.: w-[this-is]w-[weird-and-invalid]
// E.g.: w-[this-is\\]w-\\[weird-but-valid]
// E.g.: content-['this-is-also-valid]-weirdly-enough']
"default", {
enumerable: true,
get: function() {
return isSyntacticallyValidPropertyValue;
}
});
let matchingBrackets = new Map([
[
'{',
'}'
],
[
'[',
']'
],
[
'(',
')'
]
]);
let inverseMatchingBrackets = new Map(Array.from(matchingBrackets.entries()).map(([k, v])=>[
v,
k
]));
let quotes = new Set([
'"',
"'",
'`'
]);
function isSyntacticallyValidPropertyValue(value) {
let stack = [];
let inQuotes = false;
for(let i = 0; i < value.length; i++){
let char = value[i];
if (char === ':' && !inQuotes && stack.length === 0) {
return false;
}
// Non-escaped quotes allow us to "allow" anything in between
if (quotes.has(char) && value[i - 1] !== '\\') {
inQuotes = !inQuotes;
}
if (inQuotes) continue;
if (value[i - 1] === '\\') continue; // Escaped
if (matchingBrackets.has(char)) {
stack.push(char);
} else if (inverseMatchingBrackets.has(char)) {
let inverse = inverseMatchingBrackets.get(char);
// Nothing to pop from, therefore it is unbalanced
if (stack.length <= 0) {
return false;
}
// Popped value must match the inverse value, otherwise it is unbalanced
if (stack.pop() !== inverse) {
return false;
}
}
}
// If there is still something on the stack, it is also unbalanced
if (stack.length > 0) {
return false;
}
// All good, totally balanced!
return true;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
default: function() {
return _default;
},
dim: function() {
return dim;
}
});
const _picocolors = /*#__PURE__*/ _interop_require_default(require("picocolors"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let alreadyShown = new Set();
function log(type, messages, key) {
if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) return;
if (key && alreadyShown.has(key)) return;
if (key) alreadyShown.add(key);
console.warn('');
messages.forEach((message)=>console.warn(type, '-', message));
}
function dim(input) {
return _picocolors.default.dim(input);
}
const _default = {
group (key, cb) {
if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) return;
if (key && alreadyShown.has(key)) return;
if (key) alreadyShown.add(key);
console.warn('');
cb({
info (messages) {
messages.forEach((message)=>console.warn(_picocolors.default.bold(_picocolors.default.cyan('info')), '-', message));
},
warn (messages) {
messages.forEach((message)=>console.warn(_picocolors.default.bold(_picocolors.default.yellow('warn')), '-', message));
},
risk (messages) {
messages.forEach((message)=>console.warn(_picocolors.default.bold(_picocolors.default.magenta('risk')), '-', message));
}
});
},
info (key, messages) {
log(_picocolors.default.bold(_picocolors.default.cyan('info')), ...Array.isArray(key) ? [
key
] : [
messages,
key
]);
},
warn (key, messages) {
log(_picocolors.default.bold(_picocolors.default.yellow('warn')), ...Array.isArray(key) ? [
key
] : [
messages,
key
]);
},
risk (key, messages) {
log(_picocolors.default.bold(_picocolors.default.magenta('risk')), ...Array.isArray(key) ? [
key
] : [
messages,
key
]);
}
};
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
asClass: function() {
return asClass;
},
default: function() {
return nameClass;
},
formatClass: function() {
return formatClass;
}
});
const _escapeClassName = /*#__PURE__*/ _interop_require_default(require("./escapeClassName"));
const _escapeCommas = /*#__PURE__*/ _interop_require_default(require("./escapeCommas"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function asClass(name) {
return (0, _escapeCommas.default)(`.${(0, _escapeClassName.default)(name)}`);
}
function nameClass(classPrefix, key) {
return asClass(formatClass(classPrefix, key));
}
function formatClass(classPrefix, key) {
if (key === 'DEFAULT') {
return classPrefix;
}
if (key === '-' || key === '-DEFAULT') {
return `-${classPrefix}`;
}
if (key.startsWith('-')) {
return `-${classPrefix}${key}`;
}
if (key.startsWith('/')) {
return `${classPrefix}${key}`;
}
return `${classPrefix}-${key}`;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return negateValue;
}
});
function negateValue(value) {
value = `${value}`;
if (value === '0') {
return '0';
}
// Flip sign of numbers
if (/^[+-]?(\d+|\d*\.\d+)(e[+-]?\d+)?(%|\w+)?$/.test(value)) {
return value.replace(/^[+-]?/, (sign)=>sign === '-' ? '' : '-');
}
// What functions we support negating numeric values for
// var() isn't inherently a numeric function but we support it anyway
// The trigonometric functions are omitted because you'll need to use calc(…) with them _anyway_
// to produce generally useful results and that will be covered already
let numericFunctions = [
'var',
'calc',
'min',
'max',
'clamp'
];
for (const fn of numericFunctions){
if (value.includes(`${fn}(`)) {
return `calc(${value} * -1)`;
}
}
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "normalizeConfig", {
enumerable: true,
get: function() {
return normalizeConfig;
}
});
const _featureFlags = require("../featureFlags");
const _log = /*#__PURE__*/ _interop_require_wildcard(require("./log"));
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
function normalizeConfig(config) {
// Quick structure validation
/**
* type FilePath = string
* type RawFile = { raw: string, extension?: string }
* type ExtractorFn = (content: string) => Array<string>
* type TransformerFn = (content: string) => string
*
* type Content =
* | Array<FilePath | RawFile>
* | {
* files: Array<FilePath | RawFile>,
* extract?: ExtractorFn | { [extension: string]: ExtractorFn }
* transform?: TransformerFn | { [extension: string]: TransformerFn }
* }
*/ let valid = (()=>{
if (config.content === 'auto') {
return true;
}
// `config.purge` should not exist anymore
if (config.purge) {
return false;
}
// `config.content` should exist
if (!config.content) {
return false;
}
// `config.content` should be an object or an array
if (!Array.isArray(config.content) && !(typeof config.content === 'object' && config.content !== null)) {
return false;
}
// When `config.content` is an array, it should consist of FilePaths or RawFiles
if (Array.isArray(config.content)) {
return config.content.every((path)=>{
// `path` can be a string
if (typeof path === 'string') return true;
// `path` can be an object { raw: string, extension?: string }
// `raw` must be a string
if (typeof (path === null || path === void 0 ? void 0 : path.raw) !== 'string') return false;
// `extension` (if provided) should also be a string
if ((path === null || path === void 0 ? void 0 : path.extension) && typeof (path === null || path === void 0 ? void 0 : path.extension) !== 'string') {
return false;
}
return true;
});
}
// When `config.content` is an object
if (typeof config.content === 'object' && config.content !== null) {
// Only `files`, `relative`, `extract`, and `transform` can exist in `config.content`
if (Object.keys(config.content).some((key)=>![
'files',
'relative',
'extract',
'transform'
].includes(key))) {
return false;
}
// `config.content.files` should exist of FilePaths or RawFiles
if (Array.isArray(config.content.files)) {
if (!config.content.files.every((path)=>{
// `path` can be a string
if (typeof path === 'string') return true;
// `path` can be an object { raw: string, extension?: string }
// `raw` must be a string
if (typeof (path === null || path === void 0 ? void 0 : path.raw) !== 'string') return false;
// `extension` (if provided) should also be a string
if ((path === null || path === void 0 ? void 0 : path.extension) && typeof (path === null || path === void 0 ? void 0 : path.extension) !== 'string') {
return false;
}
return true;
})) {
return false;
}
// `config.content.extract` is optional, and can be a Function or a Record<String, Function>
if (typeof config.content.extract === 'object') {
for (let value of Object.values(config.content.extract)){
if (typeof value !== 'function') {
return false;
}
}
} else if (!(config.content.extract === undefined || typeof config.content.extract === 'function')) {
return false;
}
// `config.content.transform` is optional, and can be a Function or a Record<String, Function>
if (typeof config.content.transform === 'object') {
for (let value of Object.values(config.content.transform)){
if (typeof value !== 'function') {
return false;
}
}
} else if (!(config.content.transform === undefined || typeof config.content.transform === 'function')) {
return false;
}
// `config.content.relative` is optional and can be a boolean
if (typeof config.content.relative !== 'boolean' && typeof config.content.relative !== 'undefined') {
return false;
}
}
return true;
}
return false;
})();
if (!valid) {
_log.default.warn('purge-deprecation', [
'The `purge`/`content` options have changed in Tailwind CSS v3.0.',
'Update your configuration file to eliminate this warning.',
'https://tailwindcss.com/docs/upgrade-guide#configure-content-sources'
]);
}
// Normalize the `safelist`
config.safelist = (()=>{
var _purge_options;
let { content, purge, safelist } = config;
if (Array.isArray(safelist)) return safelist;
if (Array.isArray(content === null || content === void 0 ? void 0 : content.safelist)) return content.safelist;
if (Array.isArray(purge === null || purge === void 0 ? void 0 : purge.safelist)) return purge.safelist;
if (Array.isArray(purge === null || purge === void 0 ? void 0 : (_purge_options = purge.options) === null || _purge_options === void 0 ? void 0 : _purge_options.safelist)) return purge.options.safelist;
return [];
})();
// Normalize the `blocklist`
config.blocklist = (()=>{
let { blocklist } = config;
if (Array.isArray(blocklist)) {
if (blocklist.every((item)=>typeof item === 'string')) {
return blocklist;
}
_log.default.warn('blocklist-invalid', [
'The `blocklist` option must be an array of strings.',
'https://tailwindcss.com/docs/content-configuration#discarding-classes'
]);
}
return [];
})();
// Normalize prefix option
if (typeof config.prefix === 'function') {
_log.default.warn('prefix-function', [
'As of Tailwind CSS v3.0, `prefix` cannot be a function.',
'Update `prefix` in your configuration to be a string to eliminate this warning.',
'https://tailwindcss.com/docs/upgrade-guide#prefix-cannot-be-a-function'
]);
config.prefix = '';
} else {
var _config_prefix;
config.prefix = (_config_prefix = config.prefix) !== null && _config_prefix !== void 0 ? _config_prefix : '';
}
// Normalize the `content`
config.content = {
relative: (()=>{
let { content } = config;
if (content === null || content === void 0 ? void 0 : content.relative) {
return content.relative;
}
return (0, _featureFlags.flagEnabled)(config, 'relativeContentPathsByDefault');
})(),
files: (()=>{
let { content, purge } = config;
if (content === undefined && purge === undefined) return [];
if (purge) {
if (Array.isArray(purge)) return purge;
if (Array.isArray(purge === null || purge === void 0 ? void 0 : purge.content)) return purge.content;
return [];
}
if (Array.isArray(content)) return content;
if (Array.isArray(content === null || content === void 0 ? void 0 : content.content)) return content.content;
if (Array.isArray(content === null || content === void 0 ? void 0 : content.files)) return content.files;
if (content === 'auto') return [
'auto'
];
return [];
})(),
extract: (()=>{
let extract = (()=>{
var _config_purge, _config_content, _config_purge_extract, _config_purge1, _config_content_extract, _config_content1, _config_purge_options, _config_purge2, _config_content_options, _config_content2;
if ((_config_purge = config.purge) === null || _config_purge === void 0 ? void 0 : _config_purge.extract) return config.purge.extract;
if ((_config_content = config.content) === null || _config_content === void 0 ? void 0 : _config_content.extract) return config.content.extract;
if ((_config_purge1 = config.purge) === null || _config_purge1 === void 0 ? void 0 : (_config_purge_extract = _config_purge1.extract) === null || _config_purge_extract === void 0 ? void 0 : _config_purge_extract.DEFAULT) return config.purge.extract.DEFAULT;
if ((_config_content1 = config.content) === null || _config_content1 === void 0 ? void 0 : (_config_content_extract = _config_content1.extract) === null || _config_content_extract === void 0 ? void 0 : _config_content_extract.DEFAULT) return config.content.extract.DEFAULT;
if ((_config_purge2 = config.purge) === null || _config_purge2 === void 0 ? void 0 : (_config_purge_options = _config_purge2.options) === null || _config_purge_options === void 0 ? void 0 : _config_purge_options.extractors) return config.purge.options.extractors;
if ((_config_content2 = config.content) === null || _config_content2 === void 0 ? void 0 : (_config_content_options = _config_content2.options) === null || _config_content_options === void 0 ? void 0 : _config_content_options.extractors) return config.content.options.extractors;
return {};
})();
let extractors = {};
let defaultExtractor = (()=>{
var _config_purge_options, _config_purge, _config_content_options, _config_content;
if ((_config_purge = config.purge) === null || _config_purge === void 0 ? void 0 : (_config_purge_options = _config_purge.options) === null || _config_purge_options === void 0 ? void 0 : _config_purge_options.defaultExtractor) {
return config.purge.options.defaultExtractor;
}
if ((_config_content = config.content) === null || _config_content === void 0 ? void 0 : (_config_content_options = _config_content.options) === null || _config_content_options === void 0 ? void 0 : _config_content_options.defaultExtractor) {
return config.content.options.defaultExtractor;
}
return undefined;
})();
if (defaultExtractor !== undefined) {
extractors.DEFAULT = defaultExtractor;
}
// Functions
if (typeof extract === 'function') {
extractors.DEFAULT = extract;
} else if (Array.isArray(extract)) {
for (let { extensions, extractor } of extract !== null && extract !== void 0 ? extract : []){
for (let extension of extensions){
extractors[extension] = extractor;
}
}
} else if (typeof extract === 'object' && extract !== null) {
Object.assign(extractors, extract);
}
return extractors;
})(),
transform: (()=>{
let transform = (()=>{
var _config_purge, _config_content, _config_purge_transform, _config_purge1, _config_content_transform, _config_content1;
if ((_config_purge = config.purge) === null || _config_purge === void 0 ? void 0 : _config_purge.transform) return config.purge.transform;
if ((_config_content = config.content) === null || _config_content === void 0 ? void 0 : _config_content.transform) return config.content.transform;
if ((_config_purge1 = config.purge) === null || _config_purge1 === void 0 ? void 0 : (_config_purge_transform = _config_purge1.transform) === null || _config_purge_transform === void 0 ? void 0 : _config_purge_transform.DEFAULT) return config.purge.transform.DEFAULT;
if ((_config_content1 = config.content) === null || _config_content1 === void 0 ? void 0 : (_config_content_transform = _config_content1.transform) === null || _config_content_transform === void 0 ? void 0 : _config_content_transform.DEFAULT) return config.content.transform.DEFAULT;
return {};
})();
let transformers = {};
if (typeof transform === 'function') {
transformers.DEFAULT = transform;
}
if (typeof transform === 'object' && transform !== null) {
Object.assign(transformers, transform);
}
return transformers;
})()
};
// Force disable the `oxideParser` feature flag when using unsupported features.
// TODO: Remove once we have prefix or separator support in the oxide parser.
if (config.prefix !== '' || config.separator !== ':') {
if (config.experimental === 'all') {
config.experimental = {};
for (let key of _featureFlags.featureFlags.experimental){
config.experimental[key] = true;
}
} else {
var _config_experimental;
config.experimental = (_config_experimental = config.experimental) !== null && _config_experimental !== void 0 ? _config_experimental : {};
}
config.experimental.oxideParser = false;
}
// Validate globs to prevent bogus globs.
// E.g.: `./src/*.{html}` is invalid, the `{html}` should just be `html`
if (config.content.files !== 'auto') {
for (let file of config.content.files){
if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) {
_log.default.warn('invalid-glob-braces', [
`The glob pattern ${(0, _log.dim)(file)} in your Tailwind CSS configuration is invalid.`,
`Update it to ${(0, _log.dim)(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`
]);
break;
}
}
}
return config;
}
/**
* @typedef {object} ScreenValue
* @property {number|undefined} min
* @property {number|undefined} max
* @property {string|undefined} raw
*/ /**
* @typedef {object} Screen
* @property {string} name
* @property {boolean} not
* @property {ScreenValue[]} values
*/ /**
* A function that normalizes the various forms that the screens object can be
* provided in.
*
* Input(s):
* - ['100px', '200px'] // Raw strings
* - { sm: '100px', md: '200px' } // Object with string values
* - { sm: { min: '100px' }, md: { max: '100px' } } // Object with object values
* - { sm: [{ min: '100px' }, { max: '200px' }] } // Object with object array (multiple values)
*
* Output(s):
* - [{ name: 'sm', values: [{ min: '100px', max: '200px' }] }] // List of objects, that contains multiple values
*
* @returns {Screen[]}
*/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
compareScreens: function() {
return compareScreens;
},
isScreenSortable: function() {
return isScreenSortable;
},
normalizeScreens: function() {
return normalizeScreens;
},
toScreen: function() {
return toScreen;
}
});
function normalizeScreens(screens, root = true) {
if (Array.isArray(screens)) {
return screens.map((screen)=>{
if (root && Array.isArray(screen)) {
throw new Error('The tuple syntax is not supported for `screens`.');
}
if (typeof screen === 'string') {
return {
name: screen.toString(),
not: false,
values: [
{
min: screen,
max: undefined
}
]
};
}
let [name, options] = screen;
name = name.toString();
if (typeof options === 'string') {
return {
name,
not: false,
values: [
{
min: options,
max: undefined
}
]
};
}
if (Array.isArray(options)) {
return {
name,
not: false,
values: options.map((option)=>resolveValue(option))
};
}
return {
name,
not: false,
values: [
resolveValue(options)
]
};
});
}
return normalizeScreens(Object.entries(screens !== null && screens !== void 0 ? screens : {}), false);
}
function isScreenSortable(screen) {
if (screen.values.length !== 1) {
return {
result: false,
reason: 'multiple-values'
};
} else if (screen.values[0].raw !== undefined) {
return {
result: false,
reason: 'raw-values'
};
} else if (screen.values[0].min !== undefined && screen.values[0].max !== undefined) {
return {
result: false,
reason: 'min-and-max'
};
}
return {
result: true,
reason: null
};
}
function compareScreens(type, a, z) {
let aScreen = toScreen(a, type);
let zScreen = toScreen(z, type);
let aSorting = isScreenSortable(aScreen);
let bSorting = isScreenSortable(zScreen);
// These cases should never happen and indicate a bug in Tailwind CSS itself
if (aSorting.reason === 'multiple-values' || bSorting.reason === 'multiple-values') {
throw new Error('Attempted to sort a screen with multiple values. This should never happen. Please open a bug report.');
} else if (aSorting.reason === 'raw-values' || bSorting.reason === 'raw-values') {
throw new Error('Attempted to sort a screen with raw values. This should never happen. Please open a bug report.');
} else if (aSorting.reason === 'min-and-max' || bSorting.reason === 'min-and-max') {
throw new Error('Attempted to sort a screen with both min and max values. This should never happen. Please open a bug report.');
}
// Let the sorting begin
let { min: aMin, max: aMax } = aScreen.values[0];
let { min: zMin, max: zMax } = zScreen.values[0];
// Negating screens flip their behavior. Basically `not min-width` is `max-width`
if (a.not) [aMin, aMax] = [
aMax,
aMin
];
if (z.not) [zMin, zMax] = [
zMax,
zMin
];
aMin = aMin === undefined ? aMin : parseFloat(aMin);
aMax = aMax === undefined ? aMax : parseFloat(aMax);
zMin = zMin === undefined ? zMin : parseFloat(zMin);
zMax = zMax === undefined ? zMax : parseFloat(zMax);
let [aValue, zValue] = type === 'min' ? [
aMin,
zMin
] : [
zMax,
aMax
];
return aValue - zValue;
}
function toScreen(value, type) {
if (typeof value === 'object') {
return value;
}
return {
name: 'arbitrary-screen',
values: [
{
[type]: value
}
]
};
}
function resolveValue({ 'min-width': _minWidth, min = _minWidth, max, raw } = {}) {
return {
min,
max,
raw
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return parseAnimationValue;
}
});
const DIRECTIONS = new Set([
'normal',
'reverse',
'alternate',
'alternate-reverse'
]);
const PLAY_STATES = new Set([
'running',
'paused'
]);
const FILL_MODES = new Set([
'none',
'forwards',
'backwards',
'both'
]);
const ITERATION_COUNTS = new Set([
'infinite'
]);
const TIMINGS = new Set([
'linear',
'ease',
'ease-in',
'ease-out',
'ease-in-out',
'step-start',
'step-end'
]);
const TIMING_FNS = [
'cubic-bezier',
'steps'
];
const COMMA = /\,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
;
const SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.
;
const TIME = /^(-?[\d.]+m?s)$/;
const DIGIT = /^(\d+)$/;
function parseAnimationValue(input) {
let animations = input.split(COMMA);
return animations.map((animation)=>{
let value = animation.trim();
let result = {
value
};
let parts = value.split(SPACE);
let seen = new Set();
for (let part of parts){
if (!seen.has('DIRECTIONS') && DIRECTIONS.has(part)) {
result.direction = part;
seen.add('DIRECTIONS');
} else if (!seen.has('PLAY_STATES') && PLAY_STATES.has(part)) {
result.playState = part;
seen.add('PLAY_STATES');
} else if (!seen.has('FILL_MODES') && FILL_MODES.has(part)) {
result.fillMode = part;
seen.add('FILL_MODES');
} else if (!seen.has('ITERATION_COUNTS') && (ITERATION_COUNTS.has(part) || DIGIT.test(part))) {
result.iterationCount = part;
seen.add('ITERATION_COUNTS');
} else if (!seen.has('TIMING_FUNCTION') && TIMINGS.has(part)) {
result.timingFunction = part;
seen.add('TIMING_FUNCTION');
} else if (!seen.has('TIMING_FUNCTION') && TIMING_FNS.some((f)=>part.startsWith(`${f}(`))) {
result.timingFunction = part;
seen.add('TIMING_FUNCTION');
} else if (!seen.has('DURATION') && TIME.test(part)) {
result.duration = part;
seen.add('DURATION');
} else if (!seen.has('DELAY') && TIME.test(part)) {
result.delay = part;
seen.add('DELAY');
} else if (!seen.has('NAME')) {
result.name = part;
seen.add('NAME');
} else {
if (!result.unknown) result.unknown = [];
result.unknown.push(part);
}
}
return result;
});
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
formatBoxShadowValue: function() {
return formatBoxShadowValue;
},
parseBoxShadowValue: function() {
return parseBoxShadowValue;
}
});
const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly");
let KEYWORDS = new Set([
'inset',
'inherit',
'initial',
'revert',
'unset'
]);
let SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.
;
let LENGTH = /^-?(\d+|\.\d+)(.*?)$/g;
function parseBoxShadowValue(input) {
let shadows = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(input, ',');
return shadows.map((shadow)=>{
let value = shadow.trim();
let result = {
raw: value
};
let parts = value.split(SPACE);
let seen = new Set();
for (let part of parts){
// Reset index, since the regex is stateful.
LENGTH.lastIndex = 0;
// Keyword
if (!seen.has('KEYWORD') && KEYWORDS.has(part)) {
result.keyword = part;
seen.add('KEYWORD');
} else if (LENGTH.test(part)) {
if (!seen.has('X')) {
result.x = part;
seen.add('X');
} else if (!seen.has('Y')) {
result.y = part;
seen.add('Y');
} else if (!seen.has('BLUR')) {
result.blur = part;
seen.add('BLUR');
} else if (!seen.has('SPREAD')) {
result.spread = part;
seen.add('SPREAD');
}
} else {
if (!result.color) {
result.color = part;
} else {
if (!result.unknown) result.unknown = [];
result.unknown.push(part);
}
}
}
// Check if valid
result.valid = result.x !== undefined && result.y !== undefined;
return result;
});
}
function formatBoxShadowValue(shadows) {
return shadows.map((shadow)=>{
if (!shadow.valid) {
return shadow.raw;
}
return [
shadow.keyword,
shadow.x,
shadow.y,
shadow.blur,
shadow.spread,
shadow.color
].filter(Boolean).join(' ');
}).join(', ');
}
// @ts-check
/**
* @typedef {{type: 'dependency', file: string} | {type: 'dir-dependency', dir: string, glob: string}} Dependency
*/ /**
*
* @param {import('../lib/content.js').ContentPath} contentPath
* @returns {Dependency[]}
*/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return parseDependency;
}
});
function parseDependency(contentPath) {
if (contentPath.ignore) {
return [];
}
if (!contentPath.glob) {
return [
{
type: 'dependency',
file: contentPath.base
}
];
}
if (process.env.ROLLUP_WATCH === 'true') {
// rollup-plugin-postcss does not support dir-dependency messages
// but directories can be watched in the same way as files
return [
{
type: 'dependency',
file: contentPath.base
}
];
}
return [
{
type: 'dir-dependency',
dir: contentPath.base,
glob: contentPath.glob
}
];
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "parseGlob", {
enumerable: true,
get: function() {
return parseGlob;
}
});
const _globparent = /*#__PURE__*/ _interop_require_default(require("glob-parent"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function parseGlob(pattern) {
let glob = pattern;
let base = (0, _globparent.default)(pattern);
if (base !== '.') {
glob = pattern.substr(base.length);
if (glob.charAt(0) === '/') {
glob = glob.substr(1);
}
}
if (glob.substr(0, 2) === './') {
glob = glob.substr(2);
}
if (glob.charAt(0) === '/') {
glob = glob.substr(1);
}
return {
base,
glob
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return parseObjectStyles;
}
});
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _postcssnested = /*#__PURE__*/ _interop_require_default(require("postcss-nested"));
const _postcssjs = /*#__PURE__*/ _interop_require_default(require("postcss-js"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function parseObjectStyles(styles) {
if (!Array.isArray(styles)) {
return parseObjectStyles([
styles
]);
}
return styles.flatMap((style)=>{
return (0, _postcss.default)([
(0, _postcssnested.default)({
bubble: [
'screen'
]
})
]).process(style, {
parser: _postcssjs.default
}).root.nodes;
});
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
asColor: function() {
return asColor;
},
asLookupValue: function() {
return asLookupValue;
},
asValue: function() {
return asValue;
},
coerceValue: function() {
return coerceValue;
},
getMatchingTypes: function() {
return getMatchingTypes;
},
parseColorFormat: function() {
return parseColorFormat;
},
typeMap: function() {
return typeMap;
},
updateAllClasses: function() {
return updateAllClasses;
}
});
const _escapeCommas = /*#__PURE__*/ _interop_require_default(require("./escapeCommas"));
const _withAlphaVariable = require("./withAlphaVariable");
const _dataTypes = require("./dataTypes");
const _negateValue = /*#__PURE__*/ _interop_require_default(require("./negateValue"));
const _validateFormalSyntax = require("./validateFormalSyntax");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function updateAllClasses(selectors, updateClass) {
selectors.walkClasses((sel)=>{
sel.value = updateClass(sel.value);
if (sel.raws && sel.raws.value) {
sel.raws.value = (0, _escapeCommas.default)(sel.raws.value);
}
});
}
function resolveArbitraryValue(modifier, validate) {
if (!isArbitraryValue(modifier)) {
return undefined;
}
let value = modifier.slice(1, -1);
if (!validate(value)) {
return undefined;
}
return (0, _dataTypes.normalize)(value);
}
function asNegativeValue(modifier, lookup = {}, validate) {
let positiveValue = lookup[modifier];
if (positiveValue !== undefined) {
return (0, _negateValue.default)(positiveValue);
}
if (isArbitraryValue(modifier)) {
let resolved = resolveArbitraryValue(modifier, validate);
if (resolved === undefined) {
return undefined;
}
return (0, _negateValue.default)(resolved);
}
}
function asValue(modifier, options = {}, { validate = ()=>true } = {}) {
var _options_values;
let value = (_options_values = options.values) === null || _options_values === void 0 ? void 0 : _options_values[modifier];
if (value !== undefined) {
return value;
}
if (options.supportsNegativeValues && modifier.startsWith('-')) {
return asNegativeValue(modifier.slice(1), options.values, validate);
}
return resolveArbitraryValue(modifier, validate);
}
function isArbitraryValue(input) {
return input.startsWith('[') && input.endsWith(']');
}
function splitUtilityModifier(modifier) {
let slashIdx = modifier.lastIndexOf('/');
// If the `/` is inside an arbitrary, we want to find the previous one if any
// This logic probably isn't perfect but it should work for most cases
let arbitraryStartIdx = modifier.lastIndexOf('[', slashIdx);
let arbitraryEndIdx = modifier.indexOf(']', slashIdx);
let isNextToArbitrary = modifier[slashIdx - 1] === ']' || modifier[slashIdx + 1] === '[';
// Backtrack to the previous `/` if the one we found was inside an arbitrary
if (!isNextToArbitrary) {
if (arbitraryStartIdx !== -1 && arbitraryEndIdx !== -1) {
if (arbitraryStartIdx < slashIdx && slashIdx < arbitraryEndIdx) {
slashIdx = modifier.lastIndexOf('/', arbitraryStartIdx);
}
}
}
if (slashIdx === -1 || slashIdx === modifier.length - 1) {
return [
modifier,
undefined
];
}
let arbitrary = isArbitraryValue(modifier);
// The modifier could be of the form `[foo]/[bar]`
// We want to handle this case properly
// without affecting `[foo/bar]`
if (arbitrary && !modifier.includes(']/[')) {
return [
modifier,
undefined
];
}
return [
modifier.slice(0, slashIdx),
modifier.slice(slashIdx + 1)
];
}
function parseColorFormat(value) {
if (typeof value === 'string' && value.includes('<alpha-value>')) {
let oldValue = value;
return ({ opacityValue = 1 })=>oldValue.replace('<alpha-value>', opacityValue);
}
return value;
}
function unwrapArbitraryModifier(modifier) {
return (0, _dataTypes.normalize)(modifier.slice(1, -1));
}
function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
var _options_values;
if (((_options_values = options.values) === null || _options_values === void 0 ? void 0 : _options_values[modifier]) !== undefined) {
var _options_values1;
return parseColorFormat((_options_values1 = options.values) === null || _options_values1 === void 0 ? void 0 : _options_values1[modifier]);
}
// TODO: Hoist this up to getMatchingTypes or something
// We do this here because we need the alpha value (if any)
let [color, alpha] = splitUtilityModifier(modifier);
if (alpha !== undefined) {
var _options_values2, _tailwindConfig_theme_opacity, _tailwindConfig_theme;
var _options_values_color;
let normalizedColor = (_options_values_color = (_options_values2 = options.values) === null || _options_values2 === void 0 ? void 0 : _options_values2[color]) !== null && _options_values_color !== void 0 ? _options_values_color : isArbitraryValue(color) ? color.slice(1, -1) : undefined;
if (normalizedColor === undefined) {
return undefined;
}
normalizedColor = parseColorFormat(normalizedColor);
if (isArbitraryValue(alpha)) {
return (0, _withAlphaVariable.withAlphaValue)(normalizedColor, unwrapArbitraryModifier(alpha));
}
if (((_tailwindConfig_theme = tailwindConfig.theme) === null || _tailwindConfig_theme === void 0 ? void 0 : (_tailwindConfig_theme_opacity = _tailwindConfig_theme.opacity) === null || _tailwindConfig_theme_opacity === void 0 ? void 0 : _tailwindConfig_theme_opacity[alpha]) === undefined) {
return undefined;
}
return (0, _withAlphaVariable.withAlphaValue)(normalizedColor, tailwindConfig.theme.opacity[alpha]);
}
return asValue(modifier, options, {
validate: _dataTypes.color
});
}
function asLookupValue(modifier, options = {}) {
var _options_values;
return (_options_values = options.values) === null || _options_values === void 0 ? void 0 : _options_values[modifier];
}
function guess(validate) {
return (modifier, options)=>{
return asValue(modifier, options, {
validate
});
};
}
let typeMap = {
any: asValue,
color: asColor,
url: guess(_dataTypes.url),
image: guess(_dataTypes.image),
length: guess(_dataTypes.length),
percentage: guess(_dataTypes.percentage),
position: guess(_dataTypes.position),
lookup: asLookupValue,
'generic-name': guess(_dataTypes.genericName),
'family-name': guess(_dataTypes.familyName),
number: guess(_dataTypes.number),
'line-width': guess(_dataTypes.lineWidth),
'absolute-size': guess(_dataTypes.absoluteSize),
'relative-size': guess(_dataTypes.relativeSize),
shadow: guess(_dataTypes.shadow),
size: guess(_validateFormalSyntax.backgroundSize)
};
let supportedTypes = Object.keys(typeMap);
function splitAtFirst(input, delim) {
let idx = input.indexOf(delim);
if (idx === -1) return [
undefined,
input
];
return [
input.slice(0, idx),
input.slice(idx + 1)
];
}
function coerceValue(types, modifier, options, tailwindConfig) {
if (options.values && modifier in options.values) {
for (let { type } of types !== null && types !== void 0 ? types : []){
let result = typeMap[type](modifier, options, {
tailwindConfig
});
if (result === undefined) {
continue;
}
return [
result,
type,
null
];
}
}
if (isArbitraryValue(modifier)) {
let arbitraryValue = modifier.slice(1, -1);
let [explicitType, value] = splitAtFirst(arbitraryValue, ':');
// It could be that this resolves to `url(https` which is not a valid
// identifier. We currently only support "simple" words with dashes or
// underscores. E.g.: family-name
if (!/^[\w-_]+$/g.test(explicitType)) {
value = arbitraryValue;
} else if (explicitType !== undefined && !supportedTypes.includes(explicitType)) {
return [];
}
if (value.length > 0 && supportedTypes.includes(explicitType)) {
return [
asValue(`[${value}]`, options),
explicitType,
null
];
}
}
let matches = getMatchingTypes(types, modifier, options, tailwindConfig);
// Find first matching type
for (let match of matches){
return match;
}
return [];
}
function* getMatchingTypes(types, rawModifier, options, tailwindConfig) {
let [modifier, utilityModifier] = splitUtilityModifier(rawModifier);
let canUseUtilityModifier = options.modifiers != null && (options.modifiers === 'any' || typeof options.modifiers === 'object' && (utilityModifier && isArbitraryValue(utilityModifier) || utilityModifier in options.modifiers));
if (!canUseUtilityModifier) {
modifier = rawModifier;
utilityModifier = undefined;
}
if (utilityModifier !== undefined && modifier === '') {
modifier = 'DEFAULT';
}
// Check the full value first
// TODO: Move to asValue… somehow
if (utilityModifier !== undefined) {
if (typeof options.modifiers === 'object') {
var _options_modifiers;
var _options_modifiers_utilityModifier;
let configValue = (_options_modifiers_utilityModifier = (_options_modifiers = options.modifiers) === null || _options_modifiers === void 0 ? void 0 : _options_modifiers[utilityModifier]) !== null && _options_modifiers_utilityModifier !== void 0 ? _options_modifiers_utilityModifier : null;
if (configValue !== null) {
utilityModifier = configValue;
} else if (isArbitraryValue(utilityModifier)) {
utilityModifier = unwrapArbitraryModifier(utilityModifier);
}
}
}
for (let { type } of types !== null && types !== void 0 ? types : []){
let result = typeMap[type](modifier, options, {
tailwindConfig
});
if (result === undefined) {
continue;
}
yield [
result,
type,
utilityModifier !== null && utilityModifier !== void 0 ? utilityModifier : null
];
}
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, /**
* @template {string | import('postcss-selector-parser').Root} T
*
* Prefix all classes in the selector with the given prefix
*
* It can take either a string or a selector AST and will return the same type
*
* @param {string} prefix
* @param {T} selector
* @param {boolean} prependNegative
* @returns {T}
*/ "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _default(prefix, selector, prependNegative = false) {
if (prefix === '') {
return selector;
}
/** @type {import('postcss-selector-parser').Root} */ let ast = typeof selector === 'string' ? (0, _postcssselectorparser.default)().astSync(selector) : selector;
ast.walkClasses((classSelector)=>{
let baseClass = classSelector.value;
let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith('-');
classSelector.value = shouldPlaceNegativeBeforePrefix ? `-${prefix}${baseClass.slice(1)}` : `${prefix}${baseClass}`;
});
return typeof selector === 'string' ? ast.toString() : ast;
}
/** @typedef {import('postcss-selector-parser').Root} Root */ /** @typedef {import('postcss-selector-parser').Selector} Selector */ /** @typedef {import('postcss-selector-parser').Pseudo} Pseudo */ /** @typedef {import('postcss-selector-parser').Node} Node */ // There are some pseudo-elements that may or may not be:
// **Actionable**
// Zero or more user-action pseudo-classes may be attached to the pseudo-element itself
// structural-pseudo-classes are NOT allowed but we don't make
// The spec is not clear on whether this is allowed or not — but in practice it is.
// **Terminal**
// It MUST be placed at the end of a selector
//
// This is the required in the spec. However, some pseudo elements are not "terminal" because
// they represent a "boundary piercing" that is compiled out by a build step.
// **Jumpable**
// Any terminal element may "jump" over combinators when moving to the end of the selector
//
// This is a backwards-compat quirk of pseudo element variants from earlier versions of Tailwind CSS.
/** @typedef {'terminal' | 'actionable' | 'jumpable'} PseudoProperty */ /** @type {Record<string, PseudoProperty[]>} */ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "movePseudos", {
enumerable: true,
get: function() {
return movePseudos;
}
});
let elementProperties = {
// Pseudo elements from the spec
'::after': [
'terminal',
'jumpable'
],
'::backdrop': [
'terminal',
'jumpable'
],
'::before': [
'terminal',
'jumpable'
],
'::cue': [
'terminal'
],
'::cue-region': [
'terminal'
],
'::first-letter': [
'terminal',
'jumpable'
],
'::first-line': [
'terminal',
'jumpable'
],
'::grammar-error': [
'terminal'
],
'::marker': [
'terminal',
'jumpable'
],
'::part': [
'terminal',
'actionable'
],
'::placeholder': [
'terminal',
'jumpable'
],
'::selection': [
'terminal',
'jumpable'
],
'::slotted': [
'terminal'
],
'::spelling-error': [
'terminal'
],
'::target-text': [
'terminal'
],
// Pseudo elements from the spec with special rules
'::file-selector-button': [
'terminal',
'actionable'
],
// Library-specific pseudo elements used by component libraries
// These are Shadow DOM-like
'::deep': [
'actionable'
],
'::v-deep': [
'actionable'
],
'::ng-deep': [
'actionable'
],
// Note: As a rule, double colons (::) should be used instead of a single colon
// (:). This distinguishes pseudo-classes from pseudo-elements. However, since
// this distinction was not present in older versions of the W3C spec, most
// browsers support both syntaxes for the original pseudo-elements.
':after': [
'terminal',
'jumpable'
],
':before': [
'terminal',
'jumpable'
],
':first-letter': [
'terminal',
'jumpable'
],
':first-line': [
'terminal',
'jumpable'
],
// The default value is used when the pseudo-element is not recognized
// Because it's not recognized, we don't know if it's terminal or not
// So we assume it can be moved AND can have user-action pseudo classes attached to it
__default__: [
'terminal',
'actionable'
]
};
function movePseudos(sel) {
let [pseudos] = movablePseudos(sel);
// Remove all pseudo elements from their respective selectors
pseudos.forEach(([sel, pseudo])=>sel.removeChild(pseudo));
// Re-add them to the end of the selector in the correct order.
// This moves terminal pseudo elements to the end of the
// selector otherwise the selector will not be valid.
//
// Examples:
// - `before:hover:text-center` would result in `.before\:hover\:text-center:hover::before`
// - `hover:before:text-center` would result in `.hover\:before\:text-center:hover::before`
//
// The selector `::before:hover` does not work but we
// can make it work for you by flipping the order.
sel.nodes.push(...pseudos.map(([, pseudo])=>pseudo));
return sel;
}
/** @typedef {[sel: Selector, pseudo: Pseudo, attachedTo: Pseudo | null]} MovablePseudo */ /** @typedef {[pseudos: MovablePseudo[], lastSeenElement: Pseudo | null]} MovablePseudosResult */ /**
* @param {Selector} sel
* @returns {MovablePseudosResult}
*/ function movablePseudos(sel) {
/** @type {MovablePseudo[]} */ let buffer = [];
/** @type {Pseudo | null} */ let lastSeenElement = null;
for (let node of sel.nodes){
if (node.type === 'combinator') {
buffer = buffer.filter(([, node])=>propertiesForPseudo(node).includes('jumpable'));
lastSeenElement = null;
} else if (node.type === 'pseudo') {
if (isMovablePseudoElement(node)) {
lastSeenElement = node;
buffer.push([
sel,
node,
null
]);
} else if (lastSeenElement && isAttachablePseudoClass(node, lastSeenElement)) {
buffer.push([
sel,
node,
lastSeenElement
]);
} else {
lastSeenElement = null;
}
var _node_nodes;
for (let sub of (_node_nodes = node.nodes) !== null && _node_nodes !== void 0 ? _node_nodes : []){
let [movable, lastSeenElementInSub] = movablePseudos(sub);
lastSeenElement = lastSeenElementInSub || lastSeenElement;
buffer.push(...movable);
}
}
}
return [
buffer,
lastSeenElement
];
}
/**
* @param {Node} node
* @returns {boolean}
*/ function isPseudoElement(node) {
return node.value.startsWith('::') || elementProperties[node.value] !== undefined;
}
/**
* @param {Node} node
* @returns {boolean}
*/ function isMovablePseudoElement(node) {
return isPseudoElement(node) && propertiesForPseudo(node).includes('terminal');
}
/**
* @param {Node} node
* @param {Pseudo} pseudo
* @returns {boolean}
*/ function isAttachablePseudoClass(node, pseudo) {
if (node.type !== 'pseudo') return false;
if (isPseudoElement(node)) return false;
return propertiesForPseudo(pseudo).includes('actionable');
}
/**
* @param {Pseudo} pseudo
* @returns {PseudoProperty[]}
*/ function propertiesForPseudo(pseudo) {
var _elementProperties_pseudo_value;
return (_elementProperties_pseudo_value = elementProperties[pseudo.value]) !== null && _elementProperties_pseudo_value !== void 0 ? _elementProperties_pseudo_value : elementProperties.__default__;
}
/**
* This function removes any uses of CSS variables used as an alpha channel
*
* This is required for selectors like `:visited` which do not allow
* changes in opacity or external control using CSS variables.
*
* @param {import('postcss').Container} container
* @param {string[]} toRemove
*/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "removeAlphaVariables", {
enumerable: true,
get: function() {
return removeAlphaVariables;
}
});
function removeAlphaVariables(container, toRemove) {
container.walkDecls((decl)=>{
if (toRemove.includes(decl.prop)) {
decl.remove();
return;
}
for (let varName of toRemove){
if (decl.value.includes(`/ var(${varName})`)) {
decl.value = decl.value.replace(`/ var(${varName})`, '');
}
}
});
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return resolveConfig;
}
});
const _negateValue = /*#__PURE__*/ _interop_require_default(require("./negateValue"));
const _corePluginList = /*#__PURE__*/ _interop_require_default(require("../corePluginList"));
const _configurePlugins = /*#__PURE__*/ _interop_require_default(require("./configurePlugins"));
const _colors = /*#__PURE__*/ _interop_require_default(require("../public/colors"));
const _defaults = require("./defaults");
const _toPath = require("./toPath");
const _normalizeConfig = require("./normalizeConfig");
const _isPlainObject = /*#__PURE__*/ _interop_require_default(require("./isPlainObject"));
const _cloneDeep = require("./cloneDeep");
const _pluginUtils = require("./pluginUtils");
const _withAlphaVariable = require("./withAlphaVariable");
const _toColorValue = /*#__PURE__*/ _interop_require_default(require("./toColorValue"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function isFunction(input) {
return typeof input === 'function';
}
function mergeWith(target, ...sources) {
let customizer = sources.pop();
for (let source of sources){
for(let k in source){
let merged = customizer(target[k], source[k]);
if (merged === undefined) {
if ((0, _isPlainObject.default)(target[k]) && (0, _isPlainObject.default)(source[k])) {
target[k] = mergeWith({}, target[k], source[k], customizer);
} else {
target[k] = source[k];
}
} else {
target[k] = merged;
}
}
}
return target;
}
const configUtils = {
colors: _colors.default,
negative (scale) {
// TODO: Log that this function isn't really needed anymore?
return Object.keys(scale).filter((key)=>scale[key] !== '0').reduce((negativeScale, key)=>{
let negativeValue = (0, _negateValue.default)(scale[key]);
if (negativeValue !== undefined) {
negativeScale[`-${key}`] = negativeValue;
}
return negativeScale;
}, {});
},
breakpoints (screens) {
return Object.keys(screens).filter((key)=>typeof screens[key] === 'string').reduce((breakpoints, key)=>({
...breakpoints,
[`screen-${key}`]: screens[key]
}), {});
}
};
function value(valueToResolve, ...args) {
return isFunction(valueToResolve) ? valueToResolve(...args) : valueToResolve;
}
function collectExtends(items) {
return items.reduce((merged, { extend })=>{
return mergeWith(merged, extend, (mergedValue, extendValue)=>{
if (mergedValue === undefined) {
return [
extendValue
];
}
if (Array.isArray(mergedValue)) {
return [
extendValue,
...mergedValue
];
}
return [
extendValue,
mergedValue
];
});
}, {});
}
function mergeThemes(themes) {
return {
...themes.reduce((merged, theme)=>(0, _defaults.defaults)(merged, theme), {}),
// In order to resolve n config objects, we combine all of their `extend` properties
// into arrays instead of objects so they aren't overridden.
extend: collectExtends(themes)
};
}
function mergeExtensionCustomizer(merged, value) {
// When we have an array of objects, we do want to merge it
if (Array.isArray(merged) && (0, _isPlainObject.default)(merged[0])) {
return merged.concat(value);
}
// When the incoming value is an array, and the existing config is an object, prepend the existing object
if (Array.isArray(value) && (0, _isPlainObject.default)(value[0]) && (0, _isPlainObject.default)(merged)) {
return [
merged,
...value
];
}
// Override arrays (for example for font-families, box-shadows, ...)
if (Array.isArray(value)) {
return value;
}
// Execute default behaviour
return undefined;
}
function mergeExtensions({ extend, ...theme }) {
return mergeWith(theme, extend, (themeValue, extensions)=>{
// The `extend` property is an array, so we need to check if it contains any functions
if (!isFunction(themeValue) && !extensions.some(isFunction)) {
return mergeWith({}, themeValue, ...extensions, mergeExtensionCustomizer);
}
return (resolveThemePath, utils)=>mergeWith({}, ...[
themeValue,
...extensions
].map((e)=>value(e, resolveThemePath, utils)), mergeExtensionCustomizer);
});
}
/**
*
* @param {string} key
* @return {Iterable<string[] & {alpha: string | undefined}>}
*/ function* toPaths(key) {
let path = (0, _toPath.toPath)(key);
if (path.length === 0) {
return;
}
yield path;
if (Array.isArray(key)) {
return;
}
let pattern = /^(.*?)\s*\/\s*([^/]+)$/;
let matches = key.match(pattern);
if (matches !== null) {
let [, prefix, alpha] = matches;
let newPath = (0, _toPath.toPath)(prefix);
newPath.alpha = alpha;
yield newPath;
}
}
function resolveFunctionKeys(object) {
// theme('colors.red.500 / 0.5') -> ['colors', 'red', '500 / 0', '5]
const resolvePath = (key, defaultValue)=>{
for (const path of toPaths(key)){
let index = 0;
let val = object;
while(val !== undefined && val !== null && index < path.length){
val = val[path[index++]];
let shouldResolveAsFn = isFunction(val) && (path.alpha === undefined || index <= path.length - 1);
val = shouldResolveAsFn ? val(resolvePath, configUtils) : val;
}
if (val !== undefined) {
if (path.alpha !== undefined) {
let normalized = (0, _pluginUtils.parseColorFormat)(val);
return (0, _withAlphaVariable.withAlphaValue)(normalized, path.alpha, (0, _toColorValue.default)(normalized));
}
if ((0, _isPlainObject.default)(val)) {
return (0, _cloneDeep.cloneDeep)(val);
}
return val;
}
}
return defaultValue;
};
Object.assign(resolvePath, {
theme: resolvePath,
...configUtils
});
return Object.keys(object).reduce((resolved, key)=>{
resolved[key] = isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key];
return resolved;
}, {});
}
function resolvePlugins(configs) {
let pluginGroups = [];
let allConfigs = [];
for (let config of configs){
allConfigs.push(config);
let plugins = [];
var _config_plugins;
for (let plugin of (_config_plugins = config === null || config === void 0 ? void 0 : config.plugins) !== null && _config_plugins !== void 0 ? _config_plugins : []){
// TODO: If we want to support ESM plugins then a handful of things will have to become async
if (typeof plugin === 'string') {
// If the plugin is specified as a string then it's just the package name
plugin = require(plugin);
var _plugin_default;
plugin = (_plugin_default = plugin.default) !== null && _plugin_default !== void 0 ? _plugin_default : plugin;
} else if (Array.isArray(plugin)) {
// If the plugin is specified as an array then it's a package name and optional options object
// [name] or [name, options]
let [pkg, options = undefined] = plugin;
plugin = require(pkg);
var _plugin_default1;
plugin = (_plugin_default1 = plugin.default) !== null && _plugin_default1 !== void 0 ? _plugin_default1 : plugin;
plugin = plugin(options);
}
if (plugin.__isOptionsFunction) {
plugin = plugin();
}
var _plugin_config;
// We're explicitly skipping registering child plugins
// This will change in v4
let [, childConfigs] = resolvePlugins([
(_plugin_config = plugin === null || plugin === void 0 ? void 0 : plugin.config) !== null && _plugin_config !== void 0 ? _plugin_config : {}
]);
plugins.push(plugin);
allConfigs.push(...childConfigs);
}
pluginGroups.push(plugins);
}
// Reverse the order of the plugin groups
// This matches the old `reduceRight` behavior of the old `resolvePluginLists`
// Why? No idea.
let plugins = pluginGroups.reverse().flat();
return [
plugins,
allConfigs
];
}
function resolveCorePlugins(corePluginConfigs) {
const result = [
...corePluginConfigs
].reduceRight((resolved, corePluginConfig)=>{
if (isFunction(corePluginConfig)) {
return corePluginConfig({
corePlugins: resolved
});
}
return (0, _configurePlugins.default)(corePluginConfig, resolved);
}, _corePluginList.default);
return result;
}
function resolveConfig(configs) {
let [plugins, pluginConfigs] = resolvePlugins(configs);
let allConfigs = [
...pluginConfigs,
{
prefix: '',
important: false,
separator: ':'
}
];
return (0, _normalizeConfig.normalizeConfig)((0, _defaults.defaults)({
theme: resolveFunctionKeys(mergeExtensions(mergeThemes(allConfigs.map((t)=>{
var _t_theme;
return (_t_theme = t === null || t === void 0 ? void 0 : t.theme) !== null && _t_theme !== void 0 ? _t_theme : {};
})))),
corePlugins: resolveCorePlugins(allConfigs.map((c)=>c.corePlugins)),
plugins
}, ...allConfigs));
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
default: function() {
return resolveConfigPath;
},
resolveDefaultConfigPath: function() {
return resolveDefaultConfigPath;
}
});
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
const defaultConfigFiles = [
'./tailwind.config.js',
'./tailwind.config.cjs',
'./tailwind.config.mjs',
'./tailwind.config.ts'
];
function isObject(value) {
return typeof value === 'object' && value !== null;
}
function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
function isString(value) {
return typeof value === 'string' || value instanceof String;
}
function resolveConfigPath(pathOrConfig) {
// require('tailwindcss')({ theme: ..., variants: ... })
if (isObject(pathOrConfig) && pathOrConfig.config === undefined && !isEmpty(pathOrConfig)) {
return null;
}
// require('tailwindcss')({ config: 'custom-config.js' })
if (isObject(pathOrConfig) && pathOrConfig.config !== undefined && isString(pathOrConfig.config)) {
return _path.default.resolve(pathOrConfig.config);
}
// require('tailwindcss')({ config: { theme: ..., variants: ... } })
if (isObject(pathOrConfig) && pathOrConfig.config !== undefined && isObject(pathOrConfig.config)) {
return null;
}
// require('tailwindcss')('custom-config.js')
if (isString(pathOrConfig)) {
return _path.default.resolve(pathOrConfig);
}
// require('tailwindcss')
return resolveDefaultConfigPath();
}
function resolveDefaultConfigPath() {
for (const configFile of defaultConfigFiles){
try {
const configPath = _path.default.resolve(configFile);
_fs.default.accessSync(configPath);
return configPath;
} catch (err) {}
}
return null;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return responsive;
}
});
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _cloneNodes = /*#__PURE__*/ _interop_require_default(require("./cloneNodes"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function responsive(rules) {
return _postcss.default.atRule({
name: 'responsive'
}).append((0, _cloneNodes.default)(Array.isArray(rules) ? rules : [
rules
]));
}
/**
* This splits a string on a top-level character.
*
* Regex doesn't support recursion (at least not the JS-flavored version).
* So we have to use a tiny state machine to keep track of paren placement.
*
* Expected behavior using commas:
* var(--a, 0 0 1px rgb(0, 0, 0)), 0 0 1px rgb(0, 0, 0)
* ─┬─ ┬ ┬ ┬
* x x x ╰──────── Split because top-level
* ╰──────────────┴──┴───────────── Ignored b/c inside >= 1 levels of parens
*
* @param {string} input
* @param {string} separator
*/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "splitAtTopLevelOnly", {
enumerable: true,
get: function() {
return splitAtTopLevelOnly;
}
});
function splitAtTopLevelOnly(input, separator) {
let stack = [];
let parts = [];
let lastPos = 0;
let isEscaped = false;
for(let idx = 0; idx < input.length; idx++){
let char = input[idx];
if (stack.length === 0 && char === separator[0] && !isEscaped) {
if (separator.length === 1 || input.slice(idx, idx + separator.length) === separator) {
parts.push(input.slice(lastPos, idx));
lastPos = idx + separator.length;
}
}
if (isEscaped) {
isEscaped = false;
} else if (char === '\\') {
isEscaped = true;
}
if (char === '(' || char === '[' || char === '{') {
stack.push(char);
} else if (char === ')' && stack[stack.length - 1] === '(' || char === ']' && stack[stack.length - 1] === '[' || char === '}' && stack[stack.length - 1] === '{') {
stack.pop();
}
}
parts.push(input.slice(lastPos));
return parts;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "tap", {
enumerable: true,
get: function() {
return tap;
}
});
function tap(value, mutator) {
mutator(value);
return value;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return toColorValue;
}
});
function toColorValue(maybeFunction) {
return typeof maybeFunction === 'function' ? maybeFunction({}) : maybeFunction;
}
/**
* Parse a path string into an array of path segments.
*
* Square bracket notation `a[b]` may be used to "escape" dots that would otherwise be interpreted as path separators.
*
* Example:
* a -> ['a']
* a.b.c -> ['a', 'b', 'c']
* a[b].c -> ['a', 'b', 'c']
* a[b.c].e.f -> ['a', 'b.c', 'e', 'f']
* a[b][c][d] -> ['a', 'b', 'c', 'd']
*
* @param {string|string[]} path
**/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "toPath", {
enumerable: true,
get: function() {
return toPath;
}
});
function toPath(path) {
if (Array.isArray(path)) return path;
let openBrackets = path.split('[').length - 1;
let closedBrackets = path.split(']').length - 1;
if (openBrackets !== closedBrackets) {
throw new Error(`Path is invalid. Has unbalanced brackets: ${path}`);
}
return path.split(/\.(?![^\[]*\])|[\[\]]/g).filter(Boolean);
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return transformThemeValue;
}
});
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _isPlainObject = /*#__PURE__*/ _interop_require_default(require("./isPlainObject"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function transformThemeValue(themeSection) {
if ([
'fontSize',
'outline'
].includes(themeSection)) {
return (value)=>{
if (typeof value === 'function') value = value({});
if (Array.isArray(value)) value = value[0];
return value;
};
}
if (themeSection === 'fontFamily') {
return (value)=>{
if (typeof value === 'function') value = value({});
let families = Array.isArray(value) && (0, _isPlainObject.default)(value[1]) ? value[0] : value;
return Array.isArray(families) ? families.join(', ') : families;
};
}
if ([
'boxShadow',
'transitionProperty',
'transitionDuration',
'transitionDelay',
'transitionTimingFunction',
'backgroundImage',
'backgroundSize',
'backgroundColor',
'cursor',
'animation'
].includes(themeSection)) {
return (value)=>{
if (typeof value === 'function') value = value({});
if (Array.isArray(value)) value = value.join(', ');
return value;
};
}
// For backwards compatibility reasons, before we switched to underscores
// instead of commas for arbitrary values.
if ([
'gridTemplateColumns',
'gridTemplateRows',
'objectPosition'
].includes(themeSection)) {
return (value)=>{
if (typeof value === 'function') value = value({});
if (typeof value === 'string') value = _postcss.default.list.comma(value).join(' ');
return value;
};
}
return (value, opts = {})=>{
if (typeof value === 'function') {
value = value(opts);
}
return value;
};
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "validateConfig", {
enumerable: true,
get: function() {
return validateConfig;
}
});
const _picocolors = /*#__PURE__*/ _interop_require_default(require("picocolors"));
const _log = /*#__PURE__*/ _interop_require_default(require("./log"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function validateConfig(config) {
if (config.content.files.length === 0) {
_log.default.warn('content-problems', [
'The `content` option in your Tailwind CSS configuration is missing or empty.',
'Configure your content sources or your generated CSS will be missing styles.',
'https://tailwindcss.com/docs/content-configuration'
]);
}
if (config.content.files.includes('auto')) {
_log.default.group('auto-content-experimental', (log)=>{
log.info([
_picocolors.default.bold('Automatically detecting Tailwind CSS content sources...')
]);
log.warn([
'Automatic content detection is experimental, and the behavior may change at any time.'
]);
});
}
// Warn if the line-clamp plugin is installed
try {
let plugin = require('@tailwindcss/line-clamp');
if (config.plugins.includes(plugin)) {
_log.default.warn('line-clamp-in-core', [
'As of Tailwind CSS v3.3, the `@tailwindcss/line-clamp` plugin is now included by default.',
'Remove it from the `plugins` array in your configuration to eliminate this warning.'
]);
config.plugins = config.plugins.filter((p)=>p !== plugin);
}
} catch (e) {}
return config;
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "backgroundSize", {
enumerable: true,
get: function() {
return backgroundSize;
}
});
const _dataTypes = require("./dataTypes");
const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly");
function backgroundSize(value) {
let keywordValues = [
'cover',
'contain'
];
// the <length-percentage> type will probably be a css function
// so we have to use `splitAtTopLevelOnly`
return (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ',').every((part)=>{
let sizes = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(part, '_').filter(Boolean);
if (sizes.length === 1 && keywordValues.includes(sizes[0])) return true;
if (sizes.length !== 1 && sizes.length !== 2) return false;
return sizes.every((size)=>(0, _dataTypes.length)(size) || (0, _dataTypes.percentage)(size) || size === 'auto');
});
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
default: function() {
return withAlphaVariable;
},
withAlphaValue: function() {
return withAlphaValue;
}
});
const _color = require("./color");
function withAlphaValue(color, alphaValue, defaultValue) {
if (typeof color === 'function') {
return color({
opacityValue: alphaValue
});
}
let parsed = (0, _color.parseColor)(color, {
loose: true
});
if (parsed === null) {
return defaultValue;
}
return (0, _color.formatColor)({
...parsed,
alpha: alphaValue
});
}
function withAlphaVariable({ color, property, variable }) {
let properties = [].concat(property);
if (typeof color === 'function') {
return {
[variable]: '1',
...Object.fromEntries(properties.map((p)=>{
return [
p,
color({
opacityVariable: variable,
opacityValue: `var(${variable})`
})
];
}))
};
}
const parsed = (0, _color.parseColor)(color);
if (parsed === null) {
return Object.fromEntries(properties.map((p)=>[
p,
color
]));
}
if (parsed.alpha !== undefined) {
// Has an alpha value, return color as-is
return Object.fromEntries(properties.map((p)=>[
p,
color
]));
}
return {
[variable]: '1',
...Object.fromEntries(properties.map((p)=>{
return [
p,
(0, _color.formatColor)({
...parsed,
alpha: `var(${variable})`
})
];
}))
};
}
"use strict";
module.exports = postcssValueParser;
"use strict";
var parse = require('./parse');
var walk = require('./walk');
var stringify = require('./stringify');
function ValueParser(value) {
if (this instanceof ValueParser) {
this.nodes = parse(value);
return this;
}
return new ValueParser(value);
}
ValueParser.prototype.toString = function() {
return Array.isArray(this.nodes) ? stringify(this.nodes) : '';
};
ValueParser.prototype.walk = function(cb, bubble) {
walk(this.nodes, cb, bubble);
return this;
};
ValueParser.unit = require('./unit');
ValueParser.walk = walk;
ValueParser.stringify = stringify;
module.exports = ValueParser;
Copyright (c) Bogdan Chadkin <trysound@yandex.ru>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
"use strict";
var openParentheses = '('.charCodeAt(0);
var closeParentheses = ')'.charCodeAt(0);
var singleQuote = "'".charCodeAt(0);
var doubleQuote = '"'.charCodeAt(0);
var backslash = '\\'.charCodeAt(0);
var slash = '/'.charCodeAt(0);
var comma = ','.charCodeAt(0);
var colon = ':'.charCodeAt(0);
var star = '*'.charCodeAt(0);
var uLower = 'u'.charCodeAt(0);
var uUpper = 'U'.charCodeAt(0);
var plus = '+'.charCodeAt(0);
var isUnicodeRange = /^[a-f0-9?-]+$/i;
module.exports = function(input) {
var tokens = [];
var value = input;
var next, quote, prev, token, escape, escapePos, whitespacePos, parenthesesOpenPos;
var pos = 0;
var code = value.charCodeAt(pos);
var max = value.length;
var stack = [
{
nodes: tokens
}
];
var balanced = 0;
var parent;
var name = '';
var before = '';
var after = '';
while(pos < max){
// Whitespaces
if (code <= 32) {
next = pos;
do {
next += 1;
code = value.charCodeAt(next);
}while (code <= 32)
token = value.slice(pos, next);
prev = tokens[tokens.length - 1];
if (code === closeParentheses && balanced) {
after = token;
} else if (prev && prev.type === 'div') {
prev.after = token;
prev.sourceEndIndex += token.length;
} else if (code === comma || code === colon || code === slash && value.charCodeAt(next + 1) !== star && (!parent || parent && parent.type === 'function' && false)) {
before = token;
} else {
tokens.push({
type: 'space',
sourceIndex: pos,
sourceEndIndex: next,
value: token
});
}
pos = next;
// Quotes
} else if (code === singleQuote || code === doubleQuote) {
next = pos;
quote = code === singleQuote ? "'" : '"';
token = {
type: 'string',
sourceIndex: pos,
quote: quote
};
do {
escape = false;
next = value.indexOf(quote, next + 1);
if (~next) {
escapePos = next;
while(value.charCodeAt(escapePos - 1) === backslash){
escapePos -= 1;
escape = !escape;
}
} else {
value += quote;
next = value.length - 1;
token.unclosed = true;
}
}while (escape)
token.value = value.slice(pos + 1, next);
token.sourceEndIndex = token.unclosed ? next : next + 1;
tokens.push(token);
pos = next + 1;
code = value.charCodeAt(pos);
// Comments
} else if (code === slash && value.charCodeAt(pos + 1) === star) {
next = value.indexOf('*/', pos);
token = {
type: 'comment',
sourceIndex: pos,
sourceEndIndex: next + 2
};
if (next === -1) {
token.unclosed = true;
next = value.length;
token.sourceEndIndex = next;
}
token.value = value.slice(pos + 2, next);
tokens.push(token);
pos = next + 2;
code = value.charCodeAt(pos);
// Operation within calc
} else if ((code === slash || code === star) && parent && parent.type === 'function' && true) {
token = value[pos];
tokens.push({
type: 'word',
sourceIndex: pos - before.length,
sourceEndIndex: pos + token.length,
value: token
});
pos += 1;
code = value.charCodeAt(pos);
// Dividers
} else if (code === slash || code === comma || code === colon) {
token = value[pos];
tokens.push({
type: 'div',
sourceIndex: pos - before.length,
sourceEndIndex: pos + token.length,
value: token,
before: before,
after: ''
});
before = '';
pos += 1;
code = value.charCodeAt(pos);
// Open parentheses
} else if (openParentheses === code) {
// Whitespaces after open parentheses
next = pos;
do {
next += 1;
code = value.charCodeAt(next);
}while (code <= 32)
parenthesesOpenPos = pos;
token = {
type: 'function',
sourceIndex: pos - name.length,
value: name,
before: value.slice(parenthesesOpenPos + 1, next)
};
pos = next;
if (name === 'url' && code !== singleQuote && code !== doubleQuote) {
next -= 1;
do {
escape = false;
next = value.indexOf(')', next + 1);
if (~next) {
escapePos = next;
while(value.charCodeAt(escapePos - 1) === backslash){
escapePos -= 1;
escape = !escape;
}
} else {
value += ')';
next = value.length - 1;
token.unclosed = true;
}
}while (escape)
// Whitespaces before closed
whitespacePos = next;
do {
whitespacePos -= 1;
code = value.charCodeAt(whitespacePos);
}while (code <= 32)
if (parenthesesOpenPos < whitespacePos) {
if (pos !== whitespacePos + 1) {
token.nodes = [
{
type: 'word',
sourceIndex: pos,
sourceEndIndex: whitespacePos + 1,
value: value.slice(pos, whitespacePos + 1)
}
];
} else {
token.nodes = [];
}
if (token.unclosed && whitespacePos + 1 !== next) {
token.after = '';
token.nodes.push({
type: 'space',
sourceIndex: whitespacePos + 1,
sourceEndIndex: next,
value: value.slice(whitespacePos + 1, next)
});
} else {
token.after = value.slice(whitespacePos + 1, next);
token.sourceEndIndex = next;
}
} else {
token.after = '';
token.nodes = [];
}
pos = next + 1;
token.sourceEndIndex = token.unclosed ? next : pos;
code = value.charCodeAt(pos);
tokens.push(token);
} else {
balanced += 1;
token.after = '';
token.sourceEndIndex = pos + 1;
tokens.push(token);
stack.push(token);
tokens = token.nodes = [];
parent = token;
}
name = '';
// Close parentheses
} else if (closeParentheses === code && balanced) {
pos += 1;
code = value.charCodeAt(pos);
parent.after = after;
parent.sourceEndIndex += after.length;
after = '';
balanced -= 1;
stack[stack.length - 1].sourceEndIndex = pos;
stack.pop();
parent = stack[balanced];
tokens = parent.nodes;
// Words
} else {
next = pos;
do {
if (code === backslash) {
next += 1;
}
next += 1;
code = value.charCodeAt(next);
}while (next < max && !(code <= 32 || code === singleQuote || code === doubleQuote || code === comma || code === colon || code === slash || code === openParentheses || code === star && parent && parent.type === 'function' && true || code === slash && parent.type === 'function' && true || code === closeParentheses && balanced))
token = value.slice(pos, next);
if (openParentheses === code) {
name = token;
} else if ((uLower === token.charCodeAt(0) || uUpper === token.charCodeAt(0)) && plus === token.charCodeAt(1) && isUnicodeRange.test(token.slice(2))) {
tokens.push({
type: 'unicode-range',
sourceIndex: pos,
sourceEndIndex: next,
value: token
});
} else {
tokens.push({
type: 'word',
sourceIndex: pos,
sourceEndIndex: next,
value: token
});
}
pos = next;
}
}
for(pos = stack.length - 1; pos; pos -= 1){
stack[pos].unclosed = true;
stack[pos].sourceEndIndex = value.length;
}
return stack[0].nodes;
};
# postcss-value-parser (forked + inlined)
This is a customized version of of [PostCSS Value Parser](https://github.com/TrySound/postcss-value-parser) to fix some bugs around parsing CSS functions.
"use strict";
function stringifyNode(node, custom) {
var type = node.type;
var value = node.value;
var buf;
var customResult;
if (custom && (customResult = custom(node)) !== undefined) {
return customResult;
} else if (type === 'word' || type === 'space') {
return value;
} else if (type === 'string') {
buf = node.quote || '';
return buf + value + (node.unclosed ? '' : buf);
} else if (type === 'comment') {
return '/*' + value + (node.unclosed ? '' : '*/');
} else if (type === 'div') {
return (node.before || '') + value + (node.after || '');
} else if (Array.isArray(node.nodes)) {
buf = stringify(node.nodes, custom);
if (type !== 'function') {
return buf;
}
return value + '(' + (node.before || '') + buf + (node.after || '') + (node.unclosed ? '' : ')');
}
return value;
}
function stringify(nodes, custom) {
var result, i;
if (Array.isArray(nodes)) {
result = '';
for(i = nodes.length - 1; ~i; i -= 1){
result = stringifyNode(nodes[i], custom) + result;
}
return result;
}
return stringifyNode(nodes, custom);
}
module.exports = stringify;
"use strict";
var minus = '-'.charCodeAt(0);
var plus = '+'.charCodeAt(0);
var dot = '.'.charCodeAt(0);
var exp = 'e'.charCodeAt(0);
var EXP = 'E'.charCodeAt(0);
// Check if three code points would start a number
// https://www.w3.org/TR/css-syntax-3/#starts-with-a-number
function likeNumber(value) {
var code = value.charCodeAt(0);
var nextCode;
if (code === plus || code === minus) {
nextCode = value.charCodeAt(1);
if (nextCode >= 48 && nextCode <= 57) {
return true;
}
var nextNextCode = value.charCodeAt(2);
if (nextCode === dot && nextNextCode >= 48 && nextNextCode <= 57) {
return true;
}
return false;
}
if (code === dot) {
nextCode = value.charCodeAt(1);
if (nextCode >= 48 && nextCode <= 57) {
return true;
}
return false;
}
if (code >= 48 && code <= 57) {
return true;
}
return false;
}
// Consume a number
// https://www.w3.org/TR/css-syntax-3/#consume-number
module.exports = function(value) {
var pos = 0;
var length = value.length;
var code;
var nextCode;
var nextNextCode;
if (length === 0 || !likeNumber(value)) {
return false;
}
code = value.charCodeAt(pos);
if (code === plus || code === minus) {
pos++;
}
while(pos < length){
code = value.charCodeAt(pos);
if (code < 48 || code > 57) {
break;
}
pos += 1;
}
code = value.charCodeAt(pos);
nextCode = value.charCodeAt(pos + 1);
if (code === dot && nextCode >= 48 && nextCode <= 57) {
pos += 2;
while(pos < length){
code = value.charCodeAt(pos);
if (code < 48 || code > 57) {
break;
}
pos += 1;
}
}
code = value.charCodeAt(pos);
nextCode = value.charCodeAt(pos + 1);
nextNextCode = value.charCodeAt(pos + 2);
if ((code === exp || code === EXP) && (nextCode >= 48 && nextCode <= 57 || (nextCode === plus || nextCode === minus) && nextNextCode >= 48 && nextNextCode <= 57)) {
pos += nextCode === plus || nextCode === minus ? 3 : 2;
while(pos < length){
code = value.charCodeAt(pos);
if (code < 48 || code > 57) {
break;
}
pos += 1;
}
}
return {
number: value.slice(0, pos),
unit: value.slice(pos)
};
};
"use strict";
module.exports = function walk(nodes, cb, bubble) {
var i, max, node, result;
for(i = 0, max = nodes.length; i < max; i += 1){
node = nodes[i];
if (!bubble) {
result = cb(node, i, nodes);
}
if (result !== false && node.type === 'function' && Array.isArray(node.nodes)) {
walk(node.nodes, cb, bubble);
}
if (bubble) {
cb(node, i, nodes);
}
}
};
import type { Config } from './types/config'
declare function loadConfig(path: string): Config
export = loadConfig
let loadConfig = require('./lib/public/load-config')
module.exports = (loadConfig.__esModule ? loadConfig : { default: loadConfig }).default
import type { AcceptedPlugin, PluginCreator } from 'postcss'
declare const plugin: PluginCreator<AcceptedPlugin | string | void>
export = plugin
let nesting = require('../lib/postcss-plugins/nesting')
module.exports = (nesting.__esModule ? nesting : { default: nesting }).default
import type { Config, PluginCreator } from './types/config'
type Plugin = {
withOptions<T>(
plugin: (options: T) => PluginCreator,
config?: (options: T) => Partial<Config>
): { (options: T): { handler: PluginCreator; config?: Partial<Config> }; __isOptionsFunction: true }
(plugin: PluginCreator, config?: Partial<Config>): { handler: PluginCreator; config?: Partial<Config> }
}
declare const plugin: Plugin
export = plugin
let createPlugin = require('./lib/public/create-plugin')
module.exports = (createPlugin.__esModule ? createPlugin : { default: createPlugin }).default
module.exports = {
// These settings are duplicated in .editorconfig:
tabWidth: 2, // indent_size = 2
useTabs: false, // indent_style = space
endOfLine: 'lf', // end_of_line = lf
semi: false, // default: true
singleQuote: true, // default: false
printWidth: 100, // default: 80
trailingComma: 'es5',
bracketSpacing: true,
overrides: [
{
files: '*.js',
options: {
parser: 'flow',
},
},
],
}
import { Config, ResolvableTo, ThemeConfig } from './types/config'
import { DefaultTheme } from './types/generated/default-theme'
import { DefaultColors } from './types/generated/colors'
type ResolvedConfig<T extends Config> = Omit<T, 'theme'> & {
theme: MergeThemes<
UnwrapResolvables<Omit<T['theme'], 'extend'>>,
T['theme'] extends { extend: infer TExtend } ? UnwrapResolvables<TExtend> : {}
>
}
type UnwrapResolvables<T> = {
[K in keyof T]: T[K] extends ResolvableTo<infer R> ? R : T[K]
}
type ThemeConfigResolved = UnwrapResolvables<ThemeConfig>
type DefaultThemeFull = DefaultTheme & { colors: DefaultColors }
type MergeThemes<Overrides extends object, Extensions extends object> = {
[K in keyof ThemeConfigResolved | keyof Overrides]: (K extends keyof Overrides
? Overrides[K]
: K extends keyof DefaultThemeFull
? DefaultThemeFull[K]
: K extends keyof ThemeConfigResolved
? ThemeConfigResolved[K]
: never) &
(K extends keyof Extensions ? Extensions[K] : {})
}
declare function resolveConfig<T extends Config>(config: T): ResolvedConfig<T>
export = resolveConfig
let resolveConfig = require('./lib/public/resolve-config')
module.exports = (resolveConfig.__esModule ? resolveConfig : { default: resolveConfig }).default
@tailwind screens;
import { corePlugins } from '../src/corePlugins'
import fs from 'fs'
import path from 'path'
let corePluginList = Object.keys(corePlugins)
fs.writeFileSync(
path.join(process.cwd(), 'src', 'corePluginList.js'),
`export default ${JSON.stringify(corePluginList)}`
)
import prettier from 'prettier'
import { corePlugins } from '../src/corePlugins'
import colors from '../src/public/colors'
import defaultTheme from '../src/public/default-theme'
import fs from 'fs'
import path from 'path'
import * as types from './type-utils'
fs.writeFileSync(
path.join(process.cwd(), 'types', 'generated', 'corePluginList.d.ts'),
`export type CorePluginList = ${Object.keys(corePlugins)
.map((p) => `'${p}'`)
.join(' | ')}`
)
let colorsWithoutDeprecatedColors = Object.fromEntries(
Object.entries(Object.getOwnPropertyDescriptors(colors))
.filter(([_, { value }]) => {
return typeof value !== 'undefined'
})
.map(([name, definition]) => [name, definition.value])
)
let deprecatedColors = Object.entries(Object.getOwnPropertyDescriptors(colors))
.filter(([_, { value }]) => {
return typeof value === 'undefined'
})
.map(([name, definition]) => {
let warn = console.warn
let messages = []
console.warn = (...args) => messages.push(args.pop())
definition.get()
console.warn = warn
let message = messages.join(' ').trim()
let newColor = message.match(/renamed to `(.*)`/)[1]
return `/** @deprecated ${message} */${name}: DefaultColors['${newColor}'],`
})
.join('\n')
fs.writeFileSync(
path.join(process.cwd(), 'types', 'generated', 'colors.d.ts'),
prettier.format(
`export interface DefaultColors { ${JSON.stringify(colorsWithoutDeprecatedColors).slice(
1,
-1
)}\n${deprecatedColors}\n}`,
{
semi: false,
singleQuote: true,
printWidth: 100,
parser: 'typescript',
}
)
)
const defaultThemeTypes = Object.entries(defaultTheme)
.map(([name, value]) => {
// Special cases for slightly more accurate types
if (name === 'keyframes') {
return [name, `Record<${types.forKeys(value)}, Record<string, CSSDeclarationList>>`]
}
if (name === 'fontSize') {
return [name, `Record<${types.forKeys(value)}, [string, { lineHeight: string }]>`]
}
// General cases
if (typeof value === 'string') {
return [name, `string`]
}
if (typeof value === 'function') {
return [name, null]
}
if (typeof value === 'object') {
if (Object.keys(value).length === 0) {
return [name, null]
}
return [name, types.forValue(value)]
}
return [name, `unknown`]
})
.filter(([, type]) => type !== null)
.map(([name, type]) => `${name}: ${type}`)
.join('\n')
fs.writeFileSync(
path.join(process.cwd(), 'types', 'generated', 'default-theme.d.ts'),
prettier.format(
`
type CSSDeclarationList = Record<string, string>
export type DefaultTheme = { ${defaultThemeTypes} }
`,
{
semi: false,
singleQuote: true,
printWidth: 100,
parser: 'typescript',
}
)
)
// Given a version, figure out what the release channel is so that we can publish to the correct
// channel on npm.
//
// E.g.:
//
// 1.2.3 -> latest (default)
// 0.0.0-insiders.ffaa88 -> insiders
// 4.1.0-alpha.4 -> alpha
let version =
process.argv[2] || process.env.npm_package_version || require('../package.json').version
let match = /\d+\.\d+\.\d+-(.*)\.\d+/g.exec(version)
if (match) {
console.log(match[1])
} else {
console.log('latest')
}
// Given a version, figure out what the release notes are so that we can use this to pre-fill the
// release notes on a GitHub release for the current version.
let path = require('path')
let fs = require('fs')
let version =
process.argv[2] || process.env.npm_package_version || require('../package.json').version
let changelog = fs.readFileSync(path.resolve(__dirname, '..', 'CHANGELOG.md'), 'utf8')
let match = new RegExp(
`## \\[${version}\\] - (.*)\\n\\n([\\s\\S]*?)\\n(?:(?:##\\s)|(?:\\[))`,
'g'
).exec(changelog)
if (match) {
let [, , notes] = match
console.log(notes.trim())
} else {
console.log(`Placeholder release notes for version: v${version}`)
}
export function union(types) {
return [...new Set(types)].join(' | ')
}
export function unionValues(values) {
return union(values.map(forValue))
}
export function forKeys(value) {
return union(Object.keys(value).map((key) => `'${key}'`))
}
export function forValue(value) {
if (Array.isArray(value)) {
return `(${unionValues(value)})[]`
}
if (typeof value === 'object') {
return `Record<${forKeys(value)}, ${unionValues(Object.values(value))}>`
}
if (typeof value === 'string') {
return `string`
}
return `any`
}
#!/usr/bin/env node
module.exports = require('./cli/index')
// @ts-check
import fs from 'fs'
import path from 'path'
import { resolveDefaultConfigPath } from '../../util/resolveConfigPath.js'
import { createProcessor } from './plugin.js'
export async function build(args) {
let input = args['--input']
let shouldWatch = args['--watch']
// TODO: Deprecate this in future versions
if (!input && args['_'][1]) {
console.error('[deprecation] Running tailwindcss without -i, please provide an input file.')
input = args['--input'] = args['_'][1]
}
if (input && input !== '-' && !fs.existsSync((input = path.resolve(input)))) {
console.error(`Specified input file ${args['--input']} does not exist.`)
process.exit(9)
}
if (args['--config'] && !fs.existsSync((args['--config'] = path.resolve(args['--config'])))) {
console.error(`Specified config file ${args['--config']} does not exist.`)
process.exit(9)
}
if (args['--no-autoprefixer']) {
console.error('[deprecation] The --no-autoprefixer flag is deprecated and has no effect.')
}
// TODO: Reference the @config path here if exists
let configPath = args['--config'] ? args['--config'] : resolveDefaultConfigPath()
let processor = await createProcessor(args, configPath)
if (shouldWatch) {
// Abort the watcher if stdin is closed to avoid zombie processes
// You can disable this behavior with --watch=always
if (args['--watch'] !== 'always') {
process.stdin.on('end', () => process.exit(0))
}
process.stdin.resume()
await processor.watch()
} else {
await processor.build().catch((e) => {
console.error(e)
process.exit(1)
})
}
}
// @ts-check
import pkg from '../../../package.json'
import path from 'path'
import fs from 'fs'
import postcss from 'postcss'
import postcssrc from 'postcss-load-config'
import browserslist from 'browserslist'
import lightning, { Features } from 'lightningcss'
import { lilconfig } from 'lilconfig'
import loadPlugins from 'postcss-load-config/src/plugins' // Little bit scary, looking at private/internal API
import loadOptions from 'postcss-load-config/src/options' // Little bit scary, looking at private/internal API
import tailwind from '../../processTailwindFeatures'
import { formatNodes, drainStdin, outputFile } from './utils'
import { env } from '../../lib/sharedState'
import resolveConfig from '../../../resolveConfig.js'
import { parseCandidateFiles } from '../../lib/content.js'
import { createWatcher } from './watching.js'
import fastGlob from 'fast-glob'
import { findAtConfigPath } from '../../lib/findAtConfigPath.js'
import log from '../../util/log'
import { loadConfig } from '../../lib/load-config'
import getModuleDependencies from '../../lib/getModuleDependencies'
import { validateConfig } from '../../util/validateConfig'
import { handleImportAtRules } from '../../lib/handleImportAtRules'
import { flagEnabled } from '../../featureFlags'
function license() {
return `/* ! tailwindcss v${pkg.version} | MIT License | https://tailwindcss.com */\n`
}
async function lightningcss(result, { map = true, minify = true } = {}) {
try {
let resolvedBrowsersListConfig = browserslist.findConfig(
result.opts.from ?? process.cwd()
)?.defaults
let defaultBrowsersListConfig = pkg.browserslist
let browsersListConfig = resolvedBrowsersListConfig ?? defaultBrowsersListConfig
let transformed = lightning.transform({
filename: result.opts.from || 'input.css',
code: Buffer.from(result.css, 'utf-8'),
minify,
sourceMap: result.map === undefined ? map : !!result.map,
inputSourceMap: result.map ? result.map.toString() : undefined,
targets: lightning.browserslistToTargets(browserslist(browsersListConfig)),
include: Features.Nesting,
exclude: Features.LogicalProperties,
})
return Object.assign(result, {
css: transformed.code.toString(),
map: result.map
? Object.assign(result.map, {
toString() {
return transformed.map?.toString()
},
})
: result.map,
})
} catch (err) {
console.error('Unable to use Lightning CSS. Using raw version instead.')
console.error(err)
return result
}
}
/**
*
* @param {string} [customPostCssPath ]
* @returns
*/
async function loadPostCssPlugins(customPostCssPath) {
let config = customPostCssPath
? await (async () => {
let file = path.resolve(customPostCssPath)
// Implementation, see: https://unpkg.com/browse/postcss-load-config@3.1.0/src/index.js
// @ts-ignore
let { config = {} } = await lilconfig('postcss').load(file)
if (typeof config === 'function') {
config = config()
} else {
config = Object.assign({}, config)
}
if (!config.plugins) {
config.plugins = []
}
return {
file,
plugins: loadPlugins(config, file),
options: loadOptions(config, file),
}
})()
: await postcssrc()
let configPlugins = config.plugins
let configPluginTailwindIdx = configPlugins.findIndex((plugin) => {
if (typeof plugin === 'function' && plugin.name === 'tailwindcss') {
return true
}
if (typeof plugin === 'object' && plugin !== null && plugin.postcssPlugin === 'tailwindcss') {
return true
}
return false
})
let beforePlugins =
configPluginTailwindIdx === -1 ? [] : configPlugins.slice(0, configPluginTailwindIdx)
let afterPlugins =
configPluginTailwindIdx === -1
? configPlugins
: configPlugins.slice(configPluginTailwindIdx + 1)
return [beforePlugins, afterPlugins, config.options]
}
let state = {
/** @type {any} */
context: null,
/** @type {ReturnType<typeof createWatcher> | null} */
watcher: null,
/** @type {{content: string, extension: string}[]} */
changedContent: [],
/** @type {{config: import('../../../types').Config, dependencies: Set<string>, dispose: Function } | null} */
configBag: null,
contextDependencies: new Set(),
/** @type {import('../../lib/content.js').ContentPath[]} */
contentPaths: [],
refreshContentPaths() {
this.contentPaths = parseCandidateFiles(this.context, this.context?.tailwindConfig)
},
get config() {
return this.context.tailwindConfig
},
get contentPatterns() {
return {
all: this.contentPaths.map((contentPath) => contentPath.pattern),
dynamic: this.contentPaths
.filter((contentPath) => contentPath.glob !== undefined)
.map((contentPath) => contentPath.pattern),
}
},
loadConfig(configPath, content) {
if (this.watcher && configPath) {
this.refreshConfigDependencies()
}
let config = loadConfig(configPath)
let dependencies = getModuleDependencies(configPath)
this.configBag = {
config,
dependencies,
dispose() {
for (let file of dependencies) {
delete require.cache[require.resolve(file)]
}
},
}
this.configBag.config = validateConfig(resolveConfig(this.configBag.config))
// Override content files if `--content` has been passed explicitly
if (content?.length > 0) {
this.configBag.config.content.files = content
}
return this.configBag.config
},
refreshConfigDependencies() {
env.DEBUG && console.time('Module dependencies')
this.configBag?.dispose()
env.DEBUG && console.timeEnd('Module dependencies')
},
readContentPaths() {
let content = []
// Resolve globs from the content config
// TODO: When we make the postcss plugin async-capable this can become async
let files = fastGlob.sync(this.contentPatterns.all)
for (let file of files) {
if (flagEnabled(this.config, 'oxideParser')) {
content.push({
file,
extension: path.extname(file).slice(1),
})
} else {
content.push({
content: fs.readFileSync(path.resolve(file), 'utf8'),
extension: path.extname(file).slice(1),
})
}
}
// Resolve raw content in the tailwind config
let rawContent = this.config.content.files.filter((file) => {
return file !== null && typeof file === 'object'
})
for (let { raw: htmlContent, extension = 'html' } of rawContent) {
content.push({ content: htmlContent, extension })
}
return content
},
getContext({ createContext, cliConfigPath, root, result, content }) {
env.DEBUG && console.time('Searching for config')
let configPath = findAtConfigPath(root, result) ?? cliConfigPath
env.DEBUG && console.timeEnd('Searching for config')
if (this.context) {
this.context.changedContent = this.changedContent.splice(0)
return this.context
}
env.DEBUG && console.time('Loading config')
let config = this.loadConfig(configPath, content)
env.DEBUG && console.timeEnd('Loading config')
env.DEBUG && console.time('Creating context')
this.context = createContext(config, [])
Object.assign(this.context, {
userConfigPath: configPath,
})
env.DEBUG && console.timeEnd('Creating context')
env.DEBUG && console.time('Resolving content paths')
this.refreshContentPaths()
env.DEBUG && console.timeEnd('Resolving content paths')
if (this.watcher) {
env.DEBUG && console.time('Watch new files')
this.watcher.refreshWatchedFiles()
env.DEBUG && console.timeEnd('Watch new files')
}
for (let file of this.readContentPaths()) {
this.context.changedContent.push(file)
}
return this.context
},
}
export async function createProcessor(args, cliConfigPath) {
let input = args['--input']
let output = args['--output']
let includePostCss = args['--postcss']
let customPostCssPath = typeof args['--postcss'] === 'string' ? args['--postcss'] : undefined
let [beforePlugins, afterPlugins, postcssOptions] = includePostCss
? await loadPostCssPlugins(customPostCssPath)
: [[], [], {}]
beforePlugins.unshift(...handleImportAtRules())
if (args['--purge']) {
log.warn('purge-flag-deprecated', [
'The `--purge` flag has been deprecated.',
'Please use `--content` instead.',
])
if (!args['--content']) {
args['--content'] = args['--purge']
}
}
let content = args['--content']?.split(/(?<!{[^}]+),/) ?? []
let tailwindPlugin = () => {
return {
postcssPlugin: 'tailwindcss',
async Once(root, { result }) {
env.DEBUG && console.time('Compiling CSS')
await tailwind(({ createContext }) => {
console.error()
console.error('Rebuilding...')
return () => {
return state.getContext({
createContext,
cliConfigPath,
root,
result,
content,
})
}
})(root, result)
env.DEBUG && console.timeEnd('Compiling CSS')
},
}
}
tailwindPlugin.postcss = true
let plugins = [
...beforePlugins,
tailwindPlugin,
!args['--minify'] && formatNodes,
...afterPlugins,
].filter(Boolean)
/** @type {import('postcss').Processor} */
// @ts-ignore
let processor = postcss(plugins)
async function readInput() {
// Piping in data, let's drain the stdin
if (input === '-') {
return drainStdin()
}
// Input file has been provided
if (input) {
return fs.promises.readFile(path.resolve(input), 'utf8')
}
// No input file provided, fallback to default atrules
return '@tailwind base; @tailwind components; @tailwind utilities'
}
async function build() {
let start = process.hrtime.bigint()
let options = {
...postcssOptions,
from: input,
to: output,
}
return readInput()
.then((css) => processor.process(css, options))
.then((result) =>
lightningcss(result, {
...options,
minify: !!args['--minify'],
})
)
.then((result) => {
if (!state.watcher) {
return result
}
env.DEBUG && console.time('Recording PostCSS dependencies')
for (let message of result.messages) {
if (message.type === 'dependency') {
state.contextDependencies.add(message.file)
}
}
env.DEBUG && console.timeEnd('Recording PostCSS dependencies')
// TODO: This needs to be in a different spot
env.DEBUG && console.time('Watch new files')
state.watcher.refreshWatchedFiles()
env.DEBUG && console.timeEnd('Watch new files')
return result
})
.then((result) => {
if (!output) {
process.stdout.write(license() + result.css)
return
}
return Promise.all([
outputFile(result.opts.to, license() + result.css),
result.map && outputFile(result.opts.to + '.map', result.map.toString()),
])
})
.then(() => {
let end = process.hrtime.bigint()
console.error()
console.error('Done in', (end - start) / BigInt(1e6) + 'ms.')
})
.then(
() => {},
(err) => {
// TODO: If an initial build fails we can't easily pick up any PostCSS dependencies
// that were collected before the error occurred
// The result is not stored on the error so we have to store it externally
// and pull the messages off of it here somehow
// This results in a less than ideal DX because the watcher will not pick up
// changes to imported CSS if one of them caused an error during the initial build
// If you fix it and then save the main CSS file so there's no error
// The watcher will start watching the imported CSS files and will be
// resilient to future errors.
if (state.watcher) {
console.error(err)
} else {
return Promise.reject(err)
}
}
)
}
/**
* @param {{file: string, content(): Promise<string>, extension: string}[]} changes
*/
async function parseChanges(changes) {
return Promise.all(
changes.map(async (change) => ({
content: await change.content(),
extension: change.extension,
}))
)
}
if (input !== undefined && input !== '-') {
state.contextDependencies.add(path.resolve(input))
}
return {
build,
watch: async () => {
state.watcher = createWatcher(args, {
state,
/**
* @param {{file: string, content(): Promise<string>, extension: string}[]} changes
*/
async rebuild(changes) {
let needsNewContext = changes.some((change) => {
return (
state.configBag?.dependencies.has(change.file) ||
state.contextDependencies.has(change.file)
)
})
if (needsNewContext) {
state.context = null
} else {
for (let change of await parseChanges(changes)) {
state.changedContent.push(change)
}
}
return build()
},
})
await build()
},
}
}
// @ts-check
import fs from 'fs'
import path from 'path'
export function indentRecursive(node, indent = 0) {
node.each &&
node.each((child, i) => {
if (!child.raws.before || !child.raws.before.trim() || child.raws.before.includes('\n')) {
child.raws.before = `\n${node.type !== 'rule' && i > 0 ? '\n' : ''}${' '.repeat(indent)}`
}
child.raws.after = `\n${' '.repeat(indent)}`
indentRecursive(child, indent + 1)
})
}
export function formatNodes(root) {
indentRecursive(root)
if (root.first) {
root.first.raws.before = ''
}
}
/**
* When rapidly saving files atomically a couple of situations can happen:
* - The file is missing since the external program has deleted it by the time we've gotten around to reading it from the earlier save.
* - The file is being written to by the external program by the time we're going to read it and is thus treated as busy because a lock is held.
*
* To work around this we retry reading the file a handful of times with a delay between each attempt
*
* @param {string} path
* @param {number} tries
* @returns {Promise<string | undefined>}
* @throws {Error} If the file is still missing or busy after the specified number of tries
*/
export async function readFileWithRetries(path, tries = 5) {
for (let n = 0; n <= tries; n++) {
try {
return await fs.promises.readFile(path, 'utf8')
} catch (err) {
if (n !== tries) {
if (err.code === 'ENOENT' || err.code === 'EBUSY') {
await new Promise((resolve) => setTimeout(resolve, 10))
continue
}
}
throw err
}
}
}
export function drainStdin() {
return new Promise((resolve, reject) => {
let result = ''
process.stdin.on('data', (chunk) => {
result += chunk
})
process.stdin.on('end', () => resolve(result))
process.stdin.on('error', (err) => reject(err))
})
}
export async function outputFile(file, newContents) {
try {
let currentContents = await fs.promises.readFile(file, 'utf8')
if (currentContents === newContents) {
return // Skip writing the file
}
} catch {}
// Write the file
await fs.promises.mkdir(path.dirname(file), { recursive: true })
await fs.promises.writeFile(file, newContents, 'utf8')
}
// @ts-check
import chokidar from 'chokidar'
import fs from 'fs'
import micromatch from 'micromatch'
import normalizePath from 'normalize-path'
import path from 'path'
import { readFileWithRetries } from './utils.js'
/**
* The core idea of this watcher is:
* 1. Whenever a file is added, changed, or renamed we queue a rebuild
* 2. Perform as few rebuilds as possible by batching them together
* 3. Coalesce events that happen in quick succession to avoid unnecessary rebuilds
* 4. Ensure another rebuild happens _if_ changed while a rebuild is in progress
*/
/**
*
* @param {*} args
* @param {{ state, rebuild(changedFiles: any[]): Promise<any> }} param1
* @returns {{
* fswatcher: import('chokidar').FSWatcher,
* refreshWatchedFiles(): void,
* }}
*/
export function createWatcher(args, { state, rebuild }) {
let shouldPoll = args['--poll']
let shouldCoalesceWriteEvents = shouldPoll || process.platform === 'win32'
// Polling interval in milliseconds
// Used only when polling or coalescing add/change events on Windows
let pollInterval = 10
let watcher = chokidar.watch([], {
// Force checking for atomic writes in all situations
// This causes chokidar to wait up to 100ms for a file to re-added after it's been unlinked
// This only works when watching directories though
atomic: true,
usePolling: shouldPoll,
interval: shouldPoll ? pollInterval : undefined,
ignoreInitial: true,
awaitWriteFinish: shouldCoalesceWriteEvents
? {
stabilityThreshold: 50,
pollInterval: pollInterval,
}
: false,
})
// A queue of rebuilds, file reads, etc… to run
let chain = Promise.resolve()
/**
* A list of files that have been changed since the last rebuild
*
* @type {{file: string, content: () => Promise<string>, extension: string}[]}
*/
let changedContent = []
/**
* A list of files for which a rebuild has already been queued.
* This is used to prevent duplicate rebuilds when multiple events are fired for the same file.
* The rebuilt file is cleared from this list when it's associated rebuild has _started_
* This is because if the file is changed during a rebuild it won't trigger a new rebuild which it should
**/
let pendingRebuilds = new Set()
let _timer
let _reject
/**
* Rebuilds the changed files and resolves when the rebuild is
* complete regardless of whether it was successful or not
*/
async function rebuildAndContinue() {
let changes = changedContent.splice(0)
// There are no changes to rebuild so we can just do nothing
if (changes.length === 0) {
return Promise.resolve()
}
// Clear all pending rebuilds for the about-to-be-built files
changes.forEach((change) => pendingRebuilds.delete(change.file))
// Resolve the promise even when the rebuild fails
return rebuild(changes).then(
() => {},
(e) => {
console.error(e.toString())
}
)
}
/**
*
* @param {*} file
* @param {(() => Promise<string>) | null} content
* @param {boolean} skipPendingCheck
* @returns {Promise<void>}
*/
function recordChangedFile(file, content = null, skipPendingCheck = false) {
file = path.resolve(file)
// Applications like Vim/Neovim fire both rename and change events in succession for atomic writes
// In that case rebuild has already been queued by rename, so can be skipped in change
if (pendingRebuilds.has(file) && !skipPendingCheck) {
return Promise.resolve()
}
// Mark that a rebuild of this file is going to happen
// It MUST happen synchronously before the rebuild is queued for this to be effective
pendingRebuilds.add(file)
changedContent.push({
file,
content: content ?? (() => fs.promises.readFile(file, 'utf8')),
extension: path.extname(file).slice(1),
})
if (_timer) {
clearTimeout(_timer)
_reject()
}
// If a rebuild is already in progress we don't want to start another one until the 10ms timer has expired
chain = chain.then(
() =>
new Promise((resolve, reject) => {
_timer = setTimeout(resolve, 10)
_reject = reject
})
)
// Resolves once this file has been rebuilt (or the rebuild for this file has failed)
// This queues as many rebuilds as there are changed files
// But those rebuilds happen after some delay
// And will immediately resolve if there are no changes
chain = chain.then(rebuildAndContinue, rebuildAndContinue)
return chain
}
watcher.on('change', (file) => recordChangedFile(file))
watcher.on('add', (file) => recordChangedFile(file))
// Restore watching any files that are "removed"
// This can happen when a file is pseudo-atomically replaced (a copy is created, overwritten, the old one is unlinked, and the new one is renamed)
// TODO: An an optimization we should allow removal when the config changes
watcher.on('unlink', (file) => {
file = normalizePath(file)
// Only re-add the file if it's not covered by a dynamic pattern
if (!micromatch.some([file], state.contentPatterns.dynamic)) {
watcher.add(file)
}
})
// Some applications such as Visual Studio (but not VS Code)
// will only fire a rename event for atomic writes and not a change event
// This is very likely a chokidar bug but it's one we need to work around
// We treat this as a change event and rebuild the CSS
watcher.on('raw', (evt, filePath, meta) => {
if (evt !== 'rename' || filePath === null) {
return
}
let watchedPath = meta.watchedPath
// Watched path might be the file itself
// Or the directory it is in
filePath = watchedPath.endsWith(filePath) ? watchedPath : path.join(watchedPath, filePath)
// Skip this event since the files it is for does not match any of the registered content globs
if (!micromatch.some([filePath], state.contentPatterns.all)) {
return
}
// Skip since we've already queued a rebuild for this file that hasn't happened yet
if (pendingRebuilds.has(filePath)) {
return
}
// We'll go ahead and add the file to the pending rebuilds list here
// It'll be removed when the rebuild starts unless the read fails
// which will be taken care of as well
pendingRebuilds.add(filePath)
async function enqueue() {
try {
// We need to read the file as early as possible outside of the chain
// because it may be gone by the time we get to it. doing the read
// immediately increases the chance that the file is still there
let content = await readFileWithRetries(path.resolve(filePath))
if (content === undefined) {
return
}
// This will push the rebuild onto the chain
// We MUST skip the rebuild check here otherwise the rebuild will never happen on Linux
// This is because the order of events and timing is different on Linux
// @ts-ignore: TypeScript isn't picking up that content is a string here
await recordChangedFile(filePath, () => content, true)
} catch {
// If reading the file fails, it's was probably a deleted temporary file
// So we can ignore it and no rebuild is needed
}
}
enqueue().then(() => {
// If the file read fails we still need to make sure the file isn't stuck in the pending rebuilds list
pendingRebuilds.delete(filePath)
})
})
return {
fswatcher: watcher,
refreshWatchedFiles() {
watcher.add(Array.from(state.contextDependencies))
watcher.add(Array.from(state.configBag.dependencies))
watcher.add(state.contentPatterns.all)
},
}
}
// @ts-check
import packageJson from '../../../package.json'
export function help({ message, usage, commands, options }) {
let indent = 2
// Render header
console.log()
console.log(`${packageJson.name} v${packageJson.version}`)
// Render message
if (message) {
console.log()
for (let msg of message.split('\n')) {
console.log(msg)
}
}
// Render usage
if (usage && usage.length > 0) {
console.log()
console.log('Usage:')
for (let example of usage) {
console.log(' '.repeat(indent), example)
}
}
// Render commands
if (commands && commands.length > 0) {
console.log()
console.log('Commands:')
for (let command of commands) {
console.log(' '.repeat(indent), command)
}
}
// Render options
if (options) {
let groupedOptions = {}
for (let [key, value] of Object.entries(options)) {
if (typeof value === 'object') {
groupedOptions[key] = { ...value, flags: [key] }
} else {
groupedOptions[value].flags.push(key)
}
}
console.log()
console.log('Options:')
for (let { flags, description, deprecated } of Object.values(groupedOptions)) {
if (deprecated) continue
if (flags.length === 1) {
console.log(
' '.repeat(indent + 4 /* 4 = "-i, ".length */),
flags.slice().reverse().join(', ').padEnd(20, ' '),
description
)
} else {
console.log(
' '.repeat(indent),
flags.slice().reverse().join(', ').padEnd(24, ' '),
description
)
}
}
}
console.log()
}
#!/usr/bin/env node
import path from 'path'
import arg from 'arg'
import fs from 'fs'
import { build } from './build'
import { help } from './help'
import { init } from './init'
function oneOf(...options) {
return Object.assign(
(value = true) => {
for (let option of options) {
let parsed = option(value)
if (parsed === value) {
return parsed
}
}
throw new Error('...')
},
{ manualParsing: true }
)
}
let commands = {
init: {
run: init,
args: {
'--esm': { type: Boolean, description: `Initialize configuration file as ESM` },
'--ts': { type: Boolean, description: `Initialize configuration file as TypeScript` },
'--postcss': { type: Boolean, description: `Initialize a \`postcss.config.js\` file` },
'--full': {
type: Boolean,
description: `Include the default values for all options in the generated configuration file`,
},
'-f': '--full',
'-p': '--postcss',
},
},
build: {
run: build,
args: {
'--input': { type: String, description: 'Input file' },
'--output': { type: String, description: 'Output file' },
'--watch': {
type: oneOf(String, Boolean),
description: 'Watch for changes and rebuild as needed',
},
'--poll': {
type: Boolean,
description: 'Use polling instead of filesystem events when watching',
},
'--content': {
type: String,
description: 'Content paths to use for removing unused classes',
},
'--purge': {
type: String,
deprecated: true,
},
'--postcss': {
type: oneOf(String, Boolean),
description: 'Load custom PostCSS configuration',
},
'--minify': { type: Boolean, description: 'Minify the output' },
'--config': {
type: String,
description: 'Path to a custom config file',
},
'--no-autoprefixer': {
deprecated: true,
type: Boolean,
description: 'Disable autoprefixer',
},
'-c': '--config',
'-i': '--input',
'-o': '--output',
'-m': '--minify',
'-w': '--watch',
'-p': '--poll',
},
},
}
let sharedFlags = {
'--help': { type: Boolean, description: 'Display usage information' },
'-h': '--help',
}
if (
process.stdout.isTTY /* Detect redirecting output to a file */ &&
(process.argv[2] === undefined ||
process.argv.slice(2).every((flag) => sharedFlags[flag] !== undefined))
) {
help({
usage: [
'tailwindcss [--input input.css] [--output output.css] [--watch] [options...]',
'tailwindcss init [--full] [--postcss] [options...]',
],
commands: Object.keys(commands)
.filter((command) => command !== 'build')
.map((command) => `${command} [options]`),
options: { ...commands.build.args, ...sharedFlags },
})
process.exit(0)
}
let command = ((arg = '') => (arg.startsWith('-') ? undefined : arg))(process.argv[2]) || 'build'
if (commands[command] === undefined) {
if (fs.existsSync(path.resolve(command))) {
// TODO: Deprecate this in future versions
// Check if non-existing command, might be a file.
command = 'build'
} else {
help({
message: `Invalid command: ${command}`,
usage: ['tailwindcss <command> [options]'],
commands: Object.keys(commands)
.filter((command) => command !== 'build')
.map((command) => `${command} [options]`),
options: sharedFlags,
})
process.exit(1)
}
}
// Execute command
let { args: flags, run } = commands[command]
let args = (() => {
try {
let result = arg(
Object.fromEntries(
Object.entries({ ...flags, ...sharedFlags })
.filter(([_key, value]) => !value?.type?.manualParsing)
.map(([key, value]) => [key, typeof value === 'object' ? value.type : value])
),
{ permissive: true }
)
// Manual parsing of flags to allow for special flags like oneOf(Boolean, String)
for (let i = result['_'].length - 1; i >= 0; --i) {
let flag = result['_'][i]
if (!flag.startsWith('-')) continue
let [flagName, flagValue] = flag.split('=')
let handler = flags[flagName]
// Resolve flagName & handler
while (typeof handler === 'string') {
flagName = handler
handler = flags[handler]
}
if (!handler) continue
let args = []
let offset = i + 1
// --flag value syntax was used so we need to pull `value` from `args`
if (flagValue === undefined) {
// Parse args for current flag
while (result['_'][offset] && !result['_'][offset].startsWith('-')) {
args.push(result['_'][offset++])
}
// Cleanup manually parsed flags + args
result['_'].splice(i, 1 + args.length)
// No args were provided, use default value defined in handler
// One arg was provided, use that directly
// Multiple args were provided so pass them all in an array
flagValue = args.length === 0 ? undefined : args.length === 1 ? args[0] : args
} else {
// Remove the whole flag from the args array
result['_'].splice(i, 1)
}
// Set the resolved value in the `result` object
result[flagName] = handler.type(flagValue, flagName)
}
// Ensure that the `command` is always the first argument in the `args`.
// This is important so that we don't have to check if a default command
// (build) was used or not from within each plugin.
//
// E.g.: tailwindcss input.css -> _: ['build', 'input.css']
// E.g.: tailwindcss build input.css -> _: ['build', 'input.css']
if (result['_'][0] !== command) {
result['_'].unshift(command)
}
return result
} catch (err) {
if (err.code === 'ARG_UNKNOWN_OPTION') {
help({
message: err.message,
usage: ['tailwindcss <command> [options]'],
options: sharedFlags,
})
process.exit(1)
}
throw err
}
})()
if (args['--help']) {
help({
options: { ...flags, ...sharedFlags },
usage: [`tailwindcss ${command} [options]`],
})
process.exit(0)
}
run(args)
// @ts-check
import fs from 'fs'
import path from 'path'
function isESM() {
const pkgPath = path.resolve('./package.json')
try {
let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
return pkg.type && pkg.type === 'module'
} catch (err) {
return false
}
}
export function init(args) {
let messages = []
let isProjectESM = args['--ts'] || args['--esm'] || isESM()
let syntax = args['--ts'] ? 'ts' : isProjectESM ? 'js' : 'cjs'
let extension = args['--ts'] ? 'ts' : 'js'
let tailwindConfigLocation = path.resolve(args['_'][1] ?? `./tailwind.config.${extension}`)
if (fs.existsSync(tailwindConfigLocation)) {
messages.push(`${path.basename(tailwindConfigLocation)} already exists.`)
} else {
let stubContentsFile = fs.readFileSync(
args['--full']
? path.resolve(__dirname, '../../../stubs/config.full.js')
: path.resolve(__dirname, '../../../stubs/config.simple.js'),
'utf8'
)
let stubFile = fs.readFileSync(
path.resolve(__dirname, `../../../stubs/tailwind.config.${syntax}`),
'utf8'
)
// Change colors import
stubContentsFile = stubContentsFile.replace('../colors', 'tailwindcss/colors')
// Replace contents of {ts,js,cjs} file with the stub {simple,full}.
stubFile =
stubFile
.replace('__CONFIG__', stubContentsFile.replace('module.exports =', '').trim())
.trim() + '\n\n'
fs.writeFileSync(tailwindConfigLocation, stubFile, 'utf8')
messages.push(`Created Tailwind CSS config file: ${path.basename(tailwindConfigLocation)}`)
}
if (args['--postcss']) {
let postcssConfigLocation = path.resolve('./postcss.config.js')
if (fs.existsSync(postcssConfigLocation)) {
messages.push(`${path.basename(postcssConfigLocation)} already exists.`)
} else {
let stubFile = fs.readFileSync(
isProjectESM
? path.resolve(__dirname, '../../../stubs/postcss.config.js')
: path.resolve(__dirname, '../../../stubs/postcss.config.cjs'),
'utf8'
)
fs.writeFileSync(postcssConfigLocation, stubFile, 'utf8')
messages.push(`Created PostCSS config file: ${path.basename(postcssConfigLocation)}`)
}
}
if (messages.length > 0) {
console.log()
for (let message of messages) {
console.log(message)
}
}
}
export default ["preflight","container","accessibility","pointerEvents","visibility","position","inset","isolation","zIndex","order","gridColumn","gridColumnStart","gridColumnEnd","gridRow","gridRowStart","gridRowEnd","float","clear","margin","boxSizing","lineClamp","display","aspectRatio","size","height","maxHeight","minHeight","width","minWidth","maxWidth","flex","flexShrink","flexGrow","flexBasis","tableLayout","captionSide","borderCollapse","borderSpacing","transformOrigin","translate","rotate","skew","scale","transform","animation","cursor","touchAction","userSelect","resize","scrollSnapType","scrollSnapAlign","scrollSnapStop","scrollMargin","scrollPadding","listStylePosition","listStyleType","listStyleImage","appearance","columns","breakBefore","breakInside","breakAfter","gridAutoColumns","gridAutoFlow","gridAutoRows","gridTemplateColumns","gridTemplateRows","flexDirection","flexWrap","placeContent","placeItems","alignContent","alignItems","justifyContent","justifyItems","gap","space","divideWidth","divideStyle","divideColor","divideOpacity","placeSelf","alignSelf","justifySelf","overflow","overscrollBehavior","scrollBehavior","textOverflow","hyphens","whitespace","textWrap","wordBreak","borderRadius","borderWidth","borderStyle","borderColor","borderOpacity","backgroundColor","backgroundOpacity","backgroundImage","gradientColorStops","boxDecorationBreak","backgroundSize","backgroundAttachment","backgroundClip","backgroundPosition","backgroundRepeat","backgroundOrigin","fill","stroke","strokeWidth","objectFit","objectPosition","padding","textAlign","textIndent","verticalAlign","fontFamily","fontSize","fontWeight","textTransform","fontStyle","fontVariantNumeric","lineHeight","letterSpacing","textColor","textOpacity","textDecoration","textDecorationColor","textDecorationStyle","textDecorationThickness","textUnderlineOffset","fontSmoothing","placeholderColor","placeholderOpacity","caretColor","accentColor","opacity","backgroundBlendMode","mixBlendMode","boxShadow","boxShadowColor","outlineStyle","outlineWidth","outlineOffset","outlineColor","ringWidth","ringColor","ringOpacity","ringOffsetWidth","ringOffsetColor","blur","brightness","contrast","dropShadow","grayscale","hueRotate","invert","saturate","sepia","filter","backdropBlur","backdropBrightness","backdropContrast","backdropGrayscale","backdropHueRotate","backdropInvert","backdropOpacity","backdropSaturate","backdropSepia","backdropFilter","transitionProperty","transitionDelay","transitionDuration","transitionTimingFunction","willChange","content","forcedColorAdjust"]

Sorry, the diff of this file is too big to display

MIT License
Copyright (c) Nicolas Gallagher
Copyright (c) Jonathan Neal
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Copyright (c) Adam Wathan
Copyright (c) Jonathan Reinink
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/
*,
::before,
::after {
box-sizing: border-box; /* 1 */
border-width: 0; /* 2 */
border-style: solid; /* 2 */
border-color: theme('borderColor.DEFAULT', currentColor); /* 2 */
}
::before,
::after {
--tw-content: '';
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
6. Use the user's configured `sans` font-variation-settings by default.
7. Disable tap highlights on iOS.
*/
html,
:host {
line-height: 1.5; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-moz-tab-size: 4; /* 3 */
tab-size: 4; /* 3 */
font-family: theme('fontFamily.sans', ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); /* 4 */
font-feature-settings: theme('fontFamily.sans[1].fontFeatureSettings', normal); /* 5 */
font-variation-settings: theme('fontFamily.sans[1].fontVariationSettings', normal); /* 6 */
-webkit-tap-highlight-color: transparent; /* 7 */
}
/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/
body {
margin: 0; /* 1 */
line-height: inherit; /* 2 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/
hr {
height: 0; /* 1 */
color: inherit; /* 2 */
border-top-width: 1px; /* 3 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the user's configured `mono` font-family by default.
2. Use the user's configured `mono` font-feature-settings by default.
3. Use the user's configured `mono` font-variation-settings by default.
4. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: theme('fontFamily.mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace); /* 1 */
font-feature-settings: theme('fontFamily.mono[1].fontFeatureSettings', normal); /* 2 */
font-variation-settings: theme('fontFamily.mono[1].fontVariationSettings', normal); /* 3 */
font-size: 1em; /* 4 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
text-indent: 0; /* 1 */
border-color: inherit; /* 2 */
border-collapse: collapse; /* 3 */
}
/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-feature-settings: inherit; /* 1 */
font-variation-settings: inherit; /* 1 */
font-size: 100%; /* 1 */
font-weight: inherit; /* 1 */
line-height: inherit; /* 1 */
color: inherit; /* 1 */
margin: 0; /* 2 */
padding: 0; /* 3 */
}
/*
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button; /* 1 */
background-color: transparent; /* 2 */
background-image: none; /* 2 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring {
outline: auto;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
[type='search'] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Removes the default spacing for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
list-style: none;
margin: 0;
padding: 0;
}
dialog {
padding: 0;
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/
input::placeholder,
textarea::placeholder {
opacity: 1; /* 1 */
color: theme('colors.gray.400', #9ca3af); /* 2 */
}
/*
Set the default cursor for buttons.
*/
button,
[role="button"] {
cursor: pointer;
}
/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block; /* 1 */
vertical-align: middle; /* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
/*
Make elements with the HTML hidden attribute stay hidden by default.
*/
[hidden] {
display: none;
}
import colors from 'picocolors'
import log from './util/log'
let defaults = {
optimizeUniversalDefaults: false,
disableColorOpacityUtilitiesByDefault: false,
relativeContentPathsByDefault: false,
oxideParser: true,
logicalSiblingUtilities: false,
}
export let featureFlags = {
future: [
'hoverOnlyWhenSupported',
'respectDefaultRingColorOpacity',
'disableColorOpacityUtilitiesByDefault',
'relativeContentPathsByDefault',
'logicalSiblingUtilities',
],
experimental: ['optimizeUniversalDefaults', 'oxideParser'],
}
export function flagEnabled(config, flag) {
if (featureFlags.future.includes(flag)) {
return config.future === 'all' || (config?.future?.[flag] ?? defaults[flag] ?? false)
}
if (featureFlags.experimental.includes(flag)) {
return (
config.experimental === 'all' || (config?.experimental?.[flag] ?? defaults[flag] ?? false)
)
}
return false
}
function experimentalFlagsEnabled(config) {
if (config.experimental === 'all') {
return featureFlags.experimental
}
return Object.keys(config?.experimental ?? {}).filter(
(flag) => featureFlags.experimental.includes(flag) && config.experimental[flag]
)
}
export function issueFlagNotices(config) {
if (process.env.JEST_WORKER_ID !== undefined) {
return
}
if (experimentalFlagsEnabled(config).length > 0) {
let changes = experimentalFlagsEnabled(config)
.map((s) => colors.yellow(s))
.join(', ')
log.warn('experimental-flags-enabled', [
`You have enabled experimental features: ${changes}`,
'Experimental features in Tailwind CSS are not covered by semver, may introduce breaking changes, and can change at any time.',
])
}
}
export default featureFlags
module.exports = require('./plugin')
import crypto from 'crypto'
import * as sharedState from './sharedState'
/**
* Calculate the hash of a string.
*
* This doesn't need to be cryptographically secure or
* anything like that since it's used only to detect
* when the CSS changes to invalidate the context.
*
* This is wrapped in a try/catch because it's really dependent
* on how Node itself is build and the environment and OpenSSL
* version / build that is installed on the user's machine.
*
* Based on the environment this can just outright fail.
*
* See https://github.com/nodejs/node/issues/40455
*
* @param {string} str
*/
function getHash(str) {
try {
return crypto.createHash('md5').update(str, 'utf-8').digest('binary')
} catch (err) {
return ''
}
}
/**
* Determine if the CSS tree is different from the
* previous version for the given `sourcePath`.
*
* @param {string} sourcePath
* @param {import('postcss').Node} root
*/
export function hasContentChanged(sourcePath, root) {
let css = root.toString()
// We only care about files with @tailwind directives
// Other files use an existing context
if (!css.includes('@tailwind')) {
return false
}
let existingHash = sharedState.sourceHashMap.get(sourcePath)
let rootHash = getHash(css)
let didChange = existingHash !== rootHash
sharedState.sourceHashMap.set(sourcePath, rootHash)
return didChange
}
let comparisonMap = {
atrule: ['name', 'params'],
rule: ['selector'],
}
let types = new Set(Object.keys(comparisonMap))
export default function collapseAdjacentRules() {
function collapseRulesIn(root) {
let currentRule = null
root.each((node) => {
if (!types.has(node.type)) {
currentRule = null
return
}
if (currentRule === null) {
currentRule = node
return
}
let properties = comparisonMap[node.type]
if (node.type === 'atrule' && node.name === 'font-face') {
currentRule = node
} else if (
properties.every(
(property) =>
(node[property] ?? '').replace(/\s+/g, ' ') ===
(currentRule[property] ?? '').replace(/\s+/g, ' ')
)
) {
// An AtRule may not have children (for example if we encounter duplicate @import url(…) rules)
if (node.nodes) {
currentRule.append(node.nodes)
}
node.remove()
} else {
currentRule = node
}
})
// After we've collapsed adjacent rules & at-rules, we need to collapse
// adjacent rules & at-rules that are children of at-rules.
// We do not care about nesting rules because Tailwind CSS
// explicitly does not handle rule nesting on its own as
// the user is expected to use a nesting plugin
root.each((node) => {
if (node.type === 'atrule') {
collapseRulesIn(node)
}
})
}
return (root) => {
collapseRulesIn(root)
}
}
export default function collapseDuplicateDeclarations() {
return (root) => {
root.walkRules((node) => {
let seen = new Map()
let droppable = new Set([])
let byProperty = new Map()
node.walkDecls((decl) => {
// This could happen if we have nested selectors. In that case the
// parent will loop over all its declarations but also the declarations
// of nested rules. With this we ensure that we are shallowly checking
// declarations.
if (decl.parent !== node) {
return
}
if (seen.has(decl.prop)) {
// Exact same value as what we have seen so far
if (seen.get(decl.prop).value === decl.value) {
// Keep the last one, drop the one we've seen so far
droppable.add(seen.get(decl.prop))
// Override the existing one with the new value. This is necessary
// so that if we happen to have more than one declaration with the
// same value, that we keep removing the previous one. Otherwise we
// will only remove the *first* one.
seen.set(decl.prop, decl)
return
}
// Not the same value, so we need to check if we can merge it so
// let's collect it first.
if (!byProperty.has(decl.prop)) {
byProperty.set(decl.prop, new Set())
}
byProperty.get(decl.prop).add(seen.get(decl.prop))
byProperty.get(decl.prop).add(decl)
}
seen.set(decl.prop, decl)
})
// Drop all the duplicate declarations with the exact same value we've
// already seen so far.
for (let decl of droppable) {
decl.remove()
}
// Analyze the declarations based on its unit, drop all the declarations
// with the same unit but the last one in the list.
for (let declarations of byProperty.values()) {
let byUnit = new Map()
for (let decl of declarations) {
let unit = resolveUnit(decl.value)
if (unit === null) {
// We don't have a unit, so should never try and collapse this
// value. This is because we can't know how to do it in a correct
// way (e.g.: overrides for older browsers)
continue
}
if (!byUnit.has(unit)) {
byUnit.set(unit, new Set())
}
byUnit.get(unit).add(decl)
}
for (let declarations of byUnit.values()) {
// Get all but the last one
let removableDeclarations = Array.from(declarations).slice(0, -1)
for (let decl of removableDeclarations) {
decl.remove()
}
}
}
})
}
}
let UNITLESS_NUMBER = Symbol('unitless-number')
function resolveUnit(input) {
let result = /^-?\d*.?\d+([\w%]+)?$/g.exec(input)
if (result) {
return result[1] ?? UNITLESS_NUMBER
}
return null
}
// @ts-check
import fs from 'fs'
import path from 'path'
import isGlob from 'is-glob'
import fastGlob from 'fast-glob'
import normalizePath from 'normalize-path'
import { parseGlob } from '../util/parseGlob'
import { env } from './sharedState'
import { resolveContentPaths } from '@tailwindcss/oxide'
/** @typedef {import('../../types/config.js').RawFile} RawFile */
/** @typedef {import('../../types/config.js').FilePath} FilePath */
/*
* @param {import('tailwindcss').Config} tailwindConfig
* @param {{skip:string[]}} options
* @returns {ContentPath[]}
*/
function resolveContentFiles(tailwindConfig, { skip = [] } = {}) {
if (
Array.isArray(tailwindConfig.content.files) &&
tailwindConfig.content.files.includes('auto')
) {
let idx = tailwindConfig.content.files.indexOf('auto')
if (idx !== -1) {
env.DEBUG && console.time('Calculating resolve content paths')
let resolved = resolveContentPaths({ base: process.cwd() })
env.DEBUG && console.timeEnd('Calculating resolve content paths')
tailwindConfig.content.files.splice(idx, 1, ...resolved)
}
}
if (skip.length > 0) {
tailwindConfig.content.files = tailwindConfig.content.files.filter(
(filePath) => !skip.includes(filePath)
)
}
return tailwindConfig.content.files
}
/**
* @typedef {object} ContentPath
* @property {string} original
* @property {string} base
* @property {string | null} glob
* @property {boolean} ignore
* @property {string} pattern
*/
/**
* Turn a list of content paths (absolute or not; glob or not) into a list of
* absolute file paths that exist on the filesystem
*
* If there are symlinks in the path then multiple paths will be returned
* one for the symlink and one for the actual file
*
* @param {*} context
* @param {import('tailwindcss').Config} tailwindConfig
* @returns {ContentPath[]}
*/
export function parseCandidateFiles(context, tailwindConfig) {
let files = resolveContentFiles(tailwindConfig, {
skip: [context.userConfigPath],
})
// Normalize the file globs
files = files.filter((filePath) => typeof filePath === 'string')
files = files.map(normalizePath)
// Split into included and excluded globs
let tasks = fastGlob.generateTasks(files)
/** @type {ContentPath[]} */
let included = []
/** @type {ContentPath[]} */
let excluded = []
for (const task of tasks) {
included.push(...task.positive.map((filePath) => parseFilePath(filePath, false)))
excluded.push(...task.negative.map((filePath) => parseFilePath(filePath, true)))
}
let paths = [...included, ...excluded]
// Resolve paths relative to the config file or cwd
paths = resolveRelativePaths(context, paths)
// Resolve symlinks if possible
paths = paths.flatMap(resolvePathSymlinks)
// Update cached patterns
paths = paths.map(resolveGlobPattern)
return paths
}
/**
*
* @param {string} filePath
* @param {boolean} ignore
* @returns {ContentPath}
*/
function parseFilePath(filePath, ignore) {
let contentPath = {
original: filePath,
base: filePath,
ignore,
pattern: filePath,
glob: null,
}
if (isGlob(filePath)) {
Object.assign(contentPath, parseGlob(filePath))
}
return contentPath
}
/**
*
* @param {ContentPath} contentPath
* @returns {ContentPath}
*/
function resolveGlobPattern(contentPath) {
// This is required for Windows support to properly pick up Glob paths.
// Afaik, this technically shouldn't be needed but there's probably
// some internal, direct path matching with a normalized path in
// a package which can't handle mixed directory separators
let base = normalizePath(contentPath.base)
// If the user's file path contains any special characters (like parens) for instance fast-glob
// is like "OOOH SHINY" and treats them as such. So we have to escape the base path to fix this
base = fastGlob.escapePath(base)
contentPath.pattern = contentPath.glob ? `${base}/${contentPath.glob}` : base
contentPath.pattern = contentPath.ignore ? `!${contentPath.pattern}` : contentPath.pattern
return contentPath
}
/**
* Resolve each path relative to the config file (when possible) if the experimental flag is enabled
* Otherwise, resolve relative to the current working directory
*
* @param {any} context
* @param {ContentPath[]} contentPaths
* @returns {ContentPath[]}
*/
function resolveRelativePaths(context, contentPaths) {
let resolveFrom = []
// Resolve base paths relative to the config file (when possible) if the experimental flag is enabled
if (context.userConfigPath && context.tailwindConfig.content.relative) {
resolveFrom = [path.dirname(context.userConfigPath)]
}
return contentPaths.map((contentPath) => {
contentPath.base = path.resolve(...resolveFrom, contentPath.base)
return contentPath
})
}
/**
* Resolve the symlink for the base directory / file in each path
* These are added as additional dependencies to watch for changes because
* some tools (like webpack) will only watch the actual file or directory
* but not the symlink itself even in projects that use monorepos.
*
* @param {ContentPath} contentPath
* @returns {ContentPath[]}
*/
function resolvePathSymlinks(contentPath) {
let paths = [contentPath]
try {
let resolvedPath = fs.realpathSync(contentPath.base)
if (resolvedPath !== contentPath.base) {
paths.push({
...contentPath,
base: resolvedPath,
})
}
} catch {
// TODO: log this?
}
return paths
}
/**
* @param {any} context
* @param {ContentPath[]} candidateFiles
* @param {Map<string, number>} fileModifiedMap
* @returns {[{ content: string, extension: string }[], Map<string, number>]}
*/
export function resolvedChangedContent(context, candidateFiles, fileModifiedMap) {
let changedContent = context.tailwindConfig.content.files
.filter((item) => typeof item.raw === 'string')
.map(({ raw, extension = 'html' }) => ({ content: raw, extension }))
let [changedFiles, mTimesToCommit] = resolveChangedFiles(candidateFiles, fileModifiedMap)
for (let changedFile of changedFiles) {
let extension = path.extname(changedFile).slice(1)
changedContent.push({ file: changedFile, extension })
}
return [changedContent, mTimesToCommit]
}
/**
*
* @param {ContentPath[]} candidateFiles
* @param {Map<string, number>} fileModifiedMap
* @returns {[Set<string>, Map<string, number>]}
*/
function resolveChangedFiles(candidateFiles, fileModifiedMap) {
let paths = candidateFiles.map((contentPath) => contentPath.pattern)
let mTimesToCommit = new Map()
let changedFiles = new Set()
env.DEBUG && console.time('Finding changed files')
let files = fastGlob.sync(paths, { absolute: true })
for (let file of files) {
let prevModified = fileModifiedMap.get(file) || -Infinity
let modified = fs.statSync(file).mtimeMs
if (modified > prevModified) {
changedFiles.add(file)
mTimesToCommit.set(file, modified)
}
}
env.DEBUG && console.timeEnd('Finding changed files')
return [changedFiles, mTimesToCommit]
}
import * as regex from './regex'
export function defaultExtractor(context) {
let patterns = Array.from(buildRegExps(context))
/**
* @param {string} content
*/
return (content) => {
/** @type {(string|string)[]} */
let results = []
for (let pattern of patterns) {
for (let result of content.match(pattern) ?? []) {
results.push(clipAtBalancedParens(result))
}
}
return results
}
}
function* buildRegExps(context) {
let separator = context.tailwindConfig.separator
let prefix =
context.tailwindConfig.prefix !== ''
? regex.optional(regex.pattern([/-?/, regex.escape(context.tailwindConfig.prefix)]))
: ''
let utility = regex.any([
// Arbitrary properties (without square brackets)
/\[[^\s:'"`]+:[^\s\[\]]+\]/,
// Arbitrary properties with balanced square brackets
// This is a targeted fix to continue to allow theme()
// with square brackets to work in arbitrary properties
// while fixing a problem with the regex matching too much
/\[[^\s:'"`\]]+:[^\s]+?\[[^\s]+\][^\s]+?\]/,
// Utilities
regex.pattern([
// Utility Name / Group Name
regex.any([
/-?(?:\w+)/,
// This is here to make sure @container supports everything that other utilities do
/@(?:\w+)/,
]),
// Normal/Arbitrary values
regex.optional(
regex.any([
regex.pattern([
// Arbitrary values
regex.any([
/-(?:\w+-)*\['[^\s]+'\]/,
/-(?:\w+-)*\["[^\s]+"\]/,
/-(?:\w+-)*\[`[^\s]+`\]/,
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s:\[\]]+\]/,
]),
// Not immediately followed by an `{[(`
/(?![{([]])/,
// optionally followed by an opacity modifier
/(?:\/[^\s'"`\\><$]*)?/,
]),
regex.pattern([
// Arbitrary values
regex.any([
/-(?:\w+-)*\['[^\s]+'\]/,
/-(?:\w+-)*\["[^\s]+"\]/,
/-(?:\w+-)*\[`[^\s]+`\]/,
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s\[\]]+\]/,
]),
// Not immediately followed by an `{[(`
/(?![{([]])/,
// optionally followed by an opacity modifier
/(?:\/[^\s'"`\\$]*)?/,
]),
// Normal values w/o quotes — may include an opacity modifier
/[-\/][^\s'"`\\$={><]*/,
])
),
]),
])
let variantPatterns = [
// Without quotes
regex.any([
// This is here to provide special support for the `@` variant
regex.pattern([/@\[[^\s"'`]+\](\/[^\s"'`]+)?/, separator]),
// With variant modifier (e.g.: group-[..]/modifier)
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]\/\w+/, separator]),
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/, separator]),
regex.pattern([/[^\s"'`\[\\]+/, separator]),
]),
// With quotes allowed
regex.any([
// With variant modifier (e.g.: group-[..]/modifier)
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s`]+\]\/\w+/, separator]),
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s`]+\]/, separator]),
regex.pattern([/[^\s`\[\\]+/, separator]),
]),
]
for (const variantPattern of variantPatterns) {
yield regex.pattern([
// Variants
'((?=((',
variantPattern,
')+))\\2)?',
// Important (optional)
/!?/,
prefix,
utility,
])
}
// 5. Inner matches
yield /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g
}
// We want to capture any "special" characters
// AND the characters immediately following them (if there is one)
let SPECIALS = /([\[\]'"`])([^\[\]'"`])?/g
let ALLOWED_CLASS_CHARACTERS = /[^"'`\s<>\]]+/
/**
* Clips a string ensuring that parentheses, quotes, etc… are balanced
* Used for arbitrary values only
*
* We will go past the end of the balanced parens until we find a non-class character
*
* Depth matching behavior:
* w-[calc(100%-theme('spacing[some_key][1.5]'))]']
* ┬ ┬ ┬┬ ┬ ┬┬ ┬┬┬┬┬┬┬
* 1 2 3 4 34 3 210 END
* ╰────┴──────────┴────────┴────────┴┴───┴─┴┴┴
*
* @param {string} input
*/
function clipAtBalancedParens(input) {
// We are care about this for arbitrary values
if (!input.includes('-[')) {
return input
}
let depth = 0
let openStringTypes = []
// Find all parens, brackets, quotes, etc
// Stop when we end at a balanced pair
// This is naive and will treat mismatched parens as balanced
// This shouldn't be a problem in practice though
let matches = input.matchAll(SPECIALS)
// We can't use lookbehind assertions because we have to support Safari
// So, instead, we've emulated it using capture groups and we'll re-work the matches to accommodate
matches = Array.from(matches).flatMap((match) => {
const [, ...groups] = match
return groups.map((group, idx) =>
Object.assign([], match, {
index: match.index + idx,
0: group,
})
)
})
for (let match of matches) {
let char = match[0]
let inStringType = openStringTypes[openStringTypes.length - 1]
if (char === inStringType) {
openStringTypes.pop()
} else if (char === "'" || char === '"' || char === '`') {
openStringTypes.push(char)
}
if (inStringType) {
continue
} else if (char === '[') {
depth++
continue
} else if (char === ']') {
depth--
continue
}
// We've gone one character past the point where we should stop
// This means that there was an extra closing `]`
// We'll clip to just before it
if (depth < 0) {
return input.substring(0, match.index - 1)
}
// We've finished balancing the brackets but there still may be characters that can be included
// For example in the class `text-[#336699]/[.35]`
// The depth goes to `0` at the closing `]` but goes up again at the `[`
// If we're at zero and encounter a non-class character then we clip the class there
if (depth === 0 && !ALLOWED_CLASS_CHARACTERS.test(char)) {
return input.substring(0, match.index)
}
}
return input
}
// Regular utilities
// {{modifier}:}*{namespace}{-{suffix}}*{/{opacityModifier}}?
// Arbitrary values
// {{modifier}:}*{namespace}-[{arbitraryValue}]{/{opacityModifier}}?
// arbitraryValue: no whitespace, balanced quotes unless within quotes, balanced brackets unless within quotes
// Arbitrary properties
// {{modifier}:}*[{validCssPropertyName}:{arbitraryValue}]
function isRoot(node) {
return node.type === 'root'
}
function isAtLayer(node) {
return node.type === 'atrule' && node.name === 'layer'
}
export default function (_context) {
return (root, result) => {
let found = false
root.walkAtRules('tailwind', (node) => {
if (found) return false
if (node.parent && !(isRoot(node.parent) || isAtLayer(node.parent))) {
found = true
node.warn(
result,
[
'Nested @tailwind rules were detected, but are not supported.',
"Consider using a prefix to scope Tailwind's classes: https://tailwindcss.com/docs/configuration#prefix",
'Alternatively, use the important selector strategy: https://tailwindcss.com/docs/configuration#selector-strategy',
].join('\n')
)
return false
}
})
root.walkRules((rule) => {
if (found) return false
rule.walkRules((nestedRule) => {
found = true
nestedRule.warn(
result,
[
'Nested CSS was detected, but CSS nesting has not been configured correctly.',
'Please enable a CSS nesting plugin *before* Tailwind in your configuration.',
'See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting',
].join('\n')
)
return false
})
})
}
}
import dlv from 'dlv'
import didYouMean from 'didyoumean'
import transformThemeValue from '../util/transformThemeValue'
import parseValue from '../value-parser/index'
import { normalizeScreens } from '../util/normalizeScreens'
import buildMediaQuery from '../util/buildMediaQuery'
import { toPath } from '../util/toPath'
import { withAlphaValue } from '../util/withAlphaVariable'
import { parseColorFormat } from '../util/pluginUtils'
import log from '../util/log'
function isObject(input) {
return typeof input === 'object' && input !== null
}
function findClosestExistingPath(theme, path) {
let parts = toPath(path)
do {
parts.pop()
if (dlv(theme, parts) !== undefined) break
} while (parts.length)
return parts.length ? parts : undefined
}
function pathToString(path) {
if (typeof path === 'string') return path
return path.reduce((acc, cur, i) => {
if (cur.includes('.')) return `${acc}[${cur}]`
return i === 0 ? cur : `${acc}.${cur}`
}, '')
}
function list(items) {
return items.map((key) => `'${key}'`).join(', ')
}
function listKeys(obj) {
return list(Object.keys(obj))
}
function validatePath(config, path, defaultValue, themeOpts = {}) {
const pathString = Array.isArray(path) ? pathToString(path) : path.replace(/^['"]+|['"]+$/g, '')
const pathSegments = Array.isArray(path) ? path : toPath(pathString)
const value = dlv(config.theme, pathSegments, defaultValue)
if (value === undefined) {
let error = `'${pathString}' does not exist in your theme config.`
const parentSegments = pathSegments.slice(0, -1)
const parentValue = dlv(config.theme, parentSegments)
if (isObject(parentValue)) {
const validKeys = Object.keys(parentValue).filter(
(key) => validatePath(config, [...parentSegments, key]).isValid
)
const suggestion = didYouMean(pathSegments[pathSegments.length - 1], validKeys)
if (suggestion) {
error += ` Did you mean '${pathToString([...parentSegments, suggestion])}'?`
} else if (validKeys.length > 0) {
error += ` '${pathToString(parentSegments)}' has the following valid keys: ${list(
validKeys
)}`
}
} else {
const closestPath = findClosestExistingPath(config.theme, pathString)
if (closestPath) {
const closestValue = dlv(config.theme, closestPath)
if (isObject(closestValue)) {
error += ` '${pathToString(closestPath)}' has the following keys: ${listKeys(
closestValue
)}`
} else {
error += ` '${pathToString(closestPath)}' is not an object.`
}
} else {
error += ` Your theme has the following top-level keys: ${listKeys(config.theme)}`
}
}
return {
isValid: false,
error,
}
}
if (
!(
typeof value === 'string' ||
typeof value === 'number' ||
typeof value === 'function' ||
value instanceof String ||
value instanceof Number ||
Array.isArray(value)
)
) {
let error = `'${pathString}' was found but does not resolve to a string.`
if (isObject(value)) {
let validKeys = Object.keys(value).filter(
(key) => validatePath(config, [...pathSegments, key]).isValid
)
if (validKeys.length) {
error += ` Did you mean something like '${pathToString([...pathSegments, validKeys[0]])}'?`
}
}
return {
isValid: false,
error,
}
}
const [themeSection] = pathSegments
return {
isValid: true,
value: transformThemeValue(themeSection)(value, themeOpts),
}
}
function extractArgs(node, vNodes, functions) {
vNodes = vNodes.map((vNode) => resolveVNode(node, vNode, functions))
let args = ['']
for (let vNode of vNodes) {
if (vNode.type === 'div' && vNode.value === ',') {
args.push('')
} else {
args[args.length - 1] += parseValue.stringify(vNode)
}
}
return args
}
function resolveVNode(node, vNode, functions) {
if (vNode.type === 'function' && functions[vNode.value] !== undefined) {
let args = extractArgs(node, vNode.nodes, functions)
vNode.type = 'word'
vNode.value = functions[vNode.value](node, ...args)
}
return vNode
}
function resolveFunctions(node, input, functions) {
let hasAnyFn = Object.keys(functions).some((fn) => input.includes(`${fn}(`))
if (!hasAnyFn) return input
return parseValue(input)
.walk((vNode) => {
resolveVNode(node, vNode, functions)
})
.toString()
}
let nodeTypePropertyMap = {
atrule: 'params',
decl: 'value',
}
/**
* @param {string} path
* @returns {Iterable<[path: string, alpha: string|undefined]>}
*/
function* toPaths(path) {
// Strip quotes from beginning and end of string
// This allows the alpha value to be present inside of quotes
path = path.replace(/^['"]+|['"]+$/g, '')
let matches = path.match(/^([^\s]+)(?![^\[]*\])(?:\s*\/\s*([^\/\s]+))$/)
let alpha = undefined
yield [path, undefined]
if (matches) {
path = matches[1]
alpha = matches[2]
yield [path, alpha]
}
}
/**
*
* @param {any} config
* @param {string} path
* @param {any} defaultValue
*/
function resolvePath(config, path, defaultValue) {
const results = Array.from(toPaths(path)).map(([path, alpha]) => {
return Object.assign(validatePath(config, path, defaultValue, { opacityValue: alpha }), {
resolvedPath: path,
alpha,
})
})
return results.find((result) => result.isValid) ?? results[0]
}
export default function (context) {
let config = context.tailwindConfig
let functions = {
theme: (node, path, ...defaultValue) => {
let { isValid, value, error, alpha } = resolvePath(
config,
path,
defaultValue.length ? defaultValue : undefined
)
if (!isValid) {
let parentNode = node.parent
let candidate = parentNode?.raws.tailwind?.candidate
if (parentNode && candidate !== undefined) {
// Remove this utility from any caches
context.markInvalidUtilityNode(parentNode)
// Remove the CSS node from the markup
parentNode.remove()
// Show a warning
log.warn('invalid-theme-key-in-class', [
`The utility \`${candidate}\` contains an invalid theme value and was not generated.`,
])
return
}
throw node.error(error)
}
let maybeColor = parseColorFormat(value)
let isColorFunction = maybeColor !== undefined && typeof maybeColor === 'function'
if (alpha !== undefined || isColorFunction) {
if (alpha === undefined) {
alpha = 1.0
}
value = withAlphaValue(maybeColor, alpha, maybeColor)
}
return value
},
screen: (node, screen) => {
screen = screen.replace(/^['"]+/g, '').replace(/['"]+$/g, '')
let screens = normalizeScreens(config.theme.screens)
let screenDefinition = screens.find(({ name }) => name === screen)
if (!screenDefinition) {
throw node.error(`The '${screen}' screen does not exist in your theme.`)
}
return buildMediaQuery(screenDefinition)
},
}
return (root) => {
root.walk((node) => {
let property = nodeTypePropertyMap[node.type]
if (property === undefined) {
return
}
node[property] = resolveFunctions(node, node[property], functions)
})
}
}
import postcss from 'postcss'
import parser from 'postcss-selector-parser'
import { resolveMatches } from './generateRules'
import escapeClassName from '../util/escapeClassName'
import { applyImportantSelector } from '../util/applyImportantSelector'
import { movePseudos } from '../util/pseudoElements'
/** @typedef {Map<string, [any, import('postcss').Rule[]]>} ApplyCache */
function extractClasses(node) {
/** @type {Map<string, Set<string>>} */
let groups = new Map()
let container = postcss.root({ nodes: [node.clone()] })
container.walkRules((rule) => {
parser((selectors) => {
selectors.walkClasses((classSelector) => {
let parentSelector = classSelector.parent.toString()
let classes = groups.get(parentSelector)
if (!classes) {
groups.set(parentSelector, (classes = new Set()))
}
classes.add(classSelector.value)
})
}).processSync(rule.selector)
})
let normalizedGroups = Array.from(groups.values(), (classes) => Array.from(classes))
let classes = normalizedGroups.flat()
return Object.assign(classes, { groups: normalizedGroups })
}
let selectorExtractor = parser()
/**
* @param {string} ruleSelectors
*/
function extractSelectors(ruleSelectors) {
return selectorExtractor.astSync(ruleSelectors)
}
function extractBaseCandidates(candidates, separator) {
let baseClasses = new Set()
for (let candidate of candidates) {
baseClasses.add(candidate.split(separator).pop())
}
return Array.from(baseClasses)
}
function prefix(context, selector) {
let prefix = context.tailwindConfig.prefix
return typeof prefix === 'function' ? prefix(selector) : prefix + selector
}
function* pathToRoot(node) {
yield node
while (node.parent) {
yield node.parent
node = node.parent
}
}
/**
* Only clone the node itself and not its children
*
* @param {*} node
* @param {*} overrides
* @returns
*/
function shallowClone(node, overrides = {}) {
let children = node.nodes
node.nodes = []
let tmp = node.clone(overrides)
node.nodes = children
return tmp
}
/**
* Clone just the nodes all the way to the top that are required to represent
* this singular rule in the tree.
*
* For example, if we have CSS like this:
* ```css
* @media (min-width: 768px) {
* @supports (display: grid) {
* .foo {
* display: grid;
* grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
* }
* }
*
* @supports (backdrop-filter: blur(1px)) {
* .bar {
* backdrop-filter: blur(1px);
* }
* }
*
* .baz {
* color: orange;
* }
* }
* ```
*
* And we're cloning `.bar` it'll return a cloned version of what's required for just that single node:
*
* ```css
* @media (min-width: 768px) {
* @supports (backdrop-filter: blur(1px)) {
* .bar {
* backdrop-filter: blur(1px);
* }
* }
* }
* ```
*
* @param {import('postcss').Node} node
*/
function nestedClone(node) {
for (let parent of pathToRoot(node)) {
if (node === parent) {
continue
}
if (parent.type === 'root') {
break
}
node = shallowClone(parent, {
nodes: [node],
})
}
return node
}
/**
* @param {import('postcss').Root} root
*/
function buildLocalApplyCache(root, context) {
/** @type {ApplyCache} */
let cache = new Map()
root.walkRules((rule) => {
// Ignore rules generated by Tailwind
for (let node of pathToRoot(rule)) {
if (node.raws.tailwind?.layer !== undefined) {
return
}
}
// Clone what's required to represent this singular rule in the tree
let container = nestedClone(rule)
let sort = context.offsets.create('user')
for (let className of extractClasses(rule)) {
let list = cache.get(className) || []
cache.set(className, list)
list.push([
{
layer: 'user',
sort,
important: false,
},
container,
])
}
})
return cache
}
/**
* @returns {ApplyCache}
*/
function buildApplyCache(applyCandidates, context) {
for (let candidate of applyCandidates) {
if (context.notClassCache.has(candidate) || context.applyClassCache.has(candidate)) {
continue
}
if (context.classCache.has(candidate)) {
context.applyClassCache.set(
candidate,
context.classCache.get(candidate).map(([meta, rule]) => [meta, rule.clone()])
)
continue
}
let matches = Array.from(resolveMatches(candidate, context))
if (matches.length === 0) {
context.notClassCache.add(candidate)
continue
}
context.applyClassCache.set(candidate, matches)
}
return context.applyClassCache
}
/**
* Build a cache only when it's first used
*
* @param {() => ApplyCache} buildCacheFn
* @returns {ApplyCache}
*/
function lazyCache(buildCacheFn) {
let cache = null
return {
get: (name) => {
cache = cache || buildCacheFn()
return cache.get(name)
},
has: (name) => {
cache = cache || buildCacheFn()
return cache.has(name)
},
}
}
/**
* Take a series of multiple caches and merge
* them so they act like one large cache
*
* @param {ApplyCache[]} caches
* @returns {ApplyCache}
*/
function combineCaches(caches) {
return {
get: (name) => caches.flatMap((cache) => cache.get(name) || []),
has: (name) => caches.some((cache) => cache.has(name)),
}
}
function extractApplyCandidates(params) {
let candidates = params.split(/[\s\t\n]+/g)
if (candidates[candidates.length - 1] === '!important') {
return [candidates.slice(0, -1), true]
}
return [candidates, false]
}
function processApply(root, context, localCache) {
let applyCandidates = new Set()
// Collect all @apply rules and candidates
let applies = []
root.walkAtRules('apply', (rule) => {
let [candidates] = extractApplyCandidates(rule.params)
for (let util of candidates) {
applyCandidates.add(util)
}
applies.push(rule)
})
// Start the @apply process if we have rules with @apply in them
if (applies.length === 0) {
return
}
// Fill up some caches!
let applyClassCache = combineCaches([localCache, buildApplyCache(applyCandidates, context)])
/**
* When we have an apply like this:
*
* .abc {
* @apply hover:font-bold;
* }
*
* What we essentially will do is resolve to this:
*
* .abc {
* @apply .hover\:font-bold:hover {
* font-weight: 500;
* }
* }
*
* Notice that the to-be-applied class is `.hover\:font-bold:hover` and that the utility candidate was `hover:font-bold`.
* What happens in this function is that we prepend a `.` and escape the candidate.
* This will result in `.hover\:font-bold`
* Which means that we can replace `.hover\:font-bold` with `.abc` in `.hover\:font-bold:hover` resulting in `.abc:hover`
*
* @param {string} selector
* @param {string} utilitySelectors
* @param {string} candidate
*/
function replaceSelector(selector, utilitySelectors, candidate) {
let selectorList = extractSelectors(selector)
let utilitySelectorsList = extractSelectors(utilitySelectors)
let candidateList = extractSelectors(`.${escapeClassName(candidate)}`)
let candidateClass = candidateList.nodes[0].nodes[0]
selectorList.each((sel) => {
/** @type {Set<import('postcss-selector-parser').Selector>} */
let replaced = new Set()
utilitySelectorsList.each((utilitySelector) => {
let hasReplaced = false
utilitySelector = utilitySelector.clone()
utilitySelector.walkClasses((node) => {
if (node.value !== candidateClass.value) {
return
}
// Don't replace multiple instances of the same class
// This is theoretically correct but only partially
// We'd need to generate every possible permutation of the replacement
// For example with `.foo + .foo { … }` and `section { @apply foo; }`
// We'd need to generate all of these:
// - `.foo + .foo`
// - `.foo + section`
// - `section + .foo`
// - `section + section`
if (hasReplaced) {
return
}
// Since you can only `@apply` class names this is sufficient
// We want to replace the matched class name with the selector the user is using
// Ex: Replace `.text-blue-500` with `.foo.bar:is(.something-cool)`
node.replaceWith(...sel.nodes.map((node) => node.clone()))
// Record that we did something and we want to use this new selector
replaced.add(utilitySelector)
hasReplaced = true
})
})
// Sort tag names before class names (but only sort each group (separated by a combinator)
// separately and not in total)
// This happens when replacing `.bar` in `.foo.bar` with a tag like `section`
for (let sel of replaced) {
let groups = [[]]
for (let node of sel.nodes) {
if (node.type === 'combinator') {
groups.push(node)
groups.push([])
} else {
let last = groups[groups.length - 1]
last.push(node)
}
}
sel.nodes = []
for (let group of groups) {
if (Array.isArray(group)) {
group.sort((a, b) => {
if (a.type === 'tag' && b.type === 'class') {
return -1
} else if (a.type === 'class' && b.type === 'tag') {
return 1
} else if (a.type === 'class' && b.type === 'pseudo' && b.value.startsWith('::')) {
return -1
} else if (a.type === 'pseudo' && a.value.startsWith('::') && b.type === 'class') {
return 1
}
return 0
})
}
sel.nodes = sel.nodes.concat(group)
}
}
sel.replaceWith(...replaced)
})
return selectorList.toString()
}
let perParentApplies = new Map()
// Collect all apply candidates and their rules
for (let apply of applies) {
let [candidates] = perParentApplies.get(apply.parent) || [[], apply.source]
perParentApplies.set(apply.parent, [candidates, apply.source])
let [applyCandidates, important] = extractApplyCandidates(apply.params)
if (apply.parent.type === 'atrule') {
if (apply.parent.name === 'screen') {
let screenType = apply.parent.params
throw apply.error(
`@apply is not supported within nested at-rules like @screen. We suggest you write this as @apply ${applyCandidates
.map((c) => `${screenType}:${c}`)
.join(' ')} instead.`
)
}
throw apply.error(
`@apply is not supported within nested at-rules like @${apply.parent.name}. You can fix this by un-nesting @${apply.parent.name}.`
)
}
for (let applyCandidate of applyCandidates) {
if ([prefix(context, 'group'), prefix(context, 'peer')].includes(applyCandidate)) {
// TODO: Link to specific documentation page with error code.
throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`)
}
if (!applyClassCache.has(applyCandidate)) {
throw apply.error(
`The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.`
)
}
let rules = applyClassCache.get(applyCandidate)
candidates.push([applyCandidate, important, rules])
}
}
for (let [parent, [candidates, atApplySource]] of perParentApplies) {
let siblings = []
for (let [applyCandidate, important, rules] of candidates) {
let potentialApplyCandidates = [
applyCandidate,
...extractBaseCandidates([applyCandidate], context.tailwindConfig.separator),
]
for (let [meta, node] of rules) {
let parentClasses = extractClasses(parent)
let nodeClasses = extractClasses(node)
// When we encounter a rule like `.dark .a, .b { … }` we only want to be left with `[.dark, .a]` if the base applyCandidate is `.a` or with `[.b]` if the base applyCandidate is `.b`
// So we've split them into groups
nodeClasses = nodeClasses.groups
.filter((classList) =>
classList.some((className) => potentialApplyCandidates.includes(className))
)
.flat()
// Add base utility classes from the @apply node to the list of
// classes to check whether it intersects and therefore results in a
// circular dependency or not.
//
// E.g.:
// .foo {
// @apply hover:a; // This applies "a" but with a modifier
// }
//
// We only have to do that with base classes of the `node`, not of the `parent`
// E.g.:
// .hover\:foo {
// @apply bar;
// }
// .bar {
// @apply foo;
// }
//
// This should not result in a circular dependency because we are
// just applying `.foo` and the rule above is `.hover\:foo` which is
// unrelated. However, if we were to apply `hover:foo` then we _did_
// have to include this one.
nodeClasses = nodeClasses.concat(
extractBaseCandidates(nodeClasses, context.tailwindConfig.separator)
)
let intersects = parentClasses.some((selector) => nodeClasses.includes(selector))
if (intersects) {
throw node.error(
`You cannot \`@apply\` the \`${applyCandidate}\` utility here because it creates a circular dependency.`
)
}
let root = postcss.root({ nodes: [node.clone()] })
// Make sure every node in the entire tree points back at the @apply rule that generated it
root.walk((node) => {
node.source = atApplySource
})
let canRewriteSelector =
node.type !== 'atrule' || (node.type === 'atrule' && node.name !== 'keyframes')
if (canRewriteSelector) {
root.walkRules((rule) => {
// Let's imagine you have the following structure:
//
// .foo {
// @apply bar;
// }
//
// @supports (a: b) {
// .bar {
// color: blue
// }
//
// .something-unrelated {}
// }
//
// In this case we want to apply `.bar` but it happens to be in
// an atrule node. We clone that node instead of the nested one
// because we still want that @supports rule to be there once we
// applied everything.
//
// However it happens to be that the `.something-unrelated` is
// also in that same shared @supports atrule. This is not good,
// and this should not be there. The good part is that this is
// a clone already and it can be safely removed. The question is
// how do we know we can remove it. Basically what we can do is
// match it against the applyCandidate that you want to apply. If
// it doesn't match the we can safely delete it.
//
// If we didn't do this, then the `replaceSelector` function
// would have replaced this with something that didn't exist and
// therefore it removed the selector altogether. In this specific
// case it would result in `{}` instead of `.something-unrelated {}`
if (!extractClasses(rule).some((candidate) => candidate === applyCandidate)) {
rule.remove()
return
}
// Strip the important selector from the parent selector if at the beginning
let importantSelector =
typeof context.tailwindConfig.important === 'string'
? context.tailwindConfig.important
: null
// We only want to move the "important" selector if this is a Tailwind-generated utility
// We do *not* want to do this for user CSS that happens to be structured the same
let isGenerated = parent.raws.tailwind !== undefined
let parentSelector =
isGenerated && importantSelector && parent.selector.indexOf(importantSelector) === 0
? parent.selector.slice(importantSelector.length)
: parent.selector
// If the selector becomes empty after replacing the important selector
// This means that it's the same as the parent selector and we don't want to replace it
// Otherwise we'll crash
if (parentSelector === '') {
parentSelector = parent.selector
}
rule.selector = replaceSelector(parentSelector, rule.selector, applyCandidate)
// And then re-add it if it was removed
if (importantSelector && parentSelector !== parent.selector) {
rule.selector = applyImportantSelector(rule.selector, importantSelector)
}
rule.walkDecls((d) => {
d.important = meta.important || important
})
// Move pseudo elements to the end of the selector (if necessary)
let selector = parser().astSync(rule.selector)
selector.each((sel) => movePseudos(sel))
rule.selector = selector.toString()
})
}
// It could be that the node we were inserted was removed because the class didn't match
// If that was the *only* rule in the parent, then we have nothing add so we skip it
if (!root.nodes[0]) {
continue
}
// Insert it
siblings.push([meta.sort, root.nodes[0]])
}
}
// Inject the rules, sorted, correctly
let nodes = context.offsets.sort(siblings).map((s) => s[1])
// `parent` refers to the node at `.abc` in: .abc { @apply mt-2 }
parent.after(nodes)
}
for (let apply of applies) {
// If there are left-over declarations, just remove the @apply
if (apply.parent.nodes.length > 1) {
apply.remove()
} else {
// The node is empty, drop the full node
apply.parent.remove()
}
}
// Do it again, in case we have other `@apply` rules
processApply(root, context, localCache)
}
export default function expandApplyAtRules(context) {
return (root) => {
// Build a cache of the user's CSS so we can use it to resolve classes used by @apply
let localCache = lazyCache(() => buildLocalApplyCache(root, context))
processApply(root, context, localCache)
}
}
import fs from 'fs'
import LRU from '@alloc/quick-lru'
import { parseCandidateStrings, IO, Parsing } from '@tailwindcss/oxide'
import * as sharedState from './sharedState'
import { generateRules } from './generateRules'
import log from '../util/log'
import cloneNodes from '../util/cloneNodes'
import { defaultExtractor } from './defaultExtractor'
import { flagEnabled } from '../featureFlags'
let env = sharedState.env
const builtInExtractors = {
DEFAULT: defaultExtractor,
}
const builtInTransformers = {
DEFAULT: (content) => content,
svelte: (content) => content.replace(/(?:^|\s)class:/g, ' '),
}
function getExtractor(context, fileExtension) {
let extractors = context.tailwindConfig.content.extract
return (
extractors[fileExtension] ||
extractors.DEFAULT ||
builtInExtractors[fileExtension] ||
// Because we call `DEFAULT(context)`, the returning function is always a new function without a
// stable identity. Marking it with `DEFAULT_EXTRACTOR` allows us to check if it is the default
// extractor without relying on the function identity.
Object.assign(builtInExtractors.DEFAULT(context), { DEFAULT_EXTRACTOR: true })
)
}
function getTransformer(tailwindConfig, fileExtension) {
let transformers = tailwindConfig.content.transform
return (
transformers[fileExtension] ||
transformers.DEFAULT ||
builtInTransformers[fileExtension] ||
builtInTransformers.DEFAULT
)
}
let extractorCache = new WeakMap()
// Scans template contents for possible classes. This is a hot path on initial build but
// not too important for subsequent builds. The faster the better though — if we can speed
// up these regexes by 50% that could cut initial build time by like 20%.
function getClassCandidates(content, extractor, candidates, seen) {
if (!extractorCache.has(extractor)) {
extractorCache.set(extractor, new LRU({ maxSize: 25000 }))
}
for (let line of content.split('\n')) {
line = line.trim()
if (seen.has(line)) {
continue
}
seen.add(line)
if (extractorCache.get(extractor).has(line)) {
for (let match of extractorCache.get(extractor).get(line)) {
candidates.add(match)
}
} else {
let extractorMatches = extractor(line).filter((s) => s !== '!*')
let lineMatchesSet = new Set(extractorMatches)
for (let match of lineMatchesSet) {
candidates.add(match)
}
extractorCache.get(extractor).set(line, lineMatchesSet)
}
}
}
/**
*
* @param {[import('./offsets.js').RuleOffset, import('postcss').Node][]} rules
* @param {*} context
*/
function buildStylesheet(rules, context) {
let sortedRules = context.offsets.sort(rules)
let returnValue = {
base: new Set(),
defaults: new Set(),
components: new Set(),
utilities: new Set(),
variants: new Set(),
}
for (let [sort, rule] of sortedRules) {
returnValue[sort.layer].add(rule)
}
return returnValue
}
export default function expandTailwindAtRules(context) {
return async (root) => {
let layerNodes = {
base: null,
components: null,
utilities: null,
variants: null,
}
root.walkAtRules((rule) => {
// Make sure this file contains Tailwind directives. If not, we can save
// a lot of work and bail early. Also we don't have to register our touch
// file as a dependency since the output of this CSS does not depend on
// the source of any templates. Think Vue <style> blocks for example.
if (rule.name === 'tailwind') {
if (Object.keys(layerNodes).includes(rule.params)) {
layerNodes[rule.params] = rule
}
}
})
if (Object.values(layerNodes).every((n) => n === null)) {
return root
}
// ---
// Find potential rules in changed files
let candidates = new Set([...(context.candidates ?? []), sharedState.NOT_ON_DEMAND])
let seen = new Set()
env.DEBUG && console.time('Reading changed files')
/** @type {[item: {file?: string, content?: string}, meta: {transformer: any, extractor: any}][]} */
let regexParserContent = []
/** @type {{file?: string, content?: string}[]} */
let rustParserContent = []
for (let item of context.changedContent) {
let transformer = getTransformer(context.tailwindConfig, item.extension)
let extractor = getExtractor(context, item.extension)
if (
flagEnabled(context.tailwindConfig, 'oxideParser') &&
transformer === builtInTransformers.DEFAULT &&
extractor?.DEFAULT_EXTRACTOR === true
) {
rustParserContent.push(item)
} else {
regexParserContent.push([item, { transformer, extractor }])
}
}
// Read files using our newer, faster parser when:
// - Oxide is enabled; AND
// - The file is using default transfomers and extractors
if (rustParserContent.length > 0) {
for (let candidate of parseCandidateStrings(
rustParserContent,
IO.Parallel | Parsing.Parallel
)) {
candidates.add(candidate)
}
}
// Otherwise, read any files in node and parse with regexes
const BATCH_SIZE = 500
for (let i = 0; i < regexParserContent.length; i += BATCH_SIZE) {
let batch = regexParserContent.slice(i, i + BATCH_SIZE)
await Promise.all(
batch.map(async ([{ file, content }, { transformer, extractor }]) => {
content = file ? await fs.promises.readFile(file, 'utf8') : content
getClassCandidates(transformer(content), extractor, candidates, seen)
})
)
}
env.DEBUG && console.timeEnd('Reading changed files')
// ---
// Generate the actual CSS
let classCacheCount = context.classCache.size
env.DEBUG && console.time('Generate rules')
env.DEBUG && console.time('Sorting candidates')
// TODO: only sort if we are not using the oxide parser (flagEnabled(context.tailwindConfig,
// 'oxideParser')) AND if we got all the candidates form the oxideParser alone. This will not
// be the case currently if you have custom transformers / extractors.
let sortedCandidates = new Set(
[...candidates].sort((a, z) => {
if (a === z) return 0
if (a < z) return -1
return 1
})
)
env.DEBUG && console.timeEnd('Sorting candidates')
generateRules(sortedCandidates, context)
env.DEBUG && console.timeEnd('Generate rules')
// We only ever add to the classCache, so if it didn't grow, there is nothing new.
env.DEBUG && console.time('Build stylesheet')
if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
context.stylesheetCache = buildStylesheet([...context.ruleCache], context)
}
env.DEBUG && console.timeEnd('Build stylesheet')
let {
defaults: defaultNodes,
base: baseNodes,
components: componentNodes,
utilities: utilityNodes,
variants: screenNodes,
} = context.stylesheetCache
// ---
// Replace any Tailwind directives with generated CSS
if (layerNodes.base) {
layerNodes.base.before(
cloneNodes([...baseNodes, ...defaultNodes], layerNodes.base.source, {
layer: 'base',
})
)
layerNodes.base.remove()
}
if (layerNodes.components) {
layerNodes.components.before(
cloneNodes([...componentNodes], layerNodes.components.source, {
layer: 'components',
})
)
layerNodes.components.remove()
}
if (layerNodes.utilities) {
layerNodes.utilities.before(
cloneNodes([...utilityNodes], layerNodes.utilities.source, {
layer: 'utilities',
})
)
layerNodes.utilities.remove()
}
// We do post-filtering to not alter the emitted order of the variants
const variantNodes = Array.from(screenNodes).filter((node) => {
const parentLayer = node.raws.tailwind?.parentLayer
if (parentLayer === 'components') {
return layerNodes.components !== null
}
if (parentLayer === 'utilities') {
return layerNodes.utilities !== null
}
return true
})
if (layerNodes.variants) {
layerNodes.variants.before(
cloneNodes(variantNodes, layerNodes.variants.source, {
layer: 'variants',
})
)
layerNodes.variants.remove()
} else if (variantNodes.length > 0) {
let cloned = cloneNodes(variantNodes, undefined, {
layer: 'variants',
})
cloned.forEach((node) => {
let parentLayer = node.raws.tailwind?.parentLayer ?? null
node.walk((n) => {
if (!n.source) {
n.source = layerNodes[parentLayer].source
}
})
})
root.append(cloned)
}
// TODO: Why is the root node having no source location for `end` possible?
root.source.end = root.source.end ?? root.source.start
// If we've got a utility layer and no utilities are generated there's likely something wrong
const hasUtilityVariants = variantNodes.some(
(node) => node.raws.tailwind?.parentLayer === 'utilities'
)
if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
log.warn('content-problems', [
'No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.',
'https://tailwindcss.com/docs/content-configuration',
])
}
// ---
if (env.DEBUG) {
console.log('Potential classes: ', candidates.size)
console.log('Active contexts: ', sharedState.contextSourcesMap.size)
}
// Clear the cache for the changed files
context.changedContent = []
// Cleanup any leftover @layer atrules
root.walkAtRules('layer', (rule) => {
if (Object.keys(layerNodes).includes(rule.params)) {
rule.remove()
}
})
}
}
import fs from 'fs'
import path from 'path'
/**
* Find the @config at-rule in the given CSS AST and return the relative path to the config file
*
* @param {import('postcss').Root} root
* @param {import('postcss').Result} result
*/
export function findAtConfigPath(root, result) {
let configPath = null
let relativeTo = null
root.walkAtRules('config', (rule) => {
relativeTo = rule.source?.input.file ?? result.opts.from ?? null
if (relativeTo === null) {
throw rule.error(
'The `@config` directive cannot be used without setting `from` in your PostCSS config.'
)
}
if (configPath) {
throw rule.error('Only one `@config` directive is allowed per file.')
}
let matches = rule.params.match(/(['"])(.*?)\1/)
if (!matches) {
throw rule.error('A path is required when using the `@config` directive.')
}
let inputPath = matches[2]
if (path.isAbsolute(inputPath)) {
throw rule.error('The `@config` directive cannot be used with an absolute path.')
}
configPath = path.resolve(path.dirname(relativeTo), inputPath)
if (!fs.existsSync(configPath)) {
throw rule.error(
`The config file at "${inputPath}" does not exist. Make sure the path is correct and the file exists.`
)
}
rule.remove()
})
return configPath ? configPath : null
}
import postcss from 'postcss'
import selectorParser from 'postcss-selector-parser'
import parseObjectStyles from '../util/parseObjectStyles'
import isPlainObject from '../util/isPlainObject'
import prefixSelector from '../util/prefixSelector'
import { updateAllClasses, getMatchingTypes } from '../util/pluginUtils'
import log from '../util/log'
import * as sharedState from './sharedState'
import {
formatVariantSelector,
finalizeSelector,
eliminateIrrelevantSelectors,
} from '../util/formatVariantSelector'
import { asClass } from '../util/nameClass'
import { normalize } from '../util/dataTypes'
import { isValidVariantFormatString, parseVariant, INTERNAL_FEATURES } from './setupContextUtils'
import isValidArbitraryValue from '../util/isSyntacticallyValidPropertyValue'
import { splitAtTopLevelOnly } from '../util/splitAtTopLevelOnly.js'
import { applyImportantSelector } from '../util/applyImportantSelector'
let classNameParser = selectorParser((selectors) => {
return selectors.first.filter(({ type }) => type === 'class').pop().value
})
export function getClassNameFromSelector(selector) {
return classNameParser.transformSync(selector)
}
// Generate match permutations for a class candidate, like:
// ['ring-offset-blue', '100']
// ['ring-offset', 'blue-100']
// ['ring', 'offset-blue-100']
// Example with dynamic classes:
// ['grid-cols', '[[linename],1fr,auto]']
// ['grid', 'cols-[[linename],1fr,auto]']
function* candidatePermutations(candidate) {
let lastIndex = Infinity
while (lastIndex >= 0) {
let dashIdx
let wasSlash = false
if (lastIndex === Infinity && candidate.endsWith(']')) {
let bracketIdx = candidate.indexOf('[')
// If character before `[` isn't a dash or a slash, this isn't a dynamic class
// e.g. string[]
if (candidate[bracketIdx - 1] === '-') {
dashIdx = bracketIdx - 1
} else if (candidate[bracketIdx - 1] === '/') {
dashIdx = bracketIdx - 1
wasSlash = true
} else {
dashIdx = -1
}
} else if (lastIndex === Infinity && candidate.includes('/')) {
dashIdx = candidate.lastIndexOf('/')
wasSlash = true
} else {
dashIdx = candidate.lastIndexOf('-', lastIndex)
}
if (dashIdx < 0) {
break
}
let prefix = candidate.slice(0, dashIdx)
let modifier = candidate.slice(wasSlash ? dashIdx : dashIdx + 1)
lastIndex = dashIdx - 1
// TODO: This feels a bit hacky
if (prefix === '' || modifier === '/') {
continue
}
yield [prefix, modifier]
}
}
function applyPrefix(matches, context) {
if (matches.length === 0 || context.tailwindConfig.prefix === '') {
return matches
}
for (let match of matches) {
let [meta] = match
if (meta.options.respectPrefix) {
let container = postcss.root({ nodes: [match[1].clone()] })
let classCandidate = match[1].raws.tailwind.classCandidate
container.walkRules((r) => {
// If this is a negative utility with a dash *before* the prefix we
// have to ensure that the generated selector matches the candidate
// Not doing this will cause `-tw-top-1` to generate the class `.tw--top-1`
// The disconnect between candidate <-> class can cause @apply to hard crash.
let shouldPrependNegative = classCandidate.startsWith('-')
r.selector = prefixSelector(
context.tailwindConfig.prefix,
r.selector,
shouldPrependNegative
)
})
match[1] = container.nodes[0]
}
}
return matches
}
function applyImportant(matches, classCandidate) {
if (matches.length === 0) {
return matches
}
let result = []
function isInKeyframes(rule) {
return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === 'keyframes'
}
for (let [meta, rule] of matches) {
let container = postcss.root({ nodes: [rule.clone()] })
container.walkRules((r) => {
// Declarations inside keyframes cannot be marked as important
// They will be ignored by the browser
if (isInKeyframes(r)) {
return
}
let ast = selectorParser().astSync(r.selector)
// Remove extraneous selectors that do not include the base candidate
ast.each((sel) => eliminateIrrelevantSelectors(sel, classCandidate))
// Update all instances of the base candidate to include the important marker
updateAllClasses(ast, (className) =>
className === classCandidate ? `!${className}` : className
)
r.selector = ast.toString()
r.walkDecls((d) => (d.important = true))
})
result.push([{ ...meta, important: true }, container.nodes[0]])
}
return result
}
// Takes a list of rule tuples and applies a variant like `hover`, sm`,
// whatever to it. We used to do some extra caching here to avoid generating
// a variant of the same rule more than once, but this was never hit because
// we cache at the entire selector level further up the tree.
//
// Technically you can get a cache hit if you have `hover:focus:text-center`
// and `focus:hover:text-center` in the same project, but it doesn't feel
// worth the complexity for that case.
function applyVariant(variant, matches, context) {
if (matches.length === 0) {
return matches
}
/** @type {{modifier: string | null, value: string | null}} */
let args = { modifier: null, value: sharedState.NONE }
// Retrieve "modifier"
{
let [baseVariant, ...modifiers] = splitAtTopLevelOnly(variant, '/')
// This is a hack to support variants with `/` in them, like `ar-1/10/20:text-red-500`
// In this case 1/10 is a value but /20 is a modifier
if (modifiers.length > 1) {
baseVariant = baseVariant + '/' + modifiers.slice(0, -1).join('/')
modifiers = modifiers.slice(-1)
}
if (modifiers.length && !context.variantMap.has(variant)) {
variant = baseVariant
args.modifier = modifiers[0]
}
}
// Retrieve "arbitrary value"
if (variant.endsWith(']') && !variant.startsWith('[')) {
// We either have:
// @[200px]
// group-[:hover]
//
// But we don't want:
// @-[200px] (`-` is incorrect)
// group[:hover] (`-` is missing)
let match = /(.)(-?)\[(.*)\]/g.exec(variant)
if (match) {
let [, char, separator, value] = match
// @-[200px] case
if (char === '@' && separator === '-') return []
// group[:hover] case
if (char !== '@' && separator === '') return []
variant = variant.replace(`${separator}[${value}]`, '')
args.value = value
}
}
// Register arbitrary variants
if (isArbitraryValue(variant) && !context.variantMap.has(variant)) {
let sort = context.offsets.recordVariant(variant)
let selector = normalize(variant.slice(1, -1))
let selectors = splitAtTopLevelOnly(selector, ',')
// We do not support multiple selectors for arbitrary variants
if (selectors.length > 1) {
return []
}
if (!selectors.every(isValidVariantFormatString)) {
return []
}
let records = selectors.map((sel, idx) => [
context.offsets.applyParallelOffset(sort, idx),
parseVariant(sel.trim()),
])
context.variantMap.set(variant, records)
}
if (context.variantMap.has(variant)) {
let isArbitraryVariant = isArbitraryValue(variant)
let internalFeatures = context.variantOptions.get(variant)?.[INTERNAL_FEATURES] ?? {}
let variantFunctionTuples = context.variantMap.get(variant).slice()
let result = []
let respectPrefix = (() => {
if (isArbitraryVariant) return false
if (internalFeatures.respectPrefix === false) return false
return true
})()
for (let [meta, rule] of matches) {
// Don't generate variants for user css
if (meta.layer === 'user') {
continue
}
let container = postcss.root({ nodes: [rule.clone()] })
for (let [variantSort, variantFunction, containerFromArray] of variantFunctionTuples) {
let clone = (containerFromArray ?? container).clone()
let collectedFormats = []
function prepareBackup() {
// Already prepared, chicken out
if (clone.raws.neededBackup) {
return
}
clone.raws.neededBackup = true
clone.walkRules((rule) => (rule.raws.originalSelector = rule.selector))
}
function modifySelectors(modifierFunction) {
prepareBackup()
clone.each((rule) => {
if (rule.type !== 'rule') {
return
}
rule.selectors = rule.selectors.map((selector) => {
return modifierFunction({
get className() {
return getClassNameFromSelector(selector)
},
selector,
})
})
})
return clone
}
let ruleWithVariant = variantFunction({
// Public API
get container() {
prepareBackup()
return clone
},
separator: context.tailwindConfig.separator,
modifySelectors,
// Private API for now
wrap(wrapper) {
let nodes = clone.nodes
clone.removeAll()
wrapper.append(nodes)
clone.append(wrapper)
},
format(selectorFormat) {
collectedFormats.push({
format: selectorFormat,
respectPrefix,
})
},
args,
})
// It can happen that a list of format strings is returned from within the function. In that
// case, we have to process them as well. We can use the existing `variantSort`.
if (Array.isArray(ruleWithVariant)) {
for (let [idx, variantFunction] of ruleWithVariant.entries()) {
// This is a little bit scary since we are pushing to an array of items that we are
// currently looping over. However, you can also think of it like a processing queue
// where you keep handling jobs until everything is done and each job can queue more
// jobs if needed.
variantFunctionTuples.push([
context.offsets.applyParallelOffset(variantSort, idx),
variantFunction,
// If the clone has been modified we have to pass that back
// though so each rule can use the modified container
clone.clone(),
])
}
continue
}
if (typeof ruleWithVariant === 'string') {
collectedFormats.push({
format: ruleWithVariant,
respectPrefix,
})
}
if (ruleWithVariant === null) {
continue
}
// We had to backup selectors, therefore we assume that somebody touched
// `container` or `modifySelectors`. Let's see if they did, so that we
// can restore the selectors, and collect the format strings.
if (clone.raws.neededBackup) {
delete clone.raws.neededBackup
clone.walkRules((rule) => {
let before = rule.raws.originalSelector
if (!before) return
delete rule.raws.originalSelector
if (before === rule.selector) return // No mutation happened
let modified = rule.selector
// Rebuild the base selector, this is what plugin authors would do
// as well. E.g.: `${variant}${separator}${className}`.
// However, plugin authors probably also prepend or append certain
// classes, pseudos, ids, ...
let rebuiltBase = selectorParser((selectors) => {
selectors.walkClasses((classNode) => {
classNode.value = `${variant}${context.tailwindConfig.separator}${classNode.value}`
})
}).processSync(before)
// Now that we know the original selector, the new selector, and
// the rebuild part in between, we can replace the part that plugin
// authors need to rebuild with `&`, and eventually store it in the
// collectedFormats. Similar to what `format('...')` would do.
//
// E.g.:
// variant: foo
// selector: .markdown > p
// modified (by plugin): .foo .foo\\:markdown > p
// rebuiltBase (internal): .foo\\:markdown > p
// format: .foo &
collectedFormats.push({
format: modified.replace(rebuiltBase, '&'),
respectPrefix,
})
rule.selector = before
})
}
// This tracks the originating layer for the variant
// For example:
// .sm:underline {} is a variant of something in the utilities layer
// .sm:container {} is a variant of the container component
clone.nodes[0].raws.tailwind = { ...clone.nodes[0].raws.tailwind, parentLayer: meta.layer }
let withOffset = [
{
...meta,
sort: context.offsets.applyVariantOffset(
meta.sort,
variantSort,
Object.assign(args, context.variantOptions.get(variant))
),
collectedFormats: (meta.collectedFormats ?? []).concat(collectedFormats),
},
clone.nodes[0],
]
result.push(withOffset)
}
}
return result
}
return []
}
function parseRules(rule, cache, options = {}) {
// PostCSS node
if (!isPlainObject(rule) && !Array.isArray(rule)) {
return [[rule], options]
}
// Tuple
if (Array.isArray(rule)) {
return parseRules(rule[0], cache, rule[1])
}
// Simple object
if (!cache.has(rule)) {
cache.set(rule, parseObjectStyles(rule))
}
return [cache.get(rule), options]
}
const IS_VALID_PROPERTY_NAME = /^[a-z_-]/
function isValidPropName(name) {
return IS_VALID_PROPERTY_NAME.test(name)
}
/**
* @param {string} declaration
* @returns {boolean}
*/
function looksLikeUri(declaration) {
// Quick bailout for obvious non-urls
// This doesn't support schemes that don't use a leading // but that's unlikely to be a problem
if (!declaration.includes('://')) {
return false
}
try {
const url = new URL(declaration)
return url.scheme !== '' && url.host !== ''
} catch (err) {
// Definitely not a valid url
return false
}
}
function isParsableNode(node) {
let isParsable = true
node.walkDecls((decl) => {
if (!isParsableCssValue(decl.prop, decl.value)) {
isParsable = false
return false
}
})
return isParsable
}
function isParsableCssValue(property, value) {
// We don't want to treat [https://example.com] as a custom property
// Even though, according to the CSS grammar, it's a totally valid CSS declaration
// So we short-circuit here by checking if the custom property looks like a URL
if (looksLikeUri(`${property}:${value}`)) {
return false
}
try {
postcss.parse(`a{${property}:${value}}`).toResult()
return true
} catch (err) {
return false
}
}
function extractArbitraryProperty(classCandidate, context) {
let [, property, value] = classCandidate.match(/^\[([a-zA-Z0-9-_]+):(\S+)\]$/) ?? []
if (value === undefined) {
return null
}
if (!isValidPropName(property)) {
return null
}
if (!isValidArbitraryValue(value)) {
return null
}
let normalized = normalize(value, { property })
if (!isParsableCssValue(property, normalized)) {
return null
}
let sort = context.offsets.arbitraryProperty()
return [
[
{ sort, layer: 'utilities' },
() => ({
[asClass(classCandidate)]: {
[property]: normalized,
},
}),
],
]
}
function* resolveMatchedPlugins(classCandidate, context) {
if (context.candidateRuleMap.has(classCandidate)) {
yield [context.candidateRuleMap.get(classCandidate), 'DEFAULT']
}
yield* (function* (arbitraryPropertyRule) {
if (arbitraryPropertyRule !== null) {
yield [arbitraryPropertyRule, 'DEFAULT']
}
})(extractArbitraryProperty(classCandidate, context))
let candidatePrefix = classCandidate
let negative = false
const twConfigPrefix = context.tailwindConfig.prefix
const twConfigPrefixLen = twConfigPrefix.length
const hasMatchingPrefix =
candidatePrefix.startsWith(twConfigPrefix) || candidatePrefix.startsWith(`-${twConfigPrefix}`)
if (candidatePrefix[twConfigPrefixLen] === '-' && hasMatchingPrefix) {
negative = true
candidatePrefix = twConfigPrefix + candidatePrefix.slice(twConfigPrefixLen + 1)
}
if (negative && context.candidateRuleMap.has(candidatePrefix)) {
yield [context.candidateRuleMap.get(candidatePrefix), '-DEFAULT']
}
for (let [prefix, modifier] of candidatePermutations(candidatePrefix)) {
if (context.candidateRuleMap.has(prefix)) {
yield [context.candidateRuleMap.get(prefix), negative ? `-${modifier}` : modifier]
}
}
}
function splitWithSeparator(input, separator) {
if (input === sharedState.NOT_ON_DEMAND) {
return [sharedState.NOT_ON_DEMAND]
}
return splitAtTopLevelOnly(input, separator)
}
function* recordCandidates(matches, classCandidate) {
for (const match of matches) {
match[1].raws.tailwind = {
...match[1].raws.tailwind,
classCandidate,
preserveSource: match[0].options?.preserveSource ?? false,
}
yield match
}
}
function* resolveMatches(candidate, context) {
let separator = context.tailwindConfig.separator
let [classCandidate, ...variants] = splitWithSeparator(candidate, separator).reverse()
let important = false
if (classCandidate.startsWith('!')) {
important = true
classCandidate = classCandidate.slice(1)
}
// TODO: Reintroduce this in ways that doesn't break on false positives
// function sortAgainst(toSort, against) {
// return toSort.slice().sort((a, z) => {
// return bigSign(against.get(a)[0] - against.get(z)[0])
// })
// }
// let sorted = sortAgainst(variants, context.variantMap)
// if (sorted.toString() !== variants.toString()) {
// let corrected = sorted.reverse().concat(classCandidate).join(':')
// throw new Error(`Class ${candidate} should be written as ${corrected}`)
// }
for (let matchedPlugins of resolveMatchedPlugins(classCandidate, context)) {
let matches = []
let typesByMatches = new Map()
let [plugins, modifier] = matchedPlugins
let isOnlyPlugin = plugins.length === 1
for (let [sort, plugin] of plugins) {
let matchesPerPlugin = []
if (typeof plugin === 'function') {
for (let ruleSet of [].concat(plugin(modifier, { isOnlyPlugin }))) {
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache)
for (let rule of rules) {
matchesPerPlugin.push([{ ...sort, options: { ...sort.options, ...options } }, rule])
}
}
}
// Only process static plugins on exact matches
else if (modifier === 'DEFAULT' || modifier === '-DEFAULT') {
let ruleSet = plugin
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache)
for (let rule of rules) {
matchesPerPlugin.push([{ ...sort, options: { ...sort.options, ...options } }, rule])
}
}
if (matchesPerPlugin.length > 0) {
let matchingTypes = Array.from(
getMatchingTypes(
sort.options?.types ?? [],
modifier,
sort.options ?? {},
context.tailwindConfig
)
).map(([_, type]) => type)
if (matchingTypes.length > 0) {
typesByMatches.set(matchesPerPlugin, matchingTypes)
}
matches.push(matchesPerPlugin)
}
}
if (isArbitraryValue(modifier)) {
if (matches.length > 1) {
// Partition plugins in 2 categories so that we can start searching in the plugins that
// don't have `any` as a type first.
let [withAny, withoutAny] = matches.reduce(
(group, plugin) => {
let hasAnyType = plugin.some(([{ options }]) =>
options.types.some(({ type }) => type === 'any')
)
if (hasAnyType) {
group[0].push(plugin)
} else {
group[1].push(plugin)
}
return group
},
[[], []]
)
function findFallback(matches) {
// If only a single plugin matches, let's take that one
if (matches.length === 1) {
return matches[0]
}
// Otherwise, find the plugin that creates a valid rule given the arbitrary value, and
// also has the correct type which preferOnConflicts the plugin in case of clashes.
return matches.find((rules) => {
let matchingTypes = typesByMatches.get(rules)
return rules.some(([{ options }, rule]) => {
if (!isParsableNode(rule)) {
return false
}
return options.types.some(
({ type, preferOnConflict }) => matchingTypes.includes(type) && preferOnConflict
)
})
})
}
// Try to find a fallback plugin, because we already know that multiple plugins matched for
// the given arbitrary value.
let fallback = findFallback(withoutAny) ?? findFallback(withAny)
if (fallback) {
matches = [fallback]
}
// We couldn't find a fallback plugin which means that there are now multiple plugins that
// generated css for the current candidate. This means that the result is ambiguous and this
// should not happen. We won't generate anything right now, so let's report this to the user
// by logging some options about what they can do.
else {
let typesPerPlugin = matches.map(
(match) => new Set([...(typesByMatches.get(match) ?? [])])
)
// Remove duplicates, so that we can detect proper unique types for each plugin.
for (let pluginTypes of typesPerPlugin) {
for (let type of pluginTypes) {
let removeFromOwnGroup = false
for (let otherGroup of typesPerPlugin) {
if (pluginTypes === otherGroup) continue
if (otherGroup.has(type)) {
otherGroup.delete(type)
removeFromOwnGroup = true
}
}
if (removeFromOwnGroup) pluginTypes.delete(type)
}
}
let messages = []
for (let [idx, group] of typesPerPlugin.entries()) {
for (let type of group) {
let rules = matches[idx]
.map(([, rule]) => rule)
.flat()
.map((rule) =>
rule
.toString()
.split('\n')
.slice(1, -1) // Remove selector and closing '}'
.map((line) => line.trim())
.map((x) => ` ${x}`) // Re-indent
.join('\n')
)
.join('\n\n')
messages.push(
` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\``
)
break
}
}
log.warn([
`The class \`${candidate}\` is ambiguous and matches multiple utilities.`,
...messages,
`If this is content and not a class, replace it with \`${candidate
.replace('[', '&lsqb;')
.replace(']', '&rsqb;')}\` to silence this warning.`,
])
continue
}
}
matches = matches.map((list) => list.filter((match) => isParsableNode(match[1])))
}
matches = matches.flat()
matches = Array.from(recordCandidates(matches, classCandidate))
matches = applyPrefix(matches, context)
if (important) {
matches = applyImportant(matches, classCandidate)
}
for (let variant of variants) {
matches = applyVariant(variant, matches, context)
}
for (let match of matches) {
match[1].raws.tailwind = { ...match[1].raws.tailwind, candidate }
// Apply final format selector
match = applyFinalFormat(match, { context, candidate })
// Skip rules with invalid selectors
// This will cause the candidate to be added to the "not class"
// cache skipping it entirely for future builds
if (match === null) {
continue
}
yield match
}
}
}
function applyFinalFormat(match, { context, candidate }) {
if (!match[0].collectedFormats) {
return match
}
let isValid = true
let finalFormat
try {
finalFormat = formatVariantSelector(match[0].collectedFormats, {
context,
candidate,
})
} catch {
// The format selector we produced is invalid
// This could be because:
// - A bug exists
// - A plugin introduced an invalid variant selector (ex: `addVariant('foo', '&;foo')`)
// - The user used an invalid arbitrary variant (ex: `[&;foo]:underline`)
// Either way the build will fail because of this
// We would rather that the build pass "silently" given that this could
// happen because of picking up invalid things when scanning content
// So we'll throw out the candidate instead
return null
}
let container = postcss.root({ nodes: [match[1].clone()] })
container.walkRules((rule) => {
if (inKeyframes(rule)) {
return
}
try {
let selector = finalizeSelector(rule.selector, finalFormat, {
candidate,
context,
})
// Finalize Selector determined that this candidate is irrelevant
// TODO: This elimination should happen earlier so this never happens
if (selector === null) {
rule.remove()
return
}
rule.selector = selector
} catch {
// If this selector is invalid we also want to skip it
// But it's likely that being invalid here means there's a bug in a plugin rather than too loosely matching content
isValid = false
return false
}
})
if (!isValid) {
return null
}
// If all rules have been eliminated we can skip this candidate entirely
if (container.nodes.length === 0) {
return null
}
match[1] = container.nodes[0]
return match
}
function inKeyframes(rule) {
return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === 'keyframes'
}
function getImportantStrategy(important) {
if (important === true) {
return (rule) => {
if (inKeyframes(rule)) {
return
}
rule.walkDecls((d) => {
if (d.parent.type === 'rule' && !inKeyframes(d.parent)) {
d.important = true
}
})
}
}
if (typeof important === 'string') {
return (rule) => {
if (inKeyframes(rule)) {
return
}
rule.selectors = rule.selectors.map((selector) => {
return applyImportantSelector(selector, important)
})
}
}
}
function generateRules(candidates, context, isSorting = false) {
let allRules = []
let strategy = getImportantStrategy(context.tailwindConfig.important)
for (let candidate of candidates) {
if (context.notClassCache.has(candidate)) {
continue
}
if (context.candidateRuleCache.has(candidate)) {
allRules = allRules.concat(Array.from(context.candidateRuleCache.get(candidate)))
continue
}
let matches = Array.from(resolveMatches(candidate, context))
if (matches.length === 0) {
context.notClassCache.add(candidate)
continue
}
context.classCache.set(candidate, matches)
let rules = context.candidateRuleCache.get(candidate) ?? new Set()
context.candidateRuleCache.set(candidate, rules)
for (const match of matches) {
let [{ sort, options }, rule] = match
if (options.respectImportant && strategy) {
let container = postcss.root({ nodes: [rule.clone()] })
container.walkRules(strategy)
rule = container.nodes[0]
}
// Note: We have to clone rules during sorting
// so we eliminate some shared mutable state
let newEntry = [sort, isSorting ? rule.clone() : rule]
rules.add(newEntry)
context.ruleCache.add(newEntry)
allRules.push(newEntry)
}
}
return allRules
}
function isArbitraryValue(input) {
return input.startsWith('[') && input.endsWith(']')
}
export { resolveMatches, generateRules }
import fs from 'fs'
import path from 'path'
let jsExtensions = ['.js', '.cjs', '.mjs']
// Given the current file `a.ts`, we want to make sure that when importing `b` that we resolve
// `b.ts` before `b.js`
//
// E.g.:
//
// a.ts
// b // .ts
// c // .ts
// a.js
// b // .js or .ts
let jsResolutionOrder = ['', '.js', '.cjs', '.mjs', '.ts', '.cts', '.mts', '.jsx', '.tsx']
let tsResolutionOrder = ['', '.ts', '.cts', '.mts', '.tsx', '.js', '.cjs', '.mjs', '.jsx']
function resolveWithExtension(file, extensions) {
// Try to find `./a.ts`, `./a.ts`, ... from `./a`
for (let ext of extensions) {
let full = `${file}${ext}`
if (fs.existsSync(full) && fs.statSync(full).isFile()) {
return full
}
}
// Try to find `./a/index.js` from `./a`
for (let ext of extensions) {
let full = `${file}/index${ext}`
if (fs.existsSync(full)) {
return full
}
}
return null
}
function* _getModuleDependencies(filename, base, seen, ext = path.extname(filename)) {
// Try to find the file
let absoluteFile = resolveWithExtension(
path.resolve(base, filename),
jsExtensions.includes(ext) ? jsResolutionOrder : tsResolutionOrder
)
if (absoluteFile === null) return // File doesn't exist
// Prevent infinite loops when there are circular dependencies
if (seen.has(absoluteFile)) return // Already seen
seen.add(absoluteFile)
// Mark the file as a dependency
yield absoluteFile
// Resolve new base for new imports/requires
base = path.dirname(absoluteFile)
ext = path.extname(absoluteFile)
let contents = fs.readFileSync(absoluteFile, 'utf-8')
// Find imports/requires
for (let match of [
...contents.matchAll(/import[\s\S]*?['"](.{3,}?)['"]/gi),
...contents.matchAll(/import[\s\S]*from[\s\S]*?['"](.{3,}?)['"]/gi),
...contents.matchAll(/require\(['"`](.+)['"`]\)/gi),
]) {
// Bail out if it's not a relative file
if (!match[1].startsWith('.')) continue
yield* _getModuleDependencies(match[1], base, seen, ext)
}
}
export default function getModuleDependencies(absoluteFilePath) {
if (absoluteFilePath === null) return new Set()
return new Set(
_getModuleDependencies(absoluteFilePath, path.dirname(absoluteFilePath), new Set())
)
}
import postcss from 'postcss'
import postcssImport from 'postcss-import'
const TAILWIND = Symbol()
export function handleImportAtRules() {
let RESTORE_ATRULE_COMMENT = '__TAILWIND_RESTORE__'
let atRulesToRestore = ['tailwind', 'config']
return [
(root) => {
root.walkAtRules((rule) => {
if (!atRulesToRestore.includes(rule.name)) return rule
rule.after(
postcss.comment({
text: RESTORE_ATRULE_COMMENT,
raws: { [TAILWIND]: { rule } },
})
)
rule.remove()
})
},
postcssImport(),
(root) => {
root.walkComments((rule) => {
if (rule.text === RESTORE_ATRULE_COMMENT) {
rule.after(rule.raws[TAILWIND].rule)
rule.remove()
}
})
},
]
}
import jitiFactory from 'jiti'
import { transform } from 'sucrase'
import { Config } from '../../types/config'
let jiti: ReturnType<typeof jitiFactory> | null = null
// @internal
// This WILL be removed in some future release
// If you rely on this your stuff WILL break
export function useCustomJiti(_jiti: () => ReturnType<typeof jitiFactory>) {
jiti = _jiti()
}
function lazyJiti() {
return (
jiti ??
(jiti = jitiFactory(__filename, {
interopDefault: true,
transform: (opts) => {
return transform(opts.source, {
transforms: ['typescript', 'imports'],
})
},
}))
)
}
export function loadConfig(path: string): Config {
let config = (function () {
try {
return path ? require(path) : {}
} catch {
return lazyJiti()(path)
}
})()
return config.default ?? config
}
import log from '../util/log'
export default function normalizeTailwindDirectives(root) {
let tailwindDirectives = new Set()
let layerDirectives = new Set()
let applyDirectives = new Set()
root.walkAtRules((atRule) => {
if (atRule.name === 'apply') {
applyDirectives.add(atRule)
}
if (atRule.name === 'tailwind') {
if (atRule.params === 'screens') {
atRule.params = 'variants'
}
tailwindDirectives.add(atRule.params)
}
if (['layer', 'responsive', 'variants'].includes(atRule.name)) {
if (['responsive', 'variants'].includes(atRule.name)) {
log.warn(`${atRule.name}-at-rule-deprecated`, [
`The \`@${atRule.name}\` directive has been deprecated in Tailwind CSS v3.0.`,
`Use \`@layer utilities\` or \`@layer components\` instead.`,
'https://tailwindcss.com/docs/upgrade-guide#replace-variants-with-layer',
])
}
layerDirectives.add(atRule)
}
})
if (
!tailwindDirectives.has('base') ||
!tailwindDirectives.has('components') ||
!tailwindDirectives.has('utilities')
) {
for (let rule of layerDirectives) {
if (rule.name === 'layer' && ['base', 'components', 'utilities'].includes(rule.params)) {
if (!tailwindDirectives.has(rule.params)) {
throw rule.error(
`\`@layer ${rule.params}\` is used but no matching \`@tailwind ${rule.params}\` directive is present.`
)
}
} else if (rule.name === 'responsive') {
if (!tailwindDirectives.has('utilities')) {
throw rule.error('`@responsive` is used but `@tailwind utilities` is missing.')
}
} else if (rule.name === 'variants') {
if (!tailwindDirectives.has('utilities')) {
throw rule.error('`@variants` is used but `@tailwind utilities` is missing.')
}
}
}
}
return { tailwindDirectives, applyDirectives }
}
// @ts-check
import bigSign from '../util/bigSign'
import { remapBitfield } from './remap-bitfield.js'
/**
* @typedef {'base' | 'defaults' | 'components' | 'utilities' | 'variants' | 'user'} Layer
*/
/**
* @typedef {object} VariantOption
* @property {number} id An unique identifier to identify `matchVariant`
* @property {function | undefined} sort The sort function
* @property {string|null} value The value we want to compare
* @property {string|null} modifier The modifier that was used (if any)
* @property {bigint} variant The variant bitmask
*/
/**
* @typedef {object} RuleOffset
* @property {Layer} layer The layer that this rule belongs to
* @property {Layer} parentLayer The layer that this rule originally belonged to. Only different from layer if this is a variant.
* @property {bigint} arbitrary 0n if false, 1n if true
* @property {bigint} variants Dynamic size. 1 bit per registered variant. 0n means no variants
* @property {bigint} parallelIndex Rule index for the parallel variant. 0 if not applicable.
* @property {bigint} index Index of the rule / utility in its given *parent* layer. Monotonically increasing.
* @property {VariantOption[]} options Some information on how we can sort arbitrary variants
*/
export class Offsets {
constructor() {
/**
* Offsets for the next rule in a given layer
*
* @type {Record<Layer, bigint>}
*/
this.offsets = {
defaults: 0n,
base: 0n,
components: 0n,
utilities: 0n,
variants: 0n,
user: 0n,
}
/**
* Positions for a given layer
*
* @type {Record<Layer, bigint>}
*/
this.layerPositions = {
defaults: 0n,
base: 1n,
components: 2n,
utilities: 3n,
// There isn't technically a "user" layer, but we need to give it a position
// Because it's used for ordering user-css from @apply
user: 4n,
variants: 5n,
}
/**
* The total number of functions currently registered across all variants (including arbitrary variants)
*
* @type {bigint}
*/
this.reservedVariantBits = 0n
/**
* Positions for a given variant
*
* @type {Map<string, bigint>}
*/
this.variantOffsets = new Map()
}
/**
* @param {Layer} layer
* @returns {RuleOffset}
*/
create(layer) {
return {
layer,
parentLayer: layer,
arbitrary: 0n,
variants: 0n,
parallelIndex: 0n,
index: this.offsets[layer]++,
options: [],
}
}
/**
* @returns {RuleOffset}
*/
arbitraryProperty() {
return {
...this.create('utilities'),
arbitrary: 1n,
}
}
/**
* Get the offset for a variant
*
* @param {string} variant
* @param {number} index
* @returns {RuleOffset}
*/
forVariant(variant, index = 0) {
let offset = this.variantOffsets.get(variant)
if (offset === undefined) {
throw new Error(`Cannot find offset for unknown variant ${variant}`)
}
return {
...this.create('variants'),
variants: offset << BigInt(index),
}
}
/**
* @param {RuleOffset} rule
* @param {RuleOffset} variant
* @param {VariantOption} options
* @returns {RuleOffset}
*/
applyVariantOffset(rule, variant, options) {
options.variant = variant.variants
return {
...rule,
layer: 'variants',
parentLayer: rule.layer === 'variants' ? rule.parentLayer : rule.layer,
variants: rule.variants | variant.variants,
options: options.sort ? [].concat(options, rule.options) : rule.options,
// TODO: Technically this is wrong. We should be handling parallel index on a per variant basis.
// We'll take the max of all the parallel indexes for now.
// @ts-ignore
parallelIndex: max([rule.parallelIndex, variant.parallelIndex]),
}
}
/**
* @param {RuleOffset} offset
* @param {number} parallelIndex
* @returns {RuleOffset}
*/
applyParallelOffset(offset, parallelIndex) {
return {
...offset,
parallelIndex: BigInt(parallelIndex),
}
}
/**
* Each variant gets 1 bit per function / rule registered.
* This is because multiple variants can be applied to a single rule and we need to know which ones are present and which ones are not.
* Additionally, every unique group of variants is grouped together in the stylesheet.
*
* This grouping is order-independent. For instance, we do not differentiate between `hover:focus` and `focus:hover`.
*
* @param {string[]} variants
* @param {(name: string) => number} getLength
*/
recordVariants(variants, getLength) {
for (let variant of variants) {
this.recordVariant(variant, getLength(variant))
}
}
/**
* The same as `recordVariants` but for a single arbitrary variant at runtime.
* @param {string} variant
* @param {number} fnCount
*
* @returns {RuleOffset} The highest offset for this variant
*/
recordVariant(variant, fnCount = 1) {
this.variantOffsets.set(variant, 1n << this.reservedVariantBits)
// Ensure space is reserved for each "function" in the parallel variant
// by offsetting the next variant by the number of parallel variants
// in the one we just added.
// Single functions that return parallel variants are NOT handled separately here
// They're offset by 1 (or the number of functions) as usual
// And each rule returned is tracked separately since the functions are evaluated lazily.
// @see `RuleOffset.parallelIndex`
this.reservedVariantBits += BigInt(fnCount)
return {
...this.create('variants'),
variants: this.variantOffsets.get(variant),
}
}
/**
* @param {RuleOffset} a
* @param {RuleOffset} b
* @returns {bigint}
*/
compare(a, b) {
// Sort layers together
if (a.layer !== b.layer) {
return this.layerPositions[a.layer] - this.layerPositions[b.layer]
}
// When sorting the `variants` layer, we need to sort based on the parent layer as well within
// this variants layer.
if (a.parentLayer !== b.parentLayer) {
return this.layerPositions[a.parentLayer] - this.layerPositions[b.parentLayer]
}
// Sort based on the sorting function
for (let aOptions of a.options) {
for (let bOptions of b.options) {
if (aOptions.id !== bOptions.id) continue
if (!aOptions.sort || !bOptions.sort) continue
let maxFnVariant = max([aOptions.variant, bOptions.variant]) ?? 0n
// Create a mask of 0s from bits 1..N where N represents the mask of the Nth bit
let mask = ~(maxFnVariant | (maxFnVariant - 1n))
let aVariantsAfterFn = a.variants & mask
let bVariantsAfterFn = b.variants & mask
// If the variants the same, we _can_ sort them
if (aVariantsAfterFn !== bVariantsAfterFn) {
continue
}
let result = aOptions.sort(
{
value: aOptions.value,
modifier: aOptions.modifier,
},
{
value: bOptions.value,
modifier: bOptions.modifier,
}
)
if (result !== 0) return result
}
}
// Sort variants in the order they were registered
if (a.variants !== b.variants) {
return a.variants - b.variants
}
// Make sure each rule returned by a parallel variant is sorted in ascending order
if (a.parallelIndex !== b.parallelIndex) {
return a.parallelIndex - b.parallelIndex
}
// Always sort arbitrary properties after other utilities
if (a.arbitrary !== b.arbitrary) {
return a.arbitrary - b.arbitrary
}
// Sort utilities, components, etc… in the order they were registered
return a.index - b.index
}
/**
* Arbitrary variants are recorded in the order they're encountered.
* This means that the order is not stable between environments and sets of content files.
*
* In order to make the order stable, we need to remap the arbitrary variant offsets to
* be in alphabetical order starting from the offset of the first arbitrary variant.
*/
recalculateVariantOffsets() {
// Sort the variants by their name
let variants = Array.from(this.variantOffsets.entries())
.filter(([v]) => v.startsWith('['))
.sort(([a], [z]) => fastCompare(a, z))
// Sort the list of offsets
// This is not necessarily a discrete range of numbers which is why
// we're using sort instead of creating a range from min/max
let newOffsets = variants.map(([, offset]) => offset).sort((a, z) => bigSign(a - z))
// Create a map from the old offsets to the new offsets in the new sort order
/** @type {[bigint, bigint][]} */
let mapping = variants.map(([, oldOffset], i) => [oldOffset, newOffsets[i]])
// Remove any variants that will not move letting us skip
// remapping if everything happens to be in order
return mapping.filter(([a, z]) => a !== z)
}
/**
* @template T
* @param {[RuleOffset, T][]} list
* @returns {[RuleOffset, T][]}
*/
remapArbitraryVariantOffsets(list) {
let mapping = this.recalculateVariantOffsets()
// No arbitrary variants? Nothing to do.
// Everything already in order? Nothing to do.
if (mapping.length === 0) {
return list
}
// Remap every variant offset in the list
return list.map((item) => {
let [offset, rule] = item
offset = {
...offset,
variants: remapBitfield(offset.variants, mapping),
}
return [offset, rule]
})
}
/**
* @template T
* @param {[RuleOffset, T][]} list
* @returns {[RuleOffset, T][]}
*/
sort(list) {
list = this.remapArbitraryVariantOffsets(list)
return list.sort(([a], [b]) => bigSign(this.compare(a, b)))
}
}
/**
*
* @param {bigint[]} nums
* @returns {bigint|null}
*/
function max(nums) {
let max = null
for (const num of nums) {
max = max ?? num
max = max > num ? max : num
}
return max
}
/**
* A fast ASCII order string comparison function.
*
* Using `.sort()` without a custom compare function is faster
* But you can only use that if you're sorting an array of
* only strings. If you're sorting strings inside objects
* or arrays, you need to use a custom compare function.
*
* @param {string} a
* @param {string} b
*/
function fastCompare(a, b) {
let aLen = a.length
let bLen = b.length
let minLen = aLen < bLen ? aLen : bLen
for (let i = 0; i < minLen; i++) {
let cmp = a.charCodeAt(i) - b.charCodeAt(i)
if (cmp !== 0) return cmp
}
return aLen - bLen
}
function partitionRules(root) {
if (!root.walkAtRules) return
let applyParents = new Set()
root.walkAtRules('apply', (rule) => {
applyParents.add(rule.parent)
})
if (applyParents.size === 0) {
return
}
for (let rule of applyParents) {
let nodeGroups = []
let lastGroup = []
for (let node of rule.nodes) {
if (node.type === 'atrule' && node.name === 'apply') {
if (lastGroup.length > 0) {
nodeGroups.push(lastGroup)
lastGroup = []
}
nodeGroups.push([node])
} else {
lastGroup.push(node)
}
}
if (lastGroup.length > 0) {
nodeGroups.push(lastGroup)
}
if (nodeGroups.length === 1) {
continue
}
for (let group of [...nodeGroups].reverse()) {
let clone = rule.clone({ nodes: [] })
clone.append(group)
rule.after(clone)
}
rule.remove()
}
}
export default function expandApplyAtRules() {
return (root) => {
partitionRules(root)
}
}
const REGEX_SPECIAL = /[\\^$.*+?()[\]{}|]/g
const REGEX_HAS_SPECIAL = RegExp(REGEX_SPECIAL.source)
/**
* @param {string|RegExp|Array<string|RegExp>} source
*/
function toSource(source) {
source = Array.isArray(source) ? source : [source]
source = source.map((item) => (item instanceof RegExp ? item.source : item))
return source.join('')
}
/**
* @param {string|RegExp|Array<string|RegExp>} source
*/
export function pattern(source) {
return new RegExp(toSource(source), 'g')
}
/**
* @param {string|RegExp|Array<string|RegExp>} source
*/
export function withoutCapturing(source) {
return new RegExp(`(?:${toSource(source)})`, 'g')
}
/**
* @param {Array<string|RegExp>} sources
*/
export function any(sources) {
return `(?:${sources.map(toSource).join('|')})`
}
/**
* @param {string|RegExp} source
*/
export function optional(source) {
return `(?:${toSource(source)})?`
}
/**
* @param {string|RegExp|Array<string|RegExp>} source
*/
export function zeroOrMore(source) {
return `(?:${toSource(source)})*`
}
/**
* Generate a RegExp that matches balanced brackets for a given depth
* We have to specify a depth because JS doesn't support recursive groups using ?R
*
* Based on https://stackoverflow.com/questions/17759004/how-to-match-string-within-parentheses-nested-in-java/17759264#17759264
*
* @param {string|RegExp|Array<string|RegExp>} source
*/
export function nestedBrackets(open, close, depth = 1) {
return withoutCapturing([
escape(open),
/[^\s]*/,
depth === 1
? `[^${escape(open)}${escape(close)}\s]*`
: any([`[^${escape(open)}${escape(close)}\s]*`, nestedBrackets(open, close, depth - 1)]),
/[^\s]*/,
escape(close),
])
}
export function escape(string) {
return string && REGEX_HAS_SPECIAL.test(string)
? string.replace(REGEX_SPECIAL, '\\$&')
: string || ''
}
// @ts-check
/**
* We must remap all the old bits to new bits for each set variant
* Only arbitrary variants are considered as those are the only
* ones that need to be re-sorted at this time
*
* An iterated process that removes and sets individual bits simultaneously
* will not work because we may have a new bit that is also a later old bit
* This means that we would be removing a previously set bit which we don't
* want to do
*
* For example (assume `bN` = `1<<N`)
* Given the "total" mapping `[[b1, b3], [b2, b4], [b3, b1], [b4, b2]]`
* The mapping is "total" because:
* 1. Every input and output is accounted for
* 2. All combinations are unique
* 3. No one input maps to multiple outputs and vice versa
* And, given an offset with all bits set:
* V = b1 | b2 | b3 | b4
*
* Let's explore the issue with removing and setting bits simultaneously:
* V & ~b1 | b3 = b2 | b3 | b4
* V & ~b2 | b4 = b3 | b4
* V & ~b3 | b1 = b1 | b4
* V & ~b4 | b2 = b1 | b2
*
* As you can see, we end up with the wrong result.
* This is because we're removing a bit that was previously set.
* And, thus the final result is missing b3 and b4.
*
* Now, let's explore the issue with removing the bits first:
* V & ~b1 = b2 | b3 | b4
* V & ~b2 = b3 | b4
* V & ~b3 = b4
* V & ~b4 = 0
*
* And then setting the bits:
* V | b3 = b3
* V | b4 = b3 | b4
* V | b1 = b1 | b3 | b4
* V | b2 = b1 | b2 | b3 | b4
*
* We get the correct result because we're not removing any bits that were
* previously set thus properly remapping the bits to the new order
*
* To collect this into a single operation that can be done simultaneously
* we must first create a mask for the old bits that are set and a mask for
* the new bits that are set. Then we can remove the old bits and set the new
* bits simultaneously in a "single" operation like so:
* OldMask = b1 | b2 | b3 | b4
* NewMask = b3 | b4 | b1 | b2
*
* So this:
* V & ~oldMask | newMask
*
* Expands to this:
* V & ~b1 & ~b2 & ~b3 & ~b4 | b3 | b4 | b1 | b2
*
* Which becomes this:
* b1 | b2 | b3 | b4
*
* Which is the correct result!
*
* @param {bigint} num
* @param {[bigint, bigint][]} mapping
*/
export function remapBitfield(num, mapping) {
// Create masks for the old and new bits that are set
let oldMask = 0n
let newMask = 0n
for (let [oldBit, newBit] of mapping) {
if (num & oldBit) {
oldMask = oldMask | oldBit
newMask = newMask | newBit
}
}
// Remove all old bits
// Set all new bits
return (num & ~oldMask) | newMask
}
import postcss from 'postcss'
import selectorParser from 'postcss-selector-parser'
import { flagEnabled } from '../featureFlags'
let getNode = {
id(node) {
return selectorParser.attribute({
attribute: 'id',
operator: '=',
value: node.value,
quoteMark: '"',
})
},
}
function minimumImpactSelector(nodes) {
let rest = nodes
.filter((node) => {
// Keep non-pseudo nodes
if (node.type !== 'pseudo') return true
// Keep pseudo nodes that have subnodes
// E.g.: `:not()` contains subnodes inside the parentheses
if (node.nodes.length > 0) return true
// Keep pseudo `elements`
// This implicitly means that we ignore pseudo `classes`
return (
node.value.startsWith('::') ||
[':before', ':after', ':first-line', ':first-letter'].includes(node.value)
)
})
.reverse()
let searchFor = new Set(['tag', 'class', 'id', 'attribute'])
let splitPointIdx = rest.findIndex((n) => searchFor.has(n.type))
if (splitPointIdx === -1) return rest.reverse().join('').trim()
let node = rest[splitPointIdx]
let bestNode = getNode[node.type] ? getNode[node.type](node) : node
rest = rest.slice(0, splitPointIdx)
let combinatorIdx = rest.findIndex((n) => n.type === 'combinator' && n.value === '>')
if (combinatorIdx !== -1) {
rest.splice(0, combinatorIdx)
rest.unshift(selectorParser.universal())
}
return [bestNode, ...rest.reverse()].join('').trim()
}
export let elementSelectorParser = selectorParser((selectors) => {
return selectors.map((s) => {
let nodes = s.split((n) => n.type === 'combinator' && n.value === ' ').pop()
return minimumImpactSelector(nodes)
})
})
let cache = new Map()
function extractElementSelector(selector) {
if (!cache.has(selector)) {
cache.set(selector, elementSelectorParser.transformSync(selector))
}
return cache.get(selector)
}
export default function resolveDefaultsAtRules({ tailwindConfig }) {
return (root) => {
let variableNodeMap = new Map()
/** @type {Set<import('postcss').AtRule>} */
let universals = new Set()
root.walkAtRules('defaults', (rule) => {
if (rule.nodes && rule.nodes.length > 0) {
universals.add(rule)
return
}
let variable = rule.params
if (!variableNodeMap.has(variable)) {
variableNodeMap.set(variable, new Set())
}
variableNodeMap.get(variable).add(rule.parent)
rule.remove()
})
if (flagEnabled(tailwindConfig, 'optimizeUniversalDefaults')) {
for (let universal of universals) {
/** @type {Map<string, Set<string>>} */
let selectorGroups = new Map()
let rules = variableNodeMap.get(universal.params) ?? []
for (let rule of rules) {
for (let selector of extractElementSelector(rule.selector)) {
// If selector contains a vendor prefix after a pseudo element or class,
// we consider them separately because merging the declarations into
// a single rule will cause browsers that do not understand the
// vendor prefix to throw out the whole rule
let selectorGroupName =
selector.includes(':-') || selector.includes('::-') ? selector : '__DEFAULT__'
let selectors = selectorGroups.get(selectorGroupName) ?? new Set()
selectorGroups.set(selectorGroupName, selectors)
selectors.add(selector)
}
}
if (flagEnabled(tailwindConfig, 'optimizeUniversalDefaults')) {
if (selectorGroups.size === 0) {
universal.remove()
continue
}
for (let [, selectors] of selectorGroups) {
let universalRule = postcss.rule({
source: universal.source,
})
universalRule.selectors = [...selectors]
universalRule.append(universal.nodes.map((node) => node.clone()))
universal.before(universalRule)
}
}
universal.remove()
}
} else if (universals.size) {
let universalRule = postcss.rule({
selectors: ['*', '::before', '::after'],
})
for (let universal of universals) {
universalRule.append(universal.nodes)
if (!universalRule.parent) {
universal.before(universalRule)
}
if (!universalRule.source) {
universalRule.source = universal.source
}
universal.remove()
}
let backdropRule = universalRule.clone({
selectors: ['::backdrop'],
})
universalRule.after(backdropRule)
}
}
}
import fs from 'fs'
import url from 'url'
import postcss from 'postcss'
import dlv from 'dlv'
import selectorParser from 'postcss-selector-parser'
import transformThemeValue from '../util/transformThemeValue'
import parseObjectStyles from '../util/parseObjectStyles'
import prefixSelector from '../util/prefixSelector'
import isPlainObject from '../util/isPlainObject'
import escapeClassName from '../util/escapeClassName'
import nameClass, { formatClass } from '../util/nameClass'
import { coerceValue } from '../util/pluginUtils'
import { variantPlugins, corePlugins } from '../corePlugins'
import * as sharedState from './sharedState'
import { env } from './sharedState'
import { toPath } from '../util/toPath'
import log from '../util/log'
import negateValue from '../util/negateValue'
import isSyntacticallyValidPropertyValue from '../util/isSyntacticallyValidPropertyValue'
import { generateRules, getClassNameFromSelector } from './generateRules'
import { hasContentChanged } from './cacheInvalidation.js'
import { Offsets } from './offsets.js'
import { finalizeSelector, formatVariantSelector } from '../util/formatVariantSelector'
export const INTERNAL_FEATURES = Symbol()
const VARIANT_TYPES = {
AddVariant: Symbol.for('ADD_VARIANT'),
MatchVariant: Symbol.for('MATCH_VARIANT'),
}
const VARIANT_INFO = {
Base: 1 << 0,
Dynamic: 1 << 1,
}
function prefix(context, selector) {
let prefix = context.tailwindConfig.prefix
return typeof prefix === 'function' ? prefix(selector) : prefix + selector
}
function normalizeOptionTypes({ type = 'any', ...options }) {
let types = [].concat(type)
return {
...options,
types: types.map((type) => {
if (Array.isArray(type)) {
return { type: type[0], ...type[1] }
}
return { type, preferOnConflict: false }
}),
}
}
function parseVariantFormatString(input) {
/** @type {string[]} */
let parts = []
// When parsing whitespace around special characters are insignificant
// However, _inside_ of a variant they could be
// Because the selector could look like this
// @media { &[data-name="foo bar"] }
// This is why we do not skip whitespace
let current = ''
let depth = 0
for (let idx = 0; idx < input.length; idx++) {
let char = input[idx]
if (char === '\\') {
// Escaped characters are not special
current += '\\' + input[++idx]
} else if (char === '{') {
// Nested rule: start
++depth
parts.push(current.trim())
current = ''
} else if (char === '}') {
// Nested rule: end
if (--depth < 0) {
throw new Error(`Your { and } are unbalanced.`)
}
parts.push(current.trim())
current = ''
} else {
// Normal character
current += char
}
}
if (current.length > 0) {
parts.push(current.trim())
}
parts = parts.filter((part) => part !== '')
return parts
}
function insertInto(list, value, { before = [] } = {}) {
before = [].concat(before)
if (before.length <= 0) {
list.push(value)
return
}
let idx = list.length - 1
for (let other of before) {
let iidx = list.indexOf(other)
if (iidx === -1) continue
idx = Math.min(idx, iidx)
}
list.splice(idx, 0, value)
}
function parseStyles(styles) {
if (!Array.isArray(styles)) {
return parseStyles([styles])
}
return styles.flatMap((style) => {
let isNode = !Array.isArray(style) && !isPlainObject(style)
return isNode ? style : parseObjectStyles(style)
})
}
function getClasses(selector, mutate) {
let parser = selectorParser((selectors) => {
let allClasses = []
if (mutate) {
mutate(selectors)
}
selectors.walkClasses((classNode) => {
allClasses.push(classNode.value)
})
return allClasses
})
return parser.transformSync(selector)
}
/**
* Ignore everything inside a :not(...). This allows you to write code like
* `div:not(.foo)`. If `.foo` is never found in your code, then we used to
* not generated it. But now we will ignore everything inside a `:not`, so
* that it still gets generated.
*
* @param {selectorParser.Root} selectors
*/
function ignoreNot(selectors) {
selectors.walkPseudos((pseudo) => {
if (pseudo.value === ':not') {
pseudo.remove()
}
})
}
function extractCandidates(node, state = { containsNonOnDemandable: false }, depth = 0) {
let classes = []
let selectors = []
if (node.type === 'rule') {
// Handle normal rules
selectors.push(...node.selectors)
} else if (node.type === 'atrule') {
// Handle at-rules (which contains nested rules)
node.walkRules((rule) => selectors.push(...rule.selectors))
}
for (let selector of selectors) {
let classCandidates = getClasses(selector, ignoreNot)
// At least one of the selectors contains non-"on-demandable" candidates.
if (classCandidates.length === 0) {
state.containsNonOnDemandable = true
}
for (let classCandidate of classCandidates) {
classes.push(classCandidate)
}
}
if (depth === 0) {
return [state.containsNonOnDemandable || classes.length === 0, classes]
}
return classes
}
function withIdentifiers(styles) {
return parseStyles(styles).flatMap((node) => {
let nodeMap = new Map()
let [containsNonOnDemandableSelectors, candidates] = extractCandidates(node)
// If this isn't "on-demandable", assign it a universal candidate to always include it.
if (containsNonOnDemandableSelectors) {
candidates.unshift(sharedState.NOT_ON_DEMAND)
}
// However, it could be that it also contains "on-demandable" candidates.
// E.g.: `span, .foo {}`, in that case it should still be possible to use
// `@apply foo` for example.
return candidates.map((c) => {
if (!nodeMap.has(node)) {
nodeMap.set(node, node)
}
return [c, nodeMap.get(node)]
})
})
}
export function isValidVariantFormatString(format) {
return format.startsWith('@') || format.includes('&')
}
export function parseVariant(variant) {
variant = variant
.replace(/\n+/g, '')
.replace(/\s{1,}/g, ' ')
.trim()
let fns = parseVariantFormatString(variant)
.map((str) => {
if (!str.startsWith('@')) {
return ({ format }) => format(str)
}
let [, name, params] = /@(\S*)( .+|[({].*)?/g.exec(str)
return ({ wrap }) => wrap(postcss.atRule({ name, params: params?.trim() ?? '' }))
})
.reverse()
return (api) => {
for (let fn of fns) {
fn(api)
}
}
}
/**
*
* @param {any} tailwindConfig
* @param {any} context
* @param {object} param2
* @param {Offsets} param2.offsets
*/
function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offsets, classList }) {
function getConfigValue(path, defaultValue) {
return path ? dlv(tailwindConfig, path, defaultValue) : tailwindConfig
}
function applyConfiguredPrefix(selector) {
return prefixSelector(tailwindConfig.prefix, selector)
}
function prefixIdentifier(identifier, options) {
if (identifier === sharedState.NOT_ON_DEMAND) {
return sharedState.NOT_ON_DEMAND
}
if (!options.respectPrefix) {
return identifier
}
return context.tailwindConfig.prefix + identifier
}
function resolveThemeValue(path, defaultValue, opts = {}) {
let parts = toPath(path)
let value = getConfigValue(['theme', ...parts], defaultValue)
return transformThemeValue(parts[0])(value, opts)
}
let variantIdentifier = 0
let api = {
postcss,
prefix: applyConfiguredPrefix,
e: escapeClassName,
config: getConfigValue,
theme: resolveThemeValue,
corePlugins: (path) => {
if (Array.isArray(tailwindConfig.corePlugins)) {
return tailwindConfig.corePlugins.includes(path)
}
return getConfigValue(['corePlugins', path], true)
},
variants: () => {
// Preserved for backwards compatibility but not used in v3.0+
return []
},
addBase(base) {
for (let [identifier, rule] of withIdentifiers(base)) {
let prefixedIdentifier = prefixIdentifier(identifier, {})
let offset = offsets.create('base')
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, [])
}
context.candidateRuleMap
.get(prefixedIdentifier)
.push([{ sort: offset, layer: 'base' }, rule])
}
},
/**
* @param {string} group
* @param {Record<string, string | string[]>} declarations
*/
addDefaults(group, declarations) {
const groups = {
[`@defaults ${group}`]: declarations,
}
for (let [identifier, rule] of withIdentifiers(groups)) {
let prefixedIdentifier = prefixIdentifier(identifier, {})
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, [])
}
context.candidateRuleMap
.get(prefixedIdentifier)
.push([{ sort: offsets.create('defaults'), layer: 'defaults' }, rule])
}
},
addComponents(components, options) {
let defaultOptions = {
preserveSource: false,
respectPrefix: true,
respectImportant: false,
}
options = Object.assign({}, defaultOptions, Array.isArray(options) ? {} : options)
for (let [identifier, rule] of withIdentifiers(components)) {
let prefixedIdentifier = prefixIdentifier(identifier, options)
classList.add(prefixedIdentifier)
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, [])
}
context.candidateRuleMap
.get(prefixedIdentifier)
.push([{ sort: offsets.create('components'), layer: 'components', options }, rule])
}
},
addUtilities(utilities, options) {
let defaultOptions = {
preserveSource: false,
respectPrefix: true,
respectImportant: true,
}
options = Object.assign({}, defaultOptions, Array.isArray(options) ? {} : options)
for (let [identifier, rule] of withIdentifiers(utilities)) {
let prefixedIdentifier = prefixIdentifier(identifier, options)
classList.add(prefixedIdentifier)
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, [])
}
context.candidateRuleMap
.get(prefixedIdentifier)
.push([{ sort: offsets.create('utilities'), layer: 'utilities', options }, rule])
}
},
matchUtilities: function (utilities, options) {
let defaultOptions = {
respectPrefix: true,
respectImportant: true,
modifiers: false,
}
options = normalizeOptionTypes({ ...defaultOptions, ...options })
let offset = offsets.create('utilities')
for (let identifier in utilities) {
let prefixedIdentifier = prefixIdentifier(identifier, options)
let rule = utilities[identifier]
classList.add([prefixedIdentifier, options])
function wrapped(modifier, { isOnlyPlugin }) {
let [value, coercedType, utilityModifier] = coerceValue(
options.types,
modifier,
options,
tailwindConfig
)
if (value === undefined) {
return []
}
if (!options.types.some(({ type }) => type === coercedType)) {
if (isOnlyPlugin) {
log.warn([
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
`You can safely update it to \`${identifier}-${modifier.replace(
coercedType + ':',
''
)}\`.`,
])
} else {
return []
}
}
if (!isSyntacticallyValidPropertyValue(value)) {
return []
}
let extras = {
get modifier() {
if (!options.modifiers) {
log.warn(`modifier-used-without-options-for-${identifier}`, [
'Your plugin must set `modifiers: true` in its options to support modifiers.',
])
}
return utilityModifier
},
}
let ruleSets = []
.concat(rule(value, extras))
.filter(Boolean)
.map((declaration) => ({
[nameClass(identifier, modifier)]: declaration,
}))
return ruleSets
}
let withOffsets = [{ sort: offset, layer: 'utilities', options }, wrapped]
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, [])
}
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
}
},
matchComponents: function (components, options) {
let defaultOptions = {
respectPrefix: true,
respectImportant: false,
modifiers: false,
}
options = normalizeOptionTypes({ ...defaultOptions, ...options })
let offset = offsets.create('components')
for (let identifier in components) {
let prefixedIdentifier = prefixIdentifier(identifier, options)
let rule = components[identifier]
classList.add([prefixedIdentifier, options])
function wrapped(modifier, { isOnlyPlugin }) {
let [value, coercedType, utilityModifier] = coerceValue(
options.types,
modifier,
options,
tailwindConfig
)
if (value === undefined) {
return []
}
if (!options.types.some(({ type }) => type === coercedType)) {
if (isOnlyPlugin) {
log.warn([
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
`You can safely update it to \`${identifier}-${modifier.replace(
coercedType + ':',
''
)}\`.`,
])
} else {
return []
}
}
if (!isSyntacticallyValidPropertyValue(value)) {
return []
}
let extras = {
get modifier() {
if (!options.modifiers) {
log.warn(`modifier-used-without-options-for-${identifier}`, [
'Your plugin must set `modifiers: true` in its options to support modifiers.',
])
}
return utilityModifier
},
}
let ruleSets = []
.concat(rule(value, extras))
.filter(Boolean)
.map((declaration) => ({
[nameClass(identifier, modifier)]: declaration,
}))
return ruleSets
}
let withOffsets = [{ sort: offset, layer: 'components', options }, wrapped]
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, [])
}
context.candidateRuleMap.get(prefixedIdentifier).push(withOffsets)
}
},
addVariant(variantName, variantFunctions, options = {}) {
variantFunctions = [].concat(variantFunctions).map((variantFunction) => {
if (typeof variantFunction !== 'string') {
// Safelist public API functions
return (api = {}) => {
let { args, modifySelectors, container, separator, wrap, format } = api
let result = variantFunction(
Object.assign(
{ modifySelectors, container, separator },
options.type === VARIANT_TYPES.MatchVariant && { args, wrap, format }
)
)
if (typeof result === 'string' && !isValidVariantFormatString(result)) {
throw new Error(
`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`
)
}
if (Array.isArray(result)) {
return result
.filter((variant) => typeof variant === 'string')
.map((variant) => parseVariant(variant))
}
// result may be undefined with legacy variants that use APIs like `modifySelectors`
// result may also be a postcss node if someone was returning the result from `modifySelectors`
return result && typeof result === 'string' && parseVariant(result)(api)
}
}
if (!isValidVariantFormatString(variantFunction)) {
throw new Error(
`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`
)
}
return parseVariant(variantFunction)
})
insertInto(variantList, variantName, options)
variantMap.set(variantName, variantFunctions)
context.variantOptions.set(variantName, options)
},
matchVariant(variant, variantFn, options) {
// A unique identifier that "groups" these variants together.
// This is for internal use only which is why it is not present in the types
let id = options?.id ?? ++variantIdentifier
let isSpecial = variant === '@'
for (let [key, value] of Object.entries(options?.values ?? {})) {
if (key === 'DEFAULT') continue
api.addVariant(
isSpecial ? `${variant}${key}` : `${variant}-${key}`,
({ args, container }) => {
return variantFn(value, { modifier: args?.modifier, container })
},
{
...options,
value,
id,
type: VARIANT_TYPES.MatchVariant,
variantInfo: VARIANT_INFO.Base,
}
)
}
let hasDefault = 'DEFAULT' in (options?.values ?? {})
api.addVariant(
variant,
({ args, container }) => {
if (args?.value === sharedState.NONE && !hasDefault) {
return null
}
return variantFn(
args?.value === sharedState.NONE
? options.values.DEFAULT
: // Falling back to args if it is a string, otherwise '' for older intellisense
// (JetBrains) plugins.
args?.value ?? (typeof args === 'string' ? args : ''),
{ modifier: args?.modifier, container }
)
},
{
...options,
id,
type: VARIANT_TYPES.MatchVariant,
variantInfo: VARIANT_INFO.Dynamic,
}
)
},
}
return api
}
let fileModifiedMapCache = new WeakMap()
export function getFileModifiedMap(context) {
if (!fileModifiedMapCache.has(context)) {
fileModifiedMapCache.set(context, new Map())
}
return fileModifiedMapCache.get(context)
}
function trackModified(files, fileModifiedMap) {
let changed = false
let mtimesToCommit = new Map()
for (let file of files) {
if (!file) continue
let parsed = url.parse(file)
let pathname = parsed.hash ? parsed.href.replace(parsed.hash, '') : parsed.href
pathname = parsed.search ? pathname.replace(parsed.search, '') : pathname
let newModified = fs.statSync(decodeURIComponent(pathname), { throwIfNoEntry: false })?.mtimeMs
if (!newModified) {
// It could happen that a file is passed in that doesn't exist. E.g.:
// postcss-cli will provide you a fake path when reading from stdin. This
// path then looks like /path-to-your-project/stdin In that case we just
// want to ignore it and don't track changes at all.
continue
}
if (!fileModifiedMap.has(file) || newModified > fileModifiedMap.get(file)) {
changed = true
}
mtimesToCommit.set(file, newModified)
}
return [changed, mtimesToCommit]
}
function extractVariantAtRules(node) {
node.walkAtRules((atRule) => {
if (['responsive', 'variants'].includes(atRule.name)) {
extractVariantAtRules(atRule)
atRule.before(atRule.nodes)
atRule.remove()
}
})
}
function collectLayerPlugins(root) {
let layerPlugins = []
root.each((node) => {
if (node.type === 'atrule' && ['responsive', 'variants'].includes(node.name)) {
node.name = 'layer'
node.params = 'utilities'
}
})
// Walk @layer rules and treat them like plugins
root.walkAtRules('layer', (layerRule) => {
extractVariantAtRules(layerRule)
if (layerRule.params === 'base') {
for (let node of layerRule.nodes) {
layerPlugins.push(function ({ addBase }) {
addBase(node, { respectPrefix: false })
})
}
layerRule.remove()
} else if (layerRule.params === 'components') {
for (let node of layerRule.nodes) {
layerPlugins.push(function ({ addComponents }) {
addComponents(node, { respectPrefix: false, preserveSource: true })
})
}
layerRule.remove()
} else if (layerRule.params === 'utilities') {
for (let node of layerRule.nodes) {
layerPlugins.push(function ({ addUtilities }) {
addUtilities(node, { respectPrefix: false, preserveSource: true })
})
}
layerRule.remove()
}
})
return layerPlugins
}
function resolvePlugins(context, root) {
let corePluginList = Object.entries(corePlugins)
.map(([name, plugin]) => {
if (!context.tailwindConfig.corePlugins.includes(name)) {
return null
}
return plugin
})
.filter(Boolean)
let userPlugins = context.tailwindConfig.plugins.map((plugin) => {
if (plugin.__isOptionsFunction) {
plugin = plugin()
}
return typeof plugin === 'function' ? plugin : plugin.handler
})
let layerPlugins = collectLayerPlugins(root)
// TODO: This is a workaround for backwards compatibility, since custom variants
// were historically sorted before screen/stackable variants.
let beforeVariants = [
variantPlugins['childVariant'],
variantPlugins['pseudoElementVariants'],
variantPlugins['pseudoClassVariants'],
variantPlugins['hasVariants'],
variantPlugins['ariaVariants'],
variantPlugins['dataVariants'],
]
let afterVariants = [
variantPlugins['supportsVariants'],
variantPlugins['reducedMotionVariants'],
variantPlugins['prefersContrastVariants'],
variantPlugins['printVariant'],
variantPlugins['screenVariants'],
variantPlugins['orientationVariants'],
variantPlugins['directionVariants'],
variantPlugins['darkVariants'],
variantPlugins['forcedColorsVariants'],
]
return [...corePluginList, ...beforeVariants, ...userPlugins, ...afterVariants, ...layerPlugins]
}
function registerPlugins(plugins, context) {
let variantList = []
let variantMap = new Map()
context.variantMap = variantMap
let offsets = new Offsets()
context.offsets = offsets
let classList = new Set()
let pluginApi = buildPluginApi(context.tailwindConfig, context, {
variantList,
variantMap,
offsets,
classList,
})
for (let plugin of plugins) {
if (Array.isArray(plugin)) {
for (let pluginItem of plugin) {
pluginItem(pluginApi)
}
} else {
plugin?.(pluginApi)
}
}
// Make sure to record bit masks for every variant
offsets.recordVariants(variantList, (variant) => variantMap.get(variant).length)
// Build variantMap
for (let [variantName, variantFunctions] of variantMap.entries()) {
context.variantMap.set(
variantName,
variantFunctions.map((variantFunction, idx) => [
offsets.forVariant(variantName, idx),
variantFunction,
])
)
}
let safelist = (context.tailwindConfig.safelist ?? []).filter(Boolean)
if (safelist.length > 0) {
let checks = []
for (let value of safelist) {
if (typeof value === 'string') {
context.changedContent.push({ content: value, extension: 'html' })
continue
}
if (value instanceof RegExp) {
log.warn('root-regex', [
'Regular expressions in `safelist` work differently in Tailwind CSS v3.0.',
'Update your `safelist` configuration to eliminate this warning.',
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
])
continue
}
checks.push(value)
}
if (checks.length > 0) {
let patternMatchingCount = new Map()
let prefixLength = context.tailwindConfig.prefix.length
let checkImportantUtils = checks.some((check) => check.pattern.source.includes('!'))
for (let util of classList) {
let utils = Array.isArray(util)
? (() => {
let [utilName, options] = util
let values = Object.keys(options?.values ?? {})
let classes = values.map((value) => formatClass(utilName, value))
if (options?.supportsNegativeValues) {
// This is the normal negated version
// e.g. `-inset-1` or `-tw-inset-1`
classes = [...classes, ...classes.map((cls) => '-' + cls)]
// This is the negated version *after* the prefix
// e.g. `tw--inset-1`
// The prefix is already attached to util name
// So we add the negative after the prefix
classes = [
...classes,
...classes.map(
(cls) => cls.slice(0, prefixLength) + '-' + cls.slice(prefixLength)
),
]
}
if (options.types.some(({ type }) => type === 'color')) {
classes = [
...classes,
...classes.flatMap((cls) =>
Object.keys(context.tailwindConfig.theme.opacity).map(
(opacity) => `${cls}/${opacity}`
)
),
]
}
if (checkImportantUtils && options?.respectImportant) {
classes = [...classes, ...classes.map((cls) => '!' + cls)]
}
return classes
})()
: [util]
for (let util of utils) {
for (let { pattern, variants = [] } of checks) {
// RegExp with the /g flag are stateful, so let's reset the last
// index pointer to reset the state.
pattern.lastIndex = 0
if (!patternMatchingCount.has(pattern)) {
patternMatchingCount.set(pattern, 0)
}
if (!pattern.test(util)) continue
patternMatchingCount.set(pattern, patternMatchingCount.get(pattern) + 1)
context.changedContent.push({ content: util, extension: 'html' })
for (let variant of variants) {
context.changedContent.push({
content: variant + context.tailwindConfig.separator + util,
extension: 'html',
})
}
}
}
}
for (let [regex, count] of patternMatchingCount.entries()) {
if (count !== 0) continue
log.warn([
`The safelist pattern \`${regex}\` doesn't match any Tailwind CSS classes.`,
'Fix this pattern or remove it from your `safelist` configuration.',
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
])
}
}
}
let darkClassName = [].concat(context.tailwindConfig.darkMode ?? 'media')[1] ?? 'dark'
// A list of utilities that are used by certain Tailwind CSS utilities but
// that don't exist on their own. This will result in them "not existing" and
// sorting could be weird since you still require them in order to make the
// host utilities work properly. (Thanks Biology)
let parasiteUtilities = [
prefix(context, darkClassName),
prefix(context, 'group'),
prefix(context, 'peer'),
]
context.getClassOrder = function getClassOrder(classes) {
// Sort classes so they're ordered in a deterministic manner
let sorted = [...classes].sort((a, z) => {
if (a === z) return 0
if (a < z) return -1
return 1
})
// Non-util classes won't be generated, so we default them to null
let sortedClassNames = new Map(sorted.map((className) => [className, null]))
// Sort all classes in order
// Non-tailwind classes won't be generated and will be left as `null`
let rules = generateRules(new Set(sorted), context, true)
rules = context.offsets.sort(rules)
let idx = BigInt(parasiteUtilities.length)
for (const [, rule] of rules) {
let candidate = rule.raws.tailwind.candidate
// When multiple rules match a candidate
// always take the position of the first one
sortedClassNames.set(candidate, sortedClassNames.get(candidate) ?? idx++)
}
return classes.map((className) => {
let order = sortedClassNames.get(className) ?? null
let parasiteIndex = parasiteUtilities.indexOf(className)
if (order === null && parasiteIndex !== -1) {
// This will make sure that it is at the very beginning of the
// `components` layer which technically means 'before any
// components'.
order = BigInt(parasiteIndex)
}
return [className, order]
})
}
// Generate a list of strings for autocompletion purposes, e.g.
// ['uppercase', 'lowercase', ...]
context.getClassList = function getClassList(options = {}) {
let output = []
for (let util of classList) {
if (Array.isArray(util)) {
let [utilName, utilOptions] = util
let negativeClasses = []
let modifiers = Object.keys(utilOptions?.modifiers ?? {})
if (utilOptions?.types?.some(({ type }) => type === 'color')) {
modifiers.push(...Object.keys(context.tailwindConfig.theme.opacity ?? {}))
}
let metadata = { modifiers }
let includeMetadata = options.includeMetadata && modifiers.length > 0
for (let [key, value] of Object.entries(utilOptions?.values ?? {})) {
// Ignore undefined and null values
if (value == null) {
continue
}
let cls = formatClass(utilName, key)
output.push(includeMetadata ? [cls, metadata] : cls)
if (utilOptions?.supportsNegativeValues && negateValue(value)) {
let cls = formatClass(utilName, `-${key}`)
negativeClasses.push(includeMetadata ? [cls, metadata] : cls)
}
}
output.push(...negativeClasses)
} else {
output.push(util)
}
}
return output
}
// Generate a list of available variants with meta information of the type of variant.
context.getVariants = function getVariants() {
let result = []
for (let [name, options] of context.variantOptions.entries()) {
if (options.variantInfo === VARIANT_INFO.Base) continue
result.push({
name,
isArbitrary: options.type === Symbol.for('MATCH_VARIANT'),
values: Object.keys(options.values ?? {}),
hasDash: name !== '@',
selectors({ modifier, value } = {}) {
let candidate = '__TAILWIND_PLACEHOLDER__'
let rule = postcss.rule({ selector: `.${candidate}` })
let container = postcss.root({ nodes: [rule.clone()] })
let before = container.toString()
let fns = (context.variantMap.get(name) ?? []).flatMap(([_, fn]) => fn)
let formatStrings = []
for (let fn of fns) {
let localFormatStrings = []
let api = {
args: { modifier, value: options.values?.[value] ?? value },
separator: context.tailwindConfig.separator,
modifySelectors(modifierFunction) {
// Run the modifierFunction over each rule
container.each((rule) => {
if (rule.type !== 'rule') {
return
}
rule.selectors = rule.selectors.map((selector) => {
return modifierFunction({
get className() {
return getClassNameFromSelector(selector)
},
selector,
})
})
})
return container
},
format(str) {
localFormatStrings.push(str)
},
wrap(wrapper) {
localFormatStrings.push(`@${wrapper.name} ${wrapper.params} { & }`)
},
container,
}
let ruleWithVariant = fn(api)
if (localFormatStrings.length > 0) {
formatStrings.push(localFormatStrings)
}
if (Array.isArray(ruleWithVariant)) {
for (let variantFunction of ruleWithVariant) {
localFormatStrings = []
variantFunction(api)
formatStrings.push(localFormatStrings)
}
}
}
// Reverse engineer the result of the `container`
let manualFormatStrings = []
let after = container.toString()
if (before !== after) {
// Figure out all selectors
container.walkRules((rule) => {
let modified = rule.selector
// Rebuild the base selector, this is what plugin authors would do
// as well. E.g.: `${variant}${separator}${className}`.
// However, plugin authors probably also prepend or append certain
// classes, pseudos, ids, ...
let rebuiltBase = selectorParser((selectors) => {
selectors.walkClasses((classNode) => {
classNode.value = `${name}${context.tailwindConfig.separator}${classNode.value}`
})
}).processSync(modified)
// Now that we know the original selector, the new selector, and
// the rebuild part in between, we can replace the part that plugin
// authors need to rebuild with `&`, and eventually store it in the
// collectedFormats. Similar to what `format('...')` would do.
//
// E.g.:
// variant: foo
// selector: .markdown > p
// modified (by plugin): .foo .foo\\:markdown > p
// rebuiltBase (internal): .foo\\:markdown > p
// format: .foo &
manualFormatStrings.push(modified.replace(rebuiltBase, '&').replace(candidate, '&'))
})
// Figure out all atrules
container.walkAtRules((atrule) => {
manualFormatStrings.push(`@${atrule.name} (${atrule.params}) { & }`)
})
}
let isArbitraryVariant = !(value in (options.values ?? {}))
let internalFeatures = options[INTERNAL_FEATURES] ?? {}
let respectPrefix = (() => {
if (isArbitraryVariant) return false
if (internalFeatures.respectPrefix === false) return false
return true
})()
formatStrings = formatStrings.map((format) =>
format.map((str) => ({
format: str,
respectPrefix,
}))
)
manualFormatStrings = manualFormatStrings.map((format) => ({
format,
respectPrefix,
}))
let opts = {
candidate,
context,
}
let result = formatStrings.map((formats) =>
finalizeSelector(`.${candidate}`, formatVariantSelector(formats, opts), opts)
.replace(`.${candidate}`, '&')
.replace('{ & }', '')
.trim()
)
if (manualFormatStrings.length > 0) {
result.push(
formatVariantSelector(manualFormatStrings, opts)
.toString()
.replace(`.${candidate}`, '&')
)
}
return result
},
})
}
return result
}
}
/**
* Mark as class as retroactively invalid
*
*
* @param {string} candidate
*/
function markInvalidUtilityCandidate(context, candidate) {
if (!context.classCache.has(candidate)) {
return
}
// Mark this as not being a real utility
context.notClassCache.add(candidate)
// Remove it from any candidate-specific caches
context.classCache.delete(candidate)
context.applyClassCache.delete(candidate)
context.candidateRuleMap.delete(candidate)
context.candidateRuleCache.delete(candidate)
// Ensure the stylesheet gets rebuilt
context.stylesheetCache = null
}
/**
* Mark as class as retroactively invalid
*
* @param {import('postcss').Node} node
*/
function markInvalidUtilityNode(context, node) {
let candidate = node.raws.tailwind.candidate
if (!candidate) {
return
}
for (const entry of context.ruleCache) {
if (entry[1].raws.tailwind.candidate === candidate) {
context.ruleCache.delete(entry)
// context.postCssNodeCache.delete(node)
}
}
markInvalidUtilityCandidate(context, candidate)
}
export function createContext(tailwindConfig, changedContent = [], root = postcss.root()) {
let context = {
disposables: [],
ruleCache: new Set(),
candidateRuleCache: new Map(),
classCache: new Map(),
applyClassCache: new Map(),
// Seed the not class cache with the blocklist (which is only strings)
notClassCache: new Set(tailwindConfig.blocklist ?? []),
postCssNodeCache: new Map(),
candidateRuleMap: new Map(),
tailwindConfig,
changedContent: changedContent,
variantMap: new Map(),
stylesheetCache: null,
variantOptions: new Map(),
markInvalidUtilityCandidate: (candidate) => markInvalidUtilityCandidate(context, candidate),
markInvalidUtilityNode: (node) => markInvalidUtilityNode(context, node),
}
let resolvedPlugins = resolvePlugins(context, root)
registerPlugins(resolvedPlugins, context)
return context
}
let contextMap = sharedState.contextMap
let configContextMap = sharedState.configContextMap
let contextSourcesMap = sharedState.contextSourcesMap
export function getContext(
root,
result,
tailwindConfig,
userConfigPath,
tailwindConfigHash,
contextDependencies
) {
let sourcePath = result.opts.from
let isConfigFile = userConfigPath !== null
env.DEBUG && console.log('Source path:', sourcePath)
let existingContext
if (isConfigFile && contextMap.has(sourcePath)) {
existingContext = contextMap.get(sourcePath)
} else if (configContextMap.has(tailwindConfigHash)) {
let context = configContextMap.get(tailwindConfigHash)
contextSourcesMap.get(context).add(sourcePath)
contextMap.set(sourcePath, context)
existingContext = context
}
let cssDidChange = hasContentChanged(sourcePath, root)
// If there's already a context in the cache and we don't need to
// reset the context, return the cached context.
if (existingContext) {
let [contextDependenciesChanged, mtimesToCommit] = trackModified(
[...contextDependencies],
getFileModifiedMap(existingContext)
)
if (!contextDependenciesChanged && !cssDidChange) {
return [existingContext, false, mtimesToCommit]
}
}
// If this source is in the context map, get the old context.
// Remove this source from the context sources for the old context,
// and clean up that context if no one else is using it. This can be
// called by many processes in rapid succession, so we check for presence
// first because the first process to run this code will wipe it out first.
if (contextMap.has(sourcePath)) {
let oldContext = contextMap.get(sourcePath)
if (contextSourcesMap.has(oldContext)) {
contextSourcesMap.get(oldContext).delete(sourcePath)
if (contextSourcesMap.get(oldContext).size === 0) {
contextSourcesMap.delete(oldContext)
for (let [tailwindConfigHash, context] of configContextMap) {
if (context === oldContext) {
configContextMap.delete(tailwindConfigHash)
}
}
for (let disposable of oldContext.disposables.splice(0)) {
disposable(oldContext)
}
}
}
}
env.DEBUG && console.log('Setting up new context...')
let context = createContext(tailwindConfig, [], root)
Object.assign(context, {
userConfigPath,
})
let [, mtimesToCommit] = trackModified([...contextDependencies], getFileModifiedMap(context))
// ---
// Update all context tracking state
configContextMap.set(tailwindConfigHash, context)
contextMap.set(sourcePath, context)
if (!contextSourcesMap.has(context)) {
contextSourcesMap.set(context, new Set())
}
contextSourcesMap.get(context).add(sourcePath)
return [context, true, mtimesToCommit]
}
// @ts-check
import fs from 'fs'
import LRU from '@alloc/quick-lru'
import hash from '../util/hashConfig'
import resolveConfig from '../public/resolve-config'
import resolveConfigPath from '../util/resolveConfigPath'
import { getContext, getFileModifiedMap } from './setupContextUtils'
import parseDependency from '../util/parseDependency'
import { validateConfig } from '../util/validateConfig.js'
import { parseCandidateFiles, resolvedChangedContent } from './content.js'
import { loadConfig } from '../lib/load-config'
import getModuleDependencies from './getModuleDependencies'
let configPathCache = new LRU({ maxSize: 100 })
let candidateFilesCache = new WeakMap()
function getCandidateFiles(context, tailwindConfig) {
if (candidateFilesCache.has(context)) {
return candidateFilesCache.get(context)
}
let candidateFiles = parseCandidateFiles(context, tailwindConfig)
return candidateFilesCache.set(context, candidateFiles).get(context)
}
// Get the config object based on a path
function getTailwindConfig(configOrPath) {
let userConfigPath = resolveConfigPath(configOrPath)
if (userConfigPath !== null) {
let [prevConfig, prevConfigHash, prevDeps, prevModified] =
configPathCache.get(userConfigPath) || []
let newDeps = getModuleDependencies(userConfigPath)
let modified = false
let newModified = new Map()
for (let file of newDeps) {
let time = fs.statSync(file).mtimeMs
newModified.set(file, time)
if (!prevModified || !prevModified.has(file) || time > prevModified.get(file)) {
modified = true
}
}
// It hasn't changed (based on timestamps)
if (!modified) {
return [prevConfig, userConfigPath, prevConfigHash, prevDeps]
}
// It has changed (based on timestamps), or first run
for (let file of newDeps) {
delete require.cache[file]
}
let newConfig = validateConfig(resolveConfig(loadConfig(userConfigPath)))
let newHash = hash(newConfig)
configPathCache.set(userConfigPath, [newConfig, newHash, newDeps, newModified])
return [newConfig, userConfigPath, newHash, newDeps]
}
// It's a plain object, not a path
let newConfig = resolveConfig(configOrPath?.config ?? configOrPath ?? {})
newConfig = validateConfig(newConfig)
return [newConfig, null, hash(newConfig), []]
}
// DISABLE_TOUCH = TRUE
// Retrieve an existing context from cache if possible (since contexts are unique per
// source path), or set up a new one (including setting up watchers and registering
// plugins) then return it
export default function setupTrackingContext(configOrPath) {
return ({ tailwindDirectives, registerDependency }) => {
return (root, result) => {
let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] =
getTailwindConfig(configOrPath)
let contextDependencies = new Set(configDependencies)
// If there are no @tailwind or @apply rules, we don't consider this CSS
// file or its dependencies to be dependencies of the context. Can reuse
// the context even if they change. We may want to think about `@layer`
// being part of this trigger too, but it's tough because it's impossible
// for a layer in one file to end up in the actual @tailwind rule in
// another file since independent sources are effectively isolated.
if (tailwindDirectives.size > 0) {
// Add current css file as a context dependencies.
contextDependencies.add(result.opts.from)
// Add all css @import dependencies as context dependencies.
for (let message of result.messages) {
if (message.type === 'dependency') {
contextDependencies.add(message.file)
}
}
}
let [context, , mTimesToCommit] = getContext(
root,
result,
tailwindConfig,
userConfigPath,
tailwindConfigHash,
contextDependencies
)
let fileModifiedMap = getFileModifiedMap(context)
let candidateFiles = getCandidateFiles(context, tailwindConfig)
// If there are no @tailwind or @apply rules, we don't consider this CSS file or it's
// dependencies to be dependencies of the context. Can reuse the context even if they change.
// We may want to think about `@layer` being part of this trigger too, but it's tough
// because it's impossible for a layer in one file to end up in the actual @tailwind rule
// in another file since independent sources are effectively isolated.
if (tailwindDirectives.size > 0) {
// Add template paths as postcss dependencies.
for (let contentPath of candidateFiles) {
for (let dependency of parseDependency(contentPath)) {
registerDependency(dependency)
}
}
let [changedContent, contentMTimesToCommit] = resolvedChangedContent(
context,
candidateFiles,
fileModifiedMap
)
for (let content of changedContent) {
context.changedContent.push(content)
}
// Add the mtimes of the content files to the commit list
// We can overwrite the existing values because unconditionally
// This is because:
// 1. Most of the files here won't be in the map yet
// 2. If they are that means it's a context dependency
// and we're reading this after the context. This means
// that the mtime we just read is strictly >= the context
// mtime. Unless the user / os is doing something weird
// in which the mtime would be going backwards. If that
// happens there's already going to be problems.
for (let [path, mtime] of contentMTimesToCommit.entries()) {
mTimesToCommit.set(path, mtime)
}
}
for (let file of configDependencies) {
registerDependency({ type: 'dependency', file })
}
// "commit" the new modified time for all context deps
// We do this here because we want content tracking to
// read the "old" mtime even when it's a context dependency.
for (let [path, mtime] of mTimesToCommit.entries()) {
fileModifiedMap.set(path, mtime)
}
return context
}
}
}
export const env =
typeof process !== 'undefined'
? {
NODE_ENV: process.env.NODE_ENV,
DEBUG: resolveDebug(process.env.DEBUG),
}
: {
NODE_ENV: 'production',
DEBUG: false,
}
export const contextMap = new Map()
export const configContextMap = new Map()
export const contextSourcesMap = new Map()
export const sourceHashMap = new Map()
export const NOT_ON_DEMAND = new String('*')
export const NONE = Symbol('__NONE__')
export function resolveDebug(debug) {
if (debug === undefined) {
return false
}
// Environment variables are strings, so convert to boolean
if (debug === 'true' || debug === '1') {
return true
}
if (debug === 'false' || debug === '0') {
return false
}
// Keep the debug convention into account:
// DEBUG=* -> This enables all debug modes
// DEBUG=projectA,projectB,projectC -> This enables debug for projectA, projectB and projectC
// DEBUG=projectA:* -> This enables all debug modes for projectA (if you have sub-types)
// DEBUG=projectA,-projectB -> This enables debug for projectA and explicitly disables it for projectB
if (debug === '*') {
return true
}
let debuggers = debug.split(',').map((d) => d.split(':')[0])
// Ignoring tailwindcss
if (debuggers.includes('-tailwindcss')) {
return false
}
// Including tailwindcss
if (debuggers.includes('tailwindcss')) {
return true
}
return false
}
import { normalizeScreens } from '../util/normalizeScreens'
import buildMediaQuery from '../util/buildMediaQuery'
export default function ({ tailwindConfig: { theme } }) {
return function (css) {
css.walkAtRules('screen', (atRule) => {
let screen = atRule.params
let screens = normalizeScreens(theme.screens)
let screenDefinition = screens.find(({ name }) => name === screen)
if (!screenDefinition) {
throw atRule.error(`No \`${screen}\` screen found.`)
}
atRule.name = 'media'
atRule.params = buildMediaQuery(screenDefinition)
})
}
}
import postcss from 'postcss'
import lightningcss, { Features } from 'lightningcss'
import browserslist from 'browserslist'
import setupTrackingContext from './lib/setupTrackingContext'
import processTailwindFeatures from './processTailwindFeatures'
import { env } from './lib/sharedState'
import { findAtConfigPath } from './lib/findAtConfigPath'
import { handleImportAtRules } from './lib/handleImportAtRules'
import { version as tailwindVersion } from '../package.json'
function license() {
return `/* ! tailwindcss v${tailwindVersion} | MIT License | https://tailwindcss.com */\n`
}
module.exports = function tailwindcss(configOrPath) {
return {
postcssPlugin: 'tailwindcss',
plugins: [
env.DEBUG &&
function (root) {
console.log('\n')
console.time('JIT TOTAL')
return root
},
...handleImportAtRules(),
async function (root, result) {
// Use the path for the `@config` directive if it exists, otherwise use the
// path for the file being processed
configOrPath = findAtConfigPath(root, result) ?? configOrPath
let context = setupTrackingContext(configOrPath)
if (root.type === 'document') {
let roots = root.nodes.filter((node) => node.type === 'root')
for (const root of roots) {
if (root.type === 'root') {
await processTailwindFeatures(context)(root, result)
}
}
return
}
await processTailwindFeatures(context)(root, result)
},
function lightningCssPlugin(_root, result) {
let map = result.map ?? result.opts.map
let intermediateResult = result.root.toResult({
map: map ? { inline: true } : false,
})
let intermediateMap = intermediateResult.map?.toJSON?.() ?? map
try {
let resolvedBrowsersListConfig = browserslist.findConfig(
result.opts.from ?? process.cwd()
)?.defaults
let defaultBrowsersListConfig = require('../package.json').browserslist
let browsersListConfig = resolvedBrowsersListConfig ?? defaultBrowsersListConfig
let transformed = lightningcss.transform({
filename: result.opts.from,
code: Buffer.from(intermediateResult.css),
minify: false,
sourceMap: !!intermediateMap,
targets: lightningcss.browserslistToTargets(browserslist(browsersListConfig)),
errorRecovery: true,
drafts: {
customMedia: true,
},
nonStandard: {
deepSelectorCombinator: true,
},
include: Features.Nesting,
exclude: Features.LogicalProperties,
})
let code = transformed.code.toString()
// https://postcss.org/api/#sourcemapoptions
if (intermediateMap && transformed.map != null) {
let prev = transformed.map.toString()
if (typeof intermediateMap === 'object') {
intermediateMap.prev = prev
} else {
code = `${code}\n/*# sourceMappingURL=data:application/json;base64,${Buffer.from(
prev
).toString('base64')} */`
}
}
result.root = postcss.parse(license() + code, {
...result.opts,
map: intermediateMap,
})
} catch (err) {
if (err.source && typeof process !== 'undefined' && process.env.JEST_WORKER_ID) {
let lines = err.source.split('\n')
err = new Error(
[
'Error formatting using Lightning CSS:',
'',
...[
'```css',
...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line),
' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(),
...lines.slice(err.loc.line, err.loc.line + 2),
'```',
],
].join('\n')
)
}
if (Error.captureStackTrace) {
Error.captureStackTrace(err, lightningCssPlugin)
}
throw err
}
},
env.DEBUG &&
function (root) {
console.timeEnd('JIT TOTAL')
console.log('\n')
return root
},
].filter(Boolean),
}
}
module.exports.postcss = true
import { nesting } from './plugin'
export default Object.assign(
function (opts) {
return {
postcssPlugin: 'tailwindcss/nesting',
Once(root, { result }) {
return nesting(opts)(root, result)
},
}
},
{ postcss: true }
)
import postcss from 'postcss'
import postcssNested from 'postcss-nested'
export function nesting(opts = postcssNested) {
return (root, result) => {
root.walkAtRules('screen', (rule) => {
rule.name = 'media'
rule.params = `screen(${rule.params})`
})
root.walkAtRules('apply', (rule) => {
rule.before(postcss.decl({ prop: '__apply', value: rule.params, source: rule.source }))
rule.remove()
})
let plugin = (() => {
if (
typeof opts === 'function' ||
(typeof opts === 'object' && opts?.hasOwnProperty?.('postcssPlugin'))
) {
return opts
}
if (typeof opts === 'string') {
return require(opts)
}
if (Object.keys(opts).length <= 0) {
return postcssNested
}
throw new Error('tailwindcss/nesting should be loaded with a nesting plugin.')
})()
postcss([plugin]).process(root, result.opts).sync()
root.walkDecls('__apply', (decl) => {
decl.before(postcss.atRule({ name: 'apply', params: decl.value, source: decl.source }))
decl.remove()
})
/**
* Use a private PostCSS API to remove the "clean" flag from the entire AST.
* This is done because running process() on the AST will set the "clean"
* flag on all nodes, which we don't want.
*
* This causes downstream plugins using the visitor API to be skipped.
*
* This is guarded because the PostCSS API is not public
* and may change in future versions of PostCSS.
*
* See https://github.com/postcss/postcss/issues/1712 for more details
*
* @param {import('postcss').Node} node
*/
function markDirty(node) {
if (!('markDirty' in node)) {
return
}
// Traverse the tree down to the leaf nodes
if (node.nodes) {
node.nodes.forEach((n) => markDirty(n))
}
// If it's a leaf node mark it as dirty
// We do this here because marking a node as dirty
// will walk up the tree and mark all parents as dirty
// resulting in a lot of unnecessary work if we did this
// for every single node
if (!node.nodes) {
node.markDirty()
}
}
markDirty(root)
return root
}
}
# tailwindcss/nesting
This is a PostCSS plugin that wraps [postcss-nested](https://github.com/postcss/postcss-nested) or [postcss-nesting](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting) and acts as a compatibility layer to make sure your nesting plugin of choice properly understands Tailwind's custom syntax like `@apply` and `@screen`.
Add it to your PostCSS configuration, somewhere before Tailwind itself:
```js
// postcss.config.js
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss/nesting'),
require('tailwindcss'),
require('autoprefixer'),
]
}
```
By default, it uses the [postcss-nested](https://github.com/postcss/postcss-nested) plugin under the hood, which uses a Sass-like syntax and is the plugin that powers nesting support in the [Tailwind CSS plugin API](https://tailwindcss.com/docs/plugins#css-in-js-syntax).
If you'd rather use [postcss-nesting](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting) (which is based on the work-in-progress [CSS Nesting](https://drafts.csswg.org/css-nesting-1/) specification), first install the plugin alongside:
```shell
npm install postcss-nesting
```
Then pass the plugin itself as an argument to `tailwindcss/nesting` in your PostCSS configuration:
```js
// postcss.config.js
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss/nesting')(require('postcss-nesting')),
require('tailwindcss'),
require('autoprefixer'),
]
}
```
This can also be helpful if for whatever reason you need to use a very specific version of `postcss-nested` and want to override the version we bundle with `tailwindcss/nesting` itself.
import normalizeTailwindDirectives from './lib/normalizeTailwindDirectives'
import expandTailwindAtRules from './lib/expandTailwindAtRules'
import expandApplyAtRules from './lib/expandApplyAtRules'
import evaluateTailwindFunctions from './lib/evaluateTailwindFunctions'
import substituteScreenAtRules from './lib/substituteScreenAtRules'
import resolveDefaultsAtRules from './lib/resolveDefaultsAtRules'
import collapseAdjacentRules from './lib/collapseAdjacentRules'
import collapseDuplicateDeclarations from './lib/collapseDuplicateDeclarations'
import partitionApplyAtRules from './lib/partitionApplyAtRules'
import detectNesting from './lib/detectNesting'
import { createContext } from './lib/setupContextUtils'
import { issueFlagNotices } from './featureFlags'
export default function processTailwindFeatures(setupContext) {
return async function (root, result) {
let { tailwindDirectives, applyDirectives } = normalizeTailwindDirectives(root)
detectNesting()(root, result)
// Partition apply rules that are found in the css
// itself.
partitionApplyAtRules()(root, result)
let context = setupContext({
tailwindDirectives,
applyDirectives,
registerDependency(dependency) {
result.messages.push({
plugin: 'tailwindcss',
parent: result.opts.from,
...dependency,
})
},
createContext(tailwindConfig, changedContent) {
return createContext(tailwindConfig, changedContent, root)
},
})(root, result)
if (context.tailwindConfig.separator === '-') {
throw new Error(
"The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead."
)
}
issueFlagNotices(context.tailwindConfig)
await expandTailwindAtRules(context)(root, result)
// Partition apply rules that are generated by
// addComponents, addUtilities and so on.
partitionApplyAtRules()(root, result)
expandApplyAtRules(context)(root, result)
evaluateTailwindFunctions(context)(root, result)
substituteScreenAtRules(context)(root, result)
resolveDefaultsAtRules(context)(root, result)
collapseAdjacentRules(context)(root, result)
collapseDuplicateDeclarations(context)(root, result)
}
}
import log from '../util/log'
function warn({ version, from, to }) {
log.warn(`${from}-color-renamed`, [
`As of Tailwind CSS ${version}, \`${from}\` has been renamed to \`${to}\`.`,
'Update your configuration file to silence this warning.',
])
}
export default {
inherit: 'inherit',
current: 'currentColor',
transparent: 'transparent',
black: '#000',
white: '#fff',
slate: {
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a',
950: '#020617',
},
gray: {
50: '#f9fafb',
100: '#f3f4f6',
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827',
950: '#030712',
},
zinc: {
50: '#fafafa',
100: '#f4f4f5',
200: '#e4e4e7',
300: '#d4d4d8',
400: '#a1a1aa',
500: '#71717a',
600: '#52525b',
700: '#3f3f46',
800: '#27272a',
900: '#18181b',
950: '#09090b',
},
neutral: {
50: '#fafafa',
100: '#f5f5f5',
200: '#e5e5e5',
300: '#d4d4d4',
400: '#a3a3a3',
500: '#737373',
600: '#525252',
700: '#404040',
800: '#262626',
900: '#171717',
950: '#0a0a0a',
},
stone: {
50: '#fafaf9',
100: '#f5f5f4',
200: '#e7e5e4',
300: '#d6d3d1',
400: '#a8a29e',
500: '#78716c',
600: '#57534e',
700: '#44403c',
800: '#292524',
900: '#1c1917',
950: '#0c0a09',
},
red: {
50: '#fef2f2',
100: '#fee2e2',
200: '#fecaca',
300: '#fca5a5',
400: '#f87171',
500: '#ef4444',
600: '#dc2626',
700: '#b91c1c',
800: '#991b1b',
900: '#7f1d1d',
950: '#450a0a',
},
orange: {
50: '#fff7ed',
100: '#ffedd5',
200: '#fed7aa',
300: '#fdba74',
400: '#fb923c',
500: '#f97316',
600: '#ea580c',
700: '#c2410c',
800: '#9a3412',
900: '#7c2d12',
950: '#431407',
},
amber: {
50: '#fffbeb',
100: '#fef3c7',
200: '#fde68a',
300: '#fcd34d',
400: '#fbbf24',
500: '#f59e0b',
600: '#d97706',
700: '#b45309',
800: '#92400e',
900: '#78350f',
950: '#451a03',
},
yellow: {
50: '#fefce8',
100: '#fef9c3',
200: '#fef08a',
300: '#fde047',
400: '#facc15',
500: '#eab308',
600: '#ca8a04',
700: '#a16207',
800: '#854d0e',
900: '#713f12',
950: '#422006',
},
lime: {
50: '#f7fee7',
100: '#ecfccb',
200: '#d9f99d',
300: '#bef264',
400: '#a3e635',
500: '#84cc16',
600: '#65a30d',
700: '#4d7c0f',
800: '#3f6212',
900: '#365314',
950: '#1a2e05',
},
green: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d',
950: '#052e16',
},
emerald: {
50: '#ecfdf5',
100: '#d1fae5',
200: '#a7f3d0',
300: '#6ee7b7',
400: '#34d399',
500: '#10b981',
600: '#059669',
700: '#047857',
800: '#065f46',
900: '#064e3b',
950: '#022c22',
},
teal: {
50: '#f0fdfa',
100: '#ccfbf1',
200: '#99f6e4',
300: '#5eead4',
400: '#2dd4bf',
500: '#14b8a6',
600: '#0d9488',
700: '#0f766e',
800: '#115e59',
900: '#134e4a',
950: '#042f2e',
},
cyan: {
50: '#ecfeff',
100: '#cffafe',
200: '#a5f3fc',
300: '#67e8f9',
400: '#22d3ee',
500: '#06b6d4',
600: '#0891b2',
700: '#0e7490',
800: '#155e75',
900: '#164e63',
950: '#083344',
},
sky: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
950: '#082f49',
},
blue: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
950: '#172554',
},
indigo: {
50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1',
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81',
950: '#1e1b4b',
},
violet: {
50: '#f5f3ff',
100: '#ede9fe',
200: '#ddd6fe',
300: '#c4b5fd',
400: '#a78bfa',
500: '#8b5cf6',
600: '#7c3aed',
700: '#6d28d9',
800: '#5b21b6',
900: '#4c1d95',
950: '#2e1065',
},
purple: {
50: '#faf5ff',
100: '#f3e8ff',
200: '#e9d5ff',
300: '#d8b4fe',
400: '#c084fc',
500: '#a855f7',
600: '#9333ea',
700: '#7e22ce',
800: '#6b21a8',
900: '#581c87',
950: '#3b0764',
},
fuchsia: {
50: '#fdf4ff',
100: '#fae8ff',
200: '#f5d0fe',
300: '#f0abfc',
400: '#e879f9',
500: '#d946ef',
600: '#c026d3',
700: '#a21caf',
800: '#86198f',
900: '#701a75',
950: '#4a044e',
},
pink: {
50: '#fdf2f8',
100: '#fce7f3',
200: '#fbcfe8',
300: '#f9a8d4',
400: '#f472b6',
500: '#ec4899',
600: '#db2777',
700: '#be185d',
800: '#9d174d',
900: '#831843',
950: '#500724',
},
rose: {
50: '#fff1f2',
100: '#ffe4e6',
200: '#fecdd3',
300: '#fda4af',
400: '#fb7185',
500: '#f43f5e',
600: '#e11d48',
700: '#be123c',
800: '#9f1239',
900: '#881337',
950: '#4c0519',
},
get lightBlue() {
warn({ version: 'v2.2', from: 'lightBlue', to: 'sky' })
return this.sky
},
get warmGray() {
warn({ version: 'v3.0', from: 'warmGray', to: 'stone' })
return this.stone
},
get trueGray() {
warn({ version: 'v3.0', from: 'trueGray', to: 'neutral' })
return this.neutral
},
get coolGray() {
warn({ version: 'v3.0', from: 'coolGray', to: 'gray' })
return this.gray
},
get blueGray() {
warn({ version: 'v3.0', from: 'blueGray', to: 'slate' })
return this.slate
},
}
import createPlugin from '../util/createPlugin'
export default createPlugin
import { cloneDeep } from '../util/cloneDeep'
import defaultConfig from '../../stubs/config.full'
export default cloneDeep(defaultConfig)
import { cloneDeep } from '../util/cloneDeep'
import defaultFullConfig from '../../stubs/config.full'
export default cloneDeep(defaultFullConfig.theme)
import { loadConfig } from '../lib/load-config'
export default loadConfig
import resolveConfigObjects from '../util/resolveConfig'
import getAllConfigs from '../util/getAllConfigs'
export default function resolveConfig(...configs) {
let [, ...defaultConfigs] = getAllConfigs(configs[0])
return resolveConfigObjects([...configs, ...defaultConfigs])
}
import parser from 'postcss-selector-parser'
import { movePseudos } from './pseudoElements'
export function applyImportantSelector(selector, important) {
let sel = parser().astSync(selector)
sel.each((sel) => {
// Wrap with :is if it's not already wrapped
let isWrapped =
sel.nodes[0].type === 'pseudo' &&
sel.nodes[0].value === ':is' &&
sel.nodes.every((node) => node.type !== 'combinator')
if (!isWrapped) {
sel.nodes = [
parser.pseudo({
value: ':is',
nodes: [sel.clone()],
}),
]
}
movePseudos(sel)
})
return `${important} ${sel.toString()}`
}
export default function bigSign(bigIntValue) {
return (bigIntValue > 0n) - (bigIntValue < 0n)
}
export default function buildMediaQuery(screens) {
screens = Array.isArray(screens) ? screens : [screens]
return screens
.map((screen) => {
let values = screen.values.map((screen) => {
if (screen.raw !== undefined) {
return screen.raw
}
return [
screen.min && `(min-width: ${screen.min})`,
screen.max && `(max-width: ${screen.max})`,
]
.filter(Boolean)
.join(' and ')
})
return screen.not ? `not all and ${values}` : values
})
.join(', ')
}
export function cloneDeep(value) {
if (Array.isArray(value)) {
return value.map((child) => cloneDeep(child))
}
if (typeof value === 'object' && value !== null) {
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, cloneDeep(v)]))
}
return value
}
/**
* @param {import('postcss').Container[]} nodes
* @param {any} source
* @param {any} raws
* @returns {import('postcss').Container[]}
*/
export default function cloneNodes(nodes, source = undefined, raws = undefined) {
return nodes.map((node) => {
let cloned = node.clone()
if (raws !== undefined) {
cloned.raws.tailwind = {
...cloned.raws.tailwind,
...raws,
}
}
if (source !== undefined) {
traverse(cloned, (node) => {
// Do not traverse nodes that have opted
// to preserve their original source
let shouldPreserveSource = node.raws.tailwind?.preserveSource === true && node.source
if (shouldPreserveSource) {
return false
}
// Otherwise we can safely replace the source
// And continue traversing
node.source = source
})
}
return cloned
})
}
/**
* Traverse a tree of nodes and don't traverse children if the callback
* returns false. Ideally we'd use Container#walk instead of this
* function but it stops traversing siblings too.
*
* @param {import('postcss').Container} node
* @param {(node: import('postcss').Container) => boolean} onNode
*/
function traverse(node, onNode) {
if (onNode(node) !== false) {
node.each?.((child) => traverse(child, onNode))
}
}
import namedColors from './colorNames'
let HEX = /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i
let SHORT_HEX = /^#([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i
let VALUE = /(?:\d+|\d*\.\d+)%?/
let SEP = /(?:\s*,\s*|\s+)/
let ALPHA_SEP = /\s*[,/]\s*/
let CUSTOM_PROPERTY = /var\(--(?:[^ )]*?)(?:,(?:[^ )]*?|var\(--[^ )]*?\)))?\)/
let RGB = new RegExp(
`^(rgba?)\\(\\s*(${VALUE.source}|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$`
)
let HSL = new RegExp(
`^(hsla?)\\(\\s*((?:${VALUE.source})(?:deg|rad|grad|turn)?|${CUSTOM_PROPERTY.source})(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?(?:${ALPHA_SEP.source}(${VALUE.source}|${CUSTOM_PROPERTY.source}))?\\s*\\)$`
)
// In "loose" mode the color may contain fewer than 3 parts, as long as at least
// one of the parts is variable.
export function parseColor(value, { loose = false } = {}) {
if (typeof value !== 'string') {
return null
}
value = value.trim()
if (value === 'transparent') {
return { mode: 'rgb', color: ['0', '0', '0'], alpha: '0' }
}
if (value in namedColors) {
return { mode: 'rgb', color: namedColors[value].map((v) => v.toString()) }
}
let hex = value
.replace(SHORT_HEX, (_, r, g, b, a) => ['#', r, r, g, g, b, b, a ? a + a : ''].join(''))
.match(HEX)
if (hex !== null) {
return {
mode: 'rgb',
color: [parseInt(hex[1], 16), parseInt(hex[2], 16), parseInt(hex[3], 16)].map((v) =>
v.toString()
),
alpha: hex[4] ? (parseInt(hex[4], 16) / 255).toString() : undefined,
}
}
let match = value.match(RGB) ?? value.match(HSL)
if (match === null) {
return null
}
let color = [match[2], match[3], match[4]].filter(Boolean).map((v) => v.toString())
// rgba(var(--my-color), 0.1)
// hsla(var(--my-color), 0.1)
if (color.length === 2 && color[0].startsWith('var(')) {
return {
mode: match[1],
color: [color[0]],
alpha: color[1],
}
}
if (!loose && color.length !== 3) {
return null
}
if (color.length < 3 && !color.some((part) => /^var\(.*?\)$/.test(part))) {
return null
}
return {
mode: match[1],
color,
alpha: match[5]?.toString?.(),
}
}
export function formatColor({ mode, color, alpha }) {
let hasAlpha = alpha !== undefined
if (mode === 'rgba' || mode === 'hsla') {
return `${mode}(${color.join(', ')}${hasAlpha ? `, ${alpha}` : ''})`
}
return `${mode}(${color.join(' ')}${hasAlpha ? ` / ${alpha}` : ''})`
}
export default {
aliceblue: [240, 248, 255],
antiquewhite: [250, 235, 215],
aqua: [0, 255, 255],
aquamarine: [127, 255, 212],
azure: [240, 255, 255],
beige: [245, 245, 220],
bisque: [255, 228, 196],
black: [0, 0, 0],
blanchedalmond: [255, 235, 205],
blue: [0, 0, 255],
blueviolet: [138, 43, 226],
brown: [165, 42, 42],
burlywood: [222, 184, 135],
cadetblue: [95, 158, 160],
chartreuse: [127, 255, 0],
chocolate: [210, 105, 30],
coral: [255, 127, 80],
cornflowerblue: [100, 149, 237],
cornsilk: [255, 248, 220],
crimson: [220, 20, 60],
cyan: [0, 255, 255],
darkblue: [0, 0, 139],
darkcyan: [0, 139, 139],
darkgoldenrod: [184, 134, 11],
darkgray: [169, 169, 169],
darkgreen: [0, 100, 0],
darkgrey: [169, 169, 169],
darkkhaki: [189, 183, 107],
darkmagenta: [139, 0, 139],
darkolivegreen: [85, 107, 47],
darkorange: [255, 140, 0],
darkorchid: [153, 50, 204],
darkred: [139, 0, 0],
darksalmon: [233, 150, 122],
darkseagreen: [143, 188, 143],
darkslateblue: [72, 61, 139],
darkslategray: [47, 79, 79],
darkslategrey: [47, 79, 79],
darkturquoise: [0, 206, 209],
darkviolet: [148, 0, 211],
deeppink: [255, 20, 147],
deepskyblue: [0, 191, 255],
dimgray: [105, 105, 105],
dimgrey: [105, 105, 105],
dodgerblue: [30, 144, 255],
firebrick: [178, 34, 34],
floralwhite: [255, 250, 240],
forestgreen: [34, 139, 34],
fuchsia: [255, 0, 255],
gainsboro: [220, 220, 220],
ghostwhite: [248, 248, 255],
gold: [255, 215, 0],
goldenrod: [218, 165, 32],
gray: [128, 128, 128],
green: [0, 128, 0],
greenyellow: [173, 255, 47],
grey: [128, 128, 128],
honeydew: [240, 255, 240],
hotpink: [255, 105, 180],
indianred: [205, 92, 92],
indigo: [75, 0, 130],
ivory: [255, 255, 240],
khaki: [240, 230, 140],
lavender: [230, 230, 250],
lavenderblush: [255, 240, 245],
lawngreen: [124, 252, 0],
lemonchiffon: [255, 250, 205],
lightblue: [173, 216, 230],
lightcoral: [240, 128, 128],
lightcyan: [224, 255, 255],
lightgoldenrodyellow: [250, 250, 210],
lightgray: [211, 211, 211],
lightgreen: [144, 238, 144],
lightgrey: [211, 211, 211],
lightpink: [255, 182, 193],
lightsalmon: [255, 160, 122],
lightseagreen: [32, 178, 170],
lightskyblue: [135, 206, 250],
lightslategray: [119, 136, 153],
lightslategrey: [119, 136, 153],
lightsteelblue: [176, 196, 222],
lightyellow: [255, 255, 224],
lime: [0, 255, 0],
limegreen: [50, 205, 50],
linen: [250, 240, 230],
magenta: [255, 0, 255],
maroon: [128, 0, 0],
mediumaquamarine: [102, 205, 170],
mediumblue: [0, 0, 205],
mediumorchid: [186, 85, 211],
mediumpurple: [147, 112, 219],
mediumseagreen: [60, 179, 113],
mediumslateblue: [123, 104, 238],
mediumspringgreen: [0, 250, 154],
mediumturquoise: [72, 209, 204],
mediumvioletred: [199, 21, 133],
midnightblue: [25, 25, 112],
mintcream: [245, 255, 250],
mistyrose: [255, 228, 225],
moccasin: [255, 228, 181],
navajowhite: [255, 222, 173],
navy: [0, 0, 128],
oldlace: [253, 245, 230],
olive: [128, 128, 0],
olivedrab: [107, 142, 35],
orange: [255, 165, 0],
orangered: [255, 69, 0],
orchid: [218, 112, 214],
palegoldenrod: [238, 232, 170],
palegreen: [152, 251, 152],
paleturquoise: [175, 238, 238],
palevioletred: [219, 112, 147],
papayawhip: [255, 239, 213],
peachpuff: [255, 218, 185],
peru: [205, 133, 63],
pink: [255, 192, 203],
plum: [221, 160, 221],
powderblue: [176, 224, 230],
purple: [128, 0, 128],
rebeccapurple: [102, 51, 153],
red: [255, 0, 0],
rosybrown: [188, 143, 143],
royalblue: [65, 105, 225],
saddlebrown: [139, 69, 19],
salmon: [250, 128, 114],
sandybrown: [244, 164, 96],
seagreen: [46, 139, 87],
seashell: [255, 245, 238],
sienna: [160, 82, 45],
silver: [192, 192, 192],
skyblue: [135, 206, 235],
slateblue: [106, 90, 205],
slategray: [112, 128, 144],
slategrey: [112, 128, 144],
snow: [255, 250, 250],
springgreen: [0, 255, 127],
steelblue: [70, 130, 180],
tan: [210, 180, 140],
teal: [0, 128, 128],
thistle: [216, 191, 216],
tomato: [255, 99, 71],
turquoise: [64, 224, 208],
violet: [238, 130, 238],
wheat: [245, 222, 179],
white: [255, 255, 255],
whitesmoke: [245, 245, 245],
yellow: [255, 255, 0],
yellowgreen: [154, 205, 50],
}
export default function (pluginConfig, plugins) {
if (pluginConfig === undefined) {
return plugins
}
const pluginNames = Array.isArray(pluginConfig)
? pluginConfig
: [
...new Set(
plugins
.filter((pluginName) => {
return pluginConfig !== false && pluginConfig[pluginName] !== false
})
.concat(
Object.keys(pluginConfig).filter((pluginName) => {
return pluginConfig[pluginName] !== false
})
)
),
]
return pluginNames
}
function createPlugin(plugin, config) {
return {
handler: plugin,
config,
}
}
createPlugin.withOptions = function (pluginFunction, configFunction = () => ({})) {
const optionsFunction = function (options) {
return {
__options: options,
handler: pluginFunction(options),
config: configFunction(options),
}
}
optionsFunction.__isOptionsFunction = true
// Expose plugin dependencies so that `object-hash` returns a different
// value if anything here changes, to ensure a rebuild is triggered.
optionsFunction.__pluginFunction = pluginFunction
optionsFunction.__configFunction = configFunction
return optionsFunction
}
export default createPlugin
import transformThemeValue from './transformThemeValue'
export default function createUtilityPlugin(
themeKey,
utilityVariations = [[themeKey, [themeKey]]],
{ filterDefault = false, ...options } = {}
) {
let transformValue = transformThemeValue(themeKey)
return function ({ matchUtilities, theme }) {
for (let utilityVariation of utilityVariations) {
let group = Array.isArray(utilityVariation[0]) ? utilityVariation : [utilityVariation]
matchUtilities(
group.reduce((obj, [classPrefix, properties]) => {
return Object.assign(obj, {
[classPrefix]: (value) => {
return properties.reduce((obj, name) => {
if (Array.isArray(name)) {
return Object.assign(obj, { [name[0]]: name[1] })
}
return Object.assign(obj, { [name]: transformValue(value) })
}, {})
},
})
}, {}),
{
...options,
values: filterDefault
? Object.fromEntries(
Object.entries(theme(themeKey) ?? {}).filter(([modifier]) => modifier !== 'DEFAULT')
)
: theme(themeKey),
}
)
}
}
}
import { parseColor } from './color'
import { parseBoxShadowValue } from './parseBoxShadowValue'
import { splitAtTopLevelOnly } from './splitAtTopLevelOnly'
let cssFunctions = ['min', 'max', 'clamp', 'calc']
let IS_CSS_FN = new RegExp(`^(${cssFunctions.join('|')})\\(.*\\)`)
// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
function isCSSFunction(value) {
return IS_CSS_FN.test(value)
}
// These properties accept a `<dashed-ident>` as one of the values. This means that you can use them
// as: `timeline-scope: --tl;`
//
// Without the `var(--tl)`, in these cases we don't want to normalize the value, and you should add
// the `var()` yourself.
//
// More info:
// - https://drafts.csswg.org/scroll-animations/#propdef-timeline-scope
// - https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope#dashed-ident
//
const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([
// Concrete properties
'scroll-timeline-name',
'timeline-scope',
'view-timeline-name',
'font-palette',
// Shorthand properties
'scroll-timeline',
'animation-timeline',
'view-timeline',
])
// This is not a data type, but rather a function that can normalize the
// correct values.
export function normalize(value, context = null, isRoot = true) {
let isVarException = context && AUTO_VAR_INJECTION_EXCEPTIONS.has(context.property)
if (value.startsWith('--') && !isVarException) {
return `var(${value})`
}
// Keep raw strings if it starts with `url(`
if (value.includes('url(')) {
return value
.split(/(url\(.*?\))/g)
.filter(Boolean)
.map((part) => {
if (/^url\(.*?\)$/.test(part)) {
return part
}
return normalize(part, context, false)
})
.join('')
}
// Convert `_` to ` `, except for escaped underscores `\_`
value = value
.replace(
/([^\\])_+/g,
(fullMatch, characterBefore) => characterBefore + ' '.repeat(fullMatch.length - 1)
)
.replace(/^_/g, ' ')
.replace(/\\_/g, '_')
// Remove leftover whitespace
if (isRoot) {
value = value.trim()
}
value = normalizeMathOperatorSpacing(value)
return value
}
/**
* Add spaces around operators inside math functions
* like calc() that do not follow an operator, '(', or `,`.
*
* @param {string} value
* @returns {string}
*/
function normalizeMathOperatorSpacing(value) {
let preventFormattingInFunctions = ['theme']
let preventFormattingKeywords = [
'min-content',
'max-content',
'fit-content',
// Env
'safe-area-inset-top',
'safe-area-inset-right',
'safe-area-inset-bottom',
'safe-area-inset-left',
'titlebar-area-x',
'titlebar-area-y',
'titlebar-area-width',
'titlebar-area-height',
'keyboard-inset-top',
'keyboard-inset-right',
'keyboard-inset-bottom',
'keyboard-inset-left',
'keyboard-inset-width',
'keyboard-inset-height',
]
return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => {
let result = ''
function lastChar() {
let char = result.trimEnd()
return char[char.length - 1]
}
for (let i = 0; i < match.length; i++) {
function peek(word) {
return word.split('').every((char, j) => match[i + j] === char)
}
function consumeUntil(chars) {
let minIndex = Infinity
for (let char of chars) {
let index = match.indexOf(char, i)
if (index !== -1 && index < minIndex) {
minIndex = index
}
}
let result = match.slice(i, minIndex)
i += result.length - 1
return result
}
let char = match[i]
// Handle `var(--variable)`
if (peek('var')) {
// When we consume until `)`, then we are dealing with this scenario:
// `var(--example)`
//
// When we consume until `,`, then we are dealing with this scenario:
// `var(--example, 1rem)`
//
// In this case we do want to "format", the default value as well
result += consumeUntil([')', ','])
}
// Skip formatting of known keywords
else if (preventFormattingKeywords.some((keyword) => peek(keyword))) {
let keyword = preventFormattingKeywords.find((keyword) => peek(keyword))
result += keyword
i += keyword.length - 1
}
// Skip formatting inside known functions
else if (preventFormattingInFunctions.some((fn) => peek(fn))) {
result += consumeUntil([')'])
}
// Handle operators
else if (
['+', '-', '*', '/'].includes(char) &&
!['(', '+', '-', '*', '/', ','].includes(lastChar())
) {
result += ` ${char} `
} else {
result += char
}
}
// Simplify multiple spaces
return result.replace(/\s+/g, ' ')
})
}
export function url(value) {
return value.startsWith('url(')
}
export function number(value) {
return !isNaN(Number(value)) || isCSSFunction(value)
}
export function percentage(value) {
return (value.endsWith('%') && number(value.slice(0, -1))) || isCSSFunction(value)
}
// Please refer to MDN when updating this list:
// https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units
// https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries#container_query_length_units
let lengthUnits = [
'cm',
'mm',
'Q',
'in',
'pc',
'pt',
'px',
'em',
'ex',
'ch',
'rem',
'lh',
'rlh',
'vw',
'vh',
'vmin',
'vmax',
'vb',
'vi',
'svw',
'svh',
'lvw',
'lvh',
'dvw',
'dvh',
'cqw',
'cqh',
'cqi',
'cqb',
'cqmin',
'cqmax',
]
let lengthUnitsPattern = `(?:${lengthUnits.join('|')})`
let lengthRegExp = new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`)
export function length(value) {
return value === '0' || lengthRegExp.test(value) || isCSSFunction(value)
}
let lineWidths = new Set(['thin', 'medium', 'thick'])
export function lineWidth(value) {
return lineWidths.has(value)
}
export function shadow(value) {
let parsedShadows = parseBoxShadowValue(normalize(value))
for (let parsedShadow of parsedShadows) {
if (!parsedShadow.valid) {
return false
}
}
return true
}
export function color(value) {
let colors = 0
let result = splitAtTopLevelOnly(value, '_').every((part) => {
part = normalize(part)
if (part.startsWith('var(')) return true
if (parseColor(part, { loose: true }) !== null) return colors++, true
return false
})
if (!result) return false
return colors > 0
}
export function image(value) {
let images = 0
let result = splitAtTopLevelOnly(value, ',').every((part) => {
part = normalize(part)
if (part.startsWith('var(')) return true
if (
url(part) ||
gradient(part) ||
['element(', 'image(', 'cross-fade(', 'image-set('].some((fn) => part.startsWith(fn))
) {
images++
return true
}
return false
})
if (!result) return false
return images > 0
}
let gradientTypes = new Set([
'conic-gradient',
'linear-gradient',
'radial-gradient',
'repeating-conic-gradient',
'repeating-linear-gradient',
'repeating-radial-gradient',
])
export function gradient(value) {
value = normalize(value)
for (let type of gradientTypes) {
if (value.startsWith(`${type}(`)) {
return true
}
}
return false
}
let validPositions = new Set(['center', 'top', 'right', 'bottom', 'left'])
export function position(value) {
let positions = 0
let result = splitAtTopLevelOnly(value, '_').every((part) => {
part = normalize(part)
if (part.startsWith('var(')) return true
if (validPositions.has(part) || length(part) || percentage(part)) {
positions++
return true
}
return false
})
if (!result) return false
return positions > 0
}
export function familyName(value) {
let fonts = 0
let result = splitAtTopLevelOnly(value, ',').every((part) => {
part = normalize(part)
if (part.startsWith('var(')) return true
// If it contains spaces, then it should be quoted
if (part.includes(' ')) {
if (!/(['"])([^"']+)\1/g.test(part)) {
return false
}
}
// If it starts with a number, it's invalid
if (/^\d/g.test(part)) {
return false
}
fonts++
return true
})
if (!result) return false
return fonts > 0
}
let genericNames = new Set([
'serif',
'sans-serif',
'monospace',
'cursive',
'fantasy',
'system-ui',
'ui-serif',
'ui-sans-serif',
'ui-monospace',
'ui-rounded',
'math',
'emoji',
'fangsong',
])
export function genericName(value) {
return genericNames.has(value)
}
let absoluteSizes = new Set([
'xx-small',
'x-small',
'small',
'medium',
'large',
'x-large',
'x-large',
'xxx-large',
])
export function absoluteSize(value) {
return absoluteSizes.has(value)
}
let relativeSizes = new Set(['larger', 'smaller'])
export function relativeSize(value) {
return relativeSizes.has(value)
}
export function defaults(target, ...sources) {
for (let source of sources) {
for (let k in source) {
if (!target?.hasOwnProperty?.(k)) {
target[k] = source[k]
}
}
for (let k of Object.getOwnPropertySymbols(source)) {
if (!target?.hasOwnProperty?.(k)) {
target[k] = source[k]
}
}
}
return target
}
import parser from 'postcss-selector-parser'
import escapeCommas from './escapeCommas'
export default function escapeClassName(className) {
let node = parser.className()
node.value = className
return escapeCommas(node?.raws?.value ?? node.value)
}
export default function escapeCommas(className) {
return className.replace(/\\,/g, '\\2c ')
}
const flattenColorPalette = (colors) =>
Object.assign(
{},
...Object.entries(colors ?? {}).flatMap(([color, values]) =>
typeof values == 'object'
? Object.entries(flattenColorPalette(values)).map(([number, hex]) => ({
[color + (number === 'DEFAULT' ? '' : `-${number}`)]: hex,
}))
: [{ [`${color}`]: values }]
)
)
export default flattenColorPalette
import selectorParser from 'postcss-selector-parser'
import unescape from 'postcss-selector-parser/dist/util/unesc'
import escapeClassName from '../util/escapeClassName'
import prefixSelector from '../util/prefixSelector'
import { movePseudos } from './pseudoElements'
import { splitAtTopLevelOnly } from './splitAtTopLevelOnly'
/** @typedef {import('postcss-selector-parser').Root} Root */
/** @typedef {import('postcss-selector-parser').Selector} Selector */
/** @typedef {import('postcss-selector-parser').Pseudo} Pseudo */
/** @typedef {import('postcss-selector-parser').Node} Node */
/** @typedef {{format: string, respectPrefix: boolean}[]} RawFormats */
/** @typedef {import('postcss-selector-parser').Root} ParsedFormats */
/** @typedef {RawFormats | ParsedFormats} AcceptedFormats */
let MERGE = ':merge'
/**
* @param {RawFormats} formats
* @param {{context: any, candidate: string, base: string | null}} options
* @returns {ParsedFormats | null}
*/
export function formatVariantSelector(formats, { context, candidate }) {
let prefix = context?.tailwindConfig.prefix ?? ''
// Parse the format selector into an AST
let parsedFormats = formats.map((format) => {
let ast = selectorParser().astSync(format.format)
return {
...format,
ast: format.respectPrefix ? prefixSelector(prefix, ast) : ast,
}
})
// We start with the candidate selector
let formatAst = selectorParser.root({
nodes: [
selectorParser.selector({
nodes: [selectorParser.className({ value: escapeClassName(candidate) })],
}),
],
})
// And iteratively merge each format selector into the candidate selector
for (let { ast } of parsedFormats) {
// 1. Handle :merge() special pseudo-class
;[formatAst, ast] = handleMergePseudo(formatAst, ast)
// 2. Merge the format selector into the current selector AST
ast.walkNesting((nesting) => nesting.replaceWith(...formatAst.nodes[0].nodes))
// 3. Keep going!
formatAst = ast
}
return formatAst
}
/**
* Given any node in a selector this gets the "simple" selector it's a part of
* A simple selector is just a list of nodes without any combinators
* Technically :is(), :not(), :has(), etc… can have combinators but those are nested
* inside the relevant node and won't be picked up so they're fine to ignore
*
* @param {Node} node
* @returns {Node[]}
**/
function simpleSelectorForNode(node) {
/** @type {Node[]} */
let nodes = []
// Walk backwards until we hit a combinator node (or the start)
while (node.prev() && node.prev().type !== 'combinator') {
node = node.prev()
}
// Now record all non-combinator nodes until we hit one (or the end)
while (node && node.type !== 'combinator') {
nodes.push(node)
node = node.next()
}
return nodes
}
/**
* Resorts the nodes in a selector to ensure they're in the correct order
* Tags go before classes, and pseudo classes go after classes
*
* @param {Selector} sel
* @returns {Selector}
**/
function resortSelector(sel) {
sel.sort((a, b) => {
if (a.type === 'tag' && b.type === 'class') {
return -1
} else if (a.type === 'class' && b.type === 'tag') {
return 1
} else if (a.type === 'class' && b.type === 'pseudo' && b.value.startsWith('::')) {
return -1
} else if (a.type === 'pseudo' && a.value.startsWith('::') && b.type === 'class') {
return 1
}
return sel.index(a) - sel.index(b)
})
return sel
}
/**
* Remove extraneous selectors that do not include the base class/candidate
*
* Example:
* Given the utility `.a, .b { color: red}`
* Given the candidate `sm:b`
*
* The final selector should be `.sm\:b` and not `.a, .sm\:b`
*
* @param {Selector} ast
* @param {string} base
*/
export function eliminateIrrelevantSelectors(sel, base) {
let hasClassesMatchingCandidate = false
sel.walk((child) => {
if (child.type === 'class' && child.value === base) {
hasClassesMatchingCandidate = true
return false // Stop walking
}
})
if (!hasClassesMatchingCandidate) {
sel.remove()
}
// We do NOT recursively eliminate sub selectors that don't have the base class
// as this is NOT a safe operation. For example, if we have:
// `.space-x-2 > :not([hidden]) ~ :not([hidden])`
// We cannot remove the [hidden] from the :not() because it would change the
// meaning of the selector.
// TODO: Can we do this for :matches, :is, and :where?
}
/**
* @param {string} current
* @param {AcceptedFormats} formats
* @param {{context: any, candidate: string, base: string | null}} options
* @returns {string}
*/
export function finalizeSelector(current, formats, { context, candidate, base }) {
let separator = context?.tailwindConfig?.separator ?? ':'
// Split by the separator, but ignore the separator inside square brackets:
//
// E.g.: dark:lg:hover:[paint-order:markers]
// ┬ ┬ ┬ ┬
// │ │ │ ╰── We will not split here
// ╰──┴─────┴─────────────── We will split here
//
base = base ?? splitAtTopLevelOnly(candidate, separator).pop()
// Parse the selector into an AST
let selector = selectorParser().astSync(current)
// Normalize escaped classes, e.g.:
//
// The idea would be to replace the escaped `base` in the selector with the
// `format`. However, in css you can escape the same selector in a few
// different ways. This would result in different strings and therefore we
// can't replace it properly.
//
// base: bg-[rgb(255,0,0)]
// base in selector: bg-\\[rgb\\(255\\,0\\,0\\)\\]
// escaped base: bg-\\[rgb\\(255\\2c 0\\2c 0\\)\\]
//
selector.walkClasses((node) => {
if (node.raws && node.value.includes(base)) {
node.raws.value = escapeClassName(unescape(node.raws.value))
}
})
// Remove extraneous selectors that do not include the base candidate
selector.each((sel) => eliminateIrrelevantSelectors(sel, base))
// If after eliminating irrelevant selectors, we end up with nothing
// Then the whole "rule" this is associated with does not need to exist
// We use `null` as a marker value for that case
if (selector.length === 0) {
return null
}
// If there are no formats that means there were no variants added to the candidate
// so we can just return the selector as-is
let formatAst = Array.isArray(formats)
? formatVariantSelector(formats, { context, candidate })
: formats
if (formatAst === null) {
return selector.toString()
}
let simpleStart = selectorParser.comment({ value: '/*__simple__*/' })
let simpleEnd = selectorParser.comment({ value: '/*__simple__*/' })
// We can safely replace the escaped base now, since the `base` section is
// now in a normalized escaped value.
selector.walkClasses((node) => {
if (node.value !== base) {
return
}
let parent = node.parent
let formatNodes = formatAst.nodes[0].nodes
// Perf optimization: if the parent is a single class we can just replace it and be done
if (parent.nodes.length === 1) {
node.replaceWith(...formatNodes)
return
}
let simpleSelector = simpleSelectorForNode(node)
parent.insertBefore(simpleSelector[0], simpleStart)
parent.insertAfter(simpleSelector[simpleSelector.length - 1], simpleEnd)
for (let child of formatNodes) {
parent.insertBefore(simpleSelector[0], child.clone())
}
node.remove()
// Re-sort the simple selector to ensure it's in the correct order
simpleSelector = simpleSelectorForNode(simpleStart)
let firstNode = parent.index(simpleStart)
parent.nodes.splice(
firstNode,
simpleSelector.length,
...resortSelector(selectorParser.selector({ nodes: simpleSelector })).nodes
)
simpleStart.remove()
simpleEnd.remove()
})
// Remove unnecessary pseudo selectors that we used as placeholders
selector.walkPseudos((p) => {
if (p.value === MERGE) {
p.replaceWith(p.nodes)
}
})
// Move pseudo elements to the end of the selector (if necessary)
selector.each((sel) => movePseudos(sel))
return selector.toString()
}
/**
*
* @param {Selector} selector
* @param {Selector} format
*/
export function handleMergePseudo(selector, format) {
/** @type {{pseudo: Pseudo, value: string}[]} */
let merges = []
// Find all :merge() pseudo-classes in `selector`
selector.walkPseudos((pseudo) => {
if (pseudo.value === MERGE) {
merges.push({
pseudo,
value: pseudo.nodes[0].toString(),
})
}
})
// Find all :merge() "attachments" in `format` and attach them to the matching selector in `selector`
format.walkPseudos((pseudo) => {
if (pseudo.value !== MERGE) {
return
}
let value = pseudo.nodes[0].toString()
// Does `selector` contain a :merge() pseudo-class with the same value?
let existing = merges.find((merge) => merge.value === value)
// Nope so there's nothing to do
if (!existing) {
return
}
// Everything after `:merge()` up to the next combinator is what is attached to the merged selector
let attachments = []
let next = pseudo.next()
while (next && next.type !== 'combinator') {
attachments.push(next)
next = next.next()
}
let combinator = next
existing.pseudo.parent.insertAfter(
existing.pseudo,
selectorParser.selector({ nodes: attachments.map((node) => node.clone()) })
)
pseudo.remove()
attachments.forEach((node) => node.remove())
// What about this case:
// :merge(.group):focus > &
// :merge(.group):hover &
if (combinator && combinator.type === 'combinator') {
combinator.remove()
}
})
return [selector, format]
}
import defaultFullConfig from '../../stubs/config.full.js'
import { flagEnabled } from '../featureFlags'
export default function getAllConfigs(config) {
const configs = (config?.presets ?? [defaultFullConfig])
.slice()
.reverse()
.flatMap((preset) => getAllConfigs(preset instanceof Function ? preset() : preset))
const features = {
// Add experimental configs here...
respectDefaultRingColorOpacity: {
theme: {
ringColor: ({ theme }) => ({
DEFAULT: '#3b82f67f',
...theme('colors'),
}),
},
},
disableColorOpacityUtilitiesByDefault: {
corePlugins: {
backgroundOpacity: false,
borderOpacity: false,
divideOpacity: false,
placeholderOpacity: false,
ringOpacity: false,
textOpacity: false,
},
},
}
const experimentals = Object.keys(features)
.filter((feature) => flagEnabled(config, feature))
.map((feature) => features[feature])
return [config, ...experimentals, ...configs]
}
import hash from 'object-hash'
export default function hashConfig(config) {
return hash(config, { ignoreUnknown: true })
}
export default function isKeyframeRule(rule) {
return rule.parent && rule.parent.type === 'atrule' && /keyframes$/.test(rule.parent.name)
}
export default function isPlainObject(value) {
if (Object.prototype.toString.call(value) !== '[object Object]') {
return false
}
const prototype = Object.getPrototypeOf(value)
return prototype === null || Object.getPrototypeOf(prototype) === null
}
let matchingBrackets = new Map([
['{', '}'],
['[', ']'],
['(', ')'],
])
let inverseMatchingBrackets = new Map(
Array.from(matchingBrackets.entries()).map(([k, v]) => [v, k])
)
let quotes = new Set(['"', "'", '`'])
// Arbitrary values must contain balanced brackets (), [] and {}. Escaped
// values don't count, and brackets inside quotes also don't count.
//
// E.g.: w-[this-is]w-[weird-and-invalid]
// E.g.: w-[this-is\\]w-\\[weird-but-valid]
// E.g.: content-['this-is-also-valid]-weirdly-enough']
export default function isSyntacticallyValidPropertyValue(value) {
let stack = []
let inQuotes = false
for (let i = 0; i < value.length; i++) {
let char = value[i]
if (char === ':' && !inQuotes && stack.length === 0) {
return false
}
// Non-escaped quotes allow us to "allow" anything in between
if (quotes.has(char) && value[i - 1] !== '\\') {
inQuotes = !inQuotes
}
if (inQuotes) continue
if (value[i - 1] === '\\') continue // Escaped
if (matchingBrackets.has(char)) {
stack.push(char)
} else if (inverseMatchingBrackets.has(char)) {
let inverse = inverseMatchingBrackets.get(char)
// Nothing to pop from, therefore it is unbalanced
if (stack.length <= 0) {
return false
}
// Popped value must match the inverse value, otherwise it is unbalanced
if (stack.pop() !== inverse) {
return false
}
}
}
// If there is still something on the stack, it is also unbalanced
if (stack.length > 0) {
return false
}
// All good, totally balanced!
return true
}
import colors from 'picocolors'
let alreadyShown = new Set()
function log(type, messages, key) {
if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) return
if (key && alreadyShown.has(key)) return
if (key) alreadyShown.add(key)
console.warn('')
messages.forEach((message) => console.warn(type, '-', message))
}
export function dim(input) {
return colors.dim(input)
}
export default {
group(key, cb) {
if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) return
if (key && alreadyShown.has(key)) return
if (key) alreadyShown.add(key)
console.warn('')
cb({
info(messages) {
messages.forEach((message) => console.warn(colors.bold(colors.cyan('info')), '-', message))
},
warn(messages) {
messages.forEach((message) =>
console.warn(colors.bold(colors.yellow('warn')), '-', message)
)
},
risk(messages) {
messages.forEach((message) =>
console.warn(colors.bold(colors.magenta('risk')), '-', message)
)
},
})
},
info(key, messages) {
log(colors.bold(colors.cyan('info')), ...(Array.isArray(key) ? [key] : [messages, key]))
},
warn(key, messages) {
log(colors.bold(colors.yellow('warn')), ...(Array.isArray(key) ? [key] : [messages, key]))
},
risk(key, messages) {
log(colors.bold(colors.magenta('risk')), ...(Array.isArray(key) ? [key] : [messages, key]))
},
}
import escapeClassName from './escapeClassName'
import escapeCommas from './escapeCommas'
export function asClass(name) {
return escapeCommas(`.${escapeClassName(name)}`)
}
export default function nameClass(classPrefix, key) {
return asClass(formatClass(classPrefix, key))
}
export function formatClass(classPrefix, key) {
if (key === 'DEFAULT') {
return classPrefix
}
if (key === '-' || key === '-DEFAULT') {
return `-${classPrefix}`
}
if (key.startsWith('-')) {
return `-${classPrefix}${key}`
}
if (key.startsWith('/')) {
return `${classPrefix}${key}`
}
return `${classPrefix}-${key}`
}
export default function negateValue(value) {
value = `${value}`
if (value === '0') {
return '0'
}
// Flip sign of numbers
if (/^[+-]?(\d+|\d*\.\d+)(e[+-]?\d+)?(%|\w+)?$/.test(value)) {
return value.replace(/^[+-]?/, (sign) => (sign === '-' ? '' : '-'))
}
// What functions we support negating numeric values for
// var() isn't inherently a numeric function but we support it anyway
// The trigonometric functions are omitted because you'll need to use calc(…) with them _anyway_
// to produce generally useful results and that will be covered already
let numericFunctions = ['var', 'calc', 'min', 'max', 'clamp']
for (const fn of numericFunctions) {
if (value.includes(`${fn}(`)) {
return `calc(${value} * -1)`
}
}
}
import { flagEnabled, featureFlags } from '../featureFlags'
import log, { dim } from './log'
export function normalizeConfig(config) {
// Quick structure validation
/**
* type FilePath = string
* type RawFile = { raw: string, extension?: string }
* type ExtractorFn = (content: string) => Array<string>
* type TransformerFn = (content: string) => string
*
* type Content =
* | Array<FilePath | RawFile>
* | {
* files: Array<FilePath | RawFile>,
* extract?: ExtractorFn | { [extension: string]: ExtractorFn }
* transform?: TransformerFn | { [extension: string]: TransformerFn }
* }
*/
let valid = (() => {
if (config.content === 'auto') {
return true
}
// `config.purge` should not exist anymore
if (config.purge) {
return false
}
// `config.content` should exist
if (!config.content) {
return false
}
// `config.content` should be an object or an array
if (
!Array.isArray(config.content) &&
!(typeof config.content === 'object' && config.content !== null)
) {
return false
}
// When `config.content` is an array, it should consist of FilePaths or RawFiles
if (Array.isArray(config.content)) {
return config.content.every((path) => {
// `path` can be a string
if (typeof path === 'string') return true
// `path` can be an object { raw: string, extension?: string }
// `raw` must be a string
if (typeof path?.raw !== 'string') return false
// `extension` (if provided) should also be a string
if (path?.extension && typeof path?.extension !== 'string') {
return false
}
return true
})
}
// When `config.content` is an object
if (typeof config.content === 'object' && config.content !== null) {
// Only `files`, `relative`, `extract`, and `transform` can exist in `config.content`
if (
Object.keys(config.content).some(
(key) => !['files', 'relative', 'extract', 'transform'].includes(key)
)
) {
return false
}
// `config.content.files` should exist of FilePaths or RawFiles
if (Array.isArray(config.content.files)) {
if (
!config.content.files.every((path) => {
// `path` can be a string
if (typeof path === 'string') return true
// `path` can be an object { raw: string, extension?: string }
// `raw` must be a string
if (typeof path?.raw !== 'string') return false
// `extension` (if provided) should also be a string
if (path?.extension && typeof path?.extension !== 'string') {
return false
}
return true
})
) {
return false
}
// `config.content.extract` is optional, and can be a Function or a Record<String, Function>
if (typeof config.content.extract === 'object') {
for (let value of Object.values(config.content.extract)) {
if (typeof value !== 'function') {
return false
}
}
} else if (
!(config.content.extract === undefined || typeof config.content.extract === 'function')
) {
return false
}
// `config.content.transform` is optional, and can be a Function or a Record<String, Function>
if (typeof config.content.transform === 'object') {
for (let value of Object.values(config.content.transform)) {
if (typeof value !== 'function') {
return false
}
}
} else if (
!(
config.content.transform === undefined || typeof config.content.transform === 'function'
)
) {
return false
}
// `config.content.relative` is optional and can be a boolean
if (
typeof config.content.relative !== 'boolean' &&
typeof config.content.relative !== 'undefined'
) {
return false
}
}
return true
}
return false
})()
if (!valid) {
log.warn('purge-deprecation', [
'The `purge`/`content` options have changed in Tailwind CSS v3.0.',
'Update your configuration file to eliminate this warning.',
'https://tailwindcss.com/docs/upgrade-guide#configure-content-sources',
])
}
// Normalize the `safelist`
config.safelist = (() => {
let { content, purge, safelist } = config
if (Array.isArray(safelist)) return safelist
if (Array.isArray(content?.safelist)) return content.safelist
if (Array.isArray(purge?.safelist)) return purge.safelist
if (Array.isArray(purge?.options?.safelist)) return purge.options.safelist
return []
})()
// Normalize the `blocklist`
config.blocklist = (() => {
let { blocklist } = config
if (Array.isArray(blocklist)) {
if (blocklist.every((item) => typeof item === 'string')) {
return blocklist
}
log.warn('blocklist-invalid', [
'The `blocklist` option must be an array of strings.',
'https://tailwindcss.com/docs/content-configuration#discarding-classes',
])
}
return []
})()
// Normalize prefix option
if (typeof config.prefix === 'function') {
log.warn('prefix-function', [
'As of Tailwind CSS v3.0, `prefix` cannot be a function.',
'Update `prefix` in your configuration to be a string to eliminate this warning.',
'https://tailwindcss.com/docs/upgrade-guide#prefix-cannot-be-a-function',
])
config.prefix = ''
} else {
config.prefix = config.prefix ?? ''
}
// Normalize the `content`
config.content = {
relative: (() => {
let { content } = config
if (content?.relative) {
return content.relative
}
return flagEnabled(config, 'relativeContentPathsByDefault')
})(),
files: (() => {
let { content, purge } = config
if (content === undefined && purge === undefined) return []
if (purge) {
if (Array.isArray(purge)) return purge
if (Array.isArray(purge?.content)) return purge.content
return []
}
if (Array.isArray(content)) return content
if (Array.isArray(content?.content)) return content.content
if (Array.isArray(content?.files)) return content.files
if (content === 'auto') return ['auto']
return []
})(),
extract: (() => {
let extract = (() => {
if (config.purge?.extract) return config.purge.extract
if (config.content?.extract) return config.content.extract
if (config.purge?.extract?.DEFAULT) return config.purge.extract.DEFAULT
if (config.content?.extract?.DEFAULT) return config.content.extract.DEFAULT
if (config.purge?.options?.extractors) return config.purge.options.extractors
if (config.content?.options?.extractors) return config.content.options.extractors
return {}
})()
let extractors = {}
let defaultExtractor = (() => {
if (config.purge?.options?.defaultExtractor) {
return config.purge.options.defaultExtractor
}
if (config.content?.options?.defaultExtractor) {
return config.content.options.defaultExtractor
}
return undefined
})()
if (defaultExtractor !== undefined) {
extractors.DEFAULT = defaultExtractor
}
// Functions
if (typeof extract === 'function') {
extractors.DEFAULT = extract
}
// Arrays
else if (Array.isArray(extract)) {
for (let { extensions, extractor } of extract ?? []) {
for (let extension of extensions) {
extractors[extension] = extractor
}
}
}
// Objects
else if (typeof extract === 'object' && extract !== null) {
Object.assign(extractors, extract)
}
return extractors
})(),
transform: (() => {
let transform = (() => {
if (config.purge?.transform) return config.purge.transform
if (config.content?.transform) return config.content.transform
if (config.purge?.transform?.DEFAULT) return config.purge.transform.DEFAULT
if (config.content?.transform?.DEFAULT) return config.content.transform.DEFAULT
return {}
})()
let transformers = {}
if (typeof transform === 'function') {
transformers.DEFAULT = transform
}
if (typeof transform === 'object' && transform !== null) {
Object.assign(transformers, transform)
}
return transformers
})(),
}
// Force disable the `oxideParser` feature flag when using unsupported features.
// TODO: Remove once we have prefix or separator support in the oxide parser.
if (config.prefix !== '' || config.separator !== ':') {
if (config.experimental === 'all') {
config.experimental = {}
for (let key of featureFlags.experimental) {
config.experimental[key] = true
}
} else {
config.experimental = config.experimental ?? {}
}
config.experimental.oxideParser = false
}
// Validate globs to prevent bogus globs.
// E.g.: `./src/*.{html}` is invalid, the `{html}` should just be `html`
if (config.content.files !== 'auto') {
for (let file of config.content.files) {
if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) {
log.warn('invalid-glob-braces', [
`The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`,
`Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`,
// TODO: Add https://tw.wtf/invalid-glob-braces
])
break
}
}
}
return config
}
/**
* @typedef {object} ScreenValue
* @property {number|undefined} min
* @property {number|undefined} max
* @property {string|undefined} raw
*/
/**
* @typedef {object} Screen
* @property {string} name
* @property {boolean} not
* @property {ScreenValue[]} values
*/
/**
* A function that normalizes the various forms that the screens object can be
* provided in.
*
* Input(s):
* - ['100px', '200px'] // Raw strings
* - { sm: '100px', md: '200px' } // Object with string values
* - { sm: { min: '100px' }, md: { max: '100px' } } // Object with object values
* - { sm: [{ min: '100px' }, { max: '200px' }] } // Object with object array (multiple values)
*
* Output(s):
* - [{ name: 'sm', values: [{ min: '100px', max: '200px' }] }] // List of objects, that contains multiple values
*
* @returns {Screen[]}
*/
export function normalizeScreens(screens, root = true) {
if (Array.isArray(screens)) {
return screens.map((screen) => {
if (root && Array.isArray(screen)) {
throw new Error('The tuple syntax is not supported for `screens`.')
}
if (typeof screen === 'string') {
return { name: screen.toString(), not: false, values: [{ min: screen, max: undefined }] }
}
let [name, options] = screen
name = name.toString()
if (typeof options === 'string') {
return { name, not: false, values: [{ min: options, max: undefined }] }
}
if (Array.isArray(options)) {
return { name, not: false, values: options.map((option) => resolveValue(option)) }
}
return { name, not: false, values: [resolveValue(options)] }
})
}
return normalizeScreens(Object.entries(screens ?? {}), false)
}
/**
* @param {Screen} screen
* @returns {{result: false, reason: string} | {result: true, reason: null}}
*/
export function isScreenSortable(screen) {
if (screen.values.length !== 1) {
return { result: false, reason: 'multiple-values' }
} else if (screen.values[0].raw !== undefined) {
return { result: false, reason: 'raw-values' }
} else if (screen.values[0].min !== undefined && screen.values[0].max !== undefined) {
return { result: false, reason: 'min-and-max' }
}
return { result: true, reason: null }
}
/**
* @param {'min' | 'max'} type
* @param {Screen | 'string'} a
* @param {Screen | 'string'} z
* @returns {number}
*/
export function compareScreens(type, a, z) {
let aScreen = toScreen(a, type)
let zScreen = toScreen(z, type)
let aSorting = isScreenSortable(aScreen)
let bSorting = isScreenSortable(zScreen)
// These cases should never happen and indicate a bug in Tailwind CSS itself
if (aSorting.reason === 'multiple-values' || bSorting.reason === 'multiple-values') {
throw new Error(
'Attempted to sort a screen with multiple values. This should never happen. Please open a bug report.'
)
} else if (aSorting.reason === 'raw-values' || bSorting.reason === 'raw-values') {
throw new Error(
'Attempted to sort a screen with raw values. This should never happen. Please open a bug report.'
)
} else if (aSorting.reason === 'min-and-max' || bSorting.reason === 'min-and-max') {
throw new Error(
'Attempted to sort a screen with both min and max values. This should never happen. Please open a bug report.'
)
}
// Let the sorting begin
let { min: aMin, max: aMax } = aScreen.values[0]
let { min: zMin, max: zMax } = zScreen.values[0]
// Negating screens flip their behavior. Basically `not min-width` is `max-width`
if (a.not) [aMin, aMax] = [aMax, aMin]
if (z.not) [zMin, zMax] = [zMax, zMin]
aMin = aMin === undefined ? aMin : parseFloat(aMin)
aMax = aMax === undefined ? aMax : parseFloat(aMax)
zMin = zMin === undefined ? zMin : parseFloat(zMin)
zMax = zMax === undefined ? zMax : parseFloat(zMax)
let [aValue, zValue] = type === 'min' ? [aMin, zMin] : [zMax, aMax]
return aValue - zValue
}
/**
*
* @param {PartialScreen> | string} value
* @param {'min' | 'max'} type
* @returns {Screen}
*/
export function toScreen(value, type) {
if (typeof value === 'object') {
return value
}
return {
name: 'arbitrary-screen',
values: [{ [type]: value }],
}
}
function resolveValue({ 'min-width': _minWidth, min = _minWidth, max, raw } = {}) {
return { min, max, raw }
}
const DIRECTIONS = new Set(['normal', 'reverse', 'alternate', 'alternate-reverse'])
const PLAY_STATES = new Set(['running', 'paused'])
const FILL_MODES = new Set(['none', 'forwards', 'backwards', 'both'])
const ITERATION_COUNTS = new Set(['infinite'])
const TIMINGS = new Set([
'linear',
'ease',
'ease-in',
'ease-out',
'ease-in-out',
'step-start',
'step-end',
])
const TIMING_FNS = ['cubic-bezier', 'steps']
const COMMA = /\,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
const SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.
const TIME = /^(-?[\d.]+m?s)$/
const DIGIT = /^(\d+)$/
export default function parseAnimationValue(input) {
let animations = input.split(COMMA)
return animations.map((animation) => {
let value = animation.trim()
let result = { value }
let parts = value.split(SPACE)
let seen = new Set()
for (let part of parts) {
if (!seen.has('DIRECTIONS') && DIRECTIONS.has(part)) {
result.direction = part
seen.add('DIRECTIONS')
} else if (!seen.has('PLAY_STATES') && PLAY_STATES.has(part)) {
result.playState = part
seen.add('PLAY_STATES')
} else if (!seen.has('FILL_MODES') && FILL_MODES.has(part)) {
result.fillMode = part
seen.add('FILL_MODES')
} else if (
!seen.has('ITERATION_COUNTS') &&
(ITERATION_COUNTS.has(part) || DIGIT.test(part))
) {
result.iterationCount = part
seen.add('ITERATION_COUNTS')
} else if (!seen.has('TIMING_FUNCTION') && TIMINGS.has(part)) {
result.timingFunction = part
seen.add('TIMING_FUNCTION')
} else if (!seen.has('TIMING_FUNCTION') && TIMING_FNS.some((f) => part.startsWith(`${f}(`))) {
result.timingFunction = part
seen.add('TIMING_FUNCTION')
} else if (!seen.has('DURATION') && TIME.test(part)) {
result.duration = part
seen.add('DURATION')
} else if (!seen.has('DELAY') && TIME.test(part)) {
result.delay = part
seen.add('DELAY')
} else if (!seen.has('NAME')) {
result.name = part
seen.add('NAME')
} else {
if (!result.unknown) result.unknown = []
result.unknown.push(part)
}
}
return result
})
}
import { splitAtTopLevelOnly } from './splitAtTopLevelOnly'
let KEYWORDS = new Set(['inset', 'inherit', 'initial', 'revert', 'unset'])
let SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.
let LENGTH = /^-?(\d+|\.\d+)(.*?)$/g
export function parseBoxShadowValue(input) {
let shadows = splitAtTopLevelOnly(input, ',')
return shadows.map((shadow) => {
let value = shadow.trim()
let result = { raw: value }
let parts = value.split(SPACE)
let seen = new Set()
for (let part of parts) {
// Reset index, since the regex is stateful.
LENGTH.lastIndex = 0
// Keyword
if (!seen.has('KEYWORD') && KEYWORDS.has(part)) {
result.keyword = part
seen.add('KEYWORD')
}
// Length value
else if (LENGTH.test(part)) {
if (!seen.has('X')) {
result.x = part
seen.add('X')
} else if (!seen.has('Y')) {
result.y = part
seen.add('Y')
} else if (!seen.has('BLUR')) {
result.blur = part
seen.add('BLUR')
} else if (!seen.has('SPREAD')) {
result.spread = part
seen.add('SPREAD')
}
}
// Color or unknown
else {
if (!result.color) {
result.color = part
} else {
if (!result.unknown) result.unknown = []
result.unknown.push(part)
}
}
}
// Check if valid
result.valid = result.x !== undefined && result.y !== undefined
return result
})
}
export function formatBoxShadowValue(shadows) {
return shadows
.map((shadow) => {
if (!shadow.valid) {
return shadow.raw
}
return [shadow.keyword, shadow.x, shadow.y, shadow.blur, shadow.spread, shadow.color]
.filter(Boolean)
.join(' ')
})
.join(', ')
}
// @ts-check
/**
* @typedef {{type: 'dependency', file: string} | {type: 'dir-dependency', dir: string, glob: string}} Dependency
*/
/**
*
* @param {import('../lib/content.js').ContentPath} contentPath
* @returns {Dependency[]}
*/
export default function parseDependency(contentPath) {
if (contentPath.ignore) {
return []
}
if (!contentPath.glob) {
return [
{
type: 'dependency',
file: contentPath.base,
},
]
}
if (process.env.ROLLUP_WATCH === 'true') {
// rollup-plugin-postcss does not support dir-dependency messages
// but directories can be watched in the same way as files
return [
{
type: 'dependency',
file: contentPath.base,
},
]
}
return [
{
type: 'dir-dependency',
dir: contentPath.base,
glob: contentPath.glob,
},
]
}
import globParent from 'glob-parent'
// Based on `glob-base`
// https://github.com/micromatch/glob-base/blob/master/index.js
export function parseGlob(pattern) {
let glob = pattern
let base = globParent(pattern)
if (base !== '.') {
glob = pattern.substr(base.length)
if (glob.charAt(0) === '/') {
glob = glob.substr(1)
}
}
if (glob.substr(0, 2) === './') {
glob = glob.substr(2)
}
if (glob.charAt(0) === '/') {
glob = glob.substr(1)
}
return { base, glob }
}
import postcss from 'postcss'
import postcssNested from 'postcss-nested'
import postcssJs from 'postcss-js'
export default function parseObjectStyles(styles) {
if (!Array.isArray(styles)) {
return parseObjectStyles([styles])
}
return styles.flatMap((style) => {
return postcss([
postcssNested({
bubble: ['screen'],
}),
]).process(style, {
parser: postcssJs,
}).root.nodes
})
}
import escapeCommas from './escapeCommas'
import { withAlphaValue } from './withAlphaVariable'
import {
normalize,
length,
number,
percentage,
url,
color as validateColor,
genericName,
familyName,
image,
absoluteSize,
relativeSize,
position,
lineWidth,
shadow,
} from './dataTypes'
import negateValue from './negateValue'
import { backgroundSize } from './validateFormalSyntax'
/**
* @param {import('postcss-selector-parser').Container} selectors
* @param {(className: string) => string} updateClass
* @returns {string}
*/
export function updateAllClasses(selectors, updateClass) {
selectors.walkClasses((sel) => {
sel.value = updateClass(sel.value)
if (sel.raws && sel.raws.value) {
sel.raws.value = escapeCommas(sel.raws.value)
}
})
}
function resolveArbitraryValue(modifier, validate) {
if (!isArbitraryValue(modifier)) {
return undefined
}
let value = modifier.slice(1, -1)
if (!validate(value)) {
return undefined
}
return normalize(value)
}
function asNegativeValue(modifier, lookup = {}, validate) {
let positiveValue = lookup[modifier]
if (positiveValue !== undefined) {
return negateValue(positiveValue)
}
if (isArbitraryValue(modifier)) {
let resolved = resolveArbitraryValue(modifier, validate)
if (resolved === undefined) {
return undefined
}
return negateValue(resolved)
}
}
export function asValue(modifier, options = {}, { validate = () => true } = {}) {
let value = options.values?.[modifier]
if (value !== undefined) {
return value
}
if (options.supportsNegativeValues && modifier.startsWith('-')) {
return asNegativeValue(modifier.slice(1), options.values, validate)
}
return resolveArbitraryValue(modifier, validate)
}
function isArbitraryValue(input) {
return input.startsWith('[') && input.endsWith(']')
}
function splitUtilityModifier(modifier) {
let slashIdx = modifier.lastIndexOf('/')
// If the `/` is inside an arbitrary, we want to find the previous one if any
// This logic probably isn't perfect but it should work for most cases
let arbitraryStartIdx = modifier.lastIndexOf('[', slashIdx)
let arbitraryEndIdx = modifier.indexOf(']', slashIdx)
let isNextToArbitrary = modifier[slashIdx - 1] === ']' || modifier[slashIdx + 1] === '['
// Backtrack to the previous `/` if the one we found was inside an arbitrary
if (!isNextToArbitrary) {
if (arbitraryStartIdx !== -1 && arbitraryEndIdx !== -1) {
if (arbitraryStartIdx < slashIdx && slashIdx < arbitraryEndIdx) {
slashIdx = modifier.lastIndexOf('/', arbitraryStartIdx)
}
}
}
if (slashIdx === -1 || slashIdx === modifier.length - 1) {
return [modifier, undefined]
}
let arbitrary = isArbitraryValue(modifier)
// The modifier could be of the form `[foo]/[bar]`
// We want to handle this case properly
// without affecting `[foo/bar]`
if (arbitrary && !modifier.includes(']/[')) {
return [modifier, undefined]
}
return [modifier.slice(0, slashIdx), modifier.slice(slashIdx + 1)]
}
export function parseColorFormat(value) {
if (typeof value === 'string' && value.includes('<alpha-value>')) {
let oldValue = value
return ({ opacityValue = 1 }) => oldValue.replace('<alpha-value>', opacityValue)
}
return value
}
function unwrapArbitraryModifier(modifier) {
return normalize(modifier.slice(1, -1))
}
export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
if (options.values?.[modifier] !== undefined) {
return parseColorFormat(options.values?.[modifier])
}
// TODO: Hoist this up to getMatchingTypes or something
// We do this here because we need the alpha value (if any)
let [color, alpha] = splitUtilityModifier(modifier)
if (alpha !== undefined) {
let normalizedColor =
options.values?.[color] ?? (isArbitraryValue(color) ? color.slice(1, -1) : undefined)
if (normalizedColor === undefined) {
return undefined
}
normalizedColor = parseColorFormat(normalizedColor)
if (isArbitraryValue(alpha)) {
return withAlphaValue(normalizedColor, unwrapArbitraryModifier(alpha))
}
if (tailwindConfig.theme?.opacity?.[alpha] === undefined) {
return undefined
}
return withAlphaValue(normalizedColor, tailwindConfig.theme.opacity[alpha])
}
return asValue(modifier, options, { validate: validateColor })
}
export function asLookupValue(modifier, options = {}) {
return options.values?.[modifier]
}
function guess(validate) {
return (modifier, options) => {
return asValue(modifier, options, { validate })
}
}
export let typeMap = {
any: asValue,
color: asColor,
url: guess(url),
image: guess(image),
length: guess(length),
percentage: guess(percentage),
position: guess(position),
lookup: asLookupValue,
'generic-name': guess(genericName),
'family-name': guess(familyName),
number: guess(number),
'line-width': guess(lineWidth),
'absolute-size': guess(absoluteSize),
'relative-size': guess(relativeSize),
shadow: guess(shadow),
size: guess(backgroundSize),
}
let supportedTypes = Object.keys(typeMap)
function splitAtFirst(input, delim) {
let idx = input.indexOf(delim)
if (idx === -1) return [undefined, input]
return [input.slice(0, idx), input.slice(idx + 1)]
}
export function coerceValue(types, modifier, options, tailwindConfig) {
if (options.values && modifier in options.values) {
for (let { type } of types ?? []) {
let result = typeMap[type](modifier, options, {
tailwindConfig,
})
if (result === undefined) {
continue
}
return [result, type, null]
}
}
if (isArbitraryValue(modifier)) {
let arbitraryValue = modifier.slice(1, -1)
let [explicitType, value] = splitAtFirst(arbitraryValue, ':')
// It could be that this resolves to `url(https` which is not a valid
// identifier. We currently only support "simple" words with dashes or
// underscores. E.g.: family-name
if (!/^[\w-_]+$/g.test(explicitType)) {
value = arbitraryValue
}
//
else if (explicitType !== undefined && !supportedTypes.includes(explicitType)) {
return []
}
if (value.length > 0 && supportedTypes.includes(explicitType)) {
return [asValue(`[${value}]`, options), explicitType, null]
}
}
let matches = getMatchingTypes(types, modifier, options, tailwindConfig)
// Find first matching type
for (let match of matches) {
return match
}
return []
}
/**
*
* @param {{type: string}[]} types
* @param {string} rawModifier
* @param {any} options
* @param {any} tailwindConfig
* @returns {Iterator<[value: string, type: string, modifier: string | null]>}
*/
export function* getMatchingTypes(types, rawModifier, options, tailwindConfig) {
let [modifier, utilityModifier] = splitUtilityModifier(rawModifier)
let canUseUtilityModifier =
options.modifiers != null &&
(options.modifiers === 'any' ||
(typeof options.modifiers === 'object' &&
((utilityModifier && isArbitraryValue(utilityModifier)) ||
utilityModifier in options.modifiers)))
if (!canUseUtilityModifier) {
modifier = rawModifier
utilityModifier = undefined
}
if (utilityModifier !== undefined && modifier === '') {
modifier = 'DEFAULT'
}
// Check the full value first
// TODO: Move to asValue… somehow
if (utilityModifier !== undefined) {
if (typeof options.modifiers === 'object') {
let configValue = options.modifiers?.[utilityModifier] ?? null
if (configValue !== null) {
utilityModifier = configValue
} else if (isArbitraryValue(utilityModifier)) {
utilityModifier = unwrapArbitraryModifier(utilityModifier)
}
}
}
for (let { type } of types ?? []) {
let result = typeMap[type](modifier, options, {
tailwindConfig,
})
if (result === undefined) {
continue
}
yield [result, type, utilityModifier ?? null]
}
}
import parser from 'postcss-selector-parser'
/**
* @template {string | import('postcss-selector-parser').Root} T
*
* Prefix all classes in the selector with the given prefix
*
* It can take either a string or a selector AST and will return the same type
*
* @param {string} prefix
* @param {T} selector
* @param {boolean} prependNegative
* @returns {T}
*/
export default function (prefix, selector, prependNegative = false) {
if (prefix === '') {
return selector
}
/** @type {import('postcss-selector-parser').Root} */
let ast = typeof selector === 'string' ? parser().astSync(selector) : selector
ast.walkClasses((classSelector) => {
let baseClass = classSelector.value
let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith('-')
classSelector.value = shouldPlaceNegativeBeforePrefix
? `-${prefix}${baseClass.slice(1)}`
: `${prefix}${baseClass}`
})
return typeof selector === 'string' ? ast.toString() : ast
}
/** @typedef {import('postcss-selector-parser').Root} Root */
/** @typedef {import('postcss-selector-parser').Selector} Selector */
/** @typedef {import('postcss-selector-parser').Pseudo} Pseudo */
/** @typedef {import('postcss-selector-parser').Node} Node */
// There are some pseudo-elements that may or may not be:
// **Actionable**
// Zero or more user-action pseudo-classes may be attached to the pseudo-element itself
// structural-pseudo-classes are NOT allowed but we don't make
// The spec is not clear on whether this is allowed or not — but in practice it is.
// **Terminal**
// It MUST be placed at the end of a selector
//
// This is the required in the spec. However, some pseudo elements are not "terminal" because
// they represent a "boundary piercing" that is compiled out by a build step.
// **Jumpable**
// Any terminal element may "jump" over combinators when moving to the end of the selector
//
// This is a backwards-compat quirk of pseudo element variants from earlier versions of Tailwind CSS.
/** @typedef {'terminal' | 'actionable' | 'jumpable'} PseudoProperty */
/** @type {Record<string, PseudoProperty[]>} */
let elementProperties = {
// Pseudo elements from the spec
'::after': ['terminal', 'jumpable'],
'::backdrop': ['terminal', 'jumpable'],
'::before': ['terminal', 'jumpable'],
'::cue': ['terminal'],
'::cue-region': ['terminal'],
'::first-letter': ['terminal', 'jumpable'],
'::first-line': ['terminal', 'jumpable'],
'::grammar-error': ['terminal'],
'::marker': ['terminal', 'jumpable'],
'::part': ['terminal', 'actionable'],
'::placeholder': ['terminal', 'jumpable'],
'::selection': ['terminal', 'jumpable'],
'::slotted': ['terminal'],
'::spelling-error': ['terminal'],
'::target-text': ['terminal'],
// Pseudo elements from the spec with special rules
'::file-selector-button': ['terminal', 'actionable'],
// Library-specific pseudo elements used by component libraries
// These are Shadow DOM-like
'::deep': ['actionable'],
'::v-deep': ['actionable'],
'::ng-deep': ['actionable'],
// Note: As a rule, double colons (::) should be used instead of a single colon
// (:). This distinguishes pseudo-classes from pseudo-elements. However, since
// this distinction was not present in older versions of the W3C spec, most
// browsers support both syntaxes for the original pseudo-elements.
':after': ['terminal', 'jumpable'],
':before': ['terminal', 'jumpable'],
':first-letter': ['terminal', 'jumpable'],
':first-line': ['terminal', 'jumpable'],
// The default value is used when the pseudo-element is not recognized
// Because it's not recognized, we don't know if it's terminal or not
// So we assume it can be moved AND can have user-action pseudo classes attached to it
__default__: ['terminal', 'actionable'],
}
/**
* @param {Selector} sel
* @returns {Selector}
*/
export function movePseudos(sel) {
let [pseudos] = movablePseudos(sel)
// Remove all pseudo elements from their respective selectors
pseudos.forEach(([sel, pseudo]) => sel.removeChild(pseudo))
// Re-add them to the end of the selector in the correct order.
// This moves terminal pseudo elements to the end of the
// selector otherwise the selector will not be valid.
//
// Examples:
// - `before:hover:text-center` would result in `.before\:hover\:text-center:hover::before`
// - `hover:before:text-center` would result in `.hover\:before\:text-center:hover::before`
//
// The selector `::before:hover` does not work but we
// can make it work for you by flipping the order.
sel.nodes.push(...pseudos.map(([, pseudo]) => pseudo))
return sel
}
/** @typedef {[sel: Selector, pseudo: Pseudo, attachedTo: Pseudo | null]} MovablePseudo */
/** @typedef {[pseudos: MovablePseudo[], lastSeenElement: Pseudo | null]} MovablePseudosResult */
/**
* @param {Selector} sel
* @returns {MovablePseudosResult}
*/
function movablePseudos(sel) {
/** @type {MovablePseudo[]} */
let buffer = []
/** @type {Pseudo | null} */
let lastSeenElement = null
for (let node of sel.nodes) {
if (node.type === 'combinator') {
buffer = buffer.filter(([, node]) => propertiesForPseudo(node).includes('jumpable'))
lastSeenElement = null
} else if (node.type === 'pseudo') {
if (isMovablePseudoElement(node)) {
lastSeenElement = node
buffer.push([sel, node, null])
} else if (lastSeenElement && isAttachablePseudoClass(node, lastSeenElement)) {
buffer.push([sel, node, lastSeenElement])
} else {
lastSeenElement = null
}
for (let sub of node.nodes ?? []) {
let [movable, lastSeenElementInSub] = movablePseudos(sub)
lastSeenElement = lastSeenElementInSub || lastSeenElement
buffer.push(...movable)
}
}
}
return [buffer, lastSeenElement]
}
/**
* @param {Node} node
* @returns {boolean}
*/
function isPseudoElement(node) {
return node.value.startsWith('::') || elementProperties[node.value] !== undefined
}
/**
* @param {Node} node
* @returns {boolean}
*/
function isMovablePseudoElement(node) {
return isPseudoElement(node) && propertiesForPseudo(node).includes('terminal')
}
/**
* @param {Node} node
* @param {Pseudo} pseudo
* @returns {boolean}
*/
function isAttachablePseudoClass(node, pseudo) {
if (node.type !== 'pseudo') return false
if (isPseudoElement(node)) return false
return propertiesForPseudo(pseudo).includes('actionable')
}
/**
* @param {Pseudo} pseudo
* @returns {PseudoProperty[]}
*/
function propertiesForPseudo(pseudo) {
return elementProperties[pseudo.value] ?? elementProperties.__default__
}
/**
* This function removes any uses of CSS variables used as an alpha channel
*
* This is required for selectors like `:visited` which do not allow
* changes in opacity or external control using CSS variables.
*
* @param {import('postcss').Container} container
* @param {string[]} toRemove
*/
export function removeAlphaVariables(container, toRemove) {
container.walkDecls((decl) => {
if (toRemove.includes(decl.prop)) {
decl.remove()
return
}
for (let varName of toRemove) {
if (decl.value.includes(`/ var(${varName})`)) {
decl.value = decl.value.replace(`/ var(${varName})`, '')
}
}
})
}
import negateValue from './negateValue'
import corePluginList from '../corePluginList'
import configurePlugins from './configurePlugins'
import colors from '../public/colors'
import { defaults } from './defaults'
import { toPath } from './toPath'
import { normalizeConfig } from './normalizeConfig'
import isPlainObject from './isPlainObject'
import { cloneDeep } from './cloneDeep'
import { parseColorFormat } from './pluginUtils'
import { withAlphaValue } from './withAlphaVariable'
import toColorValue from './toColorValue'
function isFunction(input) {
return typeof input === 'function'
}
function mergeWith(target, ...sources) {
let customizer = sources.pop()
for (let source of sources) {
for (let k in source) {
let merged = customizer(target[k], source[k])
if (merged === undefined) {
if (isPlainObject(target[k]) && isPlainObject(source[k])) {
target[k] = mergeWith({}, target[k], source[k], customizer)
} else {
target[k] = source[k]
}
} else {
target[k] = merged
}
}
}
return target
}
const configUtils = {
colors,
negative(scale) {
// TODO: Log that this function isn't really needed anymore?
return Object.keys(scale)
.filter((key) => scale[key] !== '0')
.reduce((negativeScale, key) => {
let negativeValue = negateValue(scale[key])
if (negativeValue !== undefined) {
negativeScale[`-${key}`] = negativeValue
}
return negativeScale
}, {})
},
breakpoints(screens) {
return Object.keys(screens)
.filter((key) => typeof screens[key] === 'string')
.reduce(
(breakpoints, key) => ({
...breakpoints,
[`screen-${key}`]: screens[key],
}),
{}
)
},
}
function value(valueToResolve, ...args) {
return isFunction(valueToResolve) ? valueToResolve(...args) : valueToResolve
}
function collectExtends(items) {
return items.reduce((merged, { extend }) => {
return mergeWith(merged, extend, (mergedValue, extendValue) => {
if (mergedValue === undefined) {
return [extendValue]
}
if (Array.isArray(mergedValue)) {
return [extendValue, ...mergedValue]
}
return [extendValue, mergedValue]
})
}, {})
}
function mergeThemes(themes) {
return {
...themes.reduce((merged, theme) => defaults(merged, theme), {}),
// In order to resolve n config objects, we combine all of their `extend` properties
// into arrays instead of objects so they aren't overridden.
extend: collectExtends(themes),
}
}
function mergeExtensionCustomizer(merged, value) {
// When we have an array of objects, we do want to merge it
if (Array.isArray(merged) && isPlainObject(merged[0])) {
return merged.concat(value)
}
// When the incoming value is an array, and the existing config is an object, prepend the existing object
if (Array.isArray(value) && isPlainObject(value[0]) && isPlainObject(merged)) {
return [merged, ...value]
}
// Override arrays (for example for font-families, box-shadows, ...)
if (Array.isArray(value)) {
return value
}
// Execute default behaviour
return undefined
}
function mergeExtensions({ extend, ...theme }) {
return mergeWith(theme, extend, (themeValue, extensions) => {
// The `extend` property is an array, so we need to check if it contains any functions
if (!isFunction(themeValue) && !extensions.some(isFunction)) {
return mergeWith({}, themeValue, ...extensions, mergeExtensionCustomizer)
}
return (resolveThemePath, utils) =>
mergeWith(
{},
...[themeValue, ...extensions].map((e) => value(e, resolveThemePath, utils)),
mergeExtensionCustomizer
)
})
}
/**
*
* @param {string} key
* @return {Iterable<string[] & {alpha: string | undefined}>}
*/
function* toPaths(key) {
let path = toPath(key)
if (path.length === 0) {
return
}
yield path
if (Array.isArray(key)) {
return
}
let pattern = /^(.*?)\s*\/\s*([^/]+)$/
let matches = key.match(pattern)
if (matches !== null) {
let [, prefix, alpha] = matches
let newPath = toPath(prefix)
newPath.alpha = alpha
yield newPath
}
}
function resolveFunctionKeys(object) {
// theme('colors.red.500 / 0.5') -> ['colors', 'red', '500 / 0', '5]
const resolvePath = (key, defaultValue) => {
for (const path of toPaths(key)) {
let index = 0
let val = object
while (val !== undefined && val !== null && index < path.length) {
val = val[path[index++]]
let shouldResolveAsFn =
isFunction(val) && (path.alpha === undefined || index <= path.length - 1)
val = shouldResolveAsFn ? val(resolvePath, configUtils) : val
}
if (val !== undefined) {
if (path.alpha !== undefined) {
let normalized = parseColorFormat(val)
return withAlphaValue(normalized, path.alpha, toColorValue(normalized))
}
if (isPlainObject(val)) {
return cloneDeep(val)
}
return val
}
}
return defaultValue
}
Object.assign(resolvePath, {
theme: resolvePath,
...configUtils,
})
return Object.keys(object).reduce((resolved, key) => {
resolved[key] = isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key]
return resolved
}, {})
}
function resolvePlugins(configs) {
let pluginGroups = []
let allConfigs = []
for (let config of configs) {
allConfigs.push(config)
let plugins = []
for (let plugin of config?.plugins ?? []) {
// TODO: If we want to support ESM plugins then a handful of things will have to become async
if (typeof plugin === 'string') {
// If the plugin is specified as a string then it's just the package name
plugin = require(plugin)
plugin = plugin.default ?? plugin
} else if (Array.isArray(plugin)) {
// If the plugin is specified as an array then it's a package name and optional options object
// [name] or [name, options]
let [pkg, options = undefined] = plugin
plugin = require(pkg)
plugin = plugin.default ?? plugin
plugin = plugin(options)
}
if (plugin.__isOptionsFunction) {
plugin = plugin()
}
// We're explicitly skipping registering child plugins
// This will change in v4
let [, childConfigs] = resolvePlugins([plugin?.config ?? {}])
plugins.push(plugin)
allConfigs.push(...childConfigs)
}
pluginGroups.push(plugins)
}
// Reverse the order of the plugin groups
// This matches the old `reduceRight` behavior of the old `resolvePluginLists`
// Why? No idea.
let plugins = pluginGroups.reverse().flat()
return [plugins, allConfigs]
}
function resolveCorePlugins(corePluginConfigs) {
const result = [...corePluginConfigs].reduceRight((resolved, corePluginConfig) => {
if (isFunction(corePluginConfig)) {
return corePluginConfig({ corePlugins: resolved })
}
return configurePlugins(corePluginConfig, resolved)
}, corePluginList)
return result
}
export default function resolveConfig(configs) {
let [plugins, pluginConfigs] = resolvePlugins(configs)
let allConfigs = [
...pluginConfigs,
{
prefix: '',
important: false,
separator: ':',
},
]
return normalizeConfig(
defaults(
{
theme: resolveFunctionKeys(
mergeExtensions(mergeThemes(allConfigs.map((t) => t?.theme ?? {})))
),
corePlugins: resolveCorePlugins(allConfigs.map((c) => c.corePlugins)),
plugins,
},
...allConfigs
)
)
}
import fs from 'fs'
import path from 'path'
const defaultConfigFiles = [
'./tailwind.config.js',
'./tailwind.config.cjs',
'./tailwind.config.mjs',
'./tailwind.config.ts',
]
function isObject(value) {
return typeof value === 'object' && value !== null
}
function isEmpty(obj) {
return Object.keys(obj).length === 0
}
function isString(value) {
return typeof value === 'string' || value instanceof String
}
export default function resolveConfigPath(pathOrConfig) {
// require('tailwindcss')({ theme: ..., variants: ... })
if (isObject(pathOrConfig) && pathOrConfig.config === undefined && !isEmpty(pathOrConfig)) {
return null
}
// require('tailwindcss')({ config: 'custom-config.js' })
if (
isObject(pathOrConfig) &&
pathOrConfig.config !== undefined &&
isString(pathOrConfig.config)
) {
return path.resolve(pathOrConfig.config)
}
// require('tailwindcss')({ config: { theme: ..., variants: ... } })
if (
isObject(pathOrConfig) &&
pathOrConfig.config !== undefined &&
isObject(pathOrConfig.config)
) {
return null
}
// require('tailwindcss')('custom-config.js')
if (isString(pathOrConfig)) {
return path.resolve(pathOrConfig)
}
// require('tailwindcss')
return resolveDefaultConfigPath()
}
export function resolveDefaultConfigPath() {
for (const configFile of defaultConfigFiles) {
try {
const configPath = path.resolve(configFile)
fs.accessSync(configPath)
return configPath
} catch (err) {}
}
return null
}
import postcss from 'postcss'
import cloneNodes from './cloneNodes'
export default function responsive(rules) {
return postcss
.atRule({
name: 'responsive',
})
.append(cloneNodes(Array.isArray(rules) ? rules : [rules]))
}
/**
* This splits a string on a top-level character.
*
* Regex doesn't support recursion (at least not the JS-flavored version).
* So we have to use a tiny state machine to keep track of paren placement.
*
* Expected behavior using commas:
* var(--a, 0 0 1px rgb(0, 0, 0)), 0 0 1px rgb(0, 0, 0)
* ─┬─ ┬ ┬ ┬
* x x x ╰──────── Split because top-level
* ╰──────────────┴──┴───────────── Ignored b/c inside >= 1 levels of parens
*
* @param {string} input
* @param {string} separator
*/
export function splitAtTopLevelOnly(input, separator) {
let stack = []
let parts = []
let lastPos = 0
let isEscaped = false
for (let idx = 0; idx < input.length; idx++) {
let char = input[idx]
if (stack.length === 0 && char === separator[0] && !isEscaped) {
if (separator.length === 1 || input.slice(idx, idx + separator.length) === separator) {
parts.push(input.slice(lastPos, idx))
lastPos = idx + separator.length
}
}
if (isEscaped) {
isEscaped = false
} else if (char === '\\') {
isEscaped = true
}
if (char === '(' || char === '[' || char === '{') {
stack.push(char)
} else if (
(char === ')' && stack[stack.length - 1] === '(') ||
(char === ']' && stack[stack.length - 1] === '[') ||
(char === '}' && stack[stack.length - 1] === '{')
) {
stack.pop()
}
}
parts.push(input.slice(lastPos))
return parts
}
export function tap(value, mutator) {
mutator(value)
return value
}
export default function toColorValue(maybeFunction) {
return typeof maybeFunction === 'function' ? maybeFunction({}) : maybeFunction
}
/**
* Parse a path string into an array of path segments.
*
* Square bracket notation `a[b]` may be used to "escape" dots that would otherwise be interpreted as path separators.
*
* Example:
* a -> ['a']
* a.b.c -> ['a', 'b', 'c']
* a[b].c -> ['a', 'b', 'c']
* a[b.c].e.f -> ['a', 'b.c', 'e', 'f']
* a[b][c][d] -> ['a', 'b', 'c', 'd']
*
* @param {string|string[]} path
**/
export function toPath(path) {
if (Array.isArray(path)) return path
let openBrackets = path.split('[').length - 1
let closedBrackets = path.split(']').length - 1
if (openBrackets !== closedBrackets) {
throw new Error(`Path is invalid. Has unbalanced brackets: ${path}`)
}
return path.split(/\.(?![^\[]*\])|[\[\]]/g).filter(Boolean)
}
import postcss from 'postcss'
import isPlainObject from './isPlainObject'
export default function transformThemeValue(themeSection) {
if (['fontSize', 'outline'].includes(themeSection)) {
return (value) => {
if (typeof value === 'function') value = value({})
if (Array.isArray(value)) value = value[0]
return value
}
}
if (themeSection === 'fontFamily') {
return (value) => {
if (typeof value === 'function') value = value({})
let families = Array.isArray(value) && isPlainObject(value[1]) ? value[0] : value
return Array.isArray(families) ? families.join(', ') : families
}
}
if (
[
'boxShadow',
'transitionProperty',
'transitionDuration',
'transitionDelay',
'transitionTimingFunction',
'backgroundImage',
'backgroundSize',
'backgroundColor',
'cursor',
'animation',
].includes(themeSection)
) {
return (value) => {
if (typeof value === 'function') value = value({})
if (Array.isArray(value)) value = value.join(', ')
return value
}
}
// For backwards compatibility reasons, before we switched to underscores
// instead of commas for arbitrary values.
if (['gridTemplateColumns', 'gridTemplateRows', 'objectPosition'].includes(themeSection)) {
return (value) => {
if (typeof value === 'function') value = value({})
if (typeof value === 'string') value = postcss.list.comma(value).join(' ')
return value
}
}
return (value, opts = {}) => {
if (typeof value === 'function') {
value = value(opts)
}
return value
}
}
import pc from 'picocolors'
import log from './log'
export function validateConfig(config) {
if (config.content.files.length === 0) {
log.warn('content-problems', [
'The `content` option in your Tailwind CSS configuration is missing or empty.',
'Configure your content sources or your generated CSS will be missing styles.',
'https://tailwindcss.com/docs/content-configuration',
])
}
if (config.content.files.includes('auto')) {
log.group('auto-content-experimental', (log) => {
log.info([pc.bold('Automatically detecting Tailwind CSS content sources...')])
log.warn([
'Automatic content detection is experimental, and the behavior may change at any time.',
])
})
}
// Warn if the line-clamp plugin is installed
try {
let plugin = require('@tailwindcss/line-clamp')
if (config.plugins.includes(plugin)) {
log.warn('line-clamp-in-core', [
'As of Tailwind CSS v3.3, the `@tailwindcss/line-clamp` plugin is now included by default.',
'Remove it from the `plugins` array in your configuration to eliminate this warning.',
])
config.plugins = config.plugins.filter((p) => p !== plugin)
}
} catch {}
return config
}
import { length, percentage } from './dataTypes'
import { splitAtTopLevelOnly } from './splitAtTopLevelOnly'
/**
*
* https://developer.mozilla.org/en-US/docs/Web/CSS/background-size#formal_syntax
*
* background-size =
* <bg-size>#
*
* <bg-size> =
* [ <length-percentage [0,∞]> | auto ]{1,2} |
* cover |
* contain
*
* <length-percentage> =
* <length> |
* <percentage>
*
* @param {string} value
*/
export function backgroundSize(value) {
let keywordValues = ['cover', 'contain']
// the <length-percentage> type will probably be a css function
// so we have to use `splitAtTopLevelOnly`
return splitAtTopLevelOnly(value, ',').every((part) => {
let sizes = splitAtTopLevelOnly(part, '_').filter(Boolean)
if (sizes.length === 1 && keywordValues.includes(sizes[0])) return true
if (sizes.length !== 1 && sizes.length !== 2) return false
return sizes.every((size) => length(size) || percentage(size) || size === 'auto')
})
}
import { parseColor, formatColor } from './color'
export function withAlphaValue(color, alphaValue, defaultValue) {
if (typeof color === 'function') {
return color({ opacityValue: alphaValue })
}
let parsed = parseColor(color, { loose: true })
if (parsed === null) {
return defaultValue
}
return formatColor({ ...parsed, alpha: alphaValue })
}
export default function withAlphaVariable({ color, property, variable }) {
let properties = [].concat(property)
if (typeof color === 'function') {
return {
[variable]: '1',
...Object.fromEntries(
properties.map((p) => {
return [p, color({ opacityVariable: variable, opacityValue: `var(${variable})` })]
})
),
}
}
const parsed = parseColor(color)
if (parsed === null) {
return Object.fromEntries(properties.map((p) => [p, color]))
}
if (parsed.alpha !== undefined) {
// Has an alpha value, return color as-is
return Object.fromEntries(properties.map((p) => [p, color]))
}
return {
[variable]: '1',
...Object.fromEntries(
properties.map((p) => {
return [p, formatColor({ ...parsed, alpha: `var(${variable})` })]
})
),
}
}
declare namespace postcssValueParser {
interface BaseNode {
/**
* The offset, inclusive, inside the CSS value at which the node starts.
*/
sourceIndex: number
/**
* The offset, exclusive, inside the CSS value at which the node ends.
*/
sourceEndIndex: number
/**
* The node's characteristic value
*/
value: string
}
interface ClosableNode {
/**
* Whether the parsed CSS value ended before the node was properly closed
*/
unclosed?: true
}
interface AdjacentAwareNode {
/**
* The token at the start of the node
*/
before: string
/**
* The token at the end of the node
*/
after: string
}
interface CommentNode extends BaseNode, ClosableNode {
type: 'comment'
}
interface DivNode extends BaseNode, AdjacentAwareNode {
type: 'div'
}
interface FunctionNode extends BaseNode, ClosableNode, AdjacentAwareNode {
type: 'function'
/**
* Nodes inside the function
*/
nodes: Node[]
}
interface SpaceNode extends BaseNode {
type: 'space'
}
interface StringNode extends BaseNode, ClosableNode {
type: 'string'
/**
* The quote type delimiting the string
*/
quote: '"' | "'"
}
interface UnicodeRangeNode extends BaseNode {
type: 'unicode-range'
}
interface WordNode extends BaseNode {
type: 'word'
}
/**
* Any node parsed from a CSS value
*/
type Node =
| CommentNode
| DivNode
| FunctionNode
| SpaceNode
| StringNode
| UnicodeRangeNode
| WordNode
interface CustomStringifierCallback {
/**
* @param node The node to stringify
* @returns The serialized CSS representation of the node
*/
(nodes: Node): string | undefined
}
interface WalkCallback {
/**
* @param node The currently visited node
* @param index The index of the node in the series of parsed nodes
* @param nodes The series of parsed nodes
* @returns Returning `false` will prevent traversal of descendant nodes (only applies if `bubble` was set to `true` in the `walk()` call)
*/
(node: Node, index: number, nodes: Node[]): void | boolean
}
/**
* A CSS dimension, decomposed into its numeric and unit parts
*/
interface Dimension {
number: string
unit: string
}
/**
* A wrapper around a parsed CSS value that allows for inspecting and walking nodes
*/
interface ParsedValue {
/**
* The series of parsed nodes
*/
nodes: Node[]
/**
* Walk all parsed nodes, applying a callback
*
* @param callback A visitor callback that will be executed for each node
* @param bubble When set to `true`, walking will be done inside-out instead of outside-in
*/
walk(callback: WalkCallback, bubble?: boolean): this
}
interface ValueParser {
/**
* Decompose a CSS dimension into its numeric and unit part
*
* @param value The dimension to decompose
* @returns An object representing `number` and `unit` part of the dimension or `false` if the decomposing fails
*/
unit(value: string): Dimension | false
/**
* Serialize a series of nodes into a CSS value
*
* @param nodes The nodes to stringify
* @param custom A custom stringifier callback
* @returns The generated CSS value
*/
stringify(nodes: Node | Node[], custom?: CustomStringifierCallback): string
/**
* Walk a series of nodes, applying a callback
*
* @param nodes The nodes to walk
* @param callback A visitor callback that will be executed for each node
* @param bubble When set to `true`, walking will be done inside-out instead of outside-in
*/
walk(nodes: Node[], callback: WalkCallback, bubble?: boolean): void
/**
* Parse a CSS value into a series of nodes to operate on
*
* @param value The value to parse
*/
new (value: string): ParsedValue
/**
* Parse a CSS value into a series of nodes to operate on
*
* @param value The value to parse
*/
(value: string): ParsedValue
}
}
declare const postcssValueParser: postcssValueParser.ValueParser
export = postcssValueParser
var parse = require('./parse')
var walk = require('./walk')
var stringify = require('./stringify')
function ValueParser(value) {
if (this instanceof ValueParser) {
this.nodes = parse(value)
return this
}
return new ValueParser(value)
}
ValueParser.prototype.toString = function () {
return Array.isArray(this.nodes) ? stringify(this.nodes) : ''
}
ValueParser.prototype.walk = function (cb, bubble) {
walk(this.nodes, cb, bubble)
return this
}
ValueParser.unit = require('./unit')
ValueParser.walk = walk
ValueParser.stringify = stringify
module.exports = ValueParser
Copyright (c) Bogdan Chadkin <trysound@yandex.ru>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
var openParentheses = '('.charCodeAt(0)
var closeParentheses = ')'.charCodeAt(0)
var singleQuote = "'".charCodeAt(0)
var doubleQuote = '"'.charCodeAt(0)
var backslash = '\\'.charCodeAt(0)
var slash = '/'.charCodeAt(0)
var comma = ','.charCodeAt(0)
var colon = ':'.charCodeAt(0)
var star = '*'.charCodeAt(0)
var uLower = 'u'.charCodeAt(0)
var uUpper = 'U'.charCodeAt(0)
var plus = '+'.charCodeAt(0)
var isUnicodeRange = /^[a-f0-9?-]+$/i
module.exports = function (input) {
var tokens = []
var value = input
var next, quote, prev, token, escape, escapePos, whitespacePos, parenthesesOpenPos
var pos = 0
var code = value.charCodeAt(pos)
var max = value.length
var stack = [{ nodes: tokens }]
var balanced = 0
var parent
var name = ''
var before = ''
var after = ''
while (pos < max) {
// Whitespaces
if (code <= 32) {
next = pos
do {
next += 1
code = value.charCodeAt(next)
} while (code <= 32)
token = value.slice(pos, next)
prev = tokens[tokens.length - 1]
if (code === closeParentheses && balanced) {
after = token
} else if (prev && prev.type === 'div') {
prev.after = token
prev.sourceEndIndex += token.length
} else if (
code === comma ||
code === colon ||
(code === slash &&
value.charCodeAt(next + 1) !== star &&
(!parent || (parent && parent.type === 'function' && false)))
) {
before = token
} else {
tokens.push({
type: 'space',
sourceIndex: pos,
sourceEndIndex: next,
value: token,
})
}
pos = next
// Quotes
} else if (code === singleQuote || code === doubleQuote) {
next = pos
quote = code === singleQuote ? "'" : '"'
token = {
type: 'string',
sourceIndex: pos,
quote: quote,
}
do {
escape = false
next = value.indexOf(quote, next + 1)
if (~next) {
escapePos = next
while (value.charCodeAt(escapePos - 1) === backslash) {
escapePos -= 1
escape = !escape
}
} else {
value += quote
next = value.length - 1
token.unclosed = true
}
} while (escape)
token.value = value.slice(pos + 1, next)
token.sourceEndIndex = token.unclosed ? next : next + 1
tokens.push(token)
pos = next + 1
code = value.charCodeAt(pos)
// Comments
} else if (code === slash && value.charCodeAt(pos + 1) === star) {
next = value.indexOf('*/', pos)
token = {
type: 'comment',
sourceIndex: pos,
sourceEndIndex: next + 2,
}
if (next === -1) {
token.unclosed = true
next = value.length
token.sourceEndIndex = next
}
token.value = value.slice(pos + 2, next)
tokens.push(token)
pos = next + 2
code = value.charCodeAt(pos)
// Operation within calc
} else if ((code === slash || code === star) && parent && parent.type === 'function' && true) {
token = value[pos]
tokens.push({
type: 'word',
sourceIndex: pos - before.length,
sourceEndIndex: pos + token.length,
value: token,
})
pos += 1
code = value.charCodeAt(pos)
// Dividers
} else if (code === slash || code === comma || code === colon) {
token = value[pos]
tokens.push({
type: 'div',
sourceIndex: pos - before.length,
sourceEndIndex: pos + token.length,
value: token,
before: before,
after: '',
})
before = ''
pos += 1
code = value.charCodeAt(pos)
// Open parentheses
} else if (openParentheses === code) {
// Whitespaces after open parentheses
next = pos
do {
next += 1
code = value.charCodeAt(next)
} while (code <= 32)
parenthesesOpenPos = pos
token = {
type: 'function',
sourceIndex: pos - name.length,
value: name,
before: value.slice(parenthesesOpenPos + 1, next),
}
pos = next
if (name === 'url' && code !== singleQuote && code !== doubleQuote) {
next -= 1
do {
escape = false
next = value.indexOf(')', next + 1)
if (~next) {
escapePos = next
while (value.charCodeAt(escapePos - 1) === backslash) {
escapePos -= 1
escape = !escape
}
} else {
value += ')'
next = value.length - 1
token.unclosed = true
}
} while (escape)
// Whitespaces before closed
whitespacePos = next
do {
whitespacePos -= 1
code = value.charCodeAt(whitespacePos)
} while (code <= 32)
if (parenthesesOpenPos < whitespacePos) {
if (pos !== whitespacePos + 1) {
token.nodes = [
{
type: 'word',
sourceIndex: pos,
sourceEndIndex: whitespacePos + 1,
value: value.slice(pos, whitespacePos + 1),
},
]
} else {
token.nodes = []
}
if (token.unclosed && whitespacePos + 1 !== next) {
token.after = ''
token.nodes.push({
type: 'space',
sourceIndex: whitespacePos + 1,
sourceEndIndex: next,
value: value.slice(whitespacePos + 1, next),
})
} else {
token.after = value.slice(whitespacePos + 1, next)
token.sourceEndIndex = next
}
} else {
token.after = ''
token.nodes = []
}
pos = next + 1
token.sourceEndIndex = token.unclosed ? next : pos
code = value.charCodeAt(pos)
tokens.push(token)
} else {
balanced += 1
token.after = ''
token.sourceEndIndex = pos + 1
tokens.push(token)
stack.push(token)
tokens = token.nodes = []
parent = token
}
name = ''
// Close parentheses
} else if (closeParentheses === code && balanced) {
pos += 1
code = value.charCodeAt(pos)
parent.after = after
parent.sourceEndIndex += after.length
after = ''
balanced -= 1
stack[stack.length - 1].sourceEndIndex = pos
stack.pop()
parent = stack[balanced]
tokens = parent.nodes
// Words
} else {
next = pos
do {
if (code === backslash) {
next += 1
}
next += 1
code = value.charCodeAt(next)
} while (
next < max &&
!(
code <= 32 ||
code === singleQuote ||
code === doubleQuote ||
code === comma ||
code === colon ||
code === slash ||
code === openParentheses ||
(code === star && parent && parent.type === 'function' && true) ||
(code === slash && parent.type === 'function' && true) ||
(code === closeParentheses && balanced)
)
)
token = value.slice(pos, next)
if (openParentheses === code) {
name = token
} else if (
(uLower === token.charCodeAt(0) || uUpper === token.charCodeAt(0)) &&
plus === token.charCodeAt(1) &&
isUnicodeRange.test(token.slice(2))
) {
tokens.push({
type: 'unicode-range',
sourceIndex: pos,
sourceEndIndex: next,
value: token,
})
} else {
tokens.push({
type: 'word',
sourceIndex: pos,
sourceEndIndex: next,
value: token,
})
}
pos = next
}
}
for (pos = stack.length - 1; pos; pos -= 1) {
stack[pos].unclosed = true
stack[pos].sourceEndIndex = value.length
}
return stack[0].nodes
}
# postcss-value-parser (forked + inlined)
This is a customized version of of [PostCSS Value Parser](https://github.com/TrySound/postcss-value-parser) to fix some bugs around parsing CSS functions.
function stringifyNode(node, custom) {
var type = node.type
var value = node.value
var buf
var customResult
if (custom && (customResult = custom(node)) !== undefined) {
return customResult
} else if (type === 'word' || type === 'space') {
return value
} else if (type === 'string') {
buf = node.quote || ''
return buf + value + (node.unclosed ? '' : buf)
} else if (type === 'comment') {
return '/*' + value + (node.unclosed ? '' : '*/')
} else if (type === 'div') {
return (node.before || '') + value + (node.after || '')
} else if (Array.isArray(node.nodes)) {
buf = stringify(node.nodes, custom)
if (type !== 'function') {
return buf
}
return value + '(' + (node.before || '') + buf + (node.after || '') + (node.unclosed ? '' : ')')
}
return value
}
function stringify(nodes, custom) {
var result, i
if (Array.isArray(nodes)) {
result = ''
for (i = nodes.length - 1; ~i; i -= 1) {
result = stringifyNode(nodes[i], custom) + result
}
return result
}
return stringifyNode(nodes, custom)
}
module.exports = stringify
var minus = '-'.charCodeAt(0)
var plus = '+'.charCodeAt(0)
var dot = '.'.charCodeAt(0)
var exp = 'e'.charCodeAt(0)
var EXP = 'E'.charCodeAt(0)
// Check if three code points would start a number
// https://www.w3.org/TR/css-syntax-3/#starts-with-a-number
function likeNumber(value) {
var code = value.charCodeAt(0)
var nextCode
if (code === plus || code === minus) {
nextCode = value.charCodeAt(1)
if (nextCode >= 48 && nextCode <= 57) {
return true
}
var nextNextCode = value.charCodeAt(2)
if (nextCode === dot && nextNextCode >= 48 && nextNextCode <= 57) {
return true
}
return false
}
if (code === dot) {
nextCode = value.charCodeAt(1)
if (nextCode >= 48 && nextCode <= 57) {
return true
}
return false
}
if (code >= 48 && code <= 57) {
return true
}
return false
}
// Consume a number
// https://www.w3.org/TR/css-syntax-3/#consume-number
module.exports = function (value) {
var pos = 0
var length = value.length
var code
var nextCode
var nextNextCode
if (length === 0 || !likeNumber(value)) {
return false
}
code = value.charCodeAt(pos)
if (code === plus || code === minus) {
pos++
}
while (pos < length) {
code = value.charCodeAt(pos)
if (code < 48 || code > 57) {
break
}
pos += 1
}
code = value.charCodeAt(pos)
nextCode = value.charCodeAt(pos + 1)
if (code === dot && nextCode >= 48 && nextCode <= 57) {
pos += 2
while (pos < length) {
code = value.charCodeAt(pos)
if (code < 48 || code > 57) {
break
}
pos += 1
}
}
code = value.charCodeAt(pos)
nextCode = value.charCodeAt(pos + 1)
nextNextCode = value.charCodeAt(pos + 2)
if (
(code === exp || code === EXP) &&
((nextCode >= 48 && nextCode <= 57) ||
((nextCode === plus || nextCode === minus) && nextNextCode >= 48 && nextNextCode <= 57))
) {
pos += nextCode === plus || nextCode === minus ? 3 : 2
while (pos < length) {
code = value.charCodeAt(pos)
if (code < 48 || code > 57) {
break
}
pos += 1
}
}
return {
number: value.slice(0, pos),
unit: value.slice(pos),
}
}
module.exports = function walk(nodes, cb, bubble) {
var i, max, node, result
for (i = 0, max = nodes.length; i < max; i += 1) {
node = nodes[i]
if (!bubble) {
result = cb(node, i, nodes)
}
if (result !== false && node.type === 'function' && Array.isArray(node.nodes)) {
walk(node.nodes, cb, bubble)
}
if (bubble) {
cb(node, i, nodes)
}
}
}
{
"printWidth": 120,
"semi": false,
"singleQuote": true,
"trailingComma": "es5"
}
module.exports = {
content: ['auto'],
presets: [],
darkMode: 'media', // or 'class'
theme: {
accentColor: ({ theme }) => ({
...theme('colors'),
auto: 'auto',
}),
animation: {
none: 'none',
spin: 'spin 1s linear infinite',
ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite',
pulse: 'pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite',
bounce: 'bounce 1s infinite',
},
aria: {
busy: 'busy="true"',
checked: 'checked="true"',
disabled: 'disabled="true"',
expanded: 'expanded="true"',
hidden: 'hidden="true"',
pressed: 'pressed="true"',
readonly: 'readonly="true"',
required: 'required="true"',
selected: 'selected="true"',
},
aspectRatio: {
auto: 'auto',
square: '1 / 1',
video: '16 / 9',
},
backdropBlur: ({ theme }) => theme('blur'),
backdropBrightness: ({ theme }) => theme('brightness'),
backdropContrast: ({ theme }) => theme('contrast'),
backdropGrayscale: ({ theme }) => theme('grayscale'),
backdropHueRotate: ({ theme }) => theme('hueRotate'),
backdropInvert: ({ theme }) => theme('invert'),
backdropOpacity: ({ theme }) => theme('opacity'),
backdropSaturate: ({ theme }) => theme('saturate'),
backdropSepia: ({ theme }) => theme('sepia'),
backgroundColor: ({ theme }) => theme('colors'),
backgroundImage: {
none: 'none',
'gradient-to-t': 'linear-gradient(to top, var(--tw-gradient-stops))',
'gradient-to-tr': 'linear-gradient(to top right, var(--tw-gradient-stops))',
'gradient-to-r': 'linear-gradient(to right, var(--tw-gradient-stops))',
'gradient-to-br': 'linear-gradient(to bottom right, var(--tw-gradient-stops))',
'gradient-to-b': 'linear-gradient(to bottom, var(--tw-gradient-stops))',
'gradient-to-bl': 'linear-gradient(to bottom left, var(--tw-gradient-stops))',
'gradient-to-l': 'linear-gradient(to left, var(--tw-gradient-stops))',
'gradient-to-tl': 'linear-gradient(to top left, var(--tw-gradient-stops))',
},
backgroundOpacity: ({ theme }) => theme('opacity'),
backgroundPosition: {
bottom: 'bottom',
center: 'center',
left: 'left',
'left-bottom': 'left bottom',
'left-top': 'left top',
right: 'right',
'right-bottom': 'right bottom',
'right-top': 'right top',
top: 'top',
},
backgroundSize: {
auto: 'auto',
cover: 'cover',
contain: 'contain',
},
blur: {
0: '0',
none: '0',
sm: '4px',
DEFAULT: '8px',
md: '12px',
lg: '16px',
xl: '24px',
'2xl': '40px',
'3xl': '64px',
},
borderColor: ({ theme }) => ({
...theme('colors'),
DEFAULT: theme('colors.gray.200', 'currentColor'),
}),
borderOpacity: ({ theme }) => theme('opacity'),
borderRadius: {
none: '0px',
sm: '0.125rem',
DEFAULT: '0.25rem',
md: '0.375rem',
lg: '0.5rem',
xl: '0.75rem',
'2xl': '1rem',
'3xl': '1.5rem',
full: '9999px',
},
borderSpacing: ({ theme }) => ({
...theme('spacing'),
}),
borderWidth: {
DEFAULT: '1px',
0: '0px',
2: '2px',
4: '4px',
8: '8px',
},
boxShadow: {
sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
DEFAULT: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
md: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
lg: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
xl: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
'2xl': '0 25px 50px -12px rgb(0 0 0 / 0.25)',
inner: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)',
none: 'none',
},
boxShadowColor: ({ theme }) => theme('colors'),
brightness: {
0: '0',
50: '.5',
75: '.75',
90: '.9',
95: '.95',
100: '1',
105: '1.05',
110: '1.1',
125: '1.25',
150: '1.5',
200: '2',
},
caretColor: ({ theme }) => theme('colors'),
colors: ({ colors }) => ({
inherit: colors.inherit,
current: colors.current,
transparent: colors.transparent,
black: colors.black,
white: colors.white,
slate: colors.slate,
gray: colors.gray,
zinc: colors.zinc,
neutral: colors.neutral,
stone: colors.stone,
red: colors.red,
orange: colors.orange,
amber: colors.amber,
yellow: colors.yellow,
lime: colors.lime,
green: colors.green,
emerald: colors.emerald,
teal: colors.teal,
cyan: colors.cyan,
sky: colors.sky,
blue: colors.blue,
indigo: colors.indigo,
violet: colors.violet,
purple: colors.purple,
fuchsia: colors.fuchsia,
pink: colors.pink,
rose: colors.rose,
}),
columns: {
auto: 'auto',
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
7: '7',
8: '8',
9: '9',
10: '10',
11: '11',
12: '12',
'3xs': '16rem',
'2xs': '18rem',
xs: '20rem',
sm: '24rem',
md: '28rem',
lg: '32rem',
xl: '36rem',
'2xl': '42rem',
'3xl': '48rem',
'4xl': '56rem',
'5xl': '64rem',
'6xl': '72rem',
'7xl': '80rem',
},
container: {},
content: {
none: 'none',
},
contrast: {
0: '0',
50: '.5',
75: '.75',
100: '1',
125: '1.25',
150: '1.5',
200: '2',
},
cursor: {
auto: 'auto',
default: 'default',
pointer: 'pointer',
wait: 'wait',
text: 'text',
move: 'move',
help: 'help',
'not-allowed': 'not-allowed',
none: 'none',
'context-menu': 'context-menu',
progress: 'progress',
cell: 'cell',
crosshair: 'crosshair',
'vertical-text': 'vertical-text',
alias: 'alias',
copy: 'copy',
'no-drop': 'no-drop',
grab: 'grab',
grabbing: 'grabbing',
'all-scroll': 'all-scroll',
'col-resize': 'col-resize',
'row-resize': 'row-resize',
'n-resize': 'n-resize',
'e-resize': 'e-resize',
's-resize': 's-resize',
'w-resize': 'w-resize',
'ne-resize': 'ne-resize',
'nw-resize': 'nw-resize',
'se-resize': 'se-resize',
'sw-resize': 'sw-resize',
'ew-resize': 'ew-resize',
'ns-resize': 'ns-resize',
'nesw-resize': 'nesw-resize',
'nwse-resize': 'nwse-resize',
'zoom-in': 'zoom-in',
'zoom-out': 'zoom-out',
},
divideColor: ({ theme }) => theme('borderColor'),
divideOpacity: ({ theme }) => theme('borderOpacity'),
divideWidth: ({ theme }) => theme('borderWidth'),
dropShadow: {
sm: '0 1px 1px rgb(0 0 0 / 0.05)',
DEFAULT: ['0 1px 2px rgb(0 0 0 / 0.1)', '0 1px 1px rgb(0 0 0 / 0.06)'],
md: ['0 4px 3px rgb(0 0 0 / 0.07)', '0 2px 2px rgb(0 0 0 / 0.06)'],
lg: ['0 10px 8px rgb(0 0 0 / 0.04)', '0 4px 3px rgb(0 0 0 / 0.1)'],
xl: ['0 20px 13px rgb(0 0 0 / 0.03)', '0 8px 5px rgb(0 0 0 / 0.08)'],
'2xl': '0 25px 25px rgb(0 0 0 / 0.15)',
none: '0 0 #0000',
},
fill: ({ theme }) => ({
none: 'none',
...theme('colors'),
}),
flex: {
1: '1 1 0%',
auto: '1 1 auto',
initial: '0 1 auto',
none: 'none',
},
flexBasis: ({ theme }) => ({
auto: 'auto',
...theme('spacing'),
'1/2': '50%',
'1/3': '33.333333%',
'2/3': '66.666667%',
'1/4': '25%',
'2/4': '50%',
'3/4': '75%',
'1/5': '20%',
'2/5': '40%',
'3/5': '60%',
'4/5': '80%',
'1/6': '16.666667%',
'2/6': '33.333333%',
'3/6': '50%',
'4/6': '66.666667%',
'5/6': '83.333333%',
'1/12': '8.333333%',
'2/12': '16.666667%',
'3/12': '25%',
'4/12': '33.333333%',
'5/12': '41.666667%',
'6/12': '50%',
'7/12': '58.333333%',
'8/12': '66.666667%',
'9/12': '75%',
'10/12': '83.333333%',
'11/12': '91.666667%',
full: '100%',
}),
flexGrow: {
0: '0',
DEFAULT: '1',
},
flexShrink: {
0: '0',
DEFAULT: '1',
},
fontFamily: {
sans: [
'ui-sans-serif',
'system-ui',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
'"Noto Color Emoji"',
],
serif: ['ui-serif', 'Georgia', 'Cambria', '"Times New Roman"', 'Times', 'serif'],
mono: [
'ui-monospace',
'SFMono-Regular',
'Menlo',
'Monaco',
'Consolas',
'"Liberation Mono"',
'"Courier New"',
'monospace',
],
},
fontSize: {
xs: ['0.75rem', { lineHeight: '1rem' }],
sm: ['0.875rem', { lineHeight: '1.25rem' }],
base: ['1rem', { lineHeight: '1.5rem' }],
lg: ['1.125rem', { lineHeight: '1.75rem' }],
xl: ['1.25rem', { lineHeight: '1.75rem' }],
'2xl': ['1.5rem', { lineHeight: '2rem' }],
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
'5xl': ['3rem', { lineHeight: '1' }],
'6xl': ['3.75rem', { lineHeight: '1' }],
'7xl': ['4.5rem', { lineHeight: '1' }],
'8xl': ['6rem', { lineHeight: '1' }],
'9xl': ['8rem', { lineHeight: '1' }],
},
fontWeight: {
thin: '100',
extralight: '200',
light: '300',
normal: '400',
medium: '500',
semibold: '600',
bold: '700',
extrabold: '800',
black: '900',
},
gap: ({ theme }) => theme('spacing'),
gradientColorStops: ({ theme }) => theme('colors'),
gradientColorStopPositions: {
'0%': '0%',
'5%': '5%',
'10%': '10%',
'15%': '15%',
'20%': '20%',
'25%': '25%',
'30%': '30%',
'35%': '35%',
'40%': '40%',
'45%': '45%',
'50%': '50%',
'55%': '55%',
'60%': '60%',
'65%': '65%',
'70%': '70%',
'75%': '75%',
'80%': '80%',
'85%': '85%',
'90%': '90%',
'95%': '95%',
'100%': '100%',
},
grayscale: {
0: '0',
DEFAULT: '100%',
},
gridAutoColumns: {
auto: 'auto',
min: 'min-content',
max: 'max-content',
fr: 'minmax(0, 1fr)',
},
gridAutoRows: {
auto: 'auto',
min: 'min-content',
max: 'max-content',
fr: 'minmax(0, 1fr)',
},
gridColumn: {
auto: 'auto',
'span-1': 'span 1 / span 1',
'span-2': 'span 2 / span 2',
'span-3': 'span 3 / span 3',
'span-4': 'span 4 / span 4',
'span-5': 'span 5 / span 5',
'span-6': 'span 6 / span 6',
'span-7': 'span 7 / span 7',
'span-8': 'span 8 / span 8',
'span-9': 'span 9 / span 9',
'span-10': 'span 10 / span 10',
'span-11': 'span 11 / span 11',
'span-12': 'span 12 / span 12',
'span-full': '1 / -1',
},
gridColumnEnd: {
auto: 'auto',
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
7: '7',
8: '8',
9: '9',
10: '10',
11: '11',
12: '12',
13: '13',
},
gridColumnStart: {
auto: 'auto',
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
7: '7',
8: '8',
9: '9',
10: '10',
11: '11',
12: '12',
13: '13',
},
gridRow: {
auto: 'auto',
'span-1': 'span 1 / span 1',
'span-2': 'span 2 / span 2',
'span-3': 'span 3 / span 3',
'span-4': 'span 4 / span 4',
'span-5': 'span 5 / span 5',
'span-6': 'span 6 / span 6',
'span-7': 'span 7 / span 7',
'span-8': 'span 8 / span 8',
'span-9': 'span 9 / span 9',
'span-10': 'span 10 / span 10',
'span-11': 'span 11 / span 11',
'span-12': 'span 12 / span 12',
'span-full': '1 / -1',
},
gridRowEnd: {
auto: 'auto',
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
7: '7',
8: '8',
9: '9',
10: '10',
11: '11',
12: '12',
13: '13',
},
gridRowStart: {
auto: 'auto',
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
7: '7',
8: '8',
9: '9',
10: '10',
11: '11',
12: '12',
13: '13',
},
gridTemplateColumns: {
none: 'none',
subgrid: 'subgrid',
1: 'repeat(1, minmax(0, 1fr))',
2: 'repeat(2, minmax(0, 1fr))',
3: 'repeat(3, minmax(0, 1fr))',
4: 'repeat(4, minmax(0, 1fr))',
5: 'repeat(5, minmax(0, 1fr))',
6: 'repeat(6, minmax(0, 1fr))',
7: 'repeat(7, minmax(0, 1fr))',
8: 'repeat(8, minmax(0, 1fr))',
9: 'repeat(9, minmax(0, 1fr))',
10: 'repeat(10, minmax(0, 1fr))',
11: 'repeat(11, minmax(0, 1fr))',
12: 'repeat(12, minmax(0, 1fr))',
},
gridTemplateRows: {
none: 'none',
subgrid: 'subgrid',
1: 'repeat(1, minmax(0, 1fr))',
2: 'repeat(2, minmax(0, 1fr))',
3: 'repeat(3, minmax(0, 1fr))',
4: 'repeat(4, minmax(0, 1fr))',
5: 'repeat(5, minmax(0, 1fr))',
6: 'repeat(6, minmax(0, 1fr))',
7: 'repeat(7, minmax(0, 1fr))',
8: 'repeat(8, minmax(0, 1fr))',
9: 'repeat(9, minmax(0, 1fr))',
10: 'repeat(10, minmax(0, 1fr))',
11: 'repeat(11, minmax(0, 1fr))',
12: 'repeat(12, minmax(0, 1fr))',
},
height: ({ theme }) => ({
auto: 'auto',
...theme('spacing'),
'1/2': '50%',
'1/3': '33.333333%',
'2/3': '66.666667%',
'1/4': '25%',
'2/4': '50%',
'3/4': '75%',
'1/5': '20%',
'2/5': '40%',
'3/5': '60%',
'4/5': '80%',
'1/6': '16.666667%',
'2/6': '33.333333%',
'3/6': '50%',
'4/6': '66.666667%',
'5/6': '83.333333%',
full: '100%',
screen: '100vh',
svh: '100svh',
lvh: '100lvh',
dvh: '100dvh',
min: 'min-content',
max: 'max-content',
fit: 'fit-content',
}),
hueRotate: {
0: '0deg',
15: '15deg',
30: '30deg',
60: '60deg',
90: '90deg',
180: '180deg',
},
inset: ({ theme }) => ({
auto: 'auto',
...theme('spacing'),
'1/2': '50%',
'1/3': '33.333333%',
'2/3': '66.666667%',
'1/4': '25%',
'2/4': '50%',
'3/4': '75%',
full: '100%',
}),
invert: {
0: '0',
DEFAULT: '100%',
},
keyframes: {
spin: {
to: {
transform: 'rotate(360deg)',
},
},
ping: {
'75%, 100%': {
transform: 'scale(2)',
opacity: '0',
},
},
pulse: {
'50%': {
opacity: '.5',
},
},
bounce: {
'0%, 100%': {
transform: 'translateY(-25%)',
animationTimingFunction: 'cubic-bezier(0.8,0,1,1)',
},
'50%': {
transform: 'none',
animationTimingFunction: 'cubic-bezier(0,0,0.2,1)',
},
},
},
letterSpacing: {
tighter: '-0.05em',
tight: '-0.025em',
normal: '0em',
wide: '0.025em',
wider: '0.05em',
widest: '0.1em',
},
lineHeight: {
none: '1',
tight: '1.25',
snug: '1.375',
normal: '1.5',
relaxed: '1.625',
loose: '2',
3: '.75rem',
4: '1rem',
5: '1.25rem',
6: '1.5rem',
7: '1.75rem',
8: '2rem',
9: '2.25rem',
10: '2.5rem',
},
listStyleType: {
none: 'none',
disc: 'disc',
decimal: 'decimal',
},
listStyleImage: {
none: 'none',
},
margin: ({ theme }) => ({
auto: 'auto',
...theme('spacing'),
}),
lineClamp: {
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
},
maxHeight: ({ theme }) => ({
...theme('spacing'),
none: 'none',
full: '100%',
screen: '100vh',
svh: '100svh',
lvh: '100lvh',
dvh: '100dvh',
min: 'min-content',
max: 'max-content',
fit: 'fit-content',
}),
maxWidth: ({ theme, breakpoints }) => ({
...theme('spacing'),
none: 'none',
xs: '20rem',
sm: '24rem',
md: '28rem',
lg: '32rem',
xl: '36rem',
'2xl': '42rem',
'3xl': '48rem',
'4xl': '56rem',
'5xl': '64rem',
'6xl': '72rem',
'7xl': '80rem',
full: '100%',
min: 'min-content',
max: 'max-content',
fit: 'fit-content',
prose: '65ch',
...breakpoints(theme('screens')),
}),
minHeight: ({ theme }) => ({
...theme('spacing'),
full: '100%',
screen: '100vh',
svh: '100svh',
lvh: '100lvh',
dvh: '100dvh',
min: 'min-content',
max: 'max-content',
fit: 'fit-content',
}),
minWidth: ({ theme }) => ({
...theme('spacing'),
full: '100%',
min: 'min-content',
max: 'max-content',
fit: 'fit-content',
}),
objectPosition: {
bottom: 'bottom',
center: 'center',
left: 'left',
'left-bottom': 'left bottom',
'left-top': 'left top',
right: 'right',
'right-bottom': 'right bottom',
'right-top': 'right top',
top: 'top',
},
opacity: {
0: '0',
5: '0.05',
10: '0.1',
15: '0.15',
20: '0.2',
25: '0.25',
30: '0.3',
35: '0.35',
40: '0.4',
45: '0.45',
50: '0.5',
55: '0.55',
60: '0.6',
65: '0.65',
70: '0.7',
75: '0.75',
80: '0.8',
85: '0.85',
90: '0.9',
95: '0.95',
100: '1',
},
order: {
first: '-9999',
last: '9999',
none: '0',
1: '1',
2: '2',
3: '3',
4: '4',
5: '5',
6: '6',
7: '7',
8: '8',
9: '9',
10: '10',
11: '11',
12: '12',
},
outlineColor: ({ theme }) => theme('colors'),
outlineOffset: {
0: '0px',
1: '1px',
2: '2px',
4: '4px',
8: '8px',
},
outlineWidth: {
0: '0px',
1: '1px',
2: '2px',
4: '4px',
8: '8px',
},
padding: ({ theme }) => theme('spacing'),
placeholderColor: ({ theme }) => theme('colors'),
placeholderOpacity: ({ theme }) => theme('opacity'),
ringColor: ({ theme }) => ({
DEFAULT: theme('colors.blue.500', '#3b82f6'),
...theme('colors'),
}),
ringOffsetColor: ({ theme }) => theme('colors'),
ringOffsetWidth: {
0: '0px',
1: '1px',
2: '2px',
4: '4px',
8: '8px',
},
ringOpacity: ({ theme }) => ({
DEFAULT: '0.5',
...theme('opacity'),
}),
ringWidth: {
DEFAULT: '3px',
0: '0px',
1: '1px',
2: '2px',
4: '4px',
8: '8px',
},
rotate: {
0: '0deg',
1: '1deg',
2: '2deg',
3: '3deg',
6: '6deg',
12: '12deg',
45: '45deg',
90: '90deg',
180: '180deg',
},
saturate: {
0: '0',
50: '.5',
100: '1',
150: '1.5',
200: '2',
},
scale: {
0: '0',
50: '.5',
75: '.75',
90: '.9',
95: '.95',
100: '1',
105: '1.05',
110: '1.1',
125: '1.25',
150: '1.5',
},
screens: {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
'2xl': '1536px',
},
scrollMargin: ({ theme }) => ({
...theme('spacing'),
}),
scrollPadding: ({ theme }) => theme('spacing'),
sepia: {
0: '0',
DEFAULT: '100%',
},
skew: {
0: '0deg',
1: '1deg',
2: '2deg',
3: '3deg',
6: '6deg',
12: '12deg',
},
space: ({ theme }) => ({
...theme('spacing'),
}),
spacing: {
px: '1px',
0: '0px',
0.5: '0.125rem',
1: '0.25rem',
1.5: '0.375rem',
2: '0.5rem',
2.5: '0.625rem',
3: '0.75rem',
3.5: '0.875rem',
4: '1rem',
5: '1.25rem',
6: '1.5rem',
7: '1.75rem',
8: '2rem',
9: '2.25rem',
10: '2.5rem',
11: '2.75rem',
12: '3rem',
14: '3.5rem',
16: '4rem',
20: '5rem',
24: '6rem',
28: '7rem',
32: '8rem',
36: '9rem',
40: '10rem',
44: '11rem',
48: '12rem',
52: '13rem',
56: '14rem',
60: '15rem',
64: '16rem',
72: '18rem',
80: '20rem',
96: '24rem',
},
stroke: ({ theme }) => ({
none: 'none',
...theme('colors'),
}),
strokeWidth: {
0: '0',
1: '1',
2: '2',
},
supports: {},
data: {},
textColor: ({ theme }) => theme('colors'),
textDecorationColor: ({ theme }) => theme('colors'),
textDecorationThickness: {
auto: 'auto',
'from-font': 'from-font',
0: '0px',
1: '1px',
2: '2px',
4: '4px',
8: '8px',
},
textIndent: ({ theme }) => ({
...theme('spacing'),
}),
textOpacity: ({ theme }) => theme('opacity'),
textUnderlineOffset: {
auto: 'auto',
0: '0px',
1: '1px',
2: '2px',
4: '4px',
8: '8px',
},
transformOrigin: {
center: 'center',
top: 'top',
'top-right': 'top right',
right: 'right',
'bottom-right': 'bottom right',
bottom: 'bottom',
'bottom-left': 'bottom left',
left: 'left',
'top-left': 'top left',
},
transitionDelay: {
0: '0s',
75: '75ms',
100: '100ms',
150: '150ms',
200: '200ms',
300: '300ms',
500: '500ms',
700: '700ms',
1000: '1000ms',
},
transitionDuration: {
DEFAULT: '150ms',
0: '0s',
75: '75ms',
100: '100ms',
150: '150ms',
200: '200ms',
300: '300ms',
500: '500ms',
700: '700ms',
1000: '1000ms',
},
transitionProperty: {
none: 'none',
all: 'all',
DEFAULT:
'color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter',
colors: 'color, background-color, border-color, text-decoration-color, fill, stroke',
opacity: 'opacity',
shadow: 'box-shadow',
transform: 'transform',
},
transitionTimingFunction: {
DEFAULT: 'cubic-bezier(0.4, 0, 0.2, 1)',
linear: 'linear',
in: 'cubic-bezier(0.4, 0, 1, 1)',
out: 'cubic-bezier(0, 0, 0.2, 1)',
'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
},
translate: ({ theme }) => ({
...theme('spacing'),
'1/2': '50%',
'1/3': '33.333333%',
'2/3': '66.666667%',
'1/4': '25%',
'2/4': '50%',
'3/4': '75%',
full: '100%',
}),
size: ({ theme }) => ({
auto: 'auto',
...theme('spacing'),
'1/2': '50%',
'1/3': '33.333333%',
'2/3': '66.666667%',
'1/4': '25%',
'2/4': '50%',
'3/4': '75%',
'1/5': '20%',
'2/5': '40%',
'3/5': '60%',
'4/5': '80%',
'1/6': '16.666667%',
'2/6': '33.333333%',
'3/6': '50%',
'4/6': '66.666667%',
'5/6': '83.333333%',
'1/12': '8.333333%',
'2/12': '16.666667%',
'3/12': '25%',
'4/12': '33.333333%',
'5/12': '41.666667%',
'6/12': '50%',
'7/12': '58.333333%',
'8/12': '66.666667%',
'9/12': '75%',
'10/12': '83.333333%',
'11/12': '91.666667%',
full: '100%',
min: 'min-content',
max: 'max-content',
fit: 'fit-content',
}),
width: ({ theme }) => ({
auto: 'auto',
...theme('spacing'),
'1/2': '50%',
'1/3': '33.333333%',
'2/3': '66.666667%',
'1/4': '25%',
'2/4': '50%',
'3/4': '75%',
'1/5': '20%',
'2/5': '40%',
'3/5': '60%',
'4/5': '80%',
'1/6': '16.666667%',
'2/6': '33.333333%',
'3/6': '50%',
'4/6': '66.666667%',
'5/6': '83.333333%',
'1/12': '8.333333%',
'2/12': '16.666667%',
'3/12': '25%',
'4/12': '33.333333%',
'5/12': '41.666667%',
'6/12': '50%',
'7/12': '58.333333%',
'8/12': '66.666667%',
'9/12': '75%',
'10/12': '83.333333%',
'11/12': '91.666667%',
full: '100%',
screen: '100vw',
svw: '100svw',
lvw: '100lvw',
dvw: '100dvw',
min: 'min-content',
max: 'max-content',
fit: 'fit-content',
}),
willChange: {
auto: 'auto',
scroll: 'scroll-position',
contents: 'contents',
transform: 'transform',
},
zIndex: {
auto: 'auto',
0: '0',
10: '10',
20: '20',
30: '30',
40: '40',
50: '50',
},
},
plugins: [],
}
module.exports = {
content: ['auto'],
theme: {
extend: {},
},
plugins: [],
}
module.exports = {
plugins: {
tailwindcss: {},
},
}
export default {
plugins: {
tailwindcss: {},
},
}
/** @type {import('tailwindcss').Config} */
module.exports = __CONFIG__
/** @type {import('tailwindcss').Config} */
export default __CONFIG__
import type { Config } from 'tailwindcss'
export default __CONFIG__ satisfies Config
@tailwind base;
@tailwind components;
@tailwind utilities;
import type { CorePluginList } from './generated/corePluginList'
import type { DefaultColors } from './generated/colors'
// Helpers
type Expand<T> = T extends object
? T extends infer O
? { [K in keyof O]: Expand<O[K]> }
: never
: T
type KeyValuePair<K extends keyof any = string, V = string> = Record<K, V>
interface RecursiveKeyValuePair<K extends keyof any = string, V = string> {
[key: string]: V | RecursiveKeyValuePair<K, V>
}
export type ResolvableTo<T> = T | ((utils: PluginUtils) => T)
type CSSRuleObject = RecursiveKeyValuePair<string, null | string | string[]>
interface PluginUtils {
colors: DefaultColors
theme(path: string, defaultValue?: unknown): any
breakpoints<I = Record<string, unknown>, O = I>(arg: I): O
rgb(arg: string): (arg: Partial<{ opacityVariable: string; opacityValue: number }>) => string
hsl(arg: string): (arg: Partial<{ opacityVariable: string; opacityValue: number }>) => string
}
// Content related config
type FilePath = string
type RawFile = { raw: string; extension?: string }
type ExtractorFn = (content: string) => string[]
type TransformerFn = (content: string) => string
type ContentConfig =
| (FilePath | RawFile)[]
| {
files: (FilePath | RawFile)[]
relative?: boolean
extract?: ExtractorFn | { [extension: string]: ExtractorFn }
transform?: TransformerFn | { [extension: string]: TransformerFn }
}
// Important related config
type ImportantConfig = boolean | string
// Prefix related config
type PrefixConfig = string
// Separator related config
type SeparatorConfig = string
// Safelist related config
type SafelistConfig = string | { pattern: RegExp; variants?: string[] }
// Blocklist related config
type BlocklistConfig = string
// Presets related config
type PresetsConfig = Partial<Config>
// Future related config
type FutureConfigValues =
| 'hoverOnlyWhenSupported'
| 'respectDefaultRingColorOpacity'
| 'disableColorOpacityUtilitiesByDefault'
| 'relativeContentPathsByDefault'
| 'logicalSiblingUtilities'
type FutureConfig = Expand<'all' | Partial<Record<FutureConfigValues, boolean>>> | []
// Experimental related config
type ExperimentalConfigValues = 'optimizeUniversalDefaults' | 'oxideParser'
type ExperimentalConfig = Expand<'all' | Partial<Record<ExperimentalConfigValues, boolean>>> | []
// DarkMode related config
type DarkModeConfig =
// Use the `media` query strategy.
| 'media'
// Use the `class` strategy, which requires a `.dark` class on the `html`.
| 'class'
// Use the `class` strategy with a custom class instead of `.dark`.
| ['class', string]
type Screen = { raw: string } | { min: string } | { max: string } | { min: string; max: string }
type ScreensConfig = string[] | KeyValuePair<string, string | Screen | Screen[]>
// Theme related config
export interface ThemeConfig {
// Responsiveness
screens: ResolvableTo<ScreensConfig>
supports: ResolvableTo<Record<string, string>>
data: ResolvableTo<Record<string, string>>
// Reusable base configs
colors: ResolvableTo<RecursiveKeyValuePair>
spacing: ResolvableTo<KeyValuePair>
// Components
container: ResolvableTo<
Partial<{
screens: ScreensConfig
center: boolean
padding: string | Record<string, string>
}>
>
// Utilities
inset: ThemeConfig['spacing']
zIndex: ResolvableTo<KeyValuePair>
order: ResolvableTo<KeyValuePair>
gridColumn: ResolvableTo<KeyValuePair>
gridColumnStart: ResolvableTo<KeyValuePair>
gridColumnEnd: ResolvableTo<KeyValuePair>
gridRow: ResolvableTo<KeyValuePair>
gridRowStart: ResolvableTo<KeyValuePair>
gridRowEnd: ResolvableTo<KeyValuePair>
margin: ThemeConfig['spacing']
aspectRatio: ResolvableTo<KeyValuePair>
height: ThemeConfig['spacing']
maxHeight: ThemeConfig['spacing']
minHeight: ResolvableTo<KeyValuePair>
width: ThemeConfig['spacing']
maxWidth: ResolvableTo<KeyValuePair>
minWidth: ResolvableTo<KeyValuePair>
flex: ResolvableTo<KeyValuePair>
flexShrink: ResolvableTo<KeyValuePair>
flexGrow: ResolvableTo<KeyValuePair>
flexBasis: ThemeConfig['spacing']
borderSpacing: ThemeConfig['spacing']
transformOrigin: ResolvableTo<KeyValuePair>
translate: ThemeConfig['spacing']
rotate: ResolvableTo<KeyValuePair>
skew: ResolvableTo<KeyValuePair>
scale: ResolvableTo<KeyValuePair>
animation: ResolvableTo<KeyValuePair>
keyframes: ResolvableTo<KeyValuePair<string, KeyValuePair<string, KeyValuePair>>>
cursor: ResolvableTo<KeyValuePair>
scrollMargin: ThemeConfig['spacing']
scrollPadding: ThemeConfig['spacing']
listStyleType: ResolvableTo<KeyValuePair>
columns: ResolvableTo<KeyValuePair>
gridAutoColumns: ResolvableTo<KeyValuePair>
gridAutoRows: ResolvableTo<KeyValuePair>
gridTemplateColumns: ResolvableTo<KeyValuePair>
gridTemplateRows: ResolvableTo<KeyValuePair>
gap: ThemeConfig['spacing']
space: ThemeConfig['spacing']
divideWidth: ThemeConfig['borderWidth']
divideColor: ThemeConfig['borderColor']
divideOpacity: ThemeConfig['borderOpacity']
borderRadius: ResolvableTo<KeyValuePair>
borderWidth: ResolvableTo<KeyValuePair>
borderColor: ThemeConfig['colors']
borderOpacity: ThemeConfig['opacity']
backgroundColor: ThemeConfig['colors']
backgroundOpacity: ThemeConfig['opacity']
backgroundImage: ResolvableTo<KeyValuePair>
gradientColorStops: ThemeConfig['colors']
backgroundSize: ResolvableTo<KeyValuePair>
backgroundPosition: ResolvableTo<KeyValuePair>
fill: ThemeConfig['colors']
stroke: ThemeConfig['colors']
strokeWidth: ResolvableTo<KeyValuePair>
objectPosition: ResolvableTo<KeyValuePair>
padding: ThemeConfig['spacing']
textIndent: ThemeConfig['spacing']
fontFamily: ResolvableTo<
KeyValuePair<
string,
| string
| string[]
| [
fontFamily: string | string[],
configuration: Partial<{
fontFeatureSettings: string
fontVariationSettings: string
}>
]
>
>
fontSize: ResolvableTo<
KeyValuePair<
string,
| string
| [fontSize: string, lineHeight: string]
| [
fontSize: string,
configuration: Partial<{
lineHeight: string
letterSpacing: string
fontWeight: string | number
}>
]
>
>
fontWeight: ResolvableTo<KeyValuePair>
lineHeight: ResolvableTo<KeyValuePair>
letterSpacing: ResolvableTo<KeyValuePair>
textColor: ThemeConfig['colors']
textOpacity: ThemeConfig['opacity']
textDecorationColor: ThemeConfig['colors']
textDecorationThickness: ResolvableTo<KeyValuePair>
textUnderlineOffset: ResolvableTo<KeyValuePair>
placeholderColor: ThemeConfig['colors']
placeholderOpacity: ThemeConfig['opacity']
caretColor: ThemeConfig['colors']
accentColor: ThemeConfig['colors']
opacity: ResolvableTo<KeyValuePair>
boxShadow: ResolvableTo<KeyValuePair>
boxShadowColor: ThemeConfig['colors']
outlineWidth: ResolvableTo<KeyValuePair>
outlineOffset: ResolvableTo<KeyValuePair>
outlineColor: ThemeConfig['colors']
ringWidth: ResolvableTo<KeyValuePair>
ringColor: ThemeConfig['colors']
ringOpacity: ThemeConfig['opacity']
ringOffsetWidth: ResolvableTo<KeyValuePair>
ringOffsetColor: ThemeConfig['colors']
blur: ResolvableTo<KeyValuePair>
brightness: ResolvableTo<KeyValuePair>
contrast: ResolvableTo<KeyValuePair>
dropShadow: ResolvableTo<KeyValuePair<string, string | string[]>>
grayscale: ResolvableTo<KeyValuePair>
hueRotate: ResolvableTo<KeyValuePair>
invert: ResolvableTo<KeyValuePair>
saturate: ResolvableTo<KeyValuePair>
sepia: ResolvableTo<KeyValuePair>
backdropBlur: ThemeConfig['blur']
backdropBrightness: ThemeConfig['brightness']
backdropContrast: ThemeConfig['contrast']
backdropGrayscale: ThemeConfig['grayscale']
backdropHueRotate: ThemeConfig['hueRotate']
backdropInvert: ThemeConfig['invert']
backdropOpacity: ThemeConfig['opacity']
backdropSaturate: ThemeConfig['saturate']
backdropSepia: ThemeConfig['sepia']
transitionProperty: ResolvableTo<KeyValuePair>
transitionTimingFunction: ResolvableTo<KeyValuePair>
transitionDelay: ResolvableTo<KeyValuePair>
transitionDuration: ResolvableTo<KeyValuePair>
willChange: ResolvableTo<KeyValuePair>
content: ResolvableTo<KeyValuePair>
}
interface CustomThemeConfig extends ThemeConfig {
[key: string]: any
}
// Core plugins related config
type CorePluginsConfig = CorePluginList[] | Expand<Partial<Record<CorePluginList, boolean>>>
// Plugins related config
type ValueType =
| 'any'
| 'color'
| 'url'
| 'image'
| 'length'
| 'percentage'
| 'position'
| 'lookup'
| 'generic-name'
| 'family-name'
| 'number'
| 'line-width'
| 'absolute-size'
| 'relative-size'
| 'shadow'
export interface PluginAPI {
// for registering new static utility styles
addUtilities(
utilities: CSSRuleObject | CSSRuleObject[],
options?: Partial<{
respectPrefix: boolean
respectImportant: boolean
}>
): void
// for registering new dynamic utility styles
matchUtilities<T = string, U = string>(
utilities: KeyValuePair<
string,
(value: T | string, extra: { modifier: U | string | null }) => CSSRuleObject | null
>,
options?: Partial<{
respectPrefix: boolean
respectImportant: boolean
type: ValueType | ValueType[]
values: KeyValuePair<string, T>
modifiers: 'any' | KeyValuePair<string, U>
supportsNegativeValues: boolean
}>
): void
// for registering new static component styles
addComponents(
components: CSSRuleObject | CSSRuleObject[],
options?: Partial<{
respectPrefix: boolean
respectImportant: boolean
}>
): void
// for registering new dynamic component styles
matchComponents<T = string, U = string>(
components: KeyValuePair<
string,
(value: T | string, extra: { modifier: U | string | null }) => CSSRuleObject | null
>,
options?: Partial<{
respectPrefix: boolean
respectImportant: boolean
type: ValueType | ValueType[]
values: KeyValuePair<string, T>
modifiers: 'any' | KeyValuePair<string, U>
supportsNegativeValues: boolean
}>
): void
// for registering new base styles
addBase(base: CSSRuleObject | CSSRuleObject[]): void
// for registering custom variants
addVariant(name: string, definition: string | string[] | (() => string) | (() => string)[]): void
matchVariant<T = string>(
name: string,
cb: (value: T | string, extra: { modifier: string | null }) => string | string[],
options?: {
values?: KeyValuePair<string, T>
sort?(
a: { value: T | string; modifier: string | null },
b: { value: T | string; modifier: string | null }
): number
}
): void
// for looking up values in the user’s theme configuration
theme: <TDefaultValue = Config['theme']>(
path?: string,
defaultValue?: TDefaultValue
) => TDefaultValue
// for looking up values in the user’s Tailwind configuration
config: <TDefaultValue = Config>(path?: string, defaultValue?: TDefaultValue) => TDefaultValue
// for checking if a core plugin is enabled
corePlugins(path: string): boolean
// for manually escaping strings meant to be used in class names
e: (className: string) => string
}
export type PluginCreator = (api: PluginAPI) => void
export type PluginsConfig = (
| PluginCreator
| { handler: PluginCreator; config?: Partial<Config> }
| {
(options: any): { handler: PluginCreator; config?: Partial<Config> }
__isOptionsFunction: true
}
| string
| [string, Record<string, any>]
)[]
// Top level config related
interface RequiredConfig {
content: ContentConfig
}
interface OptionalConfig {
important: Partial<ImportantConfig>
prefix: Partial<PrefixConfig>
separator: Partial<SeparatorConfig>
safelist: Array<SafelistConfig>
blocklist: Array<BlocklistConfig>
presets: Array<PresetsConfig>
future: Partial<FutureConfig>
experimental: Partial<ExperimentalConfig>
darkMode: Partial<DarkModeConfig>
theme: Partial<CustomThemeConfig & { extend: Partial<CustomThemeConfig> }>
corePlugins: Partial<CorePluginsConfig>
plugins: Partial<PluginsConfig>
// Custom
[key: string]: any
}
export type Config = RequiredConfig & Partial<OptionalConfig>

Sorry, the diff of this file is not supported yet

export interface DefaultColors {
inherit: 'inherit'
current: 'currentColor'
transparent: 'transparent'
black: '#000'
white: '#fff'
slate: {
'50': '#f8fafc'
'100': '#f1f5f9'
'200': '#e2e8f0'
'300': '#cbd5e1'
'400': '#94a3b8'
'500': '#64748b'
'600': '#475569'
'700': '#334155'
'800': '#1e293b'
'900': '#0f172a'
'950': '#020617'
}
gray: {
'50': '#f9fafb'
'100': '#f3f4f6'
'200': '#e5e7eb'
'300': '#d1d5db'
'400': '#9ca3af'
'500': '#6b7280'
'600': '#4b5563'
'700': '#374151'
'800': '#1f2937'
'900': '#111827'
'950': '#030712'
}
zinc: {
'50': '#fafafa'
'100': '#f4f4f5'
'200': '#e4e4e7'
'300': '#d4d4d8'
'400': '#a1a1aa'
'500': '#71717a'
'600': '#52525b'
'700': '#3f3f46'
'800': '#27272a'
'900': '#18181b'
'950': '#09090b'
}
neutral: {
'50': '#fafafa'
'100': '#f5f5f5'
'200': '#e5e5e5'
'300': '#d4d4d4'
'400': '#a3a3a3'
'500': '#737373'
'600': '#525252'
'700': '#404040'
'800': '#262626'
'900': '#171717'
'950': '#0a0a0a'
}
stone: {
'50': '#fafaf9'
'100': '#f5f5f4'
'200': '#e7e5e4'
'300': '#d6d3d1'
'400': '#a8a29e'
'500': '#78716c'
'600': '#57534e'
'700': '#44403c'
'800': '#292524'
'900': '#1c1917'
'950': '#0c0a09'
}
red: {
'50': '#fef2f2'
'100': '#fee2e2'
'200': '#fecaca'
'300': '#fca5a5'
'400': '#f87171'
'500': '#ef4444'
'600': '#dc2626'
'700': '#b91c1c'
'800': '#991b1b'
'900': '#7f1d1d'
'950': '#450a0a'
}
orange: {
'50': '#fff7ed'
'100': '#ffedd5'
'200': '#fed7aa'
'300': '#fdba74'
'400': '#fb923c'
'500': '#f97316'
'600': '#ea580c'
'700': '#c2410c'
'800': '#9a3412'
'900': '#7c2d12'
'950': '#431407'
}
amber: {
'50': '#fffbeb'
'100': '#fef3c7'
'200': '#fde68a'
'300': '#fcd34d'
'400': '#fbbf24'
'500': '#f59e0b'
'600': '#d97706'
'700': '#b45309'
'800': '#92400e'
'900': '#78350f'
'950': '#451a03'
}
yellow: {
'50': '#fefce8'
'100': '#fef9c3'
'200': '#fef08a'
'300': '#fde047'
'400': '#facc15'
'500': '#eab308'
'600': '#ca8a04'
'700': '#a16207'
'800': '#854d0e'
'900': '#713f12'
'950': '#422006'
}
lime: {
'50': '#f7fee7'
'100': '#ecfccb'
'200': '#d9f99d'
'300': '#bef264'
'400': '#a3e635'
'500': '#84cc16'
'600': '#65a30d'
'700': '#4d7c0f'
'800': '#3f6212'
'900': '#365314'
'950': '#1a2e05'
}
green: {
'50': '#f0fdf4'
'100': '#dcfce7'
'200': '#bbf7d0'
'300': '#86efac'
'400': '#4ade80'
'500': '#22c55e'
'600': '#16a34a'
'700': '#15803d'
'800': '#166534'
'900': '#14532d'
'950': '#052e16'
}
emerald: {
'50': '#ecfdf5'
'100': '#d1fae5'
'200': '#a7f3d0'
'300': '#6ee7b7'
'400': '#34d399'
'500': '#10b981'
'600': '#059669'
'700': '#047857'
'800': '#065f46'
'900': '#064e3b'
'950': '#022c22'
}
teal: {
'50': '#f0fdfa'
'100': '#ccfbf1'
'200': '#99f6e4'
'300': '#5eead4'
'400': '#2dd4bf'
'500': '#14b8a6'
'600': '#0d9488'
'700': '#0f766e'
'800': '#115e59'
'900': '#134e4a'
'950': '#042f2e'
}
cyan: {
'50': '#ecfeff'
'100': '#cffafe'
'200': '#a5f3fc'
'300': '#67e8f9'
'400': '#22d3ee'
'500': '#06b6d4'
'600': '#0891b2'
'700': '#0e7490'
'800': '#155e75'
'900': '#164e63'
'950': '#083344'
}
sky: {
'50': '#f0f9ff'
'100': '#e0f2fe'
'200': '#bae6fd'
'300': '#7dd3fc'
'400': '#38bdf8'
'500': '#0ea5e9'
'600': '#0284c7'
'700': '#0369a1'
'800': '#075985'
'900': '#0c4a6e'
'950': '#082f49'
}
blue: {
'50': '#eff6ff'
'100': '#dbeafe'
'200': '#bfdbfe'
'300': '#93c5fd'
'400': '#60a5fa'
'500': '#3b82f6'
'600': '#2563eb'
'700': '#1d4ed8'
'800': '#1e40af'
'900': '#1e3a8a'
'950': '#172554'
}
indigo: {
'50': '#eef2ff'
'100': '#e0e7ff'
'200': '#c7d2fe'
'300': '#a5b4fc'
'400': '#818cf8'
'500': '#6366f1'
'600': '#4f46e5'
'700': '#4338ca'
'800': '#3730a3'
'900': '#312e81'
'950': '#1e1b4b'
}
violet: {
'50': '#f5f3ff'
'100': '#ede9fe'
'200': '#ddd6fe'
'300': '#c4b5fd'
'400': '#a78bfa'
'500': '#8b5cf6'
'600': '#7c3aed'
'700': '#6d28d9'
'800': '#5b21b6'
'900': '#4c1d95'
'950': '#2e1065'
}
purple: {
'50': '#faf5ff'
'100': '#f3e8ff'
'200': '#e9d5ff'
'300': '#d8b4fe'
'400': '#c084fc'
'500': '#a855f7'
'600': '#9333ea'
'700': '#7e22ce'
'800': '#6b21a8'
'900': '#581c87'
'950': '#3b0764'
}
fuchsia: {
'50': '#fdf4ff'
'100': '#fae8ff'
'200': '#f5d0fe'
'300': '#f0abfc'
'400': '#e879f9'
'500': '#d946ef'
'600': '#c026d3'
'700': '#a21caf'
'800': '#86198f'
'900': '#701a75'
'950': '#4a044e'
}
pink: {
'50': '#fdf2f8'
'100': '#fce7f3'
'200': '#fbcfe8'
'300': '#f9a8d4'
'400': '#f472b6'
'500': '#ec4899'
'600': '#db2777'
'700': '#be185d'
'800': '#9d174d'
'900': '#831843'
'950': '#500724'
}
rose: {
'50': '#fff1f2'
'100': '#ffe4e6'
'200': '#fecdd3'
'300': '#fda4af'
'400': '#fb7185'
'500': '#f43f5e'
'600': '#e11d48'
'700': '#be123c'
'800': '#9f1239'
'900': '#881337'
'950': '#4c0519'
}
/** @deprecated As of Tailwind CSS v2.2, `lightBlue` has been renamed to `sky`. Update your configuration file to silence this warning. */ lightBlue: DefaultColors['sky']
/** @deprecated As of Tailwind CSS v3.0, `warmGray` has been renamed to `stone`. Update your configuration file to silence this warning. */ warmGray: DefaultColors['stone']
/** @deprecated As of Tailwind CSS v3.0, `trueGray` has been renamed to `neutral`. Update your configuration file to silence this warning. */ trueGray: DefaultColors['neutral']
/** @deprecated As of Tailwind CSS v3.0, `coolGray` has been renamed to `gray`. Update your configuration file to silence this warning. */ coolGray: DefaultColors['gray']
/** @deprecated As of Tailwind CSS v3.0, `blueGray` has been renamed to `slate`. Update your configuration file to silence this warning. */ blueGray: DefaultColors['slate']
}
export type CorePluginList = 'preflight' | 'container' | 'accessibility' | 'pointerEvents' | 'visibility' | 'position' | 'inset' | 'isolation' | 'zIndex' | 'order' | 'gridColumn' | 'gridColumnStart' | 'gridColumnEnd' | 'gridRow' | 'gridRowStart' | 'gridRowEnd' | 'float' | 'clear' | 'margin' | 'boxSizing' | 'lineClamp' | 'display' | 'aspectRatio' | 'size' | 'height' | 'maxHeight' | 'minHeight' | 'width' | 'minWidth' | 'maxWidth' | 'flex' | 'flexShrink' | 'flexGrow' | 'flexBasis' | 'tableLayout' | 'captionSide' | 'borderCollapse' | 'borderSpacing' | 'transformOrigin' | 'translate' | 'rotate' | 'skew' | 'scale' | 'transform' | 'animation' | 'cursor' | 'touchAction' | 'userSelect' | 'resize' | 'scrollSnapType' | 'scrollSnapAlign' | 'scrollSnapStop' | 'scrollMargin' | 'scrollPadding' | 'listStylePosition' | 'listStyleType' | 'listStyleImage' | 'appearance' | 'columns' | 'breakBefore' | 'breakInside' | 'breakAfter' | 'gridAutoColumns' | 'gridAutoFlow' | 'gridAutoRows' | 'gridTemplateColumns' | 'gridTemplateRows' | 'flexDirection' | 'flexWrap' | 'placeContent' | 'placeItems' | 'alignContent' | 'alignItems' | 'justifyContent' | 'justifyItems' | 'gap' | 'space' | 'divideWidth' | 'divideStyle' | 'divideColor' | 'divideOpacity' | 'placeSelf' | 'alignSelf' | 'justifySelf' | 'overflow' | 'overscrollBehavior' | 'scrollBehavior' | 'textOverflow' | 'hyphens' | 'whitespace' | 'textWrap' | 'wordBreak' | 'borderRadius' | 'borderWidth' | 'borderStyle' | 'borderColor' | 'borderOpacity' | 'backgroundColor' | 'backgroundOpacity' | 'backgroundImage' | 'gradientColorStops' | 'boxDecorationBreak' | 'backgroundSize' | 'backgroundAttachment' | 'backgroundClip' | 'backgroundPosition' | 'backgroundRepeat' | 'backgroundOrigin' | 'fill' | 'stroke' | 'strokeWidth' | 'objectFit' | 'objectPosition' | 'padding' | 'textAlign' | 'textIndent' | 'verticalAlign' | 'fontFamily' | 'fontSize' | 'fontWeight' | 'textTransform' | 'fontStyle' | 'fontVariantNumeric' | 'lineHeight' | 'letterSpacing' | 'textColor' | 'textOpacity' | 'textDecoration' | 'textDecorationColor' | 'textDecorationStyle' | 'textDecorationThickness' | 'textUnderlineOffset' | 'fontSmoothing' | 'placeholderColor' | 'placeholderOpacity' | 'caretColor' | 'accentColor' | 'opacity' | 'backgroundBlendMode' | 'mixBlendMode' | 'boxShadow' | 'boxShadowColor' | 'outlineStyle' | 'outlineWidth' | 'outlineOffset' | 'outlineColor' | 'ringWidth' | 'ringColor' | 'ringOpacity' | 'ringOffsetWidth' | 'ringOffsetColor' | 'blur' | 'brightness' | 'contrast' | 'dropShadow' | 'grayscale' | 'hueRotate' | 'invert' | 'saturate' | 'sepia' | 'filter' | 'backdropBlur' | 'backdropBrightness' | 'backdropContrast' | 'backdropGrayscale' | 'backdropHueRotate' | 'backdropInvert' | 'backdropOpacity' | 'backdropSaturate' | 'backdropSepia' | 'backdropFilter' | 'transitionProperty' | 'transitionDelay' | 'transitionDuration' | 'transitionTimingFunction' | 'willChange' | 'content' | 'forcedColorAdjust'
type CSSDeclarationList = Record<string, string>
export type DefaultTheme = {
animation: Record<'none' | 'spin' | 'ping' | 'pulse' | 'bounce', string>
aria: Record<
| 'busy'
| 'checked'
| 'disabled'
| 'expanded'
| 'hidden'
| 'pressed'
| 'readonly'
| 'required'
| 'selected',
string
>
aspectRatio: Record<'auto' | 'square' | 'video', string>
backgroundImage: Record<
| 'none'
| 'gradient-to-t'
| 'gradient-to-tr'
| 'gradient-to-r'
| 'gradient-to-br'
| 'gradient-to-b'
| 'gradient-to-bl'
| 'gradient-to-l'
| 'gradient-to-tl',
string
>
backgroundPosition: Record<
| 'bottom'
| 'center'
| 'left'
| 'left-bottom'
| 'left-top'
| 'right'
| 'right-bottom'
| 'right-top'
| 'top',
string
>
backgroundSize: Record<'auto' | 'cover' | 'contain', string>
blur: Record<'0' | 'none' | 'sm' | 'DEFAULT' | 'md' | 'lg' | 'xl' | '2xl' | '3xl', string>
borderRadius: Record<
'none' | 'sm' | 'DEFAULT' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full',
string
>
borderWidth: Record<'0' | '2' | '4' | '8' | 'DEFAULT', string>
boxShadow: Record<'sm' | 'DEFAULT' | 'md' | 'lg' | 'xl' | '2xl' | 'inner' | 'none', string>
brightness: Record<
'0' | '50' | '75' | '90' | '95' | '100' | '105' | '110' | '125' | '150' | '200',
string
>
columns: Record<
| '1'
| '2'
| '3'
| '4'
| '5'
| '6'
| '7'
| '8'
| '9'
| '10'
| '11'
| '12'
| 'auto'
| '3xs'
| '2xs'
| 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| '2xl'
| '3xl'
| '4xl'
| '5xl'
| '6xl'
| '7xl',
string
>
content: Record<'none', string>
contrast: Record<'0' | '50' | '75' | '100' | '125' | '150' | '200', string>
cursor: Record<
| 'auto'
| 'default'
| 'pointer'
| 'wait'
| 'text'
| 'move'
| 'help'
| 'not-allowed'
| 'none'
| 'context-menu'
| 'progress'
| 'cell'
| 'crosshair'
| 'vertical-text'
| 'alias'
| 'copy'
| 'no-drop'
| 'grab'
| 'grabbing'
| 'all-scroll'
| 'col-resize'
| 'row-resize'
| 'n-resize'
| 'e-resize'
| 's-resize'
| 'w-resize'
| 'ne-resize'
| 'nw-resize'
| 'se-resize'
| 'sw-resize'
| 'ew-resize'
| 'ns-resize'
| 'nesw-resize'
| 'nwse-resize'
| 'zoom-in'
| 'zoom-out',
string
>
dropShadow: Record<'sm' | 'DEFAULT' | 'md' | 'lg' | 'xl' | '2xl' | 'none', string | string[]>
flex: Record<'1' | 'auto' | 'initial' | 'none', string>
flexGrow: Record<'0' | 'DEFAULT', string>
flexShrink: Record<'0' | 'DEFAULT', string>
fontFamily: Record<'sans' | 'serif' | 'mono', string[]>
fontSize: Record<
| 'xs'
| 'sm'
| 'base'
| 'lg'
| 'xl'
| '2xl'
| '3xl'
| '4xl'
| '5xl'
| '6xl'
| '7xl'
| '8xl'
| '9xl',
[string, { lineHeight: string }]
>
fontWeight: Record<
| 'thin'
| 'extralight'
| 'light'
| 'normal'
| 'medium'
| 'semibold'
| 'bold'
| 'extrabold'
| 'black',
string
>
gradientColorStopPositions: Record<
| '0%'
| '5%'
| '10%'
| '15%'
| '20%'
| '25%'
| '30%'
| '35%'
| '40%'
| '45%'
| '50%'
| '55%'
| '60%'
| '65%'
| '70%'
| '75%'
| '80%'
| '85%'
| '90%'
| '95%'
| '100%',
string
>
grayscale: Record<'0' | 'DEFAULT', string>
gridAutoColumns: Record<'auto' | 'min' | 'max' | 'fr', string>
gridAutoRows: Record<'auto' | 'min' | 'max' | 'fr', string>
gridColumn: Record<
| 'auto'
| 'span-1'
| 'span-2'
| 'span-3'
| 'span-4'
| 'span-5'
| 'span-6'
| 'span-7'
| 'span-8'
| 'span-9'
| 'span-10'
| 'span-11'
| 'span-12'
| 'span-full',
string
>
gridColumnEnd: Record<
'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | '13' | 'auto',
string
>
gridColumnStart: Record<
'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | '13' | 'auto',
string
>
gridRow: Record<
| 'auto'
| 'span-1'
| 'span-2'
| 'span-3'
| 'span-4'
| 'span-5'
| 'span-6'
| 'span-7'
| 'span-8'
| 'span-9'
| 'span-10'
| 'span-11'
| 'span-12'
| 'span-full',
string
>
gridRowEnd: Record<
'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | '13' | 'auto',
string
>
gridRowStart: Record<
'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | '13' | 'auto',
string
>
gridTemplateColumns: Record<
'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'none' | 'subgrid',
string
>
gridTemplateRows: Record<
'1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' | 'none' | 'subgrid',
string
>
hueRotate: Record<'0' | '15' | '30' | '60' | '90' | '180', string>
invert: Record<'0' | 'DEFAULT', string>
keyframes: Record<'spin' | 'ping' | 'pulse' | 'bounce', Record<string, CSSDeclarationList>>
letterSpacing: Record<'tighter' | 'tight' | 'normal' | 'wide' | 'wider' | 'widest', string>
lineHeight: Record<
| '3'
| '4'
| '5'
| '6'
| '7'
| '8'
| '9'
| '10'
| 'none'
| 'tight'
| 'snug'
| 'normal'
| 'relaxed'
| 'loose',
string
>
listStyleType: Record<'none' | 'disc' | 'decimal', string>
listStyleImage: Record<'none', string>
lineClamp: Record<'1' | '2' | '3' | '4' | '5' | '6', string>
objectPosition: Record<
| 'bottom'
| 'center'
| 'left'
| 'left-bottom'
| 'left-top'
| 'right'
| 'right-bottom'
| 'right-top'
| 'top',
string
>
opacity: Record<
| '0'
| '5'
| '10'
| '15'
| '20'
| '25'
| '30'
| '35'
| '40'
| '45'
| '50'
| '55'
| '60'
| '65'
| '70'
| '75'
| '80'
| '85'
| '90'
| '95'
| '100',
string
>
order: Record<
| '1'
| '2'
| '3'
| '4'
| '5'
| '6'
| '7'
| '8'
| '9'
| '10'
| '11'
| '12'
| 'first'
| 'last'
| 'none',
string
>
outlineOffset: Record<'0' | '1' | '2' | '4' | '8', string>
outlineWidth: Record<'0' | '1' | '2' | '4' | '8', string>
ringOffsetWidth: Record<'0' | '1' | '2' | '4' | '8', string>
ringWidth: Record<'0' | '1' | '2' | '4' | '8' | 'DEFAULT', string>
rotate: Record<'0' | '1' | '2' | '3' | '6' | '12' | '45' | '90' | '180', string>
saturate: Record<'0' | '50' | '100' | '150' | '200', string>
scale: Record<'0' | '50' | '75' | '90' | '95' | '100' | '105' | '110' | '125' | '150', string>
screens: Record<'sm' | 'md' | 'lg' | 'xl' | '2xl', string>
sepia: Record<'0' | 'DEFAULT', string>
skew: Record<'0' | '1' | '2' | '3' | '6' | '12', string>
spacing: Record<
| '0'
| '1'
| '2'
| '3'
| '4'
| '5'
| '6'
| '7'
| '8'
| '9'
| '10'
| '11'
| '12'
| '14'
| '16'
| '20'
| '24'
| '28'
| '32'
| '36'
| '40'
| '44'
| '48'
| '52'
| '56'
| '60'
| '64'
| '72'
| '80'
| '96'
| 'px'
| '0.5'
| '1.5'
| '2.5'
| '3.5',
string
>
strokeWidth: Record<'0' | '1' | '2', string>
textDecorationThickness: Record<'0' | '1' | '2' | '4' | '8' | 'auto' | 'from-font', string>
textUnderlineOffset: Record<'0' | '1' | '2' | '4' | '8' | 'auto', string>
transformOrigin: Record<
| 'center'
| 'top'
| 'top-right'
| 'right'
| 'bottom-right'
| 'bottom'
| 'bottom-left'
| 'left'
| 'top-left',
string
>
transitionDelay: Record<
'0' | '75' | '100' | '150' | '200' | '300' | '500' | '700' | '1000',
string
>
transitionDuration: Record<
'0' | '75' | '100' | '150' | '200' | '300' | '500' | '700' | '1000' | 'DEFAULT',
string
>
transitionProperty: Record<
'none' | 'all' | 'DEFAULT' | 'colors' | 'opacity' | 'shadow' | 'transform',
string
>
transitionTimingFunction: Record<'DEFAULT' | 'linear' | 'in' | 'out' | 'in-out', string>
willChange: Record<'auto' | 'scroll' | 'contents' | 'transform', string>
zIndex: Record<'0' | '10' | '20' | '30' | '40' | '50' | 'auto', string>
}
import type { PluginCreator } from 'postcss'
import type { Config } from './config.d'
declare const plugin: PluginCreator<string | Config | { config: string | Config }>
declare type _Config = Config
declare namespace plugin {
export type { _Config as Config }
}
export = plugin
@tailwind variants;