@fluixi/devtools 0.2.0-alpha.2 → 0.2.0-alpha.4
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 +80 -2
- package/dist/callsite.cjs +72 -0
- package/dist/callsite.d.ts +22 -0
- package/dist/callsite.d.ts.map +1 -0
- package/dist/callsite.js +82 -0
- package/dist/callsite.mjs +51 -0
- package/dist/change-view.cjs +134 -0
- package/dist/change-view.d.ts +10 -0
- package/dist/change-view.d.ts.map +1 -0
- package/dist/change-view.js +102 -0
- package/dist/change-view.mjs +111 -0
- package/dist/copy.cjs +63 -0
- package/dist/copy.d.ts +9 -0
- package/dist/copy.d.ts.map +1 -0
- package/dist/copy.js +52 -0
- package/dist/copy.mjs +42 -0
- package/dist/describe.cjs +55 -0
- package/dist/describe.d.ts +3 -0
- package/dist/describe.d.ts.map +1 -0
- package/dist/describe.js +47 -0
- package/dist/describe.mjs +34 -0
- package/dist/detail-panel.cjs +307 -0
- package/dist/detail-panel.d.ts +17 -0
- package/dist/detail-panel.d.ts.map +1 -0
- package/dist/detail-panel.js +217 -0
- package/dist/detail-panel.mjs +284 -0
- package/dist/diff.cjs +225 -0
- package/dist/diff.d.ts +31 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +132 -0
- package/dist/diff.mjs +202 -0
- package/dist/dom.cjs +204 -0
- package/dist/dom.d.ts +81 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +269 -0
- package/dist/dom.mjs +183 -0
- package/dist/export.cjs +221 -0
- package/dist/export.d.ts +55 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +90 -0
- package/dist/export.mjs +209 -0
- package/dist/float.cjs +232 -0
- package/dist/float.d.ts +54 -0
- package/dist/float.d.ts.map +1 -0
- package/dist/float.js +256 -0
- package/dist/float.mjs +211 -0
- package/dist/format.cjs +175 -0
- package/dist/format.d.ts +16 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +188 -0
- package/dist/format.mjs +154 -0
- package/dist/graph-view.cjs +893 -0
- package/dist/graph-view.d.ts +79 -2
- package/dist/graph-view.d.ts.map +1 -1
- package/dist/graph-view.js +866 -50
- package/dist/graph-view.mjs +870 -0
- package/dist/highlight.cjs +140 -0
- package/dist/highlight.d.ts +56 -0
- package/dist/highlight.d.ts.map +1 -0
- package/dist/highlight.js +154 -0
- package/dist/highlight.mjs +119 -0
- package/dist/history.cjs +95 -0
- package/dist/history.d.ts +59 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +85 -0
- package/dist/history.mjs +74 -0
- package/dist/hook.cjs +1562 -0
- package/dist/hook.d.ts +60 -0
- package/dist/hook.d.ts.map +1 -0
- package/dist/hook.js +142 -0
- package/dist/hook.mjs +1553 -0
- package/dist/index.cjs +4552 -0
- package/dist/index.d.ts +44 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -1
- package/dist/index.mjs +4544 -0
- package/dist/inspector.cjs +688 -0
- package/dist/inspector.d.ts +60 -0
- package/dist/inspector.d.ts.map +1 -0
- package/dist/inspector.js +415 -0
- package/dist/inspector.mjs +676 -0
- package/dist/instrument.cjs +497 -0
- package/dist/instrument.d.ts +147 -5
- package/dist/instrument.d.ts.map +1 -1
- package/dist/instrument.js +164 -44
- package/dist/instrument.mjs +487 -0
- package/dist/kind-filter.cjs +172 -0
- package/dist/kind-filter.d.ts +39 -0
- package/dist/kind-filter.d.ts.map +1 -0
- package/dist/kind-filter.js +151 -0
- package/dist/kind-filter.mjs +151 -0
- package/dist/menu.cjs +141 -0
- package/dist/menu.d.ts +37 -0
- package/dist/menu.d.ts.map +1 -0
- package/dist/menu.js +125 -0
- package/dist/menu.mjs +120 -0
- package/dist/observe.cjs +1352 -0
- package/dist/observe.d.ts +80 -0
- package/dist/observe.d.ts.map +1 -0
- package/dist/observe.js +893 -0
- package/dist/observe.mjs +1345 -0
- package/dist/palette.cjs +52 -0
- package/dist/palette.d.ts +11 -0
- package/dist/palette.d.ts.map +1 -0
- package/dist/palette.js +27 -0
- package/dist/palette.mjs +31 -0
- package/dist/path.cjs +45 -0
- package/dist/path.d.ts +19 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +49 -0
- package/dist/path.mjs +24 -0
- package/dist/plugin.cjs +87 -0
- package/dist/plugin.d.ts +121 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +74 -0
- package/dist/plugin.mjs +66 -0
- package/dist/plugins/context.cjs +98 -0
- package/dist/plugins/context.d.ts +10 -0
- package/dist/plugins/context.d.ts.map +1 -0
- package/dist/plugins/context.js +80 -0
- package/dist/plugins/context.mjs +75 -0
- package/dist/plugins/directives.cjs +98 -0
- package/dist/plugins/directives.d.ts +25 -0
- package/dist/plugins/directives.d.ts.map +1 -0
- package/dist/plugins/directives.js +78 -0
- package/dist/plugins/directives.mjs +75 -0
- package/dist/plugins/index.cjs +162 -0
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +9 -0
- package/dist/plugins/index.mjs +140 -0
- package/dist/source.cjs +111 -0
- package/dist/source.d.ts +72 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +153 -0
- package/dist/source.mjs +90 -0
- package/dist/timeline.cjs +350 -0
- package/dist/timeline.d.ts +30 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +271 -0
- package/dist/timeline.mjs +327 -0
- package/dist/tree.cjs +574 -0
- package/dist/tree.d.ts +128 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +645 -0
- package/dist/tree.mjs +551 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/value-pane.cjs +223 -0
- package/dist/value-pane.d.ts +10 -0
- package/dist/value-pane.d.ts.map +1 -0
- package/dist/value-pane.js +61 -0
- package/dist/value-pane.mjs +200 -0
- package/dist/wire.cjs +109 -0
- package/dist/wire.d.ts +100 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +93 -0
- package/dist/wire.mjs +89 -0
- package/package.json +17 -5
package/dist/float.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Taking a pane out of the layout and putting it back.
|
|
3
|
+
*
|
|
4
|
+
* The inspector, the timeline and the tree each live in a fixed corner of the panel. Reading
|
|
5
|
+
* one of them properly means giving it room, and the room has to come from the others. So
|
|
6
|
+
* each carries a button that lifts it into a card over everything, and the same button puts
|
|
7
|
+
* it back exactly where it was.
|
|
8
|
+
*
|
|
9
|
+
* The pane element itself is moved rather than re-rendered. Whatever drew into it keeps its
|
|
10
|
+
* handle on it, its listeners, and its scroll position — a floated timeline is the same
|
|
11
|
+
* timeline, not a copy of one.
|
|
12
|
+
*/
|
|
13
|
+
/** So a card cannot be dragged or resized into something unreadable. */
|
|
14
|
+
const MIN_W = 240;
|
|
15
|
+
const MIN_H = 160;
|
|
16
|
+
/**
|
|
17
|
+
* Pointer capture, for the reason the splitters need it: without it the events stop arriving
|
|
18
|
+
* once the pointer crosses the graph or an iframe, the release is never seen, and the card
|
|
19
|
+
* keeps following the mouse.
|
|
20
|
+
*/
|
|
21
|
+
function draggable(handle,
|
|
22
|
+
/** Total travel since the press, not the step since the last event. */
|
|
23
|
+
onMove, onStart) {
|
|
24
|
+
handle.addEventListener('pointerdown', (event) => {
|
|
25
|
+
if (event.button !== 0)
|
|
26
|
+
return;
|
|
27
|
+
// Capture retargets the click that follows onto the handle, so a button inside it would
|
|
28
|
+
// never hear its own click.
|
|
29
|
+
if (event.target.closest('button'))
|
|
30
|
+
return;
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
handle.setPointerCapture(event.pointerId);
|
|
33
|
+
const fromX = event.clientX;
|
|
34
|
+
const fromY = event.clientY;
|
|
35
|
+
onStart?.();
|
|
36
|
+
// Measured from where the press began. Adding up each step instead loses whatever a
|
|
37
|
+
// clamp refused, so dragging back out of a minimum grows the card immediately rather
|
|
38
|
+
// than when the pointer returns to where it stopped shrinking.
|
|
39
|
+
const move = (e) => onMove(e.clientX - fromX, e.clientY - fromY);
|
|
40
|
+
const stop = () => {
|
|
41
|
+
handle.removeEventListener('pointermove', move);
|
|
42
|
+
handle.removeEventListener('pointerup', stop);
|
|
43
|
+
handle.removeEventListener('pointercancel', stop);
|
|
44
|
+
handle.removeEventListener('lostpointercapture', stop);
|
|
45
|
+
if (handle.hasPointerCapture(event.pointerId))
|
|
46
|
+
handle.releasePointerCapture(event.pointerId);
|
|
47
|
+
};
|
|
48
|
+
handle.addEventListener('pointermove', move);
|
|
49
|
+
handle.addEventListener('pointerup', stop);
|
|
50
|
+
handle.addEventListener('pointercancel', stop);
|
|
51
|
+
handle.addEventListener('lostpointercapture', stop);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/** Enough of a cascade that two cards opened together do not sit on top of each other. */
|
|
55
|
+
let opened = 0;
|
|
56
|
+
/**
|
|
57
|
+
* The moving and resizing, on its own.
|
|
58
|
+
*
|
|
59
|
+
* Both a floated pane and the value pane want the same card, and writing the drag twice is
|
|
60
|
+
* how two of them end up behaving differently.
|
|
61
|
+
*/
|
|
62
|
+
export function floatCard(doc, title, at) {
|
|
63
|
+
const card = doc.createElement('div');
|
|
64
|
+
card.className = 'fx-float';
|
|
65
|
+
const spot = at ?? {
|
|
66
|
+
x: 60 + (opened % 4) * 28,
|
|
67
|
+
y: 60 + (opened % 4) * 28,
|
|
68
|
+
width: 360,
|
|
69
|
+
height: 280,
|
|
70
|
+
};
|
|
71
|
+
opened += 1;
|
|
72
|
+
const bar = doc.createElement('div');
|
|
73
|
+
bar.className = 'fx-float-bar';
|
|
74
|
+
const name = doc.createElement('span');
|
|
75
|
+
name.textContent = title;
|
|
76
|
+
bar.append(name);
|
|
77
|
+
card.append(bar);
|
|
78
|
+
// Kept here rather than read back from the element each move. offsetWidth is what the
|
|
79
|
+
// card ended up at, so once a size clamps, every further move measures from the clamp
|
|
80
|
+
// and the card grows when the pointer is still travelling the other way.
|
|
81
|
+
let x = spot.x;
|
|
82
|
+
let y = spot.y;
|
|
83
|
+
let w = spot.width;
|
|
84
|
+
let h = spot.height;
|
|
85
|
+
const apply = () => {
|
|
86
|
+
const view = doc.defaultView;
|
|
87
|
+
const vw = view?.innerWidth ?? w;
|
|
88
|
+
const vh = view?.innerHeight ?? h;
|
|
89
|
+
w = Math.min(Math.max(MIN_W, w), vw);
|
|
90
|
+
h = Math.min(Math.max(MIN_H, h), vh);
|
|
91
|
+
// Fully on screen: a card wider than the window puts its own resize handles past the
|
|
92
|
+
// edge, and then there is no way to make it smaller again.
|
|
93
|
+
x = Math.min(Math.max(0, x), Math.max(0, vw - w));
|
|
94
|
+
y = Math.min(Math.max(0, y), Math.max(0, vh - h));
|
|
95
|
+
card.style.left = `${x}px`;
|
|
96
|
+
card.style.top = `${y}px`;
|
|
97
|
+
card.style.width = `${w}px`;
|
|
98
|
+
card.style.height = `${h}px`;
|
|
99
|
+
};
|
|
100
|
+
// Every edge and corner, so a card against one side of the window can still be resized
|
|
101
|
+
// from the other.
|
|
102
|
+
let from = { x, y, w, h };
|
|
103
|
+
const remember = () => {
|
|
104
|
+
from = { x, y, w, h };
|
|
105
|
+
};
|
|
106
|
+
for (const edge of ['n', 's', 'e', 'w', 'ne', 'nw', 'se', 'sw']) {
|
|
107
|
+
const handle = doc.createElement('div');
|
|
108
|
+
handle.className = `fx-float-h fx-float-${edge}`;
|
|
109
|
+
card.append(handle);
|
|
110
|
+
draggable(handle, (dx, dy) => {
|
|
111
|
+
if (edge.includes('e'))
|
|
112
|
+
w = from.w + dx;
|
|
113
|
+
if (edge.includes('s'))
|
|
114
|
+
h = from.h + dy;
|
|
115
|
+
// A top or left edge leaves the opposite one where it is, so the card only moves
|
|
116
|
+
// by as much as the size actually gave.
|
|
117
|
+
if (edge.includes('w')) {
|
|
118
|
+
w = Math.max(MIN_W, from.w - dx);
|
|
119
|
+
x = from.x + from.w - w;
|
|
120
|
+
}
|
|
121
|
+
if (edge.includes('n')) {
|
|
122
|
+
h = Math.max(MIN_H, from.h - dy);
|
|
123
|
+
y = from.y + from.h - h;
|
|
124
|
+
}
|
|
125
|
+
apply();
|
|
126
|
+
}, remember);
|
|
127
|
+
}
|
|
128
|
+
draggable(bar, (dx, dy) => {
|
|
129
|
+
x = from.x + dx;
|
|
130
|
+
y = from.y + dy;
|
|
131
|
+
apply();
|
|
132
|
+
}, remember);
|
|
133
|
+
apply();
|
|
134
|
+
return { card, bar, remove: () => card.remove() };
|
|
135
|
+
}
|
|
136
|
+
export function makeFloatable(pane, options) {
|
|
137
|
+
const doc = pane.ownerDocument;
|
|
138
|
+
let card = null;
|
|
139
|
+
/** Where the pane came from, so it goes back there rather than at the end. */
|
|
140
|
+
let home = null;
|
|
141
|
+
const button = doc.createElement('button');
|
|
142
|
+
button.type = 'button';
|
|
143
|
+
button.className = 'fx-float-btn';
|
|
144
|
+
button.textContent = '⇱';
|
|
145
|
+
button.title = `Float ${options.title}`;
|
|
146
|
+
pane.classList.add('fx-floatable');
|
|
147
|
+
pane.append(button);
|
|
148
|
+
/**
|
|
149
|
+
* The panes rewrite their own contents — the inspector replaces its markup whenever the
|
|
150
|
+
* selection changes — which takes the button with it. Rather than asking each of them to
|
|
151
|
+
* leave it alone, it is put back when it goes.
|
|
152
|
+
*/
|
|
153
|
+
const keep = new MutationObserver(() => {
|
|
154
|
+
if (button.parentNode !== pane)
|
|
155
|
+
pane.append(button);
|
|
156
|
+
});
|
|
157
|
+
keep.observe(pane, { childList: true });
|
|
158
|
+
function dock() {
|
|
159
|
+
if (!card || !home)
|
|
160
|
+
return;
|
|
161
|
+
home.parent.insertBefore(pane, home.before);
|
|
162
|
+
card.remove();
|
|
163
|
+
card = null;
|
|
164
|
+
home = null;
|
|
165
|
+
pane.classList.remove('fx-floated');
|
|
166
|
+
button.textContent = '⇱';
|
|
167
|
+
button.title = `Float ${options.title}`;
|
|
168
|
+
options.onChange?.(false);
|
|
169
|
+
}
|
|
170
|
+
function float() {
|
|
171
|
+
if (card || !pane.parentNode)
|
|
172
|
+
return;
|
|
173
|
+
home = { parent: pane.parentNode, before: pane.nextSibling };
|
|
174
|
+
const built = floatCard(doc, options.title, options.at);
|
|
175
|
+
card = built.card;
|
|
176
|
+
card.append(pane);
|
|
177
|
+
doc.body.appendChild(card);
|
|
178
|
+
pane.classList.add('fx-floated');
|
|
179
|
+
button.textContent = '⇲';
|
|
180
|
+
button.title = `Put ${options.title} back`;
|
|
181
|
+
options.onChange?.(true);
|
|
182
|
+
}
|
|
183
|
+
button.addEventListener('click', (event) => {
|
|
184
|
+
event.stopPropagation();
|
|
185
|
+
if (card)
|
|
186
|
+
dock();
|
|
187
|
+
else
|
|
188
|
+
float();
|
|
189
|
+
});
|
|
190
|
+
return {
|
|
191
|
+
get floating() {
|
|
192
|
+
return card !== null;
|
|
193
|
+
},
|
|
194
|
+
toggle() {
|
|
195
|
+
if (card)
|
|
196
|
+
dock();
|
|
197
|
+
else
|
|
198
|
+
float();
|
|
199
|
+
return card !== null;
|
|
200
|
+
},
|
|
201
|
+
dock,
|
|
202
|
+
destroy() {
|
|
203
|
+
keep.disconnect();
|
|
204
|
+
dock();
|
|
205
|
+
button.remove();
|
|
206
|
+
pane.classList.remove('fx-floatable');
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
export const FLOAT_CSS = `
|
|
211
|
+
.fx-floatable { position: relative; }
|
|
212
|
+
.fx-float-btn {
|
|
213
|
+
position: absolute; top: 2px; right: 2px; z-index: 5;
|
|
214
|
+
width: 18px; height: 18px; padding: 0; line-height: 1;
|
|
215
|
+
font-size: 11px; color: var(--fx-muted, #8a90a2);
|
|
216
|
+
background: var(--fx-panel, #14161c);
|
|
217
|
+
border: 1px solid var(--fx-line, #262a35); border-radius: 4px;
|
|
218
|
+
cursor: pointer; opacity: 0; transition: opacity .12s;
|
|
219
|
+
}
|
|
220
|
+
.fx-floatable:hover .fx-float-btn, .fx-float-btn:focus-visible { opacity: 1; }
|
|
221
|
+
.fx-float-btn:hover { color: var(--fx-accent, #5eead4); border-color: var(--fx-accent, #5eead4); }
|
|
222
|
+
|
|
223
|
+
.fx-float {
|
|
224
|
+
position: fixed; z-index: 60; display: flex; flex-direction: column;
|
|
225
|
+
background: var(--fx-panel, #14161c);
|
|
226
|
+
border: 1px solid var(--fx-line, #262a35); border-radius: 8px;
|
|
227
|
+
box-shadow: 0 12px 34px rgba(0, 0, 0, .5); overflow: hidden;
|
|
228
|
+
}
|
|
229
|
+
.fx-float-bar {
|
|
230
|
+
display: flex; align-items: center; padding: 4px 8px; cursor: move;
|
|
231
|
+
font-size: 11px; color: var(--fx-muted, #8a90a2);
|
|
232
|
+
background: var(--fx-bg, #0f1115); border-bottom: 1px solid var(--fx-line, #262a35);
|
|
233
|
+
user-select: none;
|
|
234
|
+
}
|
|
235
|
+
/* The pane fills the card, whatever it was sized to in the layout it came from. */
|
|
236
|
+
.fx-float > .fx-floated {
|
|
237
|
+
flex: 1; min-height: 0; width: auto; height: auto; overflow: auto;
|
|
238
|
+
}
|
|
239
|
+
/* Edges and corners. Thin, and over everything, so a card can be resized from whichever
|
|
240
|
+
side is reachable. */
|
|
241
|
+
.fx-float-h { position: absolute; z-index: 1; }
|
|
242
|
+
.fx-float-n, .fx-float-s { left: 8px; right: 8px; height: 6px; cursor: ns-resize; }
|
|
243
|
+
.fx-float-e, .fx-float-w { top: 8px; bottom: 8px; width: 6px; cursor: ew-resize; }
|
|
244
|
+
.fx-float-n { top: -3px; }
|
|
245
|
+
.fx-float-s { bottom: -3px; }
|
|
246
|
+
.fx-float-e { right: -3px; }
|
|
247
|
+
.fx-float-w { left: -3px; }
|
|
248
|
+
.fx-float-ne, .fx-float-nw, .fx-float-se, .fx-float-sw { width: 14px; height: 14px; }
|
|
249
|
+
.fx-float-nw { top: -3px; left: -3px; cursor: nwse-resize; }
|
|
250
|
+
.fx-float-ne { top: -3px; right: -3px; cursor: nesw-resize; }
|
|
251
|
+
.fx-float-sw { bottom: -3px; left: -3px; cursor: nesw-resize; }
|
|
252
|
+
.fx-float-se {
|
|
253
|
+
bottom: 0; right: 0; cursor: nwse-resize;
|
|
254
|
+
background: linear-gradient(135deg, transparent 50%, var(--fx-line, #262a35) 50%);
|
|
255
|
+
}
|
|
256
|
+
`;
|
package/dist/float.mjs
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// src/float.ts
|
|
2
|
+
var MIN_W = 240;
|
|
3
|
+
var MIN_H = 160;
|
|
4
|
+
function draggable(handle, onMove, onStart) {
|
|
5
|
+
handle.addEventListener("pointerdown", (event) => {
|
|
6
|
+
if (event.button !== 0) return;
|
|
7
|
+
if (event.target.closest("button")) return;
|
|
8
|
+
event.preventDefault();
|
|
9
|
+
handle.setPointerCapture(event.pointerId);
|
|
10
|
+
const fromX = event.clientX;
|
|
11
|
+
const fromY = event.clientY;
|
|
12
|
+
onStart?.();
|
|
13
|
+
const move = (e) => onMove(e.clientX - fromX, e.clientY - fromY);
|
|
14
|
+
const stop = () => {
|
|
15
|
+
handle.removeEventListener("pointermove", move);
|
|
16
|
+
handle.removeEventListener("pointerup", stop);
|
|
17
|
+
handle.removeEventListener("pointercancel", stop);
|
|
18
|
+
handle.removeEventListener("lostpointercapture", stop);
|
|
19
|
+
if (handle.hasPointerCapture(event.pointerId)) handle.releasePointerCapture(event.pointerId);
|
|
20
|
+
};
|
|
21
|
+
handle.addEventListener("pointermove", move);
|
|
22
|
+
handle.addEventListener("pointerup", stop);
|
|
23
|
+
handle.addEventListener("pointercancel", stop);
|
|
24
|
+
handle.addEventListener("lostpointercapture", stop);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
var opened = 0;
|
|
28
|
+
function floatCard(doc, title, at) {
|
|
29
|
+
const card = doc.createElement("div");
|
|
30
|
+
card.className = "fx-float";
|
|
31
|
+
const spot = at ?? {
|
|
32
|
+
x: 60 + opened % 4 * 28,
|
|
33
|
+
y: 60 + opened % 4 * 28,
|
|
34
|
+
width: 360,
|
|
35
|
+
height: 280
|
|
36
|
+
};
|
|
37
|
+
opened += 1;
|
|
38
|
+
const bar = doc.createElement("div");
|
|
39
|
+
bar.className = "fx-float-bar";
|
|
40
|
+
const name = doc.createElement("span");
|
|
41
|
+
name.textContent = title;
|
|
42
|
+
bar.append(name);
|
|
43
|
+
card.append(bar);
|
|
44
|
+
let x = spot.x;
|
|
45
|
+
let y = spot.y;
|
|
46
|
+
let w = spot.width;
|
|
47
|
+
let h = spot.height;
|
|
48
|
+
const apply = () => {
|
|
49
|
+
const view = doc.defaultView;
|
|
50
|
+
const vw = view?.innerWidth ?? w;
|
|
51
|
+
const vh = view?.innerHeight ?? h;
|
|
52
|
+
w = Math.min(Math.max(MIN_W, w), vw);
|
|
53
|
+
h = Math.min(Math.max(MIN_H, h), vh);
|
|
54
|
+
x = Math.min(Math.max(0, x), Math.max(0, vw - w));
|
|
55
|
+
y = Math.min(Math.max(0, y), Math.max(0, vh - h));
|
|
56
|
+
card.style.left = `${x}px`;
|
|
57
|
+
card.style.top = `${y}px`;
|
|
58
|
+
card.style.width = `${w}px`;
|
|
59
|
+
card.style.height = `${h}px`;
|
|
60
|
+
};
|
|
61
|
+
let from = { x, y, w, h };
|
|
62
|
+
const remember = () => {
|
|
63
|
+
from = { x, y, w, h };
|
|
64
|
+
};
|
|
65
|
+
for (const edge of ["n", "s", "e", "w", "ne", "nw", "se", "sw"]) {
|
|
66
|
+
const handle = doc.createElement("div");
|
|
67
|
+
handle.className = `fx-float-h fx-float-${edge}`;
|
|
68
|
+
card.append(handle);
|
|
69
|
+
draggable(
|
|
70
|
+
handle,
|
|
71
|
+
(dx, dy) => {
|
|
72
|
+
if (edge.includes("e")) w = from.w + dx;
|
|
73
|
+
if (edge.includes("s")) h = from.h + dy;
|
|
74
|
+
if (edge.includes("w")) {
|
|
75
|
+
w = Math.max(MIN_W, from.w - dx);
|
|
76
|
+
x = from.x + from.w - w;
|
|
77
|
+
}
|
|
78
|
+
if (edge.includes("n")) {
|
|
79
|
+
h = Math.max(MIN_H, from.h - dy);
|
|
80
|
+
y = from.y + from.h - h;
|
|
81
|
+
}
|
|
82
|
+
apply();
|
|
83
|
+
},
|
|
84
|
+
remember
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
draggable(
|
|
88
|
+
bar,
|
|
89
|
+
(dx, dy) => {
|
|
90
|
+
x = from.x + dx;
|
|
91
|
+
y = from.y + dy;
|
|
92
|
+
apply();
|
|
93
|
+
},
|
|
94
|
+
remember
|
|
95
|
+
);
|
|
96
|
+
apply();
|
|
97
|
+
return { card, bar, remove: () => card.remove() };
|
|
98
|
+
}
|
|
99
|
+
function makeFloatable(pane, options) {
|
|
100
|
+
const doc = pane.ownerDocument;
|
|
101
|
+
let card = null;
|
|
102
|
+
let home = null;
|
|
103
|
+
const button = doc.createElement("button");
|
|
104
|
+
button.type = "button";
|
|
105
|
+
button.className = "fx-float-btn";
|
|
106
|
+
button.textContent = "⇱";
|
|
107
|
+
button.title = `Float ${options.title}`;
|
|
108
|
+
pane.classList.add("fx-floatable");
|
|
109
|
+
pane.append(button);
|
|
110
|
+
const keep = new MutationObserver(() => {
|
|
111
|
+
if (button.parentNode !== pane) pane.append(button);
|
|
112
|
+
});
|
|
113
|
+
keep.observe(pane, { childList: true });
|
|
114
|
+
function dock() {
|
|
115
|
+
if (!card || !home) return;
|
|
116
|
+
home.parent.insertBefore(pane, home.before);
|
|
117
|
+
card.remove();
|
|
118
|
+
card = null;
|
|
119
|
+
home = null;
|
|
120
|
+
pane.classList.remove("fx-floated");
|
|
121
|
+
button.textContent = "⇱";
|
|
122
|
+
button.title = `Float ${options.title}`;
|
|
123
|
+
options.onChange?.(false);
|
|
124
|
+
}
|
|
125
|
+
function float() {
|
|
126
|
+
if (card || !pane.parentNode) return;
|
|
127
|
+
home = { parent: pane.parentNode, before: pane.nextSibling };
|
|
128
|
+
const built = floatCard(doc, options.title, options.at);
|
|
129
|
+
card = built.card;
|
|
130
|
+
card.append(pane);
|
|
131
|
+
doc.body.appendChild(card);
|
|
132
|
+
pane.classList.add("fx-floated");
|
|
133
|
+
button.textContent = "⇲";
|
|
134
|
+
button.title = `Put ${options.title} back`;
|
|
135
|
+
options.onChange?.(true);
|
|
136
|
+
}
|
|
137
|
+
button.addEventListener("click", (event) => {
|
|
138
|
+
event.stopPropagation();
|
|
139
|
+
if (card) dock();
|
|
140
|
+
else float();
|
|
141
|
+
});
|
|
142
|
+
return {
|
|
143
|
+
get floating() {
|
|
144
|
+
return card !== null;
|
|
145
|
+
},
|
|
146
|
+
toggle() {
|
|
147
|
+
if (card) dock();
|
|
148
|
+
else float();
|
|
149
|
+
return card !== null;
|
|
150
|
+
},
|
|
151
|
+
dock,
|
|
152
|
+
destroy() {
|
|
153
|
+
keep.disconnect();
|
|
154
|
+
dock();
|
|
155
|
+
button.remove();
|
|
156
|
+
pane.classList.remove("fx-floatable");
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
var FLOAT_CSS = `
|
|
161
|
+
.fx-floatable { position: relative; }
|
|
162
|
+
.fx-float-btn {
|
|
163
|
+
position: absolute; top: 2px; right: 2px; z-index: 5;
|
|
164
|
+
width: 18px; height: 18px; padding: 0; line-height: 1;
|
|
165
|
+
font-size: 11px; color: var(--fx-muted, #8a90a2);
|
|
166
|
+
background: var(--fx-panel, #14161c);
|
|
167
|
+
border: 1px solid var(--fx-line, #262a35); border-radius: 4px;
|
|
168
|
+
cursor: pointer; opacity: 0; transition: opacity .12s;
|
|
169
|
+
}
|
|
170
|
+
.fx-floatable:hover .fx-float-btn, .fx-float-btn:focus-visible { opacity: 1; }
|
|
171
|
+
.fx-float-btn:hover { color: var(--fx-accent, #5eead4); border-color: var(--fx-accent, #5eead4); }
|
|
172
|
+
|
|
173
|
+
.fx-float {
|
|
174
|
+
position: fixed; z-index: 60; display: flex; flex-direction: column;
|
|
175
|
+
background: var(--fx-panel, #14161c);
|
|
176
|
+
border: 1px solid var(--fx-line, #262a35); border-radius: 8px;
|
|
177
|
+
box-shadow: 0 12px 34px rgba(0, 0, 0, .5); overflow: hidden;
|
|
178
|
+
}
|
|
179
|
+
.fx-float-bar {
|
|
180
|
+
display: flex; align-items: center; padding: 4px 8px; cursor: move;
|
|
181
|
+
font-size: 11px; color: var(--fx-muted, #8a90a2);
|
|
182
|
+
background: var(--fx-bg, #0f1115); border-bottom: 1px solid var(--fx-line, #262a35);
|
|
183
|
+
user-select: none;
|
|
184
|
+
}
|
|
185
|
+
/* The pane fills the card, whatever it was sized to in the layout it came from. */
|
|
186
|
+
.fx-float > .fx-floated {
|
|
187
|
+
flex: 1; min-height: 0; width: auto; height: auto; overflow: auto;
|
|
188
|
+
}
|
|
189
|
+
/* Edges and corners. Thin, and over everything, so a card can be resized from whichever
|
|
190
|
+
side is reachable. */
|
|
191
|
+
.fx-float-h { position: absolute; z-index: 1; }
|
|
192
|
+
.fx-float-n, .fx-float-s { left: 8px; right: 8px; height: 6px; cursor: ns-resize; }
|
|
193
|
+
.fx-float-e, .fx-float-w { top: 8px; bottom: 8px; width: 6px; cursor: ew-resize; }
|
|
194
|
+
.fx-float-n { top: -3px; }
|
|
195
|
+
.fx-float-s { bottom: -3px; }
|
|
196
|
+
.fx-float-e { right: -3px; }
|
|
197
|
+
.fx-float-w { left: -3px; }
|
|
198
|
+
.fx-float-ne, .fx-float-nw, .fx-float-se, .fx-float-sw { width: 14px; height: 14px; }
|
|
199
|
+
.fx-float-nw { top: -3px; left: -3px; cursor: nwse-resize; }
|
|
200
|
+
.fx-float-ne { top: -3px; right: -3px; cursor: nesw-resize; }
|
|
201
|
+
.fx-float-sw { bottom: -3px; left: -3px; cursor: nesw-resize; }
|
|
202
|
+
.fx-float-se {
|
|
203
|
+
bottom: 0; right: 0; cursor: nwse-resize;
|
|
204
|
+
background: linear-gradient(135deg, transparent 50%, var(--fx-line, #262a35) 50%);
|
|
205
|
+
}
|
|
206
|
+
`;
|
|
207
|
+
export {
|
|
208
|
+
FLOAT_CSS,
|
|
209
|
+
floatCard,
|
|
210
|
+
makeFloatable
|
|
211
|
+
};
|
package/dist/format.cjs
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/format.ts
|
|
21
|
+
var format_exports = {};
|
|
22
|
+
__export(format_exports, {
|
|
23
|
+
formatValue: () => formatValue,
|
|
24
|
+
indentValue: () => indentValue,
|
|
25
|
+
shorten: () => shorten
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(format_exports);
|
|
28
|
+
var MAX_DEPTH = 3;
|
|
29
|
+
var MAX_ENTRIES = 8;
|
|
30
|
+
function domName(v) {
|
|
31
|
+
if (typeof v?.nodeType !== "number" || typeof v.nodeName !== "string") return null;
|
|
32
|
+
return v.tagName ? `<${v.tagName.toLowerCase()}>` : `#${v.nodeName.toLowerCase()}`;
|
|
33
|
+
}
|
|
34
|
+
function fnName(v) {
|
|
35
|
+
return v.name ? `ƒ ${v.name}()` : "ƒ";
|
|
36
|
+
}
|
|
37
|
+
function className(v) {
|
|
38
|
+
const name = v.constructor?.name;
|
|
39
|
+
return name && name !== "Object" ? `${name} ` : "";
|
|
40
|
+
}
|
|
41
|
+
function primitive(v) {
|
|
42
|
+
if (v === null) return "null";
|
|
43
|
+
switch (typeof v) {
|
|
44
|
+
case "undefined":
|
|
45
|
+
return "undefined";
|
|
46
|
+
case "string":
|
|
47
|
+
return JSON.stringify(v);
|
|
48
|
+
case "number":
|
|
49
|
+
case "boolean":
|
|
50
|
+
return String(v);
|
|
51
|
+
case "bigint":
|
|
52
|
+
return `${v}n`;
|
|
53
|
+
case "symbol":
|
|
54
|
+
return v.toString();
|
|
55
|
+
case "function":
|
|
56
|
+
return fnName(v);
|
|
57
|
+
default:
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function walk(value, depth, seen) {
|
|
62
|
+
const simple = primitive(value);
|
|
63
|
+
if (simple !== null) return simple;
|
|
64
|
+
const object = value;
|
|
65
|
+
if (seen.has(object)) return "[circular]";
|
|
66
|
+
const dom = domName(object);
|
|
67
|
+
if (dom) return dom;
|
|
68
|
+
if (object instanceof Date) return Number.isNaN(object.getTime()) ? "Invalid Date" : object.toISOString();
|
|
69
|
+
if (object instanceof RegExp) return String(object);
|
|
70
|
+
if (object instanceof Error) return `${object.name}: ${object.message}`;
|
|
71
|
+
if (object instanceof Promise) return "Promise";
|
|
72
|
+
if (ArrayBuffer.isView(object)) {
|
|
73
|
+
return `${className(object).trim()}(${object.length ?? ""})`;
|
|
74
|
+
}
|
|
75
|
+
if (depth >= MAX_DEPTH) return Array.isArray(object) ? "[…]" : "{…}";
|
|
76
|
+
seen.add(object);
|
|
77
|
+
try {
|
|
78
|
+
if (Array.isArray(object)) {
|
|
79
|
+
const shown2 = object.slice(0, MAX_ENTRIES).map((item) => walk(item, depth + 1, seen));
|
|
80
|
+
if (object.length > MAX_ENTRIES) shown2.push("…");
|
|
81
|
+
return `[${shown2.join(", ")}]`;
|
|
82
|
+
}
|
|
83
|
+
if (object instanceof Map) {
|
|
84
|
+
const shown2 = [];
|
|
85
|
+
for (const [k, v] of object) {
|
|
86
|
+
if (shown2.length === MAX_ENTRIES) {
|
|
87
|
+
shown2.push("…");
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
shown2.push(`${walk(k, depth + 1, seen)} => ${walk(v, depth + 1, seen)}`);
|
|
91
|
+
}
|
|
92
|
+
return `Map(${object.size}) {${shown2.join(", ")}}`;
|
|
93
|
+
}
|
|
94
|
+
if (object instanceof Set) {
|
|
95
|
+
const shown2 = [];
|
|
96
|
+
for (const item of object) {
|
|
97
|
+
if (shown2.length === MAX_ENTRIES) {
|
|
98
|
+
shown2.push("…");
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
shown2.push(walk(item, depth + 1, seen));
|
|
102
|
+
}
|
|
103
|
+
return `Set(${object.size}) {${shown2.join(", ")}}`;
|
|
104
|
+
}
|
|
105
|
+
const keys = Object.keys(object);
|
|
106
|
+
const shown = keys.slice(0, MAX_ENTRIES).map((key) => {
|
|
107
|
+
let read;
|
|
108
|
+
try {
|
|
109
|
+
read = walk(object[key], depth + 1, seen);
|
|
110
|
+
} catch {
|
|
111
|
+
read = "[unreadable]";
|
|
112
|
+
}
|
|
113
|
+
return `${key}: ${read}`;
|
|
114
|
+
});
|
|
115
|
+
if (keys.length > MAX_ENTRIES) shown.push("…");
|
|
116
|
+
return `${className(object)}{${shown.join(", ")}}`;
|
|
117
|
+
} finally {
|
|
118
|
+
seen.delete(object);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function formatValue(value, limit = 240) {
|
|
122
|
+
let text;
|
|
123
|
+
try {
|
|
124
|
+
text = walk(value, 0, /* @__PURE__ */ new Set());
|
|
125
|
+
} catch {
|
|
126
|
+
text = "[unreadable]";
|
|
127
|
+
}
|
|
128
|
+
return text.length > limit ? `${text.slice(0, limit - 1)}…` : text;
|
|
129
|
+
}
|
|
130
|
+
function shorten(text, limit = 18) {
|
|
131
|
+
return text.length > limit ? `${text.slice(0, limit - 1)}…` : text;
|
|
132
|
+
}
|
|
133
|
+
function indentValue(text, pad = " ") {
|
|
134
|
+
const out = [];
|
|
135
|
+
let depth = 0;
|
|
136
|
+
let quote = null;
|
|
137
|
+
let line = "";
|
|
138
|
+
const flush = () => {
|
|
139
|
+
if (line.trim()) out.push(pad.repeat(depth) + line.trim());
|
|
140
|
+
line = "";
|
|
141
|
+
};
|
|
142
|
+
for (let i = 0; i < text.length; i++) {
|
|
143
|
+
const c = text[i];
|
|
144
|
+
if (quote) {
|
|
145
|
+
line += c;
|
|
146
|
+
if (c === quote && text[i - 1] !== "\\") quote = null;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (c === '"' || c === "'") {
|
|
150
|
+
quote = c;
|
|
151
|
+
line += c;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (c === "{" || c === "[") {
|
|
155
|
+
line += c;
|
|
156
|
+
flush();
|
|
157
|
+
depth++;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (c === "}" || c === "]") {
|
|
161
|
+
flush();
|
|
162
|
+
depth = Math.max(0, depth - 1);
|
|
163
|
+
line = c;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (c === ",") {
|
|
167
|
+
line += c;
|
|
168
|
+
flush();
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
line += c;
|
|
172
|
+
}
|
|
173
|
+
flush();
|
|
174
|
+
return out.join("\n");
|
|
175
|
+
}
|
package/dist/format.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A printable rendering of any value. Never throws, never leaves `[object Object]`.
|
|
3
|
+
*
|
|
4
|
+
* `limit` caps the result; what is cut ends in an ellipsis.
|
|
5
|
+
*/
|
|
6
|
+
export declare function formatValue(value: unknown, limit?: number): string;
|
|
7
|
+
/** The short form a node card has room for. */
|
|
8
|
+
export declare function shorten(text: string, limit?: number): string;
|
|
9
|
+
/**
|
|
10
|
+
* The same text across lines, so a value too wide to read is readable.
|
|
11
|
+
*
|
|
12
|
+
* Works on what `formatValue` produced rather than on the value itself: a panel elsewhere
|
|
13
|
+
* has only the string. Quotes are tracked so a brace inside one is left alone.
|
|
14
|
+
*/
|
|
15
|
+
export declare function indentValue(text: string, pad?: string): string;
|
|
16
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAoHA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAM,GAAG,MAAM,CAQ/D;AAED,+CAA+C;AAC/C,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,CAExD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAO,GAAG,MAAM,CA4C5D"}
|