@frontfriend/sdk 0.0.0-stage → 1.1.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.
Files changed (69) hide show
  1. package/LICENSE +46 -0
  2. package/README.md +352 -2
  3. package/dist/THIRD_PARTY_NOTICES +44 -0
  4. package/dist/application-adoption-lock.d.ts +31 -0
  5. package/dist/application-adoption.d.ts +103 -0
  6. package/dist/browser.mjs +1 -0
  7. package/dist/cli.js +372 -0
  8. package/dist/cn.d.ts +2 -0
  9. package/dist/cn.js +1 -0
  10. package/dist/cn.mjs +1 -0
  11. package/dist/component-config.d.ts +330 -0
  12. package/dist/component-config.mjs +1 -0
  13. package/dist/component-recipes.d.ts +29 -0
  14. package/dist/components-config-schema.d.ts +2 -0
  15. package/dist/components-config-schema.js +1 -0
  16. package/dist/ffdc.d.ts +17 -0
  17. package/dist/ffdc.js +1 -0
  18. package/dist/ffdc.mjs +1 -0
  19. package/dist/foundation-contract.json +56 -0
  20. package/dist/index.js +1 -0
  21. package/dist/index.mjs +1 -0
  22. package/dist/lib/core/adoption.js +1 -0
  23. package/dist/lib/core/api-client.js +10 -0
  24. package/dist/lib/core/application-adoption-lock.js +6 -0
  25. package/dist/lib/core/application-adoption.js +28 -0
  26. package/dist/lib/core/cache-manager.js +1 -0
  27. package/dist/lib/core/cached-components-config.js +1 -0
  28. package/dist/lib/core/classes-source.js +1 -0
  29. package/dist/lib/core/component-config.js +1 -0
  30. package/dist/lib/core/component-recipes.js +8 -0
  31. package/dist/lib/core/components-config-schema.js +1 -0
  32. package/dist/lib/core/config-loader.js +1 -0
  33. package/dist/lib/core/constants.js +1 -0
  34. package/dist/lib/core/credentials.js +2 -0
  35. package/dist/lib/core/env-utils.js +2 -0
  36. package/dist/lib/core/errors.js +1 -0
  37. package/dist/lib/core/file-utils.js +2 -0
  38. package/dist/lib/core/nativeSource.d.ts +10 -0
  39. package/dist/lib/core/nativeSource.js +2 -0
  40. package/dist/lib/core/package-identity.js +1 -0
  41. package/dist/lib/core/path-utils.js +2 -0
  42. package/dist/lib/core/project-target.js +1 -0
  43. package/dist/lib/core/static-config.js +9 -0
  44. package/dist/lib/core/token-artifact-client.js +8 -0
  45. package/dist/lib/core/token-artifact.d.ts +39 -0
  46. package/dist/lib/core/token-artifact.js +1 -0
  47. package/dist/lib/core/token-processor.d.ts +23 -0
  48. package/dist/lib/core/token-processor.js +5 -0
  49. package/dist/lib/react/utils.d.ts +25 -0
  50. package/dist/lib/react/utils.mjs +1 -0
  51. package/dist/lib/vue/utils.d.ts +27 -0
  52. package/dist/lib/vue/utils.mjs +1 -0
  53. package/dist/mcp.cjs +226 -0
  54. package/dist/next.d.ts +11 -0
  55. package/dist/next.js +2 -0
  56. package/dist/next.mjs +1 -0
  57. package/dist/package.json +4 -0
  58. package/dist/project-target.d.ts +22 -0
  59. package/dist/runtime.d.ts +15 -0
  60. package/dist/runtime.js +1 -0
  61. package/dist/runtime.mjs +1 -0
  62. package/dist/scripts/generate-icon-types.js +38 -0
  63. package/dist/theme.css +3 -0
  64. package/dist/types/index.d.ts +68 -0
  65. package/dist/vite.d.mts +9 -0
  66. package/dist/vite.d.ts +8 -0
  67. package/dist/vite.js +9 -0
  68. package/dist/vite.mjs +1 -0
  69. package/package.json +202 -3
@@ -0,0 +1 @@
1
+ const{createHash,createPublicKey,sign,verify}=require("node:crypto"),{assertComponentsConfig}=require("./cached-components-config"),MAX_ARTIFACT_BYTES=16*1024*1024;function tokenApiOrigin(r){const e=new URL(r).origin;return e==="https://app.v4.frontfriend.dev"?"https://app.frontfriend.dev":e}function digest(r){return createHash("sha256").update(r).digest("hex")}function segment(r){if(typeof r!="string"||!/^[a-zA-Z0-9_-][a-zA-Z0-9_.-]{0,199}$/.test(r))throw new Error("Invalid token artifact identity.");return r}function prefix(r){return`sdk/1/${segment(r)}`}function releaseKey(r,e){return`${prefix(r)}/releases/${segment(e)}.json`}function tagKey(r,e){return`${prefix(r)}/tags/${segment(e)}.json`}function assertPayload(r,e){if(!r||typeof r!="object"||Array.isArray(r))throw new Error("Invalid token payload.");if(e==="shadcn"){if(r.base!=="shadcn"||!r.nativeTokens||typeof r.nativeCss!="string"||!r.nativeCss.trim())throw new Error("The selected Release has no native shadcn token artifact.")}else if(e==="frontfriend"){assertComponentsConfig(r.componentsConfig);for(const n of["tokens","variables","semanticVariables","semanticDarkVariables"])if(!r[n]||typeof r[n]!="object"||Array.isArray(r[n]))throw new Error(`Missing token field: ${n}.`)}else throw new Error("Unsupported token base library.")}function assertManifest(r,e={}){if(!r||r.schemaVersion!==1||r.runtime!=="sdk"||r.colorFormat!=="oklch"||!["frontfriend","shadcn"].includes(r.baseLibrary)||!/^[a-f0-9]{64}$/.test(r.digest)||!Number.isSafeInteger(r.bytes)||r.bytes<=0||r.bytes>MAX_ARTIFACT_BYTES||!Number.isFinite(Date.parse(r.publishedAt))||typeof r.processorVersion!="string")throw new Error("Invalid token manifest.");if(segment(r.ffId),segment(r.releaseId),segment(r.tokenVersionId),new URL(r.apiOrigin).origin!==r.apiOrigin)throw new Error("Invalid token API origin.");if(r.artifactKey!==`${prefix(r.ffId)}/artifacts/${r.digest}.json`)throw new Error("Invalid token artifact path.");for(const n of["apiOrigin","ffId","releaseId","tokenVersionId","baseLibrary"]){const o=n==="apiOrigin"&&e[n]?tokenApiOrigin(e[n]):e[n];if(o&&r[n]!==o)throw new Error(`Token manifest does not match ${n}.`)}return r}function validateArtifact(r,e,n){if(assertManifest(r,n),e.length!==r.bytes||digest(e)!==r.digest)throw new Error("Token artifact digest or size mismatch.");const o=JSON.parse(e.toString("utf8"));if(assertPayload(o,r.baseLibrary),o.metadata?.ffId!==r.ffId)throw new Error("Token payload belongs to another Design System.");return o}function makeArtifact(r,e){assertPayload(e,r.baseLibrary);const n=Buffer.from(JSON.stringify(e)),o=digest(n),t={schemaVersion:1,runtime:"sdk",colorFormat:"oklch",apiOrigin:tokenApiOrigin(r.apiOrigin),ffId:r.ffId,releaseId:r.releaseId,tokenVersionId:r.tokenVersionId,baseLibrary:r.baseLibrary,processorVersion:r.processorVersion,publishedAt:r.publishedAt,digest:o,bytes:n.length,artifactKey:`${prefix(r.ffId)}/artifacts/${o}.json`};return validateArtifact(t,n),{manifest:t,bytes:n}}const OFFLINE_LICENSE_KEYS={"https://app.frontfriend.dev":"MCowBQYDK2VwAyEAQNi4QA/eGZeq4jNgL4HfvlzuF6pTTOjsJYWYOmT9RMc=","https://app.dev.frontfriend.dev":"MCowBQYDK2VwAyEAEFTW/bfHgmUqTT1D12GkWv5uvDvo/Xl4+rbFrUTWy90="};function signOfflineLicense(r,e){const n=Buffer.from(JSON.stringify({schemaVersion:1,capability:"tokens.offline",...r,apiOrigin:tokenApiOrigin(r.apiOrigin)}));return{payload:n.toString("base64"),signature:sign(null,n,e).toString("base64")}}function offlineLicenseKey(r,e,n){if(e[r])return e[r];const{hostname:o}=new URL(r);return["localhost","127.0.0.1","[::1]"].includes(o)?n.FF_OFFLINE_LICENSE_LOCAL_KEY:void 0}function verifyOfflineLicense(r,e,n=OFFLINE_LICENSE_KEYS,o=process.env){const t=tokenApiOrigin(e.apiOrigin),s=offlineLicenseKey(t,n,o);if(!s)throw new Error("This Frontfriend platform issues no offline licenses.");if(typeof r?.payload!="string"||typeof r?.signature!="string")throw new Error("Malformed offline license.");const f=Buffer.from(r.payload,"base64"),a=createPublicKey({key:Buffer.from(s,"base64"),format:"der",type:"spki"});if(!verify(null,f,a,Buffer.from(r.signature,"base64")))throw new Error("The offline license signature is invalid.");const i=JSON.parse(f.toString("utf8"));if(i.schemaVersion!==1||i.capability!=="tokens.offline"||i.ffId!==e.ffId||i.apiOrigin!==t)throw new Error("The offline license belongs to another Design System or platform.");return i}module.exports={OFFLINE_LICENSE_KEYS,signOfflineLicense,verifyOfflineLicense,tokenApiOrigin,MAX_ARTIFACT_BYTES,digest,segment,prefix,releaseKey,tagKey,assertManifest,validateArtifact,makeArtifact};
@@ -0,0 +1,23 @@
1
+ export = TokenProcessor;
2
+ declare class TokenProcessor {
3
+ constructor(config?: {});
4
+ config: {};
5
+ hexToOklch(colorValue: string): string;
6
+ processColors(colorsData: any): any;
7
+ processSemanticTokens(semanticData: any, colorMap: any): any;
8
+ fetchFontCss(url: string, { timeoutMs }?: {
9
+ timeoutMs?: number;
10
+ }): Promise<string>;
11
+ parseFontFaces(css: string): any[];
12
+ processFonts(fontData: any): Promise<any[]>;
13
+ processFontFamilies(globalTokens: any): any;
14
+ processAnimations(animationData: any): any;
15
+ generateSafelistClasses(tokens: any): any[];
16
+ extractClassesFromComponentsConfig(componentsConfig: any): any[];
17
+ generateClassesContent(classes?: Array<string>): string;
18
+ processCustomCss(css: string): any;
19
+ process(data: any): Promise<any>;
20
+ buildSemanticColorNamespaces(tokenGroups: any): Array<string>;
21
+ generateThemeCSSFromProcessedTokens(processedTokens: any): string;
22
+ generateThemeCSS(processedData: any): string;
23
+ }
@@ -0,0 +1,5 @@
1
+ var C=(l,e)=>()=>(e||l((e={exports:{}}).exports,e),e.exports);var _=C((Ce,R)=>{var m=require("fs");function Z(l){try{let e=m.readFileSync(l,"utf8");return JSON.parse(e)}catch(e){if(e.code==="ENOENT")return null;throw e}}function Q(l){try{return m.readFileSync(l,"utf8").replace(/^\uFEFF/,"")}catch(e){if(e.code==="ENOENT")return null;throw e}}function Y(l,e,t=2){let o=JSON.stringify(e,null,t);m.writeFileSync(l,o,"utf8")}function D(l,e){m.writeFileSync(l,e,"utf8")}function ee(l,e){if(e==null||typeof e=="object"&&Object.keys(e).length===0||Array.isArray(e)&&e.length===0){let o=`module.exports = ${Array.isArray(e)?"[]":"{}"};`;m.writeFileSync(l,o,"utf8")}else{let t=`module.exports = ${JSON.stringify(e,null,2)};`;m.writeFileSync(l,t,"utf8")}}function te(l){return m.existsSync(l)}function re(l){m.mkdirSync(l,{recursive:!0})}function oe(l){m.rmSync(l,{recursive:!0,force:!0})}function se(l){m.rmSync(l,{force:!0})}function ne(l,e){m.mkdirSync(require("path").dirname(l),{recursive:!0,mode:448});let t=`${l}.${process.pid}.${Date.now()}.tmp`;try{m.writeFileSync(t,`${JSON.stringify(e,null,2)}
2
+ `,{mode:384}),m.renameSync(t,l);try{m.chmodSync(l,384)}catch{}}finally{m.rmSync(t,{force:!0})}}async function ie(l,e,t){m.mkdirSync(require("path").dirname(l),{recursive:!0,mode:448});let o=`${l}.lock`,n=Date.now()+2e4,c;for(;c===void 0;)try{c=m.openSync(o,"wx",384),m.writeFileSync(c,String(process.pid))}catch(f){if(f.code!=="EEXIST")throw f;try{let r=Number(m.readFileSync(o,"utf8"));if(Number.isInteger(r)&&r>0)try{process.kill(r,0)}catch(s){if(s.code==="ESRCH"){m.unlinkSync(o);continue}}}catch(r){if(r.code==="ENOENT")continue}if(Date.now()>=n)throw t();await new Promise(r=>setTimeout(r,50))}try{return await e()}finally{m.closeSync(c),m.unlinkSync(o)}}R.exports={writePrivateJsonFileAtomic:ne,withPrivateFileLock:ie,readJsonFileSafe:Z,readFileSafe:Q,writeJsonFile:Y,writeTextFile:D,writeModuleExportsFile:ee,fileExists:te,ensureDirectoryExists:re,removeDirectory:oe,removeFile:se}});var I=C((Se,L)=>{var x=class extends Error{constructor(e,t,o){super(e),this.name="APIError",this.statusCode=t,this.url=o,this.code=`API_${t}`}},w=class extends Error{constructor(e,t){super(e),this.name="CacheError",this.operation=t,this.code=`CACHE_${t.toUpperCase()}`}},F=class extends Error{constructor(e,t){super(e),this.name="ConfigError",this.field=t,this.code=t?`CONFIG_${String(t).toUpperCase()}`:"CONFIG_ERROR"}},O=class extends Error{constructor(e,t){super(e),this.name="ProcessingError",this.token=t,this.code="PROCESSING_ERROR"}};L.exports={APIError:x,CacheError:w,ConfigError:F,ProcessingError:O}});var U=C((xe,K)=>{var M=["open","closed","checked","unchecked","indeterminate","active"],W={open:['[data-expanded]:not([data-expanded="false"])','[data-popup-open]:not([data-popup-open="false"])','[data-panel-open]:not([data-panel-open="false"])']},P="on",q=["/* Dark mode follows the root class the theme picker toggles. */","@custom-variant dark {"," &:is(.dark, .dark *) {"," @slot;"," }","}",""],E=[...q,"/* Cross-primitive state variants (Radix `data-state=x`, Base UI `data-x`). */",...M.flatMap(l=>{let e=[`[data-state="${l}"]`,`[data-${l}]:not([data-${l}="false"])`,...W[l]||[]];return[`@custom-variant data-${l} {`,...e.map((t,o)=>` &:where(${t})${o===e.length-1?" {":","}`)," @slot;"," }","}",""]}),`@custom-variant data-${P} {`,' &:where([data-state="on"]),',' &:where([aria-pressed="true"]) {'," @slot;"," }","}","","@custom-variant data-selected {",' &:where([data-selected="true"]) {'," @slot;"," }","}","","@custom-variant data-disabled {",' &:where([data-disabled="true"]),',' &:where([data-disabled]:not([data-disabled="false"])) {'," @slot;"," }","}","",...["horizontal","vertical"].flatMap(l=>[`@custom-variant data-${l} {`,` &:where([data-orientation="${l}"]) {`," @slot;"," }","}",""])],ae=E.filter(l=>l.startsWith("@custom-variant ")).map(l=>l.slice(16).replace(" {",""));function ce(){return E.join(`
3
+ `)}K.exports={CROSS_PRIMITIVE_STATES:M,DARK_VARIANT_CSS:q,EXTRA_STATE_MATCHERS:W,PRESSED_STATE:P,STATE_VARIANT_CSS:E,STATE_VARIANT_NAMES:ae,stateVariantCss:ce}});var J=C((we,H)=>{var le="classes.txt",fe="classes.css",ue=new Set(["after","backdrop","before","file","first-letter","first-line","marker","placeholder","selection"]);function de(l){if(typeof l!="string")return!0;let e=l.split(":").slice(0,-1);return e.every((t,o)=>!ue.has(t)||o===e.length-1)}H.exports={CLASSES_SOURCE_FILE:le,CSS_CLASSES_SOURCE_FILE:fe,isCompilableClass:de}});var{fileExists:Fe,readJsonFileSafe:Oe}=_(),me=require("color"),he=require("https"),Ee=require("fs"),je=require("path"),{ProcessingError:be}=I(),{STATE_VARIANT_CSS:pe}=U(),{CLASSES_SOURCE_FILE:ye,isCompilableClass:G}=J(),ge={"--background":"oklch(1 0 0)","--foreground":"oklch(0.145 0 0)","--card":"oklch(1 0 0)","--card-foreground":"oklch(0.145 0 0)","--popover":"oklch(1 0 0)","--popover-foreground":"oklch(0.145 0 0)","--primary":"oklch(0.205 0 0)","--primary-foreground":"oklch(0.985 0 0)","--secondary":"oklch(0.97 0 0)","--secondary-foreground":"oklch(0.205 0 0)","--muted":"oklch(0.97 0 0)","--muted-foreground":"oklch(0.556 0 0)","--accent":"oklch(0.97 0 0)","--accent-foreground":"oklch(0.205 0 0)","--destructive":"oklch(0.577 0.245 27.325)","--destructive-foreground":"oklch(0.985 0 0)","--border":"oklch(0.922 0 0)","--input":"oklch(0.922 0 0)","--ring":"oklch(0.708 0 0)","--sidebar":"oklch(0.985 0 0)","--sidebar-foreground":"oklch(0.145 0 0)","--sidebar-primary":"oklch(0.205 0 0)","--sidebar-primary-foreground":"oklch(0.985 0 0)","--sidebar-accent":"oklch(0.97 0 0)","--sidebar-accent-foreground":"oklch(0.205 0 0)","--sidebar-border":"oklch(0.922 0 0)","--sidebar-ring":"oklch(0.708 0 0)","--chart-1":"oklch(0.646 0.222 41.116)","--chart-2":"oklch(0.6 0.118 184.704)","--chart-3":"oklch(0.398 0.07 227.392)","--chart-4":"oklch(0.828 0.189 84.429)","--chart-5":"oklch(0.769 0.188 70.08)"},ve={"--background":["--bg-default","--bg-neutral-low","--layer-base"],"--foreground":["--text-neutral-strong","--text-default"],"--card":["--layer-1","--bg-neutral-low","--bg-default"],"--card-foreground":["--text-neutral-strong","--text-default"],"--popover":["--layer-1","--bg-neutral-low","--bg-default"],"--popover-foreground":["--text-neutral-strong","--text-default"],"--primary":["--bg-brand-mid","--bg-brand-strong"],"--primary-foreground":["--text-onbrand-strong","--text-inverse-low"],"--secondary":["--bg-interactive-subtle","--bg-neutral-low"],"--secondary-foreground":["--text-oninteractive-subtle","--text-neutral-strong"],"--muted":["--bg-neutral-low","--bg-disabled"],"--muted-foreground":["--text-neutral-subtle","--text-disabled"],"--accent":["--bg-interactive-low","--bg-brand-low","--bg-neutral-low"],"--accent-foreground":["--text-oninteractive-low","--text-brand-strong","--text-neutral-strong"],"--destructive":["--bg-negative-mid","--bg-negative-subtle"],"--destructive-foreground":["--text-onnegative-subtle","--text-inverse-low"],"--border":["--border-neutral-subtle","--border-default"],"--input":["--border-neutral-subtle","--border-default"],"--ring":["--border-brand-mid","--bg-brand-mid"],"--sidebar":["--layer-1","--bg-neutral-low","--bg-default"],"--sidebar-foreground":["--text-neutral-strong","--text-default"],"--sidebar-primary":["--bg-brand-mid","--bg-brand-strong"],"--sidebar-primary-foreground":["--text-onbrand-strong","--text-inverse-low"],"--sidebar-accent":["--bg-interactive-low","--bg-neutral-low"],"--sidebar-accent-foreground":["--text-oninteractive-low","--text-neutral-strong"],"--sidebar-border":["--border-neutral-subtle","--border-default"],"--sidebar-ring":["--border-brand-mid","--bg-brand-mid"],"--chart-1":["--bg-brand-mid","--bg-brand-strong"],"--chart-2":["--bg-interactive-mid","--bg-interactive-low"],"--chart-3":["--bg-positive-mid","--bg-positive-subtle"],"--chart-4":["--bg-warning-mid","--bg-warning-subtle"],"--chart-5":["--bg-negative-mid","--bg-negative-subtle"]};function $e(l,e,t){for(let o of e||[])if(l[o])return l[o];return t}function z(l={}){return Object.fromEntries(Object.entries(l?.radius||{}).filter(([,e])=>typeof e?.$value=="string").map(([e,t])=>[e.toLowerCase(),t.$value.replace(/\{([^}]+)\}/g,(o,n)=>`var(--${n.replace(/\./g,"-").toLowerCase()})`)]))}function B(l={},e={}){let t={};for(let[n,c]of Object.entries(ve))t[n]=$e(l,c,ge[n]);let o=e.borderRadius||{};return t["--radius"]=o.default||o.md||o.lg||"0.625rem",t["--radius-sm"]=o.sm||"calc(var(--radius) - 4px)",t["--radius-md"]=o.md||"calc(var(--radius) - 2px)",t["--radius-lg"]=o.lg||"var(--radius)",t["--radius-xl"]=o.xl||"calc(var(--radius) + 4px)",t}var j=class{constructor(e={}){this.config=e}hexToOklch(e){if(typeof e=="string"&&/^oklch\(.*\)$/i.test(e.trim()))return e.trim();try{let t=me(e),o=t.rgb(),n=o.red()/255,c=o.green()/255,f=o.blue()/255,r=k=>k<=.04045?k/12.92:Math.pow((k+.055)/1.055,2.4),s=r(n),i=r(c),a=r(f),d=s*.4124564+i*.3575761+a*.1804375,u=s*.2126729+i*.7151522+a*.072175,h=s*.0193339+i*.119192+a*.9503041,b=Math.cbrt(.8189330101*d+.3618667424*u-.1288597137*h),y=Math.cbrt(.0329845436*d+.9293118715*u+.0361456387*h),p=Math.cbrt(.0482003018*d+.2643662691*u+.633851707*h),g=.2104542553*b+.793617785*y-.0040720468*p,$=1.9779984951*b-2.428592205*y+.4505937099*p,v=.0259040371*b+.7827717662*y-.808675766*p,X=Math.sqrt($*$+v*v),S=Math.atan2(v,$)*180/Math.PI;S<0&&(S+=360);let V=Math.round(g*1e3)/1e3,A=Math.round(X*1e3)/1e3,N=Math.round(S*100)/100,T=t.alpha();if(T<1){let k=Math.round(T*100)/100;return`oklch(${V} ${A} ${N} / ${k})`}return`oklch(${V} ${A} ${N})`}catch(t){throw new be(`Failed to convert color ${e}: ${t.message}`,e)}}processColors(e){let t={},o={},n={backgroundColor:{},textColor:{},borderColor:{}};if(!e||typeof e!="object")return console.log(" \u26A0\uFE0F No valid color data to process"),{variables:t,colorMap:o,utilities:n};let c=(f,r="")=>{for(let[s,i]of Object.entries(f))if(i&&typeof i=="object")if(i.$value){let a=r?`${r}-${s}`:s,d=`--color-${a}`,u=this.hexToOklch(i.$value);t[d]=u,o[a]=d;let h=`var(${d})`;n.backgroundColor[a]=h,n.textColor[a]=h,n.borderColor[a]=h}else{let a=r?`${r}-${s}`:s;c(i,a)}};return e&&(e.colors?c(e.colors):c(e)),{variables:t,colorMap:o,utilities:n}}processSemanticTokens(e,t){let o={},n={backgroundColor:{},textColor:{},borderColor:{}},c=s=>s.replace(/ /g,"").replace(/\./g,"-").toLowerCase(),f=s=>{if(typeof s!="string")return null;let i=s.match(/^\{(.+)\}$/);if(!i)return null;let a=i[1].split(".");return a[0]==="colors"&&a.length>1?a[1]==="colors"&&a.length>2?a.slice(2).join("-"):a.slice(1).join("-"):a.join("-")},r=(s,i)=>{if(e[s])for(let[a,d]of Object.entries(e[s])){if(a==="disabled"){let u=f(d.$value);if(u){let h=t[u];if(h){let b=`--${s}-disabled`;o[b]=`var(${h})`,n[i].disabled=`var(${b})`}}continue}for(let[u,h]of Object.entries(d))for(let[b,y]of Object.entries(h)){let p=c(`${a}-${u}-${b}`);p.endsWith("-default")&&(p=p.slice(0,-8));let g=`--${s}-${p}`,$=f(y.$value);if($){let v=t[$];v&&(o[g]=`var(${v})`,n[i][p]=`var(${g})`)}else if(y.$value){let v=this.hexToOklch(y.$value);o[g]=v,n[i][p]=`var(${g})`}}}};if(r("bg","backgroundColor"),r("text","textColor"),r("border","borderColor"),e.layer)for(let[s,i]of Object.entries(e.layer)){let a=`--layer-${s}`,d=f(i.$value);if(d){let u=d.replace(/\./g,"-").toLowerCase();if(u.endsWith("-default")&&(u=u.slice(0,-8)),u.startsWith("bg-")||u.startsWith("text-")||u.startsWith("border-")){let h=`--${u}`;o[a]=`var(${h})`,n.backgroundColor[`layer-${s}`]=`var(${a})`}else{let h=t[u];h&&(o[a]=`var(${h})`,n.backgroundColor[`layer-${s}`]=`var(${a})`)}}else if(i.$value){let u=this.hexToOklch(i.$value);o[a]=u,n.backgroundColor[`layer-${s}`]=`var(${a})`}}if(e.overlay)for(let[s,i]of Object.entries(e.overlay)){let a=`--overlay-${s}`;i.$value&&(o[a]=i.$value,n.backgroundColor[`overlay-${s}`]=`var(${a})`)}if(e.icon){n.fill||(n.fill={});for(let[s,i]of Object.entries(e.icon)){if(s==="disabled"){let a=f(i.$value);if(a){let d=t[a];if(d){let u="--icon-disabled";o[u]=`var(${d})`,n.textColor["icon-disabled"]=`var(${u})`,n.fill["icon-disabled"]=`var(${u})`}}continue}for(let[a,d]of Object.entries(i))for(let[u,h]of Object.entries(d)){let b=c(`icon-${s}-${a}-${u}`);b.endsWith("-default")&&(b=b.slice(0,-8));let y=`--${b}`,p=f(h.$value);if(p){let g=t[p];g&&(o[y]=`var(${g})`,n.textColor[b]=`var(${y})`,n.fill[b]=`var(${y})`)}}}}return{semanticVariables:o,tokens:n}}async fetchFontCss(e,{timeoutMs:t=1e4}={}){if(!Number.isFinite(t)||t<=0)throw new Error("Font CSS timeout must be positive");return new Promise((o,n)=>{let c,f=setTimeout(()=>{let s=new Error("Font CSS request timed out");n(s),c?.destroy(s)},t);f.unref?.();let r=s=>{clearTimeout(f),n(s)};try{c=he.get(e,s=>{let i="";if(s.on("error",r),s.on("aborted",()=>r(new Error("Font CSS response was interrupted"))),s.statusCode!==200){r(new Error(`Failed to fetch font CSS: ${s.statusCode}`)),s.destroy?.();return}s.on("data",a=>{i+=a}),s.on("end",()=>{clearTimeout(f),o(i)})}),c.on("error",r)}catch(s){r(s)}})}parseFontFaces(e){let t=/@font-face\s*{([^}]+)}/g,o=[],n;for(;(n=t.exec(e))!==null;){let c=n[1].trim().split(";").filter(Boolean),f={};c.forEach(r=>{let s=r.indexOf(":");if(s!==-1){let i=r.slice(0,s).trim(),a=r.slice(s+1).trim();i==="font-family"?f[i]=a.replace(/["']/g,""):f[i]=a}}),f.src&&(f.src=f.src.replace(/url\(["']?/,"url('").replace(/["']?\)/,"')")),o.push(f)}return o}async processFonts(e){let t=[];if(!e||typeof e!="object")return t;let o=Object.keys(e).filter(n=>n.startsWith("font"));for(let n of o){let c=e[n];if(typeof c=="string"&&c.startsWith("http"))try{let f=await this.fetchFontCss(c),r=this.parseFontFaces(f);r.length>0&&t.push(...r)}catch(f){console.warn(`Failed to process font ${n}:`,f.message)}}return t}processFontFamilies(e){let t={};if(!e||!e.font||!e.font.family)return t;let o=e.font.family;for(let[n,c]of Object.entries(o))if(c&&c.$value){let f=n.toLowerCase(),r=c.$value;typeof r=="string"&&r.startsWith("{")&&r.endsWith("}")&&(r=r.slice(1,-1));let s=i=>i.split(" ").map(a=>a.charAt(0).toUpperCase()+a.slice(1).toLowerCase()).join(" ");if(r.includes(","))t[f]=r;else{let i=s(r);i.includes(" ")&&!i.startsWith('"')&&!i.startsWith("'")?t[f]=`"${i}", sans-serif`:t[f]=`${i}, sans-serif`}}return t}processAnimations(e){let t={},o={};if(!e||typeof e!="object")return{keyframes:t,animations:o};for(let[n,c]of Object.entries(e))if(c&&typeof c=="object"){let f=`${n}`;if(c.keyframes){let s={};for(let[i,a]of Object.entries(c.keyframes))a&&typeof a=="object"&&(s[i]=a);t[f]=s}let r=[f,c.duration||"1s",c.easing||"ease",c.delay||"0s",c.iterations||"1",c.direction||"normal",c.fillMode||"none"].join(" ");o[n]=r}return{keyframes:t,animations:o}}generateSafelistClasses(e){let t=[];if(e.backgroundColor)for(let o of Object.keys(e.backgroundColor))t.push(`bg-${o}`);if(e.textColor)for(let o of Object.keys(e.textColor))t.push(`text-${o}`);if(e.borderColor)for(let o of Object.keys(e.borderColor))t.push(`border-${o}`);if(e.fill)for(let o of Object.keys(e.fill))t.push(`fill-${o}`),o.startsWith("icon-")&&t.push(`text-${o}`);if(e.fontFamily)for(let o of Object.keys(e.fontFamily))t.push(`font-${o}`);if(e.animations)for(let o of Object.keys(e.animations))t.push(`animate-${o}`);return t}extractClassesFromComponentsConfig(e){let t=new Set,o=c=>{typeof c=="string"&&c.split(/\s+/).filter(r=>r.length>0).forEach(r=>{t.add(r)})},n=c=>{if(!(!c||typeof c!="object"))for(let f in c){if(f==="icons")continue;let r=c[f];typeof r=="string"?o(r):typeof r=="object"&&n(r)}};return e&&n(e),Array.from(t).filter(G).sort()}generateClassesContent(e=[]){e=e.filter(G);let t=["/*"," * Frontfriend Component Classes"," *"," * This file contains all classes used in Frontfriend component configs."," * Tailwind v4 scans this file via @source to generate utilities."," * DO NOT EDIT - Auto-generated by frontfriend CLI"," */","","/*"," * Classes:"],o=" * ";for(let n of[...new Set(e)].sort())o.length+n.length+1>100?(t.push(o),o=` * ${n}`):o+=(o===" * "?"":" ")+n;return o!==" * "&&t.push(o),t.push(" */"),t.join(`
4
+ `)}processCustomCss(e){return!e||typeof e!="string"?{}:{raw:e}}async process(e){try{let t={variables:{},semanticVariables:{},semanticDarkVariables:{},utilities:{},fontFaces:[],keyframes:{},animations:{},safelist:[],metadata:{},custom:e.customCss?this.processCustomCss(e.customCss):{}},o=e.colors;if(o){let n=this.processColors(o);t.variables={...t.variables,...n.variables},t.utilities={...t.utilities,...n.utilities},t.colorMap=n.colorMap||{}}else t.colorMap={};if(e.semantic&&t.colorMap){let n=this.processSemanticTokens(e.semantic,t.colorMap);t.semanticVariables=n.semanticVariables,n.tokens&&(t.tokens=n.tokens,t.utilities=n.tokens)}if(e.semanticDark&&t.colorMap){let n=this.processSemanticTokens(e.semanticDark,t.colorMap);t.semanticDarkVariables=n.semanticVariables}if(e.fonts&&(t.fontFaces=await this.processFonts(e.fonts)),e.globalTokens){t.fontFamilies=this.processFontFamilies(e.globalTokens);let n=z(e.globalTokens);Object.keys(n).length&&(t.utilities.borderRadius=n),t.fontFamilies&&(t.utilities.fontFamily||(t.utilities.fontFamily={}),Object.assign(t.utilities.fontFamily,t.fontFamilies))}if(e.animations){let n=this.processAnimations(e.animations);t.keyframes=n.keyframes,t.animations=n.animations}return t.safelist=this.generateSafelistClasses(t.tokens||t.utilities),t.metadata={timestamp:new Date().toISOString(),version:e.version||"2.0.0",ffId:e.ffId},t}catch(t){throw console.error("Error processing tokens:",t),t}}buildSemanticColorNamespaces(e){let t=[["","border","--border-"],["layer-","layer","--layer-"],["overlay-","overlay","--overlay-"],["icon-","icon","--icon-"]],o=[["","bg","--bg-"],["layer-","layer","--layer-"],["overlay-","overlay","--overlay-"],["icon-","icon","--icon-"]],c=[{namespace:"--background-color",roles:o},{namespace:"--text-color",roles:[["","text","--text-"],["layer-","layer","--layer-"],["overlay-","overlay","--overlay-"],["icon-","icon","--icon-"]]},{namespace:"--border-color",roles:t},{namespace:"--ring-color",roles:t},{namespace:"--outline-color",roles:t},{namespace:"--stroke",roles:t},{namespace:"--ring-offset-color",roles:o},{namespace:"--fill",roles:o}],f=[];for(let{namespace:r,roles:s}of c)for(let[i,a,d]of s)for(let u of e[a]||[])f.push(` ${r}-${i}${u}: var(${d}${u});`);return f.length===0?[]:["","@theme {",...f,"}"]}generateThemeCSSFromProcessedTokens(e){return this.generateThemeCSS({variables:e.variables||{},semanticVariables:e.semanticVariables||{},semanticDarkVariables:e.semanticDarkVariables||{},fontFamilies:e.tokens?.fontFamily||{},utilities:{borderRadius:z(e.globalTokens)},fontFaces:e.fonts||[],keyframes:e.keyframes||{},animations:e.animations||{},custom:e.custom||{}})}generateThemeCSS(e){let t=['@import "tw-animate-css";',"",...pe,"@theme {"];for(let[r,s]of Object.entries(e.variables||{}))t.push(` ${r}: ${s};`);for(let[r,s]of Object.entries(e.fontFamilies||{})){let i=r.startsWith("--")?r:`--font-${r}`,a=Array.isArray(s)?s.join(", "):s;t.push(` ${i}: ${a};`)}e.fontFamilies?.primary&&!e.fontFamilies.sans&&t.push(" --font-sans: var(--font-primary);");for(let[r,s]of Object.entries(e.utilities?.spacing||{})){let i=r.startsWith("--")?r:`--spacing-${r}`;t.push(` ${i}: ${s};`)}for(let[r,s]of Object.entries(e.utilities?.borderRadius||{})){let i=r.startsWith("--")?r:`--radius-${r}`;t.push(` ${i}: ${s};`)}t.push("}","");let o=e.semanticVariables||{},n=B(o,e.utilities||{});t.push(":root:not(.dark) {");for(let[r,s]of Object.entries(n))t.push(` ${r}: ${s};`);for(let[r,s]of Object.entries(o))t.push(` ${r}: ${s};`);if(t.push("}"),e.semanticDarkVariables&&Object.keys(e.semanticDarkVariables).length>0){let r={...o,...e.semanticDarkVariables},s=B(r,e.utilities||{});t.push("",":root.dark {");for(let[i,a]of Object.entries(s))t.push(` ${i}: ${a};`);for(let[i,a]of Object.entries(e.semanticDarkVariables))t.push(` ${i}: ${a};`);t.push("}")}let c={bg:[],text:[],border:[],icon:[],layer:[],overlay:[]};for(let r of Object.keys(e.semanticVariables||{}))r.startsWith("--bg-")&&c.bg.push(r.slice(5)),r.startsWith("--text-")&&c.text.push(r.slice(7)),r.startsWith("--border-")&&c.border.push(r.slice(9)),r.startsWith("--icon-")&&c.icon.push(r.slice(7)),r.startsWith("--layer-")&&c.layer.push(r.slice(8)),r.startsWith("--overlay-")&&c.overlay.push(r.slice(10));let f=(r,s)=>{t.push("",`@utility ${r} {`);for(let i of s)t.push(` ${i}`);t.push("}")};for(let r of c.icon)f(`icon-${r}`,[`color: var(--icon-${r});`]);t.push(...this.buildSemanticColorNamespaces(c));for(let r of e.fontFaces||[]){t.push("","@font-face {");for(let[s,i]of Object.entries(r)){let a=s.replace(/([A-Z])/g,"-$1").toLowerCase(),d=Array.isArray(i)?i.join(", "):i;t.push(` ${a}: ${d};`)}t.push("}")}for(let[r,s]of Object.entries(e.keyframes||{})){t.push("",`@keyframes ${r} {`);for(let[i,a]of Object.entries(s)){t.push(` ${i} {`);for(let[d,u]of Object.entries(a)){let h=d.replace(/([A-Z])/g,"-$1").toLowerCase();t.push(` ${h}: ${u};`)}t.push(" }")}t.push("}")}for(let[r,s]of Object.entries(e.animations||{}))f(`animate-${r}`,[`animation: ${s};`]);return e.custom?.raw&&t.push("","/* Custom CSS */",e.custom.raw),t.push("","/* Component classes for Tailwind scanning */",`@source './${ye}';`),t.join(`
5
+ `)}};module.exports=j;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Combines class names with tailwind-merge
3
+ * @param inputs - Class names to combine
4
+ * @returns Merged class string
5
+ */
6
+ export function cn(...inputs: any[]): string;
7
+
8
+ /**
9
+ * React hook for media query
10
+ * @param query - Media query string
11
+ * @returns Boolean indicating if query matches
12
+ */
13
+ export function useMediaQuery(query: string): boolean;
14
+
15
+ /**
16
+ * React hook for responsive breakpoints
17
+ * @returns Object with breakpoint states and active breakpoint
18
+ */
19
+ export function useBreakpoints(): {
20
+ isXs: boolean;
21
+ isSm: boolean;
22
+ isMd: boolean;
23
+ isLg: boolean;
24
+ active: 'xs' | 'sm' | 'md' | 'lg';
25
+ };
@@ -0,0 +1 @@
1
+ import{cn as p}from"cn";import{useEffect as m,useState as r}from"react";function t(e){let[a,s]=r(!1);return m(()=>{let i=window.matchMedia(e);s(i.matches);let n=c=>s(c.matches);return i.addEventListener("change",n),()=>i.removeEventListener("change",n)},[e]),a}function o(){let e={isXs:t("(max-width: 640px)"),isSm:t("(min-width: 641px) and (max-width: 768px)"),isMd:t("(min-width: 769px) and (max-width: 1024px)"),isLg:t("(min-width: 1025px)"),active:"xs"};return e.isXs&&(e.active="xs"),e.isSm&&(e.active="sm"),e.isMd&&(e.active="md"),e.isLg&&(e.active="lg"),e}export{p as cn,o as useBreakpoints,t as useMediaQuery};
@@ -0,0 +1,27 @@
1
+ import type { Ref, ComputedRef } from 'vue';
2
+
3
+ /**
4
+ * Combines class names with tailwind-merge
5
+ * @param inputs - Class names to combine
6
+ * @returns Merged class string
7
+ */
8
+ export function cn(...inputs: any[]): string;
9
+
10
+ /**
11
+ * Vue composition API hook for media query
12
+ * @param query - Media query string
13
+ * @returns Ref<boolean> indicating if query matches
14
+ */
15
+ export function useMediaQuery(query: string): Ref<boolean>;
16
+
17
+ /**
18
+ * Vue composition API hook for responsive breakpoints
19
+ * @returns Object with breakpoint states and active breakpoint
20
+ */
21
+ export function useBreakpoints(): {
22
+ isXs: Ref<boolean>;
23
+ isSm: Ref<boolean>;
24
+ isMd: Ref<boolean>;
25
+ isLg: Ref<boolean>;
26
+ active: ComputedRef<'xs' | 'sm' | 'md' | 'lg'>;
27
+ };
@@ -0,0 +1 @@
1
+ import{cn as f}from"cn";import{ref as a,onMounted as s,onUnmounted as m}from"vue";import{computed as u}from"vue";function i(r){let e=a(!1);return s(()=>{let t=window.matchMedia(r);e.value=t.matches;let n=o=>{e.value=o.matches};t.addEventListener("change",n),m(()=>{t.removeEventListener("change",n)})}),e}function x(){let r=i("(max-width: 640px)"),e=i("(min-width: 641px) and (max-width: 768px)"),t=i("(min-width: 769px) and (max-width: 1024px)"),n=i("(min-width: 1025px)"),o=u(()=>r.value?"xs":e.value?"sm":t.value?"md":n.value?"lg":"xs");return{isXs:r,isSm:e,isMd:t,isLg:n,active:o}}export{f as cn,x as useBreakpoints,i as useMediaQuery};