@stacksjs/stx 0.2.345 → 0.2.347
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/dist/binding-manifest.js +2 -0
- package/dist/{chunk-kqzpmwx2.js → chunk-0573wv97.js} +183 -171
- package/dist/{chunk-223makqc.js → chunk-0vdng9sh.js} +1 -1
- package/dist/{chunk-ybx8n794.js → chunk-16kfapt5.js} +1 -1
- package/dist/{chunk-e7gs18rc.js → chunk-1kwtdq06.js} +1 -1
- package/dist/{chunk-qkdcbeaw.js → chunk-1vtd57x6.js} +6 -6
- package/dist/{chunk-fp868yhg.js → chunk-1zjh3d0f.js} +1 -1
- package/dist/{chunk-8rhjt6fh.js → chunk-24rhp7ye.js} +1 -1
- package/dist/{chunk-1qyg1q6d.js → chunk-3phs970s.js} +1 -1
- package/dist/{chunk-nqz501eq.js → chunk-4fcvaazx.js} +2 -2
- package/dist/{chunk-zmazqcb8.js → chunk-4k8rebtb.js} +1 -1
- package/dist/{chunk-6fwp7gee.js → chunk-5d3f7rth.js} +1 -1
- package/dist/{chunk-1t4ece3v.js → chunk-632jxm61.js} +1 -1
- package/dist/{chunk-1vv9g6cj.js → chunk-6be9r0tz.js} +1 -1
- package/dist/{chunk-cypg8qwn.js → chunk-6h8t40zg.js} +1 -1
- package/dist/{chunk-7g5vk4c3.js → chunk-8753m7f0.js} +1 -1
- package/dist/{chunk-esjcyxa9.js → chunk-8b8jwbne.js} +2 -2
- package/dist/{chunk-qr3zcm87.js → chunk-8cd3ws01.js} +1 -1
- package/dist/{chunk-9jbssgem.js → chunk-8m0g0h4x.js} +146 -10
- package/dist/{chunk-77p1kjg2.js → chunk-9rc9gshn.js} +2 -2
- package/dist/{chunk-1vtdege3.js → chunk-adevnpdw.js} +1 -1
- package/dist/{chunk-aapqf6bj.js → chunk-dmpexr7d.js} +1 -1
- package/dist/{chunk-vhg91hnw.js → chunk-e6zk6ntt.js} +1 -1
- package/dist/{chunk-3zm4hgcf.js → chunk-e9sk8fqy.js} +1 -1
- package/dist/{chunk-kfkf9v2d.js → chunk-f5veee11.js} +1 -1
- package/dist/{chunk-6wmjwbq9.js → chunk-fbs0x8r3.js} +1 -1
- package/dist/{chunk-gvemapw4.js → chunk-fqp4b8k4.js} +1 -1
- package/dist/{chunk-9qtf2b1p.js → chunk-gkr35yjh.js} +1 -1
- package/dist/chunk-gnb15a8d.js +32 -0
- package/dist/{chunk-4spaszfn.js → chunk-h2sbvyr4.js} +190 -190
- package/dist/chunk-h8apy0k1.js +2 -0
- package/dist/chunk-hpr2sdfc.js +2 -0
- package/dist/{chunk-xq0e2y4x.js → chunk-jxg9vnsy.js} +1 -1
- package/dist/{chunk-pajk5680.js → chunk-nqqknczy.js} +2 -2
- package/dist/{chunk-2fhk4e68.js → chunk-ns38fhve.js} +1 -1
- package/dist/{chunk-v7aa7v85.js → chunk-p3p4d6g1.js} +1 -1
- package/dist/{chunk-1yh6pq6b.js → chunk-pwh8pbks.js} +1 -1
- package/dist/{chunk-eqzc88et.js → chunk-q018c92j.js} +1 -1
- package/dist/{chunk-z8wb7kbj.js → chunk-qrhbqzz0.js} +1 -1
- package/dist/{chunk-jnbg3e4r.js → chunk-rd02ysw3.js} +1 -1
- package/dist/{chunk-zwr4bn6a.js → chunk-rv28743b.js} +1 -1
- package/dist/{chunk-b5mnam29.js → chunk-s2rc73vk.js} +1 -1
- package/dist/{chunk-yca761bm.js → chunk-st8wkk98.js} +1 -1
- package/dist/{chunk-yg5r7bnm.js → chunk-swvm1wgn.js} +27 -3
- package/dist/{chunk-rzda6bd6.js → chunk-tg56j4ka.js} +1 -1
- package/dist/{chunk-nrt99ptw.js → chunk-tshyy2br.js} +1 -1
- package/dist/{chunk-c8e2deyp.js → chunk-vxk12k35.js} +1 -1
- package/dist/{chunk-ek2m0kkw.js → chunk-w7vyd0n0.js} +1 -1
- package/dist/{chunk-xrjx7b2v.js → chunk-wjaqhspq.js} +1 -1
- package/dist/{chunk-mr8ccsnm.js → chunk-xvr9enmb.js} +1 -1
- package/dist/{chunk-72yrrggn.js → chunk-xy99vzs2.js} +1 -1
- package/dist/chunk-y8g8neeh.js +2 -0
- package/dist/{chunk-h1vax4wg.js → chunk-yr634wtd.js} +1 -1
- package/dist/{chunk-7m9qk7da.js → chunk-zrbhpfda.js} +1 -1
- package/dist/cli.js +8 -8
- package/dist/component-library.d.ts +0 -31
- package/dist/component-library.js +279 -17
- package/dist/config.js +16 -4
- package/dist/craft-entry.js +1 -1
- package/dist/craft.js +1 -1
- package/dist/dev-server/ts-css.js +16 -47
- package/dist/process.js +34 -8
- package/dist/pwa.js +1 -1
- package/dist/signals.js +146 -10
- package/dist/ssg.js +2 -2
- package/dist/stx-virtual-ts.d.ts +16 -1
- package/dist/stx-virtual-ts.js +33 -2
- package/dist/theme-tokens.js +9 -5
- package/dist/typecheck.js +2 -0
- package/dist/types/config-types.d.ts +10 -0
- package/dist/variable-extractor.d.ts +31 -0
- package/dist/variable-extractor.js +9 -5
- package/package.json +5 -5
- package/dist/chunk-57t402mn.js +0 -2
- package/dist/chunk-66tgkvqw.js +0 -2
- package/dist/chunk-c4tf1vpy.js +0 -2
- package/dist/chunk-r38xq7fp.js +0 -33
|
@@ -354,56 +354,25 @@ async function generateCssUncached(htmlContent, appDir) {
|
|
|
354
354
|
cachedConfig = await resolveUserCssConfig(resolveRoot);
|
|
355
355
|
configFingerprint = fingerprintConfig(cachedConfig);
|
|
356
356
|
}
|
|
357
|
-
const baseConfig = hw.defaultConfig || hw.config, userConfig = cachedConfig || {}, merged = mergeCssConfig(baseConfig, userConfig), { safelist, includePreflight, minify, tokenCSS } = merged, cssConfig = merged.config, generator = new hw.CSSGenerator(cssConfig);
|
|
357
|
+
const baseConfig = hw.defaultConfig || hw.config, userConfig = cachedConfig || {}, merged = mergeCssConfig(baseConfig, userConfig), { safelist, includePreflight, minify, tokenCSS } = merged, cssConfig = merged.config, generator = new hw.CSSGenerator(cssConfig), shortcuts = cssConfig.shortcuts || userConfig.shortcuts || {}, usedShortcuts = Object.keys(shortcuts).filter((name) => classes.has(name) || safelist.includes(name));
|
|
358
358
|
for (const cls of safelist)
|
|
359
|
-
|
|
359
|
+
if (!shortcuts[cls])
|
|
360
|
+
generator.generate(cls);
|
|
360
361
|
for (const className of classes)
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
`);
|
|
374
|
-
for (const [name, classStr] of Object.entries(shortcuts)) {
|
|
375
|
-
if (!classes.has(name) && !safelist.includes(name))
|
|
376
|
-
continue;
|
|
377
|
-
const parts = classStr.split(/\s+/).filter(Boolean), decls = [], darkDecls = [];
|
|
378
|
-
for (const cls of parts) {
|
|
379
|
-
const isDark = cls.startsWith("dark:"), selectorTarget = `.${(isDark ? cls.slice(5) : cls).replace(/\//g, "\\/").replace(/:/g, "\\:").replace(/\./g, "\\.").replace(/\[/g, "\\[").replace(/\]/g, "\\]").replace(/%/g, "\\%")}`;
|
|
380
|
-
for (let i = 0;i < cssLines.length; i++) {
|
|
381
|
-
const line = cssLines[i].trim();
|
|
382
|
-
if (line === `${selectorTarget} {` || line.startsWith(`${selectorTarget} {`)) {
|
|
383
|
-
let j = i, ruleContent = "";
|
|
384
|
-
while (j < cssLines.length) {
|
|
385
|
-
ruleContent += cssLines[j];
|
|
386
|
-
if (cssLines[j].includes("}"))
|
|
387
|
-
break;
|
|
388
|
-
j++;
|
|
389
|
-
}
|
|
390
|
-
const declMatch = ruleContent.match(/\{([^}]+)\}/);
|
|
391
|
-
if (declMatch)
|
|
392
|
-
if (isDark)
|
|
393
|
-
darkDecls.push(declMatch[1].trim());
|
|
394
|
-
else
|
|
395
|
-
decls.push(declMatch[1].trim());
|
|
396
|
-
break;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
if (decls.length)
|
|
401
|
-
css += `
|
|
402
|
-
.${name} { ${decls.join(" ")} }`;
|
|
403
|
-
if (darkDecls.length)
|
|
404
|
-
css += `
|
|
405
|
-
@media (prefers-color-scheme: dark) { .dark .${name} { ${darkDecls.join(" ")} } }`;
|
|
362
|
+
if (!shortcuts[className])
|
|
363
|
+
generator.generate(className);
|
|
364
|
+
let shortcutCSS = "";
|
|
365
|
+
if (usedShortcuts.length > 0) {
|
|
366
|
+
const shortcutGenerator = new hw.CSSGenerator(cssConfig);
|
|
367
|
+
for (const name of usedShortcuts)
|
|
368
|
+
shortcutGenerator.generate(name);
|
|
369
|
+
shortcutCSS = shortcutGenerator.toCSS(!1, minify);
|
|
370
|
+
if (shortcutCSS && !shortcutCSS.endsWith(`
|
|
371
|
+
`))
|
|
372
|
+
shortcutCSS += `
|
|
373
|
+
`;
|
|
406
374
|
}
|
|
375
|
+
let css = shortcutCSS + generator.toCSS(includePreflight, minify);
|
|
407
376
|
css = tokenCSS + css;
|
|
408
377
|
setLruCache(cacheKey, css);
|
|
409
378
|
writeDiskCache(cacheKey, css);
|
package/dist/process.js
CHANGED
|
@@ -641,23 +641,49 @@ function scriptSourceOf(attrs) {
|
|
|
641
641
|
const match = new RegExp(`${SCRIPT_SOURCE_ATTR}="([^"]*)"`).exec(attrs);
|
|
642
642
|
return match ? decodeURIComponent(match[1]) : void 0;
|
|
643
643
|
}
|
|
644
|
+
function escapeForBoundary(value) {
|
|
645
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
646
|
+
}
|
|
647
|
+
function serverScriptErrorBoundary(sourcePath, kind, message) {
|
|
648
|
+
return `<div data-stx-server-script-error role="alert" style="padding:12px 14px;border:1px solid #f0b4b4;border-left-width:4px;background:#fff5f5;color:#7a1f1f;font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace"><strong style="display:block;margin-bottom:4px">stx: a <script server> ${kind === "module-resolution" ? "imports a module that does not resolve" : kind === "syntax" ? "does not parse" : "names something that does not exist"}, so this component rendered nothing.</strong><span style="display:block;opacity:.85">${escapeForBoundary(sourcePath)}</span><span style="display:block;margin-top:4px">${escapeForBoundary(message)}</span></div>`;
|
|
649
|
+
}
|
|
644
650
|
async function extractServerScriptVariables(output, context, filePath) {
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
651
|
+
const { scanScriptTags } = await importOnce("stx/signal-processing", () => import("./signal-processing.js")), boundaries = [], showBoundaries = !isProduction() && !isTest();
|
|
652
|
+
for (const script of scanScriptTags(output)) {
|
|
653
|
+
const attrs = script.attrs;
|
|
654
|
+
if (!/\bserver\b/.test(attrs))
|
|
655
|
+
continue;
|
|
656
|
+
const bodyStart = script.start + script.fullMatch.indexOf(">") + 1, closeStart = findScriptBodyEnd(output, bodyStart);
|
|
657
|
+
if (closeStart === -1)
|
|
658
|
+
continue;
|
|
659
|
+
const scriptContent = output.slice(bodyStart, closeStart);
|
|
660
|
+
if (!scriptContent.trim())
|
|
650
661
|
continue;
|
|
651
|
-
const sourcePath = scriptSourceOf(attrs) ?? filePath;
|
|
662
|
+
const sourcePath = scriptSourceOf(attrs) ?? filePath, at = { index: script.start, length: closeStart + 9 - script.start };
|
|
652
663
|
try {
|
|
653
664
|
const { extractVariables } = await importOnce("stx/variable-extractor", () => import("./variable-extractor.js"));
|
|
654
|
-
await extractVariables(scriptContent, context, sourcePath, {
|
|
665
|
+
await extractVariables(scriptContent, context, sourcePath, {
|
|
666
|
+
preserveExisting: !0,
|
|
667
|
+
onFailure: (failure) => {
|
|
668
|
+
if (!showBoundaries || failure.kind === "unknown")
|
|
669
|
+
return;
|
|
670
|
+
boundaries.push({ ...at, markup: serverScriptErrorBoundary(sourcePath, failure.kind, failure.message) });
|
|
671
|
+
}
|
|
672
|
+
});
|
|
655
673
|
} catch (e) {
|
|
656
674
|
const err = e instanceof Error ? e : Error(String(e));
|
|
657
675
|
errorLogger.log(err, { filePath: sourcePath, phase: "server-script-extraction" }, "warning");
|
|
658
676
|
console.warn(`[stx] server <script> extraction failed in ${sourcePath}: ${err.message}`);
|
|
677
|
+
if (showBoundaries)
|
|
678
|
+
boundaries.push({ ...at, markup: serverScriptErrorBoundary(sourcePath, "unknown", err.message) });
|
|
659
679
|
}
|
|
660
680
|
}
|
|
681
|
+
if (boundaries.length === 0)
|
|
682
|
+
return output;
|
|
683
|
+
let result = output;
|
|
684
|
+
for (const boundary of boundaries.sort((a, b) => b.index - a.index))
|
|
685
|
+
result = result.slice(0, boundary.index) + boundary.markup + result.slice(boundary.index + boundary.length);
|
|
686
|
+
return result;
|
|
661
687
|
}
|
|
662
688
|
async function interpolateClientScriptExpressions(output, context, filePath) {
|
|
663
689
|
try {
|
|
@@ -673,7 +699,7 @@ async function interpolateClientScriptExpressions(output, context, filePath) {
|
|
|
673
699
|
async function processOtherDirectives(template, context, filePath, options, dependencies) {
|
|
674
700
|
let output = template;
|
|
675
701
|
const opts = options;
|
|
676
|
-
await extractServerScriptVariables(output, context, filePath);
|
|
702
|
+
output = await extractServerScriptVariables(output, context, filePath);
|
|
677
703
|
output = await interpolateClientScriptExpressions(output, context, filePath);
|
|
678
704
|
output = await processJsDirectives(output, context, filePath);
|
|
679
705
|
output = await processTsDirectives(output, context, filePath);
|
package/dist/pwa.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import{Fk as wq,Gk as dq,Hk as Cq,Ik as mq,Jk as gq}from"./chunk-wvc7t11n.js";import{Kk as S,Lk as Tq,Mk as _q,Nk as z,Ok as D,Pk as P,Qk as kq,Rk as vq,Sk as w,Tk as Iq,Uk as d,Vk as Hq,Wk as Oq,Xk as Mq}from"./chunk-c30qnb6z.js";import{Ew as Aq,Fw as bq,Gw as Sq,Hw as zq,Iw as Dq,Jw as Pq}from"./chunk-9nrgjtah.js";import{Nw as N}from"./chunk-ejqpq0wc.js";import p from"fs";import E from"path";import C from"fs";import L from"path";var k=[72,96,128,144,152,192,384,512],v=[120,152,167,180],I=[16,32];async function H(G,B){let q={success:!0,generatedFiles:[],errors:[],warnings:[]},K=G.pwa?.icons;if(!K?.src)return q.errors.push("No source icon specified in pwa.icons.src"),q.success=!1,q;let Y=L.isAbsolute(K.src)?K.src:L.resolve(process.cwd(),K.src);if(!await Bun.file(Y).exists())return q.errors.push(`Source icon not found: ${Y}`),q.success=!1,q;let Q=L.resolve(B,K.outputDir||"pwa-icons");try{C.mkdirSync(Q,{recursive:!0})}catch{return q.errors.push(`Failed to create output directory: ${Q}`),q.success=!1,q}let X=K.sizes||k,j=K.generateWebP??!0,J=K.generateAppleIcons??!0;try{let y;try{y=await import("sharp")}catch{return q.errors.push(`sharp is not installed. Install it with: bun add sharp
|
|
3
|
-
Icon generation requires the sharp package for image processing.`),q.success=!1,q}let R=await y.default(Y).metadata();if(R.width&&R.width<512)q.warnings.push(`Source icon is ${R.width}x${R.height}. Recommend using at least 512x512 for best quality.`);for(let $ of X){let x=L.join(Q,`icon-${$}x${$}.png`);if(await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x),j){let F=L.join(Q,`icon-${$}x${$}.webp`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).webp({quality:90}).toFile(F),q.generatedFiles.push(F)}}if(J){for(let x of v){let F=L.join(Q,`apple-touch-icon-${x}x${x}.png`);await y.default(Y).resize(x,x,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile(F),q.generatedFiles.push(F)}let $=L.join(Q,"apple-touch-icon.png");await y.default(Y).resize(180,180,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile($),q.generatedFiles.push($)}for(let $ of I){let x=L.join(Q,`favicon-${$}x${$}.png`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x)}let U=512,T=L.join(Q,`icon-maskable-${U}x${U}.png`),Z=Math.floor(U*0.1),_=U-Z*2;await y.default(Y).resize(_,_,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).extend({top:Z,bottom:Z,left:Z,right:Z,background:{r:255,g:255,b:255,alpha:1}}).png().toFile(T),q.generatedFiles.push(T)}catch(y){let V=y instanceof Error?y.message:String(y);q.errors.push(`Icon generation failed: ${V}`),q.success=!1}return q}function n(G){let B=G.sizes||k,q=G.outputDir?`/${G.outputDir}`:"/pwa-icons",K=G.generateWebP??!0,Y=G.generateAppleIcons??!0,Q=[];for(let X of B)if(Q.push(`${q}/icon-${X}x${X}.png`),K)Q.push(`${q}/icon-${X}x${X}.webp`);if(Y){Q.push(`${q}/apple-touch-icon.png`);for(let X of v)Q.push(`${q}/apple-touch-icon-${X}x${X}.png`)}for(let X of I)Q.push(`${q}/favicon-${X}x${X}.png`);return Q.push(`${q}/icon-maskable-512x512.png`),Q}async function O(){try{return await import("sharp"),!0}catch{return!1}}function m(G,B,q,K){let Y=[],Q=K.join(" ");for(let X of G)if(Y.push({src:`${B}/icon-${X}x${X}.png`,sizes:`${X}x${X}`,type:"image/png",purpose:Q}),q)Y.push({src:`${B}/icon-${X}x${X}.webp`,sizes:`${X}x${X}`,type:"image/webp",purpose:Q});return Y}function g(G){return G.map((B)=>({name:B.name,short_name:B.shortName,description:B.description,url:B.url,icons:B.icons?.map((q)=>({src:q.src,sizes:q.sizes,type:q.type}))}))}function h(G){let B=G.pwa?.shareTarget;if(!B?.enabled)return;let q={action:B.action||"/share",method:B.method||"POST",enctype:B.enctype||"multipart/form-data",params:{title:B.params?.title||"title",text:B.params?.text||"text",url:B.params?.url||"url"}};if(B.acceptFiles&&B.acceptFiles.length>0)q.params.files=B.acceptFiles.map((K)=>({name:K.name,accept:K.accept}));return q}function c(G){let B=G.pwa?.fileHandlers;if(!B?.enabled||!B.accept)return;let q=[{action:B.action||"/",accept:B.accept,launch_type:B.launchType||"single-client"}];if(B.icons)q[0].icons=B.icons.map((K)=>({src:K.src,sizes:K.sizes,type:K.type}));return q}function l(G){let B=G.pwa?.protocolHandlers;if(!B||B.length===0)return;return B.map((q)=>({protocol:q.protocol,url:q.url}))}function u(G){let B=G.pwa;if(!B?.enabled||!B.manifest)return null;let{manifest:q,icons:K}=B,Y=K?.sizes||[72,96,128,144,152,192,384,512],Q=K?.outputDir?`/${K.outputDir}`:"/pwa-icons",X=K?.generateWebP??!0,j=K?.purpose||["any","maskable"],J={name:q.name,short_name:q.shortName||q.name,description:q.description,start_url:q.startUrl||"/",display:q.display||"standalone",display_override:q.displayOverride,orientation:q.orientation,theme_color:q.themeColor,background_color:q.backgroundColor,scope:q.scope||"/",lang:q.lang,dir:q.dir,id:q.id,categories:q.categories,icons:m(Y,Q,X,j)};if(q.shortcuts&&q.shortcuts.length>0)J.shortcuts=g(q.shortcuts);if(q.screenshots&&q.screenshots.length>0)J.screenshots=q.screenshots.map((U)=>({src:U.src,sizes:U.sizes,type:U.type,label:U.label,form_factor:U.platform}));let y=h(G);if(y)J.share_target=y;let V=c(G);if(V)J.file_handlers=V;let R=l(G);if(R)J.protocol_handlers=R;if(q.launchHandler)J.launch_handler={client_mode:q.launchHandler};if(q.handleLinks)J.handle_links=q.handleLinks;if(q.edgeSidePanel?.enabled)J.edge_side_panel={preferred_width:q.edgeSidePanel.preferredWidth};return J}function M(G){let B=u(G);if(!B)return"";let q=JSON.parse(JSON.stringify(B));return JSON.stringify(q,null,2)}function i(G,B){return{...B,...G,shortcuts:G.shortcuts||B.shortcuts,screenshots:G.screenshots||B.screenshots,categories:G.categories||B.categories}}function s(G){let B=[],q=G.pwa;if(!q?.enabled)return B;let K=q.manifest;if(!K)return B.push("PWA manifest configuration is missing"),B;if(!K.name)B.push("Manifest name is required");let Y=["fullscreen","standalone","minimal-ui","browser"];if(K.display&&!Y.includes(K.display))B.push(`Invalid display mode: ${K.display}. Must be one of: ${Y.join(", ")}`);let Q=["any","natural","landscape","landscape-primary","landscape-secondary","portrait","portrait-primary","portrait-secondary"];if(K.orientation&&!Q.includes(K.orientation))B.push(`Invalid orientation: ${K.orientation}`);let X=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;if(K.themeColor&&!X.test(K.themeColor))B.push(`Invalid theme color: ${K.themeColor}. Must be a valid hex color.`);if(K.backgroundColor&&!X.test(K.backgroundColor))B.push(`Invalid background color: ${K.backgroundColor}. Must be a valid hex color.`);if(q.shareTarget?.enabled){if(!q.shareTarget.action)B.push("Share target action URL is required")}if(q.fileHandlers?.enabled){if(!q.fileHandlers.accept||Object.keys(q.fileHandlers.accept).length===0)B.push("File handlers must specify accepted MIME types")}if(q.protocolHandlers)for(let j of q.protocolHandlers){if(!j.protocol)B.push("Protocol handler missing protocol");if(!j.url||!j.url.includes("%s"))B.push(`Protocol handler URL must contain %s placeholder: ${j.protocol}`)}return B}import A from"path";async function b(G){let B=G.pwa?.offline;if(!B?.enabled)return"";if(B.page){let q=A.isAbsolute(B.page)?B.page:A.resolve(process.cwd(),B.page);if(await Bun.file(q).exists())try{let{processDirectives:K}=await import("./chunk-
|
|
3
|
+
Icon generation requires the sharp package for image processing.`),q.success=!1,q}let R=await y.default(Y).metadata();if(R.width&&R.width<512)q.warnings.push(`Source icon is ${R.width}x${R.height}. Recommend using at least 512x512 for best quality.`);for(let $ of X){let x=L.join(Q,`icon-${$}x${$}.png`);if(await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x),j){let F=L.join(Q,`icon-${$}x${$}.webp`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).webp({quality:90}).toFile(F),q.generatedFiles.push(F)}}if(J){for(let x of v){let F=L.join(Q,`apple-touch-icon-${x}x${x}.png`);await y.default(Y).resize(x,x,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile(F),q.generatedFiles.push(F)}let $=L.join(Q,"apple-touch-icon.png");await y.default(Y).resize(180,180,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile($),q.generatedFiles.push($)}for(let $ of I){let x=L.join(Q,`favicon-${$}x${$}.png`);await y.default(Y).resize($,$,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(x),q.generatedFiles.push(x)}let U=512,T=L.join(Q,`icon-maskable-${U}x${U}.png`),Z=Math.floor(U*0.1),_=U-Z*2;await y.default(Y).resize(_,_,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).extend({top:Z,bottom:Z,left:Z,right:Z,background:{r:255,g:255,b:255,alpha:1}}).png().toFile(T),q.generatedFiles.push(T)}catch(y){let V=y instanceof Error?y.message:String(y);q.errors.push(`Icon generation failed: ${V}`),q.success=!1}return q}function n(G){let B=G.sizes||k,q=G.outputDir?`/${G.outputDir}`:"/pwa-icons",K=G.generateWebP??!0,Y=G.generateAppleIcons??!0,Q=[];for(let X of B)if(Q.push(`${q}/icon-${X}x${X}.png`),K)Q.push(`${q}/icon-${X}x${X}.webp`);if(Y){Q.push(`${q}/apple-touch-icon.png`);for(let X of v)Q.push(`${q}/apple-touch-icon-${X}x${X}.png`)}for(let X of I)Q.push(`${q}/favicon-${X}x${X}.png`);return Q.push(`${q}/icon-maskable-512x512.png`),Q}async function O(){try{return await import("sharp"),!0}catch{return!1}}function m(G,B,q,K){let Y=[],Q=K.join(" ");for(let X of G)if(Y.push({src:`${B}/icon-${X}x${X}.png`,sizes:`${X}x${X}`,type:"image/png",purpose:Q}),q)Y.push({src:`${B}/icon-${X}x${X}.webp`,sizes:`${X}x${X}`,type:"image/webp",purpose:Q});return Y}function g(G){return G.map((B)=>({name:B.name,short_name:B.shortName,description:B.description,url:B.url,icons:B.icons?.map((q)=>({src:q.src,sizes:q.sizes,type:q.type}))}))}function h(G){let B=G.pwa?.shareTarget;if(!B?.enabled)return;let q={action:B.action||"/share",method:B.method||"POST",enctype:B.enctype||"multipart/form-data",params:{title:B.params?.title||"title",text:B.params?.text||"text",url:B.params?.url||"url"}};if(B.acceptFiles&&B.acceptFiles.length>0)q.params.files=B.acceptFiles.map((K)=>({name:K.name,accept:K.accept}));return q}function c(G){let B=G.pwa?.fileHandlers;if(!B?.enabled||!B.accept)return;let q=[{action:B.action||"/",accept:B.accept,launch_type:B.launchType||"single-client"}];if(B.icons)q[0].icons=B.icons.map((K)=>({src:K.src,sizes:K.sizes,type:K.type}));return q}function l(G){let B=G.pwa?.protocolHandlers;if(!B||B.length===0)return;return B.map((q)=>({protocol:q.protocol,url:q.url}))}function u(G){let B=G.pwa;if(!B?.enabled||!B.manifest)return null;let{manifest:q,icons:K}=B,Y=K?.sizes||[72,96,128,144,152,192,384,512],Q=K?.outputDir?`/${K.outputDir}`:"/pwa-icons",X=K?.generateWebP??!0,j=K?.purpose||["any","maskable"],J={name:q.name,short_name:q.shortName||q.name,description:q.description,start_url:q.startUrl||"/",display:q.display||"standalone",display_override:q.displayOverride,orientation:q.orientation,theme_color:q.themeColor,background_color:q.backgroundColor,scope:q.scope||"/",lang:q.lang,dir:q.dir,id:q.id,categories:q.categories,icons:m(Y,Q,X,j)};if(q.shortcuts&&q.shortcuts.length>0)J.shortcuts=g(q.shortcuts);if(q.screenshots&&q.screenshots.length>0)J.screenshots=q.screenshots.map((U)=>({src:U.src,sizes:U.sizes,type:U.type,label:U.label,form_factor:U.platform}));let y=h(G);if(y)J.share_target=y;let V=c(G);if(V)J.file_handlers=V;let R=l(G);if(R)J.protocol_handlers=R;if(q.launchHandler)J.launch_handler={client_mode:q.launchHandler};if(q.handleLinks)J.handle_links=q.handleLinks;if(q.edgeSidePanel?.enabled)J.edge_side_panel={preferred_width:q.edgeSidePanel.preferredWidth};return J}function M(G){let B=u(G);if(!B)return"";let q=JSON.parse(JSON.stringify(B));return JSON.stringify(q,null,2)}function i(G,B){return{...B,...G,shortcuts:G.shortcuts||B.shortcuts,screenshots:G.screenshots||B.screenshots,categories:G.categories||B.categories}}function s(G){let B=[],q=G.pwa;if(!q?.enabled)return B;let K=q.manifest;if(!K)return B.push("PWA manifest configuration is missing"),B;if(!K.name)B.push("Manifest name is required");let Y=["fullscreen","standalone","minimal-ui","browser"];if(K.display&&!Y.includes(K.display))B.push(`Invalid display mode: ${K.display}. Must be one of: ${Y.join(", ")}`);let Q=["any","natural","landscape","landscape-primary","landscape-secondary","portrait","portrait-primary","portrait-secondary"];if(K.orientation&&!Q.includes(K.orientation))B.push(`Invalid orientation: ${K.orientation}`);let X=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;if(K.themeColor&&!X.test(K.themeColor))B.push(`Invalid theme color: ${K.themeColor}. Must be a valid hex color.`);if(K.backgroundColor&&!X.test(K.backgroundColor))B.push(`Invalid background color: ${K.backgroundColor}. Must be a valid hex color.`);if(q.shareTarget?.enabled){if(!q.shareTarget.action)B.push("Share target action URL is required")}if(q.fileHandlers?.enabled){if(!q.fileHandlers.accept||Object.keys(q.fileHandlers.accept).length===0)B.push("File handlers must specify accepted MIME types")}if(q.protocolHandlers)for(let j of q.protocolHandlers){if(!j.protocol)B.push("Protocol handler missing protocol");if(!j.url||!j.url.includes("%s"))B.push(`Protocol handler URL must contain %s placeholder: ${j.protocol}`)}return B}import A from"path";async function b(G){let B=G.pwa?.offline;if(!B?.enabled)return"";if(B.page){let q=A.isAbsolute(B.page)?B.page:A.resolve(process.cwd(),B.page);if(await Bun.file(q).exists())try{let{processDirectives:K}=await import("./chunk-ns38fhve.js"),Y=await Bun.file(q).text();return await K(Y,{},q,G,new Set)}catch(K){console.warn(`[PWA] Failed to process custom offline page: ${K}`)}else console.warn(`[PWA] Custom offline page not found: ${q}`)}return f(G)}function f(G){let B=G.pwa?.offline,q=G.pwa?.manifest,K=B?.fallbackTitle||"You are offline",Y=B?.fallbackMessage||"Please check your internet connection and try again.",Q=q?.themeColor||"#4f46e5",X=q?.shortName||q?.name||"App";return`<!DOCTYPE html>
|
|
4
4
|
<html lang="en">
|
|
5
5
|
<head>
|
|
6
6
|
<meta charset="UTF-8">
|
package/dist/signals.js
CHANGED
|
@@ -6487,6 +6487,89 @@ catch (e) {} }
|
|
|
6487
6487
|
// Both return Promises and render into a temporary modal overlay.
|
|
6488
6488
|
|
|
6489
6489
|
var _dialogId = 0;
|
|
6490
|
+
|
|
6491
|
+
// Shared across every open dialog, because four of the defects in #1998 were
|
|
6492
|
+
// each dialog acting as if it were the only one.
|
|
6493
|
+
var _dialogStack = [];
|
|
6494
|
+
// What WE set inert, so restoring never clears an app's own inert.
|
|
6495
|
+
var _dialogInerted = [];
|
|
6496
|
+
// Saved once, when the first dialog opens.
|
|
6497
|
+
var _dialogScrollLock = null;
|
|
6498
|
+
|
|
6499
|
+
/*
|
|
6500
|
+
* The page behind an aria-modal dialog does not scroll and is not reachable
|
|
6501
|
+
* by a virtual cursor (stacksjs/stx#1998, items 1 and 2).
|
|
6502
|
+
*
|
|
6503
|
+
* The backdrop is position:fixed;inset:0, so it stayed put while the content
|
|
6504
|
+
* behind it scrolled away underneath - the dialog claimed to be modal and the
|
|
6505
|
+
* page moved anyway. And the Tab trap, which #1875 added, only covers the
|
|
6506
|
+
* keyboard: aria-modal support for the virtual cursor is uneven, so a screen
|
|
6507
|
+
* reader could still browse the page behind the dialog.
|
|
6508
|
+
*
|
|
6509
|
+
* inert rather than aria-hidden on the siblings: aria-hidden on an element
|
|
6510
|
+
* that contains focus is itself a violation, and inert removes the subtree
|
|
6511
|
+
* from the tab order and the accessibility tree together. Everything except
|
|
6512
|
+
* the TOPMOST dialog goes inert, which also settles the two traps competing
|
|
6513
|
+
* for Tab while both were open - a backgrounded dialog's buttons stop being
|
|
6514
|
+
* focusable at all.
|
|
6515
|
+
*/
|
|
6516
|
+
function _dialogSyncModality() {
|
|
6517
|
+
var top = _dialogStack.length ? _dialogStack[_dialogStack.length - 1] : null;
|
|
6518
|
+
|
|
6519
|
+
for (var i = 0; i < _dialogInerted.length; i++) {
|
|
6520
|
+
try { _dialogInerted[i].inert = false; }
|
|
6521
|
+
catch (_e) { /* element may be gone */ }
|
|
6522
|
+
}
|
|
6523
|
+
_dialogInerted = [];
|
|
6524
|
+
|
|
6525
|
+
if (!top) {
|
|
6526
|
+
if (_dialogScrollLock) {
|
|
6527
|
+
document.body.style.overflow = _dialogScrollLock.body;
|
|
6528
|
+
document.documentElement.style.overflow = _dialogScrollLock.html;
|
|
6529
|
+
document.body.style.paddingRight = _dialogScrollLock.pad;
|
|
6530
|
+
_dialogScrollLock = null;
|
|
6531
|
+
}
|
|
6532
|
+
return;
|
|
6533
|
+
}
|
|
6534
|
+
|
|
6535
|
+
if (!_dialogScrollLock) {
|
|
6536
|
+
_dialogScrollLock = {
|
|
6537
|
+
body: document.body.style.overflow,
|
|
6538
|
+
html: document.documentElement.style.overflow,
|
|
6539
|
+
pad: document.body.style.paddingRight
|
|
6540
|
+
};
|
|
6541
|
+
// Compensate for the scrollbar the lock removes, or the whole page shifts
|
|
6542
|
+
// sideways the moment a dialog opens.
|
|
6543
|
+
var gap = window.innerWidth - document.documentElement.clientWidth;
|
|
6544
|
+
if (gap > 0) {
|
|
6545
|
+
var existing = Number.parseFloat(window.getComputedStyle(document.body).paddingRight) || 0;
|
|
6546
|
+
document.body.style.paddingRight = (existing + gap) + 'px';
|
|
6547
|
+
}
|
|
6548
|
+
document.body.style.overflow = 'hidden';
|
|
6549
|
+
document.documentElement.style.overflow = 'hidden';
|
|
6550
|
+
}
|
|
6551
|
+
|
|
6552
|
+
var kids = document.body.children;
|
|
6553
|
+
for (var k = 0; k < kids.length; k++) {
|
|
6554
|
+
var kid = kids[k];
|
|
6555
|
+
if (kid === top || kid.inert) continue;
|
|
6556
|
+
try {
|
|
6557
|
+
kid.inert = true;
|
|
6558
|
+
_dialogInerted.push(kid);
|
|
6559
|
+
}
|
|
6560
|
+
catch (_e) { /* inert unsupported; the Tab trap still holds */ }
|
|
6561
|
+
}
|
|
6562
|
+
}
|
|
6563
|
+
|
|
6564
|
+
/** Dialogs animate unless the reader asked them not to (#1998 item 5). */
|
|
6565
|
+
function _dialogReducedMotion() {
|
|
6566
|
+
try {
|
|
6567
|
+
return !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches);
|
|
6568
|
+
}
|
|
6569
|
+
catch (_e) {
|
|
6570
|
+
return false;
|
|
6571
|
+
}
|
|
6572
|
+
}
|
|
6490
6573
|
var _dialogIcons = {
|
|
6491
6574
|
info: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#2563eb" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>',
|
|
6492
6575
|
warning: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#d97706" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
|
|
@@ -6514,14 +6597,23 @@ catch (e) {} }
|
|
|
6514
6597
|
var icon = _dialogIcons[type] || _dialogIcons.info;
|
|
6515
6598
|
|
|
6516
6599
|
return new Promise(function(resolve) {
|
|
6600
|
+
// Inline transitions cannot be reached by a stylesheet media query, so the
|
|
6601
|
+
// preference is read here instead (#1998 item 5). One matchMedia probe
|
|
6602
|
+
// rather than usePreferredReducedMotion(): that returns a signal with a
|
|
6603
|
+
// change listener, and an imperative dialog that reads the value once at
|
|
6604
|
+
// open time would leak one listener per call.
|
|
6605
|
+
var still = _dialogReducedMotion();
|
|
6606
|
+
var fade = still ? '' : 'transition:opacity 0.2s ease;';
|
|
6607
|
+
var scale = still ? '' : 'transition:transform 0.2s ease;';
|
|
6608
|
+
|
|
6517
6609
|
var backdrop = document.createElement('div');
|
|
6518
6610
|
backdrop.id = id;
|
|
6519
|
-
backdrop.style.cssText = 'position:fixed;inset:0;z-index:999999;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0.5);backdrop-filter:blur(2px);opacity:
|
|
6611
|
+
backdrop.style.cssText = 'position:fixed;inset:0;z-index:999999;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0.5);backdrop-filter:blur(2px);opacity:' + (still ? '1' : '0') + ';' + fade + 'font-family:system-ui,-apple-system,sans-serif';
|
|
6520
6612
|
backdrop.setAttribute('role', 'alertdialog');
|
|
6521
6613
|
backdrop.setAttribute('aria-modal', 'true');
|
|
6522
6614
|
|
|
6523
6615
|
var panel = document.createElement('div');
|
|
6524
|
-
panel.style.cssText = 'max-width:24rem;width:calc(100% - 2rem);border-radius:0.75rem;padding:1.5rem;background:' + bg + ';color:' + textColor + ';box-shadow:0 20px 60px rgba(0,0,0,0.3);transform:scale(0.95);
|
|
6616
|
+
panel.style.cssText = 'max-width:24rem;width:calc(100% - 2rem);border-radius:0.75rem;padding:1.5rem;background:' + bg + ';color:' + textColor + ';box-shadow:0 20px 60px rgba(0,0,0,0.3);transform:scale(' + (still ? '1' : '0.95') + ');' + scale + 'text-align:center';
|
|
6525
6617
|
|
|
6526
6618
|
var iconDiv = document.createElement('div');
|
|
6527
6619
|
iconDiv.style.cssText = 'display:flex;justify-content:center;margin-bottom:1rem';
|
|
@@ -6562,9 +6654,25 @@ catch (e) {} }
|
|
|
6562
6654
|
if (closed) return;
|
|
6563
6655
|
closed = true;
|
|
6564
6656
|
document.removeEventListener('keydown', keyHandler, true);
|
|
6657
|
+
|
|
6658
|
+
// Out of the stack BEFORE resolving, so a caller that opens another
|
|
6659
|
+
// dialog the moment this one answers does not land under a backdrop
|
|
6660
|
+
// that is still fading.
|
|
6661
|
+
var at = _dialogStack.indexOf(backdrop);
|
|
6662
|
+
if (at !== -1) _dialogStack.splice(at, 1);
|
|
6663
|
+
|
|
6664
|
+
// The fade is 200ms and resolve() is immediate, so for those 200ms a
|
|
6665
|
+
// full-viewport element at z-index 999999 was still hit-testing at the
|
|
6666
|
+
// centre of the screen - after the caller's await had already returned
|
|
6667
|
+
// (#1998 item 6). Fading out is right; swallowing clicks is not.
|
|
6668
|
+
backdrop.style.pointerEvents = 'none';
|
|
6565
6669
|
backdrop.style.opacity = '0';
|
|
6566
|
-
panel.style.transform = 'scale(0.95)';
|
|
6567
|
-
setTimeout(function() { backdrop.remove(); }, 200);
|
|
6670
|
+
if (!still) panel.style.transform = 'scale(0.95)';
|
|
6671
|
+
setTimeout(function() { backdrop.remove(); }, still ? 0 : 200);
|
|
6672
|
+
|
|
6673
|
+
// Unlocks the page and clears inert when this was the last dialog, or
|
|
6674
|
+
// hands modality back to the one underneath when it was not.
|
|
6675
|
+
_dialogSyncModality();
|
|
6568
6676
|
if (previouslyFocused && typeof previouslyFocused.focus === 'function') {
|
|
6569
6677
|
try { previouslyFocused.focus(); }
|
|
6570
6678
|
catch (_e) { /* element may be gone; not worth failing the dialog over */ }
|
|
@@ -6572,8 +6680,11 @@ catch (e) {} }
|
|
|
6572
6680
|
resolve(result);
|
|
6573
6681
|
}
|
|
6574
6682
|
|
|
6683
|
+
// Declared out here rather than inside the branch: the focus decision
|
|
6684
|
+
// below needs to know whether a Cancel button exists at all.
|
|
6685
|
+
var cancelBtn = null;
|
|
6575
6686
|
if (isConfirm) {
|
|
6576
|
-
|
|
6687
|
+
cancelBtn = document.createElement('button');
|
|
6577
6688
|
cancelBtn.textContent = cancelText;
|
|
6578
6689
|
cancelBtn.style.cssText = 'padding:0.5rem 1.25rem;border-radius:0.5rem;font-size:0.875rem;font-weight:500;cursor:pointer;border:1px solid ' + (isDark ? '#374151' : '#d1d5db') + ';background:transparent;color:' + textColor + ';transition:background 0.15s';
|
|
6579
6690
|
cancelBtn.onmouseover = function() { this.style.background = isDark ? '#374151' : '#f3f4f6'; };
|
|
@@ -6594,11 +6705,15 @@ catch (e) {} }
|
|
|
6594
6705
|
panel.appendChild(btnRow);
|
|
6595
6706
|
backdrop.appendChild(panel);
|
|
6596
6707
|
document.body.appendChild(backdrop);
|
|
6708
|
+
_dialogStack.push(backdrop);
|
|
6709
|
+
_dialogSyncModality();
|
|
6597
6710
|
|
|
6598
6711
|
// Animate in
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6712
|
+
if (!still) {
|
|
6713
|
+
void backdrop.offsetHeight;
|
|
6714
|
+
backdrop.style.opacity = '1';
|
|
6715
|
+
panel.style.transform = 'scale(1)';
|
|
6716
|
+
}
|
|
6602
6717
|
|
|
6603
6718
|
// Escape, plus a real focus trap.
|
|
6604
6719
|
//
|
|
@@ -6611,6 +6726,11 @@ catch (e) {} }
|
|
|
6611
6726
|
// walked straight out into the page behind it. Capture phase so the trap
|
|
6612
6727
|
// wins over anything the page has bound.
|
|
6613
6728
|
var keyHandler = function(e) {
|
|
6729
|
+
// Every dialog binds its own capture-phase handler on document and none
|
|
6730
|
+
// of them checked whether they were on top, so ONE Escape resolved every
|
|
6731
|
+
// open dialog at once (#1998 item 4). The backgrounded dialogs are inert
|
|
6732
|
+
// too, which is what stops their traps competing for Tab.
|
|
6733
|
+
if (_dialogStack.length && _dialogStack[_dialogStack.length - 1] !== backdrop) return;
|
|
6614
6734
|
if (e.key === 'Escape') {
|
|
6615
6735
|
e.preventDefault();
|
|
6616
6736
|
cleanup(isConfirm ? false : undefined);
|
|
@@ -6640,8 +6760,24 @@ catch (e) {} }
|
|
|
6640
6760
|
};
|
|
6641
6761
|
document.addEventListener('keydown', keyHandler, true);
|
|
6642
6762
|
|
|
6643
|
-
|
|
6644
|
-
|
|
6763
|
+
/*
|
|
6764
|
+
* Initial focus, which was an unconditional okBtn.focus() (#1998 item 3).
|
|
6765
|
+
*
|
|
6766
|
+
* type: 'error' already paints that button red, so the API knows the
|
|
6767
|
+
* action is destructive - and still handed it the keyboard, where a stray
|
|
6768
|
+
* Enter or Space confirmed the delete. An error-type confirm now defaults
|
|
6769
|
+
* to Cancel, and defaultFocus overrides either way.
|
|
6770
|
+
*
|
|
6771
|
+
* An alert has only one button, so it keeps it: there is nothing
|
|
6772
|
+
* destructive to land on and focus has to go somewhere inside the trap.
|
|
6773
|
+
*/
|
|
6774
|
+
var focusTarget = okBtn;
|
|
6775
|
+
if (isConfirm && cancelBtn) {
|
|
6776
|
+
var want = opts.defaultFocus;
|
|
6777
|
+
if (want === 'cancel' || (!want && type === 'error')) focusTarget = cancelBtn;
|
|
6778
|
+
else if (want === 'confirm') focusTarget = okBtn;
|
|
6779
|
+
}
|
|
6780
|
+
focusTarget.focus();
|
|
6645
6781
|
});
|
|
6646
6782
|
}
|
|
6647
6783
|
|
package/dist/ssg.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{Bk as Fq,wk as Uq,xk as Iq}from"./chunk-
|
|
2
|
+
import{Bk as Fq,wk as Uq,xk as Iq}from"./chunk-p3p4d6g1.js";import{Ck as Eq,Dk as Tq,Ek as Dq}from"./chunk-c0n802j1.js";import{Zk as _q,al as zq,bl as Aq}from"./chunk-0vdng9sh.js";import"./chunk-9rc9gshn.js";import"./chunk-fvsefztj.js";import{Jp as P,Sm as Oq,io as l,lo as Hq,sr as n}from"./chunk-h2sbvyr4.js";import"./chunk-8y1ve8tc.js";import"./chunk-njx93b4z.js";import"./chunk-bqdfbwdf.js";import"./chunk-89mqnh67.js";import"./chunk-xvh1k1a4.js";import{it as Xq}from"./chunk-gnb15a8d.js";import{nt as d}from"./chunk-y2f41kaq.js";import"./chunk-xj6bcwqa.js";import"./chunk-qrhbqzz0.js";import"./chunk-vhta1be7.js";import{Ut as Bq}from"./chunk-tc4pj651.js";import"./chunk-san1eq0r.js";import"./chunk-avwywzsj.js";import"./chunk-wj21f1e0.js";import"./chunk-d86q27j8.js";import"./chunk-72x62kch.js";import{rw as Yq,sw as Vq,tw as jq,uw as Gq,vw as Lq,ww as Nq}from"./chunk-swvm1wgn.js";import"./chunk-9nrgjtah.js";import{Nw as y}from"./chunk-ejqpq0wc.js";import O from"fs";import j from"path";import{createHash as xq}from"crypto";function yq(q){try{return new Bun.Transpiler({loader:"js",minifyWhitespace:!0}).transformSync(q).replace(/\}(var |let |const |function )/g,"};$1").trim()}catch{return q}}var Pq=/<script\s+type="stx\/island"\s+data-stx-island="([^"]+)"([^>]*)>([\s\S]*?)<\/script>/g;function Cq(q){return Bun.hash(q).toString(16)}function Qq(q,Z={}){if(!q.includes('type="stx/island"'))return{html:q,chunks:[]};let $=new Map,Q=q.replace(Pq,(J,W,z,A)=>{let G=A.trim();if(!G)return J;if(/\bdata-stx-src=/.test(z))return J;if(Z.minify)G=yq(G);let X=Cq(G);if(!$.has(X))$.set(X,G);let B=Z.integrity?` data-stx-integrity="sha384-${xq("sha384").update(G).digest("base64")}"`:"";return`<script type="stx/island" data-stx-island="${W}" data-stx-src="/_stx/islands/${X}.js"${B}${z}></script>`}),K=Array.from($,([J,W])=>({hash:J,code:W}));return{html:Q,chunks:K}}var gq=new Set(["visible","idle"]);function Zq(q){if(!q.includes("data-stx-src="))return q;let Z=new Map,$=/data-stx-scope="([^"]+)"[^>]*?stx-hydrate="([^"]+)"/g,Q;while((Q=$.exec(q))!==null)Z.set(Q[1],Q[2]);let K=new Set,J=/data-stx-island="([^"]+)"[^>]*?data-stx-src="([^"]+)"/g,W;while((W=J.exec(q))!==null)if(gq.has(Z.get(W[1])||""))K.add(W[2]);let z=q.lastIndexOf("</head>");if(K.size===0||z===-1)return q;let A=Array.from(K).filter((G)=>!q.includes(`rel="prefetch" href="${G}"`)).map((G)=>`<link rel="prefetch" href="${G}" as="script">`).join("");if(!A)return q;return q.slice(0,z)+A+q.slice(z)}var fq=["STX_SITE_URL","SITE_URL","URL","VERCEL_URL","CF_PAGES_URL"];function h(q){let Z=q.trim();if(!Z)return null;let $=/^https?:\/\//i.test(Z)?Z:`https://${Z}`;try{return new URL($).origin+new URL($).pathname.replace(/\/$/,"")}catch{return null}}function mq(q){for(let Z of fq){let $=q[Z];if(!$)continue;let Q=h($);if(Q)return{url:Q,source:"env",via:Z}}return null}function $q(q){if(!q||typeof q!=="object")return null;let Z=q,$=Z.site?.url??Z.url??Z.app?.url;return typeof $==="string"?h($):null}async function dq(q){let{existsSync:Z}=await import("fs"),$=await import("path");for(let Q of["site.config.ts","site.config.js",".config/site.config.ts"]){let K=$.resolve(q,Q);if(!Z(K))continue;try{let J=await import(K),W=$q(J.default??J);if(W)return W}catch{}}return null}async function Kq(q={}){let Z=q.cwd??process.cwd(),$=q.env??process.env;if(q.explicit){let W=h(q.explicit);if(W)return{url:W,source:"option"}}let Q=$q(q.stxConfig);if(Q)return{url:Q,source:"stx.config",via:"site.url"};let K=await dq(Z);if(K)return{url:K,source:"site.config",via:"url"};let J=mq($);if(J)return J;return{url:"http://localhost",source:"fallback"}}function Wq(){return["No site URL configured \u2014 sitemap.xml and robots.txt will point at http://localhost."," Set one in stx.config.ts (site: { url: 'https://example.com' }), in site.config.ts,"," via --domain, or with SITE_URL in the build environment."].join(`
|
|
3
3
|
`)}class wq{cacheDir;cache=new Map;loaded=!1;salt;constructor(q,Z=""){this.cacheDir=q,this.salt=Z}async load(){if(this.loaded)return;let q=j.join(this.cacheDir,"build-cache.json");if(await Bun.file(q).exists())try{let Z=JSON.parse(await Bun.file(q).text());for(let[$,Q]of Object.entries(Z))this.cache.set($,Q)}catch{}this.loaded=!0}async save(){await O.promises.mkdir(this.cacheDir,{recursive:!0});let q=j.join(this.cacheDir,"build-cache.json"),Z={};for(let[$,Q]of this.cache)Z[$]=Q;await Bun.write(q,JSON.stringify(Z))}getHash(q,Z){let $=O.statSync(q),Q=`${this.salt}|${q}:${$.mtimeMs}`;for(let J of Z)if(O.existsSync(J)){let W=O.statSync(J);Q+=`:${J}:${W.mtimeMs}`}let K=0;for(let J=0;J<Q.length;J++){let W=Q.charCodeAt(J);K=(K<<5)-K+W,K=K&K}return Math.abs(K).toString(36)}get(q,Z){let $=this.cache.get(q);if(!$)return null;let Q=this.getHash(Z,$.dependencies??[]);if($.hash!==Q)return this.cache.delete(q),null;return $.html}set(q,Z,$,Q){let K=this.getHash(Z,$);this.cache.set(q,{hash:K,html:Q,generatedAt:Date.now(),dependencies:$})}}class Rq{cacheDir;constructor(q){this.cacheDir=q}getFilePath(q){let Z=q.replace(/[^a-zA-Z0-9]/g,"_")+".json";return j.join(this.cacheDir,"isr",Z)}async get(q){let Z=this.getFilePath(q);if(!await Bun.file(Z).exists())return null;try{return JSON.parse(await Bun.file(Z).text())}catch{return null}}async set(q,Z){let $=this.getFilePath(q);await O.promises.mkdir(j.dirname($),{recursive:!0}),await Bun.write($,JSON.stringify(Z))}async invalidate(q){let Z=this.getFilePath(q);if(await Bun.file(Z).exists())await O.promises.unlink(Z)}async invalidatePattern(q){let Z=j.join(this.cacheDir,"isr");if(!O.existsSync(Z))return;let $=await O.promises.readdir(Z);for(let Q of $){let K=Q.replace(/_/g,"/").replace(".json","");if(q.test(K))await O.promises.unlink(j.join(Z,Q))}}async needsRevalidation(q){let Z=await this.get(q);if(!Z)return!0;return Date.now()>Z.revalidateAfter}}async function pq(q){try{let $=(await Bun.file(q).text()).match(/<script\s+server\b[^>]*>([\s\S]*?)<\/script>/i);if(!$)return null;let Q=$[1];if(!Q.includes("getStaticPaths"))return null;let K=Q.match(/(?:export\s+)?(?:async\s+)?function\s+getStaticPaths\s*\([^)]*\)\s*\{([\s\S]*?)\n[\t ]*\}/);if(!K)return null;return await Function(`
|
|
4
4
|
return (async function getStaticPaths() {
|
|
5
5
|
${K[1]}
|
|
@@ -41,7 +41,7 @@ ${q.map((Q)=>{let K=new URL(Q.loc,Z).href,J=` <url>
|
|
|
41
41
|
${$.join(`
|
|
42
42
|
`)}
|
|
43
43
|
</channel>
|
|
44
|
-
</rss>`}async function aq(q={}){let Z=Date.now();Aq();let $=await n(process.cwd()),Q=$.build||{},K=await Kq({explicit:q.domain||Q.domain,stxConfig:$});if(K.source==="fallback"&&(q.sitemap??Q.sitemap??!0))console.warn(Wq());let J={router:q.router??$?.router??{},pagesDir:q.pagesDir||Q.pagesDir||"pages",outputDir:q.outputDir||Q.outputDir||"dist",baseUrl:q.baseUrl||Q.baseUrl||"/",domain:K.url,revalidate:q.revalidate??Q.revalidate??!1,sitemap:q.sitemap??Q.sitemap??!0,sitemapExclude:q.sitemapExclude||Q.sitemapExclude||[],robots:q.robots??Q.robots??!0,rss:q.rss??Q.rss??!1,concurrency:q.concurrency||Q.concurrency||10,cache:q.cache??Q.cache??!0,cacheDir:q.cacheDir||Q.cacheDir||d(process.cwd(),"ssg-cache"),contentLoaders:q.contentLoaders||[],hooks:q.hooks||{},minify:q.minify??Q.minify??!0,generate404:q.generate404??Q.generate404??!0,publicDir:q.publicDir||Q.publicDir||"public",trailingSlash:q.trailingSlash??Q.trailingSlash??!1,cleanOutput:q.cleanOutput??Q.cleanOutput??!0,cacheSalt:q.cacheSalt??"",partialsDir:q.partialsDir||$?.partialsDir||"",componentsDir:q.componentsDir||$?.componentsDir||"",failOnIncludeError:q.failOnIncludeError??!0,chunkIslands:q.chunkIslands===!0,prefetchIslands:q.prefetchIslands===!0,integrityIslands:q.integrityIslands===!0},W={totalPages:0,successCount:0,failedCount:0,cachedCount:0,buildTime:0,pages:[],errors:[]},z=new Set,A=0,G={},X={};await J.hooks.onBuildStart?.();try{if(J.cleanOutput&&O.existsSync(J.outputDir))await O.promises.rm(J.outputDir,{recursive:!0});await O.promises.mkdir(J.outputDir,{recursive:!0});let L=J.cacheSalt;if(!L){let{resolveUserCssConfig:Y,fingerprintConfig:N}=await import("./chunk-
|
|
44
|
+
</rss>`}async function aq(q={}){let Z=Date.now();Aq();let $=await n(process.cwd()),Q=$.build||{},K=await Kq({explicit:q.domain||Q.domain,stxConfig:$});if(K.source==="fallback"&&(q.sitemap??Q.sitemap??!0))console.warn(Wq());let J={router:q.router??$?.router??{},pagesDir:q.pagesDir||Q.pagesDir||"pages",outputDir:q.outputDir||Q.outputDir||"dist",baseUrl:q.baseUrl||Q.baseUrl||"/",domain:K.url,revalidate:q.revalidate??Q.revalidate??!1,sitemap:q.sitemap??Q.sitemap??!0,sitemapExclude:q.sitemapExclude||Q.sitemapExclude||[],robots:q.robots??Q.robots??!0,rss:q.rss??Q.rss??!1,concurrency:q.concurrency||Q.concurrency||10,cache:q.cache??Q.cache??!0,cacheDir:q.cacheDir||Q.cacheDir||d(process.cwd(),"ssg-cache"),contentLoaders:q.contentLoaders||[],hooks:q.hooks||{},minify:q.minify??Q.minify??!0,generate404:q.generate404??Q.generate404??!0,publicDir:q.publicDir||Q.publicDir||"public",trailingSlash:q.trailingSlash??Q.trailingSlash??!1,cleanOutput:q.cleanOutput??Q.cleanOutput??!0,cacheSalt:q.cacheSalt??"",partialsDir:q.partialsDir||$?.partialsDir||"",componentsDir:q.componentsDir||$?.componentsDir||"",failOnIncludeError:q.failOnIncludeError??!0,chunkIslands:q.chunkIslands===!0,prefetchIslands:q.prefetchIslands===!0,integrityIslands:q.integrityIslands===!0},W={totalPages:0,successCount:0,failedCount:0,cachedCount:0,buildTime:0,pages:[],errors:[]},z=new Set,A=0,G={},X={};await J.hooks.onBuildStart?.();try{if(J.cleanOutput&&O.existsSync(J.outputDir))await O.promises.rm(J.outputDir,{recursive:!0});await O.promises.mkdir(J.outputDir,{recursive:!0});let L=J.cacheSalt;if(!L){let{resolveUserCssConfig:Y,fingerprintConfig:N}=await import("./chunk-rd02ysw3.js");try{L=N(await Y(process.cwd()))}catch{}}let{prepareImageDelivery:_}=await import("./chunk-e631svvs.js"),F=await _(J.publicDir,J.outputDir);if(F.count>0)console.log(`Optimized ${F.count} image(s) for responsive delivery`),L=[L,F.fingerprint].filter(Boolean).join(":");let C=new wq(J.cacheDir,L);if(J.cache)await C.load();try{let{generateCss:Y}=await import("./chunk-rd02ysw3.js");await Y('<div class="bg-black"></div>')}catch{}Yq();let kq=$?.routeMiddleware?.dir||"middleware";await jq(process.cwd(),kq);let p=Vq();if(p.length>0)console.log(`Loaded ${p.length} middleware: ${p.join(", ")}`);let bq=$?.routeMiddleware?.global||[];Fq($?.layoutsDir,d(process.cwd()));let i=l(".",{pagesDir:J.pagesDir,pagesDirs:$?._layerPageDirs});console.log(`Found ${i.length} routes`);let g=[];for(let Y of i){let N=await uq(Y);for(let H of N)g.push({route:Y,url:H.url,params:H.params,props:H.props,revalidate:H.revalidate??J.revalidate})}W.totalPages=g.length,console.log(`Generating ${W.totalPages} pages...`);let b=[],s=[];for(let Y=0;Y<g.length;Y+=J.concurrency)s.push(g.slice(Y,Y+J.concurrency));for(let Y of s)await Promise.all(Y.map(async(N)=>{let{route:H,url:V,params:S,props:Sq,revalidate:a}=N;try{await J.hooks.onPageStart?.(V);let w=await Bun.file(H.filePath).text(),R=JJ(w),vq=R?.middleware?Array.isArray(R.middleware)?R.middleware:[R.middleware]:[],t=[...bq,...vq];if(t.length>0){let D=Gq(V,S,R||{}),M=Lq(D,null,void 0,{isServer:!0}),E=await Nq(t,M);if(E.redirect){let U=typeof E.redirect==="string"?E.redirect:E.redirect.path||E.redirect,x=QJ(String(U),V),k=ZJ(V,J);await O.promises.mkdir(j.dirname(k),{recursive:!0}),await Bun.write(k,x),W.successCount++,W.pages.push({route:V,outputPath:k,size:Buffer.byteLength(x),cached:!1}),b.push({loc:V,lastmod:new Date().toISOString()}),console.log(` \u21B3 ${V} \u2192 redirect to ${U}`);return}if(E.abort){let U=typeof E.abort==="string"?E.abort:E.abort?.error?.message||"aborted";console.warn(` \u21B3 ${V} \u2014 middleware aborted: ${U}`);return}}let e=w.match(/definePageMeta\s*\(\s*\{[\s\S]*?validate\s*:\s*((?:\([^)]*\)|[^,}])*(?:\{[\s\S]*?\})?)/m);if(e)try{if(!await Function("route",`
|
|
45
45
|
const validate = ${e[1]};
|
|
46
46
|
return validate(route);
|
|
47
47
|
`)({params:S})){console.warn(`Validation failed for ${V}, skipping...`);return}}catch{}let I=null,qq=!1;if(J.cache){if(I=C.get(V,H.filePath),I)qq=!0,W.cachedCount++}if(!I){let D=await Mq(H,S,Sq,J,$);if(I=D.html,J.failOnIncludeError&&D.includeFailures.length>0)throw Error(`${D.includeFailures.length} include(s) failed to resolve, so this page would have shipped with an error banner where the markup should be:
|
package/dist/stx-virtual-ts.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export interface TemplateExpression {
|
|
|
62
62
|
line: number;
|
|
63
63
|
/** 1-based column of the expression's first character. */
|
|
64
64
|
column: number;
|
|
65
|
-
kind: 'interpolation' | 'directive';
|
|
65
|
+
kind: 'interpolation' | 'directive' | 'condition';
|
|
66
66
|
/** For directives, the attribute name (`:if`, `@click`, `x-text`). */
|
|
67
67
|
attribute?: string;
|
|
68
68
|
/**
|
|
@@ -86,6 +86,15 @@ export interface MappedLine {
|
|
|
86
86
|
* the start of the attribute.
|
|
87
87
|
*/
|
|
88
88
|
prefixLength?: number;
|
|
89
|
+
/**
|
|
90
|
+
* Characters of `if (…) {` wrapper before the expression's own statement.
|
|
91
|
+
*
|
|
92
|
+
* A diagnostic inside this span is about the enclosing CONDITION, not about
|
|
93
|
+
* the expression this line carries - and the condition is checked on a line
|
|
94
|
+
* of its own, so reporting it here too would name innocent markup twice
|
|
95
|
+
* (stacksjs/stx#2013).
|
|
96
|
+
*/
|
|
97
|
+
guardPrefixLength?: number;
|
|
89
98
|
}
|
|
90
99
|
export interface VirtualFile {
|
|
91
100
|
text: string;
|
|
@@ -463,6 +472,12 @@ export interface ResolvedPosition {
|
|
|
463
472
|
column: number;
|
|
464
473
|
/** Set when the diagnostic came from a template expression. */
|
|
465
474
|
expression?: TemplateExpression;
|
|
475
|
+
/**
|
|
476
|
+
* The hit landed in the `if (…) {` wrapper that markup guards put around an
|
|
477
|
+
* expression, so it is about the CONDITION rather than this expression. The
|
|
478
|
+
* condition has a line of its own (stacksjs/stx#2013).
|
|
479
|
+
*/
|
|
480
|
+
inGuard?: boolean;
|
|
466
481
|
}
|
|
467
482
|
/**
|
|
468
483
|
* Translate a position in a virtual buffer back to the `.stx` file.
|
package/dist/stx-virtual-ts.js
CHANGED
|
@@ -173,6 +173,35 @@ export function extractTemplateExpressions(source) {
|
|
|
173
173
|
kind: "interpolation"
|
|
174
174
|
});
|
|
175
175
|
}
|
|
176
|
+
const condition = /@(if|elseif|else\s+if|unless)\b\s*\(/g;
|
|
177
|
+
while ((m = condition.exec(masked)) !== null) {
|
|
178
|
+
const open = m.index + m[0].length - 1;
|
|
179
|
+
let depth = 0, index = open;
|
|
180
|
+
for (;index < masked.length; index++) {
|
|
181
|
+
const char = masked[index];
|
|
182
|
+
if (char === "(")
|
|
183
|
+
depth++;
|
|
184
|
+
else if (char === ")") {
|
|
185
|
+
depth--;
|
|
186
|
+
if (depth === 0)
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (depth !== 0)
|
|
191
|
+
continue;
|
|
192
|
+
const raw = masked.slice(open + 1, index), code = raw.trim();
|
|
193
|
+
condition.lastIndex = index + 1;
|
|
194
|
+
if (!code)
|
|
195
|
+
continue;
|
|
196
|
+
const start = open + 1 + (raw.length - raw.trimStart().length);
|
|
197
|
+
found.push({
|
|
198
|
+
code,
|
|
199
|
+
line: lineAt(masked, start),
|
|
200
|
+
column: columnAt(masked, start),
|
|
201
|
+
offset: m.index,
|
|
202
|
+
kind: "condition"
|
|
203
|
+
});
|
|
204
|
+
}
|
|
176
205
|
DIRECTIVE_ATTR_RE.lastIndex = 0;
|
|
177
206
|
while ((m = DIRECTIVE_ATTR_RE.exec(masked)) !== null) {
|
|
178
207
|
const name = m[1], value = m[3] ?? "", base = name.replace(/\..*$/, "").replace(/^([^:].*?):.*$/, "$1");
|
|
@@ -648,7 +677,8 @@ export function buildVirtualTypeScript(source, options = {}) {
|
|
|
648
677
|
line: expression.line,
|
|
649
678
|
column: expression.column,
|
|
650
679
|
expression,
|
|
651
|
-
prefixLength: statement.prefixLength + pad.length + guardPrefix.length
|
|
680
|
+
prefixLength: statement.prefixLength + pad.length + guardPrefix.length,
|
|
681
|
+
guardPrefixLength: pad.length + guardPrefix.length
|
|
652
682
|
});
|
|
653
683
|
}
|
|
654
684
|
if (indent > 0)
|
|
@@ -689,6 +719,7 @@ export function resolvePosition(virtual, line, column) {
|
|
|
689
719
|
return {
|
|
690
720
|
line: mapped.line,
|
|
691
721
|
column: mapped.column + within,
|
|
692
|
-
expression: mapped.expression
|
|
722
|
+
expression: mapped.expression,
|
|
723
|
+
inGuard: column <= (mapped.guardPrefixLength ?? 0)
|
|
693
724
|
};
|
|
694
725
|
}
|
package/dist/theme-tokens.js
CHANGED
|
@@ -3,22 +3,26 @@ export const SEMANTIC_TOKENS = {
|
|
|
3
3
|
"fg-strong": { light: "neutral-700", dark: "neutral-300", description: "Labels, secondary headings" },
|
|
4
4
|
"fg-muted": { light: "neutral-600", dark: "neutral-400", description: "Supporting text" },
|
|
5
5
|
"fg-soft": { light: "neutral-500", dark: "neutral-400", description: "De-emphasised text" },
|
|
6
|
-
"fg-subtle": { light: "neutral-400", dark: "neutral-500", description: "
|
|
6
|
+
"fg-subtle": { light: "neutral-400", dark: "neutral-500", description: "Recessive, non-essential text" },
|
|
7
7
|
surface: { light: "neutral-50", dark: "neutral-800", description: "Page and panel background" },
|
|
8
8
|
"surface-raised": { light: "neutral-100", dark: "neutral-700", description: "Cards, popovers" },
|
|
9
9
|
"surface-sunken": { light: "neutral-200", dark: "neutral-700", description: "Wells, track backgrounds" },
|
|
10
10
|
panel: { light: "white", dark: "neutral-800", description: "Card, menu, dialog surface" },
|
|
11
11
|
field: { light: "white", dark: "neutral-700", description: "Form control surface" },
|
|
12
|
+
page: { light: "neutral-50", dark: "neutral-900", description: "Page background, behind panels" },
|
|
13
|
+
content: { light: "white", dark: "neutral-900", description: "Content area under a chrome header - a table or list body" },
|
|
12
14
|
"surface-hover": { light: "neutral-100", dark: "neutral-700", description: "Row or item highlight on a page or panel" },
|
|
13
15
|
"surface-raised-hover": { light: "neutral-200", dark: "neutral-600", description: "Raised surface, hovered" },
|
|
14
16
|
"surface-sunken-hover": { light: "neutral-300", dark: "neutral-600", description: "Sunken surface, hovered" },
|
|
15
17
|
"field-hover": { light: "neutral-50", dark: "neutral-600", description: "Form control surface, hovered" },
|
|
18
|
+
link: { light: "blue-500", dark: "blue-400", description: "Hyperlink" },
|
|
19
|
+
"link-hover": { light: "blue-600", dark: "blue-300", description: "Hyperlink, hovered" },
|
|
16
20
|
inverse: { light: "neutral-900", dark: "neutral-700", description: "Tooltip bubble, inverted surface" },
|
|
17
21
|
"inverse-ink": { light: "white", dark: "white", description: "Text on an inverted surface" },
|
|
18
22
|
line: { light: "neutral-200", dark: "neutral-700", description: "Default border, divider" },
|
|
19
23
|
"line-strong": { light: "neutral-300", dark: "neutral-600", description: "Input border, focus ring track" },
|
|
20
24
|
accent: { light: "blue-600", dark: "blue-400", description: "Primary action, selected state" },
|
|
21
|
-
info: { light: "cyan-600", dark: "cyan-400", description: "Informational emphasis
|
|
25
|
+
info: { light: "cyan-600", dark: "cyan-400", description: "Informational emphasis" },
|
|
22
26
|
danger: { light: "red-600", dark: "red-400", description: "Errors, destructive actions" },
|
|
23
27
|
success: { light: "green-600", dark: "green-400", description: "Confirmation" },
|
|
24
28
|
warning: { light: "yellow-600", dark: "yellow-400", description: "Caution" },
|
|
@@ -33,9 +37,9 @@ export const SEMANTIC_TOKENS = {
|
|
|
33
37
|
"success-solid-hover": { light: "green-600", dark: "green-700", description: "Confirmation fill, hovered" },
|
|
34
38
|
"warning-solid-hover": { light: "yellow-600", dark: "yellow-700", description: "Caution fill, hovered" },
|
|
35
39
|
"accent-ink": { light: "white", dark: "white", description: "Text on a primary fill" },
|
|
36
|
-
"info-ink": { light: "
|
|
40
|
+
"info-ink": { light: "neutral-900", dark: "neutral-900", description: "Text on an informational fill" },
|
|
37
41
|
"danger-ink": { light: "white", dark: "white", description: "Text on a destructive fill" },
|
|
38
|
-
"success-ink": { light: "
|
|
42
|
+
"success-ink": { light: "neutral-900", dark: "neutral-900", description: "Text on a confirmation fill" },
|
|
39
43
|
"warning-ink": { light: "neutral-900", dark: "neutral-900", description: "Text on a caution fill" },
|
|
40
44
|
"accent-soft": { light: "blue-100", dark: "blue-900", description: "Tinted primary fill" },
|
|
41
45
|
"accent-soft-ink": { light: "blue-800", dark: "blue-200", description: "Text on a tinted primary fill" },
|
|
@@ -54,7 +58,7 @@ export const SEMANTIC_TOKENS = {
|
|
|
54
58
|
"secondary-soft": { light: "purple-100", dark: "purple-900", description: "Tinted secondary fill" },
|
|
55
59
|
"secondary-soft-ink": { light: "purple-800", dark: "purple-200", description: "Text on a tinted secondary fill" },
|
|
56
60
|
"danger-fg": { light: "red-900", dark: "red-300", description: "Text in a field with an error" },
|
|
57
|
-
"danger-fg-subtle": { light: "red-300", dark: "red-500", description: "
|
|
61
|
+
"danger-fg-subtle": { light: "red-300", dark: "red-500", description: "Recessive text in a field with an error" },
|
|
58
62
|
"danger-line": { light: "red-300", dark: "red-600", description: "Border of a field with an error" },
|
|
59
63
|
"danger-focus": { light: "red-500", dark: "red-400", description: "Focus ring of a field with an error" }
|
|
60
64
|
};
|
package/dist/typecheck.js
CHANGED
|
@@ -305,6 +305,8 @@ export async function typecheckStxFiles(files, options = {}) {
|
|
|
305
305
|
const at = resolvePosition(entry.virtual, line, column);
|
|
306
306
|
if (!at?.expression)
|
|
307
307
|
continue;
|
|
308
|
+
if (at.inGuard)
|
|
309
|
+
continue;
|
|
308
310
|
if (Number(code) === 2774)
|
|
309
311
|
continue;
|
|
310
312
|
line = at.line;
|
|
@@ -708,6 +708,16 @@ export interface StxConfig {
|
|
|
708
708
|
defaultLayout?: string;
|
|
709
709
|
/** Plugins to load — npm packages, local paths, or [path, options] tuples */
|
|
710
710
|
plugins?: Array<string | [string, Record<string, any>]>;
|
|
711
|
+
/**
|
|
712
|
+
* Installed packages whose components resolve by bare tag, with no plugin
|
|
713
|
+
* entry and no import.
|
|
714
|
+
*
|
|
715
|
+
* Each is loaded through its own `<pkg>/stx-plugin` export if the project has
|
|
716
|
+
* it installed, and is searched AFTER every project directory - so a
|
|
717
|
+
* component the app wrote still wins. Defaults to `['@stacksjs/components']`;
|
|
718
|
+
* set it to `[]` to opt out entirely (stacksjs/stx#2011).
|
|
719
|
+
*/
|
|
720
|
+
componentPackages?: string[];
|
|
711
721
|
/** Path to public/static assets directory, defaults to 'public' */
|
|
712
722
|
publicDir?: string;
|
|
713
723
|
/** Path to .env file, defaults to '.env' in project root (Bun loads this automatically) */
|