micra.js 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +231 -0
- package/README.md +69 -40
- package/dist/core/mount.d.ts +8 -2
- package/dist/core/registry.d.ts +13 -4
- package/dist/dom/directives.d.ts +11 -15
- package/dist/dom/each.d.ts +6 -4
- package/dist/dom/events.d.ts +15 -5
- package/dist/dom/refs.d.ts +5 -5
- package/dist/dom/scan.d.ts +34 -0
- package/dist/index.d.ts +1 -1
- package/dist/micra.cjs.js +199 -144
- package/dist/micra.cjs.js.map +4 -4
- package/dist/micra.esm.js +199 -144
- package/dist/micra.esm.js.map +4 -4
- package/dist/micra.js +199 -144
- package/dist/micra.js.map +4 -4
- package/dist/micra.min.js +2 -2
- package/dist/types.d.ts +63 -21
- package/llms-full.txt +600 -0
- package/llms.txt +148 -0
- package/package.json +11 -3
- package/src/core/mount.ts +126 -98
- package/src/core/registry.ts +19 -9
- package/src/dom/directives.ts +34 -120
- package/src/dom/each.ts +36 -19
- package/src/dom/events.ts +23 -31
- package/src/dom/refs.ts +6 -7
- package/src/dom/scan.ts +189 -0
- package/src/index.ts +2 -0
- package/src/types.ts +76 -21
- package/src/utils/fetch.ts +3 -1
package/dist/micra.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Micra.js v2.
|
|
1
|
+
/* Micra.js v2.2.0 — https://github.com/micra-js/micra — MIT */
|
|
2
2
|
|
|
3
3
|
// src/utils/fetch.ts
|
|
4
4
|
function getCSRF() {
|
|
@@ -27,7 +27,8 @@ async function micraFetch(url, options = {}) {
|
|
|
27
27
|
if (method === "GET" || method === "HEAD") {
|
|
28
28
|
const params = {};
|
|
29
29
|
for (const [k, v] of Object.entries(options)) {
|
|
30
|
-
if (k !== "method" && k !== "headers" && v != null)
|
|
30
|
+
if (k !== "method" && k !== "headers" && k !== "signal" && v != null)
|
|
31
|
+
params[k] = String(v);
|
|
31
32
|
}
|
|
32
33
|
if (Object.keys(params).length)
|
|
33
34
|
finalUrl += (url.includes("?") ? "&" : "?") + new URLSearchParams(params);
|
|
@@ -38,6 +39,7 @@ async function micraFetch(url, options = {}) {
|
|
|
38
39
|
const res = await fetch(finalUrl, {
|
|
39
40
|
method,
|
|
40
41
|
headers,
|
|
42
|
+
...options.signal !== void 0 ? { signal: options.signal } : {},
|
|
41
43
|
...body !== void 0 ? { body } : {}
|
|
42
44
|
});
|
|
43
45
|
if (!res.ok)
|
|
@@ -219,27 +221,6 @@ function createScheduler(render) {
|
|
|
219
221
|
};
|
|
220
222
|
}
|
|
221
223
|
|
|
222
|
-
// src/dom/query.ts
|
|
223
|
-
function queryAll(root, sel) {
|
|
224
|
-
return Array.from(root.querySelectorAll(sel));
|
|
225
|
-
}
|
|
226
|
-
function queryOwn(root, attr) {
|
|
227
|
-
return filterOwn(root, queryAll(root, `[${attr}]`));
|
|
228
|
-
}
|
|
229
|
-
function queryOwnAll(root, sel) {
|
|
230
|
-
return filterOwn(root, queryAll(root, sel));
|
|
231
|
-
}
|
|
232
|
-
function filterOwn(root, els) {
|
|
233
|
-
return els.filter((el) => {
|
|
234
|
-
let node = el.parentElement;
|
|
235
|
-
while (node && node !== root) {
|
|
236
|
-
if (node.hasAttribute("data-component")) return false;
|
|
237
|
-
node = node.parentElement;
|
|
238
|
-
}
|
|
239
|
-
return true;
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
|
|
243
224
|
// src/dom/directives.ts
|
|
244
225
|
function applyText(el, expr, state) {
|
|
245
226
|
var _a;
|
|
@@ -293,92 +274,37 @@ function applyClass(el, pairs, state) {
|
|
|
293
274
|
el.classList.toggle(cls, Boolean(evalExpr(valExpr, state)));
|
|
294
275
|
}
|
|
295
276
|
}
|
|
296
|
-
function parsePairs(expr) {
|
|
297
|
-
const out = [];
|
|
298
|
-
for (const part of expr.split(",")) {
|
|
299
|
-
const colonIdx = part.indexOf(":");
|
|
300
|
-
if (colonIdx === -1) continue;
|
|
301
|
-
const left = part.slice(0, colonIdx).trim();
|
|
302
|
-
const right = part.slice(colonIdx + 1).trim();
|
|
303
|
-
if (!left) continue;
|
|
304
|
-
out.push([left, right]);
|
|
305
|
-
}
|
|
306
|
-
return out;
|
|
307
|
-
}
|
|
308
277
|
function applyModel(el, key, rawState) {
|
|
309
278
|
const html = el;
|
|
310
279
|
const stateVal = rawState[key];
|
|
311
280
|
const desired = stateVal == null ? "" : String(stateVal);
|
|
312
281
|
if (html.value !== desired) html.value = desired;
|
|
313
282
|
}
|
|
314
|
-
function
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
if: pick("data-if"),
|
|
326
|
-
show: pick("data-show"),
|
|
327
|
-
bind: pickPairs("data-bind"),
|
|
328
|
-
model: pick("data-model"),
|
|
329
|
-
class: pickPairs("data-class")
|
|
330
|
-
};
|
|
331
|
-
}
|
|
332
|
-
function applyDirectives(root, state, rawState, _instance) {
|
|
333
|
-
if (root.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
334
|
-
applyFromList(buildFragmentList(root), state, rawState);
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
|
-
const el = root;
|
|
338
|
-
if (!el.__micraCache) el.__micraCache = buildCache(el);
|
|
339
|
-
applyFromList(el.__micraCache, state, rawState);
|
|
340
|
-
}
|
|
341
|
-
function applyFromList(cache, state, rawState) {
|
|
342
|
-
cache.if.forEach((b) => applyIf(b, state));
|
|
343
|
-
cache.text.forEach((b) => applyText(b.el, b.expr, state));
|
|
344
|
-
cache.html.forEach((b) => applyHtml(b.el, b.expr, state));
|
|
345
|
-
cache.show.forEach((b) => applyShow(b.el, b.expr, state));
|
|
346
|
-
cache.bind.forEach((b) => applyBind(b.el, b.pairs, state));
|
|
347
|
-
cache.model.forEach((b) => applyModel(b.el, b.expr.trim(), rawState));
|
|
348
|
-
cache.class.forEach((b) => applyClass(b.el, b.pairs, state));
|
|
349
|
-
}
|
|
350
|
-
function buildFragmentList(frag) {
|
|
351
|
-
const pick = (attr) => queryAll(frag, `[${attr}]`).filter((el) => !el.closest("template")).map((el) => ({ el, expr: el.getAttribute(attr) }));
|
|
352
|
-
const pickPairs = (attr) => pick(attr).map((b) => ({ ...b, pairs: parsePairs(b.expr) }));
|
|
353
|
-
return {
|
|
354
|
-
text: pick("data-text"),
|
|
355
|
-
html: pick("data-html"),
|
|
356
|
-
if: pick("data-if"),
|
|
357
|
-
show: pick("data-show"),
|
|
358
|
-
bind: pickPairs("data-bind"),
|
|
359
|
-
model: pick("data-model"),
|
|
360
|
-
class: pickPairs("data-class")
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
function validateDirectives(root) {
|
|
364
|
-
var _a, _b;
|
|
365
|
-
queryOwn(root, "data-each").forEach((el) => {
|
|
283
|
+
function applyDirectives(scan, state, rawState, _instance) {
|
|
284
|
+
for (const b of scan.if) applyIf(b, state);
|
|
285
|
+
for (const b of scan.text) applyText(b.el, b.expr, state);
|
|
286
|
+
for (const b of scan.html) applyHtml(b.el, b.expr, state);
|
|
287
|
+
for (const b of scan.show) applyShow(b.el, b.expr, state);
|
|
288
|
+
for (const b of scan.bind) applyBind(b.el, b.pairs, state);
|
|
289
|
+
for (const b of scan.model) applyModel(b.el, b.expr.trim(), rawState);
|
|
290
|
+
for (const b of scan.class) applyClass(b.el, b.pairs, state);
|
|
291
|
+
}
|
|
292
|
+
function validateDirectives(scan) {
|
|
293
|
+
for (const el of scan.each) {
|
|
366
294
|
const tmpl = el;
|
|
367
295
|
if (!el.hasAttribute("data-key") && !tmpl.__micraNoKeyWarned) {
|
|
368
296
|
tmpl.__micraNoKeyWarned = true;
|
|
369
|
-
warn(
|
|
297
|
+
warn(
|
|
298
|
+
`data-each="${el.getAttribute("data-each")}" has no data-key \u2014 keyed diff disabled. Add data-key="id" for better performance.`
|
|
299
|
+
);
|
|
370
300
|
}
|
|
371
|
-
}
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
return ((_a2 = p.trim().split(":")[0]) == null ? void 0 : _a2.trim()) === "class";
|
|
379
|
-
});
|
|
380
|
-
if (hasClassBind && el.hasAttribute("data-class")) {
|
|
381
|
-
warn(`element has both data-bind="class:..." and data-class \u2014 they fight on every render. Use one.`);
|
|
301
|
+
}
|
|
302
|
+
for (const b of scan.bind) {
|
|
303
|
+
const hasClassBind = b.pairs.some((p) => p[0] === "class");
|
|
304
|
+
if (hasClassBind && b.el.hasAttribute("data-class")) {
|
|
305
|
+
warn(
|
|
306
|
+
`element has both data-bind="class:..." and data-class \u2014 they fight on every render. Use one.`
|
|
307
|
+
);
|
|
382
308
|
}
|
|
383
309
|
}
|
|
384
310
|
}
|
|
@@ -389,17 +315,13 @@ function track(instance, el, type, fn) {
|
|
|
389
315
|
el.addEventListener(type, fn);
|
|
390
316
|
((_a = instance.__micraListeners) != null ? _a : instance.__micraListeners = []).push({ el, type, fn });
|
|
391
317
|
}
|
|
392
|
-
function bindDataOn(
|
|
393
|
-
var _a
|
|
394
|
-
const isFragment = root.nodeType === 11;
|
|
395
|
-
const els = isFragment ? queryAll(root, "[data-on]") : queryOwn(root, "data-on");
|
|
396
|
-
if (!isFragment && ((_a = root.hasAttribute) == null ? void 0 : _a.call(root, "data-on")) && !els.includes(root))
|
|
397
|
-
els.unshift(root);
|
|
318
|
+
function bindDataOn(els, instance) {
|
|
319
|
+
var _a;
|
|
398
320
|
for (const el of els) {
|
|
399
321
|
const mEl = el;
|
|
400
322
|
if (mEl.__micraEvents) continue;
|
|
401
323
|
mEl.__micraEvents = true;
|
|
402
|
-
const spec = (
|
|
324
|
+
const spec = (_a = mEl.dataset["on"]) != null ? _a : "";
|
|
403
325
|
for (const part of spec.split(",")) {
|
|
404
326
|
const [evSpec, method] = part.trim().split(":");
|
|
405
327
|
if (!evSpec || !method) continue;
|
|
@@ -415,11 +337,8 @@ function bindDataOn(root, instance) {
|
|
|
415
337
|
}
|
|
416
338
|
}
|
|
417
339
|
}
|
|
418
|
-
function bindAtEvents(
|
|
419
|
-
const
|
|
420
|
-
const all = isFragment ? queryAll(root, "*") : queryOwnAll(root, "*");
|
|
421
|
-
if (!isFragment && !all.includes(root)) all.unshift(root);
|
|
422
|
-
for (const el of all) {
|
|
340
|
+
function bindAtEvents(els, instance) {
|
|
341
|
+
for (const el of els) {
|
|
423
342
|
const mEl = el;
|
|
424
343
|
if (mEl.__micraAtBound) continue;
|
|
425
344
|
let bound = false;
|
|
@@ -440,15 +359,12 @@ function bindAtEvents(root, instance) {
|
|
|
440
359
|
if (bound) mEl.__micraAtBound = true;
|
|
441
360
|
}
|
|
442
361
|
}
|
|
443
|
-
function bindModels(
|
|
444
|
-
|
|
445
|
-
const isFragment = root.nodeType === 11;
|
|
446
|
-
const els = isFragment ? queryAll(root, "[data-model]") : queryOwn(root, "data-model");
|
|
447
|
-
for (const el of els) {
|
|
362
|
+
function bindModels(bindings, instance) {
|
|
363
|
+
for (const { el, expr } of bindings) {
|
|
448
364
|
const mEl = el;
|
|
449
365
|
if (mEl.__micraModel) continue;
|
|
450
366
|
mEl.__micraModel = true;
|
|
451
|
-
const key = (
|
|
367
|
+
const key = expr.trim();
|
|
452
368
|
const tag = el.tagName;
|
|
453
369
|
const inputEl = el;
|
|
454
370
|
const inputType = inputEl.type;
|
|
@@ -469,11 +385,132 @@ function bindModels(root, instance) {
|
|
|
469
385
|
}
|
|
470
386
|
}
|
|
471
387
|
|
|
388
|
+
// src/dom/scan.ts
|
|
389
|
+
function emptyScan() {
|
|
390
|
+
return {
|
|
391
|
+
text: [],
|
|
392
|
+
html: [],
|
|
393
|
+
if: [],
|
|
394
|
+
show: [],
|
|
395
|
+
bind: [],
|
|
396
|
+
model: [],
|
|
397
|
+
class: [],
|
|
398
|
+
each: [],
|
|
399
|
+
on: [],
|
|
400
|
+
atEvents: [],
|
|
401
|
+
refs: []
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
function parsePairs(expr) {
|
|
405
|
+
const out = [];
|
|
406
|
+
for (const part of expr.split(",")) {
|
|
407
|
+
const colon = part.indexOf(":");
|
|
408
|
+
if (colon === -1) continue;
|
|
409
|
+
const left = part.slice(0, colon).trim();
|
|
410
|
+
const right = part.slice(colon + 1).trim();
|
|
411
|
+
if (!left) continue;
|
|
412
|
+
out.push([left, right]);
|
|
413
|
+
}
|
|
414
|
+
return out;
|
|
415
|
+
}
|
|
416
|
+
function classify(el, scan) {
|
|
417
|
+
if (el.tagName === "TEMPLATE") {
|
|
418
|
+
if (el.hasAttribute("data-each")) scan.each.push(el);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const attrs = el.attributes;
|
|
422
|
+
let atEventSeen = false;
|
|
423
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
424
|
+
const a = attrs[i];
|
|
425
|
+
const name = a.name;
|
|
426
|
+
const first = name.charCodeAt(0);
|
|
427
|
+
if (first === 64) {
|
|
428
|
+
if (!atEventSeen) {
|
|
429
|
+
scan.atEvents.push(el);
|
|
430
|
+
atEventSeen = true;
|
|
431
|
+
}
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
if (first === 100 && name.length >= 6 && name.charCodeAt(4) === 45) {
|
|
435
|
+
const rest = name.slice(5);
|
|
436
|
+
switch (rest) {
|
|
437
|
+
case "text":
|
|
438
|
+
scan.text.push({ el, expr: a.value });
|
|
439
|
+
break;
|
|
440
|
+
case "html":
|
|
441
|
+
scan.html.push({ el, expr: a.value });
|
|
442
|
+
break;
|
|
443
|
+
case "if":
|
|
444
|
+
scan.if.push({ el, expr: a.value });
|
|
445
|
+
break;
|
|
446
|
+
case "show":
|
|
447
|
+
scan.show.push({ el, expr: a.value });
|
|
448
|
+
break;
|
|
449
|
+
case "bind": {
|
|
450
|
+
const pairs = parsePairs(a.value);
|
|
451
|
+
scan.bind.push({ el, expr: a.value, pairs });
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
case "model":
|
|
455
|
+
scan.model.push({ el, expr: a.value });
|
|
456
|
+
break;
|
|
457
|
+
case "class": {
|
|
458
|
+
const pairs = parsePairs(a.value);
|
|
459
|
+
scan.class.push({ el, expr: a.value, pairs });
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
case "on":
|
|
463
|
+
scan.on.push(el);
|
|
464
|
+
break;
|
|
465
|
+
case "ref":
|
|
466
|
+
scan.refs.push(el);
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
var NESTED_COMPONENT_FILTER = {
|
|
473
|
+
acceptNode(node) {
|
|
474
|
+
if (node.hasAttribute("data-component"))
|
|
475
|
+
return NodeFilter.FILTER_REJECT;
|
|
476
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
function scanComponent(root) {
|
|
480
|
+
const scan = emptyScan();
|
|
481
|
+
classify(root, scan);
|
|
482
|
+
const walker = document.createTreeWalker(
|
|
483
|
+
root,
|
|
484
|
+
NodeFilter.SHOW_ELEMENT,
|
|
485
|
+
NESTED_COMPONENT_FILTER
|
|
486
|
+
);
|
|
487
|
+
let node = walker.nextNode();
|
|
488
|
+
while (node) {
|
|
489
|
+
classify(node, scan);
|
|
490
|
+
node = walker.nextNode();
|
|
491
|
+
}
|
|
492
|
+
return scan;
|
|
493
|
+
}
|
|
494
|
+
function scanFragment(frag) {
|
|
495
|
+
const scan = emptyScan();
|
|
496
|
+
const walker = document.createTreeWalker(
|
|
497
|
+
frag,
|
|
498
|
+
NodeFilter.SHOW_ELEMENT,
|
|
499
|
+
NESTED_COMPONENT_FILTER
|
|
500
|
+
);
|
|
501
|
+
let node = walker.nextNode();
|
|
502
|
+
while (node) {
|
|
503
|
+
classify(node, scan);
|
|
504
|
+
node = walker.nextNode();
|
|
505
|
+
}
|
|
506
|
+
return scan;
|
|
507
|
+
}
|
|
508
|
+
|
|
472
509
|
// src/dom/each.ts
|
|
473
|
-
function renderList(
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
if (tmplEl.tagName !== "TEMPLATE")
|
|
510
|
+
function renderList(templates, state, rawState, instance) {
|
|
511
|
+
var _a;
|
|
512
|
+
for (const tmplEl of templates) {
|
|
513
|
+
if (tmplEl.tagName !== "TEMPLATE") continue;
|
|
477
514
|
const tmpl = tmplEl;
|
|
478
515
|
const itemsExpr = tmpl.getAttribute("data-each");
|
|
479
516
|
const keyAttr = (_a = tmpl.getAttribute("data-key")) != null ? _a : null;
|
|
@@ -488,21 +525,22 @@ function renderList(root, state, rawState, instance) {
|
|
|
488
525
|
const marker = tmpl.__micraMarker;
|
|
489
526
|
const keyMap = tmpl.__micraNodes;
|
|
490
527
|
const parent = marker.parentNode;
|
|
491
|
-
if (!parent)
|
|
528
|
+
if (!parent) continue;
|
|
492
529
|
if (!Array.isArray(items)) {
|
|
493
530
|
tmpl.__micraList.forEach((n) => n.remove());
|
|
494
531
|
tmpl.__micraList = [];
|
|
495
532
|
keyMap.clear();
|
|
496
|
-
|
|
533
|
+
continue;
|
|
497
534
|
}
|
|
498
535
|
if (keyAttr) {
|
|
499
536
|
renderKeyed(tmpl, items, keyAttr, marker, keyMap, parent, state, rawState, instance);
|
|
500
537
|
} else {
|
|
501
538
|
renderNoKey(tmpl, items, marker, parent, state, rawState, instance);
|
|
502
539
|
}
|
|
503
|
-
}
|
|
540
|
+
}
|
|
504
541
|
}
|
|
505
542
|
function renderKeyed(tmpl, items, keyAttr, marker, keyMap, parent, state, rawState, instance) {
|
|
543
|
+
var _a;
|
|
506
544
|
const nextKeys = /* @__PURE__ */ new Set();
|
|
507
545
|
const nextNodes = [];
|
|
508
546
|
let warnedNullKey = false;
|
|
@@ -530,14 +568,18 @@ function renderKeyed(tmpl, items, keyAttr, marker, keyMap, parent, state, rawSta
|
|
|
530
568
|
}
|
|
531
569
|
node.__micraKey = key;
|
|
532
570
|
keyMap.set(key, node);
|
|
533
|
-
|
|
534
|
-
|
|
571
|
+
const rowScan2 = scanComponent(node);
|
|
572
|
+
node.__micraScan = rowScan2;
|
|
573
|
+
bindDataOn(rowScan2.on, instance);
|
|
574
|
+
bindAtEvents(rowScan2.atEvents, instance);
|
|
575
|
+
bindModels(rowScan2.model, instance);
|
|
535
576
|
}
|
|
536
577
|
const itemState = Object.assign(
|
|
537
578
|
Object.create(state),
|
|
538
579
|
{ item, index, $index: index }
|
|
539
580
|
);
|
|
540
|
-
|
|
581
|
+
const rowScan = (_a = node.__micraScan) != null ? _a : node.__micraScan = scanComponent(node);
|
|
582
|
+
applyDirectives(rowScan, itemState, rawState, instance);
|
|
541
583
|
nextNodes.push(node);
|
|
542
584
|
}
|
|
543
585
|
for (const [key, node] of keyMap) {
|
|
@@ -563,9 +605,11 @@ function renderNoKey(tmpl, items, marker, parent, state, rawState, instance) {
|
|
|
563
605
|
Object.create(state),
|
|
564
606
|
{ item, index, $index: index }
|
|
565
607
|
);
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
608
|
+
const fragScan = scanFragment(clone);
|
|
609
|
+
applyDirectives(fragScan, itemState, rawState, instance);
|
|
610
|
+
bindDataOn(fragScan.on, instance);
|
|
611
|
+
bindAtEvents(fragScan.atEvents, instance);
|
|
612
|
+
bindModels(fragScan.model, instance);
|
|
569
613
|
const nodes = Array.from(clone.childNodes);
|
|
570
614
|
nodes.forEach((n) => {
|
|
571
615
|
n.__micraEach = true;
|
|
@@ -577,9 +621,9 @@ function renderNoKey(tmpl, items, marker, parent, state, rawState, instance) {
|
|
|
577
621
|
}
|
|
578
622
|
|
|
579
623
|
// src/dom/refs.ts
|
|
580
|
-
function collectRefs(
|
|
624
|
+
function collectRefs(els, instance) {
|
|
581
625
|
instance.refs = {};
|
|
582
|
-
for (const el of
|
|
626
|
+
for (const el of els) {
|
|
583
627
|
const name = el.dataset["ref"];
|
|
584
628
|
if (name) instance.refs[name] = el;
|
|
585
629
|
}
|
|
@@ -593,10 +637,13 @@ function mount(selector, definition) {
|
|
|
593
637
|
warn(`"${selector}" not found`);
|
|
594
638
|
return null;
|
|
595
639
|
}
|
|
596
|
-
if (_instances.has(root))
|
|
640
|
+
if (_instances.has(root))
|
|
641
|
+
return _instances.get(root);
|
|
597
642
|
const rawState = { ...(_a = definition.state) != null ? _a : {} };
|
|
598
643
|
const instance = { $el: root, refs: {} };
|
|
599
|
-
for (const [key, val] of Object.entries(
|
|
644
|
+
for (const [key, val] of Object.entries(
|
|
645
|
+
definition
|
|
646
|
+
)) {
|
|
600
647
|
if (key === "state" || key === "onCreate" || key === "onDestroy") continue;
|
|
601
648
|
if (typeof val === "function") instance[key] = val;
|
|
602
649
|
}
|
|
@@ -640,22 +687,27 @@ function mount(selector, definition) {
|
|
|
640
687
|
});
|
|
641
688
|
let warnedReentry = false;
|
|
642
689
|
instance.render = function() {
|
|
690
|
+
var _a2;
|
|
643
691
|
if (instance.__micraDestroyed) return;
|
|
644
692
|
if (isRendering) {
|
|
645
693
|
if (!warnedReentry) {
|
|
646
|
-
warn(
|
|
694
|
+
warn(
|
|
695
|
+
"render() re-entry detected \u2014 mutation inside a directive expression is ignored. Move state writes to a method."
|
|
696
|
+
);
|
|
647
697
|
warnedReentry = true;
|
|
648
698
|
}
|
|
649
699
|
return;
|
|
650
700
|
}
|
|
651
701
|
isRendering = true;
|
|
652
702
|
try {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
703
|
+
const mRoot2 = root;
|
|
704
|
+
const scan = (_a2 = mRoot2.__micraScan) != null ? _a2 : mRoot2.__micraScan = scanComponent(root);
|
|
705
|
+
applyDirectives(scan, exprState, rawState, instance);
|
|
706
|
+
renderList(scan.each, exprState, rawState, instance);
|
|
707
|
+
bindDataOn(scan.on, instance);
|
|
708
|
+
bindAtEvents(scan.atEvents, instance);
|
|
709
|
+
bindModels(scan.model, instance);
|
|
710
|
+
collectRefs(scan.refs, instance);
|
|
659
711
|
} finally {
|
|
660
712
|
isRendering = false;
|
|
661
713
|
}
|
|
@@ -664,14 +716,16 @@ function mount(selector, definition) {
|
|
|
664
716
|
var _a2, _b;
|
|
665
717
|
if (instance.__micraDestroyed) return;
|
|
666
718
|
instance.__micraDestroyed = true;
|
|
667
|
-
(_a2 = instance.__micraListeners) == null ? void 0 : _a2.forEach(
|
|
719
|
+
(_a2 = instance.__micraListeners) == null ? void 0 : _a2.forEach(
|
|
720
|
+
({ el, type, fn }) => el.removeEventListener(type, fn)
|
|
721
|
+
);
|
|
668
722
|
instance.__micraListeners = [];
|
|
669
723
|
const clearFlags = (el) => {
|
|
670
724
|
const m = el;
|
|
671
725
|
delete m.__micraEvents;
|
|
672
726
|
delete m.__micraAtBound;
|
|
673
727
|
delete m.__micraModel;
|
|
674
|
-
delete m.
|
|
728
|
+
delete m.__micraScan;
|
|
675
729
|
};
|
|
676
730
|
clearFlags(root);
|
|
677
731
|
root.querySelectorAll("*").forEach(clearFlags);
|
|
@@ -683,7 +737,8 @@ function mount(selector, definition) {
|
|
|
683
737
|
};
|
|
684
738
|
_instances.set(root, instance);
|
|
685
739
|
instance.render();
|
|
686
|
-
|
|
740
|
+
const mRoot = root;
|
|
741
|
+
if (mRoot.__micraScan) validateDirectives(mRoot.__micraScan);
|
|
687
742
|
if (typeof definition.onCreate === "function")
|
|
688
743
|
Promise.resolve().then(
|
|
689
744
|
() => definition.onCreate.call(instance)
|