@taprootio/espalier 2.18.0 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{ACCEPTED_COLOR_FORMS as j,apcaContrast as J,deriveSemantic as Y,parseCssColor as O,parseOklch as X,serializeOklch as Z}from"./color-engine.js";import{computeVariants as q,parseAnchorSource as Q,resolveAnchorColor as ee,resolveMappingSource as ne}from"./variant-engine.js";const L=/^[a-z][a-z0-9-]*$/;function te(t){return Q(t)}function xe(t,e){return ee(t,e)}const E=["canvas","ink","accent","action","structure"],N={canvas:{color:[["background","surface"],["layer1","raised1"],["layer2","raised2"],["layer3","raised3"],["layer4","raised4"]]},ink:{color:[["text","text"],["inputSelection","text"]],heading:[["headings","muted"],["headingsHover","ink"]]},accent:{color:[["linkHoverBg","raised2"],["inputSelectionBg","raised2"],["inputCaret","ink"]],text:[["link","accent"],["linkHover","text"]]},action:{color:[["actionBackground","muted"]],ink:[["actionText","surface"]]},structure:{color:[["border","border"],["shadow","shadow"]]}},oe=new Set(["action.color"]),se={canvas:"background",ink:"text",accent:"link",action:"actionBackground",structure:"border"},re={"action.ink":{role:"canvas",slot:"color"}},ie=.45;function W(t,e){const i=F.actionText,a=[...x].sort((p,m)=>t[p]-t[m]||x.indexOf(p)-x.indexOf(m)),u=e?a.filter(p=>e(p)>=i.targetLc):a,s=u.length>0?u:a;let l,f=1/0;for(const p of s){const m=Math.abs(t[p]-ie);m<f&&(f=m,l=p)}return l??"muted"}function ae(t,e){const i=e[t]>.5;let a=x[0];for(const u of x)(i?e[u]<e[a]:e[u]>e[a])&&(a=u);return a}function A(t,e){if(t===void 0)return;if(typeof t=="string")return e==="color"?t:void 0;const i=t[e];return typeof i=="string"?i:void 0}function D(t,e,i,a={}){const u={},s={};for(const[l,f]of Object.entries(a.explicitMappings??{}))f!==void 0&&(s[l]=f.lightness);for(const l of E){const f=t[l];if(f!==void 0)for(const[p,m]of Object.entries(N[l])){const h=re[`${l}.${p}`];let n=A(f,p),o=!1;if(n===void 0&&(h&&(n=A(t[h.role],h.slot),n??=i[se[h.role]]?.source,o=n!==void 0),n??=A(f,"color")),n!==void 0)for(const[r,c]of m){let g=c;if(oe.has(`${l}.${p}`))g=W(e,a.actionSurfaceContrast?y=>a.actionSurfaceContrast(n,y):void 0);else if(o&&h){const y=F[r],b=(y&&s[y.bg])??W(e,a.actionSurfaceContrast?S=>a.actionSurfaceContrast(A(f,"color"),S):void 0);g=ae(b,e)}u[r]={source:n,lightness:g}}}}return u}const F={text:{bg:"background",targetLc:75},dangerText:{bg:"background",targetLc:75},headings:{bg:"background",targetLc:60},headingsHover:{bg:"background",targetLc:60},link:{bg:"background",targetLc:75},linkHover:{bg:"background",targetLc:75},actionText:{bg:"actionBackground",targetLc:75},inputCaret:{bg:"layer2",targetLc:60},inputSelection:{bg:"inputSelectionBg",targetLc:60}},I=["background","layer1","layer2","layer3","layer4","actionBackground","actionText","border","shadow","text","dangerText","headings","headingsHover","link","linkHover","linkHoverBg","inputCaret","inputSelection","inputSelectionBg"],T=["primary","analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning"],ce=["analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning"],x=["surface","raised1","raised2","raised3","raised4","accent","muted","text","border","ink","shadow"],ue={surface:.99,raised1:.97,raised2:.9,raised3:.8,raised4:.72,accent:.5,muted:.45,text:.35,border:.3,ink:.25,shadow:.2},le={surface:.15,raised1:.2,raised2:.3,raised3:.4,raised4:.36,accent:.6,muted:.75,text:.85,border:.7,ink:.95,shadow:.6},w={background:{source:"primary",lightness:"surface"},layer1:{source:"primary",lightness:"raised1"},layer2:{source:"primary",lightness:"raised2"},layer3:{source:"primary",lightness:"raised3"},layer4:{source:"primary",lightness:"raised4"},actionBackground:{source:"primary",lightness:"raised3"},actionText:{source:"primary",lightness:"ink"},border:{source:"primary",lightness:"border"},shadow:{source:"primary",lightness:"shadow"},text:{source:"primary",lightness:"text"},dangerText:{source:"danger",lightness:"text"},headings:{source:"primary",lightness:"muted"},headingsHover:{source:"primary",lightness:"text"},link:{source:"complementary",lightness:"accent"},linkHover:{source:"complementary",lightness:"text"},linkHoverBg:{source:"triadic-left",lightness:"raised2"},inputCaret:{source:"triadic-right",lightness:"ink"},inputSelection:{source:"complementary",lightness:"text"},inputSelectionBg:{source:"triadic-left",lightness:"raised2"}},v=.4;function R(){const t={};for(const e of I)t[e]={min:0,max:v};return t}const P={seedColor:"oklch(0.7 0.125 216)",fontBody:"",fontHeadings:"",fontBrand:"",fontMonospace:"",fontWeightBody:"normal",fontWeightHeadings:"bold",fontWeightBrand:"bold",fontWeightMonospace:"normal",stylesheets:[],rootFontSize:16,typeRatio:1.25,spaceRatio:1.618,borderRadius:.2,viewportMin:320,viewportMax:1200,angles:{analogous:30,complementary:180,splitComplementary:30,triadic:120},semanticHues:{danger:27,success:150,warning:90},variantChroma:{},chroma:R(),semanticMappings:{...w},anchors:{},roles:{}},fe={...P,chroma:R(),semanticMappings:{...w},anchors:{},roles:{},lightness:{...ue}},pe={...P,chroma:R(),semanticMappings:{...w},anchors:{},roles:{},lightness:{...le}},M=new WeakMap;M.set(fe,new Set),M.set(pe,new Set);const K=new Set(["__proto__","constructor","prototype"]);function d(t){return!K.has(t)}function ge(t,e){return K.has(t)?void 0:e}function Se(t){return`--esp-color-${t.replace(/([A-Z])/g,"-$1").replace(/(\d)/g,"-$1").toLowerCase()}`}function me(t){try{const e=atob(t),i=JSON.parse(e,ge);return typeof i!="object"||i===null||Array.isArray(i)?null:i}catch{return null}}function H(t){return btoa(JSON.stringify(t))}function _(t){if(X(t))return t;const e=O(t);return e?Z(e):t}function U(t,e){const i={};for(const[a,u]of Object.entries(t))d(a)&&(i[a]=u);if(!e)return i;for(const[a,u]of Object.entries(e)){if(u===void 0||!d(a))continue;const s=i[a];if(s!==void 0&&typeof u=="object"&&u!==null){const l={};if(typeof s=="string")l.color=s;else for(const[f,p]of Object.entries(s))d(f)&&(l[f]=p);for(const[f,p]of Object.entries(u))p!==void 0&&d(f)&&(l[f]=p);i[a]=l;continue}i[a]=u}return i}function de(t){const e={};for(const[i,a]of Object.entries(t)){if(!d(i))continue;if(typeof a=="string"){e[i]=_(a);continue}const u={};for(const[s,l]of Object.entries(a))d(s)&&(u[s]=typeof l=="string"?_(l):l);e[i]=u}return e}function z(t){const e=O(t.seedColor);if(!e)return;const i=q(e,t);return(a,u)=>{const s=ne(a,i,t.anchors)??i.primary,l=t.chroma.actionBackground,f=Y(s,t.lightness[u],l.min,l.max),p={l:f.l>.5?0:1,c:0,h:0};return Math.abs(J(p,f))}}function he(t){const e=M.get(t);if(e)return new Set(e);const i=new Set,a=D(t.roles,t.lightness,t.semanticMappings,{actionSurfaceContrast:z(t)});for(const[u,s]of Object.entries(a)){const l=t.semanticMappings[u];(l.source!==s.source||l.lightness!==s.lightness)&&i.add(u)}return i}function Oe(t,e){const i={...t.roles,...e.roles},a={...t.lightness,...e.lightness},u=de(U(t.anchors,e.anchors)),s=typeof e.seedColor=="string"?_(e.seedColor):t.seedColor,l=e.semanticMappings,f={...t.angles,...e.angles},p={...t.semanticHues,...e.semanticHues},m={...t.variantChroma,...e.variantChroma},h=B(t.chroma,e.chroma),n=he(t),o=new Set(n),r={};for(const $ of n)r[$]=t.semanticMappings[$];for(const[$,C]of Object.entries(l??{}))C!==void 0&&(o.add($),r[$]=C);const c=B(t.semanticMappings,l),g=z({angles:f,anchors:u,chroma:h,lightness:a,seedColor:s,semanticHues:p,variantChroma:m}),y=D(i,a,c,{explicitMappings:r,actionSurfaceContrast:g}),b={};for(const[$,C]of Object.entries(y))o.has($)||(b[$]=C);const S=B(B(t.semanticMappings,b),l),k={...t,seedColor:s,fontBody:e.fontBody??t.fontBody,fontHeadings:e.fontHeadings??t.fontHeadings,fontBrand:e.fontBrand??t.fontBrand,fontMonospace:e.fontMonospace??t.fontMonospace,fontWeightBody:String(e.fontWeightBody??t.fontWeightBody),fontWeightHeadings:String(e.fontWeightHeadings??t.fontWeightHeadings),fontWeightBrand:String(e.fontWeightBrand??t.fontWeightBrand),fontWeightMonospace:String(e.fontWeightMonospace??t.fontWeightMonospace),stylesheets:e.stylesheets??[...t.stylesheets],rootFontSize:e.rootFontSize??t.rootFontSize,typeRatio:e.typeRatio??t.typeRatio,spaceRatio:e.spaceRatio??t.spaceRatio,borderRadius:e.borderRadius??t.borderRadius,viewportMin:e.viewportMin??t.viewportMin,viewportMax:e.viewportMax??t.viewportMax,angles:f,semanticHues:p,variantChroma:m,lightness:a,chroma:h,semanticMappings:S,anchors:u,roles:i};return e.pageBackgroundImage!==void 0&&(k.pageBackgroundImage=e.pageBackgroundImage),e.pageBackgroundImageOpacity!==void 0&&(k.pageBackgroundImageOpacity=e.pageBackgroundImageOpacity),e.boxBackgroundImage!==void 0&&(k.boxBackgroundImage=e.boxBackgroundImage),e.boxBackgroundImageOpacity!==void 0&&(k.boxBackgroundImageOpacity=e.boxBackgroundImageOpacity),e.vellumOpacity!==void 0&&(k.vellumOpacity=e.vellumOpacity),e.vellumBackgroundImage!==void 0&&(k.vellumBackgroundImage=e.vellumBackgroundImage),e.vellumBackgroundImageOpacity!==void 0&&(k.vellumBackgroundImageOpacity=e.vellumBackgroundImageOpacity),M.set(k,new Set(o)),k}function B(t,e){if(!e)return{...t};const i={...t};for(const a of Object.keys(e)){const u=e[a];u!==void 0&&(i[a]=u)}return i}function ve(t){const e=[],i=[];let a;try{a=atob(t)}catch{return e.push("Failed to decode Base64 string."),{valid:!1,errors:e,warnings:i}}let u;try{u=JSON.parse(a)}catch{return e.push("Decoded string is not valid JSON."),{valid:!1,errors:e,warnings:i}}if(typeof u!="object"||u===null||Array.isArray(u))return e.push("Theme must be a JSON object."),{valid:!1,errors:e,warnings:i};const s=u;"seedColor"in s&&(typeof s.seedColor!="string"?e.push("seedColor must be a string."):O(s.seedColor)||e.push(`seedColor is not a valid CSS color: "${s.seedColor}". Accepted forms: ${j}.`));for(const n of["fontBody","fontHeadings","fontBrand","fontMonospace"])n in s&&typeof s[n]!="string"&&e.push(`${n} must be a string.`);const l=["normal","bold","lighter","bolder"],f=["inherit","initial","unset","revert","revert-layer"];for(const n of["fontWeightBody","fontWeightHeadings","fontWeightBrand","fontWeightMonospace"])if(n in s){const o=s[n];if(typeof o=="number")(o<1||o>1e3)&&e.push(`${n} numeric value must be 1\u20131000 (got ${o}).`);else if(typeof o=="string"){const r=l.includes(o)||f.includes(o);if(/^\d+$/.test(o)){const g=Number(o);(g<1||g>1e3)&&e.push(`${n} numeric value must be 1\u20131000 (got "${o}").`)}else r||i.push(`${n} = "${o}" is not a standard font-weight value.`)}else e.push(`${n} must be a string or number.`)}"stylesheets"in s&&(Array.isArray(s.stylesheets)?s.stylesheets.some(n=>typeof n!="string")&&e.push("Every entry in stylesheets must be a string."):e.push("stylesheets must be an array of strings."));const p=[["rootFontSize",1,100],["borderRadius",0,10],["viewportMin",100,1e4],["viewportMax",200,1e4]];for(const[n,o,r]of p)if(n in s)if(typeof s[n]!="number"||!isFinite(s[n]))e.push(`${n} must be a finite number.`);else{const c=s[n];o!==void 0&&c<o&&e.push(`${n} must be \u2265 ${o} (got ${c}).`),r!==void 0&&c>r&&i.push(`${n} = ${c} is unusually high (max ${r}).`)}for(const n of["typeRatio","spaceRatio"])if(n in s)if(typeof s[n]!="number"||!isFinite(s[n]))e.push(`${n} must be a finite number.`);else{const o=s[n];o<=1&&e.push(`${n} must be > 1 (got ${o}).`);const r=n==="typeRatio"?1.3:2;o>r&&i.push(`${n} = ${o} is very high (max ${r}); scales may be extreme.`)}if("viewportMin"in s&&"viewportMax"in s){const n=s.viewportMin,o=s.viewportMax;typeof n=="number"&&typeof o=="number"&&n>=o&&e.push(`viewportMin (${n}) must be less than viewportMax (${o}).`)}if("angles"in s)if(typeof s.angles!="object"||s.angles===null)e.push("angles must be an object.");else{const n=s.angles;for(const o of["analogous","complementary","splitComplementary","triadic"])if(o in n)if(typeof n[o]!="number"||!isFinite(n[o]))e.push(`angles.${o} must be a finite number.`);else{const r=n[o];(r<0||r>360)&&i.push(`angles.${o} = ${r} is outside 0\u2013360.`)}}if("semanticHues"in s)if(typeof s.semanticHues!="object"||s.semanticHues===null)e.push("semanticHues must be an object.");else{const n=s.semanticHues;for(const o of["danger","success","warning"])if(o in n)if(typeof n[o]!="number"||!isFinite(n[o]))e.push(`semanticHues.${o} must be a finite number.`);else{const r=n[o];(r<0||r>360)&&i.push(`semanticHues.${o} = ${r} is outside 0\u2013360.`)}}if("variantChroma"in s)if(typeof s.variantChroma!="object"||s.variantChroma===null)e.push("variantChroma must be an object.");else{const n=s.variantChroma;for(const o of ce)if(o in n)if(typeof n[o]!="number"||!isFinite(n[o]))e.push(`variantChroma["${o}"] must be a finite number.`);else{const r=n[o];r<0&&e.push(`variantChroma["${o}"] must be \u2265 0 (got ${r}).`),r>v&&i.push(`variantChroma["${o}"] = ${r} exceeds ${v}.`)}}if("lightness"in s)if(typeof s.lightness!="object"||s.lightness===null)e.push("lightness must be an object.");else{const n=s.lightness;for(const o of x)if(o in n)if(typeof n[o]!="number"||!isFinite(n[o]))e.push(`lightness.${o} must be a finite number.`);else{const r=n[o];(r<0||r>1)&&e.push(`lightness.${o} must be 0\u20131 (got ${r}).`)}}if("chroma"in s)if(typeof s.chroma!="object"||s.chroma===null)e.push("chroma must be an object.");else{const n=s.chroma;for(const o of I)if(o in n){const r=n[o];if(typeof r!="object"||r===null){e.push(`chroma.${o} must be { min, max }.`);continue}const c=r;(typeof c.min!="number"||c.min<0)&&e.push(`chroma.${o}.min must be \u2265 0.`),(typeof c.max!="number"||c.max<0||c.max>v)&&e.push(`chroma.${o}.max must be 0\u2013${v}.`),typeof c.min=="number"&&typeof c.max=="number"&&c.min>c.max&&e.push(`chroma.${o}.min (${c.min}) must be \u2264 max (${c.max}).`)}}if("anchors"in s)if(typeof s.anchors!="object"||s.anchors===null||Array.isArray(s.anchors))e.push("anchors must be an object of named colors.");else for(const[n,o]of Object.entries(s.anchors))if(d(n)?L.test(n)||e.push(`anchors: "${n}" is not a valid anchor name; use a lowercase slug (letters, digits, hyphens).`):e.push(`anchors: "${n}" is a reserved JavaScript property name and cannot be an anchor name; rename it.`),T.includes(n)&&e.push(`anchors: "${n}" collides with a reserved color source name.`),typeof o=="string")O(o)||e.push(`anchors.${n} is not a valid CSS color: "${o}". Accepted forms: ${j}.`);else if(typeof o=="object"&&o!==null&&!Array.isArray(o)){const r=o;typeof r.color!="string"&&e.push(`anchors.${n} must declare its base "color".`);for(const[c,g]of Object.entries(r))d(c)?c!=="color"&&!L.test(c)&&e.push(`anchors.${n}: "${c}" is not a valid slot name; use a lowercase slug.`):e.push(`anchors.${n}: "${c}" is a reserved JavaScript property name and cannot be a slot name; rename it.`),typeof g!="string"?e.push(`anchors.${n}.${c} must be a CSS color string.`):O(g)||e.push(`anchors.${n}.${c} is not a valid CSS color: "${g}". Accepted forms: ${j}.`)}else e.push(`anchors.${n} must be a color string or a { color, \u2026slots } object.`);const m=new Map;if("anchors"in s&&typeof s.anchors=="object"&&s.anchors!==null&&!Array.isArray(s.anchors))for(const[n,o]of Object.entries(s.anchors))m.set(n,o);function h(n,o){if(!n.startsWith("anchor:")){T.includes(n)||e.push(`${o} must be one of: ${T.join(", ")}, or a declared anchor as anchor:<name> / anchor:<name>.<slot>.`);return}const r=te(n);if(!r){e.push(`${o} "${n}" is not valid anchor syntax; use anchor:<name> or anchor:<name>.<slot>.`);return}if(!m.has(r.name)){const c=[...m.keys()];e.push(`${o} references undeclared anchor "${r.name}". Declared anchors: ${c.length>0?c.join(", "):"(none)"}.`);return}if(r.slot!==void 0){const c=m.get(r.name);if(typeof(typeof c=="object"&&c!==null&&!Array.isArray(c)?c[r.slot]:void 0)!="string"){const y=typeof c=="object"&&c!==null?Object.keys(c).filter(b=>b!=="color"):[];e.push(`${o} references unknown slot "${r.slot}" on anchor "${r.name}". Declared slots: ${y.length>0?y.join(", "):"(none)"}.`)}}}if("roles"in s)if(typeof s.roles!="object"||s.roles===null||Array.isArray(s.roles))e.push("roles must be an object.");else{const n=s.roles;for(const[o,r]of Object.entries(n)){if(!E.includes(o)){e.push(`roles.${o} is not a role; expected one of: ${E.join(", ")}. (The status family is reserved and is not a role.)`);continue}const c=o,g=N[c];if(typeof r=="string"){h(r,`roles.${c}`);continue}if(typeof r!="object"||r===null||Array.isArray(r)){e.push(`roles.${c} must be a color source or a { color, \u2026slots } object.`);continue}const y=r;typeof y.color!="string"&&e.push(`roles.${c} must declare its base "color".`);for(const[b,S]of Object.entries(y)){if(!Object.prototype.hasOwnProperty.call(g,b)||!d(b)){const k=Object.keys(g).filter($=>$!=="color");e.push(`roles.${c}.${b} is not a slot of the ${c} role. Declared slots: ${k.length>0?k.join(", "):"(none)"}.`);continue}typeof S!="string"?e.push(`roles.${c}.${b} must be a color source string.`):h(S,`roles.${c}.${b}`)}}}if("semanticMappings"in s)if(typeof s.semanticMappings!="object"||s.semanticMappings===null)e.push("semanticMappings must be an object.");else{const n=s.semanticMappings;for(const o of I)if(o in n){const r=n[o];if(typeof r!="object"||r===null){e.push(`semanticMappings.${o} must be { source, lightness }.`);continue}const c=r;typeof c.source!="string"?e.push(`semanticMappings.${o}.source must be a string.`):h(c.source,`semanticMappings.${o}.source`),(typeof c.lightness!="string"||!x.includes(c.lightness))&&e.push(`semanticMappings.${o}.lightness must be one of: ${x.join(", ")}.`)}}for(const n of["pageBackgroundImage","boxBackgroundImage","vellumBackgroundImage"])n in s&&typeof s[n]!="string"&&e.push(`${n} must be a string.`);for(const n of["pageBackgroundImageOpacity","boxBackgroundImageOpacity","vellumOpacity","vellumBackgroundImageOpacity"])if(n in s)if(typeof s[n]!="number"||!isFinite(s[n]))e.push(`${n} must be a finite number.`);else{const o=s[n];(o<0||o>1)&&e.push(`${n} must be 0\u20131 (got ${o}).`)}return{valid:e.length===0,errors:e,warnings:i}}const ye=["anchors","angles","roles","chroma","lightness","semanticHues","semanticMappings","variantChroma"];function be(t,e){const i={};for(const[a,u]of Object.entries(t))d(a)&&(i[a]=u);for(const[a,u]of Object.entries(e))u!==void 0&&d(a)&&(i[a]=u);for(const a of ye){const u=t[a],s=e[a];if(u&&typeof u=="object"&&!Array.isArray(u)&&s&&typeof s=="object"&&!Array.isArray(s)){if(a==="anchors"){i[a]=U(u,s);continue}const l={};for(const[f,p]of Object.entries(u))d(f)&&(l[f]=p);for(const[f,p]of Object.entries(s))p!==void 0&&d(f)&&(l[f]=p);i[a]=l}}return i}function Ce(...t){let e={};for(const i of t){if(!i)continue;const a=me(i);a&&(e=be(e,a))}return H(e)}function G(t){return t.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")}const V={borderRadius:.1,fontBody:'"Noto Sans", sans-serif',fontWeightBody:"normal",fontHeadings:'"Inika", serif',fontWeightHeadings:"normal",fontBrand:'"Inika", serif',fontWeightBrand:"normal",fontMonospace:'"JetBrains Mono", monospace',fontWeightMonospace:"normal",seedColor:"oklch(.07 0.15 216)"};function Ae(t){return H({...V,pageBackgroundImage:`url("${G(t)}")`,pageBackgroundImageOpacity:.5})}function Me(t){return H({...V,pageBackgroundImage:`url("${G(t)}")`,pageBackgroundImageOpacity:.55})}export{L as ANCHOR_SLUG_PATTERN,T as COLOR_SOURCES,le as DEFAULT_DARK_LIGHTNESS,pe as DEFAULT_DARK_THEME,ue as DEFAULT_LIGHT_LIGHTNESS,fe as DEFAULT_LIGHT_THEME,w as DEFAULT_SEMANTIC_MAPPINGS,x as LIGHTNESS_KEYS,ye as NESTED_THEME_KEYS,E as ROLE_NAMES,re as ROLE_PAIRED_INK,N as ROLE_TOKEN_PLAN,I as SEMANTIC_COLOR_NAMES,F as TOKEN_PAIRINGS,ce as VARIANT_COLOR_SOURCES,Me as buildTaprootDarkTheme,Ae as buildTaprootLightTheme,D as compileRoles,H as encodeTheme,Ce as layerThemes,be as mergePartials,Oe as mergeTheme,te as parseAnchorSource,me as parseTheme,xe as resolveAnchorColor,Se as semanticToCSS,ve as validateTheme};
1
+ import{ACCEPTED_COLOR_FORMS as w,apcaContrast as de,deriveSemantic as he,parseCssColor as M,parseOklch as ye,serializeOklch as be}from"./color-engine.js";import{computeVariants as $e,parseAnchorSource as xe,resolveAnchorColor as ke,resolveMappingSource as Se}from"./variant-engine.js";import{auditDataPalette as Ae,DATA_SERIES_KEYS as I,DEFAULT_DATA_PALETTE as N,DEFAULT_DATA_RAMP_STEPS as je,MAX_DATA_RAMP_STEPS as F,MIN_DATA_RAMP_LIGHTNESS_STEP as X,MIN_DATA_RAMP_STEPS as W}from"./data-colors.js";const A=/^[a-z][a-z0-9-]*$/;function Z(n){return xe(n)}function Re(n,e){return ke(n,e)}function Oe(n,e){const a=Z(n);if(a){const r=Re(e,a);return r&&M(r)?r:null}return M(n)?n:null}const P=["canvas","ink","accent","action","structure"],Q={canvas:{color:[["background","surface"],["layer1","raised1"],["layer2","raised2"],["layer3","raised3"],["layer4","raised4"]]},ink:{color:[["text","text"],["inputSelection","text"]],heading:[["headings","muted"],["headingsHover","ink"]]},accent:{color:[["linkHoverBg","raised2"],["inputSelectionBg","raised2"],["inputCaret","ink"]],text:[["link","accent"],["linkHover","text"]]},action:{color:[["actionBackground","muted"]],ink:[["actionText","surface"]]},structure:{color:[["border","border"],["shadow","shadow"]]}},Ce=new Set(["action.color"]),Me={canvas:"background",ink:"text",accent:"link",action:"actionBackground",structure:"border"},ve={"action.ink":{role:"canvas",slot:"color"}},Ee=.45;function ee(n,e){const a=ne.actionText,r=[...j].sort((m,b)=>n[m]-n[b]||j.indexOf(m)-j.indexOf(b)),i=e?r.filter(m=>e(m)>=a.targetLc):r,o=i.length>0?i:r;let l,p=1/0;for(const m of o){const b=Math.abs(n[m]-Ee);b<p&&(p=b,l=m)}return l??"muted"}function Te(n,e){const a=e[n]>.5;let r=j[0];for(const i of j)(a?e[i]<e[r]:e[i]>e[r])&&(r=i);return r}function H(n,e){if(n===void 0)return;if(typeof n=="string")return e==="color"?n:void 0;const a=n[e];return typeof a=="string"?a:void 0}function te(n,e,a,r={}){const i={},o={};for(const[l,p]of Object.entries(r.explicitMappings??{}))p!==void 0&&(o[l]=p.lightness);for(const l of P){const p=n[l];if(p!==void 0)for(const[m,b]of Object.entries(Q[l])){const h=ve[`${l}.${m}`];let $=H(p,m),R=!1;if($===void 0&&(h&&($=H(n[h.role],h.slot),$??=a[Me[h.role]]?.source,R=$!==void 0),$??=H(p,"color")),$!==void 0)for(const[S,O]of b){let t=O;if(Ce.has(`${l}.${m}`))t=ee(e,r.actionSurfaceContrast?s=>r.actionSurfaceContrast($,s):void 0);else if(R&&h){const s=ne[S],u=(s&&o[s.bg])??ee(e,r.actionSurfaceContrast?c=>r.actionSurfaceContrast(H(p,"color"),c):void 0);t=Te(u,e)}i[S]={source:$,lightness:t}}}}return i}const ne={text:{bg:"background",targetLc:75},dangerText:{bg:"background",targetLc:75},headings:{bg:"background",targetLc:60},headingsHover:{bg:"background",targetLc:60},link:{bg:"background",targetLc:75},linkHover:{bg:"background",targetLc:75},actionText:{bg:"actionBackground",targetLc:75},inputCaret:{bg:"layer2",targetLc:60},inputSelection:{bg:"inputSelectionBg",targetLc:60}},z=["background","layer1","layer2","layer3","layer4","actionBackground","actionText","border","shadow","text","dangerText","headings","headingsHover","link","linkHover","linkHoverBg","inputCaret","inputSelection","inputSelectionBg"],K=["primary","analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning"],Be=["analogous-left","analogous-right","complementary","split-complementary-left","split-complementary-right","triadic-left","triadic-right","danger","success","warning"],j=["surface","raised1","raised2","raised3","raised4","accent","muted","text","border","ink","shadow"],_e={surface:.99,raised1:.97,raised2:.9,raised3:.8,raised4:.72,accent:.5,muted:.45,text:.35,border:.3,ink:.25,shadow:.2},we={surface:.15,raised1:.2,raised2:.3,raised3:.4,raised4:.36,accent:.6,muted:.75,text:.85,border:.7,ink:.95,shadow:.6},U={background:{source:"primary",lightness:"surface"},layer1:{source:"primary",lightness:"raised1"},layer2:{source:"primary",lightness:"raised2"},layer3:{source:"primary",lightness:"raised3"},layer4:{source:"primary",lightness:"raised4"},actionBackground:{source:"primary",lightness:"raised3"},actionText:{source:"primary",lightness:"ink"},border:{source:"primary",lightness:"border"},shadow:{source:"primary",lightness:"shadow"},text:{source:"primary",lightness:"text"},dangerText:{source:"danger",lightness:"text"},headings:{source:"primary",lightness:"muted"},headingsHover:{source:"primary",lightness:"text"},link:{source:"complementary",lightness:"accent"},linkHover:{source:"complementary",lightness:"text"},linkHoverBg:{source:"triadic-left",lightness:"raised2"},inputCaret:{source:"triadic-right",lightness:"ink"},inputSelection:{source:"complementary",lightness:"text"},inputSelectionBg:{source:"triadic-left",lightness:"raised2"}},T=.4;function G(){const n={};for(const e of z)n[e]={min:0,max:T};return n}const oe={seedColor:"oklch(0.7 0.125 216)",fontBody:"",fontHeadings:"",fontBrand:"",fontMonospace:"",fontWeightBody:"normal",fontWeightHeadings:"bold",fontWeightBrand:"bold",fontWeightMonospace:"normal",stylesheets:[],rootFontSize:16,typeRatio:1.25,spaceRatio:1.618,borderRadius:.2,viewportMin:320,viewportMax:1200,angles:{analogous:30,complementary:180,splitComplementary:30,triadic:120},semanticHues:{danger:27,success:150,warning:90},variantChroma:{},chroma:G(),semanticMappings:{...U},anchors:{},roles:{},contexts:{},dataPalette:{...N},dataRamps:{}},se={...oe,chroma:G(),semanticMappings:{...U},anchors:{},roles:{},contexts:{},dataPalette:{...N},dataRamps:{},lightness:{..._e}},Ie={...oe,chroma:G(),semanticMappings:{...U},anchors:{},roles:{},contexts:{},dataPalette:{...N},dataRamps:{},lightness:{...we}},L=new WeakMap;L.set(se,new Set),L.set(Ie,new Set);const re=new Set(["__proto__","constructor","prototype"]);function g(n){return!re.has(n)}function Pe(n,e){return re.has(n)?void 0:e}function qe(n){return`--esp-color-${n.replace(/([A-Z])/g,"-$1").replace(/(\d)/g,"-$1").toLowerCase()}`}function V(n){try{const e=atob(n),a=JSON.parse(e,Pe);return typeof a!="object"||a===null||Array.isArray(a)?null:a}catch{return null}}function J(n){return btoa(JSON.stringify(n))}function D(n){if(ye(n))return n;const e=M(n);return e?be(e):n}function ae(n,e){const a={};for(const[r,i]of Object.entries(n))g(r)&&(a[r]=i);if(!e)return a;for(const[r,i]of Object.entries(e)){if(i===void 0||!g(r))continue;const o=a[r];if(o!==void 0&&typeof i=="object"&&i!==null){const l={};if(typeof o=="string")l.color=o;else for(const[p,m]of Object.entries(o))g(p)&&(l[p]=m);for(const[p,m]of Object.entries(i))m!==void 0&&g(p)&&(l[p]=m);a[r]=l;continue}a[r]=i}return a}function ie(n){if(typeof n!="object"||n===null||Array.isArray(n))return null;const e=n,a={};for(const r of P){const i=e[r];i!==void 0&&(a[r]=i)}if(typeof e.lightness=="object"&&e.lightness!==null&&!Array.isArray(e.lightness)){const r={};for(const i of j){const o=e.lightness[i];o!==void 0&&(r[i]=o)}a.lightness=r}return a}function He(n,e){const a={};for(const[r,i]of Object.entries(n)){if(!g(r)||!A.test(r))continue;const o=ie(i);o&&(a[r]=o)}if(!e)return a;for(const[r,i]of Object.entries(e)){if(!g(r)||!A.test(r)||i===void 0)continue;const o=ie(i);if(!o)continue;const l=a[r];a[r]={...l??{},...o,...l?.lightness||o.lightness?{lightness:{...l?.lightness,...o.lightness}}:{}}}return a}function v(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)}function E(n){const e={};for(const[a,r]of Object.entries(n))r!==void 0&&g(a)&&(e[a]=r);return e}function ce(n){if(!v(n))return n;const e=E(n);return v(n.lightness)&&(e.lightness=E(n.lightness)),e}function Le(n,e){const a={};for(const[r,i]of Object.entries(n))g(r)&&(a[r]=ce(i));if(!e)return a;for(const[r,i]of Object.entries(e)){if(!g(r)||i===void 0)continue;const o=a[r];if(!v(o)||!v(i)){a[r]=ce(i);continue}const l={...E(o),...E(i)};v(o.lightness)&&v(i.lightness)?l.lightness={...E(o.lightness),...E(i.lightness)}:v(i.lightness)&&(l.lightness=E(i.lightness)),a[r]=l}return a}function De(n){const e={};for(const[a,r]of Object.entries(n)){if(!g(a))continue;if(typeof r=="string"){e[a]=D(r);continue}const i={};for(const[o,l]of Object.entries(r))g(o)&&(i[o]=typeof l=="string"?D(l):l);e[a]=i}return e}function B(n){return typeof n!="string"?"":n.startsWith("anchor:")?n:D(n)}function Ne(n){const e={};for(const a of I)e[a]=B(n[a]);return e}function ue(n,e){const a={};for(const[r,i]of Object.entries(n))g(r)&&A.test(r)&&i&&typeof i=="object"&&!Array.isArray(i)&&(a[r]={...i});if(!e)return a;for(const[r,i]of Object.entries(e)){if(!g(r)||!A.test(r)||!i||typeof i!="object"||Array.isArray(i))continue;const o=a[r],l=o!==void 0&&i.type!==void 0&&i.type!==o.type;a[r]={...l?{}:o??{},...i}}return a}function Fe(n){const e={};for(const[a,r]of Object.entries(n))if(g(a)){if(r.type==="sequential"&&typeof r.source=="string"){e[a]={...r,source:B(r.source)};continue}if(r.type==="diverging"&&typeof r.start=="string"&&typeof r.end=="string"){e[a]={...r,start:B(r.start),end:B(r.end),...typeof r.neutral=="string"?{neutral:B(r.neutral)}:{}};continue}e[a]={...r}}return e}function le(n){const e=M(n.seedColor);if(!e)return;const a=$e(e,n);return(r,i)=>{const o=Se(r,a,n.anchors)??a.primary,l=n.chroma.actionBackground,p=he(o,n.lightness[i],l.min,l.max),m={l:p.l>.5?0:1,c:0,h:0};return Math.abs(de(m,p))}}function We(n){const e=L.get(n);if(e)return new Set(e);const a=new Set,r=te(n.roles,n.lightness,n.semanticMappings,{actionSurfaceContrast:le(n)});for(const[i,o]of Object.entries(r)){const l=n.semanticMappings[i];(l.source!==o.source||l.lightness!==o.lightness)&&a.add(i)}return a}function ze(n,e){const a={...n.roles,...e.roles},r=He(n.contexts,e.contexts),i={...n.lightness,...e.lightness},o=De(ae(n.anchors,e.anchors)),l=typeof e.seedColor=="string"?D(e.seedColor):n.seedColor,p=e.semanticMappings,m={...n.angles,...e.angles},b={...n.semanticHues,...e.semanticHues},h={...n.variantChroma,...e.variantChroma},$=_(n.chroma,e.chroma),R=Ne(_(n.dataPalette,e.dataPalette)),S=Fe(ue(n.dataRamps,e.dataRamps)),O=We(n),t=new Set(O),s={};for(const x of O)s[x]=n.semanticMappings[x];for(const[x,k]of Object.entries(p??{}))k!==void 0&&(t.add(x),s[x]=k);const u=_(n.semanticMappings,p),c=le({angles:m,anchors:o,chroma:$,lightness:i,seedColor:l,semanticHues:b,variantChroma:h}),f=te(a,i,u,{explicitMappings:s,actionSurfaceContrast:c}),d={};for(const[x,k]of Object.entries(f))t.has(x)||(d[x]=k);const C=_(_(n.semanticMappings,d),p),y={...n,seedColor:l,fontBody:e.fontBody??n.fontBody,fontHeadings:e.fontHeadings??n.fontHeadings,fontBrand:e.fontBrand??n.fontBrand,fontMonospace:e.fontMonospace??n.fontMonospace,fontWeightBody:String(e.fontWeightBody??n.fontWeightBody),fontWeightHeadings:String(e.fontWeightHeadings??n.fontWeightHeadings),fontWeightBrand:String(e.fontWeightBrand??n.fontWeightBrand),fontWeightMonospace:String(e.fontWeightMonospace??n.fontWeightMonospace),stylesheets:e.stylesheets??[...n.stylesheets],rootFontSize:e.rootFontSize??n.rootFontSize,typeRatio:e.typeRatio??n.typeRatio,spaceRatio:e.spaceRatio??n.spaceRatio,borderRadius:e.borderRadius??n.borderRadius,viewportMin:e.viewportMin??n.viewportMin,viewportMax:e.viewportMax??n.viewportMax,angles:m,semanticHues:b,variantChroma:h,lightness:i,chroma:$,semanticMappings:C,anchors:o,roles:a,contexts:r,dataPalette:R,dataRamps:S};return e.pageBackgroundImage!==void 0&&(y.pageBackgroundImage=e.pageBackgroundImage),e.pageBackgroundImageOpacity!==void 0&&(y.pageBackgroundImageOpacity=e.pageBackgroundImageOpacity),e.boxBackgroundImage!==void 0&&(y.boxBackgroundImage=e.boxBackgroundImage),e.boxBackgroundImageOpacity!==void 0&&(y.boxBackgroundImageOpacity=e.boxBackgroundImageOpacity),e.vellumOpacity!==void 0&&(y.vellumOpacity=e.vellumOpacity),e.vellumBackgroundImage!==void 0&&(y.vellumBackgroundImage=e.vellumBackgroundImage),e.vellumBackgroundImageOpacity!==void 0&&(y.vellumBackgroundImageOpacity=e.vellumBackgroundImageOpacity),L.set(y,new Set(t)),y}function _(n,e){if(!e)return{...n};const a={...n};for(const r of Object.keys(e)){const i=e[r];i!==void 0&&(a[r]=i)}return a}function fe(n){const e=[],a=[];let r;try{r=atob(n)}catch{return e.push("Failed to decode Base64 string."),{valid:!1,errors:e,warnings:a}}let i;try{i=JSON.parse(r)}catch{return e.push("Decoded string is not valid JSON."),{valid:!1,errors:e,warnings:a}}if(typeof i!="object"||i===null||Array.isArray(i))return e.push("Theme must be a JSON object."),{valid:!1,errors:e,warnings:a};const o=i;"seedColor"in o&&(typeof o.seedColor!="string"?e.push("seedColor must be a string."):M(o.seedColor)||e.push(`seedColor is not a valid CSS color: "${o.seedColor}". Accepted forms: ${w}.`));for(const t of["fontBody","fontHeadings","fontBrand","fontMonospace"])t in o&&typeof o[t]!="string"&&e.push(`${t} must be a string.`);const l=["normal","bold","lighter","bolder"],p=["inherit","initial","unset","revert","revert-layer"];for(const t of["fontWeightBody","fontWeightHeadings","fontWeightBrand","fontWeightMonospace"])if(t in o){const s=o[t];if(typeof s=="number")(s<1||s>1e3)&&e.push(`${t} numeric value must be 1\u20131000 (got ${s}).`);else if(typeof s=="string"){const u=l.includes(s)||p.includes(s);if(/^\d+$/.test(s)){const f=Number(s);(f<1||f>1e3)&&e.push(`${t} numeric value must be 1\u20131000 (got "${s}").`)}else u||a.push(`${t} = "${s}" is not a standard font-weight value.`)}else e.push(`${t} must be a string or number.`)}"stylesheets"in o&&(Array.isArray(o.stylesheets)?o.stylesheets.some(t=>typeof t!="string")&&e.push("Every entry in stylesheets must be a string."):e.push("stylesheets must be an array of strings."));const m=[["rootFontSize",1,100],["borderRadius",0,10],["viewportMin",100,1e4],["viewportMax",200,1e4]];for(const[t,s,u]of m)if(t in o)if(typeof o[t]!="number"||!isFinite(o[t]))e.push(`${t} must be a finite number.`);else{const c=o[t];s!==void 0&&c<s&&e.push(`${t} must be \u2265 ${s} (got ${c}).`),u!==void 0&&c>u&&a.push(`${t} = ${c} is unusually high (max ${u}).`)}for(const t of["typeRatio","spaceRatio"])if(t in o)if(typeof o[t]!="number"||!isFinite(o[t]))e.push(`${t} must be a finite number.`);else{const s=o[t];s<=1&&e.push(`${t} must be > 1 (got ${s}).`);const u=t==="typeRatio"?1.3:2;s>u&&a.push(`${t} = ${s} is very high (max ${u}); scales may be extreme.`)}if("viewportMin"in o&&"viewportMax"in o){const t=o.viewportMin,s=o.viewportMax;typeof t=="number"&&typeof s=="number"&&t>=s&&e.push(`viewportMin (${t}) must be less than viewportMax (${s}).`)}if("angles"in o)if(typeof o.angles!="object"||o.angles===null)e.push("angles must be an object.");else{const t=o.angles;for(const s of["analogous","complementary","splitComplementary","triadic"])if(s in t)if(typeof t[s]!="number"||!isFinite(t[s]))e.push(`angles.${s} must be a finite number.`);else{const u=t[s];(u<0||u>360)&&a.push(`angles.${s} = ${u} is outside 0\u2013360.`)}}if("semanticHues"in o)if(typeof o.semanticHues!="object"||o.semanticHues===null)e.push("semanticHues must be an object.");else{const t=o.semanticHues;for(const s of["danger","success","warning"])if(s in t)if(typeof t[s]!="number"||!isFinite(t[s]))e.push(`semanticHues.${s} must be a finite number.`);else{const u=t[s];(u<0||u>360)&&a.push(`semanticHues.${s} = ${u} is outside 0\u2013360.`)}}if("variantChroma"in o)if(typeof o.variantChroma!="object"||o.variantChroma===null)e.push("variantChroma must be an object.");else{const t=o.variantChroma;for(const s of Be)if(s in t)if(typeof t[s]!="number"||!isFinite(t[s]))e.push(`variantChroma["${s}"] must be a finite number.`);else{const u=t[s];u<0&&e.push(`variantChroma["${s}"] must be \u2265 0 (got ${u}).`),u>T&&a.push(`variantChroma["${s}"] = ${u} exceeds ${T}.`)}}function b(t,s){if(typeof t!="object"||t===null||Array.isArray(t)){e.push(`${s} must be an object.`);return}const u=t;for(const c of j)if(c in u)if(typeof u[c]!="number"||!isFinite(u[c]))e.push(`${s}.${c} must be a finite number.`);else{const f=u[c];(f<0||f>1)&&e.push(`${s}.${c} must be 0\u20131 (got ${f}).`)}}if("lightness"in o&&b(o.lightness,"lightness"),"chroma"in o)if(typeof o.chroma!="object"||o.chroma===null)e.push("chroma must be an object.");else{const t=o.chroma;for(const s of z)if(s in t){const u=t[s];if(typeof u!="object"||u===null){e.push(`chroma.${s} must be { min, max }.`);continue}const c=u;(typeof c.min!="number"||c.min<0)&&e.push(`chroma.${s}.min must be \u2265 0.`),(typeof c.max!="number"||c.max<0||c.max>T)&&e.push(`chroma.${s}.max must be 0\u2013${T}.`),typeof c.min=="number"&&typeof c.max=="number"&&c.min>c.max&&e.push(`chroma.${s}.min (${c.min}) must be \u2264 max (${c.max}).`)}}if("anchors"in o)if(typeof o.anchors!="object"||o.anchors===null||Array.isArray(o.anchors))e.push("anchors must be an object of named colors.");else for(const[t,s]of Object.entries(o.anchors))if(g(t)?A.test(t)||e.push(`anchors: "${t}" is not a valid anchor name; use a lowercase slug (letters, digits, hyphens).`):e.push(`anchors: "${t}" is a reserved JavaScript property name and cannot be an anchor name; rename it.`),K.includes(t)&&e.push(`anchors: "${t}" collides with a reserved color source name.`),typeof s=="string")M(s)||e.push(`anchors.${t} is not a valid CSS color: "${s}". Accepted forms: ${w}.`);else if(typeof s=="object"&&s!==null&&!Array.isArray(s)){const u=s;typeof u.color!="string"&&e.push(`anchors.${t} must declare its base "color".`);for(const[c,f]of Object.entries(u))g(c)?c!=="color"&&!A.test(c)&&e.push(`anchors.${t}: "${c}" is not a valid slot name; use a lowercase slug.`):e.push(`anchors.${t}: "${c}" is a reserved JavaScript property name and cannot be a slot name; rename it.`),typeof f!="string"?e.push(`anchors.${t}.${c} must be a CSS color string.`):M(f)||e.push(`anchors.${t}.${c} is not a valid CSS color: "${f}". Accepted forms: ${w}.`)}else e.push(`anchors.${t} must be a color string or a { color, \u2026slots } object.`);const h=new Map;if("anchors"in o&&typeof o.anchors=="object"&&o.anchors!==null&&!Array.isArray(o.anchors))for(const[t,s]of Object.entries(o.anchors))h.set(t,s);function $(t,s){const u=Z(t);if(!u){e.push(`${s} "${t}" is not valid anchor syntax; use anchor:<name> or anchor:<name>.<slot>.`);return}if(!h.has(u.name)){const c=[...h.keys()];e.push(`${s} references undeclared anchor "${u.name}". Declared anchors: ${c.length>0?c.join(", "):"(none)"}.`);return}if(u.slot!==void 0){const c=h.get(u.name);if(typeof(typeof c=="object"&&c!==null&&!Array.isArray(c)?c[u.slot]:void 0)!="string"){const d=typeof c=="object"&&c!==null?Object.keys(c).filter(C=>C!=="color"):[];e.push(`${s} references unknown slot "${u.slot}" on anchor "${u.name}". Declared slots: ${d.length>0?d.join(", "):"(none)"}.`)}}}function R(t,s){if(t.startsWith("anchor:")){$(t,s);return}K.includes(t)||e.push(`${s} must be one of: ${K.join(", ")}, or a declared anchor as anchor:<name> / anchor:<name>.<slot>.`)}function S(t,s){if(t.startsWith("anchor:")){$(t,s);return}M(t)||e.push(`${s} is not a valid CSS color: "${t}". Accepted forms: ${w}, or a declared anchor as anchor:<name> / anchor:<name>.<slot>.`)}if("dataPalette"in o)if(typeof o.dataPalette!="object"||o.dataPalette===null||Array.isArray(o.dataPalette))e.push("dataPalette must be an object with series1\u2013series8 color values.");else{const t=o.dataPalette;for(const[s,u]of Object.entries(t)){if(!I.includes(s)){e.push(`dataPalette.${s} is not a series slot; expected one of: ${I.join(", ")}.`);continue}typeof u!="string"?e.push(`dataPalette.${s} must be a CSS color or anchor reference string.`):S(u,`dataPalette.${s}`)}}if("dataRamps"in o)if(typeof o.dataRamps!="object"||o.dataRamps===null||Array.isArray(o.dataRamps))e.push("dataRamps must be an object of named ramp declarations.");else for(const[t,s]of Object.entries(o.dataRamps)){if(g(t)?A.test(t)||e.push(`dataRamps: "${t}" is not a valid ramp name; use a lowercase slug (letters, digits, hyphens).`):e.push(`dataRamps: "${t}" is a reserved JavaScript property name and cannot be a ramp name; rename it.`),typeof s!="object"||s===null||Array.isArray(s)){e.push(`dataRamps.${t} must be a sequential or diverging ramp object.`);continue}const u=s,c=u.steps??je;if((typeof c!="number"||!Number.isInteger(c)||c<W||c>F)&&e.push(`dataRamps.${t}.steps must be an integer from ${W} through ${F}.`),u.type==="sequential"){typeof u.source!="string"?e.push(`dataRamps.${t}.source must be a CSS color or anchor reference string.`):S(u.source,`dataRamps.${t}.source`);const f=u.lightnessStart??.95,d=u.lightnessEnd??.25;for(const[C,y]of[["lightnessStart",f],["lightnessEnd",d]])(typeof y!="number"||!Number.isFinite(y)||y<0||y>1)&&e.push(`dataRamps.${t}.${C} must be a finite number from 0 through 1.`);typeof f=="number"&&typeof d=="number"&&f<=d?e.push(`dataRamps.${t}.lightnessStart must be greater than lightnessEnd.`):typeof f=="number"&&Number.isFinite(f)&&typeof d=="number"&&Number.isFinite(d)&&typeof c=="number"&&Number.isInteger(c)&&c>=W&&c<=F&&(f-d)/(c-1)<=X&&e.push(`dataRamps.${t} lightness bounds must leave more than ${X} lightness between serialized stops.`);continue}if(u.type==="diverging"){typeof c=="number"&&Number.isInteger(c)&&c%2===0&&e.push(`dataRamps.${t}.steps must be odd so the neutral is the exact midpoint.`);for(const f of["start","end"])typeof u[f]!="string"?e.push(`dataRamps.${t}.${f} must be a CSS color or anchor reference string.`):S(u[f],`dataRamps.${t}.${f}`);"neutral"in u&&(typeof u.neutral!="string"?e.push(`dataRamps.${t}.neutral must be a CSS color or anchor reference string.`):S(u.neutral,`dataRamps.${t}.neutral`));continue}e.push(`dataRamps.${t}.type must be "sequential" or "diverging".`)}if("dataPalette"in o&&e.length===0){const t=ze(se,o),s={};let u=!0;for(const c of I){const f=Oe(t.dataPalette[c],t.anchors);if(!f){u=!1;break}s[c]=f}if(u)for(const c of Ae(s))a.push(`dataPalette.${c.series[0]} and dataPalette.${c.series[1]} are only ${c.distance.toFixed(4)} apart under ${c.simulation} simulation (minimum ${c.threshold.toFixed(4)}); also distinguish the series with labels, shapes, or patterns.`)}function O(t,s){if(typeof t!="object"||t===null||Array.isArray(t)){e.push(`${s} must be an object.`);return}const u=t;for(const[c,f]of Object.entries(u)){const d=`${s}.${c}`;if(!P.includes(c)){e.push(`${d} is not a role; expected one of: ${P.join(", ")}. (The status family is reserved and is not a role.)`);continue}const C=c,y=Q[C];if(typeof f=="string"){R(f,d);continue}if(typeof f!="object"||f===null||Array.isArray(f)){e.push(`${d} must be a color source or a { color, \u2026slots } object.`);continue}const x=f;typeof x.color!="string"&&e.push(`${d} must declare its base "color".`);for(const[k,q]of Object.entries(x)){if(!Object.prototype.hasOwnProperty.call(y,k)||!g(k)){const Y=Object.keys(y).filter(ge=>ge!=="color");e.push(`${d}.${k} is not a slot of the ${C} role. Declared slots: ${Y.length>0?Y.join(", "):"(none)"}.`);continue}typeof q!="string"?e.push(`${d}.${k} must be a color source string.`):R(q,`${d}.${k}`)}}}if("roles"in o&&O(o.roles,"roles"),"contexts"in o)if(typeof o.contexts!="object"||o.contexts===null||Array.isArray(o.contexts))e.push("contexts must be an object.");else for(const[t,s]of Object.entries(o.contexts)){if(!g(t)||!A.test(t)){e.push(`contexts.${t} must be a lowercase slug matching ${A.source}.`);continue}if(typeof s!="object"||s===null||Array.isArray(s)){O(s,`contexts.${t}`);continue}const u=s,c=Object.fromEntries(Object.entries(u).filter(([f])=>f!=="lightness"));O(c,`contexts.${t}`),"lightness"in u&&b(u.lightness,`contexts.${t}.lightness`)}if("semanticMappings"in o)if(typeof o.semanticMappings!="object"||o.semanticMappings===null)e.push("semanticMappings must be an object.");else{const t=o.semanticMappings;for(const s of z)if(s in t){const u=t[s];if(typeof u!="object"||u===null){e.push(`semanticMappings.${s} must be { source, lightness }.`);continue}const c=u;typeof c.source!="string"?e.push(`semanticMappings.${s}.source must be a string.`):R(c.source,`semanticMappings.${s}.source`),(typeof c.lightness!="string"||!j.includes(c.lightness))&&e.push(`semanticMappings.${s}.lightness must be one of: ${j.join(", ")}.`)}}for(const t of["pageBackgroundImage","boxBackgroundImage","vellumBackgroundImage"])t in o&&typeof o[t]!="string"&&e.push(`${t} must be a string.`);for(const t of["pageBackgroundImageOpacity","boxBackgroundImageOpacity","vellumOpacity","vellumBackgroundImageOpacity"])if(t in o)if(typeof o[t]!="number"||!isFinite(o[t]))e.push(`${t} must be a finite number.`);else{const s=o[t];(s<0||s>1)&&e.push(`${t} must be 0\u20131 (got ${s}).`)}return{valid:e.length===0,errors:e,warnings:a}}function Ye(n,e){const a=fe(n),r=fe(e),i=[...a.errors.map(l=>`light: ${l}`),...r.errors.map(l=>`dark: ${l}`)],o=[...a.warnings.map(l=>`light: ${l}`),...r.warnings.map(l=>`dark: ${l}`)];if(a.valid&&r.valid){const l=new Set(Object.keys(V(n)?.contexts??{})),p=new Set(Object.keys(V(e)?.contexts??{})),m=[...p].filter(h=>!l.has(h)).sort(),b=[...l].filter(h=>!p.has(h)).sort();(m.length>0||b.length>0)&&i.push(`contexts must declare the same names in both schemes. Missing from light: ${m.join(", ")||"(none)"}. Missing from dark: ${b.join(", ")||"(none)"}.`)}return{valid:i.length===0,errors:i,warnings:o}}const Ke=["anchors","angles","contexts","dataPalette","dataRamps","roles","chroma","lightness","semanticHues","semanticMappings","variantChroma"];function Ue(n,e){const a={};for(const[r,i]of Object.entries(n))g(r)&&(a[r]=i);for(const[r,i]of Object.entries(e))i!==void 0&&g(r)&&(a[r]=i);for(const r of Ke){const i=n[r],o=e[r];if(i&&typeof i=="object"&&!Array.isArray(i)&&o&&typeof o=="object"&&!Array.isArray(o)){if(r==="anchors"){a[r]=ae(i,o);continue}if(r==="contexts"){a[r]=Le(i,o);continue}if(r==="dataRamps"){a[r]=ue(i,o);continue}const l={};for(const[p,m]of Object.entries(i))g(p)&&(l[p]=m);for(const[p,m]of Object.entries(o))m!==void 0&&g(p)&&(l[p]=m);a[r]=l}}return a}function Xe(...n){let e={};for(const a of n){if(!a)continue;const r=V(a);r&&(e=Ue(e,r))}return J(e)}function pe(n){return n.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r")}const me={borderRadius:.1,fontBody:'"Noto Sans", sans-serif',fontWeightBody:"normal",fontHeadings:'"Inika", serif',fontWeightHeadings:"normal",fontBrand:'"Inika", serif',fontWeightBrand:"normal",fontMonospace:'"JetBrains Mono", monospace',fontWeightMonospace:"normal",seedColor:"oklch(.07 0.15 216)"};function Ze(n){return J({...me,pageBackgroundImage:`url("${pe(n)}")`,pageBackgroundImageOpacity:.5})}function Qe(n){return J({...me,pageBackgroundImage:`url("${pe(n)}")`,pageBackgroundImageOpacity:.55})}export{A as ANCHOR_SLUG_PATTERN,K as COLOR_SOURCES,we as DEFAULT_DARK_LIGHTNESS,Ie as DEFAULT_DARK_THEME,_e as DEFAULT_LIGHT_LIGHTNESS,se as DEFAULT_LIGHT_THEME,U as DEFAULT_SEMANTIC_MAPPINGS,j as LIGHTNESS_KEYS,Ke as NESTED_THEME_KEYS,P as ROLE_NAMES,ve as ROLE_PAIRED_INK,Q as ROLE_TOKEN_PLAN,z as SEMANTIC_COLOR_NAMES,ne as TOKEN_PAIRINGS,Be as VARIANT_COLOR_SOURCES,Qe as buildTaprootDarkTheme,Ze as buildTaprootLightTheme,te as compileRoles,J as encodeTheme,Xe as layerThemes,Ue as mergePartials,ze as mergeTheme,Z as parseAnchorSource,V as parseTheme,Re as resolveAnchorColor,Oe as resolveDataColorSource,qe as semanticToCSS,fe as validateTheme,Ye as validateThemePair};
@@ -9,6 +9,38 @@
9
9
  "name": "--esp-seed-color",
10
10
  "description": "The OKLCH seed color string that drives the entire palette."
11
11
  },
12
+ {
13
+ "name": "--esp-color-series-1",
14
+ "description": "First categorical data-series color."
15
+ },
16
+ {
17
+ "name": "--esp-color-series-2",
18
+ "description": "Second categorical data-series color."
19
+ },
20
+ {
21
+ "name": "--esp-color-series-3",
22
+ "description": "Third categorical data-series color."
23
+ },
24
+ {
25
+ "name": "--esp-color-series-4",
26
+ "description": "Fourth categorical data-series color."
27
+ },
28
+ {
29
+ "name": "--esp-color-series-5",
30
+ "description": "Fifth categorical data-series color."
31
+ },
32
+ {
33
+ "name": "--esp-color-series-6",
34
+ "description": "Sixth categorical data-series color."
35
+ },
36
+ {
37
+ "name": "--esp-color-series-7",
38
+ "description": "Seventh categorical data-series color."
39
+ },
40
+ {
41
+ "name": "--esp-color-series-8",
42
+ "description": "Eighth categorical data-series color."
43
+ },
12
44
 
13
45
  {
14
46
  "name": "--esp-color-primary",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": 1,
2
+ "version": 2,
3
3
  "tokens": [
4
4
  {
5
5
  "name": "--esp-action-menu-background",
@@ -331,6 +331,46 @@
331
331
  "category": "root-theme",
332
332
  "description": ""
333
333
  },
334
+ {
335
+ "name": "--esp-color-series-1",
336
+ "category": "root-theme",
337
+ "description": "First categorical data-series color."
338
+ },
339
+ {
340
+ "name": "--esp-color-series-2",
341
+ "category": "root-theme",
342
+ "description": "Second categorical data-series color."
343
+ },
344
+ {
345
+ "name": "--esp-color-series-3",
346
+ "category": "root-theme",
347
+ "description": "Third categorical data-series color."
348
+ },
349
+ {
350
+ "name": "--esp-color-series-4",
351
+ "category": "root-theme",
352
+ "description": "Fourth categorical data-series color."
353
+ },
354
+ {
355
+ "name": "--esp-color-series-5",
356
+ "category": "root-theme",
357
+ "description": "Fifth categorical data-series color."
358
+ },
359
+ {
360
+ "name": "--esp-color-series-6",
361
+ "category": "root-theme",
362
+ "description": "Sixth categorical data-series color."
363
+ },
364
+ {
365
+ "name": "--esp-color-series-7",
366
+ "category": "root-theme",
367
+ "description": "Seventh categorical data-series color."
368
+ },
369
+ {
370
+ "name": "--esp-color-series-8",
371
+ "category": "root-theme",
372
+ "description": "Eighth categorical data-series color."
373
+ },
334
374
  {
335
375
  "name": "--esp-color-shadow",
336
376
  "category": "root-theme",
@@ -2455,5 +2495,13 @@
2455
2495
  "category": "root-theme",
2456
2496
  "description": ""
2457
2497
  }
2498
+ ],
2499
+ "patterns": [
2500
+ {
2501
+ "template": "--esp-color-ramp-<name>-<step>",
2502
+ "pattern": "^--esp-color-ramp-[a-z][a-z0-9-]*-(?:[1-9]|1[01])$",
2503
+ "category": "root-theme",
2504
+ "description": "A generated data-ramp stop. <name> is a declared dataRamps slug and <step> is 1 through that ramp's configured step count (maximum 11)."
2505
+ }
2458
2506
  ]
2459
2507
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taprootio/espalier",
3
- "version": "2.18.0",
3
+ "version": "2.20.0",
4
4
  "packageManager": "bun@1.3.12",
5
5
  "description": "Espalier — a themeable, accessible, framework-agnostic, enterprise-grade design system built on web standards and love.",
6
6
  "customElements": "custom-elements.json",
@@ -266,6 +266,10 @@
266
266
  "types": "./dist/shared/theme.d.ts",
267
267
  "import": "./dist/shared/theme.js"
268
268
  },
269
+ "./shared/data-colors": {
270
+ "types": "./dist/shared/data-colors.d.ts",
271
+ "import": "./dist/shared/data-colors.js"
272
+ },
269
273
  "./shared/font-helpers": {
270
274
  "types": "./dist/shared/font-helpers.d.ts",
271
275
  "import": "./dist/shared/font-helpers.js"