@torpor/view 1.1.0 → 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/compile.cjs +80 -20
- package/dist/compile.mjs +80 -20
- package/dist/compile.mjs.map +1 -1
- package/package.json +1 -1
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);
|
package/dist/compile.mjs
CHANGED
|
@@ -2200,12 +2200,15 @@ function headElementSelector(node) {
|
|
|
2200
2200
|
function buildElementAttributes$1(node, varName, status, b) {
|
|
2201
2201
|
let fragment = status.fragmentStack.at(-1)?.fragment;
|
|
2202
2202
|
if (!fragment) throw new Error("No fragment on stack");
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2203
|
+
const combinedHandlers = combinedEventHandlers(node, status);
|
|
2204
|
+
const consumedHandlers = new Set(Array.from(combinedHandlers.values(), (c) => c.index));
|
|
2205
|
+
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) {
|
|
2206
|
+
if (name === "&group") buildBindGroupAttribute(node, varName, value, status, b, combinedHandlers.get(index));
|
|
2207
|
+
else if (name === "&value" || name === "&checked") buildBindAttribute(node, varName, name, value, status, b, combinedHandlers.get(index));
|
|
2206
2208
|
else if (name === "onmount") buildMount("elMount", `return (${trimEnd(value.trim(), ";")})(${varName});`, status, b);
|
|
2207
|
-
else if (name.startsWith("on"))
|
|
2208
|
-
|
|
2209
|
+
else if (name.startsWith("on")) {
|
|
2210
|
+
if (!consumedHandlers.has(index)) buildEventAttribute(varName, name, value, span, status, b);
|
|
2211
|
+
} else if (name.startsWith("transition")) buildTransitionAttribute(node, varName, name, value, status, b);
|
|
2209
2212
|
else if (name === "class") {
|
|
2210
2213
|
status.imports.add("t_class");
|
|
2211
2214
|
const params = [value];
|
|
@@ -2243,21 +2246,20 @@ function buildElementAttributes$1(node, varName, status, b) {
|
|
|
2243
2246
|
}
|
|
2244
2247
|
}
|
|
2245
2248
|
}
|
|
2246
|
-
function buildBindGroupAttribute(node, varName, value, status, b) {
|
|
2249
|
+
function buildBindGroupAttribute(node, varName, value, status, b, combined) {
|
|
2247
2250
|
value = replaceForVarNames(value, status);
|
|
2248
2251
|
let eventName = "change";
|
|
2249
2252
|
let inputValue = node.attributes.find((a) => a.name === "value")?.value;
|
|
2250
2253
|
let set = `${value} == ${inputValue}`;
|
|
2251
2254
|
let propName = "checked";
|
|
2252
2255
|
buildRun("setBinding", `${`${varName}.${propName} = ${set}`};`, status, b);
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
if (e.target.${propName}) ${value} = ${inputValue};
|
|
2256
|
-
});`);
|
|
2256
|
+
emitBindEvent(varName, eventName, `(e) => {
|
|
2257
|
+
if (e.target.${propName}) ${value} = ${inputValue};
|
|
2258
|
+
}`, `if (e.target.${propName}) ${value} = ${inputValue};`, combined, status, b);
|
|
2257
2259
|
}
|
|
2258
|
-
function buildBindAttribute(node, varName, name, value, status, b) {
|
|
2260
|
+
function buildBindAttribute(node, varName, name, value, status, b, combined) {
|
|
2259
2261
|
value = replaceForVarNames(value, status);
|
|
2260
|
-
let eventName =
|
|
2262
|
+
let eventName = bindEventName(node, name);
|
|
2261
2263
|
let defaultValue = "\"\"";
|
|
2262
2264
|
let inputValue = "e.target.value";
|
|
2263
2265
|
if (node.tagName === "input") {
|
|
@@ -2270,25 +2272,83 @@ function buildBindAttribute(node, varName, name, value, status, b) {
|
|
|
2270
2272
|
case "checkbox":
|
|
2271
2273
|
defaultValue = "false";
|
|
2272
2274
|
inputValue = "e.target.checked";
|
|
2273
|
-
break;
|
|
2274
|
-
case "radio":
|
|
2275
|
-
eventName = "change";
|
|
2276
|
-
inputValue = "e.target.value";
|
|
2277
2275
|
}
|
|
2278
2276
|
} else if (node.tagName === "select") {
|
|
2279
|
-
eventName = "change";
|
|
2280
2277
|
if (node.attributes.find((a) => a.name === "multiple")) {
|
|
2281
2278
|
buildRun("setBinding", `Array.from(${varName}.options).forEach((opt) => opt.selected = Array.isArray(${value}) && ${value}.includes(opt.value));`, status, b);
|
|
2282
|
-
|
|
2283
|
-
b.append(`t_event(${varName}, "change", (e) => ${value} = Array.from(e.target.selectedOptions).map((opt) => opt.value));`);
|
|
2279
|
+
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);
|
|
2284
2280
|
return;
|
|
2285
2281
|
}
|
|
2286
2282
|
}
|
|
2287
2283
|
let set = `${value} || ${defaultValue}`;
|
|
2288
2284
|
const propName = name.substring(1);
|
|
2289
2285
|
buildRun("setBinding", `${propName === "value" ? `${varName}.${propName} = String(${set})` : `${varName}.${propName} = ${set}`};`, status, b);
|
|
2286
|
+
emitBindEvent(varName, eventName, `(e) => ${value} = ${inputValue}`, `${value} = ${inputValue};`, combined, status, b);
|
|
2287
|
+
}
|
|
2288
|
+
/**
|
|
2289
|
+
* Gets the name of the event that a &-binding attribute uses to write the
|
|
2290
|
+
* element's state back to the bound value
|
|
2291
|
+
*/
|
|
2292
|
+
function bindEventName(node, name) {
|
|
2293
|
+
if (name === "&group") return "change";
|
|
2294
|
+
if (node.tagName === "select") return "change";
|
|
2295
|
+
if (node.tagName === "input") {
|
|
2296
|
+
let typeAttribute = node.attributes.find((a) => a.name === "type");
|
|
2297
|
+
if (typeAttribute?.value && trimQuotes(typeAttribute.value) === "radio") return "change";
|
|
2298
|
+
}
|
|
2299
|
+
return "input";
|
|
2300
|
+
}
|
|
2301
|
+
/**
|
|
2302
|
+
* Pairs &-binding attributes (&value, &checked, &group) with user `on<event>`
|
|
2303
|
+
* handler attributes listening to the same event. Both would emit their own
|
|
2304
|
+
* t_event call for the element, but the second registration would clobber
|
|
2305
|
+
* the first -- typically the binding's state write -- so the pair is emitted
|
|
2306
|
+
* as one t_event that calls the binding write and the user handler in source
|
|
2307
|
+
* order. Returns a map from binding attribute index to the combined handler.
|
|
2308
|
+
*/
|
|
2309
|
+
function combinedEventHandlers(node, status) {
|
|
2310
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
2311
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
2312
|
+
for (let [index, { name, value, fullyReactive }] of node.attributes.entries()) {
|
|
2313
|
+
if (value == null || !fullyReactive) continue;
|
|
2314
|
+
if (name === "&value" || name === "&checked" || name === "&group") bindings.set(bindEventName(node, name), index);
|
|
2315
|
+
else if (name.startsWith("on")) handlers.set(name.substring(2), index);
|
|
2316
|
+
}
|
|
2317
|
+
const combined = /* @__PURE__ */ new Map();
|
|
2318
|
+
for (let [eventName, bindingIndex] of bindings) {
|
|
2319
|
+
const handlerIndex = handlers.get(eventName);
|
|
2320
|
+
if (handlerIndex === void 0) continue;
|
|
2321
|
+
const handler = node.attributes[handlerIndex];
|
|
2322
|
+
combined.set(bindingIndex, {
|
|
2323
|
+
index: handlerIndex,
|
|
2324
|
+
value: replaceForVarNames(handler.value, status),
|
|
2325
|
+
span: handler.span,
|
|
2326
|
+
first: handlerIndex < bindingIndex
|
|
2327
|
+
});
|
|
2328
|
+
}
|
|
2329
|
+
return combined;
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Emits the t_event call for a &-binding, optionally combined with a user
|
|
2333
|
+
* `on<event>` handler for the same event (which is called after -- or, when
|
|
2334
|
+
* it appeared first in source, before -- the binding write)
|
|
2335
|
+
*/
|
|
2336
|
+
function emitBindEvent(varName, eventName, listener, body, combined, status, b) {
|
|
2290
2337
|
status.imports.add("t_event");
|
|
2291
|
-
|
|
2338
|
+
if (!combined) {
|
|
2339
|
+
b.append(`t_event(${varName}, "${eventName}", ${listener});`);
|
|
2340
|
+
return;
|
|
2341
|
+
}
|
|
2342
|
+
b.append(`t_event(${varName}, "${eventName}", (e) => {`);
|
|
2343
|
+
const handlerCall = `((${combined.value}) as ((e: any) => any) | undefined)?.(e);`;
|
|
2344
|
+
if (combined.first) {
|
|
2345
|
+
addMappedText("", handlerCall, "", combined.span, status, b);
|
|
2346
|
+
b.append(body);
|
|
2347
|
+
} else {
|
|
2348
|
+
b.append(body);
|
|
2349
|
+
addMappedText("", handlerCall, "", combined.span, status, b);
|
|
2350
|
+
}
|
|
2351
|
+
b.append("});");
|
|
2292
2352
|
}
|
|
2293
2353
|
function buildEventAttribute(varName, name, value, span, status, b) {
|
|
2294
2354
|
value = replaceForVarNames(value, status);
|