@stacksjs/stx 0.2.674 → 0.2.676
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/{chunk-szevd7d5.js → chunk-028e9fty.js} +2 -2
- package/dist/{chunk-rr527jt6.js → chunk-078qg8r5.js} +2 -2
- package/dist/chunk-0gk78x3r.js +2 -0
- package/dist/{chunk-fw413k9q.js → chunk-1b9thkg5.js} +2 -2
- package/dist/chunk-1e73whqh.js +2 -0
- package/dist/chunk-1rztwjdj.js +130 -0
- package/dist/{chunk-srq9fqq8.js → chunk-245sas8r.js} +38 -38
- package/dist/chunk-248a88mc.js +2 -0
- package/dist/chunk-2nqtmp8c.js +2 -0
- package/dist/chunk-2pga7zzb.js +4 -0
- package/dist/{chunk-bkkpq8dx.js → chunk-304dbbsw.js} +10 -10
- package/dist/{chunk-z22zy22p.js → chunk-34e8e8te.js} +2 -2
- package/dist/{chunk-md2jn67b.js → chunk-374nhgyf.js} +2 -2
- package/dist/chunk-3bfegbpw.js +2 -0
- package/dist/chunk-3gdt16xa.js +2 -0
- package/dist/chunk-3wsm9g9c.js +2 -0
- package/dist/chunk-3xx9d934.js +2 -0
- package/dist/{chunk-ham5x7ts.js → chunk-4fhbh04h.js} +4 -4
- package/dist/{chunk-5vt48yce.js → chunk-4jnv2v5e.js} +9 -9
- package/dist/chunk-4rk5qnqf.js +24 -0
- package/dist/chunk-526mf3fr.js +4 -0
- package/dist/chunk-54zkkxmb.js +2 -0
- package/dist/{chunk-kdebh22m.js → chunk-551s7ha0.js} +10 -10
- package/dist/chunk-5v7vm8cv.js +14 -0
- package/dist/{chunk-rdr09efy.js → chunk-5z0q3qv3.js} +5 -5
- package/dist/{chunk-6sjtyd0k.js → chunk-5z8mq37c.js} +4 -4
- package/dist/{chunk-ce6zddpf.js → chunk-6beg47t4.js} +2 -2
- package/dist/{chunk-trz8z4j4.js → chunk-6bwca55g.js} +37 -37
- package/dist/chunk-6kam8r5y.js +2 -0
- package/dist/{chunk-tddnb5bv.js → chunk-6ycyaf5g.js} +2 -2
- package/dist/chunk-707sx5sk.js +20 -0
- package/dist/chunk-78d5tn4r.js +2 -0
- package/dist/{chunk-pb6erpj3.js → chunk-78x52gz3.js} +5 -5
- package/dist/{chunk-zp79zkkd.js → chunk-78yjmbbs.js} +2 -2
- package/dist/{chunk-v21bhhjb.js → chunk-7j7h1eg3.js} +1 -1
- package/dist/{chunk-zmg1peyg.js → chunk-8aq07a1j.js} +3 -3
- package/dist/chunk-8p92r2sc.js +2 -0
- package/dist/chunk-909ymsjz.js +2 -0
- package/dist/{chunk-r7fdw2v5.js → chunk-97h9ga3b.js} +3 -3
- package/dist/chunk-9859r1d5.js +2 -0
- package/dist/{chunk-25zmy8q6.js → chunk-9wdd7eq6.js} +2 -2
- package/dist/{chunk-p6qd7ad0.js → chunk-a2zb5fgg.js} +2 -2
- package/dist/chunk-arh1qgmp.js +2 -0
- package/dist/chunk-b18x0v21.js +2 -0
- package/dist/chunk-b23vscaq.js +2 -0
- package/dist/{chunk-4b9s7wgy.js → chunk-be2rswkw.js} +2 -2
- package/dist/{chunk-qz5b8ed4.js → chunk-bh19ezq0.js} +5 -5
- package/dist/chunk-bm42rsaa.js +2 -0
- package/dist/{chunk-cbjabv1w.js → chunk-bpj387yx.js} +6 -6
- package/dist/chunk-c4enpsj8.js +2 -0
- package/dist/chunk-cdbaanmx.js +2 -0
- package/dist/chunk-cfm6a679.js +2 -0
- package/dist/chunk-cs8wq7nv.js +2 -0
- package/dist/{chunk-hegfgw27.js → chunk-cxgremn0.js} +5 -5
- package/dist/chunk-d2xf5hh9.js +2 -0
- package/dist/{chunk-rym0309c.js → chunk-d4ch6exz.js} +3 -3
- package/dist/chunk-dda8pdya.js +2 -0
- package/dist/{chunk-7adznted.js → chunk-dera8fmc.js} +2 -2
- package/dist/chunk-dmd7mgjw.js +3 -0
- package/dist/chunk-ds91e0fe.js +2 -0
- package/dist/{chunk-hgry3mjd.js → chunk-dxh45gve.js} +1 -1
- package/dist/chunk-e492je6q.js +2 -0
- package/dist/{chunk-7j1zgrnf.js → chunk-ehzd1yc6.js} +9 -9
- package/dist/chunk-etz2dmec.js +2 -0
- package/dist/{chunk-4s8zacxg.js → chunk-f26n6y9p.js} +4 -4
- package/dist/{chunk-4w6baw62.js → chunk-fbrgz3s8.js} +2 -2
- package/dist/chunk-fd72t30s.js +2 -0
- package/dist/{chunk-sqn3y9qt.js → chunk-fdvfzknd.js} +2 -2
- package/dist/chunk-ft3f9nj0.js +2 -0
- package/dist/{chunk-dgc1a3yt.js → chunk-fzc98qgn.js} +7 -7
- package/dist/{chunk-s0vtjyyj.js → chunk-g12ht81a.js} +2 -2
- package/dist/chunk-g6gqja52.js +2 -0
- package/dist/{chunk-hb3edeq9.js → chunk-ga5kjf9b.js} +6 -6
- package/dist/chunk-ggwvnpwj.js +2 -0
- package/dist/{chunk-hsmcbh0p.js → chunk-ghm9f13q.js} +5 -5
- package/dist/chunk-gx6wxmbv.js +2 -0
- package/dist/chunk-gz5rvwgx.js +2 -0
- package/dist/chunk-hamk3dky.js +2 -0
- package/dist/{chunk-vayhx642.js → chunk-haz2ezyk.js} +2 -2
- package/dist/chunk-hh58k0nh.js +3 -0
- package/dist/chunk-hqj28381.js +3 -0
- package/dist/chunk-j60jye3e.js +25 -0
- package/dist/chunk-jjet6qxq.js +2 -0
- package/dist/chunk-jk7chxkt.js +2 -0
- package/dist/{chunk-d09q93yf.js → chunk-jv021x8e.js} +2 -2
- package/dist/{chunk-pg2v1pb5.js → chunk-k06n5bjp.js} +3 -3
- package/dist/{chunk-35ezh7de.js → chunk-k72jqz6a.js} +3 -3
- package/dist/chunk-kn34esxw.js +2 -0
- package/dist/chunk-kqbpkg8n.js +2 -0
- package/dist/{chunk-aet1pgw7.js → chunk-krcd3039.js} +74 -74
- package/dist/{chunk-asezs2n3.js → chunk-kxj8e1gd.js} +6 -6
- package/dist/{chunk-5zhp87wv.js → chunk-mabja59q.js} +2 -2
- package/dist/chunk-mf19qxgv.js +3 -0
- package/dist/chunk-mjsebtg6.js +2 -0
- package/dist/{chunk-fd49fahd.js → chunk-mn47s2ef.js} +5 -5
- package/dist/{chunk-nj343mw2.js → chunk-mq915g3j.js} +5 -5
- package/dist/chunk-n63r9b4f.js +2 -0
- package/dist/{chunk-j6m8xqh3.js → chunk-n8wvqnfc.js} +2 -2
- package/dist/chunk-n94ts3t9.js +21 -0
- package/dist/{chunk-w7t2cfgy.js → chunk-p27ptd9f.js} +65 -65
- package/dist/{chunk-t0k16vqv.js → chunk-p9az13b2.js} +2 -2
- package/dist/chunk-pwn0j1vq.js +2 -0
- package/dist/chunk-q1jcf6vm.js +2 -0
- package/dist/{chunk-am2w363p.js → chunk-q3gactm1.js} +4 -4
- package/dist/chunk-q3nnaxf9.js +2 -0
- package/dist/{chunk-w3d98907.js → chunk-q4rejyd2.js} +2 -2
- package/dist/{chunk-hz4x7h0n.js → chunk-qbzqary0.js} +5 -5
- package/dist/{chunk-a4p18ybc.js → chunk-qr7a378v.js} +3 -3
- package/dist/{chunk-bsajk82t.js → chunk-qwdcts9w.js} +19 -19
- package/dist/chunk-rc79yyqx.js +2 -0
- package/dist/{chunk-yx3dpdwc.js → chunk-rfc5pdv2.js} +3 -3
- package/dist/chunk-rnws0dh3.js +2 -0
- package/dist/chunk-rxxajm31.js +31 -0
- package/dist/{chunk-thceyzj6.js → chunk-rza1p6e4.js} +2 -2
- package/dist/chunk-s73z8zss.js +11 -0
- package/dist/chunk-s8qe247r.js +2 -0
- package/dist/{chunk-d1a86qx8.js → chunk-sptewgky.js} +1 -1
- package/dist/{chunk-mwnhdsbp.js → chunk-sqh3tvtw.js} +2 -2
- package/dist/{chunk-6s7tvmqp.js → chunk-sr3hmrah.js} +2 -2
- package/dist/chunk-sswy3tfc.js +2 -0
- package/dist/chunk-swxznm5v.js +2 -0
- package/dist/{chunk-9dtbvjpp.js → chunk-tmqrbs98.js} +31 -20
- package/dist/chunk-tst8p27s.js +12 -0
- package/dist/chunk-tz09earb.js +2 -0
- package/dist/{chunk-fbmth6xv.js → chunk-vay5v6sj.js} +13 -13
- package/dist/{chunk-ck2e3e47.js → chunk-vd5w1jaz.js} +3 -3
- package/dist/chunk-vewt3464.js +2 -0
- package/dist/{chunk-xghcsg3f.js → chunk-vg1pg6yt.js} +1 -1
- package/dist/{chunk-s2wptfm1.js → chunk-wav0xbnb.js} +2 -2
- package/dist/chunk-whzvx5w5.js +2 -0
- package/dist/chunk-wk1gt95z.js +2 -0
- package/dist/{chunk-t9kxhe46.js → chunk-wr1gm35v.js} +1 -1
- package/dist/{chunk-faakv1p6.js → chunk-wscnjtss.js} +2 -2
- package/dist/{chunk-t79jfpv6.js → chunk-x4q4bx3q.js} +2 -2
- package/dist/chunk-x63f2ywm.js +2 -0
- package/dist/{chunk-y1pcdeg9.js → chunk-x7wr720m.js} +5 -5
- package/dist/chunk-xk7cp691.js +2 -0
- package/dist/chunk-xna6b7km.js +2 -0
- package/dist/{chunk-v6peecfp.js → chunk-xnx06qqt.js} +2 -2
- package/dist/chunk-xw4rm5zj.js +2 -0
- package/dist/{chunk-5qtthtg3.js → chunk-y34tyrpb.js} +7 -7
- package/dist/chunk-yar7fwrb.js +2 -0
- package/dist/{chunk-2zzc7006.js → chunk-yn9kvsk1.js} +2 -2
- package/dist/chunk-yt33wzqk.js +2 -0
- package/dist/chunk-z35ftpqp.js +421 -0
- package/dist/{chunk-4bgjrrvz.js → chunk-z7ghjs7w.js} +1 -1
- package/dist/chunk-zq7xbc1k.js +2 -0
- package/dist/cli.js +22 -22
- package/dist/client/signals-for-runtime.js +16 -5
- package/dist/craft-entry.js +2 -2
- package/dist/craft.js +2 -2
- package/dist/native/compiler/headwind-to-style.js +13 -1
- package/dist/native/compiler/html-to-ir.d.ts +2 -0
- package/dist/native/compiler/html-to-ir.js +9 -0
- package/dist/native/compiler/ir.d.ts +1 -0
- package/dist/native/compiler/render-screen.js +4 -3
- package/dist/native/compiler/style-config.d.ts +3 -0
- package/dist/native/compiler/style-config.js +5 -0
- package/dist/native/components/primitives.d.ts +2 -0
- package/dist/native/event-names.js +2 -0
- package/dist/native/prop-names.js +1 -0
- package/dist/native/runtime/craft-bridge.js +15 -8
- package/dist/pwa.js +3 -3
- package/dist/signal-processing.js +75 -16
- package/dist/ssg-static-paths.d.ts +12 -0
- package/dist/ssg-static-paths.js +62 -0
- package/dist/ssg.d.ts +2 -4
- package/dist/ssg.js +43 -47
- package/dist/utils.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-0jwdcqj8.js +0 -2
- package/dist/chunk-0mwdq478.js +0 -2
- package/dist/chunk-0nfqgv4n.js +0 -4
- package/dist/chunk-1y6egkty.js +0 -2
- package/dist/chunk-280p4q7a.js +0 -2
- package/dist/chunk-2881tcqt.js +0 -2
- package/dist/chunk-2a775q7x.js +0 -2
- package/dist/chunk-2asdbd5e.js +0 -2
- package/dist/chunk-34yj93hh.js +0 -2
- package/dist/chunk-40tswfe7.js +0 -21
- package/dist/chunk-41de209e.js +0 -2
- package/dist/chunk-506mv7hb.js +0 -3
- package/dist/chunk-5s1ay9mv.js +0 -2
- package/dist/chunk-7kznee1g.js +0 -2
- package/dist/chunk-7mvz972c.js +0 -12
- package/dist/chunk-80zgyaqe.js +0 -2
- package/dist/chunk-84tqb1rn.js +0 -2
- package/dist/chunk-8azm7nha.js +0 -2
- package/dist/chunk-902qnyg0.js +0 -2
- package/dist/chunk-9n6jwcpb.js +0 -2
- package/dist/chunk-a6y8td0d.js +0 -2
- package/dist/chunk-a7kt1ts4.js +0 -2
- package/dist/chunk-a81y8g40.js +0 -2
- package/dist/chunk-aft1zc84.js +0 -2
- package/dist/chunk-bawq4fqy.js +0 -31
- package/dist/chunk-bdp2r0v4.js +0 -2
- package/dist/chunk-brtvm8mb.js +0 -2
- package/dist/chunk-bvzr9zqt.js +0 -2
- package/dist/chunk-cbvgtf3m.js +0 -2
- package/dist/chunk-cfydbaeq.js +0 -2
- package/dist/chunk-dq8c3h4n.js +0 -2
- package/dist/chunk-e36pne7n.js +0 -2
- package/dist/chunk-e62qfexp.js +0 -2
- package/dist/chunk-eq5jzaj5.js +0 -2
- package/dist/chunk-f9zyf9n6.js +0 -421
- package/dist/chunk-fb7t1nn9.js +0 -24
- package/dist/chunk-fr39emcz.js +0 -2
- package/dist/chunk-fsq13amm.js +0 -2
- package/dist/chunk-fxh12vqd.js +0 -2
- package/dist/chunk-gcc9fa33.js +0 -2
- package/dist/chunk-h6t2ney6.js +0 -2
- package/dist/chunk-hvtzw1jh.js +0 -2
- package/dist/chunk-j8g5cvvm.js +0 -2
- package/dist/chunk-jzjpyyw2.js +0 -2
- package/dist/chunk-k1b8x73j.js +0 -2
- package/dist/chunk-nw9bdk2n.js +0 -2
- package/dist/chunk-p4jkswz8.js +0 -2
- package/dist/chunk-p4r90vqf.js +0 -2
- package/dist/chunk-p8bgy5tt.js +0 -2
- package/dist/chunk-pqqe2b6m.js +0 -11
- package/dist/chunk-q6nwcav4.js +0 -2
- package/dist/chunk-qmqavdz2.js +0 -2
- package/dist/chunk-qpw72bty.js +0 -2
- package/dist/chunk-qwnh1kj6.js +0 -2
- package/dist/chunk-qy9m6qdn.js +0 -2
- package/dist/chunk-qychcdsm.js +0 -2
- package/dist/chunk-rj3w1ama.js +0 -2
- package/dist/chunk-rv39s5az.js +0 -20
- package/dist/chunk-sf0r963g.js +0 -2
- package/dist/chunk-ss820yys.js +0 -2
- package/dist/chunk-t4j9g2vh.js +0 -2
- package/dist/chunk-trh7s6k3.js +0 -130
- package/dist/chunk-ttemwrbx.js +0 -2
- package/dist/chunk-twqzn21x.js +0 -14
- package/dist/chunk-v14rq8b4.js +0 -3
- package/dist/chunk-vdxg7e1y.js +0 -4
- package/dist/chunk-vq513cxx.js +0 -2
- package/dist/chunk-vvq8xe3n.js +0 -2
- package/dist/chunk-w8t31bn9.js +0 -2
- package/dist/chunk-x1kz4d7j.js +0 -2
- package/dist/chunk-xaa36b0x.js +0 -3
- package/dist/chunk-xcsyqwxf.js +0 -25
- package/dist/chunk-xn9jrjzh.js +0 -2
- package/dist/chunk-z97bwx8m.js +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DENSITY_FONT_SIZES, DENSITY_SPACING, SEMANTIC_TOKENS, SHAPE_TOKENS, tokenVariable } from "../../theme-tokens.js";
|
|
2
2
|
import { nativeDensitySpacing, nativeDensityType, nativeShapeRadius } from "./design-tokens.js";
|
|
3
|
-
import { nativeBreakpoint, nativeShortcut, nativeThemeColor } from "./style-config.js";
|
|
3
|
+
import { nativeBreakpoint, nativeShortcut, nativeThemeColor, nativeThemeFont } from "./style-config.js";
|
|
4
4
|
import { parseNativeStyle } from "./inline-style.js";
|
|
5
5
|
const colors = {
|
|
6
6
|
transparent: "transparent",
|
|
@@ -712,6 +712,18 @@ const classParsers = {
|
|
|
712
712
|
"overflow-x-scroll": () => !0,
|
|
713
713
|
"overflow-y-auto": () => !0,
|
|
714
714
|
"overflow-y-scroll": () => !0,
|
|
715
|
+
"font-sans": (_, style) => {
|
|
716
|
+
style.fontFamily = nativeThemeFont("sans") ?? "sans-serif";
|
|
717
|
+
return !0;
|
|
718
|
+
},
|
|
719
|
+
"font-serif": (_, style) => {
|
|
720
|
+
style.fontFamily = nativeThemeFont("serif") ?? "serif";
|
|
721
|
+
return !0;
|
|
722
|
+
},
|
|
723
|
+
"font-mono": (_, style) => {
|
|
724
|
+
style.fontFamily = nativeThemeFont("mono") ?? "monospace";
|
|
725
|
+
return !0;
|
|
726
|
+
},
|
|
715
727
|
"font-thin": (_, style) => {
|
|
716
728
|
style.fontWeight = "100";
|
|
717
729
|
return !0;
|
|
@@ -21,6 +21,8 @@ export declare function mustacheBinding(text: string): string | null;
|
|
|
21
21
|
export declare function translateHtmlToIR(html: string, options?: TranslateOptions): Promise<TranslationResult>;
|
|
22
22
|
/** The same translation, wrapped in an `STXDocument` for the renderers. */
|
|
23
23
|
export declare function translateHtmlToDocument(html: string, options?: TranslateOptions & { script?: STXDocument['script'] }): Promise<{ document: STXDocument, diagnostics: TranslationDiagnostic[] }>;
|
|
24
|
+
/** Explicit website-only markup; unlike chrome this does not configure app navigation. */
|
|
25
|
+
export declare function excludeNativeSubtrees(html: string): Promise<string>;
|
|
24
26
|
/**
|
|
25
27
|
* Every event name at least one renderer dispatches on.
|
|
26
28
|
*
|
|
@@ -22,6 +22,7 @@ export const NATIVE_EVENTS = new Set([
|
|
|
22
22
|
"onEndReached",
|
|
23
23
|
"onError",
|
|
24
24
|
"onFocus",
|
|
25
|
+
"onPageSelected",
|
|
25
26
|
"onLayout",
|
|
26
27
|
"onLoad",
|
|
27
28
|
"onLoadEnd",
|
|
@@ -248,6 +249,7 @@ function settle(frame, diagnostics) {
|
|
|
248
249
|
return node;
|
|
249
250
|
}
|
|
250
251
|
export async function translateHtmlToIR(html, options = {}) {
|
|
252
|
+
html = await excludeNativeSubtrees(html);
|
|
251
253
|
const diagnostics = [], stylesheetTheme = await extractStylesheetTheme(html, (name) => diagnostics.push({ kind: "unsupported-theme-rule", tag: "style", name })), stylesheetVariables = createStyleVariables(stylesheetTheme.light).computed(), usedClasses = new Set([...html.matchAll(/\sclass(?:name)?\s*=\s*"([^"]*)"/gi)].flatMap((match) => match[1].split(/\s+/))), stylesheetRules = await extractStylesheetRules(html, (name, classes) => {
|
|
252
254
|
if (!classes.length || classes.some((name) => usedClasses.has(name)))
|
|
253
255
|
diagnostics.push({ kind: "unsupported-style-rule", tag: "style", name });
|
|
@@ -566,3 +568,10 @@ export async function translateHtmlToDocument(html, options = {}) {
|
|
|
566
568
|
diagnostics
|
|
567
569
|
};
|
|
568
570
|
}
|
|
571
|
+
export async function excludeNativeSubtrees(html) {
|
|
572
|
+
if (!/\bdata-native-exclude\b/i.test(html))
|
|
573
|
+
return html;
|
|
574
|
+
return new HTMLRewriter().on("[data-native-exclude]", { element(element) {
|
|
575
|
+
element.remove();
|
|
576
|
+
} }).transform(new Response(html)).text();
|
|
577
|
+
}
|
|
@@ -5,7 +5,7 @@ import { classifyAttribute, extractBindingManifest } from "../../binding-manifes
|
|
|
5
5
|
import { processDirectives } from "../../process.js";
|
|
6
6
|
import { processScriptSetup } from "../../signal-processing.js";
|
|
7
7
|
import { appThemeCSS } from "./app-theme.js";
|
|
8
|
-
import { translateHtmlToDocument } from "./html-to-ir.js";
|
|
8
|
+
import { excludeNativeSubtrees, translateHtmlToDocument } from "./html-to-ir.js";
|
|
9
9
|
import { extractClientScript } from "./client-script.js";
|
|
10
10
|
import { extractLayoutChrome } from "./layout-chrome.js";
|
|
11
11
|
import { extractGeneratedSetupScript, extractNativeClientScripts } from "./setup-script.js";
|
|
@@ -20,6 +20,7 @@ export function nativePrimitivesDir() {
|
|
|
20
20
|
return candidates[0];
|
|
21
21
|
}
|
|
22
22
|
export async function compileScreenSource(source, filePath, options = {}) {
|
|
23
|
+
source = await excludeNativeSubtrees(source);
|
|
23
24
|
const root = options.root ?? path.dirname(filePath), loaded = await loadStxConfig(root), sourceRoot = typeof loaded.root === "string" && loaded.root ? path.resolve(root, loaded.root) : root, fromRoot = (dir, fallback) => dir ? path.isAbsolute(dir) ? dir : path.resolve(sourceRoot, dir) : path.join(sourceRoot, fallback), config = {
|
|
24
25
|
root,
|
|
25
26
|
layoutsDir: fromRoot(loaded.layoutsDir, "layouts"),
|
|
@@ -29,11 +30,11 @@ export async function compileScreenSource(source, filePath, options = {}) {
|
|
|
29
30
|
buildMode: "serve",
|
|
30
31
|
cache: !1,
|
|
31
32
|
_targetComponentDirs: [nativePrimitivesDir()],
|
|
32
|
-
_targetComponentFallbackNames: ["Button", "Checkbox", "Switch", "TextInput"],
|
|
33
|
+
_targetComponentFallbackNames: ["Button", "Checkbox", "Switch", "TextInput", "Video"],
|
|
33
34
|
_nativeHostAttrs: !0,
|
|
34
35
|
skipEventDirectives: !0,
|
|
35
36
|
_pluginComponentDirs: loaded._pluginComponentDirs ?? []
|
|
36
|
-
}, context = { ...options.context ?? {}, __stx_inject_css: !1, __stx_native_screen: !0 }, dependencies = new Set([filePath]), renderedHtml = await processDirectives(source, context, filePath, config, dependencies), { html: content, chrome } = await extractLayoutChrome(renderedHtml), { html, manifest } = extractBindingManifest(content), theme = await appThemeCSS(root), { document, diagnostics } = await translateHtmlToDocument(theme ? `<style>${theme}</style>${html}` : html, {
|
|
37
|
+
}, context = { ...options.context ?? {}, __stx_inject_css: !1, __stx_native_screen: !0 }, dependencies = new Set([filePath]), renderedHtml = await processDirectives(source, context, filePath, config, dependencies), { html: content, chrome } = await extractLayoutChrome(await excludeNativeSubtrees(renderedHtml)), { html, manifest } = extractBindingManifest(await excludeNativeSubtrees(content)), theme = await appThemeCSS(root), { document, diagnostics } = await translateHtmlToDocument(theme ? `<style>${theme}</style>${html}` : html, {
|
|
37
38
|
source: filePath,
|
|
38
39
|
script: extractClientScript(source)
|
|
39
40
|
});
|
|
@@ -13,6 +13,8 @@ export declare function nativeShortcut(name: string): string | undefined;
|
|
|
13
13
|
export declare function nativeThemeColor(name: string): string | undefined;
|
|
14
14
|
/** A breakpoint's min-width in points, or undefined when `name` is not one. */
|
|
15
15
|
export declare function nativeBreakpoint(name: string): number | undefined;
|
|
16
|
+
/** The app font stack; generic families are resolved by the platform host. */
|
|
17
|
+
export declare function nativeThemeFont(name: string): string | undefined;
|
|
16
18
|
/**
|
|
17
19
|
* The app's own utility vocabulary, for native styles.
|
|
18
20
|
*
|
|
@@ -28,5 +30,6 @@ export declare const DEFAULT_BREAKPOINTS: Readonly<Record<string, number>>;
|
|
|
28
30
|
export declare interface NativeStyleConfig {
|
|
29
31
|
shortcuts?: Record<string, string>
|
|
30
32
|
colors?: Record<string, unknown>
|
|
33
|
+
fontFamily?: Record<string, string | string[]>
|
|
31
34
|
breakpoints?: Record<string, number>
|
|
32
35
|
}
|
|
@@ -33,6 +33,7 @@ function resolve(config) {
|
|
|
33
33
|
return {
|
|
34
34
|
shortcuts: new Map(Object.entries(config.shortcuts ?? {}).filter(([, value]) => typeof value === "string")),
|
|
35
35
|
colors: flattenColors(config.colors),
|
|
36
|
+
fontFamily: new Map(Object.entries(config.fontFamily ?? {}).map(([name, value]) => [name, Array.isArray(value) ? value.join(", ") : value])),
|
|
36
37
|
breakpoints: new Map(Object.entries({ ...DEFAULT_BREAKPOINTS, ...breakpointsOf(config.breakpoints) }))
|
|
37
38
|
};
|
|
38
39
|
}
|
|
@@ -56,6 +57,7 @@ export function nativeStyleConfigFrom(cssConfig) {
|
|
|
56
57
|
const theme = cssConfig.theme ?? {}, shortcuts = Object.fromEntries(Object.entries(cssConfig.shortcuts ?? {}).filter(([, value]) => typeof value === "string"));
|
|
57
58
|
return {
|
|
58
59
|
...Object.keys(shortcuts).length ? { shortcuts } : {},
|
|
60
|
+
...theme.fontFamily ? { fontFamily: JSON.parse(JSON.stringify(theme.fontFamily)) } : {},
|
|
59
61
|
...theme.colors ? { colors: JSON.parse(JSON.stringify(theme.colors)) } : {},
|
|
60
62
|
...theme.screens ? { breakpoints: breakpointsOf(theme.screens) } : {}
|
|
61
63
|
};
|
|
@@ -69,3 +71,6 @@ export function nativeThemeColor(name) {
|
|
|
69
71
|
export function nativeBreakpoint(name) {
|
|
70
72
|
return active().breakpoints.get(name);
|
|
71
73
|
}
|
|
74
|
+
export function nativeThemeFont(name) {
|
|
75
|
+
return active().fontFamily.get(name);
|
|
76
|
+
}
|
|
@@ -81,6 +81,8 @@ export declare interface ScrollViewProps extends ViewProps {
|
|
|
81
81
|
refreshControl?: RefreshControlProps
|
|
82
82
|
stickyHeaderIndices?: number[]
|
|
83
83
|
scrollTarget?: string | { id: string, key?: string | number, animated?: boolean } | null
|
|
84
|
+
pageIndex?: number
|
|
85
|
+
onPageSelected?: (event: { nativeEvent: { index: number, count: number } }) => void
|
|
84
86
|
pagingEnabled?: boolean
|
|
85
87
|
scrollEnabled?: boolean
|
|
86
88
|
}
|
|
@@ -32,6 +32,8 @@ export const NATIVE_EVENT_NAMES = {
|
|
|
32
32
|
momentumscrollbegin: "onMomentumScrollBegin",
|
|
33
33
|
"momentum-scroll-end": "onMomentumScrollEnd",
|
|
34
34
|
momentumscrollend: "onMomentumScrollEnd",
|
|
35
|
+
"page-selected": "onPageSelected",
|
|
36
|
+
pageselected: "onPageSelected",
|
|
35
37
|
refresh: "onRefresh",
|
|
36
38
|
layout: "onLayout",
|
|
37
39
|
"end-reached": "onEndReached",
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { STXBridge } from "../bridge/protocol.js";
|
|
1
|
+
import { NativeCapabilityError, STXBridge } from "../bridge/protocol.js";
|
|
2
2
|
import { createEventSourceClass, createStreamingBody } from "./event-stream.js";
|
|
3
3
|
import { abortError, isNativeDocument, NativeFormData, nativeFormParts, updateNativeDocumentVisibility } from "./jsc-globals.js";
|
|
4
4
|
import { buttonsKey, changedTabItems, chromePath, hostButton, mergeChromeButtons } from "./navigation-chrome.js";
|
|
5
5
|
import { installNativeNavigation, nativeRouteParams } from "./web-navigation.js";
|
|
6
6
|
import { installNativeWebStorage } from "./web-storage.js";
|
|
7
|
+
const permissionFallbacks = new WeakSet;
|
|
7
8
|
function capabilityFlags(capabilities) {
|
|
8
9
|
return {
|
|
9
10
|
desktop: capabilities.has("desktop"),
|
|
@@ -549,13 +550,6 @@ export function installCraftBridge(protocol, nativeBridge, target = globalThis,
|
|
|
549
550
|
openSettings: () => request("Push", "openSettings", []).then(Boolean)
|
|
550
551
|
};
|
|
551
552
|
craft.registerPush = craft.push.register;
|
|
552
|
-
craft.permissions = Object.assign({}, craft.permissions, {
|
|
553
|
-
check: (permission) => permission === "notifications" ? craft.push.getPermissionStatus() : Promise.resolve("undetermined"),
|
|
554
|
-
request: (permission) => permission === "notifications" ? craft.push.requestPermission() : Promise.resolve("undetermined"),
|
|
555
|
-
openSettings: () => craft.push.openSettings().then(() => {
|
|
556
|
-
return;
|
|
557
|
-
})
|
|
558
|
-
});
|
|
559
553
|
protocol.on("PUSH_TOKEN", ({ payload }) => {
|
|
560
554
|
const token = String(payload?.token || "");
|
|
561
555
|
if (!token)
|
|
@@ -565,6 +559,19 @@ export function installCraftBridge(protocol, nativeBridge, target = globalThis,
|
|
|
565
559
|
target.dispatchEvent(new target.CustomEvent("craftPushToken", { detail: { token } }));
|
|
566
560
|
});
|
|
567
561
|
}
|
|
562
|
+
const permissions = craft.permissions ??= {}, unsupportedPermission = (method, permission) => Promise.reject(new NativeCapabilityError("PERMISSION_UNSUPPORTED", `Native permissions.${method}${permission === void 0 ? "" : `("${permission}")`} is not supported by this host`)), permissionDefaults = {
|
|
563
|
+
check: (permission) => capabilities.has("push") && permission === "notifications" ? craft.push.getPermissionStatus() : unsupportedPermission("check", permission),
|
|
564
|
+
request: (permission) => capabilities.has("push") && permission === "notifications" ? craft.push.requestPermission() : unsupportedPermission("request", permission),
|
|
565
|
+
openSettings: () => capabilities.has("push") ? craft.push.openSettings().then(() => {
|
|
566
|
+
return;
|
|
567
|
+
}) : unsupportedPermission("openSettings")
|
|
568
|
+
};
|
|
569
|
+
for (const [method, fallback] of Object.entries(permissionDefaults)) {
|
|
570
|
+
if (typeof permissions[method] === "function" && !permissionFallbacks.has(permissions[method]))
|
|
571
|
+
continue;
|
|
572
|
+
permissions[method] = fallback;
|
|
573
|
+
permissionFallbacks.add(fallback);
|
|
574
|
+
}
|
|
568
575
|
if (capabilities.has("health")) {
|
|
569
576
|
craft.health = {
|
|
570
577
|
requestAuthorization: (types, options = {}) => ask("Health", "requestAuthorization", [types, options]),
|
package/dist/pwa.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
3
|
-
Icon generation requires the sharp package for image processing.`),e.success=!1,e}let g=await c.default(o).metadata();if(g.width&&g.width<512)e.warnings.push(`Source icon is ${g.width}x${g.height}. Recommend using at least 512x512 for best quality.`);for(let i of s){let d=u.join(a,`icon-${i}x${i}.png`);if(await c.default(o).resize(i,i,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(d),e.generatedFiles.push(d),l){let x=u.join(a,`icon-${i}x${i}.webp`);await c.default(o).resize(i,i,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).webp({quality:90}).toFile(x),e.generatedFiles.push(x)}}if(p){for(let d of S){let x=u.join(a,`apple-touch-icon-${d}x${d}.png`);await c.default(o).resize(d,d,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile(x),e.generatedFiles.push(x)}let i=u.join(a,"apple-touch-icon.png");await c.default(o).resize(180,180,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile(i),e.generatedFiles.push(i)}for(let i of P){let d=u.join(a,`favicon-${i}x${i}.png`);await c.default(o).resize(i,i,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(d),e.generatedFiles.push(d)}let f=512,y=u.join(a,`icon-maskable-${f}x${f}.png`),m=Math.floor(f*0.1),k=f-m*2;await c.default(o).resize(k,k,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).extend({top:m,bottom:m,left:m,right:m,background:{r:255,g:255,b:255,alpha:1}}).png().toFile(y),e.generatedFiles.push(y)}catch(c){let h=c instanceof Error?c.message:String(c);e.errors.push(`Icon generation failed: ${h}`),e.success=!1}return e}function N(n){let t=n.sizes||v,e=n.outputDir?`/${n.outputDir}`:"/pwa-icons",r=n.generateWebP??!0,o=n.generateAppleIcons??!0,a=[];for(let s of t)if(a.push(`${e}/icon-${s}x${s}.png`),r)a.push(`${e}/icon-${s}x${s}.webp`);if(o){a.push(`${e}/apple-touch-icon.png`);for(let s of S)a.push(`${e}/apple-touch-icon-${s}x${s}.png`)}for(let s of P)a.push(`${e}/favicon-${s}x${s}.png`);return a.push(`${e}/icon-maskable-512x512.png`),a}async function I(){try{return await import("sharp"),!0}catch{return!1}}function A(n,t,e,r){let o=[],a=r.join(" ");for(let s of n)if(o.push({src:`${t}/icon-${s}x${s}.png`,sizes:`${s}x${s}`,type:"image/png",purpose:a}),e)o.push({src:`${t}/icon-${s}x${s}.webp`,sizes:`${s}x${s}`,type:"image/webp",purpose:a});return o}function C(n){return n.map((t)=>({name:t.name,short_name:t.shortName,description:t.description,url:t.url,icons:t.icons?.map((e)=>({src:e.src,sizes:e.sizes,type:e.type}))}))}function T(n){let t=n.pwa?.shareTarget;if(!t?.enabled)return;let e={action:t.action||"/share",method:t.method||"POST",enctype:t.enctype||"multipart/form-data",params:{title:t.params?.title||"title",text:t.params?.text||"text",url:t.params?.url||"url"}};if(t.acceptFiles&&t.acceptFiles.length>0)e.params.files=t.acceptFiles.map((r)=>({name:r.name,accept:r.accept}));return e}function H(n){let t=n.pwa?.fileHandlers;if(!t?.enabled||!t.accept)return;let e=[{action:t.action||"/",accept:t.accept,launch_type:t.launchType||"single-client"}];if(t.icons)e[0].icons=t.icons.map((r)=>({src:r.src,sizes:r.sizes,type:r.type}));return e}function W(n){let t=n.pwa?.protocolHandlers;if(!t||t.length===0)return;return t.map((e)=>({protocol:e.protocol,url:e.url}))}function j(n){let t=n.pwa;if(!t?.enabled||!t.manifest)return null;let{manifest:e,icons:r}=t,o=r?.sizes||[72,96,128,144,152,192,384,512],a=r?.outputDir?`/${r.outputDir}`:"/pwa-icons",s=r?.generateWebP??!0,l=r?.purpose||["any","maskable"],p={name:e.name,short_name:e.shortName||e.name,description:e.description,start_url:e.startUrl||"/",display:e.display||"standalone",display_override:e.displayOverride,orientation:e.orientation,theme_color:e.themeColor,background_color:e.backgroundColor,scope:e.scope||"/",lang:e.lang,dir:e.dir,id:e.id,categories:e.categories,icons:A(o,a,s,l)};if(e.shortcuts&&e.shortcuts.length>0)p.shortcuts=C(e.shortcuts);if(e.screenshots&&e.screenshots.length>0)p.screenshots=e.screenshots.map((f)=>({src:f.src,sizes:f.sizes,type:f.type,label:f.label,form_factor:f.platform}));let c=T(n);if(c)p.share_target=c;let h=H(n);if(h)p.file_handlers=h;let g=W(n);if(g)p.protocol_handlers=g;if(e.launchHandler)p.launch_handler={client_mode:e.launchHandler};if(e.handleLinks)p.handle_links=e.handleLinks;if(e.edgeSidePanel?.enabled)p.edge_side_panel={preferred_width:e.edgeSidePanel.preferredWidth};return p}function _(n){let t=j(n);if(!t)return"";let e=JSON.parse(JSON.stringify(t));return JSON.stringify(e,null,2)}function q(n,t){return{...t,...n,shortcuts:n.shortcuts||t.shortcuts,screenshots:n.screenshots||t.screenshots,categories:n.categories||t.categories}}function D(n){let t=[],e=n.pwa;if(!e?.enabled)return t;let r=e.manifest;if(!r)return t.push("PWA manifest configuration is missing"),t;if(!r.name)t.push("Manifest name is required");let o=["fullscreen","standalone","minimal-ui","browser"];if(r.display&&!o.includes(r.display))t.push(`Invalid display mode: ${r.display}. Must be one of: ${o.join(", ")}`);let a=["any","natural","landscape","landscape-primary","landscape-secondary","portrait","portrait-primary","portrait-secondary"];if(r.orientation&&!a.includes(r.orientation))t.push(`Invalid orientation: ${r.orientation}`);let s=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;if(r.themeColor&&!s.test(r.themeColor))t.push(`Invalid theme color: ${r.themeColor}. Must be a valid hex color.`);if(r.backgroundColor&&!s.test(r.backgroundColor))t.push(`Invalid background color: ${r.backgroundColor}. Must be a valid hex color.`);if(e.shareTarget?.enabled){if(!e.shareTarget.action)t.push("Share target action URL is required")}if(e.fileHandlers?.enabled){if(!e.fileHandlers.accept||Object.keys(e.fileHandlers.accept).length===0)t.push("File handlers must specify accepted MIME types")}if(e.protocolHandlers)for(let l of e.protocolHandlers){if(!l.protocol)t.push("Protocol handler missing protocol");if(!l.url||!l.url.includes("%s"))t.push(`Protocol handler URL must contain %s placeholder: ${l.protocol}`)}return t}import z from"path";async function F(n){let t=n.pwa?.offline;if(!t?.enabled)return"";if(t.page){let e=z.isAbsolute(t.page)?t.page:z.resolve(process.cwd(),t.page);if(await Bun.file(e).exists())try{let{processDirectives:r}=await import("./chunk-
|
|
2
|
+
import{Rs,Bt,xc,yu}from"./chunk-5z8mq37c.js";import{$s,Zo,gu,mu,hu}from"./chunk-fzc98qgn.js";import{bc,vc,wc,pu,fu}from"./chunk-jv021x8e.js";import{He,Sn,Qo}from"./chunk-k72jqz6a.js";import{bu,vu,wu,xu,As,Xp}from"./chunk-mabja59q.js";import B from"fs";import w from"path";import O from"fs";import u from"path";var v=[72,96,128,144,152,192,384,512],S=[120,152,167,180],P=[16,32];async function M(n,t){let e={success:!0,generatedFiles:[],errors:[],warnings:[]},r=n.pwa?.icons;if(!r?.src)return e.errors.push("No source icon specified in pwa.icons.src"),e.success=!1,e;let o=u.isAbsolute(r.src)?r.src:u.resolve(process.cwd(),r.src);if(!await Bun.file(o).exists())return e.errors.push(`Source icon not found: ${o}`),e.success=!1,e;let a=u.resolve(t,r.outputDir||"pwa-icons");try{O.mkdirSync(a,{recursive:!0})}catch{return e.errors.push(`Failed to create output directory: ${a}`),e.success=!1,e}let s=r.sizes||v,l=r.generateWebP??!0,p=r.generateAppleIcons??!0;try{let c;try{c=await import("sharp")}catch{return e.errors.push(`sharp is not installed. Install it with: bun add sharp
|
|
3
|
+
Icon generation requires the sharp package for image processing.`),e.success=!1,e}let g=await c.default(o).metadata();if(g.width&&g.width<512)e.warnings.push(`Source icon is ${g.width}x${g.height}. Recommend using at least 512x512 for best quality.`);for(let i of s){let d=u.join(a,`icon-${i}x${i}.png`);if(await c.default(o).resize(i,i,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(d),e.generatedFiles.push(d),l){let x=u.join(a,`icon-${i}x${i}.webp`);await c.default(o).resize(i,i,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).webp({quality:90}).toFile(x),e.generatedFiles.push(x)}}if(p){for(let d of S){let x=u.join(a,`apple-touch-icon-${d}x${d}.png`);await c.default(o).resize(d,d,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile(x),e.generatedFiles.push(x)}let i=u.join(a,"apple-touch-icon.png");await c.default(o).resize(180,180,{fit:"contain",background:{r:255,g:255,b:255,alpha:1}}).png().toFile(i),e.generatedFiles.push(i)}for(let i of P){let d=u.join(a,`favicon-${i}x${i}.png`);await c.default(o).resize(i,i,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).png().toFile(d),e.generatedFiles.push(d)}let f=512,y=u.join(a,`icon-maskable-${f}x${f}.png`),m=Math.floor(f*0.1),k=f-m*2;await c.default(o).resize(k,k,{fit:"contain",background:{r:0,g:0,b:0,alpha:0}}).extend({top:m,bottom:m,left:m,right:m,background:{r:255,g:255,b:255,alpha:1}}).png().toFile(y),e.generatedFiles.push(y)}catch(c){let h=c instanceof Error?c.message:String(c);e.errors.push(`Icon generation failed: ${h}`),e.success=!1}return e}function N(n){let t=n.sizes||v,e=n.outputDir?`/${n.outputDir}`:"/pwa-icons",r=n.generateWebP??!0,o=n.generateAppleIcons??!0,a=[];for(let s of t)if(a.push(`${e}/icon-${s}x${s}.png`),r)a.push(`${e}/icon-${s}x${s}.webp`);if(o){a.push(`${e}/apple-touch-icon.png`);for(let s of S)a.push(`${e}/apple-touch-icon-${s}x${s}.png`)}for(let s of P)a.push(`${e}/favicon-${s}x${s}.png`);return a.push(`${e}/icon-maskable-512x512.png`),a}async function I(){try{return await import("sharp"),!0}catch{return!1}}function A(n,t,e,r){let o=[],a=r.join(" ");for(let s of n)if(o.push({src:`${t}/icon-${s}x${s}.png`,sizes:`${s}x${s}`,type:"image/png",purpose:a}),e)o.push({src:`${t}/icon-${s}x${s}.webp`,sizes:`${s}x${s}`,type:"image/webp",purpose:a});return o}function C(n){return n.map((t)=>({name:t.name,short_name:t.shortName,description:t.description,url:t.url,icons:t.icons?.map((e)=>({src:e.src,sizes:e.sizes,type:e.type}))}))}function T(n){let t=n.pwa?.shareTarget;if(!t?.enabled)return;let e={action:t.action||"/share",method:t.method||"POST",enctype:t.enctype||"multipart/form-data",params:{title:t.params?.title||"title",text:t.params?.text||"text",url:t.params?.url||"url"}};if(t.acceptFiles&&t.acceptFiles.length>0)e.params.files=t.acceptFiles.map((r)=>({name:r.name,accept:r.accept}));return e}function H(n){let t=n.pwa?.fileHandlers;if(!t?.enabled||!t.accept)return;let e=[{action:t.action||"/",accept:t.accept,launch_type:t.launchType||"single-client"}];if(t.icons)e[0].icons=t.icons.map((r)=>({src:r.src,sizes:r.sizes,type:r.type}));return e}function W(n){let t=n.pwa?.protocolHandlers;if(!t||t.length===0)return;return t.map((e)=>({protocol:e.protocol,url:e.url}))}function j(n){let t=n.pwa;if(!t?.enabled||!t.manifest)return null;let{manifest:e,icons:r}=t,o=r?.sizes||[72,96,128,144,152,192,384,512],a=r?.outputDir?`/${r.outputDir}`:"/pwa-icons",s=r?.generateWebP??!0,l=r?.purpose||["any","maskable"],p={name:e.name,short_name:e.shortName||e.name,description:e.description,start_url:e.startUrl||"/",display:e.display||"standalone",display_override:e.displayOverride,orientation:e.orientation,theme_color:e.themeColor,background_color:e.backgroundColor,scope:e.scope||"/",lang:e.lang,dir:e.dir,id:e.id,categories:e.categories,icons:A(o,a,s,l)};if(e.shortcuts&&e.shortcuts.length>0)p.shortcuts=C(e.shortcuts);if(e.screenshots&&e.screenshots.length>0)p.screenshots=e.screenshots.map((f)=>({src:f.src,sizes:f.sizes,type:f.type,label:f.label,form_factor:f.platform}));let c=T(n);if(c)p.share_target=c;let h=H(n);if(h)p.file_handlers=h;let g=W(n);if(g)p.protocol_handlers=g;if(e.launchHandler)p.launch_handler={client_mode:e.launchHandler};if(e.handleLinks)p.handle_links=e.handleLinks;if(e.edgeSidePanel?.enabled)p.edge_side_panel={preferred_width:e.edgeSidePanel.preferredWidth};return p}function _(n){let t=j(n);if(!t)return"";let e=JSON.parse(JSON.stringify(t));return JSON.stringify(e,null,2)}function q(n,t){return{...t,...n,shortcuts:n.shortcuts||t.shortcuts,screenshots:n.screenshots||t.screenshots,categories:n.categories||t.categories}}function D(n){let t=[],e=n.pwa;if(!e?.enabled)return t;let r=e.manifest;if(!r)return t.push("PWA manifest configuration is missing"),t;if(!r.name)t.push("Manifest name is required");let o=["fullscreen","standalone","minimal-ui","browser"];if(r.display&&!o.includes(r.display))t.push(`Invalid display mode: ${r.display}. Must be one of: ${o.join(", ")}`);let a=["any","natural","landscape","landscape-primary","landscape-secondary","portrait","portrait-primary","portrait-secondary"];if(r.orientation&&!a.includes(r.orientation))t.push(`Invalid orientation: ${r.orientation}`);let s=/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;if(r.themeColor&&!s.test(r.themeColor))t.push(`Invalid theme color: ${r.themeColor}. Must be a valid hex color.`);if(r.backgroundColor&&!s.test(r.backgroundColor))t.push(`Invalid background color: ${r.backgroundColor}. Must be a valid hex color.`);if(e.shareTarget?.enabled){if(!e.shareTarget.action)t.push("Share target action URL is required")}if(e.fileHandlers?.enabled){if(!e.fileHandlers.accept||Object.keys(e.fileHandlers.accept).length===0)t.push("File handlers must specify accepted MIME types")}if(e.protocolHandlers)for(let l of e.protocolHandlers){if(!l.protocol)t.push("Protocol handler missing protocol");if(!l.url||!l.url.includes("%s"))t.push(`Protocol handler URL must contain %s placeholder: ${l.protocol}`)}return t}import z from"path";async function F(n){let t=n.pwa?.offline;if(!t?.enabled)return"";if(t.page){let e=z.isAbsolute(t.page)?t.page:z.resolve(process.cwd(),t.page);if(await Bun.file(e).exists())try{let{processDirectives:r}=await import("./chunk-wk1gt95z.js"),o=await Bun.file(e).text();return await r(o,{},e,n,new Set)}catch(r){console.warn(`[PWA] Failed to process custom offline page: ${r}`)}else console.warn(`[PWA] Custom offline page not found: ${e}`)}return E(n)}function E(n){let t=n.pwa?.offline,e=n.pwa?.manifest,r=t?.fallbackTitle||"You are offline",o=t?.fallbackMessage||"Please check your internet connection and try again.",a=e?.themeColor||"#4f46e5",s=e?.shortName||e?.name||"App";return`<!DOCTYPE html>
|
|
4
4
|
<html lang="en">
|
|
5
5
|
<head>
|
|
6
6
|
<meta charset="UTF-8">
|
|
@@ -233,4 +233,4 @@ Icon generation requires the sharp package for image processing.`),e.success=!1,
|
|
|
233
233
|
}, 5000);
|
|
234
234
|
</script>
|
|
235
235
|
</body>
|
|
236
|
-
</html>`}function b(n){return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}async function re(n,t){let e={success:!0,files:{icons:[]},errors:[],warnings:[]},r=n.pwa;if(!r?.enabled)return e;try{B.mkdirSync(t,{recursive:!0})}catch{return e.errors.push(`Failed to create output directory: ${t}`),e.success=!1,e}try{let a=_(n);if(a){let s=w.join(t,"manifest.json");await Bun.write(s,a),e.files.manifest=s}}catch(a){let s=a instanceof Error?a.message:String(a);e.errors.push(`Failed to generate manifest.json: ${s}`),e.success=!1}if(r.icons?.src)if(await I()){let s=await M(n,t);if(e.files.icons=s.generatedFiles,e.warnings.push(...s.warnings),!s.success)e.errors.push(...s.errors),e.success=!1}else e.warnings.push("sharp is not installed. Skipping icon generation. Install with: bun add sharp");if(r.offline?.enabled)try{let a=await F(n);if(a){let s=w.join(t,"offline.html");await Bun.write(s,a),e.files.offlinePage=s}}catch(a){let s=a instanceof Error?a.message:String(a);e.errors.push(`Failed to generate offline page: ${s}`),e.success=!1}let o;if(r.precache?.enabled){let a=
|
|
236
|
+
</html>`}function b(n){return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}async function re(n,t){let e={success:!0,files:{icons:[]},errors:[],warnings:[]},r=n.pwa;if(!r?.enabled)return e;try{B.mkdirSync(t,{recursive:!0})}catch{return e.errors.push(`Failed to create output directory: ${t}`),e.success=!1,e}try{let a=_(n);if(a){let s=w.join(t,"manifest.json");await Bun.write(s,a),e.files.manifest=s}}catch(a){let s=a instanceof Error?a.message:String(a);e.errors.push(`Failed to generate manifest.json: ${s}`),e.success=!1}if(r.icons?.src)if(await I()){let s=await M(n,t);if(e.files.icons=s.generatedFiles,e.warnings.push(...s.warnings),!s.success)e.errors.push(...s.errors),e.success=!1}else e.warnings.push("sharp is not installed. Skipping icon generation. Install with: bun add sharp");if(r.offline?.enabled)try{let a=await F(n);if(a){let s=w.join(t,"offline.html");await Bun.write(s,a),e.files.offlinePage=s}}catch(a){let s=a instanceof Error?a.message:String(a);e.errors.push(`Failed to generate offline page: ${s}`),e.success=!1}let o;if(r.precache?.enabled){let a=He(t,n);o={fileCount:a.fileCount,totalSize:a.totalSize},e.precacheStats=o}try{let a=Rs(n,t);if(a){let s=Bt(n),l=w.join(t,s);await Bun.write(l,a),e.files.serviceWorker=l}}catch(a){let s=a instanceof Error?a.message:String(a);e.errors.push(`Failed to generate service worker: ${s}`),e.success=!1}return e}function ae(n,t){return Zo(n,t)}function se(n){return n.pwa?.enabled===!0}export{S as APPLE_TOUCH_ICON_SIZES,v as DEFAULT_ICON_SIZES,P as FAVICON_SIZES,vc as auditBuildOutput,bc as auditConfig,re as buildPwaAssets,wc as calculateAuditResult,fu as formatAuditResult,Qo as formatSize,j as generateManifest,_ as generateManifestJson,mu as generateManifestLink,F as generateOfflinePage,He as generatePrecacheManifest,Sn as generatePrecacheManifestJs,M as generatePwaIcons,$s as generatePwaTags,Rs as generateServiceWorker,yu as generateServiceWorkerAuto,gu as generateSwRegistrationScript,hu as generateThemeColorMeta,N as getExpectedIconPaths,Bt as getServiceWorkerFileName,Zo as injectPwaTags,se as isPwaEnabled,I as isSharpAvailable,xc as isWorkboxEnabled,q as mergeManifestConfig,ae as processPwaHtml,As as pwaDirectives,bu as pwaInstallDirective,wu as pwaOfflineDirective,xu as pwaPushDirective,vu as pwaUpdateDirective,Xp as registerPwaDirectives,pu as runPwaAudit,D as validateManifest};
|
|
@@ -447,32 +447,91 @@ function nextSiblingHasElse(template, fromIndex) {
|
|
|
447
447
|
export function preEvalLiteralReactiveIfs(template) {
|
|
448
448
|
if (!template.includes(":if") && !template.includes(":show") && !template.includes("x-if") && !template.includes("x-show") && !template.includes("@if=") && !template.includes("@show="))
|
|
449
449
|
return template;
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
450
|
+
const candidates = [], tagName = /<([a-zA-Z][\w-]*)/y, whitespace = /\s/, conditionalNames = new Set([":if", ":show", "x-if", "x-show", "@if", "@show"]);
|
|
451
|
+
scanAtElementPosition(template, (html, start) => {
|
|
452
|
+
tagName.lastIndex = start;
|
|
453
|
+
const name = tagName.exec(html);
|
|
454
|
+
if (!name || /^(?:script|style)$/i.test(name[1]))
|
|
455
|
+
return -1;
|
|
456
|
+
let i = tagName.lastIndex, conditional;
|
|
457
|
+
while (i < html.length) {
|
|
458
|
+
const beforeSpace = i;
|
|
459
|
+
while (i < html.length && whitespace.test(html[i]))
|
|
460
|
+
i++;
|
|
461
|
+
let closing = i;
|
|
462
|
+
if (html[closing] === "/") {
|
|
463
|
+
closing++;
|
|
464
|
+
while (closing < html.length && whitespace.test(html[closing]))
|
|
465
|
+
closing++;
|
|
466
|
+
}
|
|
467
|
+
if (html[closing] === ">") {
|
|
468
|
+
if (conditional)
|
|
469
|
+
candidates.push({ start, end: closing + 1, tag: name[1], ...conditional });
|
|
470
|
+
return -1;
|
|
471
|
+
}
|
|
472
|
+
if (i === beforeSpace)
|
|
473
|
+
return -1;
|
|
474
|
+
const attrStart = i;
|
|
475
|
+
while (i < html.length && !whitespace.test(html[i]) && html[i] !== "=" && html[i] !== ">")
|
|
476
|
+
i++;
|
|
477
|
+
if (i === attrStart)
|
|
478
|
+
return -1;
|
|
479
|
+
const attrName = html.slice(attrStart, i);
|
|
480
|
+
if (attrName.startsWith("@") && attrName.includes("("))
|
|
481
|
+
return -1;
|
|
482
|
+
const nameEnd = i;
|
|
483
|
+
let valueStart = i;
|
|
484
|
+
while (valueStart < html.length && whitespace.test(html[valueStart]))
|
|
485
|
+
valueStart++;
|
|
486
|
+
if (html[valueStart] !== "=") {
|
|
487
|
+
i = nameEnd;
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
valueStart++;
|
|
491
|
+
while (valueStart < html.length && whitespace.test(html[valueStart]))
|
|
492
|
+
valueStart++;
|
|
493
|
+
const quote = html[valueStart];
|
|
494
|
+
if (quote === '"' || quote === "'") {
|
|
495
|
+
const end = html.indexOf(quote, valueStart + 1);
|
|
496
|
+
if (end === -1)
|
|
497
|
+
return -1;
|
|
498
|
+
if (!conditional && quote === '"' && conditionalNames.has(attrName))
|
|
499
|
+
conditional = {
|
|
500
|
+
attrName,
|
|
501
|
+
attrStart: beforeSpace,
|
|
502
|
+
attrEnd: end + 1,
|
|
503
|
+
value: html.slice(valueStart + 1, end)
|
|
504
|
+
};
|
|
505
|
+
i = end + 1;
|
|
506
|
+
} else {
|
|
507
|
+
i = valueStart;
|
|
508
|
+
while (i < html.length && !whitespace.test(html[i]) && html[i] !== ">")
|
|
509
|
+
i++;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return -1;
|
|
513
|
+
});
|
|
514
|
+
const replacements = [];
|
|
515
|
+
let skippedThrough = -1;
|
|
516
|
+
for (const candidate of candidates) {
|
|
517
|
+
const { start: startIdx, end: startTagEnd, tag, attrName, value } = candidate;
|
|
518
|
+
if (startIdx < skippedThrough)
|
|
519
|
+
continue;
|
|
520
|
+
const verdict = evalLiteralCondition(value);
|
|
460
521
|
if (verdict === void 0)
|
|
461
522
|
continue;
|
|
462
|
-
const
|
|
523
|
+
const elementEnd = /\/\s*>$/.test(template.slice(startIdx, startTagEnd)) || VOID_ELEMENT_TAGS.has(tag.toLowerCase()) ? startTagEnd : findElementEnd(template, startIdx, tag, startTagEnd);
|
|
463
524
|
if (elementEnd === -1)
|
|
464
525
|
continue;
|
|
465
|
-
if ((attrName === ":if" || attrName === "x-if" || attrName === "@if") && nextSiblingHasElse(template, elementEnd))
|
|
466
|
-
tagWithLiteralIf.lastIndex = startTagEnd;
|
|
526
|
+
if ((attrName === ":if" || attrName === "x-if" || attrName === "@if") && nextSiblingHasElse(template, elementEnd))
|
|
467
527
|
continue;
|
|
468
|
-
}
|
|
469
528
|
if (verdict === !0) {
|
|
470
|
-
const rebuiltStartTag =
|
|
529
|
+
const rebuiltStartTag = template.slice(startIdx, candidate.attrStart) + template.slice(candidate.attrEnd, startTagEnd);
|
|
471
530
|
replacements.push({ start: startIdx, end: startTagEnd, replacement: rebuiltStartTag });
|
|
472
531
|
continue;
|
|
473
532
|
}
|
|
474
533
|
replacements.push({ start: startIdx, end: elementEnd, replacement: "" });
|
|
475
|
-
|
|
534
|
+
skippedThrough = elementEnd;
|
|
476
535
|
}
|
|
477
536
|
if (replacements.length === 0)
|
|
478
537
|
return template;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StaticPath, StaticPathsResult } from './ssg';
|
|
2
|
+
/** Define static paths for dynamic routes (used in templates). */
|
|
3
|
+
export declare function defineStaticPaths(pathsFn: () => Promise<StaticPath[]> | StaticPath[]): () => Promise<StaticPathsResult>;
|
|
4
|
+
/**
|
|
5
|
+
* Preserve failure provenance instead of collapsing it into "hook absent".
|
|
6
|
+
* Hook evaluation remains isolated from the page's other server declarations;
|
|
7
|
+
* this does not add imported/module-closure evaluation to the SSG.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readStaticPaths(filePath: string): Promise<StaticPathsOutcome>;
|
|
10
|
+
export type StaticPathsOutcome = | { kind: 'absent' }
|
|
11
|
+
| { kind: 'ok', value: StaticPathsResult }
|
|
12
|
+
| { kind: 'error', phase: 'read' | 'parse' | 'execute' | 'result', error: Error }
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { classifyAllScripts } from "./script-classifier.js";
|
|
2
|
+
import { declaresClientIdentifier } from "./client-declarations.js";
|
|
3
|
+
import { bracketDepths, stripCommentsAndLiterals } from "./strip-literals.js";
|
|
4
|
+
import { extractBalancedExpression, findMatchingDelimiter } from "./parser/tokenizer.js";
|
|
5
|
+
export function defineStaticPaths(pathsFn) {
|
|
6
|
+
return async () => ({ paths: await pathsFn(), fallback: !1 });
|
|
7
|
+
}
|
|
8
|
+
let transpiler;
|
|
9
|
+
function hookExpression(code) {
|
|
10
|
+
const masked = stripCommentsAndLiterals(code), { depths } = bracketDepths(masked), declarations = /\b(?:async\s+)?function\s+getStaticPaths\s*\(/g;
|
|
11
|
+
let match;
|
|
12
|
+
while ((match = declarations.exec(masked)) !== null) {
|
|
13
|
+
if (depths[match.index] !== 0)
|
|
14
|
+
continue;
|
|
15
|
+
const paramsEnd = findMatchingDelimiter(masked, "(", ")", declarations.lastIndex - 1), bodyStart = masked.indexOf("{", paramsEnd + 1), bodyEnd = findMatchingDelimiter(masked, "{", "}", bodyStart);
|
|
16
|
+
if (paramsEnd < 0 || bodyStart < 0 || bodyEnd < 0)
|
|
17
|
+
break;
|
|
18
|
+
return code.slice(match.index, bodyEnd + 1);
|
|
19
|
+
}
|
|
20
|
+
const variables = /\b(?:const|let|var)\s+getStaticPaths\s*=/g;
|
|
21
|
+
while ((match = variables.exec(masked)) !== null) {
|
|
22
|
+
if (depths[match.index] !== 0)
|
|
23
|
+
continue;
|
|
24
|
+
const end = extractBalancedExpression(masked, variables.lastIndex).endPos;
|
|
25
|
+
return code.slice(variables.lastIndex, end).trim();
|
|
26
|
+
}
|
|
27
|
+
throw SyntaxError("Could not extract getStaticPaths; use a top-level function or const declaration");
|
|
28
|
+
}
|
|
29
|
+
export async function readStaticPaths(filePath) {
|
|
30
|
+
let phase = "read";
|
|
31
|
+
try {
|
|
32
|
+
const content = await Bun.file(filePath).text();
|
|
33
|
+
phase = "parse";
|
|
34
|
+
const scripts = classifyAllScripts(content), serverScripts = [...scripts.server, ...scripts.client, ...scripts.signals].filter((script) => /(?:^|\s)server(?:\s|=|$)/i.test(stripCommentsAndLiterals(script.attrs))).sort((a, b) => content.indexOf(a.fullTag) - content.indexOf(b.fullTag));
|
|
35
|
+
for (const script of serverScripts) {
|
|
36
|
+
if (!/\bgetStaticPaths\b/.test(stripCommentsAndLiterals(script.content)))
|
|
37
|
+
continue;
|
|
38
|
+
const code = (transpiler ??= new Bun.Transpiler({ loader: "ts", target: "bun" })).transformSync(script.content);
|
|
39
|
+
if (!/\bgetStaticPaths\b/.test(stripCommentsAndLiterals(code)))
|
|
40
|
+
continue;
|
|
41
|
+
const expression = hookExpression(code);
|
|
42
|
+
if (/\bdefineStaticPaths\b/.test(stripCommentsAndLiterals(expression)) && declaresClientIdentifier(code, "defineStaticPaths"))
|
|
43
|
+
throw SyntaxError("Cannot evaluate a module-local defineStaticPaths binding during isolated hook extraction");
|
|
44
|
+
phase = "execute";
|
|
45
|
+
const hook = Function("defineStaticPaths", `return (${expression})`)(defineStaticPaths);
|
|
46
|
+
if (typeof hook !== "function")
|
|
47
|
+
throw TypeError("getStaticPaths must be a function");
|
|
48
|
+
const returned = await hook();
|
|
49
|
+
phase = "result";
|
|
50
|
+
const value = Array.isArray(returned) ? { paths: returned } : returned;
|
|
51
|
+
if (!value || typeof value !== "object" || !("paths" in value) || !Array.isArray(value.paths))
|
|
52
|
+
throw TypeError("getStaticPaths must return { paths: [...] } or an array of paths");
|
|
53
|
+
for (const entry of value.paths)
|
|
54
|
+
if (!entry || typeof entry !== "object" || !entry.params || typeof entry.params !== "object" || Array.isArray(entry.params))
|
|
55
|
+
throw TypeError("Each getStaticPaths path must contain a params object");
|
|
56
|
+
return { kind: "ok", value };
|
|
57
|
+
}
|
|
58
|
+
return { kind: "absent" };
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return { kind: "error", phase, error: error instanceof Error ? error : Error(String(error)) };
|
|
61
|
+
}
|
|
62
|
+
}
|
package/dist/ssg.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference path="./stx.d.ts" />
|
|
2
|
+
import { defineStaticPaths } from './ssg-static-paths';
|
|
2
3
|
import type { StxOptions } from './types';
|
|
3
4
|
/**
|
|
4
5
|
* Whether a page declares an `action` — the export that receives its own POST.
|
|
@@ -34,10 +35,6 @@ export declare function createISRHandler(options?: SSGConfig): {
|
|
|
34
35
|
revalidate: (route: string) => Promise<void>
|
|
35
36
|
invalidate: (route: string | RegExp) => Promise<void>
|
|
36
37
|
};
|
|
37
|
-
/**
|
|
38
|
-
* Define static paths for dynamic routes (used in templates)
|
|
39
|
-
*/
|
|
40
|
-
export declare function defineStaticPaths(pathsFn: () => Promise<StaticPath[]> | StaticPath[]): () => Promise<StaticPathsResult>;
|
|
41
38
|
/**
|
|
42
39
|
* Create a markdown content loader
|
|
43
40
|
*/
|
|
@@ -193,6 +190,7 @@ declare class FileISRCache implements ISRCache {
|
|
|
193
190
|
invalidatePattern(pattern: RegExp): Promise<void>;
|
|
194
191
|
needsRevalidation(route: string): Promise<boolean>;
|
|
195
192
|
}
|
|
193
|
+
export { defineStaticPaths } from './ssg-static-paths';
|
|
196
194
|
// =============================================================================
|
|
197
195
|
// Exports
|
|
198
196
|
// =============================================================================
|