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
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/dom/scan.ts — Single-pass directive/event/ref scanner.
|
|
3
|
+
*
|
|
4
|
+
* Replaces 10+ querySelectorAll calls per render with ONE TreeWalker
|
|
5
|
+
* traversal that classifies every directive attribute in a single visit.
|
|
6
|
+
*
|
|
7
|
+
* Boundaries:
|
|
8
|
+
* - REJECT (skip subtree) on nested [data-component] — same semantics as
|
|
9
|
+
* the old `filterOwn` helper, but applied during the walk so we don't
|
|
10
|
+
* even *visit* those nodes.
|
|
11
|
+
* - <template> contents are not visited (browser TreeWalker default).
|
|
12
|
+
* `<template data-each>` itself IS visited and classified into scan.each;
|
|
13
|
+
* its children are processed by each.ts on every render via scanFragment.
|
|
14
|
+
*
|
|
15
|
+
* Hot-path notes:
|
|
16
|
+
* - We read `el.attributes` once and switch by suffix. No allocations per
|
|
17
|
+
* non-matching attr.
|
|
18
|
+
* - Pair-parsing (`data-bind`, `data-class`) happens here, once, at scan
|
|
19
|
+
* time. Reused on every render.
|
|
20
|
+
*/
|
|
21
|
+
import type { ScanIndex } from "../types";
|
|
22
|
+
/**
|
|
23
|
+
* Scan an Element subtree owned by one component. Skips nested
|
|
24
|
+
* [data-component] subtrees entirely. Visits the root itself.
|
|
25
|
+
*
|
|
26
|
+
* Cached on `el.__micraScan` after the first call — subsequent renders
|
|
27
|
+
* are free.
|
|
28
|
+
*/
|
|
29
|
+
export declare function scanComponent(root: Element): ScanIndex;
|
|
30
|
+
/**
|
|
31
|
+
* Scan a DocumentFragment (no-key each clone). Not cached — these fragments
|
|
32
|
+
* are temporary and re-cloned every render.
|
|
33
|
+
*/
|
|
34
|
+
export declare function scanFragment(frag: DocumentFragment): ScanIndex;
|
package/dist/index.d.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*
|
|
22
22
|
* @module Micra
|
|
23
23
|
*/
|
|
24
|
-
export type { StateRecord, UnsubFn, EventHandler, FetchOptions, ComponentInstance, ComponentDefinition, } from './types';
|
|
24
|
+
export type { StateRecord, UnsubFn, EventHandler, FetchOptions, ComponentMethods, ComponentBuiltins, ComponentInstance, ComponentDefinition, } from './types';
|
|
25
25
|
export { FetchError } from './utils/fetch';
|
|
26
26
|
export { define, defineComponent, instances, registry, debug } from './core/registry';
|
|
27
27
|
export { mount } from './core/mount';
|
package/dist/micra.cjs.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
|
"use strict";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -62,7 +62,8 @@ async function micraFetch(url, options = {}) {
|
|
|
62
62
|
if (method === "GET" || method === "HEAD") {
|
|
63
63
|
const params = {};
|
|
64
64
|
for (const [k, v] of Object.entries(options)) {
|
|
65
|
-
if (k !== "method" && k !== "headers" && v != null)
|
|
65
|
+
if (k !== "method" && k !== "headers" && k !== "signal" && v != null)
|
|
66
|
+
params[k] = String(v);
|
|
66
67
|
}
|
|
67
68
|
if (Object.keys(params).length)
|
|
68
69
|
finalUrl += (url.includes("?") ? "&" : "?") + new URLSearchParams(params);
|
|
@@ -73,6 +74,7 @@ async function micraFetch(url, options = {}) {
|
|
|
73
74
|
const res = await fetch(finalUrl, {
|
|
74
75
|
method,
|
|
75
76
|
headers,
|
|
77
|
+
...options.signal !== void 0 ? { signal: options.signal } : {},
|
|
76
78
|
...body !== void 0 ? { body } : {}
|
|
77
79
|
});
|
|
78
80
|
if (!res.ok)
|
|
@@ -254,27 +256,6 @@ function createScheduler(render) {
|
|
|
254
256
|
};
|
|
255
257
|
}
|
|
256
258
|
|
|
257
|
-
// src/dom/query.ts
|
|
258
|
-
function queryAll(root, sel) {
|
|
259
|
-
return Array.from(root.querySelectorAll(sel));
|
|
260
|
-
}
|
|
261
|
-
function queryOwn(root, attr) {
|
|
262
|
-
return filterOwn(root, queryAll(root, `[${attr}]`));
|
|
263
|
-
}
|
|
264
|
-
function queryOwnAll(root, sel) {
|
|
265
|
-
return filterOwn(root, queryAll(root, sel));
|
|
266
|
-
}
|
|
267
|
-
function filterOwn(root, els) {
|
|
268
|
-
return els.filter((el) => {
|
|
269
|
-
let node = el.parentElement;
|
|
270
|
-
while (node && node !== root) {
|
|
271
|
-
if (node.hasAttribute("data-component")) return false;
|
|
272
|
-
node = node.parentElement;
|
|
273
|
-
}
|
|
274
|
-
return true;
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
|
|
278
259
|
// src/dom/directives.ts
|
|
279
260
|
function applyText(el, expr, state) {
|
|
280
261
|
var _a;
|
|
@@ -328,92 +309,37 @@ function applyClass(el, pairs, state) {
|
|
|
328
309
|
el.classList.toggle(cls, Boolean(evalExpr(valExpr, state)));
|
|
329
310
|
}
|
|
330
311
|
}
|
|
331
|
-
function parsePairs(expr) {
|
|
332
|
-
const out = [];
|
|
333
|
-
for (const part of expr.split(",")) {
|
|
334
|
-
const colonIdx = part.indexOf(":");
|
|
335
|
-
if (colonIdx === -1) continue;
|
|
336
|
-
const left = part.slice(0, colonIdx).trim();
|
|
337
|
-
const right = part.slice(colonIdx + 1).trim();
|
|
338
|
-
if (!left) continue;
|
|
339
|
-
out.push([left, right]);
|
|
340
|
-
}
|
|
341
|
-
return out;
|
|
342
|
-
}
|
|
343
312
|
function applyModel(el, key, rawState) {
|
|
344
313
|
const html = el;
|
|
345
314
|
const stateVal = rawState[key];
|
|
346
315
|
const desired = stateVal == null ? "" : String(stateVal);
|
|
347
316
|
if (html.value !== desired) html.value = desired;
|
|
348
317
|
}
|
|
349
|
-
function
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
if: pick("data-if"),
|
|
361
|
-
show: pick("data-show"),
|
|
362
|
-
bind: pickPairs("data-bind"),
|
|
363
|
-
model: pick("data-model"),
|
|
364
|
-
class: pickPairs("data-class")
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
function applyDirectives(root, state, rawState, _instance) {
|
|
368
|
-
if (root.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
369
|
-
applyFromList(buildFragmentList(root), state, rawState);
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
const el = root;
|
|
373
|
-
if (!el.__micraCache) el.__micraCache = buildCache(el);
|
|
374
|
-
applyFromList(el.__micraCache, state, rawState);
|
|
375
|
-
}
|
|
376
|
-
function applyFromList(cache, state, rawState) {
|
|
377
|
-
cache.if.forEach((b) => applyIf(b, state));
|
|
378
|
-
cache.text.forEach((b) => applyText(b.el, b.expr, state));
|
|
379
|
-
cache.html.forEach((b) => applyHtml(b.el, b.expr, state));
|
|
380
|
-
cache.show.forEach((b) => applyShow(b.el, b.expr, state));
|
|
381
|
-
cache.bind.forEach((b) => applyBind(b.el, b.pairs, state));
|
|
382
|
-
cache.model.forEach((b) => applyModel(b.el, b.expr.trim(), rawState));
|
|
383
|
-
cache.class.forEach((b) => applyClass(b.el, b.pairs, state));
|
|
384
|
-
}
|
|
385
|
-
function buildFragmentList(frag) {
|
|
386
|
-
const pick = (attr) => queryAll(frag, `[${attr}]`).filter((el) => !el.closest("template")).map((el) => ({ el, expr: el.getAttribute(attr) }));
|
|
387
|
-
const pickPairs = (attr) => pick(attr).map((b) => ({ ...b, pairs: parsePairs(b.expr) }));
|
|
388
|
-
return {
|
|
389
|
-
text: pick("data-text"),
|
|
390
|
-
html: pick("data-html"),
|
|
391
|
-
if: pick("data-if"),
|
|
392
|
-
show: pick("data-show"),
|
|
393
|
-
bind: pickPairs("data-bind"),
|
|
394
|
-
model: pick("data-model"),
|
|
395
|
-
class: pickPairs("data-class")
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
function validateDirectives(root) {
|
|
399
|
-
var _a, _b;
|
|
400
|
-
queryOwn(root, "data-each").forEach((el) => {
|
|
318
|
+
function applyDirectives(scan, state, rawState, _instance) {
|
|
319
|
+
for (const b of scan.if) applyIf(b, state);
|
|
320
|
+
for (const b of scan.text) applyText(b.el, b.expr, state);
|
|
321
|
+
for (const b of scan.html) applyHtml(b.el, b.expr, state);
|
|
322
|
+
for (const b of scan.show) applyShow(b.el, b.expr, state);
|
|
323
|
+
for (const b of scan.bind) applyBind(b.el, b.pairs, state);
|
|
324
|
+
for (const b of scan.model) applyModel(b.el, b.expr.trim(), rawState);
|
|
325
|
+
for (const b of scan.class) applyClass(b.el, b.pairs, state);
|
|
326
|
+
}
|
|
327
|
+
function validateDirectives(scan) {
|
|
328
|
+
for (const el of scan.each) {
|
|
401
329
|
const tmpl = el;
|
|
402
330
|
if (!el.hasAttribute("data-key") && !tmpl.__micraNoKeyWarned) {
|
|
403
331
|
tmpl.__micraNoKeyWarned = true;
|
|
404
|
-
warn(
|
|
332
|
+
warn(
|
|
333
|
+
`data-each="${el.getAttribute("data-each")}" has no data-key \u2014 keyed diff disabled. Add data-key="id" for better performance.`
|
|
334
|
+
);
|
|
405
335
|
}
|
|
406
|
-
}
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
return ((_a2 = p.trim().split(":")[0]) == null ? void 0 : _a2.trim()) === "class";
|
|
414
|
-
});
|
|
415
|
-
if (hasClassBind && el.hasAttribute("data-class")) {
|
|
416
|
-
warn(`element has both data-bind="class:..." and data-class \u2014 they fight on every render. Use one.`);
|
|
336
|
+
}
|
|
337
|
+
for (const b of scan.bind) {
|
|
338
|
+
const hasClassBind = b.pairs.some((p) => p[0] === "class");
|
|
339
|
+
if (hasClassBind && b.el.hasAttribute("data-class")) {
|
|
340
|
+
warn(
|
|
341
|
+
`element has both data-bind="class:..." and data-class \u2014 they fight on every render. Use one.`
|
|
342
|
+
);
|
|
417
343
|
}
|
|
418
344
|
}
|
|
419
345
|
}
|
|
@@ -424,17 +350,13 @@ function track(instance, el, type, fn) {
|
|
|
424
350
|
el.addEventListener(type, fn);
|
|
425
351
|
((_a = instance.__micraListeners) != null ? _a : instance.__micraListeners = []).push({ el, type, fn });
|
|
426
352
|
}
|
|
427
|
-
function bindDataOn(
|
|
428
|
-
var _a
|
|
429
|
-
const isFragment = root.nodeType === 11;
|
|
430
|
-
const els = isFragment ? queryAll(root, "[data-on]") : queryOwn(root, "data-on");
|
|
431
|
-
if (!isFragment && ((_a = root.hasAttribute) == null ? void 0 : _a.call(root, "data-on")) && !els.includes(root))
|
|
432
|
-
els.unshift(root);
|
|
353
|
+
function bindDataOn(els, instance) {
|
|
354
|
+
var _a;
|
|
433
355
|
for (const el of els) {
|
|
434
356
|
const mEl = el;
|
|
435
357
|
if (mEl.__micraEvents) continue;
|
|
436
358
|
mEl.__micraEvents = true;
|
|
437
|
-
const spec = (
|
|
359
|
+
const spec = (_a = mEl.dataset["on"]) != null ? _a : "";
|
|
438
360
|
for (const part of spec.split(",")) {
|
|
439
361
|
const [evSpec, method] = part.trim().split(":");
|
|
440
362
|
if (!evSpec || !method) continue;
|
|
@@ -450,11 +372,8 @@ function bindDataOn(root, instance) {
|
|
|
450
372
|
}
|
|
451
373
|
}
|
|
452
374
|
}
|
|
453
|
-
function bindAtEvents(
|
|
454
|
-
const
|
|
455
|
-
const all = isFragment ? queryAll(root, "*") : queryOwnAll(root, "*");
|
|
456
|
-
if (!isFragment && !all.includes(root)) all.unshift(root);
|
|
457
|
-
for (const el of all) {
|
|
375
|
+
function bindAtEvents(els, instance) {
|
|
376
|
+
for (const el of els) {
|
|
458
377
|
const mEl = el;
|
|
459
378
|
if (mEl.__micraAtBound) continue;
|
|
460
379
|
let bound = false;
|
|
@@ -475,15 +394,12 @@ function bindAtEvents(root, instance) {
|
|
|
475
394
|
if (bound) mEl.__micraAtBound = true;
|
|
476
395
|
}
|
|
477
396
|
}
|
|
478
|
-
function bindModels(
|
|
479
|
-
|
|
480
|
-
const isFragment = root.nodeType === 11;
|
|
481
|
-
const els = isFragment ? queryAll(root, "[data-model]") : queryOwn(root, "data-model");
|
|
482
|
-
for (const el of els) {
|
|
397
|
+
function bindModels(bindings, instance) {
|
|
398
|
+
for (const { el, expr } of bindings) {
|
|
483
399
|
const mEl = el;
|
|
484
400
|
if (mEl.__micraModel) continue;
|
|
485
401
|
mEl.__micraModel = true;
|
|
486
|
-
const key = (
|
|
402
|
+
const key = expr.trim();
|
|
487
403
|
const tag = el.tagName;
|
|
488
404
|
const inputEl = el;
|
|
489
405
|
const inputType = inputEl.type;
|
|
@@ -504,11 +420,132 @@ function bindModels(root, instance) {
|
|
|
504
420
|
}
|
|
505
421
|
}
|
|
506
422
|
|
|
423
|
+
// src/dom/scan.ts
|
|
424
|
+
function emptyScan() {
|
|
425
|
+
return {
|
|
426
|
+
text: [],
|
|
427
|
+
html: [],
|
|
428
|
+
if: [],
|
|
429
|
+
show: [],
|
|
430
|
+
bind: [],
|
|
431
|
+
model: [],
|
|
432
|
+
class: [],
|
|
433
|
+
each: [],
|
|
434
|
+
on: [],
|
|
435
|
+
atEvents: [],
|
|
436
|
+
refs: []
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function parsePairs(expr) {
|
|
440
|
+
const out = [];
|
|
441
|
+
for (const part of expr.split(",")) {
|
|
442
|
+
const colon = part.indexOf(":");
|
|
443
|
+
if (colon === -1) continue;
|
|
444
|
+
const left = part.slice(0, colon).trim();
|
|
445
|
+
const right = part.slice(colon + 1).trim();
|
|
446
|
+
if (!left) continue;
|
|
447
|
+
out.push([left, right]);
|
|
448
|
+
}
|
|
449
|
+
return out;
|
|
450
|
+
}
|
|
451
|
+
function classify(el, scan) {
|
|
452
|
+
if (el.tagName === "TEMPLATE") {
|
|
453
|
+
if (el.hasAttribute("data-each")) scan.each.push(el);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const attrs = el.attributes;
|
|
457
|
+
let atEventSeen = false;
|
|
458
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
459
|
+
const a = attrs[i];
|
|
460
|
+
const name = a.name;
|
|
461
|
+
const first = name.charCodeAt(0);
|
|
462
|
+
if (first === 64) {
|
|
463
|
+
if (!atEventSeen) {
|
|
464
|
+
scan.atEvents.push(el);
|
|
465
|
+
atEventSeen = true;
|
|
466
|
+
}
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
if (first === 100 && name.length >= 6 && name.charCodeAt(4) === 45) {
|
|
470
|
+
const rest = name.slice(5);
|
|
471
|
+
switch (rest) {
|
|
472
|
+
case "text":
|
|
473
|
+
scan.text.push({ el, expr: a.value });
|
|
474
|
+
break;
|
|
475
|
+
case "html":
|
|
476
|
+
scan.html.push({ el, expr: a.value });
|
|
477
|
+
break;
|
|
478
|
+
case "if":
|
|
479
|
+
scan.if.push({ el, expr: a.value });
|
|
480
|
+
break;
|
|
481
|
+
case "show":
|
|
482
|
+
scan.show.push({ el, expr: a.value });
|
|
483
|
+
break;
|
|
484
|
+
case "bind": {
|
|
485
|
+
const pairs = parsePairs(a.value);
|
|
486
|
+
scan.bind.push({ el, expr: a.value, pairs });
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
case "model":
|
|
490
|
+
scan.model.push({ el, expr: a.value });
|
|
491
|
+
break;
|
|
492
|
+
case "class": {
|
|
493
|
+
const pairs = parsePairs(a.value);
|
|
494
|
+
scan.class.push({ el, expr: a.value, pairs });
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
case "on":
|
|
498
|
+
scan.on.push(el);
|
|
499
|
+
break;
|
|
500
|
+
case "ref":
|
|
501
|
+
scan.refs.push(el);
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
var NESTED_COMPONENT_FILTER = {
|
|
508
|
+
acceptNode(node) {
|
|
509
|
+
if (node.hasAttribute("data-component"))
|
|
510
|
+
return NodeFilter.FILTER_REJECT;
|
|
511
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
function scanComponent(root) {
|
|
515
|
+
const scan = emptyScan();
|
|
516
|
+
classify(root, scan);
|
|
517
|
+
const walker = document.createTreeWalker(
|
|
518
|
+
root,
|
|
519
|
+
NodeFilter.SHOW_ELEMENT,
|
|
520
|
+
NESTED_COMPONENT_FILTER
|
|
521
|
+
);
|
|
522
|
+
let node = walker.nextNode();
|
|
523
|
+
while (node) {
|
|
524
|
+
classify(node, scan);
|
|
525
|
+
node = walker.nextNode();
|
|
526
|
+
}
|
|
527
|
+
return scan;
|
|
528
|
+
}
|
|
529
|
+
function scanFragment(frag) {
|
|
530
|
+
const scan = emptyScan();
|
|
531
|
+
const walker = document.createTreeWalker(
|
|
532
|
+
frag,
|
|
533
|
+
NodeFilter.SHOW_ELEMENT,
|
|
534
|
+
NESTED_COMPONENT_FILTER
|
|
535
|
+
);
|
|
536
|
+
let node = walker.nextNode();
|
|
537
|
+
while (node) {
|
|
538
|
+
classify(node, scan);
|
|
539
|
+
node = walker.nextNode();
|
|
540
|
+
}
|
|
541
|
+
return scan;
|
|
542
|
+
}
|
|
543
|
+
|
|
507
544
|
// src/dom/each.ts
|
|
508
|
-
function renderList(
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
if (tmplEl.tagName !== "TEMPLATE")
|
|
545
|
+
function renderList(templates, state, rawState, instance) {
|
|
546
|
+
var _a;
|
|
547
|
+
for (const tmplEl of templates) {
|
|
548
|
+
if (tmplEl.tagName !== "TEMPLATE") continue;
|
|
512
549
|
const tmpl = tmplEl;
|
|
513
550
|
const itemsExpr = tmpl.getAttribute("data-each");
|
|
514
551
|
const keyAttr = (_a = tmpl.getAttribute("data-key")) != null ? _a : null;
|
|
@@ -523,21 +560,22 @@ function renderList(root, state, rawState, instance) {
|
|
|
523
560
|
const marker = tmpl.__micraMarker;
|
|
524
561
|
const keyMap = tmpl.__micraNodes;
|
|
525
562
|
const parent = marker.parentNode;
|
|
526
|
-
if (!parent)
|
|
563
|
+
if (!parent) continue;
|
|
527
564
|
if (!Array.isArray(items)) {
|
|
528
565
|
tmpl.__micraList.forEach((n) => n.remove());
|
|
529
566
|
tmpl.__micraList = [];
|
|
530
567
|
keyMap.clear();
|
|
531
|
-
|
|
568
|
+
continue;
|
|
532
569
|
}
|
|
533
570
|
if (keyAttr) {
|
|
534
571
|
renderKeyed(tmpl, items, keyAttr, marker, keyMap, parent, state, rawState, instance);
|
|
535
572
|
} else {
|
|
536
573
|
renderNoKey(tmpl, items, marker, parent, state, rawState, instance);
|
|
537
574
|
}
|
|
538
|
-
}
|
|
575
|
+
}
|
|
539
576
|
}
|
|
540
577
|
function renderKeyed(tmpl, items, keyAttr, marker, keyMap, parent, state, rawState, instance) {
|
|
578
|
+
var _a;
|
|
541
579
|
const nextKeys = /* @__PURE__ */ new Set();
|
|
542
580
|
const nextNodes = [];
|
|
543
581
|
let warnedNullKey = false;
|
|
@@ -565,14 +603,18 @@ function renderKeyed(tmpl, items, keyAttr, marker, keyMap, parent, state, rawSta
|
|
|
565
603
|
}
|
|
566
604
|
node.__micraKey = key;
|
|
567
605
|
keyMap.set(key, node);
|
|
568
|
-
|
|
569
|
-
|
|
606
|
+
const rowScan2 = scanComponent(node);
|
|
607
|
+
node.__micraScan = rowScan2;
|
|
608
|
+
bindDataOn(rowScan2.on, instance);
|
|
609
|
+
bindAtEvents(rowScan2.atEvents, instance);
|
|
610
|
+
bindModels(rowScan2.model, instance);
|
|
570
611
|
}
|
|
571
612
|
const itemState = Object.assign(
|
|
572
613
|
Object.create(state),
|
|
573
614
|
{ item, index, $index: index }
|
|
574
615
|
);
|
|
575
|
-
|
|
616
|
+
const rowScan = (_a = node.__micraScan) != null ? _a : node.__micraScan = scanComponent(node);
|
|
617
|
+
applyDirectives(rowScan, itemState, rawState, instance);
|
|
576
618
|
nextNodes.push(node);
|
|
577
619
|
}
|
|
578
620
|
for (const [key, node] of keyMap) {
|
|
@@ -598,9 +640,11 @@ function renderNoKey(tmpl, items, marker, parent, state, rawState, instance) {
|
|
|
598
640
|
Object.create(state),
|
|
599
641
|
{ item, index, $index: index }
|
|
600
642
|
);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
643
|
+
const fragScan = scanFragment(clone);
|
|
644
|
+
applyDirectives(fragScan, itemState, rawState, instance);
|
|
645
|
+
bindDataOn(fragScan.on, instance);
|
|
646
|
+
bindAtEvents(fragScan.atEvents, instance);
|
|
647
|
+
bindModels(fragScan.model, instance);
|
|
604
648
|
const nodes = Array.from(clone.childNodes);
|
|
605
649
|
nodes.forEach((n) => {
|
|
606
650
|
n.__micraEach = true;
|
|
@@ -612,9 +656,9 @@ function renderNoKey(tmpl, items, marker, parent, state, rawState, instance) {
|
|
|
612
656
|
}
|
|
613
657
|
|
|
614
658
|
// src/dom/refs.ts
|
|
615
|
-
function collectRefs(
|
|
659
|
+
function collectRefs(els, instance) {
|
|
616
660
|
instance.refs = {};
|
|
617
|
-
for (const el of
|
|
661
|
+
for (const el of els) {
|
|
618
662
|
const name = el.dataset["ref"];
|
|
619
663
|
if (name) instance.refs[name] = el;
|
|
620
664
|
}
|
|
@@ -628,10 +672,13 @@ function mount(selector, definition) {
|
|
|
628
672
|
warn(`"${selector}" not found`);
|
|
629
673
|
return null;
|
|
630
674
|
}
|
|
631
|
-
if (_instances.has(root))
|
|
675
|
+
if (_instances.has(root))
|
|
676
|
+
return _instances.get(root);
|
|
632
677
|
const rawState = { ...(_a = definition.state) != null ? _a : {} };
|
|
633
678
|
const instance = { $el: root, refs: {} };
|
|
634
|
-
for (const [key, val] of Object.entries(
|
|
679
|
+
for (const [key, val] of Object.entries(
|
|
680
|
+
definition
|
|
681
|
+
)) {
|
|
635
682
|
if (key === "state" || key === "onCreate" || key === "onDestroy") continue;
|
|
636
683
|
if (typeof val === "function") instance[key] = val;
|
|
637
684
|
}
|
|
@@ -675,22 +722,27 @@ function mount(selector, definition) {
|
|
|
675
722
|
});
|
|
676
723
|
let warnedReentry = false;
|
|
677
724
|
instance.render = function() {
|
|
725
|
+
var _a2;
|
|
678
726
|
if (instance.__micraDestroyed) return;
|
|
679
727
|
if (isRendering) {
|
|
680
728
|
if (!warnedReentry) {
|
|
681
|
-
warn(
|
|
729
|
+
warn(
|
|
730
|
+
"render() re-entry detected \u2014 mutation inside a directive expression is ignored. Move state writes to a method."
|
|
731
|
+
);
|
|
682
732
|
warnedReentry = true;
|
|
683
733
|
}
|
|
684
734
|
return;
|
|
685
735
|
}
|
|
686
736
|
isRendering = true;
|
|
687
737
|
try {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
738
|
+
const mRoot2 = root;
|
|
739
|
+
const scan = (_a2 = mRoot2.__micraScan) != null ? _a2 : mRoot2.__micraScan = scanComponent(root);
|
|
740
|
+
applyDirectives(scan, exprState, rawState, instance);
|
|
741
|
+
renderList(scan.each, exprState, rawState, instance);
|
|
742
|
+
bindDataOn(scan.on, instance);
|
|
743
|
+
bindAtEvents(scan.atEvents, instance);
|
|
744
|
+
bindModels(scan.model, instance);
|
|
745
|
+
collectRefs(scan.refs, instance);
|
|
694
746
|
} finally {
|
|
695
747
|
isRendering = false;
|
|
696
748
|
}
|
|
@@ -699,14 +751,16 @@ function mount(selector, definition) {
|
|
|
699
751
|
var _a2, _b;
|
|
700
752
|
if (instance.__micraDestroyed) return;
|
|
701
753
|
instance.__micraDestroyed = true;
|
|
702
|
-
(_a2 = instance.__micraListeners) == null ? void 0 : _a2.forEach(
|
|
754
|
+
(_a2 = instance.__micraListeners) == null ? void 0 : _a2.forEach(
|
|
755
|
+
({ el, type, fn }) => el.removeEventListener(type, fn)
|
|
756
|
+
);
|
|
703
757
|
instance.__micraListeners = [];
|
|
704
758
|
const clearFlags = (el) => {
|
|
705
759
|
const m = el;
|
|
706
760
|
delete m.__micraEvents;
|
|
707
761
|
delete m.__micraAtBound;
|
|
708
762
|
delete m.__micraModel;
|
|
709
|
-
delete m.
|
|
763
|
+
delete m.__micraScan;
|
|
710
764
|
};
|
|
711
765
|
clearFlags(root);
|
|
712
766
|
root.querySelectorAll("*").forEach(clearFlags);
|
|
@@ -718,7 +772,8 @@ function mount(selector, definition) {
|
|
|
718
772
|
};
|
|
719
773
|
_instances.set(root, instance);
|
|
720
774
|
instance.render();
|
|
721
|
-
|
|
775
|
+
const mRoot = root;
|
|
776
|
+
if (mRoot.__micraScan) validateDirectives(mRoot.__micraScan);
|
|
722
777
|
if (typeof definition.onCreate === "function")
|
|
723
778
|
Promise.resolve().then(
|
|
724
779
|
() => definition.onCreate.call(instance)
|