@hozu/devtools 0.16.0 → 0.17.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/dist/overlay/app.js +270 -31
- package/dist/overlay/app.js.map +1 -1
- package/dist/overlay/assets.d.ts +44 -0
- package/dist/overlay/assets.d.ts.map +1 -0
- package/dist/overlay/assets.js +294 -0
- package/dist/overlay/assets.js.map +1 -0
- package/dist/overlay/look.d.ts +2 -0
- package/dist/overlay/look.d.ts.map +1 -1
- package/dist/overlay/look.js +117 -32
- package/dist/overlay/look.js.map +1 -1
- package/dist/overlay/measure.d.ts +18 -0
- package/dist/overlay/measure.d.ts.map +1 -0
- package/dist/overlay/measure.js +33 -0
- package/dist/overlay/measure.js.map +1 -0
- package/dist/overlay/notes.js +1 -1
- package/dist/overlay/notes.js.map +1 -1
- package/dist/overlay/style.d.ts +2 -2
- package/dist/overlay/style.d.ts.map +1 -1
- package/dist/overlay/style.js +87 -0
- package/dist/overlay/style.js.map +1 -1
- package/dist/plain.d.ts.map +1 -1
- package/dist/plain.js +6 -5
- package/dist/plain.js.map +1 -1
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +17 -3
- package/dist/prompt.js.map +1 -1
- package/dist/theme.d.ts +3 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +50 -3
- package/dist/theme.js.map +1 -1
- package/package.json +2 -2
package/dist/overlay/app.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { describeFor, friendlyName, questionFor } from '../plain.js';
|
|
2
2
|
import { joinRequests, labelOf, openRequestsLine, requestMarkdown, scopesFor, } from '../prompt.js';
|
|
3
3
|
import { held, hold, node, one, page, remove, save, saved, theme, tree } from './api.js';
|
|
4
|
+
import { assetsBoard } from './assets.js';
|
|
4
5
|
import { h, read, write } from './dom.js';
|
|
5
6
|
import { drawer } from './effects.js';
|
|
6
7
|
import { previewLabel, renderLayers } from './layers.js';
|
|
7
8
|
import { logo } from './logo.js';
|
|
8
9
|
import { lookSection, preview } from './look.js';
|
|
10
|
+
import { distances, sizeOf } from './measure.js';
|
|
9
11
|
import { agentNotes } from './notes.js';
|
|
10
12
|
import { css, outlineCss } from './style.js';
|
|
11
13
|
import { firstText, previewText, restoreText, textSection } from './text.js';
|
|
@@ -31,6 +33,9 @@ const state = {
|
|
|
31
33
|
};
|
|
32
34
|
const persist = () => write(key, state);
|
|
33
35
|
const host = document.createElement('hozu-devtools');
|
|
36
|
+
host.setAttribute('data-lenis-prevent', '');
|
|
37
|
+
for (const type of ['wheel', 'touchstart', 'touchmove', 'keydown'])
|
|
38
|
+
host.addEventListener(type, (event) => event.stopPropagation(), { passive: true });
|
|
34
39
|
const shadow = host.attachShadow({ mode: 'open' });
|
|
35
40
|
const root = h('div', { class: 'root' });
|
|
36
41
|
const hover = h('div', { class: 'box', hidden: true }, [h('div', { class: 'tag' })]);
|
|
@@ -59,7 +64,119 @@ const api = drawer({
|
|
|
59
64
|
},
|
|
60
65
|
closed: () => { },
|
|
61
66
|
});
|
|
62
|
-
|
|
67
|
+
const screenCookie = 'hozu-dev-preview';
|
|
68
|
+
const screenOf = () => {
|
|
69
|
+
const raw = new RegExp(`(?:^|;\\s*)${screenCookie}=([^;]+)`).exec(document.cookie)?.[1];
|
|
70
|
+
try {
|
|
71
|
+
return raw ? decodeURIComponent(raw) : null;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const setScreen = (value) => {
|
|
78
|
+
document.cookie = value
|
|
79
|
+
? `${screenCookie}=${encodeURIComponent(value)}; path=/; SameSite=Lax`
|
|
80
|
+
: `${screenCookie}=; path=/; max-age=0; SameSite=Lax`;
|
|
81
|
+
};
|
|
82
|
+
const showKey = 'hozu-devtools:assets-show';
|
|
83
|
+
function showInstances(c) {
|
|
84
|
+
const here = c.uses.flatMap((u) => [...doc.querySelectorAll(`[data-hz="${CSS.escape(u.node)}"]`)]);
|
|
85
|
+
if (!here.length) {
|
|
86
|
+
const page = c.uses.flatMap((u) => u.pages).find((p) => !p.params);
|
|
87
|
+
if (!page)
|
|
88
|
+
return;
|
|
89
|
+
try {
|
|
90
|
+
sessionStorage.setItem(showKey, c.id);
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
93
|
+
win.location.href = page.path;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
assets.close();
|
|
97
|
+
state.mode = 'select';
|
|
98
|
+
state.picks = [
|
|
99
|
+
...state.picks.filter(hasContent),
|
|
100
|
+
...here.map((el) => ({
|
|
101
|
+
id: el.getAttribute('data-hz') ?? '',
|
|
102
|
+
index: indexOf(el),
|
|
103
|
+
note: '',
|
|
104
|
+
scope: 'component',
|
|
105
|
+
visible: visibleOf(el),
|
|
106
|
+
})),
|
|
107
|
+
];
|
|
108
|
+
state.active = state.picks.length - 1;
|
|
109
|
+
state.panel = 'inspector';
|
|
110
|
+
persist();
|
|
111
|
+
renderDock();
|
|
112
|
+
drawPicks();
|
|
113
|
+
void renderPanel();
|
|
114
|
+
}
|
|
115
|
+
const assets = assetsBoard({
|
|
116
|
+
plain: state.audience === 'builder',
|
|
117
|
+
theme: () => theme(),
|
|
118
|
+
stylesheets: () => [...doc.querySelectorAll('link[rel="stylesheet"]')].map((l) => l.href).filter(Boolean),
|
|
119
|
+
show: (c) => showInstances(c),
|
|
120
|
+
change: (c, note) => {
|
|
121
|
+
const first = c.uses[0];
|
|
122
|
+
if (!first)
|
|
123
|
+
return;
|
|
124
|
+
state.picks.push({ id: first.node, index: 0, note, scope: 'component', visible: '' });
|
|
125
|
+
state.active = state.picks.length - 1;
|
|
126
|
+
persist();
|
|
127
|
+
assets.close();
|
|
128
|
+
renderDock();
|
|
129
|
+
open('changes', null, 'draft');
|
|
130
|
+
},
|
|
131
|
+
screen: (route, path, name) => {
|
|
132
|
+
setScreen(`${route}:${name}`);
|
|
133
|
+
if (win.location.pathname === path)
|
|
134
|
+
win.location.reload();
|
|
135
|
+
else
|
|
136
|
+
win.location.href = path;
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
async function screensSection() {
|
|
140
|
+
const res = await fetch(`/_hozu/dev/previews?path=${encodeURIComponent(win.location.pathname)}`, {
|
|
141
|
+
cache: 'no-store',
|
|
142
|
+
}).catch(() => null);
|
|
143
|
+
const out = res?.ok
|
|
144
|
+
? (await res.json())
|
|
145
|
+
: null;
|
|
146
|
+
if (!out?.route || !out.previews.length)
|
|
147
|
+
return null;
|
|
148
|
+
return h('div', { class: 'sec' }, [
|
|
149
|
+
h('div', { class: 'label' }, ['Previews (previews.ts)']),
|
|
150
|
+
...out.previews.map((p) => {
|
|
151
|
+
const value = `${out.route}:${p.name}`;
|
|
152
|
+
const on = out.current === value;
|
|
153
|
+
return h('div', { class: 'look' }, [
|
|
154
|
+
h('span', { class: 'what' }, [p.name]),
|
|
155
|
+
h('button', {
|
|
156
|
+
class: on ? 'link done' : 'link',
|
|
157
|
+
type: 'button',
|
|
158
|
+
onclick: () => {
|
|
159
|
+
setScreen(on ? null : value);
|
|
160
|
+
win.location.reload();
|
|
161
|
+
},
|
|
162
|
+
}, [on ? 'Exit' : 'Preview']),
|
|
163
|
+
]);
|
|
164
|
+
}),
|
|
165
|
+
]);
|
|
166
|
+
}
|
|
167
|
+
root.append(bench, panel, dock, api.el, assets.board);
|
|
168
|
+
try {
|
|
169
|
+
const pending = sessionStorage.getItem(showKey);
|
|
170
|
+
if (pending) {
|
|
171
|
+
sessionStorage.removeItem(showKey);
|
|
172
|
+
void assets.catalog().then((list) => {
|
|
173
|
+
const c = list?.find((x) => x.id === pending);
|
|
174
|
+
if (c)
|
|
175
|
+
setTimeout(() => showInstances(c), 300);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch { }
|
|
63
180
|
document.documentElement.append(host);
|
|
64
181
|
const darkScheme = matchMedia('(prefers-color-scheme: dark)');
|
|
65
182
|
function applyTheme() {
|
|
@@ -72,6 +189,8 @@ let win = window;
|
|
|
72
189
|
let frameEl = null;
|
|
73
190
|
const frames = h('div');
|
|
74
191
|
let outline = null;
|
|
192
|
+
let measuring = false;
|
|
193
|
+
const measure = h('div', { class: 'measure', hidden: true });
|
|
75
194
|
const agent = agentNotes({
|
|
76
195
|
doc: () => doc,
|
|
77
196
|
win: () => win,
|
|
@@ -89,7 +208,7 @@ function mountOutline(target) {
|
|
|
89
208
|
outline?.remove();
|
|
90
209
|
const el = target.createElement('hozu-devtools-outline');
|
|
91
210
|
el.style.cssText = 'all:initial;position:fixed;inset:0;pointer-events:none;z-index:2147483646';
|
|
92
|
-
el.attachShadow({ mode: 'open' }).append(h('style', {}, [outlineCss]), frames, boxes, agent.layer, hover);
|
|
211
|
+
el.attachShadow({ mode: 'open' }).append(h('style', {}, [outlineCss]), frames, boxes, agent.layer, hover, measure);
|
|
93
212
|
target.documentElement.append(el);
|
|
94
213
|
outline = el;
|
|
95
214
|
}
|
|
@@ -131,6 +250,9 @@ function place(box, el) {
|
|
|
131
250
|
target.style.width = `${r.width + 4}px`;
|
|
132
251
|
target.style.height = `${r.height + 4}px`;
|
|
133
252
|
}
|
|
253
|
+
const size = box.querySelector(':scope > .size');
|
|
254
|
+
if (size)
|
|
255
|
+
size.textContent = sizeOf(r);
|
|
134
256
|
const tag = box.firstElementChild;
|
|
135
257
|
if (!tag?.classList.contains('tag'))
|
|
136
258
|
return;
|
|
@@ -175,6 +297,37 @@ async function showHover(el, force = false) {
|
|
|
175
297
|
if (hovered === el)
|
|
176
298
|
tag.replaceChildren(...tagText(n, el));
|
|
177
299
|
}
|
|
300
|
+
function drawMeasure() {
|
|
301
|
+
const active = state.picks[state.active];
|
|
302
|
+
const from = active ? elementOf(active) : hovered;
|
|
303
|
+
const to = active ? hovered : (hovered?.parentElement?.closest('[data-hz]') ?? null);
|
|
304
|
+
if (!measuring || state.mode !== 'select' || !from || !to || from === to) {
|
|
305
|
+
measure.hidden = true;
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const a = from.getBoundingClientRect();
|
|
309
|
+
const b = to.getBoundingClientRect();
|
|
310
|
+
const px = (n) => `${n}px`;
|
|
311
|
+
const target = h('div', { class: 'm-target' });
|
|
312
|
+
Object.assign(target.style, { left: px(b.left), top: px(b.top), width: px(b.width), height: px(b.height) });
|
|
313
|
+
const parts = [target];
|
|
314
|
+
for (const l of distances(a, b)) {
|
|
315
|
+
const line = h('div', { class: `m-line ${l.axis}` });
|
|
316
|
+
const label = h('div', { class: 'm-label' }, [String(Math.round(l.to - l.from))]);
|
|
317
|
+
const mid = (l.from + l.to) / 2;
|
|
318
|
+
if (l.axis === 'h') {
|
|
319
|
+
Object.assign(line.style, { left: px(l.from), top: px(l.at), width: px(l.to - l.from) });
|
|
320
|
+
Object.assign(label.style, { left: px(mid), top: px(l.at) });
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
Object.assign(line.style, { left: px(l.at), top: px(l.from), height: px(l.to - l.from) });
|
|
324
|
+
Object.assign(label.style, { left: px(l.at), top: px(mid) });
|
|
325
|
+
}
|
|
326
|
+
parts.push(line, label);
|
|
327
|
+
}
|
|
328
|
+
measure.replaceChildren(...parts);
|
|
329
|
+
measure.hidden = false;
|
|
330
|
+
}
|
|
178
331
|
function drawPicks() {
|
|
179
332
|
for (const p of state.picks) {
|
|
180
333
|
preview(elementOf(p), p.style ?? []);
|
|
@@ -185,6 +338,7 @@ function drawPicks() {
|
|
|
185
338
|
boxes.replaceChildren(...state.picks.map((p, i) => {
|
|
186
339
|
const box = framed(h('div', { class: 'box selected' }, [
|
|
187
340
|
state.picks.length > 1 ? h('div', { class: 'badge' }, [String(i + 1)]) : null,
|
|
341
|
+
h('div', { class: 'size' }),
|
|
188
342
|
]), true);
|
|
189
343
|
place(box, state.mode === 'select' ? elementOf(p) : null);
|
|
190
344
|
return box;
|
|
@@ -203,6 +357,7 @@ function frame() {
|
|
|
203
357
|
}
|
|
204
358
|
if (hovered && (state.mode === 'select' || forced))
|
|
205
359
|
place(hover, hovered);
|
|
360
|
+
drawMeasure();
|
|
206
361
|
agent.frame();
|
|
207
362
|
requestAnimationFrame(frame);
|
|
208
363
|
}
|
|
@@ -272,12 +427,13 @@ function listen(target) {
|
|
|
272
427
|
return;
|
|
273
428
|
const mouse = event;
|
|
274
429
|
const clicked = markedFrom(event);
|
|
275
|
-
const el =
|
|
430
|
+
const el = clicked;
|
|
276
431
|
if (!el)
|
|
277
432
|
return;
|
|
278
433
|
select({ id: el.getAttribute('data-hz') ?? '', index: indexOf(el), visible: visibleOf(el) }, mouse.shiftKey);
|
|
279
434
|
}, { capture: true, signal });
|
|
280
435
|
target.addEventListener('pointermove', (event) => {
|
|
436
|
+
measuring = event.altKey;
|
|
281
437
|
if (state.mode !== 'select')
|
|
282
438
|
return;
|
|
283
439
|
const el = ours(event) ? null : markedFrom(event);
|
|
@@ -285,30 +441,60 @@ function listen(target) {
|
|
|
285
441
|
void showHover(el);
|
|
286
442
|
}, { capture: true, passive: true, signal });
|
|
287
443
|
target.addEventListener('keydown', onKey, { capture: true, signal });
|
|
444
|
+
target.addEventListener('keyup', (event) => {
|
|
445
|
+
measuring = event.altKey;
|
|
446
|
+
}, { capture: true, signal });
|
|
447
|
+
target.addEventListener('blur', () => {
|
|
448
|
+
measuring = false;
|
|
449
|
+
}, { signal });
|
|
288
450
|
return stop;
|
|
289
451
|
}
|
|
452
|
+
/** The marked parts directly inside `parent` (or the page), in document order. */
|
|
453
|
+
function partsIn(parent) {
|
|
454
|
+
const all = [...(parent ?? doc).querySelectorAll('[data-hz]')];
|
|
455
|
+
return all.filter((e) => (e.parentElement?.closest('[data-hz]') ?? null) === parent);
|
|
456
|
+
}
|
|
290
457
|
function walk(direction) {
|
|
291
458
|
const active = state.picks[state.active];
|
|
292
459
|
if (!active)
|
|
293
460
|
return;
|
|
294
461
|
const el = elementOf(active);
|
|
295
462
|
const own = el?.getAttribute('data-hz') === active.id;
|
|
463
|
+
const beside = () => {
|
|
464
|
+
if (!el || !own)
|
|
465
|
+
return null;
|
|
466
|
+
const list = partsIn(el.parentElement?.closest('[data-hz]') ?? null).filter((e) => {
|
|
467
|
+
const b = e.getBoundingClientRect();
|
|
468
|
+
return e === el || (b.width > 0 && b.height > 0);
|
|
469
|
+
});
|
|
470
|
+
const at = list.indexOf(el);
|
|
471
|
+
return list[(at + (direction === 'next' ? 1 : -1) + list.length) % list.length] ?? null;
|
|
472
|
+
};
|
|
296
473
|
const next = direction === 'up'
|
|
297
474
|
? own
|
|
298
475
|
? el?.parentElement?.closest('[data-hz]')
|
|
299
476
|
: el
|
|
300
|
-
:
|
|
301
|
-
?
|
|
302
|
-
|
|
303
|
-
|
|
477
|
+
: direction === 'down'
|
|
478
|
+
? own
|
|
479
|
+
? el?.querySelector('[data-hz]')
|
|
480
|
+
: null
|
|
481
|
+
: beside();
|
|
482
|
+
if (!next || ((direction === 'next' || direction === 'previous') && next === el))
|
|
304
483
|
return;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
484
|
+
const moved = { id: next.getAttribute('data-hz') ?? '', index: indexOf(next), visible: visibleOf(next) };
|
|
485
|
+
if (hasContent(active)) {
|
|
486
|
+
const existing = state.picks.findIndex((p) => p.id === moved.id && p.index === moved.index);
|
|
487
|
+
if (existing >= 0)
|
|
488
|
+
state.active = existing;
|
|
489
|
+
else {
|
|
490
|
+
state.picks.push({ ...moved, note: '', scope: null });
|
|
491
|
+
state.active = state.picks.length - 1;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
preview(el, []);
|
|
496
|
+
state.picks[state.active] = { ...moved, note: '', scope: null };
|
|
497
|
+
}
|
|
312
498
|
persist();
|
|
313
499
|
drawPicks();
|
|
314
500
|
void renderPanel();
|
|
@@ -325,6 +511,8 @@ function setMode(mode) {
|
|
|
325
511
|
const typingIn = (event) => event.composedPath().some((t) => ['TEXTAREA', 'INPUT', 'SELECT'].includes(t.tagName));
|
|
326
512
|
function onKey(event) {
|
|
327
513
|
const typing = typingIn(event);
|
|
514
|
+
if (event.key === 'Escape' && assets.isOpen())
|
|
515
|
+
return assets.close();
|
|
328
516
|
if (event.altKey && event.shiftKey && event.code === 'KeyS') {
|
|
329
517
|
event.preventDefault();
|
|
330
518
|
return setMode(state.mode === 'select' ? 'browse' : 'select');
|
|
@@ -340,12 +528,27 @@ function onKey(event) {
|
|
|
340
528
|
persist();
|
|
341
529
|
return void renderPanel();
|
|
342
530
|
}
|
|
343
|
-
if (
|
|
344
|
-
|
|
345
|
-
state.
|
|
346
|
-
|
|
347
|
-
|
|
531
|
+
if (event.key === 'Alt') {
|
|
532
|
+
measuring = true;
|
|
533
|
+
if (state.mode === 'select')
|
|
534
|
+
event.preventDefault();
|
|
535
|
+
return;
|
|
348
536
|
}
|
|
537
|
+
if (state.mode !== 'select' || !state.picks.length || event.composedPath().includes(host))
|
|
538
|
+
return;
|
|
539
|
+
const step = event.key === 'ArrowUp' || (event.key === 'Enter' && event.shiftKey)
|
|
540
|
+
? 'up'
|
|
541
|
+
: event.key === 'ArrowDown' || event.key === 'Enter'
|
|
542
|
+
? 'down'
|
|
543
|
+
: event.key === 'Tab'
|
|
544
|
+
? event.shiftKey
|
|
545
|
+
? 'previous'
|
|
546
|
+
: 'next'
|
|
547
|
+
: null;
|
|
548
|
+
if (!step)
|
|
549
|
+
return;
|
|
550
|
+
event.preventDefault();
|
|
551
|
+
walk(step);
|
|
349
552
|
}
|
|
350
553
|
let listening = listen(window);
|
|
351
554
|
const reload = () => win.location.reload();
|
|
@@ -440,6 +643,12 @@ function renderDock() {
|
|
|
440
643
|
void renderPanel();
|
|
441
644
|
},
|
|
442
645
|
}, ['Layers']),
|
|
646
|
+
h('button', {
|
|
647
|
+
class: 'act',
|
|
648
|
+
type: 'button',
|
|
649
|
+
title: 'Every component of the app, its variants, previews and uses; and the design tokens',
|
|
650
|
+
onclick: () => void assets.open(),
|
|
651
|
+
}, ['Assets']),
|
|
443
652
|
h('button', {
|
|
444
653
|
class: 'act',
|
|
445
654
|
type: 'button',
|
|
@@ -455,7 +664,7 @@ function renderDock() {
|
|
|
455
664
|
state.panel = state.picks.length ? 'inspector' : null;
|
|
456
665
|
openBench();
|
|
457
666
|
},
|
|
458
|
-
}, ['
|
|
667
|
+
}, ['Frame']),
|
|
459
668
|
h('button', {
|
|
460
669
|
class: 'act gear',
|
|
461
670
|
type: 'button',
|
|
@@ -467,6 +676,17 @@ function renderDock() {
|
|
|
467
676
|
void renderPanel();
|
|
468
677
|
},
|
|
469
678
|
}, ['⚙']),
|
|
679
|
+
screenOf()
|
|
680
|
+
? h('button', {
|
|
681
|
+
class: 'previewing',
|
|
682
|
+
type: 'button',
|
|
683
|
+
title: 'Exit the preview from previews.ts',
|
|
684
|
+
onclick: () => {
|
|
685
|
+
setScreen(null);
|
|
686
|
+
win.location.reload();
|
|
687
|
+
},
|
|
688
|
+
}, [`Screen: ${screenOf().slice(screenOf().indexOf(':') + 1)}`, ' · Exit'])
|
|
689
|
+
: null,
|
|
470
690
|
held()
|
|
471
691
|
? h('button', {
|
|
472
692
|
class: 'previewing',
|
|
@@ -479,7 +699,8 @@ function renderDock() {
|
|
|
479
699
|
? h('div', { class: 'tip', role: 'note' }, [
|
|
480
700
|
h('span', {}, [h('kbd', {}, ['Click']), ' a part to select it']),
|
|
481
701
|
h('span', {}, [h('kbd', {}, ['Shift']), '+click adds another']),
|
|
482
|
-
h('span', {}, [h('kbd', {}, ['
|
|
702
|
+
h('span', {}, [h('kbd', {}, ['⇧ Enter']), ' picks its parent']),
|
|
703
|
+
h('span', {}, [h('kbd', {}, ['Alt']), ' measures']),
|
|
483
704
|
h('span', {}, [h('kbd', {}, ['Esc']), ' stops']),
|
|
484
705
|
])
|
|
485
706
|
: null,
|
|
@@ -979,8 +1200,13 @@ async function renderPanel() {
|
|
|
979
1200
|
return renderSettings();
|
|
980
1201
|
if (state.panel === 'notes')
|
|
981
1202
|
return agent.render(panel);
|
|
982
|
-
if (state.panel === 'layers')
|
|
983
|
-
|
|
1203
|
+
if (state.panel === 'layers') {
|
|
1204
|
+
await renderLayers(panel, await tree(win.location.pathname), layersHost(() => open(state.picks.length ? 'inspector' : null)));
|
|
1205
|
+
const screens = await screensSection();
|
|
1206
|
+
if (screens)
|
|
1207
|
+
panel.append(screens);
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
984
1210
|
const active = state.picks[state.active];
|
|
985
1211
|
if (state.panel !== 'inspector' || !active) {
|
|
986
1212
|
panel.hidden = state.view !== 'workbench';
|
|
@@ -1065,7 +1291,7 @@ async function renderChanges() {
|
|
|
1065
1291
|
const done = h('button', {
|
|
1066
1292
|
class: 'link done',
|
|
1067
1293
|
type: 'button',
|
|
1068
|
-
title: '
|
|
1294
|
+
title: 'Resolved or not needed: remove it',
|
|
1069
1295
|
onclick: async () => {
|
|
1070
1296
|
if (!armed) {
|
|
1071
1297
|
armed = true;
|
|
@@ -1075,7 +1301,7 @@ async function renderChanges() {
|
|
|
1075
1301
|
await remove(r.number);
|
|
1076
1302
|
void renderPanel();
|
|
1077
1303
|
},
|
|
1078
|
-
}, ['
|
|
1304
|
+
}, ['Resolve']);
|
|
1079
1305
|
return h('div', { class: 'req' }, [
|
|
1080
1306
|
h('span', { class: 'n' }, [r.number]),
|
|
1081
1307
|
h('button', { class: 't open-req', type: 'button', onclick: () => open('changes', r.number, 'saved') }, [r.title]),
|
|
@@ -1088,7 +1314,7 @@ async function renderChanges() {
|
|
|
1088
1314
|
message ? h('div', { class: 'notice' }, message) : null,
|
|
1089
1315
|
...(list.length
|
|
1090
1316
|
? [...list].reverse().map(row)
|
|
1091
|
-
: [h('div', { class: 'empty' }, ['No open requests.
|
|
1317
|
+
: [h('div', { class: 'empty' }, ['No open requests. Resolved ones are removed.'])]),
|
|
1092
1318
|
list.length
|
|
1093
1319
|
? h('div', { class: 'sec' }, [
|
|
1094
1320
|
h('div', { class: 'choice' }, [
|
|
@@ -1200,7 +1426,7 @@ async function renderRequest(number) {
|
|
|
1200
1426
|
renderDock();
|
|
1201
1427
|
open('changes', null, 'saved');
|
|
1202
1428
|
},
|
|
1203
|
-
}, ['
|
|
1429
|
+
}, ['Resolve · remove']);
|
|
1204
1430
|
panel.replaceChildren(h('div', { class: 'head' }, [
|
|
1205
1431
|
h('button', { class: 'back', type: 'button', onclick: () => open('changes', null, 'saved') }, [
|
|
1206
1432
|
'← Saved',
|
|
@@ -1299,7 +1525,10 @@ function renderSettings() {
|
|
|
1299
1525
|
['Alt+Shift+S', 'Select on or off'],
|
|
1300
1526
|
['Click', 'Select'],
|
|
1301
1527
|
['Shift+click', 'Add to the request'],
|
|
1302
|
-
['
|
|
1528
|
+
['Shift+Enter', 'Select the area around it'],
|
|
1529
|
+
['Enter', 'Select inside it'],
|
|
1530
|
+
['Tab / Shift+Tab', 'Next / previous part beside it'],
|
|
1531
|
+
['Alt (hold)', 'Measure: W × H and the distance to the part under the pointer'],
|
|
1303
1532
|
['Double-click', 'Select a text'],
|
|
1304
1533
|
['↑ ↓', 'Around it / inside it'],
|
|
1305
1534
|
['Esc', 'Back to Browse'],
|
|
@@ -1316,6 +1545,10 @@ const left = h('div', { class: 'bench-left' });
|
|
|
1316
1545
|
const stage = h('div', { class: 'stage' });
|
|
1317
1546
|
const sizer = h('div', { class: 'sizer' });
|
|
1318
1547
|
const bar = h('div', { class: 'bench-bar' });
|
|
1548
|
+
addEventListener('keydown', (event) => {
|
|
1549
|
+
if (state.view === 'workbench' && win !== window)
|
|
1550
|
+
onKey(event);
|
|
1551
|
+
}, true);
|
|
1319
1552
|
function retarget(frame) {
|
|
1320
1553
|
listening.abort();
|
|
1321
1554
|
const w = frame?.contentWindow ?? null;
|
|
@@ -1418,7 +1651,13 @@ function renderBar() {
|
|
|
1418
1651
|
'aria-pressed': api.isOpen() ? 'true' : 'false',
|
|
1419
1652
|
onclick: () => api.toggle(),
|
|
1420
1653
|
}, ['API']),
|
|
1421
|
-
h('button', {
|
|
1654
|
+
h('button', {
|
|
1655
|
+
class: 'act',
|
|
1656
|
+
type: 'button',
|
|
1657
|
+
title: 'Every component of the app, its variants, previews and uses; and the design tokens',
|
|
1658
|
+
onclick: () => void assets.open(),
|
|
1659
|
+
}, ['Assets']),
|
|
1660
|
+
h('button', { class: 'act exit', type: 'button', onclick: () => closeBench() }, ['Exit frame']),
|
|
1422
1661
|
]));
|
|
1423
1662
|
}
|
|
1424
1663
|
async function renderLeft() {
|
|
@@ -1435,7 +1674,7 @@ function openBench() {
|
|
|
1435
1674
|
bench.hidden = false;
|
|
1436
1675
|
const frame = h('iframe', {
|
|
1437
1676
|
src: location.href,
|
|
1438
|
-
title: 'The page in
|
|
1677
|
+
title: 'The page in Frame',
|
|
1439
1678
|
'data-hozu-bench': true,
|
|
1440
1679
|
});
|
|
1441
1680
|
frame.addEventListener('load', () => {
|
|
@@ -1506,7 +1745,7 @@ addEventListener('resize', layout);
|
|
|
1506
1745
|
addEventListener('keydown', (event) => {
|
|
1507
1746
|
if (event.key === 'Escape' && !typingIn(event) && bench.classList.contains('layers-open'))
|
|
1508
1747
|
closeLayers();
|
|
1509
|
-
});
|
|
1748
|
+
}, true);
|
|
1510
1749
|
renderDock();
|
|
1511
1750
|
drawPicks();
|
|
1512
1751
|
void renderPanel();
|