Skip to content

Commit 03f1bec

Browse files
committed
perf(treeview): handle large JSON with "Load More"
1 parent a7722e5 commit 03f1bec

File tree

2 files changed

+51
-9
lines changed

2 files changed

+51
-9
lines changed

src/css/styles.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,25 @@ body {
540540
display: block;
541541
}
542542

543+
/* Load-more button for virtualized tree chunks */
544+
.tree-load-more {
545+
display: block;
546+
margin: var(--space-xs) 0 var(--space-xs) var(--space-lg);
547+
padding: 2px var(--space-sm);
548+
font-family: var(--font-primary);
549+
font-size: var(--font-size-xs);
550+
color: var(--color-text-muted);
551+
background: transparent;
552+
border: 1px dashed var(--color-border);
553+
border-radius: var(--radius-sm);
554+
cursor: pointer;
555+
transition: color 0.15s, border-color 0.15s;
556+
}
557+
558+
.tree-load-more:hover {
559+
color: var(--color-accent);
560+
border-color: var(--color-accent);
561+
}
543562

544563
/* Context Menu */
545564
.context-menu {

src/js/editor/treeView.js

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
*/
44

55
class TreeView {
6+
/** Max children to render at once before showing a "Load more" button */
7+
static CHUNK_SIZE = 100;
8+
69
constructor(container) {
710
this.container = container;
811
this.data = null;
@@ -202,16 +205,36 @@ class TreeView {
202205
}
203206

204207
populateChildren(container, value, parentPathArray) {
205-
if (Array.isArray(value)) {
206-
value.forEach((item, index) => {
207-
const childNode = this.createNode(item, index.toString(), parentPathArray);
208-
container.appendChild(childNode);
209-
});
210-
} else {
211-
Object.entries(value).forEach(([key, val]) => {
212-
const childNode = this.createNode(val, key, parentPathArray);
213-
container.appendChild(childNode);
208+
const entries = Array.isArray(value)
209+
? value.map((item, index) => ({ key: index.toString(), val: item }))
210+
: Object.entries(value).map(([key, val]) => ({ key, val }));
211+
212+
this._renderChunk(container, entries, 0, parentPathArray);
213+
}
214+
215+
/**
216+
* Render a slice of entries into `container`, appending a "Load more" button
217+
* if there are remaining items beyond this chunk.
218+
*/
219+
_renderChunk(container, entries, startIndex, parentPathArray) {
220+
const end = Math.min(startIndex + TreeView.CHUNK_SIZE, entries.length);
221+
222+
for (let i = startIndex; i < end; i++) {
223+
const { key, val } = entries[i];
224+
container.appendChild(this.createNode(val, key, parentPathArray));
225+
}
226+
227+
if (end < entries.length) {
228+
const remaining = entries.length - end;
229+
const loadMoreBtn = document.createElement('button');
230+
loadMoreBtn.className = 'tree-load-more';
231+
loadMoreBtn.textContent = `Load ${Math.min(remaining, TreeView.CHUNK_SIZE)} more… (${remaining} remaining)`;
232+
loadMoreBtn.addEventListener('click', (e) => {
233+
e.stopPropagation();
234+
loadMoreBtn.remove();
235+
this._renderChunk(container, entries, end, parentPathArray);
214236
});
237+
container.appendChild(loadMoreBtn);
215238
}
216239
}
217240

0 commit comments

Comments
 (0)