Skip to content

Commit 8dccb61

Browse files
authored
fix: group iteration nodes in one each block (#145)
1 parent afbb536 commit 8dccb61

File tree

9 files changed

+76
-99
lines changed

9 files changed

+76
-99
lines changed

src/app.d.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ declare global {
5555
detail?: any;
5656
tagName?: string;
5757

58-
parent?: SvelteBlockDetail;
59-
parentBlock?: SvelteBlockDetail;
6058
children: SvelteBlockDetail[];
59+
/** `type: 'element' | 'component'` */
60+
parent?: SvelteBlockDetail;
61+
/** like `parent` but `type: 'component'` */
62+
container?: SvelteBlockDetail;
6163

6264
block: SvelteComponentDetail['component']['$$']['fragment'];
6365
ctx: Array<any>; // TODO: do we need this typed?

src/client/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ function serialize(node) {
111111
id: node.id,
112112
type: node.type,
113113
tagName: node.tagName,
114+
detail: {},
114115
});
115116
switch (node.type) {
116117
case 'component': {

src/client/svelte.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ const nodes = {
2323
this.map.set(node.detail, node);
2424

2525
let target = source && this.map.get(source);
26-
if (!target || target.parentBlock != node.parentBlock) {
27-
target = node.parentBlock;
26+
if (!target || target.container != node.container) {
27+
target = node.container;
2828
}
2929
node.parent = target;
3030

@@ -94,14 +94,14 @@ document.addEventListener('SvelteRegisterBlock', ({ detail }) => {
9494
type: 'block',
9595
detail: rest,
9696
tagName: type === 'pending' ? 'await' : type,
97-
parentBlock: parent,
97+
container: parent,
9898
children: [],
9999
});
100100

101101
switch (type) {
102102
case 'then':
103103
case 'catch':
104-
if (!node.parentBlock) node.parentBlock = last_promise;
104+
if (!node.container) node.container = last_promise;
105105
break;
106106

107107
case 'slot':
@@ -129,25 +129,26 @@ document.addEventListener('SvelteRegisterBlock', ({ detail }) => {
129129
}
130130

131131
if (type === 'each') {
132-
const group =
133-
(parent && nodes.map.get(parent.id + id)) ||
132+
let group = parent && nodes.map.get(parent.id + id);
133+
if (!group) {
134134
// @ts-expect-error - each block fallback
135-
/** @type {SvelteBlockDetail} */ ({
135+
group = /** @type {SvelteBlockDetail} */ ({
136136
version: '',
137137
id: pointer++,
138138
type: 'block',
139139
tagName: 'each',
140-
parentBlock: parent,
140+
container: parent,
141141
children: [],
142142
detail: {
143143
ctx: {},
144144
source: detail.source,
145145
},
146146
});
147-
parent && nodes.map.set(parent.id + id, group);
148-
nodes.add({ node: group, target, anchor });
147+
parent && nodes.map.set(parent.id + id, group);
148+
nodes.add({ node: group, target, anchor });
149+
}
149150

150-
node.parentBlock = group;
151+
node.container = group;
151152
node.type = 'iteration';
152153

153154
// @ts-expect-error - overloaded nodes
@@ -185,7 +186,7 @@ document.addEventListener('SvelteRegisterBlock', ({ detail }) => {
185186
const node = nodes.map.get(current_node_id);
186187
if (node) {
187188
if (node.tagName === 'await') {
188-
last_promise = node.parentBlock;
189+
last_promise = node.container;
189190
}
190191
nodes.remove(node);
191192
}
@@ -217,7 +218,7 @@ document.addEventListener('SvelteDOMInsert', ({ detail }) => {
217218
type,
218219
detail: element,
219220
tagName: element.nodeName.toLowerCase(),
220-
parentBlock: current_block,
221+
container: current_block,
221222
children: [],
222223
},
223224
});

src/lib/nodes/Anchor.svelte

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/lib/nodes/Iteration.svelte

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script lang="ts">
2+
import Ellipsis from './Ellipsis.svelte';
3+
4+
export let expanded: boolean;
5+
</script>
6+
7+
<!-- svelte-ignore a11y-no-static-element-interactions -->
8+
<div class="expandable" on:dblclick={() => (expanded = !expanded)}>
9+
<span>&#8618;</span>
10+
{#if !expanded}
11+
<Ellipsis on:click={() => (expanded = true)} />
12+
{/if}
13+
</div>
14+
15+
{#if expanded}
16+
<slot />
17+
{/if}

src/lib/nodes/Node.svelte

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<script lang="ts">
22
import Indexer from '$lib/components/Indexer.svelte';
3-
import Element from './Element.svelte';
43
import Block from './Block.svelte';
4+
import Element from './Element.svelte';
5+
import Iteration from './Iteration.svelte';
56
import Slot from './Slot.svelte';
67
78
import { background } from '$lib/runtime';
@@ -56,32 +57,21 @@
5657
</ul>
5758
</Element>
5859
{:else if node.type === 'block'}
59-
<Block tagName={node.tagName} source={node.detail?.source} bind:expanded={node.expanded}>
60+
<Block tagName={node.tagName} source={node.detail.source} bind:expanded={node.expanded}>
6061
<ul>
6162
{#each node.children as child (child.id)}
6263
<svelte:self node={child} depth={depth + 1} />
6364
{/each}
6465
</ul>
6566
</Block>
6667
{:else if node.type === 'iteration'}
67-
<ul>
68-
<!-- TODO: figure this out
69-
<span
70-
class:selected={current}
71-
class:hover={active}
72-
style:z-index="1"
73-
style:position="absolute"
74-
style:left="{left - 4}px"
75-
style:transform="translateX(-100%)"
76-
>
77-
&#8618;
78-
</span>
79-
-->
80-
81-
{#each node.children as child (child.id)}
82-
<svelte:self node={child} depth={depth + 1} />
83-
{/each}
84-
</ul>
68+
<Iteration bind:expanded={node.expanded}>
69+
<ul>
70+
{#each node.children as child (child.id)}
71+
<svelte:self node={child} depth={depth + 1} />
72+
{/each}
73+
</ul>
74+
</Iteration>
8575
{:else if node.type === 'slot'}
8676
<Slot tagName={node.tagName} bind:expanded={node.expanded}>
8777
<ul>
@@ -92,7 +82,7 @@
9282
</Slot>
9383
{:else if node.type === 'text'}
9484
<div>
95-
<Indexer text={node.detail?.nodeValue} />
85+
<Indexer text={node.detail.nodeValue} />
9686
</div>
9787
{:else if node.type === 'anchor'}
9888
<div>#anchor</div>

src/lib/runtime.ts

Lines changed: 22 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { hovered, root, selected } from './store';
1+
import { type DebugNode, hovered, root, selected } from './store';
22

33
const tabId = chrome.devtools.inspectedWindow.tabId;
44
const port = chrome.runtime.connect({ name: `${tabId}` });
@@ -11,21 +11,7 @@ export const background = {
1111
},
1212
};
1313

14-
const nodes = new Map();
15-
16-
function insertNode(node: any, target: any, anchorId: number) {
17-
node.parent = target;
18-
19-
const index = anchorId ? target.children.findIndex((o: any) => o.id === anchorId) : -1;
20-
21-
if (index !== -1) {
22-
target.children.splice(index, 0, node);
23-
} else {
24-
target.children.push(node);
25-
}
26-
27-
target.invalidate();
28-
}
14+
const nodes = new Map<null | number, DebugNode>();
2915

3016
function resolveEventBubble(node: any) {
3117
if (!node.detail || !node.detail.listeners) return;
@@ -65,47 +51,43 @@ port.onMessage.addListener(({ type, payload }) => {
6551
}
6652

6753
case 'courier/node:add': {
68-
const { node, target, anchor } = payload;
54+
const { node, target, anchor } = payload as {
55+
node: DebugNode;
56+
target: null | number;
57+
anchor: null | number;
58+
};
6959

7060
node.children = [];
7161
node.expanded = false;
7262
node.invalidate = () => {};
7363
resolveEventBubble(node);
7464

75-
const map_node = nodes.get(target);
65+
const parent = nodes.get(target);
7666
nodes.set(node.id, node);
67+
if (!parent) return root.update((n) => [...n, node]);
7768

78-
if (map_node) {
79-
insertNode(node, map_node, anchor);
80-
return;
81-
}
82-
83-
if (node._timeout) return;
84-
85-
node._timeout = setTimeout(() => {
86-
delete node._timeout;
87-
const targetNode = nodes.get(target);
88-
if (targetNode) insertNode(node, targetNode, anchor);
89-
else root.update((o) => [...o, node]);
90-
}, 100);
69+
const index = parent.children.findIndex((n) => n.id === anchor);
70+
if (index === -1) parent.children.push(node);
71+
else parent.children.splice(index, 0, node);
9172

92-
break;
73+
return (node.parent = parent).invalidate();
9374
}
9475

9576
case 'courier/node:remove': {
96-
const current = nodes.get(payload.node.id);
97-
nodes.delete(current.id);
98-
if (!current.parent) break;
77+
const node = payload.node as SvelteBlockDetail;
78+
const current = nodes.get(node.id);
79+
if (current) nodes.delete(current.id);
80+
if (!current?.parent) return;
9981

100-
const index = current.parent.children.findIndex((o: any) => o.id === current.id);
82+
const index = current.parent.children.findIndex((o) => o.id === current.id);
10183
current.parent.children.splice(index, 1);
102-
current.parent.invalidate();
103-
break;
84+
return current.parent.invalidate();
10485
}
10586

10687
case 'courier/node:update': {
107-
const current = nodes.get(payload.node.id);
108-
if (!current) return; // TODO: investigate why this happens
88+
const node = payload.node as SvelteBlockDetail;
89+
const current = nodes.get(node.id);
90+
if (!current) return;
10991
Object.assign(current, payload.node);
11092
resolveEventBubble(current);
11193

src/lib/store.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import { writable } from 'svelte/store';
22

33
type Overwrite<A, B> = Omit<A, keyof B> & B;
44

5-
type DebugNode = Overwrite<
5+
export type DebugNode = Overwrite<
66
SvelteBlockDetail,
77
{
88
invalidate(): void;
99
expanded: boolean;
10-
detail?: {
10+
detail: {
1111
attributes?: Array<{
1212
key: string;
1313
value: string;

src/routes/+layout.svelte

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,15 @@
124124

125125
<!-- component details -->
126126
<Resizable axis="x">
127-
{@const events = $selected?.detail?.listeners?.map((l) => {
127+
{@const events = $selected?.detail.listeners?.map((l) => {
128128
const suffix = l.modifiers?.length ? `|${l.modifiers.join('|')}` : '';
129129
const value = { __is: 'function', source: l.handler };
130130
return { key: l.event + suffix, value };
131131
})}
132132

133133
{#if $selected?.type === 'component'}
134134
<h2>Props</h2>
135-
<PropertyList id={$selected.id} entries={$selected.detail?.attributes} />
135+
<PropertyList id={$selected.id} entries={$selected.detail.attributes} />
136136

137137
<Divider type="horizontal" />
138138

@@ -142,13 +142,13 @@
142142
<Divider type="horizontal" />
143143

144144
<h2>State</h2>
145-
<PropertyList id={$selected.id} entries={$selected.detail?.ctx} />
145+
<PropertyList id={$selected.id} entries={$selected.detail.ctx} />
146146
{:else if $selected?.type === 'block' || $selected?.type === 'iteration'}
147147
<h2>State</h2>
148-
<PropertyList readonly id={$selected.id} entries={$selected.detail?.ctx} />
148+
<PropertyList readonly id={$selected.id} entries={$selected.detail.ctx} />
149149
{:else if $selected?.type === 'element'}
150150
<h2>Attributes</h2>
151-
<PropertyList readonly id={$selected.id} entries={$selected.detail?.attributes} />
151+
<PropertyList readonly id={$selected.id} entries={$selected.detail.attributes} />
152152

153153
<Divider type="horizontal" />
154154

0 commit comments

Comments
 (0)