aberdeen 1.18.1 → 1.19.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/README.md +9 -0
- package/dist/src/aberdeen.d.ts +29 -0
- package/{dist-docs/assets/aberdeen/aberdeen.js → dist/src/aberdeen.dev.js} +796 -21
- package/dist/src/aberdeen.dev.js.map +12 -0
- package/dist/src/aberdeen.js +79 -19
- package/dist/src/aberdeen.js.map +3 -3
- package/dist/src/devtools.d.ts +26 -0
- package/dist/tests/fakedom.js +20 -3
- package/dist/tests/fakedom.js.map +3 -3
- package/dist/tests/helpers.js +20 -3
- package/dist/tests/helpers.js.map +3 -3
- package/html-to-aberdeen +9 -5
- package/package.json +17 -10
- package/skill/A.md +127 -0
- package/skill/Dispatcher.md +51 -0
- package/skill/OPAQUE.md +15 -0
- package/skill/PromiseProxy.md +25 -0
- package/skill/Route.md +50 -0
- package/skill/SKILL.md +272 -156
- package/skill/applyCanon.md +20 -0
- package/skill/applyPrediction.md +15 -0
- package/skill/back.md +11 -0
- package/skill/clean.md +43 -0
- package/skill/clone.md +15 -0
- package/skill/copy.md +40 -0
- package/skill/count.md +32 -0
- package/skill/cssVars.md +15 -0
- package/skill/darkMode.md +26 -0
- package/skill/derive.md +56 -0
- package/skill/developer-tools.md +23 -0
- package/skill/disableCreateDestroy.md +11 -0
- package/skill/dump.md +37 -0
- package/skill/freeze.md +20 -0
- package/skill/full-example-multi-page-app.md +146 -0
- package/skill/go.md +25 -0
- package/skill/grow.md +13 -0
- package/skill/html-to-aberdeen.md +9 -0
- package/skill/insertCss.md +79 -0
- package/skill/insertGlobalCss.md +68 -0
- package/skill/interceptLinks.md +19 -0
- package/skill/invertString.md +32 -0
- package/skill/isEmpty.md +38 -0
- package/skill/map.md +16 -0
- package/skill/matchCurrent.md +27 -0
- package/skill/merge.md +27 -0
- package/skill/mount.md +48 -0
- package/skill/multiMap.md +15 -0
- package/skill/onEach.md +14 -0
- package/skill/partition.md +15 -0
- package/skill/peek.md +36 -0
- package/skill/persistScroll.md +13 -0
- package/skill/proxy.md +11 -0
- package/skill/push.md +13 -0
- package/skill/ref.md +39 -0
- package/skill/runQueue.md +34 -0
- package/skill/setErrorHandler.md +48 -0
- package/skill/setLog.md +9 -0
- package/skill/setSpacingCssVars.md +31 -0
- package/skill/shrink.md +13 -0
- package/skill/unmountAll.md +9 -0
- package/skill/unproxy.md +43 -0
- package/skill/up.md +13 -0
- package/src/aberdeen.ts +220 -82
- package/src/devtools.ts +685 -0
- package/dist-docs/.nojekyll +0 -1
- package/dist-docs/Tutorial/index.html +0 -305
- package/dist-docs/aberdeen/A/index.html +0 -115
- package/dist-docs/aberdeen/CUSTOM_DUMP/index.html +0 -7
- package/dist-docs/aberdeen/NO_COPY/index.html +0 -2
- package/dist-docs/aberdeen/OPAQUE/index.html +0 -12
- package/dist-docs/aberdeen/PromiseProxy/index.html +0 -8
- package/dist-docs/aberdeen/clean/index.html +0 -11
- package/dist-docs/aberdeen/clone/index.html +0 -5
- package/dist-docs/aberdeen/copy/index.html +0 -22
- package/dist-docs/aberdeen/count/index.html +0 -7
- package/dist-docs/aberdeen/cssVars/index.html +0 -11
- package/dist-docs/aberdeen/darkMode/index.html +0 -9
- package/dist-docs/aberdeen/default/index.html +0 -341
- package/dist-docs/aberdeen/derive/index.html +0 -18
- package/dist-docs/aberdeen/disableCreateDestroy/index.html +0 -6
- package/dist-docs/aberdeen/dump/index.html +0 -11
- package/dist-docs/aberdeen/index.html +0 -54
- package/dist-docs/aberdeen/insertCss/index.html +0 -30
- package/dist-docs/aberdeen/insertGlobalCss/index.html +0 -19
- package/dist-docs/aberdeen/invertString/index.html +0 -13
- package/dist-docs/aberdeen/isEmpty/index.html +0 -12
- package/dist-docs/aberdeen/map/index.html +0 -26
- package/dist-docs/aberdeen/merge/index.html +0 -11
- package/dist-docs/aberdeen/mount/index.html +0 -17
- package/dist-docs/aberdeen/multiMap/index.html +0 -28
- package/dist-docs/aberdeen/onEach/index.html +0 -19
- package/dist-docs/aberdeen/partition/index.html +0 -36
- package/dist-docs/aberdeen/peek/index.html +0 -40
- package/dist-docs/aberdeen/proxy/index.html +0 -35
- package/dist-docs/aberdeen/ref/index.html +0 -13
- package/dist-docs/aberdeen/runQueue/index.html +0 -13
- package/dist-docs/aberdeen/setErrorHandler/index.html +0 -16
- package/dist-docs/aberdeen/setSpacingCssVars/index.html +0 -8
- package/dist-docs/aberdeen/unmountAll/index.html +0 -5
- package/dist-docs/aberdeen/unproxy/index.html +0 -11
- package/dist-docs/assets/aberdeen/aberdeen.d.ts +0 -961
- package/dist-docs/assets/aberdeen/aberdeen.js.map +0 -11
- package/dist-docs/assets/aberdeen/dispatcher.d.ts +0 -57
- package/dist-docs/assets/aberdeen/dispatcher.js +0 -66
- package/dist-docs/assets/aberdeen/dispatcher.js.map +0 -10
- package/dist-docs/assets/aberdeen/helpers/reverseSortedSet.d.ts +0 -96
- package/dist-docs/assets/aberdeen/prediction.d.ts +0 -33
- package/dist-docs/assets/aberdeen/prediction.js +0 -112
- package/dist-docs/assets/aberdeen/prediction.js.map +0 -10
- package/dist-docs/assets/aberdeen/route.d.ts +0 -137
- package/dist-docs/assets/aberdeen/route.js +0 -287
- package/dist-docs/assets/aberdeen/route.js.map +0 -10
- package/dist-docs/assets/aberdeen/transitions.d.ts +0 -18
- package/dist-docs/assets/aberdeen/transitions.js +0 -47
- package/dist-docs/assets/aberdeen/transitions.js.map +0 -10
- package/dist-docs/assets/custom.js +0 -573
- package/dist-docs/assets/favicon.png +0 -0
- package/dist-docs/assets/hierarchy.js +0 -1
- package/dist-docs/assets/highlight.css +0 -134
- package/dist-docs/assets/icons.js +0 -18
- package/dist-docs/assets/icons.svg +0 -1
- package/dist-docs/assets/main.js +0 -60
- package/dist-docs/assets/navigation.js +0 -1
- package/dist-docs/assets/search.js +0 -1
- package/dist-docs/assets/style.css +0 -1640
- package/dist-docs/dispatcher/Dispatcher/index.html +0 -21
- package/dist-docs/dispatcher/MATCH_FAILED/index.html +0 -2
- package/dist-docs/dispatcher/MATCH_REST/index.html +0 -2
- package/dist-docs/dispatcher/index.html +0 -4
- package/dist-docs/hierarchy.html +0 -1
- package/dist-docs/index.html +0 -61
- package/dist-docs/media/CHANGELOG.md +0 -260
- package/dist-docs/modules.html +0 -1
- package/dist-docs/prediction/applyCanon/index.html +0 -13
- package/dist-docs/prediction/applyPrediction/index.html +0 -8
- package/dist-docs/prediction/index.html +0 -9
- package/dist-docs/route/Route/index.html +0 -23
- package/dist-docs/route/back/index.html +0 -4
- package/dist-docs/route/current/index.html +0 -2
- package/dist-docs/route/go/index.html +0 -14
- package/dist-docs/route/index.html +0 -15
- package/dist-docs/route/interceptLinks/index.html +0 -8
- package/dist-docs/route/matchCurrent/index.html +0 -10
- package/dist-docs/route/persistScroll/index.html +0 -6
- package/dist-docs/route/push/index.html +0 -6
- package/dist-docs/route/setLog/index.html +0 -3
- package/dist-docs/route/up/index.html +0 -5
- package/dist-docs/sitemap.xml +0 -239
- package/dist-docs/transitions/grow/index.html +0 -6
- package/dist-docs/transitions/index.html +0 -5
- package/dist-docs/transitions/shrink/index.html +0 -6
- package/skill/aberdeen.md +0 -4584
- package/skill/dispatcher.md +0 -129
- package/skill/prediction.md +0 -73
- package/skill/route.md +0 -322
- package/skill/transitions.md +0 -59
|
@@ -101,6 +101,7 @@ class ReverseSortedSet {
|
|
|
101
101
|
// src/aberdeen.ts
|
|
102
102
|
var sortedQueue;
|
|
103
103
|
var runQueueDepth = 0;
|
|
104
|
+
var freezeCount = 0;
|
|
104
105
|
var topRedrawScope;
|
|
105
106
|
var survivingEl;
|
|
106
107
|
function recordSideEffect(scope, type, key, value) {
|
|
@@ -115,7 +116,10 @@ function undoSideEffects(el, se) {
|
|
|
115
116
|
value ? el.classList.add(key) : el.classList.remove(key);
|
|
116
117
|
break;
|
|
117
118
|
case 1 /* Style */:
|
|
118
|
-
|
|
119
|
+
if (key[0] === "-" && key[1] === "-")
|
|
120
|
+
value ? el.style.setProperty(key, value) : el.style.removeProperty(key);
|
|
121
|
+
else
|
|
122
|
+
el.style[key] = value == null ? "" : value;
|
|
119
123
|
break;
|
|
120
124
|
case 2 /* Prop */:
|
|
121
125
|
el[key] = value;
|
|
@@ -142,6 +146,8 @@ function queue(runner) {
|
|
|
142
146
|
sortedQueue.add(runner);
|
|
143
147
|
}
|
|
144
148
|
function runQueue() {
|
|
149
|
+
if (freezeCount)
|
|
150
|
+
return;
|
|
145
151
|
let time = Date.now();
|
|
146
152
|
while (sortedQueue) {
|
|
147
153
|
const runner = sortedQueue.fetchLast();
|
|
@@ -157,6 +163,17 @@ function runQueue() {
|
|
|
157
163
|
if (time > 9)
|
|
158
164
|
console.debug(`Aberdeen queue took ${time}ms`);
|
|
159
165
|
}
|
|
166
|
+
function freeze() {
|
|
167
|
+
freezeCount++;
|
|
168
|
+
let released = false;
|
|
169
|
+
return () => {
|
|
170
|
+
if (released)
|
|
171
|
+
return;
|
|
172
|
+
released = true;
|
|
173
|
+
if (!--freezeCount)
|
|
174
|
+
runQueue();
|
|
175
|
+
};
|
|
176
|
+
}
|
|
160
177
|
function arrayToStr(parts) {
|
|
161
178
|
let result = "";
|
|
162
179
|
for (const part of parts) {
|
|
@@ -245,6 +262,7 @@ class ContentScope extends Scope {
|
|
|
245
262
|
if (!this.changes) {
|
|
246
263
|
this.changes = new Map;
|
|
247
264
|
queue(this);
|
|
265
|
+
dev?.schedule(this, index, oldData, newData, new Error);
|
|
248
266
|
}
|
|
249
267
|
let targetDelta = this.changes.get(target);
|
|
250
268
|
if (!targetDelta) {
|
|
@@ -302,6 +320,7 @@ class ChainedScope extends ContentScope {
|
|
|
302
320
|
}
|
|
303
321
|
if (!useParentCleaners)
|
|
304
322
|
currentScope.cleaners.push(this);
|
|
323
|
+
dev?.create(this, currentScope, new Error);
|
|
305
324
|
}
|
|
306
325
|
getPrecedingNode() {
|
|
307
326
|
return findLastNodeInPrevSiblings(this.prevSibling);
|
|
@@ -321,6 +340,7 @@ class RegularScope extends ChainedScope {
|
|
|
321
340
|
redraw() {
|
|
322
341
|
const savedScope = currentScope;
|
|
323
342
|
currentScope = this;
|
|
343
|
+
dev?.render(this);
|
|
324
344
|
try {
|
|
325
345
|
this.renderer();
|
|
326
346
|
} catch (e) {
|
|
@@ -347,6 +367,7 @@ class MountScope extends ContentScope {
|
|
|
347
367
|
this.el = el;
|
|
348
368
|
this.renderer = renderer;
|
|
349
369
|
this.svg = el.namespaceURI === "http://www.w3.org/2000/svg";
|
|
370
|
+
dev?.create(this, currentScope, new Error);
|
|
350
371
|
const oldTopRedrawScope = topRedrawScope;
|
|
351
372
|
topRedrawScope = this;
|
|
352
373
|
this.redraw();
|
|
@@ -451,6 +472,7 @@ class OnEachScope extends Scope {
|
|
|
451
472
|
this.prevSibling = currentScope.getChildPrevSibling();
|
|
452
473
|
currentScope.lastChild = this;
|
|
453
474
|
currentScope.cleaners.push(this);
|
|
475
|
+
dev?.create(this, currentScope, new Error);
|
|
454
476
|
if (target instanceof Array) {
|
|
455
477
|
for (let i = 0;i < target.length; i++) {
|
|
456
478
|
new OnEachItemScope(this, i, false);
|
|
@@ -481,8 +503,10 @@ class OnEachScope extends Scope {
|
|
|
481
503
|
this.changedIndexes = new Map;
|
|
482
504
|
for (const index of indexes.keys()) {
|
|
483
505
|
const oldScope = this.byIndex.get(index);
|
|
484
|
-
if (oldScope)
|
|
506
|
+
if (oldScope) {
|
|
485
507
|
oldScope.remove();
|
|
508
|
+
dev?.delete(oldScope);
|
|
509
|
+
}
|
|
486
510
|
if (this.target instanceof Set || this.target instanceof Map ? this.target.has(index) : (index in this.target)) {
|
|
487
511
|
new OnEachItemScope(this, index, true);
|
|
488
512
|
} else {
|
|
@@ -524,6 +548,7 @@ class OnEachItemScope extends ContentScope {
|
|
|
524
548
|
this.svg = currentScope.svg;
|
|
525
549
|
this.parent.byIndex.set(this.itemIndex, this);
|
|
526
550
|
this.lastChild = this;
|
|
551
|
+
dev?.create(this, this.parent, new Error);
|
|
527
552
|
if (topRedraw)
|
|
528
553
|
topRedrawScope = this;
|
|
529
554
|
this.redraw();
|
|
@@ -582,6 +607,7 @@ class OnEachItemScope extends ContentScope {
|
|
|
582
607
|
}
|
|
583
608
|
const savedScope = currentScope;
|
|
584
609
|
currentScope = this;
|
|
610
|
+
dev?.render(this);
|
|
585
611
|
let sortKey;
|
|
586
612
|
try {
|
|
587
613
|
if (this.parent.makeSortKey) {
|
|
@@ -626,15 +652,31 @@ class OnEachItemScope extends ContentScope {
|
|
|
626
652
|
function addNode(el, node) {
|
|
627
653
|
if (el !== currentScope.el) {
|
|
628
654
|
el.appendChild(node);
|
|
655
|
+
dev?.node(currentScope, node, false);
|
|
629
656
|
return;
|
|
630
657
|
}
|
|
631
658
|
const parentEl = currentScope.el;
|
|
632
659
|
const prevNode = currentScope.getInsertAfterNode();
|
|
633
660
|
parentEl.insertBefore(node, prevNode ? prevNode.nextSibling : parentEl.firstChild);
|
|
634
661
|
currentScope.lastChild = node;
|
|
662
|
+
dev?.node(currentScope, node, true);
|
|
635
663
|
}
|
|
636
664
|
var ROOT_SCOPE = new RootScope;
|
|
637
665
|
var currentScope = ROOT_SCOPE;
|
|
666
|
+
var dev;
|
|
667
|
+
function _setDev(hooks) {
|
|
668
|
+
dev = hooks;
|
|
669
|
+
if (!hooks)
|
|
670
|
+
return;
|
|
671
|
+
const childScopes = (scope) => scope instanceof OnEachScope ? [...scope.byIndex.values()] : scope.cleaners.filter((c) => c instanceof Scope);
|
|
672
|
+
const replay = (scope, parent) => {
|
|
673
|
+
hooks.create(scope, parent, undefined);
|
|
674
|
+
for (const child of childScopes(scope))
|
|
675
|
+
replay(child, scope);
|
|
676
|
+
};
|
|
677
|
+
for (const child of childScopes(ROOT_SCOPE))
|
|
678
|
+
replay(child, ROOT_SCOPE);
|
|
679
|
+
}
|
|
638
680
|
function leakScope(func) {
|
|
639
681
|
const savedScope = currentScope;
|
|
640
682
|
currentScope = new RootScope;
|
|
@@ -652,6 +694,8 @@ var peeking = 0;
|
|
|
652
694
|
function subscribe(target, index, observer = currentScope) {
|
|
653
695
|
if (observer === ROOT_SCOPE || peeking)
|
|
654
696
|
return;
|
|
697
|
+
if (observer === currentScope)
|
|
698
|
+
dev?.read(currentScope, target, index);
|
|
655
699
|
let byTarget = subscribers.get(target);
|
|
656
700
|
if (!byTarget)
|
|
657
701
|
subscribers.set(target, byTarget = new Map);
|
|
@@ -1250,7 +1294,7 @@ function setSpacingCssVars(base = 1, unit = "rem") {
|
|
|
1250
1294
|
cssVars[i] = 2 ** (i - 3) * base + unit;
|
|
1251
1295
|
}
|
|
1252
1296
|
}
|
|
1253
|
-
var CSS_VAR_PATTERN = /(\burl\([^)]*\))|("[^"]*")|(^|
|
|
1297
|
+
var CSS_VAR_PATTERN = /(\burl\([^)]*\))|("[^"]*")|(^|[\s(,])\$([\w-]+)/g;
|
|
1254
1298
|
var DIGIT_FIRST = /^\d/;
|
|
1255
1299
|
function cssVarRef(value) {
|
|
1256
1300
|
if (value.indexOf("$") < 0)
|
|
@@ -1557,12 +1601,22 @@ function insertCss(style) {
|
|
|
1557
1601
|
const prefix = `.AbdStl${++cssCount}`;
|
|
1558
1602
|
const css = typeof style === "string" ? styleStringToCss(style, prefix) : objectToCss(style, prefix);
|
|
1559
1603
|
if (css) {
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1604
|
+
const cnt = cssSnippetCount++;
|
|
1605
|
+
const key = arrayToStr([currentScope.prio, cnt]);
|
|
1606
|
+
cssSnippets[key] = css;
|
|
1607
|
+
clean(() => delete cssSnippets[key]);
|
|
1563
1608
|
}
|
|
1564
1609
|
return prefix;
|
|
1565
1610
|
}
|
|
1611
|
+
function insertGlobalCss(style) {
|
|
1612
|
+
const css = objectToCss(style, "");
|
|
1613
|
+
if (css) {
|
|
1614
|
+
const cnt = cssSnippetCount++;
|
|
1615
|
+
const key = arrayToStr([currentScope.prio, cnt]);
|
|
1616
|
+
cssSnippets[key] = css;
|
|
1617
|
+
clean(() => delete cssSnippets[key]);
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1566
1620
|
var cssSnippets = proxy({});
|
|
1567
1621
|
var cssSnippetCount = 0;
|
|
1568
1622
|
function combinePrefixSelector(prefix, key) {
|
|
@@ -1634,14 +1688,6 @@ function styleStringToCss(styleStr, selector) {
|
|
|
1634
1688
|
return props ? `${selector}{${props}}
|
|
1635
1689
|
` : "";
|
|
1636
1690
|
}
|
|
1637
|
-
function insertGlobalCss(style) {
|
|
1638
|
-
const css = objectToCss(style, "");
|
|
1639
|
-
if (css) {
|
|
1640
|
-
let cnt = cssSnippetCount++;
|
|
1641
|
-
cssSnippets[cnt] = css;
|
|
1642
|
-
clean(() => delete cssSnippets[cnt]);
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
1691
|
var CSS_SHORT = {
|
|
1646
1692
|
m: "margin",
|
|
1647
1693
|
mt: "margin-top",
|
|
@@ -1687,16 +1733,27 @@ function applyArg(el, key, value) {
|
|
|
1687
1733
|
list.remove(...classes);
|
|
1688
1734
|
} else if (key[0] === "$") {
|
|
1689
1735
|
key = key.substring(1);
|
|
1736
|
+
if (key[0] === "$")
|
|
1737
|
+
key = "--" + key.substring(1);
|
|
1690
1738
|
const val = value == null || value === false ? "" : typeof value === "string" ? cssVarRef(value) : String(value);
|
|
1691
1739
|
const expanded = CSS_SHORT[key] || key;
|
|
1692
1740
|
const style = el.style;
|
|
1693
1741
|
const setOwn = el === currentScope.el;
|
|
1694
1742
|
const props = typeof expanded === "string" ? [expanded] : expanded;
|
|
1695
1743
|
for (const prop of props) {
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1744
|
+
if (prop[0] === "-" && prop[1] === "-") {
|
|
1745
|
+
if (setOwn)
|
|
1746
|
+
recordSideEffect(currentScope, 1 /* Style */, prop, style.getPropertyValue(prop));
|
|
1747
|
+
if (val === "")
|
|
1748
|
+
style.removeProperty(prop);
|
|
1749
|
+
else
|
|
1750
|
+
style.setProperty(prop, val);
|
|
1751
|
+
} else {
|
|
1752
|
+
const cm = toCamel(prop);
|
|
1753
|
+
if (setOwn)
|
|
1754
|
+
recordSideEffect(currentScope, 1 /* Style */, cm, style[cm]);
|
|
1755
|
+
style[cm] = val;
|
|
1756
|
+
}
|
|
1700
1757
|
}
|
|
1701
1758
|
} else if (value == null) {} else if (key in SPECIAL_PROPS) {
|
|
1702
1759
|
SPECIAL_PROPS[key](el, value);
|
|
@@ -1924,6 +1981,7 @@ var aberdeen_default = Object.assign(A, {
|
|
|
1924
1981
|
derive,
|
|
1925
1982
|
disableCreateDestroy,
|
|
1926
1983
|
dump,
|
|
1984
|
+
freeze,
|
|
1927
1985
|
insertCss,
|
|
1928
1986
|
insertGlobalCss,
|
|
1929
1987
|
invertString,
|
|
@@ -1945,6 +2003,721 @@ var aberdeen_default = Object.assign(A, {
|
|
|
1945
2003
|
unmountAll,
|
|
1946
2004
|
unproxy
|
|
1947
2005
|
});
|
|
2006
|
+
|
|
2007
|
+
// src/devtools.ts
|
|
2008
|
+
var devtools_default = aberdeen_default;
|
|
2009
|
+
var tool;
|
|
2010
|
+
function activate() {
|
|
2011
|
+
if (tool)
|
|
2012
|
+
return;
|
|
2013
|
+
try {
|
|
2014
|
+
Error.stackTraceLimit = 50;
|
|
2015
|
+
} catch {}
|
|
2016
|
+
const t = new DevTools;
|
|
2017
|
+
tool = t;
|
|
2018
|
+
_setDev(t);
|
|
2019
|
+
}
|
|
2020
|
+
var TYPES = {
|
|
2021
|
+
RegularScope: { label: "scope", color: "#34d399" },
|
|
2022
|
+
MountScope: { label: "mount", color: "#60a5fa" },
|
|
2023
|
+
OnEachScope: { label: "onEach", color: "#c084fc" },
|
|
2024
|
+
OnEachItemScope: { label: "item", color: "#f472b6" },
|
|
2025
|
+
ResultScope: { label: "derive", color: "#fbbf24" },
|
|
2026
|
+
SetArgScope: { label: "attr", color: "#94a3b8" },
|
|
2027
|
+
RootScope: { label: "root", color: "#64748b" }
|
|
2028
|
+
};
|
|
2029
|
+
var typeInfo = (t) => TYPES[t] || { label: t, color: "#cbd5e1" };
|
|
2030
|
+
var STYLE = `
|
|
2031
|
+
/* Whole overlay tree is click-through (pointer-events inherits); only the dialog opts in. */
|
|
2032
|
+
:host { all: initial; position: fixed; top: 0; left: 0; pointer-events: none; }
|
|
2033
|
+
* { box-sizing: border-box; font-family: ui-monospace, monospace; }
|
|
2034
|
+
|
|
2035
|
+
.box { position: fixed; pointer-events: none; border-radius: 2px; z-index: 2147483000; }
|
|
2036
|
+
.box.parent { border: 2px dotted #f59e0b; background: rgba(245,158,11,.06); }
|
|
2037
|
+
.box.child { border: 2px solid #34d399; background: rgba(52,211,153,.10); }
|
|
2038
|
+
|
|
2039
|
+
.dlg {
|
|
2040
|
+
position: fixed; left: 16px; top: 16px; width: 660px; max-width: 95vw; height: 480px; max-height: 90vh;
|
|
2041
|
+
background: #1e1b2e; color: #ede9fe; border: 1px solid #6d28d9; border-radius: 8px;
|
|
2042
|
+
box-shadow: 0 10px 36px rgba(0,0,0,.6); display: flex; flex-direction: column;
|
|
2043
|
+
font-size: 12px; pointer-events: auto; z-index: 2147483600; /* above the highlight boxes */
|
|
2044
|
+
}
|
|
2045
|
+
.hd { display: flex; align-items: center; justify-content: space-between; gap: 10px;
|
|
2046
|
+
padding: 6px 6px 6px 12px; border-bottom: 1px solid #4c1d95; cursor: move; user-select: none; }
|
|
2047
|
+
.hd .title { font-weight: bold; color: #c4b5fd; }
|
|
2048
|
+
.hd .x { cursor: pointer; color: #c4b5fd; padding: 2px 8px; border-radius: 4px; }
|
|
2049
|
+
.hd .x:hover { background: #6d28d9; color: #fff; }
|
|
2050
|
+
.cols { display: flex; flex: 1; min-height: 0; }
|
|
2051
|
+
.left { width: 56%; display: flex; flex-direction: column; min-width: 0; border-right: 1px solid #4c1d95; }
|
|
2052
|
+
.right { width: 44%; overflow: auto; padding: 8px 10px; }
|
|
2053
|
+
|
|
2054
|
+
.menu { display: flex; flex-wrap: wrap; gap: 6px; padding: 6px 8px; border-bottom: 1px solid #2e2a40; }
|
|
2055
|
+
.menu button { font: inherit; background: #2e2a40; color: #ddd6fe; border: 1px solid #4c1d95;
|
|
2056
|
+
border-radius: 5px; padding: 3px 8px; cursor: pointer; }
|
|
2057
|
+
.menu button:hover { background: #6d28d9; }
|
|
2058
|
+
.menu button.on { background: #6d28d9; color: #fff; }
|
|
2059
|
+
|
|
2060
|
+
.tree { flex: 1; overflow: auto; padding: 4px 0; }
|
|
2061
|
+
.node { white-space: nowrap; display: flex; align-items: center; gap: 6px; padding: 1px 8px; cursor: pointer; }
|
|
2062
|
+
.node:hover { background: #312a4a; }
|
|
2063
|
+
.node.sel { background: #4c1d95; }
|
|
2064
|
+
.node .tw { width: 12px; color: #94a3b8; text-align: center; flex: none; }
|
|
2065
|
+
.badge { flex: none; font-size: 10px; padding: 0 5px; border-radius: 3px; color: #0b0a12; font-weight: bold; }
|
|
2066
|
+
.node .loc { color: #e2e8f0; overflow: hidden; text-overflow: ellipsis; }
|
|
2067
|
+
.node .t { color: #8b82a8; flex: none; }
|
|
2068
|
+
|
|
2069
|
+
.right h4 { margin: 0 0 6px; color: #c4b5fd; font-size: 12px; }
|
|
2070
|
+
.right .row { margin-bottom: 3px; }
|
|
2071
|
+
.right .k { color: #94a3b8; }
|
|
2072
|
+
.sec { color: #a78bfa; font-weight: bold; font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
|
|
2073
|
+
margin: 12px 0 5px; border-bottom: 1px solid #3a3450; padding-bottom: 3px; }
|
|
2074
|
+
.loclink { color: #93c5fd; cursor: pointer; text-decoration: underline dotted; }
|
|
2075
|
+
.loclink:hover { color: #c4d9ff; }
|
|
2076
|
+
.logbtn { font: inherit; font-size: 10px; background: #2e2a40; color: #ddd6fe; border: 1px solid #4c1d95;
|
|
2077
|
+
border-radius: 4px; padding: 0 6px; cursor: pointer; }
|
|
2078
|
+
.logbtn:hover { background: #6d28d9; }
|
|
2079
|
+
.stack { white-space: pre-wrap; color: #cbd5e1; font-size: 11px; line-height: 1.5; margin-top: 2px;
|
|
2080
|
+
border-left: 2px solid #3a3450; padding-left: 6px; }
|
|
2081
|
+
.muted { color: #64748b; }
|
|
2082
|
+
.reads .key { color: #fbbf24; } .reads .val { color: #93c5fd; }
|
|
2083
|
+
.empty { color: #64748b; padding: 16px; text-align: center; white-space: pre-line; line-height: 1.5; }
|
|
2084
|
+
`;
|
|
2085
|
+
var lastPos;
|
|
2086
|
+
|
|
2087
|
+
class DevTools {
|
|
2088
|
+
root = { id: 0, scope: null, type: "RootScope", parent: undefined, children: [], createdTime: 0, renderCount: 0, topNodes: [] };
|
|
2089
|
+
scopeMap = new WeakMap;
|
|
2090
|
+
pending = new WeakMap;
|
|
2091
|
+
nodeMap = new WeakMap;
|
|
2092
|
+
elOwner = new WeakMap;
|
|
2093
|
+
origin = -1;
|
|
2094
|
+
nextId = 1;
|
|
2095
|
+
host = document.createElement("div");
|
|
2096
|
+
shadow;
|
|
2097
|
+
overlay;
|
|
2098
|
+
dlg;
|
|
2099
|
+
treeEl;
|
|
2100
|
+
rightEl;
|
|
2101
|
+
menuEl;
|
|
2102
|
+
mode = "tree";
|
|
2103
|
+
selectedId;
|
|
2104
|
+
collapsed = new Set;
|
|
2105
|
+
recentSince = 0;
|
|
2106
|
+
boxes = [];
|
|
2107
|
+
thaw;
|
|
2108
|
+
altPressed = false;
|
|
2109
|
+
rebuildScheduled = false;
|
|
2110
|
+
lastX = -1;
|
|
2111
|
+
lastY = -1;
|
|
2112
|
+
constructor() {
|
|
2113
|
+
this.shadow = this.host.attachShadow({ mode: "open" });
|
|
2114
|
+
const style = document.createElement("style");
|
|
2115
|
+
style.textContent = STYLE;
|
|
2116
|
+
this.shadow.appendChild(style);
|
|
2117
|
+
this.overlay = eln("div");
|
|
2118
|
+
this.shadow.appendChild(this.overlay);
|
|
2119
|
+
this.buildDialog();
|
|
2120
|
+
document.body.appendChild(this.host);
|
|
2121
|
+
this.positionDialog();
|
|
2122
|
+
this.renderEmptyDetails();
|
|
2123
|
+
window.addEventListener("keydown", this.onKeyDown, true);
|
|
2124
|
+
window.addEventListener("keyup", this.onKeyUp, true);
|
|
2125
|
+
window.addEventListener("blur", this.onBlur, true);
|
|
2126
|
+
window.addEventListener("pointermove", this.onPointerMove, true);
|
|
2127
|
+
window.addEventListener("scroll", this.reposition, true);
|
|
2128
|
+
window.addEventListener("resize", this.reposition, true);
|
|
2129
|
+
}
|
|
2130
|
+
destroy() {
|
|
2131
|
+
this.savePos();
|
|
2132
|
+
window.removeEventListener("keydown", this.onKeyDown, true);
|
|
2133
|
+
window.removeEventListener("keyup", this.onKeyUp, true);
|
|
2134
|
+
window.removeEventListener("blur", this.onBlur, true);
|
|
2135
|
+
window.removeEventListener("pointermove", this.onPointerMove, true);
|
|
2136
|
+
window.removeEventListener("scroll", this.reposition, true);
|
|
2137
|
+
window.removeEventListener("resize", this.reposition, true);
|
|
2138
|
+
this.clearBoxes();
|
|
2139
|
+
if (this.thaw)
|
|
2140
|
+
this.thaw();
|
|
2141
|
+
this.host.remove();
|
|
2142
|
+
tool = undefined;
|
|
2143
|
+
_setDev(undefined);
|
|
2144
|
+
}
|
|
2145
|
+
stamp() {
|
|
2146
|
+
const now = performance.now();
|
|
2147
|
+
if (this.origin < 0)
|
|
2148
|
+
this.origin = now;
|
|
2149
|
+
return now - this.origin;
|
|
2150
|
+
}
|
|
2151
|
+
create(scope, parentScope, err) {
|
|
2152
|
+
const parent = this.scopeMap.get(parentScope) || this.root;
|
|
2153
|
+
const d = {
|
|
2154
|
+
id: ++this.nextId,
|
|
2155
|
+
scope,
|
|
2156
|
+
type: scope.constructor.name,
|
|
2157
|
+
parent,
|
|
2158
|
+
children: [],
|
|
2159
|
+
el: scope.el instanceof Element ? scope.el : undefined,
|
|
2160
|
+
createdTime: err ? this.stamp() : undefined,
|
|
2161
|
+
createError: err,
|
|
2162
|
+
renderCount: 0,
|
|
2163
|
+
topNodes: []
|
|
2164
|
+
};
|
|
2165
|
+
this.scopeMap.set(scope, d);
|
|
2166
|
+
parent.children.push(d);
|
|
2167
|
+
if (d.el)
|
|
2168
|
+
this.elOwner.set(d.el, d);
|
|
2169
|
+
this.scheduleRebuild();
|
|
2170
|
+
}
|
|
2171
|
+
render(scope) {
|
|
2172
|
+
const d = this.scopeMap.get(scope);
|
|
2173
|
+
if (!d)
|
|
2174
|
+
return;
|
|
2175
|
+
d.children.length = 0;
|
|
2176
|
+
d.topNodes = [];
|
|
2177
|
+
d.subs = [];
|
|
2178
|
+
const p = this.pending.get(scope);
|
|
2179
|
+
if (p) {
|
|
2180
|
+
d.renderTime = this.stamp();
|
|
2181
|
+
d.renderCount++;
|
|
2182
|
+
d.renderError = p.error;
|
|
2183
|
+
d.renderChange = p.change;
|
|
2184
|
+
this.pending.delete(scope);
|
|
2185
|
+
}
|
|
2186
|
+
this.scheduleRebuild();
|
|
2187
|
+
}
|
|
2188
|
+
schedule(scope, index, oldData, newData, err) {
|
|
2189
|
+
this.pending.set(scope, { change: { index, oldData, newData }, error: err });
|
|
2190
|
+
}
|
|
2191
|
+
node(scope, node, top) {
|
|
2192
|
+
const d = this.scopeMap.get(scope);
|
|
2193
|
+
if (!d)
|
|
2194
|
+
return;
|
|
2195
|
+
this.nodeMap.set(node, d);
|
|
2196
|
+
if (top)
|
|
2197
|
+
d.topNodes.push(node);
|
|
2198
|
+
}
|
|
2199
|
+
read(scope, target, index) {
|
|
2200
|
+
const d = this.scopeMap.get(scope);
|
|
2201
|
+
if (d) {
|
|
2202
|
+
d.subs ||= [];
|
|
2203
|
+
if (d.subs.length < 500)
|
|
2204
|
+
d.subs.push([target, index]);
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
delete(scope) {
|
|
2208
|
+
const d = this.scopeMap.get(scope);
|
|
2209
|
+
if (!d)
|
|
2210
|
+
return;
|
|
2211
|
+
if (d.parent) {
|
|
2212
|
+
const i = d.parent.children.indexOf(d);
|
|
2213
|
+
if (i >= 0)
|
|
2214
|
+
d.parent.children.splice(i, 1);
|
|
2215
|
+
}
|
|
2216
|
+
this.scopeMap.delete(scope);
|
|
2217
|
+
this.scheduleRebuild();
|
|
2218
|
+
}
|
|
2219
|
+
buildDialog() {
|
|
2220
|
+
this.dlg = eln("div", "dlg");
|
|
2221
|
+
const hd = eln("div", "hd");
|
|
2222
|
+
hd.appendChild(eln("div", "title", "Aberdeen dev tools"));
|
|
2223
|
+
const x = eln("div", "x", "✕");
|
|
2224
|
+
x.addEventListener("click", () => this.destroy());
|
|
2225
|
+
hd.appendChild(x);
|
|
2226
|
+
this.dlg.appendChild(hd);
|
|
2227
|
+
this.setupDrag(hd);
|
|
2228
|
+
const cols = eln("div", "cols");
|
|
2229
|
+
const left = eln("div", "left");
|
|
2230
|
+
this.menuEl = eln("div", "menu");
|
|
2231
|
+
this.treeEl = eln("div", "tree");
|
|
2232
|
+
left.appendChild(this.menuEl);
|
|
2233
|
+
left.appendChild(this.treeEl);
|
|
2234
|
+
this.rightEl = eln("div", "right");
|
|
2235
|
+
cols.appendChild(left);
|
|
2236
|
+
cols.appendChild(this.rightEl);
|
|
2237
|
+
this.dlg.appendChild(cols);
|
|
2238
|
+
this.shadow.appendChild(this.dlg);
|
|
2239
|
+
this.buildMenu();
|
|
2240
|
+
}
|
|
2241
|
+
positionDialog() {
|
|
2242
|
+
const m = 16;
|
|
2243
|
+
const w = this.dlg.offsetWidth, h = this.dlg.offsetHeight;
|
|
2244
|
+
const left = lastPos ? lastPos.left : Math.max(m, window.innerWidth - w - m);
|
|
2245
|
+
const top = lastPos ? lastPos.top : Math.max(m, window.innerHeight - h - m);
|
|
2246
|
+
this.dlg.style.left = left + "px";
|
|
2247
|
+
this.dlg.style.top = top + "px";
|
|
2248
|
+
}
|
|
2249
|
+
savePos() {
|
|
2250
|
+
lastPos = { left: this.dlg.offsetLeft, top: this.dlg.offsetTop };
|
|
2251
|
+
}
|
|
2252
|
+
buildMenu() {
|
|
2253
|
+
this.menuEl.textContent = "";
|
|
2254
|
+
const btn = (label, on, fn) => {
|
|
2255
|
+
const b = eln("button", on ? "on" : undefined, label);
|
|
2256
|
+
b.addEventListener("click", () => {
|
|
2257
|
+
fn();
|
|
2258
|
+
this.buildMenu();
|
|
2259
|
+
});
|
|
2260
|
+
this.menuEl.appendChild(b);
|
|
2261
|
+
};
|
|
2262
|
+
btn("Tree", this.mode === "tree", () => {
|
|
2263
|
+
this.mode = "tree";
|
|
2264
|
+
this.rebuild();
|
|
2265
|
+
});
|
|
2266
|
+
btn("Recent", this.mode === "recent", () => {
|
|
2267
|
+
this.mode = "recent";
|
|
2268
|
+
this.rebuild();
|
|
2269
|
+
});
|
|
2270
|
+
btn("Freeze", !!this.thaw, () => {
|
|
2271
|
+
if (this.thaw) {
|
|
2272
|
+
this.thaw();
|
|
2273
|
+
this.thaw = undefined;
|
|
2274
|
+
} else
|
|
2275
|
+
this.thaw = aberdeen_default.freeze();
|
|
2276
|
+
});
|
|
2277
|
+
if (this.mode === "recent")
|
|
2278
|
+
btn("Clear", false, () => {
|
|
2279
|
+
this.recentSince = this.lastEventTime();
|
|
2280
|
+
this.rebuild();
|
|
2281
|
+
});
|
|
2282
|
+
this.menuEl.appendChild(eln("span", "muted", " Alt-hover an element to select its scope"));
|
|
2283
|
+
}
|
|
2284
|
+
lastEventTime() {
|
|
2285
|
+
let max = 0;
|
|
2286
|
+
const walk = (d) => {
|
|
2287
|
+
if (d.renderTime != null && d.renderTime > max)
|
|
2288
|
+
max = d.renderTime;
|
|
2289
|
+
d.children.forEach(walk);
|
|
2290
|
+
};
|
|
2291
|
+
this.root.children.forEach(walk);
|
|
2292
|
+
return max;
|
|
2293
|
+
}
|
|
2294
|
+
scheduleRebuild() {
|
|
2295
|
+
if (this.rebuildScheduled)
|
|
2296
|
+
return;
|
|
2297
|
+
this.rebuildScheduled = true;
|
|
2298
|
+
requestAnimationFrame(() => {
|
|
2299
|
+
this.rebuildScheduled = false;
|
|
2300
|
+
this.rebuild();
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
rebuild() {
|
|
2304
|
+
const scrollTop = this.treeEl.scrollTop;
|
|
2305
|
+
this.treeEl.textContent = "";
|
|
2306
|
+
if (this.mode === "tree") {
|
|
2307
|
+
for (const child of this.root.children)
|
|
2308
|
+
this.renderNode(child, 0);
|
|
2309
|
+
if (!this.root.children.length)
|
|
2310
|
+
this.treeEl.appendChild(eln("div", "empty", "No live scopes yet."));
|
|
2311
|
+
} else {
|
|
2312
|
+
this.renderRecent();
|
|
2313
|
+
}
|
|
2314
|
+
this.treeEl.scrollTop = scrollTop;
|
|
2315
|
+
const d = this.selectedId != null ? this.findScope(this.selectedId) : undefined;
|
|
2316
|
+
if (d) {
|
|
2317
|
+
this.renderDetails(d);
|
|
2318
|
+
this.highlight(d);
|
|
2319
|
+
} else {
|
|
2320
|
+
this.selectedId = undefined;
|
|
2321
|
+
this.clearBoxes();
|
|
2322
|
+
this.renderEmptyDetails();
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
renderEmptyDetails() {
|
|
2326
|
+
if (this.rightEl.firstElementChild?.classList.contains("empty"))
|
|
2327
|
+
return;
|
|
2328
|
+
this.rightEl.textContent = "";
|
|
2329
|
+
this.rightEl.appendChild(eln("div", "empty", `No scope selected.
|
|
2330
|
+
|
|
2331
|
+
Click a scope in the tree — or hold Alt and hover an element on the page to select the scope that drew it.`));
|
|
2332
|
+
}
|
|
2333
|
+
renderRecent() {
|
|
2334
|
+
const all = [];
|
|
2335
|
+
const walk = (d) => {
|
|
2336
|
+
if (d.renderTime != null && d.renderTime > this.recentSince)
|
|
2337
|
+
all.push(d);
|
|
2338
|
+
d.children.forEach(walk);
|
|
2339
|
+
};
|
|
2340
|
+
this.root.children.forEach(walk);
|
|
2341
|
+
all.sort((x, y) => y.renderTime - x.renderTime);
|
|
2342
|
+
if (!all.length) {
|
|
2343
|
+
this.treeEl.appendChild(eln("div", "empty", "No re-renders observed yet."));
|
|
2344
|
+
return;
|
|
2345
|
+
}
|
|
2346
|
+
for (const d of all.slice(0, 60)) {
|
|
2347
|
+
const row = eln("div", "node" + (d.id === this.selectedId ? " sel" : ""));
|
|
2348
|
+
row.dataset.id = String(d.id);
|
|
2349
|
+
row.style.paddingLeft = "8px";
|
|
2350
|
+
const info = typeInfo(d.type);
|
|
2351
|
+
const badge = eln("span", "badge", info.label);
|
|
2352
|
+
badge.style.background = info.color;
|
|
2353
|
+
row.appendChild(badge);
|
|
2354
|
+
row.appendChild(eln("span", "loc", d.renderChange ? changeSummary(d.renderChange) : appFrame(d.createError) || d.type));
|
|
2355
|
+
row.appendChild(eln("span", "t", ms(d.renderTime, 0)));
|
|
2356
|
+
row.addEventListener("click", () => this.select(d));
|
|
2357
|
+
row.addEventListener("pointerenter", () => this.highlight(d));
|
|
2358
|
+
row.addEventListener("pointerleave", () => this.highlight(this.selectedId != null ? this.findScope(this.selectedId) : undefined));
|
|
2359
|
+
this.treeEl.appendChild(row);
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
renderNode(d, depth) {
|
|
2363
|
+
const row = eln("div", "node" + (d.id === this.selectedId ? " sel" : ""));
|
|
2364
|
+
row.dataset.id = String(d.id);
|
|
2365
|
+
row.style.paddingLeft = 8 + depth * 14 + "px";
|
|
2366
|
+
const hasKids = d.children.length > 0;
|
|
2367
|
+
const tw = eln("div", "tw", hasKids ? this.collapsed.has(d.id) ? "▸" : "▾" : "");
|
|
2368
|
+
if (hasKids)
|
|
2369
|
+
tw.addEventListener("click", (e) => {
|
|
2370
|
+
e.stopPropagation();
|
|
2371
|
+
if (this.collapsed.has(d.id))
|
|
2372
|
+
this.collapsed.delete(d.id);
|
|
2373
|
+
else
|
|
2374
|
+
this.collapsed.add(d.id);
|
|
2375
|
+
this.rebuild();
|
|
2376
|
+
});
|
|
2377
|
+
row.appendChild(tw);
|
|
2378
|
+
const info = typeInfo(d.type);
|
|
2379
|
+
const badge = eln("span", "badge", info.label);
|
|
2380
|
+
badge.style.background = info.color;
|
|
2381
|
+
row.appendChild(badge);
|
|
2382
|
+
row.appendChild(eln("span", "loc", appFrame(d.createError) || (d.createError === undefined ? "(pre-open)" : "(internal)")));
|
|
2383
|
+
if (d.createdTime != null)
|
|
2384
|
+
row.appendChild(eln("span", "t", ms(d.createdTime, 0)));
|
|
2385
|
+
row.addEventListener("click", () => this.select(d));
|
|
2386
|
+
row.addEventListener("pointerenter", () => this.highlight(d));
|
|
2387
|
+
row.addEventListener("pointerleave", () => this.highlight(this.selectedId != null ? this.findScope(this.selectedId) : undefined));
|
|
2388
|
+
this.treeEl.appendChild(row);
|
|
2389
|
+
if (hasKids && !this.collapsed.has(d.id))
|
|
2390
|
+
for (const c of d.children)
|
|
2391
|
+
this.renderNode(c, depth + 1);
|
|
2392
|
+
}
|
|
2393
|
+
findScope(id, node = this.root) {
|
|
2394
|
+
if (node.id === id)
|
|
2395
|
+
return node;
|
|
2396
|
+
for (const c of node.children) {
|
|
2397
|
+
const r = this.findScope(id, c);
|
|
2398
|
+
if (r)
|
|
2399
|
+
return r;
|
|
2400
|
+
}
|
|
2401
|
+
return;
|
|
2402
|
+
}
|
|
2403
|
+
select(d) {
|
|
2404
|
+
this.selectedId = d ? d.id : undefined;
|
|
2405
|
+
for (const el of this.treeEl.querySelectorAll(".node.sel"))
|
|
2406
|
+
el.classList.remove("sel");
|
|
2407
|
+
if (!d) {
|
|
2408
|
+
this.renderEmptyDetails();
|
|
2409
|
+
this.clearBoxes();
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
const row = this.treeEl.querySelector(`.node[data-id="${d.id}"]`);
|
|
2413
|
+
if (row) {
|
|
2414
|
+
row.classList.add("sel");
|
|
2415
|
+
row.scrollIntoView({ block: "nearest" });
|
|
2416
|
+
}
|
|
2417
|
+
this.renderDetails(d);
|
|
2418
|
+
this.highlight(d);
|
|
2419
|
+
}
|
|
2420
|
+
renderDetails(d) {
|
|
2421
|
+
const r = this.rightEl;
|
|
2422
|
+
r.textContent = "";
|
|
2423
|
+
const info = typeInfo(d.type);
|
|
2424
|
+
const head = eln("h4");
|
|
2425
|
+
const badge = eln("span", "badge", info.label);
|
|
2426
|
+
badge.style.background = info.color;
|
|
2427
|
+
head.appendChild(badge);
|
|
2428
|
+
head.appendChild(document.createTextNode(" " + d.type));
|
|
2429
|
+
r.appendChild(head);
|
|
2430
|
+
r.appendChild(kv("owned nodes", String(d.topNodes.length)));
|
|
2431
|
+
r.appendChild(kv("child scopes", String(d.children.length)));
|
|
2432
|
+
if (d.type === "OnEachItemScope" && d.scope)
|
|
2433
|
+
r.appendChild(renderItemValue(d.scope));
|
|
2434
|
+
if (d.subs && d.subs.length)
|
|
2435
|
+
r.appendChild(this.renderReads(d));
|
|
2436
|
+
r.appendChild(section("Creation"));
|
|
2437
|
+
r.appendChild(kv("time", d.createdTime != null ? ms(d.createdTime) : "unknown"));
|
|
2438
|
+
r.appendChild(stackRow("stack", d.createError, "unknown"));
|
|
2439
|
+
if (!d.createError)
|
|
2440
|
+
r.appendChild(eln("div", "muted", "Reload with ?abdev=1 to capture creation stacks."));
|
|
2441
|
+
r.appendChild(section("Last trigger"));
|
|
2442
|
+
if (d.renderTime != null) {
|
|
2443
|
+
r.appendChild(kv("time", ms(d.renderTime) + " (" + d.renderCount + "×)"));
|
|
2444
|
+
if (d.renderChange)
|
|
2445
|
+
r.appendChild(kv("change", changeSummary(d.renderChange)));
|
|
2446
|
+
r.appendChild(stackRow("stack", d.renderError, "(no application frame)"));
|
|
2447
|
+
} else {
|
|
2448
|
+
r.appendChild(eln("div", "muted", "not triggered yet"));
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
renderReads(d) {
|
|
2452
|
+
const wrap = eln("div", "row reads");
|
|
2453
|
+
wrap.appendChild(eln("div", "k", "observing:"));
|
|
2454
|
+
const groups = new Map;
|
|
2455
|
+
for (const [obj, key] of d.subs) {
|
|
2456
|
+
let s = groups.get(obj);
|
|
2457
|
+
if (!s)
|
|
2458
|
+
groups.set(obj, s = new Set);
|
|
2459
|
+
s.add(key);
|
|
2460
|
+
}
|
|
2461
|
+
if (!groups.size) {
|
|
2462
|
+
wrap.appendChild(eln("div", "muted", "(none)"));
|
|
2463
|
+
return wrap;
|
|
2464
|
+
}
|
|
2465
|
+
let n = 0;
|
|
2466
|
+
for (const [obj, keys] of groups) {
|
|
2467
|
+
if (n++ > 16) {
|
|
2468
|
+
wrap.appendChild(eln("div", "muted", "…"));
|
|
2469
|
+
break;
|
|
2470
|
+
}
|
|
2471
|
+
const line = eln("div");
|
|
2472
|
+
line.appendChild(document.createTextNode("{ "));
|
|
2473
|
+
let first = true;
|
|
2474
|
+
for (const k of [...keys].slice(0, 16)) {
|
|
2475
|
+
if (!first)
|
|
2476
|
+
line.appendChild(document.createTextNode(", "));
|
|
2477
|
+
first = false;
|
|
2478
|
+
line.appendChild(eln("span", "key", readKey(k)));
|
|
2479
|
+
if (typeof k !== "symbol") {
|
|
2480
|
+
line.appendChild(document.createTextNode("="));
|
|
2481
|
+
let v;
|
|
2482
|
+
try {
|
|
2483
|
+
v = obj[k];
|
|
2484
|
+
} catch {
|
|
2485
|
+
v = "?";
|
|
2486
|
+
}
|
|
2487
|
+
line.appendChild(eln("span", "val", preview(v)));
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
line.appendChild(document.createTextNode(" }"));
|
|
2491
|
+
wrap.appendChild(line);
|
|
2492
|
+
}
|
|
2493
|
+
return wrap;
|
|
2494
|
+
}
|
|
2495
|
+
highlight(d) {
|
|
2496
|
+
this.clearBoxes();
|
|
2497
|
+
if (!d)
|
|
2498
|
+
return;
|
|
2499
|
+
if (d.el instanceof Element)
|
|
2500
|
+
this.box(d.el.getBoundingClientRect(), "parent");
|
|
2501
|
+
for (const n of d.topNodes)
|
|
2502
|
+
if (n instanceof Element)
|
|
2503
|
+
this.box(n.getBoundingClientRect(), "child");
|
|
2504
|
+
for (const c of d.children)
|
|
2505
|
+
this.box(regionRect(c), "child");
|
|
2506
|
+
}
|
|
2507
|
+
box(rect, kind) {
|
|
2508
|
+
if (!rect || !rect.width && !rect.height)
|
|
2509
|
+
return;
|
|
2510
|
+
const b = eln("div", "box " + kind);
|
|
2511
|
+
Object.assign(b.style, { left: rect.left + "px", top: rect.top + "px", width: rect.width + "px", height: rect.height + "px" });
|
|
2512
|
+
this.overlay.appendChild(b);
|
|
2513
|
+
this.boxes.push(b);
|
|
2514
|
+
}
|
|
2515
|
+
clearBoxes() {
|
|
2516
|
+
for (const b of this.boxes)
|
|
2517
|
+
b.remove();
|
|
2518
|
+
this.boxes.length = 0;
|
|
2519
|
+
}
|
|
2520
|
+
reposition = () => {
|
|
2521
|
+
const d = this.selectedId != null ? this.findScope(this.selectedId) : undefined;
|
|
2522
|
+
if (d)
|
|
2523
|
+
this.highlight(d);
|
|
2524
|
+
};
|
|
2525
|
+
overUI(t) {
|
|
2526
|
+
return !(t instanceof Node) || t === this.host || this.host.contains(t);
|
|
2527
|
+
}
|
|
2528
|
+
onKeyDown = (e) => {
|
|
2529
|
+
if (e.key === "Alt") {
|
|
2530
|
+
this.altPressed = true;
|
|
2531
|
+
this.resolveAt(this.lastX, this.lastY);
|
|
2532
|
+
} else if (e.key === "Escape") {
|
|
2533
|
+
e.preventDefault();
|
|
2534
|
+
this.destroy();
|
|
2535
|
+
}
|
|
2536
|
+
};
|
|
2537
|
+
onKeyUp = (e) => {
|
|
2538
|
+
if (e.key === "Alt")
|
|
2539
|
+
this.altPressed = false;
|
|
2540
|
+
};
|
|
2541
|
+
onBlur = () => {
|
|
2542
|
+
this.altPressed = false;
|
|
2543
|
+
};
|
|
2544
|
+
onPointerMove = (e) => {
|
|
2545
|
+
this.lastX = e.clientX;
|
|
2546
|
+
this.lastY = e.clientY;
|
|
2547
|
+
if (this.altPressed)
|
|
2548
|
+
this.resolveAt(this.lastX, this.lastY);
|
|
2549
|
+
};
|
|
2550
|
+
resolveAt(x, y) {
|
|
2551
|
+
if (x < 0)
|
|
2552
|
+
return;
|
|
2553
|
+
const target = document.elementFromPoint(x, y);
|
|
2554
|
+
if (!target || this.overUI(target))
|
|
2555
|
+
return;
|
|
2556
|
+
let node = target;
|
|
2557
|
+
let d;
|
|
2558
|
+
while (node) {
|
|
2559
|
+
d = (node instanceof Element ? this.elOwner.get(node) : undefined) || this.nodeMap.get(node);
|
|
2560
|
+
if (d)
|
|
2561
|
+
break;
|
|
2562
|
+
node = node.parentNode;
|
|
2563
|
+
}
|
|
2564
|
+
if (d && d.id !== this.selectedId)
|
|
2565
|
+
this.select(d);
|
|
2566
|
+
}
|
|
2567
|
+
setupDrag(handle) {
|
|
2568
|
+
let sx = 0, sy = 0, ox = 0, oy = 0, down = false;
|
|
2569
|
+
handle.addEventListener("pointerdown", (e) => {
|
|
2570
|
+
if (e.target.classList.contains("x"))
|
|
2571
|
+
return;
|
|
2572
|
+
down = true;
|
|
2573
|
+
sx = e.clientX;
|
|
2574
|
+
sy = e.clientY;
|
|
2575
|
+
ox = this.dlg.offsetLeft;
|
|
2576
|
+
oy = this.dlg.offsetTop;
|
|
2577
|
+
handle.setPointerCapture(e.pointerId);
|
|
2578
|
+
});
|
|
2579
|
+
handle.addEventListener("pointermove", (e) => {
|
|
2580
|
+
if (!down)
|
|
2581
|
+
return;
|
|
2582
|
+
this.dlg.style.left = Math.max(0, Math.min(window.innerWidth - 80, ox + e.clientX - sx)) + "px";
|
|
2583
|
+
this.dlg.style.top = Math.max(0, Math.min(window.innerHeight - 24, oy + e.clientY - sy)) + "px";
|
|
2584
|
+
});
|
|
2585
|
+
handle.addEventListener("pointerup", () => {
|
|
2586
|
+
down = false;
|
|
2587
|
+
this.savePos();
|
|
2588
|
+
});
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
function eln(tag, cls, text) {
|
|
2592
|
+
const e = document.createElement(tag);
|
|
2593
|
+
if (cls)
|
|
2594
|
+
e.className = cls;
|
|
2595
|
+
if (text != null)
|
|
2596
|
+
e.textContent = text;
|
|
2597
|
+
return e;
|
|
2598
|
+
}
|
|
2599
|
+
function kv(k, v) {
|
|
2600
|
+
const row = eln("div", "row");
|
|
2601
|
+
row.appendChild(eln("span", "k", k + ": "));
|
|
2602
|
+
row.appendChild(document.createTextNode(v));
|
|
2603
|
+
return row;
|
|
2604
|
+
}
|
|
2605
|
+
function section(title) {
|
|
2606
|
+
return eln("div", "sec", title);
|
|
2607
|
+
}
|
|
2608
|
+
function stackRow(label, err, emptyMsg) {
|
|
2609
|
+
const row = eln("div", "row");
|
|
2610
|
+
row.appendChild(eln("span", "k", label + ": "));
|
|
2611
|
+
const full = formatStack(err && err.stack);
|
|
2612
|
+
if (!full) {
|
|
2613
|
+
row.appendChild(eln("span", "muted", emptyMsg));
|
|
2614
|
+
return row;
|
|
2615
|
+
}
|
|
2616
|
+
const link = eln("span", "loclink", appFrame(err) || "(internal)");
|
|
2617
|
+
const pre = eln("div", "stack");
|
|
2618
|
+
pre.textContent = full;
|
|
2619
|
+
pre.style.display = "none";
|
|
2620
|
+
link.addEventListener("click", () => {
|
|
2621
|
+
pre.style.display = pre.style.display ? "" : "none";
|
|
2622
|
+
});
|
|
2623
|
+
row.appendChild(link);
|
|
2624
|
+
row.appendChild(pre);
|
|
2625
|
+
return row;
|
|
2626
|
+
}
|
|
2627
|
+
function readKey(k) {
|
|
2628
|
+
if (typeof k !== "symbol")
|
|
2629
|
+
return String(k);
|
|
2630
|
+
return k.description === "any" ? "*" : k.description === "mapSize" ? "size" : k.description || "?";
|
|
2631
|
+
}
|
|
2632
|
+
function changeSummary(c) {
|
|
2633
|
+
return `${readKey(c.index)}: ${preview(c.oldData)} → ${preview(c.newData)}`;
|
|
2634
|
+
}
|
|
2635
|
+
function renderItemValue(scope) {
|
|
2636
|
+
const target = scope.parent?.target;
|
|
2637
|
+
const idx = scope.itemIndex;
|
|
2638
|
+
const isSet = target instanceof Set;
|
|
2639
|
+
const value = isSet ? idx : target instanceof Map ? target.get(idx) : target ? target[idx] : undefined;
|
|
2640
|
+
const wrap = eln("div", "row");
|
|
2641
|
+
if (!isSet)
|
|
2642
|
+
wrap.appendChild(kv("key", String(idx)));
|
|
2643
|
+
const line = eln("div");
|
|
2644
|
+
line.appendChild(eln("span", "k", "value: "));
|
|
2645
|
+
line.appendChild(eln("span", "val", preview(value)));
|
|
2646
|
+
const btn = eln("button", "logbtn", "to console");
|
|
2647
|
+
btn.addEventListener("click", () => console.log(value));
|
|
2648
|
+
line.appendChild(document.createTextNode(" "));
|
|
2649
|
+
line.appendChild(btn);
|
|
2650
|
+
wrap.appendChild(line);
|
|
2651
|
+
return wrap;
|
|
2652
|
+
}
|
|
2653
|
+
function ms(t, dp = 1) {
|
|
2654
|
+
return "+" + t.toLocaleString(undefined, { minimumFractionDigits: dp, maximumFractionDigits: dp }) + "ms";
|
|
2655
|
+
}
|
|
2656
|
+
function preview(v) {
|
|
2657
|
+
if (v === null)
|
|
2658
|
+
return "null";
|
|
2659
|
+
if (typeof v === "string")
|
|
2660
|
+
return JSON.stringify(v.length > 30 ? v.slice(0, 30) + "…" : v);
|
|
2661
|
+
if (typeof v === "object")
|
|
2662
|
+
return Array.isArray(v) ? `[${v.length}]` : "{…}";
|
|
2663
|
+
if (typeof v === "function")
|
|
2664
|
+
return "fn";
|
|
2665
|
+
return String(v);
|
|
2666
|
+
}
|
|
2667
|
+
function deepNodes(d, out = []) {
|
|
2668
|
+
for (const n of d.topNodes)
|
|
2669
|
+
out.push(n);
|
|
2670
|
+
for (const c of d.children)
|
|
2671
|
+
deepNodes(c, out);
|
|
2672
|
+
return out;
|
|
2673
|
+
}
|
|
2674
|
+
function regionRect(d) {
|
|
2675
|
+
let l = Infinity, t = Infinity, r = -Infinity, b = -Infinity;
|
|
2676
|
+
for (const n of deepNodes(d)) {
|
|
2677
|
+
if (!(n instanceof Element))
|
|
2678
|
+
continue;
|
|
2679
|
+
const q = n.getBoundingClientRect();
|
|
2680
|
+
if (!q.width && !q.height)
|
|
2681
|
+
continue;
|
|
2682
|
+
l = Math.min(l, q.left);
|
|
2683
|
+
t = Math.min(t, q.top);
|
|
2684
|
+
r = Math.max(r, q.right);
|
|
2685
|
+
b = Math.max(b, q.bottom);
|
|
2686
|
+
}
|
|
2687
|
+
if (l === Infinity)
|
|
2688
|
+
return;
|
|
2689
|
+
return new DOMRect(l, t, r - l, b - t);
|
|
2690
|
+
}
|
|
2691
|
+
function appFrame(err) {
|
|
2692
|
+
const s = formatStack(err && err.stack);
|
|
2693
|
+
if (!s)
|
|
2694
|
+
return "";
|
|
2695
|
+
const first = s.split(`
|
|
2696
|
+
`)[0];
|
|
2697
|
+
const m = first.match(/([^\/\\(]+):(\d+):\d+\)?$/);
|
|
2698
|
+
return m ? `${m[1]}:${m[2]}` : first.replace(/^at\s+/, "");
|
|
2699
|
+
}
|
|
2700
|
+
function formatStack(stack) {
|
|
2701
|
+
if (!stack)
|
|
2702
|
+
return "";
|
|
2703
|
+
const origin = location.protocol + "//" + location.host;
|
|
2704
|
+
return stack.split(`
|
|
2705
|
+
`).map((l) => l.trim().split(origin).join("")).filter((l) => (l.startsWith("at ") || l.includes("@")) && !/aberdeen(\.dev)?\.[jt]s|devtools\.[jt]s/.test(l)).join(`
|
|
2706
|
+
`);
|
|
2707
|
+
}
|
|
2708
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
2709
|
+
if (/[?&]abdev=1\b/.test(location.search))
|
|
2710
|
+
activate();
|
|
2711
|
+
window.addEventListener("keydown", (e) => {
|
|
2712
|
+
if ((e.ctrlKey || e.metaKey) && e.altKey && e.code === "KeyA") {
|
|
2713
|
+
e.preventDefault();
|
|
2714
|
+
if (tool)
|
|
2715
|
+
tool.destroy();
|
|
2716
|
+
else
|
|
2717
|
+
activate();
|
|
2718
|
+
}
|
|
2719
|
+
});
|
|
2720
|
+
}
|
|
1948
2721
|
export {
|
|
1949
2722
|
withEmitHandler,
|
|
1950
2723
|
unproxy,
|
|
@@ -1966,17 +2739,19 @@ export {
|
|
|
1966
2739
|
invertString,
|
|
1967
2740
|
insertGlobalCss,
|
|
1968
2741
|
insertCss,
|
|
2742
|
+
freeze,
|
|
1969
2743
|
dump,
|
|
1970
2744
|
disableCreateDestroy,
|
|
1971
2745
|
derive,
|
|
1972
2746
|
defaultEmitHandler,
|
|
1973
|
-
|
|
2747
|
+
devtools_default as default,
|
|
1974
2748
|
darkMode,
|
|
1975
2749
|
cssVars,
|
|
1976
2750
|
count,
|
|
1977
2751
|
copy,
|
|
1978
2752
|
clone,
|
|
1979
2753
|
clean,
|
|
2754
|
+
_setDev,
|
|
1980
2755
|
OPAQUE,
|
|
1981
2756
|
NO_COPY,
|
|
1982
2757
|
MAP_SIZE_SYMBOL,
|
|
@@ -1985,5 +2760,5 @@ export {
|
|
|
1985
2760
|
A
|
|
1986
2761
|
};
|
|
1987
2762
|
|
|
1988
|
-
//# debugId=
|
|
1989
|
-
//# sourceMappingURL=aberdeen.js.map
|
|
2763
|
+
//# debugId=5E581450DD669A5F64756E2164756E21
|
|
2764
|
+
//# sourceMappingURL=aberdeen.dev.js.map
|