@symbo.ls/brender 3.14.663 → 3.14.664
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.
- package/CHANGELOG.md +22 -0
- package/dist/esm/render.js +29 -49
- package/package.json +8 -8
- package/render.js +71 -483
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @symbo.ls/brender
|
|
2
2
|
|
|
3
|
+
## 3.14.664
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Performance pass on the 3.14.827–3.14.832 batch, and opt-in View Transitions.
|
|
8
|
+
|
|
9
|
+
- Element create is faster than 3.14.826 again (kekela-like 4,068-element tree: create CPU min 1,265–1,355 ms vs 1,361–1,532 ms on 3.14.826). Per-definition caching of the extends merge layers (46,330 → 13,600 entries), no per-element source-text reads, one attribute writer.
|
|
10
|
+
- `css()` 3x faster (21 → 7 µs per call), byte-identical CSS output.
|
|
11
|
+
- Helmet renders a head layer only when its values change (20 `root.update({})` → 0 head renders, was 40). One runtime head writer: `applyElementMetadata`.
|
|
12
|
+
- brender/mermaid: registry script is escaped on the ISR and non-adopt paths; head/SSR output byte-identical otherwise.
|
|
13
|
+
- View Transitions for page switches (opt-in), `viewTransitionName` / `viewTransitionClass` flat props, `designSystem.viewTransition` animations.
|
|
14
|
+
- utils exports shared helpers used by helmet, frank, fetch and polyglot (escapeHtml, jsonForScript, alternateLinkKey, faviconLinkKey, bareLibraryKey, librarySpecsFor, polyglotLangStorageKey, ...).
|
|
15
|
+
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- smbls@3.14.833
|
|
18
|
+
- @symbo.ls/element@3.14.803
|
|
19
|
+
- @symbo.ls/css@3.14.777
|
|
20
|
+
- @symbo.ls/scratch@3.14.788
|
|
21
|
+
- @symbo.ls/utils@3.14.786
|
|
22
|
+
- @symbo.ls/fetch@3.14.664
|
|
23
|
+
- @symbo.ls/helmet@3.14.670
|
|
24
|
+
|
|
3
25
|
## 3.14.663
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/dist/esm/render.js
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
import{resolve as d,join as At,dirname as T}from"path";import{existsSync as y,unlinkSync as Pt,readFileSync as V,realpathSync as qt}from"fs";import{resolvePackageEntry as It}from"./packageEntry.js";import{tmpdir as vt}from"os";import{randomBytes as Dt}from"crypto";import{createRequire as ot}from"module";import{createEnv as at}from"./env.js";import{resetKeys as ft,assignKeys as ut,mapKeysToElements as pt}from"./keys.js";import{extractMetadata as st,generateHeadHtml as Mt}from"./metadata.js";import"./hydrate.js";import{composeIntoShell as Bt}from"./shell.js";import{prefetchPageData as Ft,injectPrefetchedState as Nt,fetchSSRTranslations as Wt}from"./prefetch.js";import{createEarlySeedScript as Ht}from"@symbo.ls/fetch";let X=null;const Gt=async()=>{if(X)return X;try{return X=(await import("@symbo.ls/funcql")).funcqlPlugin,X}catch{return null}};import"linkedom";import{reset as Jt}from"@symbo.ls/css";const rt=(t,e)=>{if(!t||!e)return;if(t[e]!==void 0)return t[e];const n=e.split(".");let o=t;for(const i of n){if(o==null||typeof o!="object")return;o=o[i]}return o},Kt=function(t,e){if(!t)return"";const n=this?.context,o=n?.polyglot,i=e||o?.defaultLang||"en";if(o?.translations){const a=o.translations[i];if(a){const r=rt(a,t);if(r!==void 0)return r}}const c=this?.state?.root||n?.state?.root;if(c?.translations){const a=c.translations[i];if(a){const r=rt(a,t);if(r!==void 0)return r}}const u=o?.defaultLang||"en";if(u!==i&&o?.translations){const a=o.translations[u];if(a){const r=rt(a,t);if(r!==void 0)return r}}return t},dt=function(){const t=this?.context;return this?.state?.root?.lang||t?.polyglot?.defaultLang||"en"},A=(t,e=new WeakMap)=>{if(t===null||typeof t!="object")return t;if(e.has(t))return e.get(t);if(Array.isArray(t)){const o=[];e.set(t,o);for(const i of t)o.push(typeof i=="object"&&i!==null?A(i,e):i);return o}const n={};e.set(t,n);for(const o of Object.keys(t)){const i=t[o];n[o]=typeof i=="object"&&i!==null?A(i,e):i}return n};let F=null;try{import.meta.url&&(F=ot(import.meta.url))}catch{}const zt=()=>{if(!import.meta.url||!F)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:r=>r};const t=qt(new URL(".",import.meta.url).pathname),e=d(t,"../..");if(y(d(e,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:e};let o;try{const r=F.resolve("smbls/package.json");o=T(r)}catch{let r=t;for(;r!==T(r);){const s=d(r,"node_modules","smbls");if(y(d(s,"package.json"))){o=s;break}r=T(r)}}let i=F;if(o)try{i=ot(d(o,"package.json"))}catch{}let c,u=process.cwd();for(;u!==T(u);){if(y(d(u,"package.json"))){c=u;break}u=T(u)}let a=i;if(c)try{a=ot(d(c,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:o,brenderDir:t,projectRoot:c,_smblsRequire:i,_projectRequire:a}},K=(t,e)=>{const n=t.isMonorepo?[F]:[t._smblsRequire,t._projectRequire,F].filter(Boolean);for(const o of n)try{return o.resolve(e)}catch{}return null},qe=(t,e,...n)=>{if(t.isMonorepo)return d(t.monorepoRoot,"packages",e,...n);const o=K(t,`${e}/package.json`);return o?d(T(o),...n):null},Ie=(t,e,...n)=>{if(t.isMonorepo)return d(t.monorepoRoot,"plugins",e,...n);const o=K(t,`@symbo.ls/${e}/package.json`);return o?d(T(o),...n):null},it=(t,e,...n)=>{if(t.isMonorepo){for(const i of["packages","plugins"]){const c=d(t.monorepoRoot,i,e,...n);if(y(c))return c}return null}const o=K(t,`@symbo.ls/${e}/package.json`);return o?d(T(o),...n):null},mt=(t,e,...n)=>{if(t.isMonorepo)return d(t.monorepoRoot,"packages","domql","packages",e,...n);const o=K(t,`@symbo.ls/${e}/package.json`);return o?d(T(o),...n):null};let N=null;const gt="smbls/ssr",ht=async()=>{const t=await import("smbls/ssr");if(typeof t?.createDomqlElement!="function")throw new Error("smbls/ssr does not export createDomqlElement");return t},Ut=async()=>{if(N)return N;const t=zt();if(!F)try{return N=await ht(),N}catch(a){throw new Error(`brender: ${gt} is not available in this bundled runtime (${a.message}). Bundle smbls \u2265 the release that adds the smbls/ssr export alongside @symbo.ls/brender.`)}let e;if(t.isMonorepo)e=d(t.monorepoRoot,"packages","smbls","src","createDomql.js");else{let a;try{return N=await ht(),N}catch(s){a=s}const r=t.smblsRoot&&d(t.smblsRoot,"src","createDomql.js");if(r&&y(r))e=r;else throw new Error(`brender: cannot load ${gt} (${a.message}). Server rendering needs smbls installed in this project, at a release that exports smbls/ssr`+(t.smblsRoot?` (found smbls at ${t.smblsRoot}).`:" (no smbls package found)."))}const n=await import("esbuild"),o=At(vt(),`br_createDomql_${Dt(6).toString("hex")}.mjs`),i=It,c={name:"workspace-resolve",setup(a){a.onResolve({filter:/^smbls/},r=>{const s=r.path.replace(/^smbls\/?/,""),f=t.isMonorepo?d(t.monorepoRoot,"packages","smbls"):t.smblsRoot;if(!f)return;if(!s){const h=i(f);return h?{path:h}:void 0}const l=d(f,s);if(y(l))return{path:l};if(y(l+".js"))return{path:l+".js"};const p=d(l,"index.js");if(y(p))return{path:p}}),a.onResolve({filter:/^domql$/},r=>{if(t.isMonorepo){const s=d(t.monorepoRoot,"packages","domql","src","index.js");if(y(s))return{path:s};const f=d(t.monorepoRoot,"packages","domql","index.js");if(y(f))return{path:f}}else try{const s=_require.resolve("domql/package.json"),f=i(T(s));if(f)return{path:f}}catch{}}),a.onResolve({filter:/^@symbo\.ls\//},r=>{const s=r.path.replace("@symbo.ls/","");if(s==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(t.isMonorepo){for(const l of["packages","plugins"]){const p=d(t.monorepoRoot,l,s,"src","index.js");if(y(p))return{path:p};const h=d(t.monorepoRoot,l,s,"index.js");if(y(h))return{path:h}}const f=d(t.monorepoRoot,"packages","default-config","blank","index.js");if(s==="default-config"&&y(f))return{path:f}}else{const f=it(t,s,"src","index.js");if(f&&y(f))return{path:f};const l=it(t,s,"index.js");if(l&&y(l))return{path:l};if(s==="default-config"){const p=it(t,"default-config","blank","index.js");if(p&&y(p))return{path:p}}}}),a.onResolve({filter:/^@domql\//},r=>{const s=r.path.replace("@symbo.ls/","");if(t.isMonorepo){const f=d(t.monorepoRoot,"packages","domql","packages",s,"src","index.js");if(y(f))return{path:f};const l=d(t.monorepoRoot,"packages","domql","packages",s,"index.js");if(y(l))return{path:l}}else{const f=mt(t,s,"src","index.js");if(f&&y(f))return{path:f};const l=mt(t,s,"index.js");if(l&&y(l))return{path:l}}}),a.onResolve({filter:/^css-in-props/},r=>{let s;if(t.isMonorepo)s=d(t.monorepoRoot,"packages","css-in-props");else{const p=K(t,"css-in-props/package.json");p&&(s=T(p))}if(!s)return;const f=r.path.replace(/^css-in-props\/?/,"");if(f){const p=d(s,f),h=d(p,"index.js");if(y(h))return{path:h};if(y(p+".js"))return{path:p+".js"};if(y(p))return{path:p}}const l=i(s);if(l)return{path:l}}),a.onResolve({filter:/^@emotion\//},r=>{let s;if(t.isMonorepo)s=d(t.monorepoRoot,"node_modules",r.path);else{const f=K(t,`${r.path}/package.json`);if(!f)return;s=T(f)}if(y(s)){const f=d(s,"package.json");if(y(f))try{const l=JSON.parse(V(f,"utf8")),p=l.module||l.main||"dist/emotion-css.esm.js";return{path:d(s,p)}}catch{}return{path:s}}}),a.onResolve({filter:/\.json$/},r=>{if(r.resolveDir){const s=d(r.resolveDir,r.path);if(y(s))return{path:s}}}),a.onLoad({filter:/smbls\/.*options\.js$/},async r=>{if(!r.path.includes("smbls/")||!r.path.endsWith("options.js"))return;let s=V(r.path,"utf8");return s=s.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),s=s.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:s,loader:"js"}}),a.onLoad({filter:/smbls\/.*init\.js$/},async r=>{if(!r.path.includes("smbls/")||!r.path.endsWith("init.js"))return;let s=V(r.path,"utf8");return s=s.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:s,loader:"js"}}),a.onLoad({filter:/.*/,namespace:"brender-stub"},()=>({contents:"export const SyncComponent = {}; export const Inspect = {}; export const Notifications = {}; export const syncPlugin = () => ({}); export const notificationsPlugin = () => ({}); export const seedRawDesignSystem = () => {}; export const inspectPlugin = () => ({}); export default {}",loader:"js"})),a.onLoad({filter:/smbls\/src\/router\.js$/},async r=>{let s=V(r.path,"utf8");return s=s.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:s,loader:"js"}}),a.onLoad({filter:/fetchOnCreate\.js$/},async r=>{if(!r.path.includes("smbls/"))return;let s=V(r.path,"utf8");return s=s.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:s,loader:"js"}})}};await n.build({entryPoints:[e],bundle:!0,format:"esm",platform:"node",outfile:o,write:!0,logLevel:"warning",plugins:[c],nodePaths:t.isMonorepo?[d(t.monorepoRoot,"node_modules")]:[...t.smblsRoot?[d(t.smblsRoot,"node_modules")]:[],...t.projectRoot?[d(t.projectRoot,"node_modules")]:[],...t.smblsRoot?[d(t.smblsRoot,"..","..","node_modules")]:[]].filter(a=>y(a)),supported:{"import-attributes":!1},external:["fs","path","os","crypto","url","http","https","stream","util","events","buffer","child_process","worker_threads","net","tls","dns","dgram","zlib","assert","querystring","string_decoder","readline","perf_hooks","async_hooks","v8","vm","cluster","inspector","module","process","tty","color-contrast-checker","linkedom"]});const u=await import(`file://${o}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",o);else try{Pt(o)}catch{}return N=u,u},Yt={Box:{},Focusable:{},Block:{display:"block"},Inline:{display:"inline"},Flex:{display:"flex"},InlineFlex:{display:"inline-flex"},Grid:{display:"grid"},InlineGrid:{display:"inline-grid"},Link:{tag:"a",attr:{href:t=>t.href,target:t=>t.target,rel:t=>t.rel}},A:{extends:"Link"},RouteLink:{extends:"Link"},Img:{tag:"img",attr:{src:t=>{let e=t.src;return typeof e=="string"&&e.includes("{{")&&(e=t.call("replaceLiteralsWithObjectFields",e,t.state)),e},alt:t=>t.alt,loading:t=>t.loading}},Image:{extends:"Img"},Button:{tag:"button"},FocusableComponent:{tag:"button"},Form:{tag:"form"},Input:{tag:"input"},TextArea:{tag:"textarea"},Textarea:{tag:"textarea"},Select:{tag:"select"},Label:{tag:"label"},Iframe:{tag:"iframe"},Video:{tag:"video"},Audio:{tag:"audio"},Canvas:{tag:"canvas"},Span:{tag:"span"},P:{tag:"p"},H1:{tag:"h1"},H2:{tag:"h2"},H3:{tag:"h3"},H4:{tag:"h4"},H5:{tag:"h5"},H6:{tag:"h6"},Svg:{tag:"svg",attr:{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"}},Text:{tag:"span"}},yt=(t,e="")=>{if(!t||!t.__ref)return{};const n={},o=t.__ref.__brKey;if(o&&(n[e===""?"__root":e]=o),t.__ref.__children)for(const i of t.__ref.__children){const c=t[i];if(c&&c.__ref){const u=e===""?i:`${e}.${i}`;Object.assign(n,yt(c,u))}}return n};let z=0;const bt=Symbol.for("brender.fetchTracked"),St=()=>z,Vt=256*1024,Xt=1024*1024,Zt=new Set(["accept-language","accept"]);let lt=0,q=null;const Qt=t=>{const[e,n]=t,o=e&&typeof e=="object"&&typeof e.url=="string",i=o?e.url:String(e),c=String(n&&n.method||o&&e.method||"GET").toUpperCase(),u={},a=r=>{if(r)if(typeof r.forEach=="function"&&!Array.isArray(r))r.forEach((s,f)=>{u[String(f).toLowerCase()]=String(s)});else if(Array.isArray(r))for(const[s,f]of r)u[String(s).toLowerCase()]=String(f);else for(const s in r)r[s]!=null&&(u[s.toLowerCase()]=String(r[s]))};return o&&a(e.headers),n&&a(n.headers),{url:i,method:c,headers:u}},te=(t,e,n,o)=>{if(!n||!n.ok||typeof n.clone!="function")return;const i=n.headers&&n.headers.get&&n.headers.get("content-type")||"";if(!/json|^text\//i.test(i))return;let c;try{c=n.clone()}catch{return}o(c.text().then(u=>{t.tainted||u.length>Vt||t.bytes+u.length>Xt||(t.bytes+=u.length,t.entries.push({url:e.url,lang:e.headers["accept-language"]||"",status:n.status,type:i,body:u}))},()=>{}))},ee=()=>{const t=globalThis.fetch;if(typeof t!="function"||t[bt])return;const e=function(...n){z++;let o=!1;const i=()=>{o||(o=!0,z--)},c=s=>{z++,s.then(()=>{z--},()=>{z--})},u=q&&!q.tainted?q:null;let a=null;if(u)try{a=Qt(n),(a.method!=="GET"||!/^https?:/i.test(a.url)||Object.keys(a.headers).some(s=>!Zt.has(s)))&&(a=null)}catch{a=null}let r;try{r=t.apply(this,n)}catch(s){throw i(),s}return r&&typeof r.then=="function"?r.then(s=>{a&&te(u,a,s,c),i()},i):i(),r};e[bt]=!0,globalThis.fetch=e},ct=({brRegistry:t,fetchSeed:e}={})=>!t||!Object.keys(t).length?"":`<script>window.__BR_REGISTRY__=${JSON.stringify(t).replace(/</g,"\\u003c")};window.__BRENDER_HYDRATE__=true<\/script>`+(e&&e.length?`
|
|
2
|
-
|
|
3
|
-
`)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
`)
|
|
7
|
-
${
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
`),
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
${
|
|
16
|
-
</style>`:""
|
|
17
|
-
`)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
`:"":G?`<script>window.__BR_REGISTRY__=${G}<\/script>
|
|
21
|
-
`:"";x=`${$}${U}<script>window.__BRENDER__=true<\/script>
|
|
22
|
-
<script type="module" src="${L}${c.clientScript}"><\/script>`}else x=`<script type="module">
|
|
1
|
+
import{resolve as u,join as ke,dirname as v}from"path";import{existsSync as d,unlinkSync as we,readFileSync as V,realpathSync as xe}from"fs";import{resolvePackageEntry as _e}from"./packageEntry.js";import{tmpdir as je}from"os";import{randomBytes as ve}from"crypto";import{createRequire as oe}from"module";import{createEnv as ie}from"./env.js";import{resetKeys as ae,assignKeys as ce,mapKeysToElements as fe}from"./keys.js";import{extractMetadata as ne,generateHeadHtml as Te}from"./metadata.js";import"./hydrate.js";import{composeIntoShell as Ee}from"./shell.js";import{prefetchPageData as Le,injectPrefetchedState as Ce,fetchSSRTranslations as qe}from"./prefetch.js";import{createEarlySeedScript as $e}from"@symbo.ls/fetch";import{headerEntries as Pe}from"@symbo.ls/fetch/rest";import{jsonForScript as De}from"@symbo.ls/utils";let Q=null;const Ae=async()=>{if(Q)return Q;try{return Q=(await import("@symbo.ls/funcql")).funcqlPlugin,Q}catch{return null}};import"linkedom";import{reset as Me}from"@symbo.ls/css";const se=(e,t)=>{if(!e||!t)return;if(e[t]!==void 0)return e[t];const o=t.split(".");let n=e;for(const l of o){if(n==null||typeof n!="object")return;n=n[l]}return n},Oe=function(e,t){if(!e)return"";const o=this?.context,n=o?.polyglot,l=t||n?.defaultLang||"en";if(n?.translations){const c=n.translations[l];if(c){const r=se(c,e);if(r!==void 0)return r}}const a=this?.state?.root||o?.state?.root;if(a?.translations){const c=a.translations[l];if(c){const r=se(c,e);if(r!==void 0)return r}}const p=n?.defaultLang||"en";if(p!==l&&n?.translations){const c=n.translations[p];if(c){const r=se(c,e);if(r!==void 0)return r}}return e},pe=function(){const e=this?.context;return this?.state?.root?.lang||e?.polyglot?.defaultLang||"en"},L=(e,t=new WeakMap)=>{if(e===null||typeof e!="object")return e;if(t.has(e))return t.get(e);if(Array.isArray(e)){const n=[];t.set(e,n);for(const l of e)n.push(typeof l=="object"&&l!==null?L(l,t):l);return n}const o={};t.set(e,o);for(const n of Object.keys(e)){const l=e[n];o[n]=typeof l=="object"&&l!==null?L(l,t):l}return o};let M=null;try{import.meta.url&&(M=oe(import.meta.url))}catch{}const Ie=()=>{if(!import.meta.url||!M)return{isMonorepo:!1,monorepoRoot:null,resolvePackage:r=>r};const e=xe(new URL(".",import.meta.url).pathname),t=u(e,"../..");if(d(u(t,"packages","smbls","src","createDomql.js")))return{isMonorepo:!0,monorepoRoot:t};let n;try{const r=M.resolve("smbls/package.json");n=v(r)}catch{let r=e;for(;r!==v(r);){const s=u(r,"node_modules","smbls");if(d(u(s,"package.json"))){n=s;break}r=v(r)}}let l=M;if(n)try{l=oe(u(n,"package.json"))}catch{}let a,p=process.cwd();for(;p!==v(p);){if(d(u(p,"package.json"))){a=p;break}p=v(p)}let c=l;if(a)try{c=oe(u(a,"package.json"))}catch{}return{isMonorepo:!1,smblsRoot:n,brenderDir:e,projectRoot:a,_smblsRequire:l,_projectRequire:c}},K=(e,t)=>{const o=e.isMonorepo?[M]:[e._smblsRequire,e._projectRequire,M].filter(Boolean);for(const n of o)try{return n.resolve(t)}catch{}return null},_t=(e,t,...o)=>{if(e.isMonorepo)return u(e.monorepoRoot,"packages",t,...o);const n=K(e,`${t}/package.json`);return n?u(v(n),...o):null},jt=(e,t,...o)=>{if(e.isMonorepo)return u(e.monorepoRoot,"plugins",t,...o);const n=K(e,`@symbo.ls/${t}/package.json`);return n?u(v(n),...o):null},re=(e,t,...o)=>{if(e.isMonorepo){for(const l of["packages","plugins"]){const a=u(e.monorepoRoot,l,t,...o);if(d(a))return a}return null}const n=K(e,`@symbo.ls/${t}/package.json`);return n?u(v(n),...o):null},ue=(e,t,...o)=>{if(e.isMonorepo)return u(e.monorepoRoot,"packages","domql","packages",t,...o);const n=K(e,`@symbo.ls/${t}/package.json`);return n?u(v(n),...o):null};let X=null;const me="smbls/ssr",Fe=async()=>{const e=await import("smbls/ssr");if(typeof e?.createDomqlElement!="function")throw new Error("smbls/ssr does not export createDomqlElement");return e},Ne=async()=>{if(X)return X;const e=Ie();let t;if(M&&e.isMonorepo)t=u(e.monorepoRoot,"packages","smbls","src","createDomql.js");else{let c;try{return X=await Fe(),X}catch(s){c=s}if(!M)throw new Error(`brender: ${me} is not available in this bundled runtime (${c.message}). Bundle smbls \u2265 the release that adds the smbls/ssr export alongside @symbo.ls/brender.`);const r=e.smblsRoot&&u(e.smblsRoot,"src","createDomql.js");if(r&&d(r))t=r;else throw new Error(`brender: cannot load ${me} (${c.message}). Server rendering needs smbls installed in this project, at a release that exports smbls/ssr`+(e.smblsRoot?` (found smbls at ${e.smblsRoot}).`:" (no smbls package found)."))}const o=await import("esbuild"),n=ke(je(),`br_createDomql_${ve(6).toString("hex")}.mjs`),l=_e,a={name:"workspace-resolve",setup(c){c.onResolve({filter:/^smbls/},r=>{const s=r.path.replace(/^smbls\/?/,""),f=e.isMonorepo?u(e.monorepoRoot,"packages","smbls"):e.smblsRoot;if(!f)return;if(!s){const h=l(f);return h?{path:h}:void 0}const i=u(f,s);if(d(i))return{path:i};if(d(i+".js"))return{path:i+".js"};const m=u(i,"index.js");if(d(m))return{path:m}}),c.onResolve({filter:/^domql$/},r=>{if(e.isMonorepo){const s=u(e.monorepoRoot,"packages","domql","src","index.js");if(d(s))return{path:s};const f=u(e.monorepoRoot,"packages","domql","index.js");if(d(f))return{path:f}}else try{const s=_require.resolve("domql/package.json"),f=l(v(s));if(f)return{path:f}}catch{}}),c.onResolve({filter:/^@symbo\.ls\//},r=>{const s=r.path.replace("@symbo.ls/","");if(s==="sync")return{path:"sync-stub",namespace:"brender-stub"};if(e.isMonorepo){for(const i of["packages","plugins"]){const m=u(e.monorepoRoot,i,s,"src","index.js");if(d(m))return{path:m};const h=u(e.monorepoRoot,i,s,"index.js");if(d(h))return{path:h}}const f=u(e.monorepoRoot,"packages","default-config","blank","index.js");if(s==="default-config"&&d(f))return{path:f}}else{const f=re(e,s,"src","index.js");if(f&&d(f))return{path:f};const i=re(e,s,"index.js");if(i&&d(i))return{path:i};if(s==="default-config"){const m=re(e,"default-config","blank","index.js");if(m&&d(m))return{path:m}}}}),c.onResolve({filter:/^@domql\//},r=>{const s=r.path.replace("@symbo.ls/","");if(e.isMonorepo){const f=u(e.monorepoRoot,"packages","domql","packages",s,"src","index.js");if(d(f))return{path:f};const i=u(e.monorepoRoot,"packages","domql","packages",s,"index.js");if(d(i))return{path:i}}else{const f=ue(e,s,"src","index.js");if(f&&d(f))return{path:f};const i=ue(e,s,"index.js");if(i&&d(i))return{path:i}}}),c.onResolve({filter:/^css-in-props/},r=>{let s;if(e.isMonorepo)s=u(e.monorepoRoot,"packages","css-in-props");else{const m=K(e,"css-in-props/package.json");m&&(s=v(m))}if(!s)return;const f=r.path.replace(/^css-in-props\/?/,"");if(f){const m=u(s,f),h=u(m,"index.js");if(d(h))return{path:h};if(d(m+".js"))return{path:m+".js"};if(d(m))return{path:m}}const i=l(s);if(i)return{path:i}}),c.onResolve({filter:/^@emotion\//},r=>{let s;if(e.isMonorepo)s=u(e.monorepoRoot,"node_modules",r.path);else{const f=K(e,`${r.path}/package.json`);if(!f)return;s=v(f)}if(d(s)){const f=u(s,"package.json");if(d(f))try{const i=JSON.parse(V(f,"utf8")),m=i.module||i.main||"dist/emotion-css.esm.js";return{path:u(s,m)}}catch{}return{path:s}}}),c.onResolve({filter:/\.json$/},r=>{if(r.resolveDir){const s=u(r.resolveDir,r.path);if(d(s))return{path:s}}}),c.onLoad({filter:/smbls\/.*options\.js$/},async r=>{if(!r.path.includes("smbls/")||!r.path.endsWith("options.js"))return;let s=V(r.path,"utf8");return s=s.replace(/import\s*\{[^}]*version[^}]*\}\s*from\s*['"][^'"]*package\.json['"][^;\n]*/,"const version = '0.0.0'"),s=s.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:s,loader:"js"}}),c.onLoad({filter:/smbls\/.*init\.js$/},async r=>{if(!r.path.includes("smbls/")||!r.path.endsWith("init.js"))return;let s=V(r.path,"utf8");return s=s.replace(/import\s*\{[^}]*createRequire[^}]*\}\s*from\s*['"]module['"][^;\n]*/g,"// createRequire removed for brender build"),{contents:s,loader:"js"}}),c.onLoad({filter:/.*/,namespace:"brender-stub"},()=>({contents:"export const SyncComponent = {}; export const Inspect = {}; export const Notifications = {}; export const syncPlugin = () => ({}); export const notificationsPlugin = () => ({}); export const seedRawDesignSystem = () => {}; export const inspectPlugin = () => ({}); export default {}",loader:"js"})),c.onLoad({filter:/smbls\/src\/router\.js$/},async r=>{let s=V(r.path,"utf8");return s=s.replace(/import\s*\{\s*Link\s*\}\s*from\s*['"]smbls['"]/,"const Link = { tag: 'a', attr: { href: (el) => el.href } }"),{contents:s,loader:"js"}}),c.onLoad({filter:/fetchOnCreate\.js$/},async r=>{if(!r.path.includes("smbls/"))return;let s=V(r.path,"utf8");return s=s.replace(/window\s*&&\s*window\.location\s*\?\s*window\.location\.host\.includes/g,"window && window.location && window.location.host ? window.location.host.includes"),{contents:s,loader:"js"}})}};await o.build({entryPoints:[t],bundle:!0,format:"esm",platform:"node",outfile:n,write:!0,logLevel:"warning",plugins:[a],nodePaths:e.isMonorepo?[u(e.monorepoRoot,"node_modules")]:[...e.smblsRoot?[u(e.smblsRoot,"node_modules")]:[],...e.projectRoot?[u(e.projectRoot,"node_modules")]:[],...e.smblsRoot?[u(e.smblsRoot,"..","..","node_modules")]:[]].filter(c=>d(c)),supported:{"import-attributes":!1},external:["fs","path","os","crypto","url","http","https","stream","util","events","buffer","child_process","worker_threads","net","tls","dns","dgram","zlib","assert","querystring","string_decoder","readline","perf_hooks","async_hooks","v8","vm","cluster","inspector","module","process","tty","color-contrast-checker","linkedom"]});const p=await import(`file://${n}`);if(process.env.BRENDER_DEBUG)console.log("[brender] Bundle saved:",n);else try{we(n)}catch{}return X=p,p},Be={Box:{},Focusable:{},Block:{display:"block"},Inline:{display:"inline"},Flex:{display:"flex"},InlineFlex:{display:"inline-flex"},Grid:{display:"grid"},InlineGrid:{display:"inline-grid"},Link:{tag:"a",attr:{href:e=>e.href,target:e=>e.target,rel:e=>e.rel}},A:{extends:"Link"},RouteLink:{extends:"Link"},Img:{tag:"img",attr:{src:e=>{let t=e.src;return typeof t=="string"&&t.includes("{{")&&(t=e.call("replaceLiteralsWithObjectFields",t,e.state)),t},alt:e=>e.alt,loading:e=>e.loading}},Image:{extends:"Img"},Button:{tag:"button"},FocusableComponent:{tag:"button"},Form:{tag:"form"},Input:{tag:"input"},TextArea:{tag:"textarea"},Textarea:{tag:"textarea"},Select:{tag:"select"},Label:{tag:"label"},Iframe:{tag:"iframe"},Video:{tag:"video"},Audio:{tag:"audio"},Canvas:{tag:"canvas"},Span:{tag:"span"},P:{tag:"p"},H1:{tag:"h1"},H2:{tag:"h2"},H3:{tag:"h3"},H4:{tag:"h4"},H5:{tag:"h5"},H6:{tag:"h6"},Svg:{tag:"svg",attr:{xmlns:"http://www.w3.org/2000/svg","xmlns:xlink":"http://www.w3.org/1999/xlink"}},Text:{tag:"span"}},He=(e,t)=>{const o={},n=l=>{const a=l&&l.__ref;if(a){if(a.__brKey){const p=t(l);o[p===""?"__root":p]=a.__brKey}if(a.__children)for(const p of a.__children)n(l[p])}};return n(e),o},Je=new Set(["app","config","pages","components","state","snippets","designSystem","dependencies","functions","methods","files","sharedLibraries"]);let G=0;const ge=Symbol.for("brender.fetchTracked"),de=()=>G,Ke=256*1024,Ge=1024*1024,We=new Set(["accept-language","accept"]);let le=0,D=null;const Ue=e=>{const[t,o]=e,n=t&&typeof t=="object"&&typeof t.url=="string",l=n?t.url:String(t),a=String(o&&o.method||n&&t.method||"GET").toUpperCase(),p={},c=r=>{if(!r)return;const s=!Array.isArray(r)&&typeof r.entries!="function";for(const[f,i]of Pe(r))s&&i==null||(p[String(f).toLowerCase()]=String(i))};return n&&c(t.headers),o&&c(o.headers),{url:l,method:a,headers:p}},Ye=(e,t,o,n)=>{if(!o||!o.ok||typeof o.clone!="function")return;const l=o.headers&&o.headers.get&&o.headers.get("content-type")||"";if(!/json|^text\//i.test(l))return;let a;try{a=o.clone()}catch{return}n(a.text().then(p=>{e.tainted||p.length>Ke||e.bytes+p.length>Ge||(e.bytes+=p.length,e.entries.push({url:t.url,lang:t.headers["accept-language"]||"",status:o.status,type:l,body:p}))},()=>{}))},ze=()=>{const e=globalThis.fetch;if(typeof e!="function"||e[ge])return;const t=function(...o){G++;let n=!1;const l=()=>{n||(n=!0,G--)},a=s=>{G++,s.then(()=>{G--},()=>{G--})},p=D&&!D.tainted?D:null;let c=null;if(p)try{c=Ue(o),(c.method!=="GET"||!/^https?:/i.test(c.url)||Object.keys(c.headers).some(s=>!We.has(s)))&&(c=null)}catch{c=null}let r;try{r=e.apply(this,o)}catch(s){throw l(),s}return r&&typeof r.then=="function"?r.then(s=>{c&&Ye(p,c,s,a),l()},l):l(),r};t[ge]=!0,globalThis.fetch=t},Ve=({brRegistry:e,fetchSeed:t,hydrateFlag:o=!0}={})=>{if(!e||!Object.keys(e).length)return"";const n=De(e);return o?`<script>window.__BR_REGISTRY__=${n};window.__BRENDER_HYDRATE__=true<\/script>`+(t&&t.length?`
|
|
2
|
+
`+$e(t):""):`<script>window.__BR_REGISTRY__=${n}<\/script>`},he=async(e,t={})=>{const{route:o="/",pathname:n,state:l,context:a,prefetch:p=!1}=t,c=n||o,r=globalThis.location,s=globalThis.window;(!globalThis.location||globalThis.location.pathname!==c)&&(globalThis.location={pathname:c,href:c,search:"",hash:"",origin:""}),globalThis.window||(globalThis.window={location:globalThis.location});let f;if(p)try{const g=e.pages||{};f={...g};const y=await Le(e,o);if(y.size){const P=JSON.parse(JSON.stringify(g[o],(_,A)=>{if(typeof A!="function")return A})),J=(_,A)=>{if(!(!_||!A))for(const E in _)typeof _[E]=="function"?A[E]=_[E]:typeof _[E]=="object"&&_[E]!==null&&!Array.isArray(_[E])&&typeof A[E]=="object"&&A[E]!==null&&J(_[E],A[E])};J(g[o],P),Ce(P,y),f[o]=P}}catch(g){console.error("[brender] Prefetch error:",g),f=e.pages}let i;if(p)try{i=await qe(e)}catch(g){console.warn("[brender] SSR translation fetch failed:",g.message)}r!==void 0?globalThis.location=r:delete globalThis.location,s!==void 0?globalThis.window=s:delete globalThis.window;const{window:m,document:h}=ie(),w=h.body;m.location.pathname=c;const T=globalThis.document,S=globalThis.location;globalThis.document=h,globalThis.location=m.location;const{createDomqlElement:R}=await Ne(),Z=L(e.app||{}),k={...e.config||{}};e.polyglot&&!k.polyglot&&(k.polyglot=e.polyglot),e.fetch&&!k.fetch&&(k.fetch=e.fetch),e.router&&!k.router&&(k.router=e.router);for(const g of Xe)e[g]!=null&&k[g]==null&&(k[g]=e[g]);const x=k.polyglot?{...k.polyglot}:void 0;i&&x&&(x.translations={...x.translations||{},...i});const j=L(e.state||{});(i||x)&&(j.root||(j.root={}),x&&(j.root.lang=j.root.lang||x.defaultLang||"en"),i&&(j.root.translations={...j.root.translations||{},...i})),Me();const F={};for(const g in e){if(Je.has(g))continue;const y=e[g];F[g]=y&&typeof y=="object"?L(y):y}const C={...F,state:j,...l?{state:{...j,...l}}:{},dependencies:L(e.dependencies||{}),components:L(e.components||{}),snippets:L(e.snippets||{}),pages:L(f||e.pages||{}),functions:{...e.functions||{},polyglot:Oe,getActiveLang:pe,getLang:pe},methods:e.methods||{},designSystem:L(e.designSystem||{}),files:e.files||{},sharedLibraries:e.sharedLibraries||[],...k,...x?{polyglot:x}:{},document:h,window:m,parent:{node:w},initOptions:{},domqlOptions:{sourcemap:!1},sync:!1,inspect:!1,notifications:!1,...a||{}},N=await Ae();N&&(C.plugins=C.plugins||[],C.plugins.some(g=>g.name==="funcql")||C.plugins.push(N)),ae(),ze(),le++,le===1?D={entries:[],bytes:0,tainted:!1}:D&&(D.tainted=!0);const W=D;let b;try{b=await R(Z,C);const g=Date.now(),y=p?2e3:50,P=J=>new Promise(_=>setTimeout(_,J));for(await P(Math.min(50,y));p&&de()>0&&Date.now()-g<y;)await P(10),de()===0&&await P(Math.max(0,Math.min(50,y-(Date.now()-g))))}finally{le--,D===W&&(D=null)}const B=W&&!W.tainted?W.entries.slice():[];ce(w);const q=fe(b),{elementPath:U}=await import("@symbo.ls/element"),O=He(b,U),Y=ne(e,o,b,b?.state),$=[],I=h.head||h.querySelector("head");if(I)for(const g of I.querySelectorAll("style")){if(g.sheet&&g.sheet.cssRules)for(const y of g.sheet.cssRules)y.cssText&&$.push(y);if(!$.length){const y=g.textContent||"";y&&$.push({cssText:y})}}const H=$.map(g=>g.cssText),{globalCSS:z,classRules:Re}=tt($);let te=ye(w.innerHTML);if(i){const g=x?.defaultLang||"en",y=i[g]||Object.values(i)[0]||{};te=te.replace(/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,(P,J)=>{const _=J.trim();return y[_]??P})}return T!==void 0?globalThis.document=T:delete globalThis.document,S!==void 0?globalThis.location=S:delete globalThis.location,{html:te,metadata:Y,registry:q,brRegistry:O,element:b,emotionCSS:H,globalCSS:z,classRules:Re,fetchSeed:B,document:h,window:m,ssrTranslations:i,prefetchedPages:f}},vt=async(e,t={})=>{const{context:o={}}=t,{window:n,document:l}=ie(),a=l.body,{create:p}=await import("@symbo.ls/element"),c=await import("@symbo.ls/utils"),r={...Be,...o.components||{}},s={...c,...o.utils||{},...o.functions||{}};ae();let f;try{f=p(e,{node:a},"root",{context:{document:l,window:n,...o,components:r,utils:s}})}catch{}ce(a);const i=f?fe(f):{};return{html:ye(a.innerHTML),registry:i,element:f}},ye=e=>e.replace(/(<svg\b[^>]*>)([\s\S]*?)(<\/svg>)/gi,(t,o,n,l)=>{if(n.includes("<")){const a=n.replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&").replace(/"/g,'"').replace(/'/g,"'");return o+a+l}return t}),Xe=["globalTheme","themeStorageKey","themeRoot","useReset","useVariable","useFontImport","useIconSprite","useSvgSprite","useDocumentTheme","useDefaultConfig","useDefaultIcons","useThemeSuffixedVars","verbose","semanticIcons"],Ze=/\.[A-Za-z_\\-]/,Qe=e=>{if(typeof e!="string"||!e)return!1;const t=e.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,'""').replace(/\[[^\]]*\]/g,"[]");return!Ze.test(t)},et=/^\s*(:root|\[data-theme|\[data-skin)/,be=e=>{const t=e&&e.cssText;if(typeof t!="string")return null;if(/^@(-webkit-)?keyframes\b/.test(t))return"keyframes";if(t.startsWith("@font-face"))return null;if(typeof e.selectorText=="string")return Qe(e.selectorText)?et.test(e.selectorText)?"root":"reset":null;const o=e.cssRules&&Array.from(e.cssRules);if(o&&o.length&&/^@(media|supports|container)\b/.test(t)){const n=new Set(o.map(be));return n.has(null)||n.size!==1?n.has(null)?null:"reset":[...n][0]}return null},tt=e=>{const t={root:[],reset:[],keyframes:[]},o=[];for(const n of e||[]){const l=be(n);l?t[l].push(n.cssText):n&&n.cssText&&o.push(n.cssText)}return{globalCSS:{rootRule:t.root.join(`
|
|
3
|
+
`),resetRules:t.reset.join(`
|
|
4
|
+
`),keyframeRules:t.keyframes.join(`
|
|
5
|
+
`),fontFaceCSS:""},classRules:o}};let ee=new Set;const Tt=()=>{ee=new Set},Et=()=>Array.from(ee).join(`
|
|
6
|
+
`),Lt=(e,t)=>e.replace(/<style data-emotion="smbls">[\s\S]*?<\/style>/,t?`<style data-emotion="smbls">
|
|
7
|
+
${t}
|
|
8
|
+
</style>`:""),Ct=async(e,t={})=>{const{route:o="/",pathname:n,prefetch:l=!0}=t,a=await he(e,{route:o,pathname:n,prefetch:l});if(!a)return null;const p=e.designSystem||{},c=a.globalCSS;let r=null,s=null;try{const f=a.element,i=f?.context?.polyglot||e.polyglot||e.config?.polyglot;if(s=f?.state?.root?.lang||i?.defaultLang||"en",a.prefetchedPages&&a.prefetchedPages[o]){const m=a.prefetchedPages[o],h=(w,T={})=>{if(!w||typeof w!="object")return T;if(w.state&&typeof w.state=="object")for(const[S,R]of Object.entries(w.state))R!=null&&typeof R!="function"&&(T[S]=R);for(const[S,R]of Object.entries(w))S==="state"||S==="props"||S==="attr"||S==="on"||S==="define"||S==="__ref"||S.startsWith("__")||R&&typeof R=="object"&&!Array.isArray(R)&&h(R,T);return T};r=h(m)}}catch{}return{html:a.html,css:a.classRules.join(`
|
|
9
|
+
`),classRules:a.classRules.slice(),globalCSS:c,resetCss:c.resetRules,fontLinks:Se(p),metadata:a.metadata||ne(e,o),brKeyCount:a.registry?Object.keys(a.registry).length:0,brRegistry:a.brRegistry||{},fetchSeed:a.fetchSeed||[],ssrTranslations:a.ssrTranslations,prefetchedState:r,activeLang:s}},qt=async(e,t="/",o={})=>{const{lang:n,themeColor:l,isr:a,hydrate:p=!0,prefetch:c=!0,shell:r,adoptDom:s=!1}=o,f=n||e.state?.lang||e.app?.metadata?.lang||"en",i=await he(e,{route:t,prefetch:c});if(!i)return null;const m={...i.metadata};if(l&&(m["theme-color"]=l),typeof r=="string"&&!e.name){const b="\0brender-undeclared-title\0";if(ne({...e,name:b},t,i.element,i.element?.state).title===b)for(const q of["title","og:title","twitter:title"])m[q]===i.metadata.title&&delete m[q]}const h=Te(m);for(const b of i.classRules)b&&ee.add(b);const w=Array.from(ee).join(`
|
|
10
|
+
`),T=i.globalCSS,S=`<style data-brender>
|
|
11
|
+
${T.rootRule||""}
|
|
12
|
+
${T.resetRules||""}
|
|
13
|
+
${T.keyframeRules||""}
|
|
14
|
+
</style>`,R=w?`<style data-emotion="smbls">
|
|
15
|
+
${w}
|
|
16
|
+
</style>`:"",Z=Se(e.designSystem||{}),k=Object.keys(i.registry).length,x=Ve({brRegistry:i.brRegistry,fetchSeed:i.fetchSeed,hydrateFlag:s});let j="";if(a&&a.clientScript){const b=Number.isInteger(o.depth)?o.depth:t==="/"?0:t.replace(/^\/|\/$/g,"").split("/").length,B=b>0?"../".repeat(b):"./";if(p){let q="";if(i.ssrTranslations){const O=e.polyglot||e.config?.polyglot,Y=O?.storagePrefix||"",$=O?.storageLangKey||"",I=[];for(const H in i.ssrTranslations){const z=i.ssrTranslations[H];z&&typeof z=="object"&&I.push(`localStorage.setItem(${JSON.stringify(Y+H)},${JSON.stringify(JSON.stringify(z))})`)}if($){const H=O?.defaultLang||"en";I.push(`if(!localStorage.getItem(${JSON.stringify($)}))localStorage.setItem(${JSON.stringify($)},${JSON.stringify(H)})`)}I.length&&(q=`<script>try{${I.join(";")}}catch(e){}<\/script>
|
|
17
|
+
`)}const U=x?x+`
|
|
18
|
+
`:"";j=`${q}${U}<script>window.__BRENDER__=true<\/script>
|
|
19
|
+
<script type="module" src="${B}${a.clientScript}"><\/script>`}else j=`<script type="module">
|
|
23
20
|
{
|
|
24
21
|
const brEls = document.querySelectorAll('body > :not(script):not(style)')
|
|
25
22
|
const observer = new MutationObserver((mutations) => {
|
|
@@ -36,36 +33,19 @@ ${e}
|
|
|
36
33
|
observer.observe(document.body, { childList: true })
|
|
37
34
|
}
|
|
38
35
|
<\/script>
|
|
39
|
-
<script type="module" src="${
|
|
40
|
-
|
|
41
|
-
${m.resetRules||""}
|
|
42
|
-
${m.keyframeRules||""}
|
|
43
|
-
</style>`,S?`<style data-emotion="smbls">
|
|
44
|
-
${S}
|
|
45
|
-
</style>`:""];return{html:Bt(r,{headTags:W,headEnd:[R,...k].filter(Boolean).join(`
|
|
46
|
-
`),body:l.html,depth:Number.isInteger(n.depth)?n.depth:0,bootScripts:s?ct(l):""}),route:e,brKeyCount:E,shell:!0}}return{html:`<!DOCTYPE html>
|
|
36
|
+
<script type="module" src="${B}${a.clientScript}"><\/script>`}const F={...e.config||{}};e.polyglot&&!F.polyglot&&(F.polyglot=e.polyglot);const C=F.polyglot;let N=h;if(C){const b=C.defaultLang||"en",q={...C.translations||{},...i.ssrTranslations||{}}[b]||{};N=h.replace(/\{\{\s*([^|{}]+?)\s*\|\s*polyglot\s*\}\}/g,(U,O)=>{const Y=O.trim();return q[Y]??U})}return typeof r=="string"?{html:Ee(r,{headTags:N,headEnd:[Z,S,R].filter(Boolean).join(`
|
|
37
|
+
`),body:i.html,depth:Number.isInteger(o.depth)?o.depth:0,bootScripts:s?x:""}),route:t,brKeyCount:k,shell:!0}:{html:`<!DOCTYPE html>
|
|
47
38
|
<html lang="${f}">
|
|
48
39
|
<head>
|
|
49
|
-
${
|
|
50
|
-
${
|
|
51
|
-
|
|
52
|
-
<style data-brender>
|
|
53
|
-
${m.rootRule||""}
|
|
54
|
-
${m.resetRules||""}
|
|
55
|
-
${m.keyframeRules||""}
|
|
56
|
-
</style>
|
|
57
|
-
${S?`<style data-emotion="smbls">
|
|
40
|
+
${N}
|
|
41
|
+
${Z}
|
|
42
|
+
|
|
58
43
|
${S}
|
|
59
|
-
|
|
44
|
+
${R}
|
|
60
45
|
</head>
|
|
61
46
|
<body>
|
|
62
|
-
${
|
|
63
|
-
${
|
|
47
|
+
${i.html}
|
|
48
|
+
${j}
|
|
64
49
|
</body>
|
|
65
|
-
</html>`,route:
|
|
66
|
-
`)
|
|
67
|
-
`);r.push(`@keyframes ${s} {
|
|
68
|
-
${l}
|
|
69
|
-
}`)}return[...r,...i].join(`
|
|
70
|
-
`)},Lt=t=>{if(!t)return"";const e=t.font_family||t.fontFamily||{},n=new Set;for(const i of Object.values(e)){if(typeof i!="string")continue;const c=i.match(/'([^']+)'/);c&&n.add(c[1])}return n.size?['<link rel="preconnect" href="https://fonts.googleapis.com">','<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>',`<link href="https://fonts.googleapis.com/css2?${[...n].map(i=>`family=${i.replace(/\s+/g,"+")}:wght@300;400;500;600;700`).join("&")}&display=swap" rel="stylesheet">`].join(`
|
|
71
|
-
`):""};export{gt as SMBLS_SSR_SPECIFIER,ct as adoptionScripts,Be as getAccumulatedEmotionCSS,wt as render,ve as renderElement,We as renderPage,Ne as renderRoute,Fe as replaceEmotionCSS,Me as resetGlobalCSSCache,De as skinRulesToCSS,ie as splitCapturedCSS};
|
|
50
|
+
</html>`,route:t,brKeyCount:k}},Se=e=>{if(!e)return"";const t=e.font_family||e.fontFamily||{},o=new Set;for(const l of Object.values(t)){if(typeof l!="string")continue;const a=l.match(/'([^']+)'/);a&&o.add(a[1])}return o.size?['<link rel="preconnect" href="https://fonts.googleapis.com">','<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>',`<link href="https://fonts.googleapis.com/css2?${[...o].map(l=>`family=${l.replace(/\s+/g,"+")}:wght@300;400;500;600;700`).join("&")}&display=swap" rel="stylesheet">`].join(`
|
|
51
|
+
`):""};export{me as SMBLS_SSR_SPECIFIER,Ve as adoptionScripts,Et as getAccumulatedEmotionCSS,he as render,vt as renderElement,qt as renderPage,Ct as renderRoute,Lt as replaceEmotionCSS,Tt as resetGlobalCSSCache,tt as splitCapturedCSS};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbo.ls/brender",
|
|
3
|
-
"version": "3.14.
|
|
3
|
+
"version": "3.14.664",
|
|
4
4
|
"license": "CC-BY-NC-4.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -46,18 +46,18 @@
|
|
|
46
46
|
"prepublishOnly": "npm run build"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@symbo.ls/css": "^3.14.
|
|
49
|
+
"@symbo.ls/css": "^3.14.777",
|
|
50
50
|
"@symbo.ls/default-config": "^3.14.785",
|
|
51
|
-
"@symbo.ls/element": "^3.14.
|
|
52
|
-
"@symbo.ls/fetch": "^3.14.
|
|
53
|
-
"@symbo.ls/helmet": "^3.14.
|
|
54
|
-
"@symbo.ls/scratch": "^3.14.
|
|
55
|
-
"@symbo.ls/utils": "^3.14.
|
|
51
|
+
"@symbo.ls/element": "^3.14.803",
|
|
52
|
+
"@symbo.ls/fetch": "^3.14.664",
|
|
53
|
+
"@symbo.ls/helmet": "^3.14.670",
|
|
54
|
+
"@symbo.ls/scratch": "^3.14.788",
|
|
55
|
+
"@symbo.ls/utils": "^3.14.786",
|
|
56
56
|
"esbuild": "^0.28.1",
|
|
57
57
|
"linkedom": "^0.16.8"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"smbls": "^3.14.
|
|
60
|
+
"smbls": "^3.14.833"
|
|
61
61
|
},
|
|
62
62
|
"optionalDependencies": {
|
|
63
63
|
"@symbo.ls/funcql": "^3.14.0"
|
package/render.js
CHANGED
|
@@ -11,6 +11,8 @@ import { hydrate } from './hydrate.js'
|
|
|
11
11
|
import { composeIntoShell } from './shell.js'
|
|
12
12
|
import { prefetchPageData, injectPrefetchedState, fetchSSRTranslations } from './prefetch.js'
|
|
13
13
|
import { createEarlySeedScript } from '@symbo.ls/fetch'
|
|
14
|
+
import { headerEntries } from '@symbo.ls/fetch/rest'
|
|
15
|
+
import { jsonForScript } from '@symbo.ls/utils'
|
|
14
16
|
|
|
15
17
|
// funcql plugin — enables evaluation of funcql schemas as property values
|
|
16
18
|
// during SSR. Async-imported to avoid polluting non-funcql codepaths.
|
|
@@ -290,18 +292,10 @@ const bundleCreateDomql = async () => {
|
|
|
290
292
|
|
|
291
293
|
const ws = detectWorkspace()
|
|
292
294
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
_cachedCreateDomql = await importSmblsSsr()
|
|
296
|
-
return _cachedCreateDomql
|
|
297
|
-
} catch (err) {
|
|
298
|
-
throw new Error(`brender: ${SMBLS_SSR_SPECIFIER} is not available in this bundled runtime (${err.message}). Bundle smbls ≥ the release that adds the smbls/ssr export alongside @symbo.ls/brender.`)
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Resolve entry point
|
|
295
|
+
// Resolve entry point: the monorepo's source, else `smbls/ssr` (one import
|
|
296
|
+
// for both a bundled runtime and an installed smbls).
|
|
303
297
|
let entry
|
|
304
|
-
if (ws.isMonorepo) {
|
|
298
|
+
if (_brenderRequire && ws.isMonorepo) {
|
|
305
299
|
entry = resolve(ws.monorepoRoot, 'packages', 'smbls', 'src', 'createDomql.js')
|
|
306
300
|
} else {
|
|
307
301
|
let ssrError
|
|
@@ -311,6 +305,9 @@ const bundleCreateDomql = async () => {
|
|
|
311
305
|
} catch (err) {
|
|
312
306
|
ssrError = err
|
|
313
307
|
}
|
|
308
|
+
if (!_brenderRequire) {
|
|
309
|
+
throw new Error(`brender: ${SMBLS_SSR_SPECIFIER} is not available in this bundled runtime (${ssrError.message}). Bundle smbls ≥ the release that adds the smbls/ssr export alongside @symbo.ls/brender.`)
|
|
310
|
+
}
|
|
314
311
|
// Legacy: an smbls that predates the ssr entry but still ships its source.
|
|
315
312
|
const srcEntry = ws.smblsRoot && resolve(ws.smblsRoot, 'src', 'createDomql.js')
|
|
316
313
|
if (srcEntry && existsSync(srcEntry)) {
|
|
@@ -630,24 +627,23 @@ const UIKIT_STUBS = {
|
|
|
630
627
|
*
|
|
631
628
|
* The registry is serialized into the pre-rendered HTML so the browser can
|
|
632
629
|
* assign the correct brKey to each skeleton element during true hydration.
|
|
630
|
+
* A path is @symbo.ls/element elementPath — the very function the hydrating
|
|
631
|
+
* client looks each element up with (adoptHydrationNode), so the two sides
|
|
632
|
+
* cannot spell a path differently. One flat object, filled in place (the
|
|
633
|
+
* recursive walk merged a fresh object per element into its parent's).
|
|
633
634
|
*/
|
|
634
|
-
const buildPathRegistry = (element,
|
|
635
|
-
if (!element || !element.__ref) return {}
|
|
635
|
+
const buildPathRegistry = (element, elementPath) => {
|
|
636
636
|
const registry = {}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const child = element[childKey]
|
|
644
|
-
if (child && child.__ref) {
|
|
645
|
-
const childPath = path === '' ? childKey : `${path}.${childKey}`
|
|
646
|
-
Object.assign(registry, buildPathRegistry(child, childPath))
|
|
647
|
-
}
|
|
637
|
+
const walk = (el) => {
|
|
638
|
+
const ref = el && el.__ref
|
|
639
|
+
if (!ref) return
|
|
640
|
+
if (ref.__brKey) {
|
|
641
|
+
const path = elementPath(el)
|
|
642
|
+
registry[path === '' ? '__root' : path] = ref.__brKey
|
|
648
643
|
}
|
|
644
|
+
if (ref.__children) for (const childKey of ref.__children) walk(el[childKey])
|
|
649
645
|
}
|
|
650
|
-
|
|
646
|
+
walk(element)
|
|
651
647
|
return registry
|
|
652
648
|
}
|
|
653
649
|
|
|
@@ -666,6 +662,15 @@ const buildPathRegistry = (element, path = '') => {
|
|
|
666
662
|
* @param {object} [options.context] - Additional context overrides
|
|
667
663
|
* @returns {Promise<{ html: string, metadata: object, registry: object, element: object }>}
|
|
668
664
|
*/
|
|
665
|
+
// The payload keys render() puts on the context itself (below `ctx`): the
|
|
666
|
+
// generic copy of every other top-level key skips them — cloning one only for
|
|
667
|
+
// the explicit key to replace it was a deep clone of `functions`, `methods`
|
|
668
|
+
// and `files` thrown away on every render.
|
|
669
|
+
const CONTEXT_KEYS_SET_BELOW = new Set([
|
|
670
|
+
'app', 'config', 'pages', 'components', 'state', 'snippets', 'designSystem', 'dependencies',
|
|
671
|
+
'functions', 'methods', 'files', 'sharedLibraries'
|
|
672
|
+
])
|
|
673
|
+
|
|
669
674
|
// ── In-flight request tracking (the post-create flush) ──────────────────────
|
|
670
675
|
// The render's flush waits for the requests a page starts while it renders
|
|
671
676
|
// (fetch plugin, SDK, project code — all end in globalThis.fetch). One
|
|
@@ -701,11 +706,15 @@ const requestShape = (args) => {
|
|
|
701
706
|
const url = isRequest ? input.url : String(input)
|
|
702
707
|
const method = String((init && init.method) || (isRequest && input.method) || 'GET').toUpperCase()
|
|
703
708
|
const headers = {}
|
|
709
|
+
// Any fetch HeadersInit, read like the REST adapter reads one (headerEntries).
|
|
710
|
+
// A plain object's null / undefined value is no header.
|
|
704
711
|
const add = (h) => {
|
|
705
712
|
if (!h) return
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
713
|
+
const plain = !Array.isArray(h) && typeof h.entries !== 'function'
|
|
714
|
+
for (const [k, v] of headerEntries(h)) {
|
|
715
|
+
if (plain && v == null) continue
|
|
716
|
+
headers[String(k).toLowerCase()] = String(v)
|
|
717
|
+
}
|
|
709
718
|
}
|
|
710
719
|
if (isRequest) add(input.headers)
|
|
711
720
|
if (init) add(init.headers)
|
|
@@ -769,9 +778,14 @@ const trackFetches = () => {
|
|
|
769
778
|
// (@symbo.ls/fetch createEarlySeedScript). Default off everywhere — a page
|
|
770
779
|
// without these keeps the fresh client render.
|
|
771
780
|
// FW-BRENDER-HYDRATION-AND-CF-DEPLOY-PROVIDER-1.
|
|
772
|
-
|
|
781
|
+
// `hydrateFlag: false` — the registry alone, for a client that replaces the
|
|
782
|
+
// server DOM but still reads the registry (renderPage's default ISR path). It
|
|
783
|
+
// inlined its own JSON.stringify there, without the `<` escape, so an element
|
|
784
|
+
// key carrying `</script>` closed the tag.
|
|
785
|
+
export const adoptionScripts = ({ brRegistry, fetchSeed, hydrateFlag = true } = {}) => {
|
|
773
786
|
if (!brRegistry || !Object.keys(brRegistry).length) return ''
|
|
774
|
-
const registry =
|
|
787
|
+
const registry = jsonForScript(brRegistry)
|
|
788
|
+
if (!hydrateFlag) return `<script>window.__BR_REGISTRY__=${registry}</script>`
|
|
775
789
|
return `<script>window.__BR_REGISTRY__=${registry};window.__BRENDER_HYDRATE__=true</script>` +
|
|
776
790
|
(fetchSeed && fetchSeed.length ? '\n' + createEarlySeedScript(fetchSeed) : '')
|
|
777
791
|
}
|
|
@@ -913,8 +927,7 @@ export const render = async (data, options = {}) => {
|
|
|
913
927
|
// build reuses. The explicit keys below still win.
|
|
914
928
|
const projectContext = {}
|
|
915
929
|
for (const key in data) {
|
|
916
|
-
if (key
|
|
917
|
-
key === 'state' || key === 'snippets' || key === 'designSystem' || key === 'dependencies') continue
|
|
930
|
+
if (CONTEXT_KEYS_SET_BELOW.has(key)) continue
|
|
918
931
|
const value = data[key]
|
|
919
932
|
projectContext[key] = value && typeof value === 'object' ? structuredCloneDeep(value) : value
|
|
920
933
|
}
|
|
@@ -1001,8 +1014,9 @@ export const render = async (data, options = {}) => {
|
|
|
1001
1014
|
const sleep = (ms) => new Promise(r => setTimeout(r, ms))
|
|
1002
1015
|
await sleep(Math.min(50, flushCap))
|
|
1003
1016
|
while (prefetch && inFlightRequests() > 0 && Date.now() - flushStart < flushCap) {
|
|
1004
|
-
|
|
1005
|
-
|
|
1017
|
+
await sleep(10)
|
|
1018
|
+
// a settled batch: another quiet period for what it triggers
|
|
1019
|
+
if (inFlightRequests() === 0) await sleep(Math.max(0, Math.min(50, flushCap - (Date.now() - flushStart))))
|
|
1006
1020
|
}
|
|
1007
1021
|
} finally {
|
|
1008
1022
|
_activeRenders--
|
|
@@ -1017,7 +1031,8 @@ export const render = async (data, options = {}) => {
|
|
|
1017
1031
|
|
|
1018
1032
|
// Build element path → brKey registry for client-side true hydration.
|
|
1019
1033
|
// Walks the element tree after mapKeysToElements has set __brKey on each element.
|
|
1020
|
-
const
|
|
1034
|
+
const { elementPath } = await import('@symbo.ls/element')
|
|
1035
|
+
const brRegistry = buildPathRegistry(element, elementPath)
|
|
1021
1036
|
|
|
1022
1037
|
// Extract metadata for the rendered route
|
|
1023
1038
|
// Pass the rendered element and its state so function-valued metadata
|
|
@@ -1025,28 +1040,22 @@ export const render = async (data, options = {}) => {
|
|
|
1025
1040
|
const metadata = extractMetadata(data, route, element, element?.state)
|
|
1026
1041
|
|
|
1027
1042
|
// Extract CSS from style tags in virtual head (atomic CSS engine writes here)
|
|
1028
|
-
const emotionCSS = []
|
|
1029
1043
|
const capturedRules = []
|
|
1030
1044
|
const head = document.head || document.querySelector('head')
|
|
1031
1045
|
if (head) {
|
|
1032
1046
|
for (const style of head.querySelectorAll('style')) {
|
|
1033
1047
|
if (style.sheet && style.sheet.cssRules) {
|
|
1034
1048
|
for (const rule of style.sheet.cssRules) {
|
|
1035
|
-
if (rule.cssText)
|
|
1036
|
-
emotionCSS.push(rule.cssText)
|
|
1037
|
-
capturedRules.push(rule)
|
|
1038
|
-
}
|
|
1049
|
+
if (rule.cssText) capturedRules.push(rule)
|
|
1039
1050
|
}
|
|
1040
1051
|
}
|
|
1041
|
-
if (!
|
|
1052
|
+
if (!capturedRules.length) {
|
|
1042
1053
|
const content = style.textContent || ''
|
|
1043
|
-
if (content) {
|
|
1044
|
-
emotionCSS.push(content)
|
|
1045
|
-
capturedRules.push({ cssText: content })
|
|
1046
|
-
}
|
|
1054
|
+
if (content) capturedRules.push({ cssText: content })
|
|
1047
1055
|
}
|
|
1048
1056
|
}
|
|
1049
1057
|
}
|
|
1058
|
+
const emotionCSS = capturedRules.map((rule) => rule.cssText)
|
|
1050
1059
|
// globalCSS: the init-injected globals; classRules: everything else, in
|
|
1051
1060
|
// capture order (see splitCapturedCSS).
|
|
1052
1061
|
const { globalCSS, classRules } = splitCapturedCSS(capturedRules)
|
|
@@ -1156,27 +1165,6 @@ const SCRATCH_CONFIG_FLAGS = [
|
|
|
1156
1165
|
'useDocumentTheme', 'useDefaultConfig', 'useDefaultIcons',
|
|
1157
1166
|
'useThemeSuffixedVars', 'verbose', 'semanticIcons',
|
|
1158
1167
|
]
|
|
1159
|
-
// Serialise scratch `buildSkinVarStyles` output — `{ selector: { var: value },
|
|
1160
|
-
// '@media …': { selector: { var: value } } }` — as CSS text
|
|
1161
|
-
// (FW-SCRATCH-SKINS-DIMENSION-1).
|
|
1162
|
-
const declarationBlock = (selector, vars, indent) => {
|
|
1163
|
-
const decls = Object.entries(vars || {})
|
|
1164
|
-
.map(([k, v]) => `${indent} ${k}: ${v}`)
|
|
1165
|
-
.join(';\n')
|
|
1166
|
-
return decls ? `${indent}${selector} {\n${decls};\n${indent}}` : ''
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
export const skinRulesToCSS = (rules) => Object.entries(rules || {})
|
|
1170
|
-
.map(([key, body]) => {
|
|
1171
|
-
if (!key.startsWith('@')) return declarationBlock(key, body, '')
|
|
1172
|
-
const inner = Object.entries(body || {})
|
|
1173
|
-
.map(([selector, vars]) => declarationBlock(selector, vars, ' '))
|
|
1174
|
-
.filter(Boolean)
|
|
1175
|
-
.join('\n')
|
|
1176
|
-
return inner ? `${key} {\n${inner}\n}` : ''
|
|
1177
|
-
})
|
|
1178
|
-
.filter(Boolean)
|
|
1179
|
-
.join('\n\n')
|
|
1180
1168
|
|
|
1181
1169
|
// ── Global CSS: the render's own capture, split ────────────────────────────
|
|
1182
1170
|
// The rules smbls init injects into the virtual <head> during render() ARE
|
|
@@ -1432,15 +1420,21 @@ export const renderPage = async (data, route = '/', options = {}) => {
|
|
|
1432
1420
|
}
|
|
1433
1421
|
const emotionCSS = Array.from(_accumulatedEmotionCSS).join('\n')
|
|
1434
1422
|
|
|
1435
|
-
// Global CSS (variables, reset, keyframes): this render's own init output
|
|
1436
|
-
|
|
1423
|
+
// Global CSS (variables, reset, keyframes): this render's own init output.
|
|
1424
|
+
// The style tags, built once for both documents below.
|
|
1437
1425
|
const globalCSS = result.globalCSS
|
|
1426
|
+
const brenderStyle = `<style data-brender>\n${globalCSS.rootRule || ''}\n${globalCSS.resetRules || ''}\n${globalCSS.keyframeRules || ''}\n</style>`
|
|
1427
|
+
const emotionStyle = emotionCSS ? `<style data-emotion="smbls">\n${emotionCSS}\n</style>` : ''
|
|
1438
1428
|
|
|
1439
1429
|
// Generate font links from design system
|
|
1440
|
-
const fontLinks = generateFontLinks(
|
|
1430
|
+
const fontLinks = generateFontLinks(data.designSystem || {})
|
|
1441
1431
|
|
|
1442
1432
|
const brKeyCount = Object.keys(result.registry).length
|
|
1443
1433
|
|
|
1434
|
+
// The element-path registry — with the opt-in hydration flag and the
|
|
1435
|
+
// recorded fetch answers under `adoptDom` (adoptionScripts).
|
|
1436
|
+
const bootScripts = adoptionScripts({ brRegistry: result.brRegistry, fetchSeed: result.fetchSeed, hydrateFlag: adoptDom })
|
|
1437
|
+
|
|
1444
1438
|
// ISR: include client SPA bundle for hydration + data fetching
|
|
1445
1439
|
let isrBody = ''
|
|
1446
1440
|
if (isr && isr.clientScript) {
|
|
@@ -1481,14 +1475,7 @@ export const renderPage = async (data, route = '/', options = {}) => {
|
|
|
1481
1475
|
}
|
|
1482
1476
|
}
|
|
1483
1477
|
// Embed BR registry for true DOM-adoption hydration
|
|
1484
|
-
const
|
|
1485
|
-
? JSON.stringify(result.brRegistry)
|
|
1486
|
-
: null
|
|
1487
|
-
const brRegistryScript = adoptDom
|
|
1488
|
-
? (adoptionScripts(result) ? adoptionScripts(result) + '\n' : '')
|
|
1489
|
-
: brRegistryJson
|
|
1490
|
-
? `<script>window.__BR_REGISTRY__=${brRegistryJson}</script>\n`
|
|
1491
|
-
: ''
|
|
1478
|
+
const brRegistryScript = bootScripts ? bootScripts + '\n' : ''
|
|
1492
1479
|
isrBody = `${translationSeed}${brRegistryScript}<script>window.__BRENDER__=true</script>
|
|
1493
1480
|
<script type="module" src="${prefix}${isr.clientScript}"></script>`
|
|
1494
1481
|
} else {
|
|
@@ -1538,33 +1525,26 @@ export const renderPage = async (data, route = '/', options = {}) => {
|
|
|
1538
1525
|
// client bundle, so writing it over a bundler's dist/index.html shipped
|
|
1539
1526
|
// pages that never booted.
|
|
1540
1527
|
if (typeof shell === 'string') {
|
|
1541
|
-
const styles = [
|
|
1542
|
-
globalCSS.fontFaceCSS ? `<style data-brender>${globalCSS.fontFaceCSS}</style>` : '',
|
|
1543
|
-
`<style data-brender>\n${globalCSS.rootRule || ''}\n${globalCSS.resetRules || ''}\n${globalCSS.keyframeRules || ''}\n</style>`,
|
|
1544
|
-
emotionCSS ? `<style data-emotion="smbls">\n${emotionCSS}\n</style>` : ''
|
|
1545
|
-
]
|
|
1546
1528
|
const html = composeIntoShell(shell, {
|
|
1547
1529
|
headTags: resolvedHeadTags,
|
|
1548
|
-
headEnd: [fontLinks,
|
|
1530
|
+
headEnd: [fontLinks, brenderStyle, emotionStyle].filter(Boolean).join('\n'),
|
|
1549
1531
|
body: result.html,
|
|
1550
1532
|
depth: Number.isInteger(options.depth) ? options.depth : 0,
|
|
1551
|
-
bootScripts: adoptDom ?
|
|
1533
|
+
bootScripts: adoptDom ? bootScripts : ''
|
|
1552
1534
|
})
|
|
1553
1535
|
return { html, route, brKeyCount, shell: true }
|
|
1554
1536
|
}
|
|
1555
1537
|
|
|
1538
|
+
// (The empty line after the font links held a @font-face <style> that
|
|
1539
|
+
// splitCapturedCSS never fills — @font-face stays in the class stream.)
|
|
1556
1540
|
const html = `<!DOCTYPE html>
|
|
1557
1541
|
<html lang="${htmlLang}">
|
|
1558
1542
|
<head>
|
|
1559
1543
|
${resolvedHeadTags}
|
|
1560
1544
|
${fontLinks}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
${
|
|
1564
|
-
${globalCSS.resetRules || ''}
|
|
1565
|
-
${globalCSS.keyframeRules || ''}
|
|
1566
|
-
</style>
|
|
1567
|
-
${emotionCSS ? `<style data-emotion="smbls">\n${emotionCSS}\n</style>` : ''}
|
|
1545
|
+
|
|
1546
|
+
${brenderStyle}
|
|
1547
|
+
${emotionStyle}
|
|
1568
1548
|
</head>
|
|
1569
1549
|
<body>
|
|
1570
1550
|
${result.html}
|
|
@@ -1575,398 +1555,6 @@ ${isrBody}
|
|
|
1575
1555
|
return { html, route, brKeyCount }
|
|
1576
1556
|
}
|
|
1577
1557
|
|
|
1578
|
-
// ── Design system token resolution ──────────────────────────────────────────
|
|
1579
|
-
|
|
1580
|
-
const LETTER_TO_INDEX = {
|
|
1581
|
-
U: -6, V: -5, W: -4, X: -3, Y: -2, Z: -1,
|
|
1582
|
-
A: 0, B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9,
|
|
1583
|
-
K: 10, L: 11, M: 12, N: 13, O: 14, P: 15
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
const SPACING_PROPS = new Set([
|
|
1587
|
-
'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft',
|
|
1588
|
-
'paddingBlock', 'paddingInline', 'paddingBlockStart', 'paddingBlockEnd',
|
|
1589
|
-
'paddingInlineStart', 'paddingInlineEnd',
|
|
1590
|
-
'margin', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft',
|
|
1591
|
-
'marginBlock', 'marginInline', 'marginBlockStart', 'marginBlockEnd',
|
|
1592
|
-
'marginInlineStart', 'marginInlineEnd',
|
|
1593
|
-
'gap', 'rowGap', 'columnGap',
|
|
1594
|
-
'top', 'right', 'bottom', 'left',
|
|
1595
|
-
'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight',
|
|
1596
|
-
'flexBasis', 'fontSize', 'lineHeight', 'letterSpacing',
|
|
1597
|
-
'borderWidth', 'borderRadius', 'outlineWidth', 'outlineOffset',
|
|
1598
|
-
'inset', 'insetBlock', 'insetInline',
|
|
1599
|
-
'boxSize', 'round'
|
|
1600
|
-
])
|
|
1601
|
-
|
|
1602
|
-
/**
|
|
1603
|
-
* Resolves a spacing token like 'B2', 'A', 'E3' to a px/em value.
|
|
1604
|
-
* Uses base * ratio^index for main steps (A=0, B=1, etc.)
|
|
1605
|
-
* and sub-ratio interpolation for sub-steps (B1, B2, B3).
|
|
1606
|
-
*/
|
|
1607
|
-
const resolveSpacingToken = (token, spacingConfig) => {
|
|
1608
|
-
if (!token || typeof token !== 'string') return null
|
|
1609
|
-
if (!spacingConfig) return null
|
|
1610
|
-
|
|
1611
|
-
const base = spacingConfig.base || 16
|
|
1612
|
-
const ratio = spacingConfig.ratio || 1.618
|
|
1613
|
-
const unit = spacingConfig.unit || 'px'
|
|
1614
|
-
const hasSubSequence = spacingConfig.subSequence !== false
|
|
1615
|
-
|
|
1616
|
-
// Handle compound values like 'B2 - -' or 'A1 B C1'
|
|
1617
|
-
if (token.includes(' ')) {
|
|
1618
|
-
const parts = token.split(' ').map(part => {
|
|
1619
|
-
if (part === '-' || part === '') return part
|
|
1620
|
-
return resolveSpacingToken(part, spacingConfig) || part
|
|
1621
|
-
})
|
|
1622
|
-
return parts.join(' ')
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
|
-
// Skip CSS keywords and values with units
|
|
1626
|
-
if (/^(none|auto|inherit|initial|unset|0)$/i.test(token)) return null
|
|
1627
|
-
if (/\d+(px|em|rem|%|vh|vw|vmin|vmax|ch|ex|cm|mm|in|pt|pc|fr|s|ms)$/i.test(token)) return null
|
|
1628
|
-
// Skip hex colors, rgb(), etc.
|
|
1629
|
-
if (/^(#|rgb|hsl|var\()/i.test(token)) return null
|
|
1630
|
-
|
|
1631
|
-
const isNegative = token.startsWith('-')
|
|
1632
|
-
const abs = isNegative ? token.slice(1) : token
|
|
1633
|
-
|
|
1634
|
-
// Match letter + optional digit: A, B, B2, E3, etc.
|
|
1635
|
-
const m = abs.match(/^([A-Z])(\d)?$/i)
|
|
1636
|
-
if (!m) return null
|
|
1637
|
-
|
|
1638
|
-
const letter = m[1].toUpperCase()
|
|
1639
|
-
const subStep = m[2] ? parseInt(m[2]) : 0
|
|
1640
|
-
const idx = LETTER_TO_INDEX[letter]
|
|
1641
|
-
if (idx === undefined) return null
|
|
1642
|
-
|
|
1643
|
-
let value = base * Math.pow(ratio, idx)
|
|
1644
|
-
|
|
1645
|
-
if (subStep > 0 && hasSubSequence) {
|
|
1646
|
-
const next = base * Math.pow(ratio, idx + 1)
|
|
1647
|
-
const diff = next - value
|
|
1648
|
-
const subRatio = diff / ratio
|
|
1649
|
-
// Sub-steps: 1 = value + (diff - subRatio), 2 = midpoint, 3 = value + subRatio
|
|
1650
|
-
const first = next - subRatio
|
|
1651
|
-
const second = value + subRatio
|
|
1652
|
-
const middle = (first + second) / 2
|
|
1653
|
-
const subs = (~~next - ~~value > 16) ? [first, middle, second] : [first, second]
|
|
1654
|
-
if (subStep <= subs.length) {
|
|
1655
|
-
value = subs[subStep - 1]
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
|
|
1659
|
-
const rounded = Math.round(value * 100) / 100
|
|
1660
|
-
const sign = isNegative ? '-' : ''
|
|
1661
|
-
return `${sign}${rounded}${unit}`
|
|
1662
|
-
}
|
|
1663
|
-
|
|
1664
|
-
// Kebab-case versions of spacing props for post-shorthand resolution
|
|
1665
|
-
const SPACING_PROPS_KEBAB = new Set(
|
|
1666
|
-
[...SPACING_PROPS].map(k => k.replace(/[A-Z]/g, m => '-' + m.toLowerCase()))
|
|
1667
|
-
)
|
|
1668
|
-
|
|
1669
|
-
/**
|
|
1670
|
-
* Try to resolve a CSS value through the design system.
|
|
1671
|
-
* Returns the resolved value or the original if not a token.
|
|
1672
|
-
*/
|
|
1673
|
-
const resolveDSValue = (key, val, ds) => {
|
|
1674
|
-
if (typeof val !== 'string') return val
|
|
1675
|
-
|
|
1676
|
-
// Color resolution
|
|
1677
|
-
if (CSS_COLOR_PROPS.has(key)) {
|
|
1678
|
-
const colorMap = ds?.color || {}
|
|
1679
|
-
if (colorMap[val]) return colorMap[val]
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
// Spacing resolution (check both camelCase and kebab-case keys)
|
|
1683
|
-
if (SPACING_PROPS.has(key) || SPACING_PROPS_KEBAB.has(key)) {
|
|
1684
|
-
const spacing = ds?.spacing || {}
|
|
1685
|
-
const resolved = resolveSpacingToken(val, spacing)
|
|
1686
|
-
if (resolved) return resolved
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
return val
|
|
1690
|
-
}
|
|
1691
|
-
|
|
1692
|
-
// ── CSS helpers ─────────────────────────────────────────────────────────────
|
|
1693
|
-
|
|
1694
|
-
const CSS_COLOR_PROPS = new Set([
|
|
1695
|
-
'color', 'background', 'backgroundColor', 'borderColor',
|
|
1696
|
-
'borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor',
|
|
1697
|
-
'outlineColor', 'fill', 'stroke'
|
|
1698
|
-
])
|
|
1699
|
-
|
|
1700
|
-
const NON_CSS_PROPS = new Set([
|
|
1701
|
-
'href', 'src', 'alt', 'title', 'id', 'name', 'type', 'value', 'placeholder',
|
|
1702
|
-
'target', 'rel', 'loading', 'srcset', 'sizes', 'media', 'role', 'tabindex',
|
|
1703
|
-
'for', 'action', 'method', 'enctype', 'autocomplete', 'autofocus',
|
|
1704
|
-
'theme', '__element', 'update',
|
|
1705
|
-
'childrenAs', 'childExtends', 'childProps', 'children'
|
|
1706
|
-
])
|
|
1707
|
-
|
|
1708
|
-
const camelToKebab = (str) => str.replace(/[A-Z]/g, m => '-' + m.toLowerCase())
|
|
1709
|
-
|
|
1710
|
-
const resolveShorthand = (key, val) => {
|
|
1711
|
-
if (typeof val === 'undefined' || val === null) return null
|
|
1712
|
-
|
|
1713
|
-
// Flex shorthands
|
|
1714
|
-
if (key === 'flow' && typeof val === 'string') {
|
|
1715
|
-
let [direction, wrap] = (val || 'row').split(' ')
|
|
1716
|
-
if (val.startsWith('x') || val === 'row') direction = 'row'
|
|
1717
|
-
if (val.startsWith('y') || val === 'column') direction = 'column'
|
|
1718
|
-
return { display: 'flex', 'flex-flow': (direction || '') + ' ' + (wrap || '') }
|
|
1719
|
-
}
|
|
1720
|
-
if (key === 'wrap') {
|
|
1721
|
-
return { display: 'flex', 'flex-wrap': val }
|
|
1722
|
-
}
|
|
1723
|
-
if ((key === 'align' || key === 'flexAlign') && typeof val === 'string') {
|
|
1724
|
-
const [alignItems, justifyContent] = val.split(' ')
|
|
1725
|
-
const result = { display: 'flex', 'align-items': alignItems }
|
|
1726
|
-
if (justifyContent) result['justify-content'] = justifyContent
|
|
1727
|
-
return result
|
|
1728
|
-
}
|
|
1729
|
-
if (key === 'gridAlign' && typeof val === 'string') {
|
|
1730
|
-
const [alignItems, justifyContent] = val.split(' ')
|
|
1731
|
-
const result = { display: 'grid', 'align-items': alignItems }
|
|
1732
|
-
if (justifyContent) result['justify-content'] = justifyContent
|
|
1733
|
-
return result
|
|
1734
|
-
}
|
|
1735
|
-
if (key === 'flexFlow' && typeof val === 'string') {
|
|
1736
|
-
let [direction, wrap] = (val || 'row').split(' ')
|
|
1737
|
-
if (val.startsWith('x') || val === 'row') direction = 'row'
|
|
1738
|
-
if (val.startsWith('y') || val === 'column') direction = 'column'
|
|
1739
|
-
return { display: 'flex', 'flex-flow': (direction || '') + ' ' + (wrap || '') }
|
|
1740
|
-
}
|
|
1741
|
-
if (key === 'flexWrap') {
|
|
1742
|
-
return { display: 'flex', 'flex-wrap': val }
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
|
-
// Background image shorthand
|
|
1746
|
-
if (key === 'backgroundImage' && typeof val === 'string' && !val.startsWith('url(') && !val.startsWith('linear-gradient') && !val.startsWith('radial-gradient') && !val.startsWith('none')) {
|
|
1747
|
-
return { 'background-image': `url(${val})` }
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
// Box/size shorthands
|
|
1751
|
-
if (key === 'round' || (key === 'borderRadius' && val)) {
|
|
1752
|
-
return { 'border-radius': typeof val === 'number' ? val + 'px' : val }
|
|
1753
|
-
}
|
|
1754
|
-
if (key === 'boxSize' && typeof val === 'string') {
|
|
1755
|
-
const [height, width] = val.split(' ')
|
|
1756
|
-
return { height, width: width || height }
|
|
1757
|
-
}
|
|
1758
|
-
if (key === 'widthRange' && typeof val === 'string') {
|
|
1759
|
-
const [minWidth, maxWidth] = val.split(' ')
|
|
1760
|
-
return { 'min-width': minWidth, 'max-width': maxWidth || minWidth }
|
|
1761
|
-
}
|
|
1762
|
-
if (key === 'heightRange' && typeof val === 'string') {
|
|
1763
|
-
const [minHeight, maxHeight] = val.split(' ')
|
|
1764
|
-
return { 'min-height': minHeight, 'max-height': maxHeight || minHeight }
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
// Grid aliases
|
|
1768
|
-
if (key === 'column') return { 'grid-column': val }
|
|
1769
|
-
if (key === 'columns') return { 'grid-template-columns': val }
|
|
1770
|
-
if (key === 'templateColumns') return { 'grid-template-columns': val }
|
|
1771
|
-
if (key === 'row') return { 'grid-row': val }
|
|
1772
|
-
if (key === 'rows') return { 'grid-template-rows': val }
|
|
1773
|
-
if (key === 'templateRows') return { 'grid-template-rows': val }
|
|
1774
|
-
if (key === 'area') return { 'grid-area': val }
|
|
1775
|
-
if (key === 'template') return { 'grid-template': val }
|
|
1776
|
-
if (key === 'templateAreas') return { 'grid-template-areas': val }
|
|
1777
|
-
if (key === 'autoColumns') return { 'grid-auto-columns': val }
|
|
1778
|
-
if (key === 'autoRows') return { 'grid-auto-rows': val }
|
|
1779
|
-
if (key === 'autoFlow') return { 'grid-auto-flow': val }
|
|
1780
|
-
if (key === 'columnStart') return { 'grid-column-start': val }
|
|
1781
|
-
if (key === 'rowStart') return { 'grid-row-start': val }
|
|
1782
|
-
|
|
1783
|
-
return null
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
const resolveInnerProps = (obj, ds) => {
|
|
1787
|
-
const result = {}
|
|
1788
|
-
for (const k in obj) {
|
|
1789
|
-
const v = obj[k]
|
|
1790
|
-
const expanded = resolveShorthand(k, v)
|
|
1791
|
-
if (expanded) {
|
|
1792
|
-
for (const ek in expanded) {
|
|
1793
|
-
result[ek] = resolveDSValue(ek, expanded[ek], ds)
|
|
1794
|
-
}
|
|
1795
|
-
continue
|
|
1796
|
-
}
|
|
1797
|
-
if (typeof v !== 'string' && typeof v !== 'number') continue
|
|
1798
|
-
result[camelToKebab(k)] = resolveDSValue(k, v, ds)
|
|
1799
|
-
}
|
|
1800
|
-
return result
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
const buildCSSFromProps = (props, ds, mediaMap) => {
|
|
1804
|
-
const base = {}
|
|
1805
|
-
const mediaRules = {}
|
|
1806
|
-
const pseudoRules = {}
|
|
1807
|
-
|
|
1808
|
-
for (const key in props) {
|
|
1809
|
-
const val = props[key]
|
|
1810
|
-
|
|
1811
|
-
if (key.charCodeAt(0) === 64 && typeof val === 'object') {
|
|
1812
|
-
const bp = mediaMap?.[key.slice(1)]
|
|
1813
|
-
if (bp) {
|
|
1814
|
-
const inner = resolveInnerProps(val, ds)
|
|
1815
|
-
if (Object.keys(inner).length) mediaRules[bp] = inner
|
|
1816
|
-
}
|
|
1817
|
-
continue
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
if (key.charCodeAt(0) === 58 && typeof val === 'object') {
|
|
1821
|
-
const inner = resolveInnerProps(val, ds)
|
|
1822
|
-
if (Object.keys(inner).length) pseudoRules[key] = inner
|
|
1823
|
-
continue
|
|
1824
|
-
}
|
|
1825
|
-
|
|
1826
|
-
if (typeof val !== 'string' && typeof val !== 'number') continue
|
|
1827
|
-
if (key.charCodeAt(0) >= 65 && key.charCodeAt(0) <= 90) continue
|
|
1828
|
-
if (NON_CSS_PROPS.has(key)) continue
|
|
1829
|
-
|
|
1830
|
-
const expanded = resolveShorthand(key, val)
|
|
1831
|
-
if (expanded) {
|
|
1832
|
-
for (const ek in expanded) {
|
|
1833
|
-
base[ek] = resolveDSValue(ek, expanded[ek], ds)
|
|
1834
|
-
}
|
|
1835
|
-
continue
|
|
1836
|
-
}
|
|
1837
|
-
|
|
1838
|
-
base[camelToKebab(key)] = resolveDSValue(key, val, ds)
|
|
1839
|
-
}
|
|
1840
|
-
|
|
1841
|
-
return { base, mediaRules, pseudoRules }
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
const renderCSSRule = (selector, { base, mediaRules, pseudoRules }) => {
|
|
1845
|
-
const lines = []
|
|
1846
|
-
const baseDecls = Object.entries(base).map(([k, v]) => `${k}: ${v}`).join('; ')
|
|
1847
|
-
if (baseDecls) lines.push(`${selector} { ${baseDecls}; }`)
|
|
1848
|
-
|
|
1849
|
-
for (const [pseudo, p] of Object.entries(pseudoRules)) {
|
|
1850
|
-
const decls = Object.entries(p).map(([k, v]) => `${k}: ${v}`).join('; ')
|
|
1851
|
-
if (decls) lines.push(`${selector}${pseudo} { ${decls}; }`)
|
|
1852
|
-
}
|
|
1853
|
-
|
|
1854
|
-
for (const [query, p] of Object.entries(mediaRules)) {
|
|
1855
|
-
const decls = Object.entries(p).map(([k, v]) => `${k}: ${v}`).join('; ')
|
|
1856
|
-
const mq = query.startsWith('@') ? query : `@media ${query}`
|
|
1857
|
-
if (decls) lines.push(`${mq} { ${selector} { ${decls}; } }`)
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1860
|
-
return lines.join('\n')
|
|
1861
|
-
}
|
|
1862
|
-
|
|
1863
|
-
// Map of component names to their implicit CSS from extends
|
|
1864
|
-
const EXTENDS_CSS = {
|
|
1865
|
-
Flex: { display: 'flex' },
|
|
1866
|
-
InlineFlex: { display: 'inline-flex' },
|
|
1867
|
-
Grid: { display: 'grid' },
|
|
1868
|
-
InlineGrid: { display: 'inline-grid' },
|
|
1869
|
-
Block: { display: 'block' },
|
|
1870
|
-
Inline: { display: 'inline' }
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
const getExtendsCSS = (el) => {
|
|
1874
|
-
const exts = el.__ref?.__extends
|
|
1875
|
-
if (!exts || !Array.isArray(exts)) return null
|
|
1876
|
-
for (const ext of exts) {
|
|
1877
|
-
if (EXTENDS_CSS[ext]) return EXTENDS_CSS[ext]
|
|
1878
|
-
}
|
|
1879
|
-
return null
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
/**
|
|
1883
|
-
* Resolve function-valued CSS props by evaluating them with (element, state).
|
|
1884
|
-
* In SSR, this gives correct initial values (e.g. display: 'none' when no auth).
|
|
1885
|
-
* Uses fallback mock state if element state is incomplete.
|
|
1886
|
-
*/
|
|
1887
|
-
const resolveElementProps = (el) => {
|
|
1888
|
-
let resolved
|
|
1889
|
-
for (const key in el) {
|
|
1890
|
-
if (typeof el[key] !== 'function') continue
|
|
1891
|
-
// Skip non-CSS props and component children
|
|
1892
|
-
if (NON_CSS_PROPS.has(key)) continue
|
|
1893
|
-
if (key.charCodeAt(0) >= 65 && key.charCodeAt(0) <= 90) continue
|
|
1894
|
-
if (key.startsWith('on')) continue
|
|
1895
|
-
if (key.startsWith('__')) continue
|
|
1896
|
-
if (!resolved) resolved = {}
|
|
1897
|
-
let result
|
|
1898
|
-
try {
|
|
1899
|
-
result = el[key](el, el.state || {})
|
|
1900
|
-
} catch {
|
|
1901
|
-
// State prototype chain may be incomplete in SSR — try with mock
|
|
1902
|
-
try {
|
|
1903
|
-
const mockState = { root: {}, ...(el.state || {}) }
|
|
1904
|
-
result = el[key](el, mockState)
|
|
1905
|
-
} catch { /* skip prop */ }
|
|
1906
|
-
}
|
|
1907
|
-
if (result !== undefined && result !== null && result !== false) {
|
|
1908
|
-
resolved[key] = result
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
return resolved || el
|
|
1912
|
-
}
|
|
1913
|
-
|
|
1914
|
-
const extractCSS = (element, ds) => {
|
|
1915
|
-
const mediaMap = ds?.media || {}
|
|
1916
|
-
const animations = ds?.animation || {}
|
|
1917
|
-
const rules = []
|
|
1918
|
-
const seen = new Set()
|
|
1919
|
-
const usedAnimations = new Set()
|
|
1920
|
-
|
|
1921
|
-
const walk = (el) => {
|
|
1922
|
-
if (!el || !el.__ref) return
|
|
1923
|
-
const props = resolveElementProps(el)
|
|
1924
|
-
if (props && el.node) {
|
|
1925
|
-
const cls = el.node.getAttribute?.('class')
|
|
1926
|
-
if (cls && !seen.has(cls)) {
|
|
1927
|
-
seen.add(cls)
|
|
1928
|
-
const cssResult = buildCSSFromProps(props, ds, mediaMap)
|
|
1929
|
-
|
|
1930
|
-
// Inject CSS from extends chain (e.g. extends: 'Flex' → display: flex)
|
|
1931
|
-
const extsCss = getExtendsCSS(el)
|
|
1932
|
-
if (extsCss) {
|
|
1933
|
-
for (const [k, v] of Object.entries(extsCss)) {
|
|
1934
|
-
const kebab = camelToKebab(k)
|
|
1935
|
-
if (!cssResult.base[kebab]) cssResult.base[kebab] = v
|
|
1936
|
-
}
|
|
1937
|
-
}
|
|
1938
|
-
|
|
1939
|
-
const has = Object.keys(cssResult.base).length || Object.keys(cssResult.mediaRules).length || Object.keys(cssResult.pseudoRules).length
|
|
1940
|
-
if (has) rules.push(renderCSSRule('.' + cls.split(' ')[0], cssResult))
|
|
1941
|
-
|
|
1942
|
-
const anim = props.animation || props.animationName
|
|
1943
|
-
if (typeof anim === 'string') {
|
|
1944
|
-
const name = anim.split(' ')[0]
|
|
1945
|
-
if (animations[name]) usedAnimations.add(name)
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
|
-
if (el.__ref?.__children) {
|
|
1950
|
-
for (const ck of el.__ref.__children) {
|
|
1951
|
-
if (el[ck]?.__ref) walk(el[ck])
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
1955
|
-
walk(element)
|
|
1956
|
-
|
|
1957
|
-
const keyframes = []
|
|
1958
|
-
for (const name of usedAnimations) {
|
|
1959
|
-
const frames = animations[name]
|
|
1960
|
-
const frameRules = Object.entries(frames).map(([step, p]) => {
|
|
1961
|
-
const decls = Object.entries(p).map(([k, v]) => `${camelToKebab(k)}: ${v}`).join('; ')
|
|
1962
|
-
return ` ${step} { ${decls}; }`
|
|
1963
|
-
}).join('\n')
|
|
1964
|
-
keyframes.push(`@keyframes ${name} {\n${frameRules}\n}`)
|
|
1965
|
-
}
|
|
1966
|
-
|
|
1967
|
-
return [...keyframes, ...rules].join('\n')
|
|
1968
|
-
}
|
|
1969
|
-
|
|
1970
1558
|
const generateFontLinks = (ds) => {
|
|
1971
1559
|
if (!ds) return ''
|
|
1972
1560
|
const families = ds.font_family || ds.fontFamily || {}
|