@torpor/view 1.0.3 → 1.1.1
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/{fromWebSocket-DeB35Q4w.d.cts → AsyncOptions-BtMe2PAd.d.cts} +21 -2
- package/dist/AsyncOptions-BtMe2PAd.d.cts.map +1 -0
- package/dist/{fromWebSocket-B52kN3-W.d.mts → AsyncOptions-ClS1_ERX.d.mts} +21 -2
- package/dist/AsyncOptions-ClS1_ERX.d.mts.map +1 -0
- package/dist/{Effect-BTKurOpr.d.mts → Effect-DazmAdyC.d.mts} +3 -3
- package/dist/{Effect-BTKurOpr.d.mts.map → Effect-DazmAdyC.d.mts.map} +1 -1
- package/dist/{Effect-COl3aRJV.d.cts → Effect-Dewn7MLc.d.cts} +3 -3
- package/dist/{Effect-COl3aRJV.d.cts.map → Effect-Dewn7MLc.d.cts.map} +1 -1
- package/dist/compile.cjs +139 -33
- package/dist/compile.mjs +139 -33
- package/dist/compile.mjs.map +1 -1
- package/dist/dev.d.cts +1 -1
- package/dist/dev.d.mts +1 -1
- package/dist/index.cjs +60 -8
- package/dist/index.d.cts +23 -6
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +23 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +60 -8
- package/dist/index.mjs.map +1 -1
- package/dist/ssr.cjs +292 -4
- package/dist/ssr.d.cts +108 -9
- package/dist/ssr.d.cts.map +1 -1
- package/dist/ssr.d.mts +108 -9
- package/dist/ssr.d.mts.map +1 -1
- package/dist/ssr.mjs +291 -5
- package/dist/ssr.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/fromWebSocket-B52kN3-W.d.mts.map +0 -1
- package/dist/fromWebSocket-DeB35Q4w.d.cts.map +0 -1
|
@@ -87,5 +87,24 @@ declare function fromServer(url: string | (() => string)): StreamSource<MessageE
|
|
|
87
87
|
*/
|
|
88
88
|
declare function fromWebSocket(url: string | (() => string)): StreamSource<MessageEvent>;
|
|
89
89
|
//#endregion
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
//#region src/types/AsyncOptions.d.ts
|
|
91
|
+
/**
|
|
92
|
+
* Options for the `$async` getter primitive.
|
|
93
|
+
*/
|
|
94
|
+
interface AsyncOptions {
|
|
95
|
+
/**
|
|
96
|
+
* Where the value comes from. The default (`"client"`) starts the fetch
|
|
97
|
+
* after hydration; `"server"` fetches during SSR and ships the resolved
|
|
98
|
+
* value embedded in the HTML (see ASYNC.md → "Server rendering").
|
|
99
|
+
*/
|
|
100
|
+
source?: "client" | "server";
|
|
101
|
+
/**
|
|
102
|
+
* With `source: "server"`, how long (ms) the server waits for this
|
|
103
|
+
* getter's promise before the enclosing `@await` boundary degrades to its
|
|
104
|
+
* `with` branch and the client fetches instead. Defaults to 5000.
|
|
105
|
+
*/
|
|
106
|
+
timeout?: number;
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { StreamSource as a, buildClasses as c, fromElement as i, ClassValue as l, fromWebSocket as n, buildStyles as o, fromServer as r, StyleValue as s, AsyncOptions as t };
|
|
110
|
+
//# sourceMappingURL=AsyncOptions-BtMe2PAd.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsyncOptions-BtMe2PAd.d.cts","names":[],"sources":["../src/types/ClassValue.ts","../src/render/buildClasses.ts","../src/types/StyleValue.ts","../src/render/buildStyles.ts","../src/types/StreamSource.ts","../src/stream/fromElement.ts","../src/stream/fromServer.ts","../src/stream/fromWebSocket.ts","../src/types/AsyncOptions.ts"],"mappings":";;KAAK,sBAEF,6CACA,MAAM;;;iBCAe,aAAa,OAAO,YAAY;;;KCHnD,sBAEF,4CACA,MAAM;;;iBCCe,YAAY,OAAO;;;;;;;;;;;;;;;;;KCYtC,aAAa,MAAM,OAAO,OAAO,eAAe;;;;;;;;;;;;;;KCHhD,mBAAmB,qBAAqB;;;;;;;;;;;iBAYrB,YAAY,UAAU,QAAQ,OACrD,QAAQ,kBACR,eACE,aAAa;;;;;;;;;;;;;;;;;iBCZQ,WAAW,+BAA+B,aAAa;;;;;;;;;;;;;;;;;iBCAvD,cAAc,+BAA+B,aAAa;;;;;;UCbzD;;;;;;EAMxB;;;;;;EAOA"}
|
|
@@ -87,5 +87,24 @@ declare function fromServer(url: string | (() => string)): StreamSource<MessageE
|
|
|
87
87
|
*/
|
|
88
88
|
declare function fromWebSocket(url: string | (() => string)): StreamSource<MessageEvent>;
|
|
89
89
|
//#endregion
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
//#region src/types/AsyncOptions.d.ts
|
|
91
|
+
/**
|
|
92
|
+
* Options for the `$async` getter primitive.
|
|
93
|
+
*/
|
|
94
|
+
interface AsyncOptions {
|
|
95
|
+
/**
|
|
96
|
+
* Where the value comes from. The default (`"client"`) starts the fetch
|
|
97
|
+
* after hydration; `"server"` fetches during SSR and ships the resolved
|
|
98
|
+
* value embedded in the HTML (see ASYNC.md → "Server rendering").
|
|
99
|
+
*/
|
|
100
|
+
source?: "client" | "server";
|
|
101
|
+
/**
|
|
102
|
+
* With `source: "server"`, how long (ms) the server waits for this
|
|
103
|
+
* getter's promise before the enclosing `@await` boundary degrades to its
|
|
104
|
+
* `with` branch and the client fetches instead. Defaults to 5000.
|
|
105
|
+
*/
|
|
106
|
+
timeout?: number;
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { StreamSource as a, buildClasses as c, fromElement as i, ClassValue as l, fromWebSocket as n, buildStyles as o, fromServer as r, StyleValue as s, AsyncOptions as t };
|
|
110
|
+
//# sourceMappingURL=AsyncOptions-ClS1_ERX.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AsyncOptions-ClS1_ERX.d.mts","names":[],"sources":["../src/types/ClassValue.ts","../src/render/buildClasses.ts","../src/types/StyleValue.ts","../src/render/buildStyles.ts","../src/types/StreamSource.ts","../src/stream/fromElement.ts","../src/stream/fromServer.ts","../src/stream/fromWebSocket.ts","../src/types/AsyncOptions.ts"],"mappings":";;KAAK,sBAEF,6CACA,MAAM;;;iBCAe,aAAa,OAAO,YAAY;;;KCHnD,sBAEF,4CACA,MAAM;;;iBCCe,YAAY,OAAO;;;;;;;;;;;;;;;;;KCYtC,aAAa,MAAM,OAAO,OAAO,eAAe;;;;;;;;;;;;;;KCHhD,mBAAmB,qBAAqB;;;;;;;;;;;iBAYrB,YAAY,UAAU,QAAQ,OACrD,QAAQ,kBACR,eACE,aAAa;;;;;;;;;;;;;;;;;iBCZQ,WAAW,+BAA+B,aAAa;;;;;;;;;;;;;;;;;iBCAvD,cAAc,+BAA+B,aAAa;;;;;;UCbzD;;;;;;EAMxB;;;;;;EAOA"}
|
|
@@ -168,7 +168,7 @@ interface Computed<T = any> {
|
|
|
168
168
|
/**
|
|
169
169
|
* True when the current suspend is a "bare refresh" — a re-fetch with no
|
|
170
170
|
* tracked dependency change, i.e. a silent `$refresh(fn, { silent: true })`
|
|
171
|
-
* (background revalidation), per ASYNC.md
|
|
171
|
+
* (background revalidation), per ASYNC.md → "Loud vs quiet")
|
|
172
172
|
* `$pending` reads this to stay quiet (return `false`) on silent refreshes,
|
|
173
173
|
* matching Solid's stale-while-revalidate default.
|
|
174
174
|
*
|
|
@@ -182,7 +182,7 @@ interface Computed<T = any> {
|
|
|
182
182
|
suspendQuiet: boolean;
|
|
183
183
|
/**
|
|
184
184
|
* The previously resolved value, retained across a refresh suspend for
|
|
185
|
-
* stale-while-revalidate (ASYNC.md
|
|
185
|
+
* stale-while-revalidate (ASYNC.md → "Stale-while-revalidate"). Maintained by `$async`'s
|
|
186
186
|
* generation-guarded settle handlers — set on resolve, cleared on
|
|
187
187
|
* rejection — so it always holds the last RESOLVED value, never a
|
|
188
188
|
* superseded run's in-flight promise (rapid prop changes would otherwise
|
|
@@ -378,4 +378,4 @@ interface Effect {
|
|
|
378
378
|
}
|
|
379
379
|
//#endregion
|
|
380
380
|
export { ProxySignal as i, Region as n, Computed as r, Effect as t };
|
|
381
|
-
//# sourceMappingURL=Effect-
|
|
381
|
+
//# sourceMappingURL=Effect-DazmAdyC.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Effect-
|
|
1
|
+
{"version":3,"file":"Effect-DazmAdyC.d.mts","names":[],"sources":["../src/types/constants.ts","../src/types/ProxySignal.ts","../src/types/Subscription.ts","../src/types/Computed.ts","../src/types/ErrorBoundary.ts","../src/types/Region.ts","../src/types/Effect.ts"],"mappings":";;;;;cAGa;;;;cAKA;;;;cAKA;;;;;;;UCNY;;;;EAIxB,aAAa;;;;EAKb,aAAa;;;;EAKb,oBAAoB;;;;EAKpB;;;;;;;;UClBwB;;;;EAIxB,QAAQ,cAAc;;;;EAKtB,QAAQ,WAAW;;;;;EAMnB,YAAY;;;;;EAMZ,YAAY;;;;;;;EAQZ,gBAAgB;;;;;;EAOhB;;;;;EAMA;;;;EAKA;;;;;;;;;UC/CwB,SAAS;;;;EAIjC,aAAa;;;;;;;;EASb;;;;EAKA,OAAO;;;;EAKP,WAAW;;;;EAKX,aAAa;;;;EAKb,aAAa;;;;;;;EAQb;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;EAQA;;;;;;;EAQA;;;;;;;;;EAUA;;;;;;;;;;;;;;;EAgBA;;;;;;;;;;;;;EAcA;;;;EAKA,UAAU;;;;EAKV;;;;;;;;;;UC3HwB;;;;;;EAMxB;;;;;EAMA;;;;;EAMA,QAAQ;;;;;;;;;EAUR,cAAc,cAAc;;;;UCnCJ;EACxB,WAAW;EACX,SAAS;EAET,gBAAgB;EAChB,YAAY;EACZ;;;;;EAMA,YAAY,IAAI;;;;EAKhB;;;;EAKA,SAAS;;;;;;;EAQT,gBAAgB;;;;;;;EAQhB;;;;;;EAOA;;;;;;;UCtCwB;;;;EAIxB,aAAa;;;;;EAMb,WAAW;;;;EAKX,SAAS;;;;EAKT,aAAa;EAKb,YAAY;;;;EAKZ;;;;;;EAOA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;EAWA,iBAAiB,IAAI;;;;EAKrB;;;;;;EAOA,SAAS;;;;;;EAOT,gBAAgB,cAAc;;;;;;;;;EAU9B;;;;;;;;;;;;;;;;EAiBA"}
|
|
@@ -168,7 +168,7 @@ interface Computed<T = any> {
|
|
|
168
168
|
/**
|
|
169
169
|
* True when the current suspend is a "bare refresh" — a re-fetch with no
|
|
170
170
|
* tracked dependency change, i.e. a silent `$refresh(fn, { silent: true })`
|
|
171
|
-
* (background revalidation), per ASYNC.md
|
|
171
|
+
* (background revalidation), per ASYNC.md → "Loud vs quiet")
|
|
172
172
|
* `$pending` reads this to stay quiet (return `false`) on silent refreshes,
|
|
173
173
|
* matching Solid's stale-while-revalidate default.
|
|
174
174
|
*
|
|
@@ -182,7 +182,7 @@ interface Computed<T = any> {
|
|
|
182
182
|
suspendQuiet: boolean;
|
|
183
183
|
/**
|
|
184
184
|
* The previously resolved value, retained across a refresh suspend for
|
|
185
|
-
* stale-while-revalidate (ASYNC.md
|
|
185
|
+
* stale-while-revalidate (ASYNC.md → "Stale-while-revalidate"). Maintained by `$async`'s
|
|
186
186
|
* generation-guarded settle handlers — set on resolve, cleared on
|
|
187
187
|
* rejection — so it always holds the last RESOLVED value, never a
|
|
188
188
|
* superseded run's in-flight promise (rapid prop changes would otherwise
|
|
@@ -378,4 +378,4 @@ interface Effect {
|
|
|
378
378
|
}
|
|
379
379
|
//#endregion
|
|
380
380
|
export { ProxySignal as i, Region as n, Computed as r, Effect as t };
|
|
381
|
-
//# sourceMappingURL=Effect-
|
|
381
|
+
//# sourceMappingURL=Effect-Dewn7MLc.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Effect-
|
|
1
|
+
{"version":3,"file":"Effect-Dewn7MLc.d.cts","names":[],"sources":["../src/types/constants.ts","../src/types/ProxySignal.ts","../src/types/Subscription.ts","../src/types/Computed.ts","../src/types/ErrorBoundary.ts","../src/types/Region.ts","../src/types/Effect.ts"],"mappings":";;;;;cAGa;;;;cAKA;;;;cAKA;;;;;;;UCNY;;;;EAIxB,aAAa;;;;EAKb,aAAa;;;;EAKb,oBAAoB;;;;EAKpB;;;;;;;;UClBwB;;;;EAIxB,QAAQ,cAAc;;;;EAKtB,QAAQ,WAAW;;;;;EAMnB,YAAY;;;;;EAMZ,YAAY;;;;;;;EAQZ,gBAAgB;;;;;;EAOhB;;;;;EAMA;;;;EAKA;;;;;;;;;UC/CwB,SAAS;;;;EAIjC,aAAa;;;;;;;;EASb;;;;EAKA,OAAO;;;;EAKP,WAAW;;;;EAKX,aAAa;;;;EAKb,aAAa;;;;;;;EAQb;;;;EAKA;;;;EAKA;;;;;;;EAQA;;;;;;;EAQA;;;;;;;EAQA;;;;;;;;;EAUA;;;;;;;;;;;;;;;EAgBA;;;;;;;;;;;;;EAcA;;;;EAKA,UAAU;;;;EAKV;;;;;;;;;;UC3HwB;;;;;;EAMxB;;;;;EAMA;;;;;EAMA,QAAQ;;;;;;;;;EAUR,cAAc,cAAc;;;;UCnCJ;EACxB,WAAW;EACX,SAAS;EAET,gBAAgB;EAChB,YAAY;EACZ;;;;;EAMA,YAAY,IAAI;;;;EAKhB;;;;EAKA,SAAS;;;;;;;EAQT,gBAAgB;;;;;;;EAQhB;;;;;;EAOA;;;;;;;UCtCwB;;;;EAIxB,aAAa;;;;;EAMb,WAAW;;;;EAKX,SAAS;;;;EAKT,aAAa;EAKb,YAAY;;;;EAKZ;;;;;;EAOA;;;;EAKA;;;;;;;EAQA;;;;;;;;;;EAWA,iBAAiB,IAAI;;;;EAKrB;;;;;;EAOA,SAAS;;;;;;EAOT,gBAAgB,cAAc;;;;;;;;;EAU9B;;;;;;;;;;;;;;;;EAiBA"}
|
package/dist/compile.cjs
CHANGED
|
@@ -2201,12 +2201,15 @@ function headElementSelector(node) {
|
|
|
2201
2201
|
function buildElementAttributes$1(node, varName, status, b) {
|
|
2202
2202
|
let fragment = status.fragmentStack.at(-1)?.fragment;
|
|
2203
2203
|
if (!fragment) throw new Error("No fragment on stack");
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2204
|
+
const combinedHandlers = combinedEventHandlers(node, status);
|
|
2205
|
+
const consumedHandlers = new Set(Array.from(combinedHandlers.values(), (c) => c.index));
|
|
2206
|
+
for (let [index, { name, value, reactive, fullyReactive, span }] of node.attributes.entries()) if (name === "self" && node.tagName === "@element") {} else if (name === "&ref") {} else if (value != null && fullyReactive) {
|
|
2207
|
+
if (name === "&group") buildBindGroupAttribute(node, varName, value, status, b, combinedHandlers.get(index));
|
|
2208
|
+
else if (name === "&value" || name === "&checked") buildBindAttribute(node, varName, name, value, status, b, combinedHandlers.get(index));
|
|
2207
2209
|
else if (name === "onmount") buildMount("elMount", `return (${trimEnd(value.trim(), ";")})(${varName});`, status, b);
|
|
2208
|
-
else if (name.startsWith("on"))
|
|
2209
|
-
|
|
2210
|
+
else if (name.startsWith("on")) {
|
|
2211
|
+
if (!consumedHandlers.has(index)) buildEventAttribute(varName, name, value, span, status, b);
|
|
2212
|
+
} else if (name.startsWith("transition")) buildTransitionAttribute(node, varName, name, value, status, b);
|
|
2210
2213
|
else if (name === "class") {
|
|
2211
2214
|
status.imports.add("t_class");
|
|
2212
2215
|
const params = [value];
|
|
@@ -2244,21 +2247,20 @@ function buildElementAttributes$1(node, varName, status, b) {
|
|
|
2244
2247
|
}
|
|
2245
2248
|
}
|
|
2246
2249
|
}
|
|
2247
|
-
function buildBindGroupAttribute(node, varName, value, status, b) {
|
|
2250
|
+
function buildBindGroupAttribute(node, varName, value, status, b, combined) {
|
|
2248
2251
|
value = replaceForVarNames(value, status);
|
|
2249
2252
|
let eventName = "change";
|
|
2250
2253
|
let inputValue = node.attributes.find((a) => a.name === "value")?.value;
|
|
2251
2254
|
let set = `${value} == ${inputValue}`;
|
|
2252
2255
|
let propName = "checked";
|
|
2253
2256
|
buildRun("setBinding", `${`${varName}.${propName} = ${set}`};`, status, b);
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
if (e.target.${propName}) ${value} = ${inputValue};
|
|
2257
|
-
});`);
|
|
2257
|
+
emitBindEvent(varName, eventName, `(e) => {
|
|
2258
|
+
if (e.target.${propName}) ${value} = ${inputValue};
|
|
2259
|
+
}`, `if (e.target.${propName}) ${value} = ${inputValue};`, combined, status, b);
|
|
2258
2260
|
}
|
|
2259
|
-
function buildBindAttribute(node, varName, name, value, status, b) {
|
|
2261
|
+
function buildBindAttribute(node, varName, name, value, status, b, combined) {
|
|
2260
2262
|
value = replaceForVarNames(value, status);
|
|
2261
|
-
let eventName =
|
|
2263
|
+
let eventName = bindEventName(node, name);
|
|
2262
2264
|
let defaultValue = "\"\"";
|
|
2263
2265
|
let inputValue = "e.target.value";
|
|
2264
2266
|
if (node.tagName === "input") {
|
|
@@ -2271,25 +2273,83 @@ function buildBindAttribute(node, varName, name, value, status, b) {
|
|
|
2271
2273
|
case "checkbox":
|
|
2272
2274
|
defaultValue = "false";
|
|
2273
2275
|
inputValue = "e.target.checked";
|
|
2274
|
-
break;
|
|
2275
|
-
case "radio":
|
|
2276
|
-
eventName = "change";
|
|
2277
|
-
inputValue = "e.target.value";
|
|
2278
2276
|
}
|
|
2279
2277
|
} else if (node.tagName === "select") {
|
|
2280
|
-
eventName = "change";
|
|
2281
2278
|
if (node.attributes.find((a) => a.name === "multiple")) {
|
|
2282
2279
|
buildRun("setBinding", `Array.from(${varName}.options).forEach((opt) => opt.selected = Array.isArray(${value}) && ${value}.includes(opt.value));`, status, b);
|
|
2283
|
-
|
|
2284
|
-
b.append(`t_event(${varName}, "change", (e) => ${value} = Array.from(e.target.selectedOptions).map((opt) => opt.value));`);
|
|
2280
|
+
emitBindEvent(varName, eventName, `(e) => ${value} = Array.from(e.target.selectedOptions).map((opt) => opt.value)`, `${value} = Array.from(e.target.selectedOptions).map((opt) => opt.value);`, combined, status, b);
|
|
2285
2281
|
return;
|
|
2286
2282
|
}
|
|
2287
2283
|
}
|
|
2288
2284
|
let set = `${value} || ${defaultValue}`;
|
|
2289
2285
|
const propName = name.substring(1);
|
|
2290
2286
|
buildRun("setBinding", `${propName === "value" ? `${varName}.${propName} = String(${set})` : `${varName}.${propName} = ${set}`};`, status, b);
|
|
2287
|
+
emitBindEvent(varName, eventName, `(e) => ${value} = ${inputValue}`, `${value} = ${inputValue};`, combined, status, b);
|
|
2288
|
+
}
|
|
2289
|
+
/**
|
|
2290
|
+
* Gets the name of the event that a &-binding attribute uses to write the
|
|
2291
|
+
* element's state back to the bound value
|
|
2292
|
+
*/
|
|
2293
|
+
function bindEventName(node, name) {
|
|
2294
|
+
if (name === "&group") return "change";
|
|
2295
|
+
if (node.tagName === "select") return "change";
|
|
2296
|
+
if (node.tagName === "input") {
|
|
2297
|
+
let typeAttribute = node.attributes.find((a) => a.name === "type");
|
|
2298
|
+
if (typeAttribute?.value && trimQuotes(typeAttribute.value) === "radio") return "change";
|
|
2299
|
+
}
|
|
2300
|
+
return "input";
|
|
2301
|
+
}
|
|
2302
|
+
/**
|
|
2303
|
+
* Pairs &-binding attributes (&value, &checked, &group) with user `on<event>`
|
|
2304
|
+
* handler attributes listening to the same event. Both would emit their own
|
|
2305
|
+
* t_event call for the element, but the second registration would clobber
|
|
2306
|
+
* the first -- typically the binding's state write -- so the pair is emitted
|
|
2307
|
+
* as one t_event that calls the binding write and the user handler in source
|
|
2308
|
+
* order. Returns a map from binding attribute index to the combined handler.
|
|
2309
|
+
*/
|
|
2310
|
+
function combinedEventHandlers(node, status) {
|
|
2311
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
2312
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
2313
|
+
for (let [index, { name, value, fullyReactive }] of node.attributes.entries()) {
|
|
2314
|
+
if (value == null || !fullyReactive) continue;
|
|
2315
|
+
if (name === "&value" || name === "&checked" || name === "&group") bindings.set(bindEventName(node, name), index);
|
|
2316
|
+
else if (name.startsWith("on")) handlers.set(name.substring(2), index);
|
|
2317
|
+
}
|
|
2318
|
+
const combined = /* @__PURE__ */ new Map();
|
|
2319
|
+
for (let [eventName, bindingIndex] of bindings) {
|
|
2320
|
+
const handlerIndex = handlers.get(eventName);
|
|
2321
|
+
if (handlerIndex === void 0) continue;
|
|
2322
|
+
const handler = node.attributes[handlerIndex];
|
|
2323
|
+
combined.set(bindingIndex, {
|
|
2324
|
+
index: handlerIndex,
|
|
2325
|
+
value: replaceForVarNames(handler.value, status),
|
|
2326
|
+
span: handler.span,
|
|
2327
|
+
first: handlerIndex < bindingIndex
|
|
2328
|
+
});
|
|
2329
|
+
}
|
|
2330
|
+
return combined;
|
|
2331
|
+
}
|
|
2332
|
+
/**
|
|
2333
|
+
* Emits the t_event call for a &-binding, optionally combined with a user
|
|
2334
|
+
* `on<event>` handler for the same event (which is called after -- or, when
|
|
2335
|
+
* it appeared first in source, before -- the binding write)
|
|
2336
|
+
*/
|
|
2337
|
+
function emitBindEvent(varName, eventName, listener, body, combined, status, b) {
|
|
2291
2338
|
status.imports.add("t_event");
|
|
2292
|
-
|
|
2339
|
+
if (!combined) {
|
|
2340
|
+
b.append(`t_event(${varName}, "${eventName}", ${listener});`);
|
|
2341
|
+
return;
|
|
2342
|
+
}
|
|
2343
|
+
b.append(`t_event(${varName}, "${eventName}", (e) => {`);
|
|
2344
|
+
const handlerCall = `((${combined.value}) as ((e: any) => any) | undefined)?.(e);`;
|
|
2345
|
+
if (combined.first) {
|
|
2346
|
+
addMappedText("", handlerCall, "", combined.span, status, b);
|
|
2347
|
+
b.append(body);
|
|
2348
|
+
} else {
|
|
2349
|
+
b.append(body);
|
|
2350
|
+
addMappedText("", handlerCall, "", combined.span, status, b);
|
|
2351
|
+
}
|
|
2352
|
+
b.append("});");
|
|
2293
2353
|
}
|
|
2294
2354
|
function buildEventAttribute(varName, name, value, span, status, b) {
|
|
2295
2355
|
value = replaceForVarNames(value, status);
|
|
@@ -2800,7 +2860,7 @@ function buildServerComponentNode(node, status, b) {
|
|
|
2800
2860
|
const nameAttribute = slot.attributes.find((a) => a.name === "name");
|
|
2801
2861
|
const slotName = nameAttribute?.value ? trimQuotes(nameAttribute.value) : "_";
|
|
2802
2862
|
const slotParams = [slot.hasSlotProps ? "$slot: Record<PropertyKey, any>" : "_$slot?: Record<PropertyKey, any>", "// @ts-ignore\n// eslint-disable-next-line no-unused-vars\n$context?: Record<PropertyKey, any>"];
|
|
2803
|
-
b.append(`${slot.hasSlotProps ? "// @ts-ignore\n" : ""}${slotsName}["${slotName}"] = (\n${slotParams.join(",\n")}\n) => {`);
|
|
2863
|
+
b.append(`${slot.hasSlotProps ? "// @ts-ignore\n" : ""}${slotsName}["${slotName}"] = async (\n${slotParams.join(",\n")}\n) => {`);
|
|
2804
2864
|
b.append(`let t_body = "";`);
|
|
2805
2865
|
for (let child of slot.children) buildServerNode(child, status, b);
|
|
2806
2866
|
if (status.output) {
|
|
@@ -2819,7 +2879,7 @@ function buildServerComponentNode(node, status, b) {
|
|
|
2819
2879
|
let renderParams = `${propsName}, $context`;
|
|
2820
2880
|
if (slotsName !== "undefined") renderParams += `, ${slotsName}`;
|
|
2821
2881
|
const componentResult = nextVarName("comp", status);
|
|
2822
|
-
b.append(`const ${componentResult} = ${componentName}(${renderParams});`);
|
|
2882
|
+
b.append(`const ${componentResult} = await ${componentName}(${renderParams});`);
|
|
2823
2883
|
b.append(`${status.inHead ? "t_head" : "t_body"} += ${componentResult}.body;`);
|
|
2824
2884
|
b.append(`t_head += ${componentResult}.head;`);
|
|
2825
2885
|
status.output += HYDRATION_END_COMMENT;
|
|
@@ -2827,16 +2887,37 @@ function buildServerComponentNode(node, status, b) {
|
|
|
2827
2887
|
}
|
|
2828
2888
|
//#endregion
|
|
2829
2889
|
//#region src/compile/build/server/buildServerAwaitNode.ts
|
|
2890
|
+
/**
|
|
2891
|
+
* Builds an `@await` boundary for the server (ASYNC.md → "Server rendering").
|
|
2892
|
+
*
|
|
2893
|
+
* Rather than inlining the `with` branch (the old shape), the boundary is
|
|
2894
|
+
* handed to the `t_await_server` runtime helper: content and `with` branches
|
|
2895
|
+
* become closures, and the helper decides at render time whether resolved
|
|
2896
|
+
* content can ship (all `source: "server"` reads settled) or the `with`
|
|
2897
|
+
* branch + client fetch is the honest output. The runtime emits the
|
|
2898
|
+
* hydration markers and anchor itself, including the `<!--t-await:...-->`
|
|
2899
|
+
* values payload for resolved boundaries.
|
|
2900
|
+
*/
|
|
2830
2901
|
function buildServerAwaitNode(node, status, b) {
|
|
2831
|
-
status.output += HYDRATION_START_COMMENT;
|
|
2832
2902
|
flushOutput(status, b);
|
|
2833
|
-
|
|
2834
|
-
status.
|
|
2835
|
-
|
|
2836
|
-
}
|
|
2837
|
-
|
|
2838
|
-
|
|
2903
|
+
status.imports.add("t_await_server");
|
|
2904
|
+
const id = status.awaitCount++;
|
|
2905
|
+
const resultName = nextVarName("await", status);
|
|
2906
|
+
b.append(`const ${resultName} = await t_await_server("${id}", async () => {`);
|
|
2907
|
+
b.append(`let t_body = "";`);
|
|
2908
|
+
b.append(`let t_head = "";`);
|
|
2909
|
+
for (let branch of node.children) if (isControlNode(branch) && branch.operation === "@await") for (let child of branch.children) buildServerNode(child, status, b);
|
|
2910
|
+
flushOutput(status, b);
|
|
2911
|
+
b.append(`return { body: t_body, head: t_head };`);
|
|
2912
|
+
b.append(`}, async () => {`);
|
|
2913
|
+
b.append(`let t_body = "";`);
|
|
2914
|
+
b.append(`let t_head = "";`);
|
|
2915
|
+
for (let branch of node.children) if (isControlNode(branch) && branch.operation === "@with") for (let child of branch.children) buildServerNode(child, status, b);
|
|
2839
2916
|
flushOutput(status, b);
|
|
2917
|
+
b.append(`return { body: t_body, head: t_head };`);
|
|
2918
|
+
b.append(`});`);
|
|
2919
|
+
b.append(`${status.inHead ? "t_head" : "t_body"} += ${resultName}.body;`);
|
|
2920
|
+
b.append(`t_head += ${resultName}.head;`);
|
|
2840
2921
|
}
|
|
2841
2922
|
//#endregion
|
|
2842
2923
|
//#region src/compile/build/server/buildServerForNode.ts
|
|
@@ -3091,7 +3172,7 @@ function buildServerSlotNode(node, status, b) {
|
|
|
3091
3172
|
else b.append(`${propsName}["${name}"] = true;`);
|
|
3092
3173
|
}
|
|
3093
3174
|
b.append(`if ($slots && $slots["${slotName}"]) {`);
|
|
3094
|
-
b.append(`${status.inHead ? "t_head" : "t_body"} += $slots["${slotName}"](${slotHasProps ? propsName : "undefined"}, $context);`);
|
|
3175
|
+
b.append(`${status.inHead ? "t_head" : "t_body"} += await $slots["${slotName}"](${slotHasProps ? propsName : "undefined"}, $context);`);
|
|
3095
3176
|
const fill = node.children.find((c) => isSpecialNode(c) && (c.tagName === "fill" || c.tagName === "filldef"));
|
|
3096
3177
|
if (fill && isSpecialNode(fill) && fill.children.length) {
|
|
3097
3178
|
b.append(`} else {`);
|
|
@@ -3194,6 +3275,8 @@ const importsMap = {
|
|
|
3194
3275
|
$unwrap: "import { $unwrap } from \"${folder}\";",
|
|
3195
3276
|
$peek: "import { $peek } from \"${folder}\";",
|
|
3196
3277
|
$batch: "import { $batch } from \"${folder}\";",
|
|
3278
|
+
t_server_flush: "import { t_server_flush } from \"${folder}\";",
|
|
3279
|
+
t_await_server: "import { t_await_server } from \"${folder}\";",
|
|
3197
3280
|
t_fmt: "import { t_fmt } from \"${folder}\";",
|
|
3198
3281
|
t_attr: "import { t_attr } from \"${folder}\";",
|
|
3199
3282
|
t_class: "import { t_class } from \"${folder}\";",
|
|
@@ -3236,18 +3319,24 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3236
3319
|
if (/\$unwrap\b/.test(scriptCode)) imports.add("$unwrap");
|
|
3237
3320
|
if (/\$peek\b/.test(scriptCode)) imports.add("$peek");
|
|
3238
3321
|
if (/\$batch\b/.test(scriptCode)) imports.add("$batch");
|
|
3322
|
+
const asyncChunks = /* @__PURE__ */ new Set();
|
|
3323
|
+
for (let [i, chunk] of template.script.entries()) if (chunk.script === "/* @params */" && i > 0) asyncChunks.add(i - 1);
|
|
3239
3324
|
let currentIndex = 0;
|
|
3240
3325
|
let current = template.components[0];
|
|
3241
|
-
for (let chunk of template.script) if (chunk.script === "/* @params */") {
|
|
3326
|
+
for (let [chunkIndex, chunk] of template.script.entries()) if (chunk.script === "/* @params */") {
|
|
3242
3327
|
let params = [
|
|
3243
3328
|
current.params ?? `${current.props?.length ? "$props: Record<PropertyKey, any>" : "_$props?: Record<PropertyKey, any>"}`,
|
|
3244
3329
|
`${current.contextProps?.length || current.markup && markupRendersComponent(current.markup) || current.error && markupRendersComponent(current.error) ? "$context" : "_$context"}?: Record<PropertyKey, any>`,
|
|
3245
3330
|
`${current.slotProps?.length ? "$slots" : "_$slots"}?: Record<string, ServerSlotRender>`
|
|
3246
3331
|
];
|
|
3247
3332
|
b.append(params.join(",\n") + ",");
|
|
3248
|
-
} else if (chunk.script === ") /* @return_type */ {") b.append("): { body: string; head: string } {");
|
|
3333
|
+
} else if (chunk.script === ") /* @return_type */ {") b.append("): Promise<{ body: string; head: string }> {");
|
|
3249
3334
|
else if (chunk.script === "/* @start */") {
|
|
3250
3335
|
if (current.contextProps?.length) b.append(`$context = Object.assign({}, $context);`);
|
|
3336
|
+
if (containsAwaitGroup(current.markup) || containsAwaitGroup(current.error) || containsAwaitGroup(current.head)) {
|
|
3337
|
+
imports.add("t_server_flush");
|
|
3338
|
+
b.append(`return t_server_flush(async () => {`);
|
|
3339
|
+
}
|
|
3251
3340
|
b.append(`let t_body = "";`);
|
|
3252
3341
|
b.append(`let t_head = "";`);
|
|
3253
3342
|
} else if (chunk.script === "/* @render */") {
|
|
@@ -3258,6 +3347,7 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3258
3347
|
styleHash: current.style?.hash || "",
|
|
3259
3348
|
varNames: {},
|
|
3260
3349
|
preserveWhitespace: false,
|
|
3350
|
+
awaitCount: 0,
|
|
3261
3351
|
options
|
|
3262
3352
|
};
|
|
3263
3353
|
b.append("");
|
|
@@ -3281,6 +3371,7 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3281
3371
|
styleHash: current.style?.hash || "",
|
|
3282
3372
|
varNames: {},
|
|
3283
3373
|
preserveWhitespace: false,
|
|
3374
|
+
awaitCount: 0,
|
|
3284
3375
|
options
|
|
3285
3376
|
};
|
|
3286
3377
|
b.append(`} catch (${current.errorVar}) {`);
|
|
@@ -3303,6 +3394,7 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3303
3394
|
varNames: {},
|
|
3304
3395
|
preserveWhitespace: false,
|
|
3305
3396
|
inHead: true,
|
|
3397
|
+
awaitCount: 0,
|
|
3306
3398
|
options
|
|
3307
3399
|
};
|
|
3308
3400
|
b.append("");
|
|
@@ -3319,9 +3411,23 @@ function buildServerTemplate(template, imports, b, options) {
|
|
|
3319
3411
|
}
|
|
3320
3412
|
} else if (chunk.script === "/* @end */") {
|
|
3321
3413
|
b.append(`return { body: t_body, head: t_head };`);
|
|
3414
|
+
if (containsAwaitGroup(current.markup) || containsAwaitGroup(current.error) || containsAwaitGroup(current.head)) b.append(`});`);
|
|
3322
3415
|
currentIndex += 1;
|
|
3323
3416
|
current = template.components[currentIndex];
|
|
3324
|
-
} else b.append(chunk.script);
|
|
3417
|
+
} else if (asyncChunks.has(chunkIndex)) b.append(chunk.script.replace(/(?<!async\s)function\s+([A-Za-z_$][\w$]*)((?:<(?:[^<>]|<[^<>]*>)*>)?)\s*\($/, "async function $1$2("));
|
|
3418
|
+
else b.append(chunk.script);
|
|
3419
|
+
}
|
|
3420
|
+
/**
|
|
3421
|
+
* Whether a markup tree contains an `@await` boundary, so the component's
|
|
3422
|
+
* render must be wrapped in a flush.
|
|
3423
|
+
*/
|
|
3424
|
+
function containsAwaitGroup(node) {
|
|
3425
|
+
if (node === void 0 || node === null) return false;
|
|
3426
|
+
if (isControlNode(node) && node.operation === "@await group") return true;
|
|
3427
|
+
if (node.type !== "text" && node.type !== "comment") {
|
|
3428
|
+
for (let child of node.children) if (containsAwaitGroup(child)) return true;
|
|
3429
|
+
}
|
|
3430
|
+
return false;
|
|
3325
3431
|
}
|
|
3326
3432
|
//#endregion
|
|
3327
3433
|
//#region src/compile/utils/trimWhitespace.ts
|