aberdeen 1.18.2 → 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 +27 -0
- package/{dist-docs/assets/aberdeen/aberdeen.js → dist/src/aberdeen.dev.js} +776 -15
- package/dist/src/aberdeen.dev.js.map +12 -0
- package/dist/src/aberdeen.js +59 -13
- package/dist/src/aberdeen.js.map +3 -3
- package/dist/src/devtools.d.ts +26 -0
- 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 +194 -73
- 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 -116
- 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 -342
- 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 -963
- 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 -266
- 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 -4586
- 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) {
|
|
@@ -145,6 +146,8 @@ function queue(runner) {
|
|
|
145
146
|
sortedQueue.add(runner);
|
|
146
147
|
}
|
|
147
148
|
function runQueue() {
|
|
149
|
+
if (freezeCount)
|
|
150
|
+
return;
|
|
148
151
|
let time = Date.now();
|
|
149
152
|
while (sortedQueue) {
|
|
150
153
|
const runner = sortedQueue.fetchLast();
|
|
@@ -160,6 +163,17 @@ function runQueue() {
|
|
|
160
163
|
if (time > 9)
|
|
161
164
|
console.debug(`Aberdeen queue took ${time}ms`);
|
|
162
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
|
+
}
|
|
163
177
|
function arrayToStr(parts) {
|
|
164
178
|
let result = "";
|
|
165
179
|
for (const part of parts) {
|
|
@@ -248,6 +262,7 @@ class ContentScope extends Scope {
|
|
|
248
262
|
if (!this.changes) {
|
|
249
263
|
this.changes = new Map;
|
|
250
264
|
queue(this);
|
|
265
|
+
dev?.schedule(this, index, oldData, newData, new Error);
|
|
251
266
|
}
|
|
252
267
|
let targetDelta = this.changes.get(target);
|
|
253
268
|
if (!targetDelta) {
|
|
@@ -305,6 +320,7 @@ class ChainedScope extends ContentScope {
|
|
|
305
320
|
}
|
|
306
321
|
if (!useParentCleaners)
|
|
307
322
|
currentScope.cleaners.push(this);
|
|
323
|
+
dev?.create(this, currentScope, new Error);
|
|
308
324
|
}
|
|
309
325
|
getPrecedingNode() {
|
|
310
326
|
return findLastNodeInPrevSiblings(this.prevSibling);
|
|
@@ -324,6 +340,7 @@ class RegularScope extends ChainedScope {
|
|
|
324
340
|
redraw() {
|
|
325
341
|
const savedScope = currentScope;
|
|
326
342
|
currentScope = this;
|
|
343
|
+
dev?.render(this);
|
|
327
344
|
try {
|
|
328
345
|
this.renderer();
|
|
329
346
|
} catch (e) {
|
|
@@ -350,6 +367,7 @@ class MountScope extends ContentScope {
|
|
|
350
367
|
this.el = el;
|
|
351
368
|
this.renderer = renderer;
|
|
352
369
|
this.svg = el.namespaceURI === "http://www.w3.org/2000/svg";
|
|
370
|
+
dev?.create(this, currentScope, new Error);
|
|
353
371
|
const oldTopRedrawScope = topRedrawScope;
|
|
354
372
|
topRedrawScope = this;
|
|
355
373
|
this.redraw();
|
|
@@ -454,6 +472,7 @@ class OnEachScope extends Scope {
|
|
|
454
472
|
this.prevSibling = currentScope.getChildPrevSibling();
|
|
455
473
|
currentScope.lastChild = this;
|
|
456
474
|
currentScope.cleaners.push(this);
|
|
475
|
+
dev?.create(this, currentScope, new Error);
|
|
457
476
|
if (target instanceof Array) {
|
|
458
477
|
for (let i = 0;i < target.length; i++) {
|
|
459
478
|
new OnEachItemScope(this, i, false);
|
|
@@ -484,8 +503,10 @@ class OnEachScope extends Scope {
|
|
|
484
503
|
this.changedIndexes = new Map;
|
|
485
504
|
for (const index of indexes.keys()) {
|
|
486
505
|
const oldScope = this.byIndex.get(index);
|
|
487
|
-
if (oldScope)
|
|
506
|
+
if (oldScope) {
|
|
488
507
|
oldScope.remove();
|
|
508
|
+
dev?.delete(oldScope);
|
|
509
|
+
}
|
|
489
510
|
if (this.target instanceof Set || this.target instanceof Map ? this.target.has(index) : (index in this.target)) {
|
|
490
511
|
new OnEachItemScope(this, index, true);
|
|
491
512
|
} else {
|
|
@@ -527,6 +548,7 @@ class OnEachItemScope extends ContentScope {
|
|
|
527
548
|
this.svg = currentScope.svg;
|
|
528
549
|
this.parent.byIndex.set(this.itemIndex, this);
|
|
529
550
|
this.lastChild = this;
|
|
551
|
+
dev?.create(this, this.parent, new Error);
|
|
530
552
|
if (topRedraw)
|
|
531
553
|
topRedrawScope = this;
|
|
532
554
|
this.redraw();
|
|
@@ -585,6 +607,7 @@ class OnEachItemScope extends ContentScope {
|
|
|
585
607
|
}
|
|
586
608
|
const savedScope = currentScope;
|
|
587
609
|
currentScope = this;
|
|
610
|
+
dev?.render(this);
|
|
588
611
|
let sortKey;
|
|
589
612
|
try {
|
|
590
613
|
if (this.parent.makeSortKey) {
|
|
@@ -629,15 +652,31 @@ class OnEachItemScope extends ContentScope {
|
|
|
629
652
|
function addNode(el, node) {
|
|
630
653
|
if (el !== currentScope.el) {
|
|
631
654
|
el.appendChild(node);
|
|
655
|
+
dev?.node(currentScope, node, false);
|
|
632
656
|
return;
|
|
633
657
|
}
|
|
634
658
|
const parentEl = currentScope.el;
|
|
635
659
|
const prevNode = currentScope.getInsertAfterNode();
|
|
636
660
|
parentEl.insertBefore(node, prevNode ? prevNode.nextSibling : parentEl.firstChild);
|
|
637
661
|
currentScope.lastChild = node;
|
|
662
|
+
dev?.node(currentScope, node, true);
|
|
638
663
|
}
|
|
639
664
|
var ROOT_SCOPE = new RootScope;
|
|
640
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
|
+
}
|
|
641
680
|
function leakScope(func) {
|
|
642
681
|
const savedScope = currentScope;
|
|
643
682
|
currentScope = new RootScope;
|
|
@@ -655,6 +694,8 @@ var peeking = 0;
|
|
|
655
694
|
function subscribe(target, index, observer = currentScope) {
|
|
656
695
|
if (observer === ROOT_SCOPE || peeking)
|
|
657
696
|
return;
|
|
697
|
+
if (observer === currentScope)
|
|
698
|
+
dev?.read(currentScope, target, index);
|
|
658
699
|
let byTarget = subscribers.get(target);
|
|
659
700
|
if (!byTarget)
|
|
660
701
|
subscribers.set(target, byTarget = new Map);
|
|
@@ -1560,12 +1601,22 @@ function insertCss(style) {
|
|
|
1560
1601
|
const prefix = `.AbdStl${++cssCount}`;
|
|
1561
1602
|
const css = typeof style === "string" ? styleStringToCss(style, prefix) : objectToCss(style, prefix);
|
|
1562
1603
|
if (css) {
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1604
|
+
const cnt = cssSnippetCount++;
|
|
1605
|
+
const key = arrayToStr([currentScope.prio, cnt]);
|
|
1606
|
+
cssSnippets[key] = css;
|
|
1607
|
+
clean(() => delete cssSnippets[key]);
|
|
1566
1608
|
}
|
|
1567
1609
|
return prefix;
|
|
1568
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
|
+
}
|
|
1569
1620
|
var cssSnippets = proxy({});
|
|
1570
1621
|
var cssSnippetCount = 0;
|
|
1571
1622
|
function combinePrefixSelector(prefix, key) {
|
|
@@ -1637,14 +1688,6 @@ function styleStringToCss(styleStr, selector) {
|
|
|
1637
1688
|
return props ? `${selector}{${props}}
|
|
1638
1689
|
` : "";
|
|
1639
1690
|
}
|
|
1640
|
-
function insertGlobalCss(style) {
|
|
1641
|
-
const css = objectToCss(style, "");
|
|
1642
|
-
if (css) {
|
|
1643
|
-
let cnt = cssSnippetCount++;
|
|
1644
|
-
cssSnippets[cnt] = css;
|
|
1645
|
-
clean(() => delete cssSnippets[cnt]);
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
1691
|
var CSS_SHORT = {
|
|
1649
1692
|
m: "margin",
|
|
1650
1693
|
mt: "margin-top",
|
|
@@ -1938,6 +1981,7 @@ var aberdeen_default = Object.assign(A, {
|
|
|
1938
1981
|
derive,
|
|
1939
1982
|
disableCreateDestroy,
|
|
1940
1983
|
dump,
|
|
1984
|
+
freeze,
|
|
1941
1985
|
insertCss,
|
|
1942
1986
|
insertGlobalCss,
|
|
1943
1987
|
invertString,
|
|
@@ -1959,6 +2003,721 @@ var aberdeen_default = Object.assign(A, {
|
|
|
1959
2003
|
unmountAll,
|
|
1960
2004
|
unproxy
|
|
1961
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
|
+
}
|
|
1962
2721
|
export {
|
|
1963
2722
|
withEmitHandler,
|
|
1964
2723
|
unproxy,
|
|
@@ -1980,17 +2739,19 @@ export {
|
|
|
1980
2739
|
invertString,
|
|
1981
2740
|
insertGlobalCss,
|
|
1982
2741
|
insertCss,
|
|
2742
|
+
freeze,
|
|
1983
2743
|
dump,
|
|
1984
2744
|
disableCreateDestroy,
|
|
1985
2745
|
derive,
|
|
1986
2746
|
defaultEmitHandler,
|
|
1987
|
-
|
|
2747
|
+
devtools_default as default,
|
|
1988
2748
|
darkMode,
|
|
1989
2749
|
cssVars,
|
|
1990
2750
|
count,
|
|
1991
2751
|
copy,
|
|
1992
2752
|
clone,
|
|
1993
2753
|
clean,
|
|
2754
|
+
_setDev,
|
|
1994
2755
|
OPAQUE,
|
|
1995
2756
|
NO_COPY,
|
|
1996
2757
|
MAP_SIZE_SYMBOL,
|
|
@@ -1999,5 +2760,5 @@ export {
|
|
|
1999
2760
|
A
|
|
2000
2761
|
};
|
|
2001
2762
|
|
|
2002
|
-
//# debugId=
|
|
2003
|
-
//# sourceMappingURL=aberdeen.js.map
|
|
2763
|
+
//# debugId=5E581450DD669A5F64756E2164756E21
|
|
2764
|
+
//# sourceMappingURL=aberdeen.dev.js.map
|