@chuvenger/devdock 0.6.0 → 0.8.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 +165 -15
- package/dist/{chunk-NXZNFF34.js → chunk-7Z3YWV5K.js} +343 -152
- package/dist/chunk-7Z3YWV5K.js.map +1 -0
- package/dist/{chunk-3MVFATRN.js → chunk-MKYQ666Z.js} +3 -3
- package/dist/{chunk-3MVFATRN.js.map → chunk-MKYQ666Z.js.map} +1 -1
- package/dist/{dock-P6l6pKjS.d.ts → dock-C8tR26RP.d.ts} +1 -1
- package/dist/{dock-d3HqT25k.d.cts → dock-Cxh5FIAv.d.cts} +1 -1
- package/dist/index.cjs +344 -149
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -3
- package/dist/index.d.ts +20 -3
- package/dist/index.js +1 -1
- package/dist/{match-DDSJIRYW.d.cts → match-CFB-9KGi.d.cts} +1 -1
- package/dist/{match-DwGIF1Xt.d.ts → match-injUeExB.d.ts} +1 -1
- package/dist/react-router.cjs +339 -149
- package/dist/react-router.cjs.map +1 -1
- package/dist/react-router.d.cts +3 -2
- package/dist/react-router.d.ts +3 -2
- package/dist/react-router.js +2 -2
- package/dist/react.cjs +339 -149
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +3 -2
- package/dist/react.d.ts +3 -2
- package/dist/react.js +2 -2
- package/dist/svelte.cjs +342 -149
- package/dist/svelte.cjs.map +1 -1
- package/dist/svelte.d.cts +4 -3
- package/dist/svelte.d.ts +4 -3
- package/dist/svelte.js +2 -2
- package/dist/svelte.js.map +1 -1
- package/dist/sveltekit.cjs +342 -149
- package/dist/sveltekit.cjs.map +1 -1
- package/dist/sveltekit.d.cts +5 -4
- package/dist/sveltekit.d.ts +5 -4
- package/dist/sveltekit.js +2 -2
- package/dist/{types-B_SpF32A.d.cts → types-BuYSEeDa.d.cts} +113 -5
- package/dist/{types-B_SpF32A.d.ts → types-BuYSEeDa.d.ts} +113 -5
- package/package.json +4 -1
- package/dist/chunk-NXZNFF34.js.map +0 -1
package/dist/react.cjs
CHANGED
|
@@ -2,26 +2,281 @@
|
|
|
2
2
|
|
|
3
3
|
var react = require('react');
|
|
4
4
|
var reactDom = require('react-dom');
|
|
5
|
+
var cn = require('cn');
|
|
5
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
7
|
|
|
7
8
|
// src/react/DevDock.tsx
|
|
8
9
|
|
|
9
10
|
// src/core/hotkey.ts
|
|
11
|
+
var isMac = () => typeof navigator !== "undefined" && /mac/i.test(navigator.platform);
|
|
12
|
+
var KEY_CODES = {
|
|
13
|
+
".": "Period",
|
|
14
|
+
",": "Comma",
|
|
15
|
+
"/": "Slash",
|
|
16
|
+
"\\": "Backslash",
|
|
17
|
+
";": "Semicolon",
|
|
18
|
+
"'": "Quote",
|
|
19
|
+
"[": "BracketLeft",
|
|
20
|
+
"]": "BracketRight",
|
|
21
|
+
"-": "Minus",
|
|
22
|
+
"=": "Equal",
|
|
23
|
+
"`": "Backquote",
|
|
24
|
+
" ": "Space",
|
|
25
|
+
space: "Space"
|
|
26
|
+
};
|
|
27
|
+
var codeFor = (key) => {
|
|
28
|
+
if (/^[a-z]$/.test(key)) return `Key${key.toUpperCase()}`;
|
|
29
|
+
if (/^[0-9]$/.test(key)) return `Digit${key}`;
|
|
30
|
+
return KEY_CODES[key];
|
|
31
|
+
};
|
|
10
32
|
function matchHotkey(spec, e) {
|
|
11
33
|
const parts = spec.toLowerCase().split("+").map((p) => p.trim()).filter(Boolean);
|
|
12
34
|
if (parts.length === 0) return false;
|
|
13
35
|
const key = parts[parts.length - 1];
|
|
14
36
|
const mods = new Set(parts.slice(0, -1));
|
|
15
|
-
const
|
|
16
|
-
const wantMeta = mods.has("meta") || mods.has("cmd") || mods.has("mod") &&
|
|
17
|
-
const wantCtrl = mods.has("ctrl") || mods.has("control") || mods.has("mod") && !
|
|
37
|
+
const mac = isMac();
|
|
38
|
+
const wantMeta = mods.has("meta") || mods.has("cmd") || mods.has("mod") && mac;
|
|
39
|
+
const wantCtrl = mods.has("ctrl") || mods.has("control") || mods.has("mod") && !mac;
|
|
18
40
|
const wantShift = mods.has("shift");
|
|
19
41
|
const wantAlt = mods.has("alt") || mods.has("option");
|
|
20
42
|
if (e.metaKey !== wantMeta) return false;
|
|
21
43
|
if (e.ctrlKey !== wantCtrl) return false;
|
|
22
44
|
if (e.shiftKey !== wantShift) return false;
|
|
23
45
|
if (e.altKey !== wantAlt) return false;
|
|
24
|
-
|
|
46
|
+
if (e.key.toLowerCase() === key) return true;
|
|
47
|
+
return wantAlt && e.code === codeFor(key);
|
|
48
|
+
}
|
|
49
|
+
var DEFAULT_HOTKEY = "alt+shift+d";
|
|
50
|
+
var MAC_SYMBOL = {
|
|
51
|
+
meta: "\u2318",
|
|
52
|
+
cmd: "\u2318",
|
|
53
|
+
ctrl: "\u2303",
|
|
54
|
+
control: "\u2303",
|
|
55
|
+
shift: "\u21E7",
|
|
56
|
+
alt: "\u2325",
|
|
57
|
+
option: "\u2325"
|
|
58
|
+
};
|
|
59
|
+
var PC_NAME = {
|
|
60
|
+
meta: "Win",
|
|
61
|
+
cmd: "Win",
|
|
62
|
+
ctrl: "Ctrl",
|
|
63
|
+
control: "Ctrl",
|
|
64
|
+
shift: "Shift",
|
|
65
|
+
alt: "Alt",
|
|
66
|
+
option: "Alt"
|
|
67
|
+
};
|
|
68
|
+
function formatHotkey(spec) {
|
|
69
|
+
const parts = spec.toLowerCase().split("+").map((p) => p.trim()).filter(Boolean);
|
|
70
|
+
if (parts.length === 0) return "";
|
|
71
|
+
const key = parts[parts.length - 1];
|
|
72
|
+
const mods = parts.slice(0, -1);
|
|
73
|
+
const mac = isMac();
|
|
74
|
+
const label = key.length === 1 ? key.toUpperCase() : key;
|
|
75
|
+
const shown = mods.map(
|
|
76
|
+
(m) => mac ? MAC_SYMBOL[m] ?? (m === "mod" ? "\u2318" : m) : PC_NAME[m] ?? (m === "mod" ? "Ctrl" : m)
|
|
77
|
+
);
|
|
78
|
+
return mac ? [...shown, label].join("") : [...shown, label].join("+");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/core/theme.ts
|
|
82
|
+
var partClass = {
|
|
83
|
+
root: "devdock-root",
|
|
84
|
+
button: "devdock-button",
|
|
85
|
+
dot: "devdock-dot",
|
|
86
|
+
buttonLabel: "devdock-button-label",
|
|
87
|
+
panel: "devdock-panel",
|
|
88
|
+
title: "devdock-title",
|
|
89
|
+
hotkeyHint: "devdock-hotkey-hint",
|
|
90
|
+
inputWrap: "devdock-input-wrap",
|
|
91
|
+
input: "devdock-input",
|
|
92
|
+
body: "devdock-body",
|
|
93
|
+
list: "devdock-list",
|
|
94
|
+
section: "devdock-section",
|
|
95
|
+
group: "devdock-group",
|
|
96
|
+
row: "devdock-row",
|
|
97
|
+
rowActive: "",
|
|
98
|
+
rowLabel: "devdock-row-label",
|
|
99
|
+
rowPath: "devdock-row-path",
|
|
100
|
+
check: "devdock-check",
|
|
101
|
+
empty: "devdock-empty",
|
|
102
|
+
viewLabel: "devdock-view-label",
|
|
103
|
+
view: "devdock-view"
|
|
104
|
+
};
|
|
105
|
+
var STYLE_MARKER = "data-devdock-styles";
|
|
106
|
+
var FONT = "ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif";
|
|
107
|
+
var BASE_CSS = `
|
|
108
|
+
.devdock-root { font-family: var(--devdock-font, ${FONT}); }
|
|
109
|
+
|
|
110
|
+
.devdock-button {
|
|
111
|
+
display: inline-flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
gap: 6px;
|
|
114
|
+
padding: 8px 12px;
|
|
115
|
+
font-size: 12px;
|
|
116
|
+
font-weight: 700;
|
|
117
|
+
letter-spacing: 0.6px;
|
|
118
|
+
color: var(--devdock-button-fg, #fff);
|
|
119
|
+
background: var(--devdock-button-bg, #111317);
|
|
120
|
+
border: 1px solid var(--devdock-border, #2a2e37);
|
|
121
|
+
border-radius: 999px;
|
|
122
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
}
|
|
125
|
+
.devdock-button:where([aria-expanded="true"]) {
|
|
126
|
+
background: var(--devdock-accent, #2563eb);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.devdock-dot {
|
|
130
|
+
width: 8px;
|
|
131
|
+
height: 8px;
|
|
132
|
+
border-radius: 999px;
|
|
133
|
+
background: var(--devdock-success, #22c55e);
|
|
134
|
+
display: inline-block;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.devdock-panel {
|
|
138
|
+
width: var(--devdock-width, 280px);
|
|
139
|
+
max-height: var(--devdock-max-height, 70vh);
|
|
140
|
+
display: flex;
|
|
141
|
+
flex-direction: column;
|
|
142
|
+
background: var(--devdock-bg, #16181d);
|
|
143
|
+
color: var(--devdock-fg, #e7e9ee);
|
|
144
|
+
border: 1px solid var(--devdock-border, #2a2e37);
|
|
145
|
+
border-radius: var(--devdock-radius, 12px);
|
|
146
|
+
box-shadow: var(--devdock-shadow, 0 12px 40px rgba(0, 0, 0, 0.45));
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.devdock-title {
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: space-between;
|
|
154
|
+
gap: 8px;
|
|
155
|
+
padding: 10px 12px;
|
|
156
|
+
border-bottom: 1px solid var(--devdock-border, #2a2e37);
|
|
157
|
+
font-size: 12px;
|
|
158
|
+
font-weight: 600;
|
|
159
|
+
letter-spacing: 0.4px;
|
|
160
|
+
text-transform: uppercase;
|
|
161
|
+
color: var(--devdock-muted, #8b909c);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.devdock-hotkey-hint {
|
|
165
|
+
flex-shrink: 0;
|
|
166
|
+
padding: 1px 5px;
|
|
167
|
+
font-family: inherit;
|
|
168
|
+
font-size: 10px;
|
|
169
|
+
font-weight: 600;
|
|
170
|
+
/* The heading's tracking and casing are for words, not for a key cap. */
|
|
171
|
+
letter-spacing: 0;
|
|
172
|
+
text-transform: none;
|
|
173
|
+
color: var(--devdock-subtle, #6b7280);
|
|
174
|
+
border: 1px solid var(--devdock-border, #2a2e37);
|
|
175
|
+
border-radius: var(--devdock-radius-xs, 4px);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.devdock-input-wrap { padding: 8px; }
|
|
179
|
+
|
|
180
|
+
.devdock-input {
|
|
181
|
+
width: 100%;
|
|
182
|
+
box-sizing: border-box;
|
|
183
|
+
padding: 8px 10px;
|
|
184
|
+
font-size: 13px;
|
|
185
|
+
color: var(--devdock-fg, #e7e9ee);
|
|
186
|
+
background: var(--devdock-input-bg, #0f1115);
|
|
187
|
+
border: 1px solid var(--devdock-border, #2a2e37);
|
|
188
|
+
border-radius: var(--devdock-radius-sm, 8px);
|
|
189
|
+
outline: none;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.devdock-body {
|
|
193
|
+
overflow-y: auto;
|
|
194
|
+
display: flex;
|
|
195
|
+
flex-direction: column;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.devdock-list { padding: 0 6px 8px; }
|
|
199
|
+
|
|
200
|
+
.devdock-section { margin-top: 6px; }
|
|
201
|
+
|
|
202
|
+
.devdock-group {
|
|
203
|
+
padding: 6px 8px 2px;
|
|
204
|
+
font-size: 10px;
|
|
205
|
+
font-weight: 700;
|
|
206
|
+
letter-spacing: 0.6px;
|
|
207
|
+
text-transform: uppercase;
|
|
208
|
+
color: var(--devdock-subtle, #6b7280);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.devdock-row {
|
|
212
|
+
display: flex;
|
|
213
|
+
align-items: center;
|
|
214
|
+
justify-content: space-between;
|
|
215
|
+
gap: 8px;
|
|
216
|
+
width: 100%;
|
|
217
|
+
text-align: left;
|
|
218
|
+
padding: 8px 10px;
|
|
219
|
+
font-size: 13px;
|
|
220
|
+
color: var(--devdock-fg, #e7e9ee);
|
|
221
|
+
background: transparent;
|
|
222
|
+
border: none;
|
|
223
|
+
border-radius: var(--devdock-radius-sm, 8px);
|
|
224
|
+
cursor: pointer;
|
|
225
|
+
}
|
|
226
|
+
.devdock-row:where([data-active]) {
|
|
227
|
+
background: var(--devdock-accent, #2563eb);
|
|
228
|
+
color: var(--devdock-accent-fg, #e7e9ee);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.devdock-row-label {
|
|
232
|
+
overflow: hidden;
|
|
233
|
+
text-overflow: ellipsis;
|
|
234
|
+
white-space: nowrap;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.devdock-row-path {
|
|
238
|
+
font-size: 11px;
|
|
239
|
+
color: var(--devdock-subtle, #6b7280);
|
|
240
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
241
|
+
flex-shrink: 0;
|
|
242
|
+
}
|
|
243
|
+
:where(.devdock-row[data-active]) .devdock-row-path {
|
|
244
|
+
/* Whatever colour the row ended up with, stepped back: currentColor in the
|
|
245
|
+
color property means the inherited one, so this tracks the row however it
|
|
246
|
+
was set - a token, a class of yours - instead of guessing at the accent. */
|
|
247
|
+
color: color-mix(in oklab, currentColor 75%, transparent);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.devdock-check {
|
|
251
|
+
flex-shrink: 0;
|
|
252
|
+
width: 12px;
|
|
253
|
+
text-align: center;
|
|
254
|
+
color: var(--devdock-success, #22c55e);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.devdock-empty {
|
|
258
|
+
padding: 12px;
|
|
259
|
+
font-size: 13px;
|
|
260
|
+
color: var(--devdock-subtle, #6b7280);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.devdock-view-label {
|
|
264
|
+
padding: 4px 8px 0;
|
|
265
|
+
font-size: 11px;
|
|
266
|
+
color: var(--devdock-muted, #8b909c);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.devdock-view { padding: 2px 8px 6px; }
|
|
270
|
+
`;
|
|
271
|
+
var DEFAULT_LAYER = "devdock";
|
|
272
|
+
function dockStyles(layer) {
|
|
273
|
+
if (!layer) return BASE_CSS;
|
|
274
|
+
const block = `@layer ${layer} {${BASE_CSS}}
|
|
275
|
+
`;
|
|
276
|
+
if (layer !== DEFAULT_LAYER) return block;
|
|
277
|
+
const order = `@layer theme, base, components, ${layer}, utilities;`;
|
|
278
|
+
return `${order}
|
|
279
|
+
${block}`;
|
|
25
280
|
}
|
|
26
281
|
|
|
27
282
|
// src/core/dock.ts
|
|
@@ -54,33 +309,12 @@ var isDevHost = () => {
|
|
|
54
309
|
if (!host) return true;
|
|
55
310
|
return host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local") || host === "::1" || host === "0.0.0.0" || isLocalIPv4(host);
|
|
56
311
|
};
|
|
57
|
-
function el(tag,
|
|
312
|
+
function el(tag, props) {
|
|
58
313
|
const node = document.createElement(tag);
|
|
59
|
-
if (styles) Object.assign(node.style, styles);
|
|
60
314
|
if (props) Object.assign(node, props);
|
|
61
315
|
return node;
|
|
62
316
|
}
|
|
63
|
-
|
|
64
|
-
return el(
|
|
65
|
-
"div",
|
|
66
|
-
{
|
|
67
|
-
padding: "6px 8px 2px",
|
|
68
|
-
fontSize: "10px",
|
|
69
|
-
fontWeight: "700",
|
|
70
|
-
letterSpacing: "0.6px",
|
|
71
|
-
textTransform: "uppercase",
|
|
72
|
-
color: "#6b7280"
|
|
73
|
-
},
|
|
74
|
-
{ textContent: text }
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
function viewLabel(text) {
|
|
78
|
-
return el(
|
|
79
|
-
"div",
|
|
80
|
-
{ padding: "4px 8px 0", fontSize: "11px", color: "#8b909c" },
|
|
81
|
-
{ textContent: text }
|
|
82
|
-
);
|
|
83
|
-
}
|
|
317
|
+
var PARTS = Object.keys(partClass);
|
|
84
318
|
function cornerStyle(position) {
|
|
85
319
|
const gap = "16px";
|
|
86
320
|
switch (position) {
|
|
@@ -103,7 +337,6 @@ function panelAnchor(position) {
|
|
|
103
337
|
[isRight ? "right" : "left"]: "0"
|
|
104
338
|
};
|
|
105
339
|
}
|
|
106
|
-
var FONT = "ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif";
|
|
107
340
|
function keyViews(views) {
|
|
108
341
|
const used = /* @__PURE__ */ new Set();
|
|
109
342
|
return views.map((view, i) => {
|
|
@@ -120,96 +353,72 @@ function createDevDock(initial = {}) {
|
|
|
120
353
|
} };
|
|
121
354
|
}
|
|
122
355
|
let opts = { ...initial };
|
|
356
|
+
const cls = (...parts) => cn.cn(parts.map((part) => [partClass[part], opts.classNames?.[part]]));
|
|
357
|
+
const classSig = () => PARTS.map((p) => cn.cn(opts.classNames?.[p])).join("\0");
|
|
123
358
|
let open = false;
|
|
124
359
|
let query = "";
|
|
125
360
|
let active = 0;
|
|
126
361
|
let mounted = false;
|
|
127
362
|
const host = el("div");
|
|
128
363
|
host.setAttribute("data-devdock", "");
|
|
129
|
-
const shadowMode = initial.shadow ?? true;
|
|
364
|
+
const shadowMode = initial.shadow ?? (initial.classNames ? "inherit" : true);
|
|
130
365
|
const useShadow = shadowMode !== false && typeof host.attachShadow === "function";
|
|
131
366
|
const shadowRoot = useShadow ? host.attachShadow({ mode: "open" }) : null;
|
|
132
367
|
const mountPoint = shadowRoot ?? host;
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
const root = el("div", { fontFamily: FONT });
|
|
136
|
-
mountPoint.appendChild(root);
|
|
137
|
-
const panel = el("div", {
|
|
138
|
-
width: "280px",
|
|
139
|
-
maxHeight: "min(70vh, 480px)",
|
|
140
|
-
display: "flex",
|
|
141
|
-
flexDirection: "column",
|
|
142
|
-
background: "#16181d",
|
|
143
|
-
color: "#e7e9ee",
|
|
144
|
-
border: "1px solid #2a2e37",
|
|
145
|
-
borderRadius: "12px",
|
|
146
|
-
boxShadow: "0 12px 40px rgba(0,0,0,0.45)",
|
|
147
|
-
overflow: "hidden"
|
|
368
|
+
const baseStyle = el("style", {
|
|
369
|
+
textContent: dockStyles(initial.cssLayer ?? DEFAULT_LAYER)
|
|
148
370
|
});
|
|
371
|
+
baseStyle.setAttribute(STYLE_MARKER, "");
|
|
372
|
+
if (shadowRoot) mountPoint.appendChild(baseStyle);
|
|
373
|
+
const styleSlot = shadowRoot && shadowMode === "inherit" ? el("div") : null;
|
|
374
|
+
if (styleSlot) {
|
|
375
|
+
styleSlot.style.display = "contents";
|
|
376
|
+
mountPoint.appendChild(styleSlot);
|
|
377
|
+
}
|
|
378
|
+
const root = el("div");
|
|
379
|
+
mountPoint.appendChild(root);
|
|
380
|
+
const panel = el("div");
|
|
149
381
|
panel.setAttribute("role", "dialog");
|
|
150
|
-
const heading = el("div"
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
textTransform: "uppercase",
|
|
157
|
-
color: "#8b909c"
|
|
158
|
-
});
|
|
159
|
-
const inputWrap = el("div", { padding: "8px" });
|
|
160
|
-
const input = el("input", {
|
|
161
|
-
width: "100%",
|
|
162
|
-
boxSizing: "border-box",
|
|
163
|
-
padding: "8px 10px",
|
|
164
|
-
fontSize: "13px",
|
|
165
|
-
color: "#e7e9ee",
|
|
166
|
-
background: "#0f1115",
|
|
167
|
-
border: "1px solid #2a2e37",
|
|
168
|
-
borderRadius: "8px",
|
|
169
|
-
outline: "none"
|
|
170
|
-
});
|
|
382
|
+
const heading = el("div");
|
|
383
|
+
const headingText = el("span");
|
|
384
|
+
const hotkeyHint = el("kbd");
|
|
385
|
+
heading.append(headingText, hotkeyHint);
|
|
386
|
+
const inputWrap = el("div");
|
|
387
|
+
const input = el("input");
|
|
171
388
|
input.placeholder = "Filter\u2026";
|
|
172
389
|
inputWrap.appendChild(input);
|
|
173
|
-
const list = el("div"
|
|
390
|
+
const list = el("div");
|
|
174
391
|
list.setAttribute("data-devdock-list", "");
|
|
175
392
|
const viewsBefore = el("div");
|
|
176
393
|
viewsBefore.setAttribute("data-devdock-views", "before");
|
|
177
394
|
const viewsAfter = el("div");
|
|
178
395
|
viewsAfter.setAttribute("data-devdock-views", "after");
|
|
179
|
-
const body = el("div"
|
|
180
|
-
overflowY: "auto",
|
|
181
|
-
display: "flex",
|
|
182
|
-
flexDirection: "column"
|
|
183
|
-
});
|
|
396
|
+
const body = el("div");
|
|
184
397
|
body.append(viewsBefore, list, viewsAfter);
|
|
185
398
|
panel.append(heading, inputWrap, body);
|
|
186
|
-
const button = el("button"
|
|
187
|
-
display: "inline-flex",
|
|
188
|
-
alignItems: "center",
|
|
189
|
-
gap: "6px",
|
|
190
|
-
padding: "8px 12px",
|
|
191
|
-
fontSize: "12px",
|
|
192
|
-
fontWeight: "700",
|
|
193
|
-
letterSpacing: "0.6px",
|
|
194
|
-
color: "#fff",
|
|
195
|
-
background: "#111317",
|
|
196
|
-
border: "1px solid #2a2e37",
|
|
197
|
-
borderRadius: "999px",
|
|
198
|
-
boxShadow: "0 4px 14px rgba(0,0,0,0.35)",
|
|
199
|
-
cursor: "pointer"
|
|
200
|
-
});
|
|
399
|
+
const button = el("button");
|
|
201
400
|
button.type = "button";
|
|
202
401
|
button.setAttribute("aria-label", "Toggle dev menu");
|
|
203
|
-
const dot = el("span"
|
|
204
|
-
width: "8px",
|
|
205
|
-
height: "8px",
|
|
206
|
-
borderRadius: "999px",
|
|
207
|
-
background: "#22c55e",
|
|
208
|
-
display: "inline-block"
|
|
209
|
-
});
|
|
402
|
+
const dot = el("span");
|
|
210
403
|
const buttonLabel = el("span");
|
|
211
404
|
button.append(dot, buttonLabel);
|
|
212
405
|
root.appendChild(button);
|
|
406
|
+
const sectionHeading = (text) => el("div", { className: cls("group"), textContent: text });
|
|
407
|
+
const viewLabel = (text) => el("div", { className: cls("viewLabel"), textContent: text });
|
|
408
|
+
const paintClasses = () => {
|
|
409
|
+
root.className = cls("root");
|
|
410
|
+
button.className = cls("button");
|
|
411
|
+
dot.className = cls("dot");
|
|
412
|
+
buttonLabel.className = cls("buttonLabel");
|
|
413
|
+
panel.className = cls("panel");
|
|
414
|
+
heading.className = cls("title");
|
|
415
|
+
hotkeyHint.className = cls("hotkeyHint");
|
|
416
|
+
inputWrap.className = cls("inputWrap");
|
|
417
|
+
input.className = cls("input");
|
|
418
|
+
body.className = cls("body");
|
|
419
|
+
list.className = cls("list");
|
|
420
|
+
};
|
|
421
|
+
const hotkey = () => opts.hotkey === void 0 ? DEFAULT_HOTKEY : opts.hotkey;
|
|
213
422
|
const enabled = () => {
|
|
214
423
|
const e = opts.enabled;
|
|
215
424
|
if (typeof e === "function") return e();
|
|
@@ -293,9 +502,9 @@ function createDevDock(initial = {}) {
|
|
|
293
502
|
const paintActive = () => {
|
|
294
503
|
rows.forEach((row, idx) => {
|
|
295
504
|
const isActive = idx === active;
|
|
296
|
-
row.node.
|
|
297
|
-
|
|
298
|
-
|
|
505
|
+
if (isActive) row.node.setAttribute("data-active", "");
|
|
506
|
+
else row.node.removeAttribute("data-active");
|
|
507
|
+
row.node.className = isActive ? cls("row", "rowActive") : cls("row");
|
|
299
508
|
});
|
|
300
509
|
};
|
|
301
510
|
const setActive = (next, scroll = false) => {
|
|
@@ -307,7 +516,7 @@ function createDevDock(initial = {}) {
|
|
|
307
516
|
const renderList = () => {
|
|
308
517
|
const filtered = getFiltered();
|
|
309
518
|
active = Math.min(active, Math.max(0, filtered.length - 1));
|
|
310
|
-
const sig = filtered.map(itemSig).join("\n");
|
|
519
|
+
const sig = [classSig(), ...filtered.map(itemSig)].join("\n");
|
|
311
520
|
if (sig === rowsSig) {
|
|
312
521
|
filtered.forEach((it, idx) => {
|
|
313
522
|
const row = rows[idx];
|
|
@@ -323,11 +532,7 @@ function createDevDock(initial = {}) {
|
|
|
323
532
|
list.replaceChildren();
|
|
324
533
|
if (filtered.length === 0) {
|
|
325
534
|
list.appendChild(
|
|
326
|
-
el(
|
|
327
|
-
"div",
|
|
328
|
-
{ padding: "12px", fontSize: "13px", color: "#6b7280" },
|
|
329
|
-
{ textContent: "Nothing here." }
|
|
330
|
-
)
|
|
535
|
+
el("div", { className: cls("empty"), textContent: "Nothing here." })
|
|
331
536
|
);
|
|
332
537
|
return;
|
|
333
538
|
}
|
|
@@ -338,55 +543,26 @@ function createDevDock(initial = {}) {
|
|
|
338
543
|
groups.set(it.group, arr);
|
|
339
544
|
}
|
|
340
545
|
for (const [groupName, groupItems] of groups) {
|
|
341
|
-
const section = el("div", {
|
|
546
|
+
const section = el("div", { className: cls("section") });
|
|
342
547
|
section.appendChild(sectionHeading(groupName));
|
|
343
548
|
for (const it of groupItems) {
|
|
344
549
|
const idx = filtered.indexOf(it);
|
|
345
|
-
const row = el("button", {
|
|
346
|
-
display: "flex",
|
|
347
|
-
alignItems: "center",
|
|
348
|
-
justifyContent: "space-between",
|
|
349
|
-
gap: "8px",
|
|
350
|
-
width: "100%",
|
|
351
|
-
textAlign: "left",
|
|
352
|
-
padding: "8px 10px",
|
|
353
|
-
fontSize: "13px",
|
|
354
|
-
color: "#e7e9ee",
|
|
355
|
-
background: "transparent",
|
|
356
|
-
border: "none",
|
|
357
|
-
borderRadius: "8px",
|
|
358
|
-
cursor: "pointer"
|
|
359
|
-
});
|
|
550
|
+
const row = el("button", { className: cls("row") });
|
|
360
551
|
row.type = "button";
|
|
361
|
-
const labelSpan = el("span", {
|
|
362
|
-
overflow: "hidden",
|
|
363
|
-
textOverflow: "ellipsis",
|
|
364
|
-
whiteSpace: "nowrap"
|
|
365
|
-
});
|
|
552
|
+
const labelSpan = el("span", { className: cls("rowLabel") });
|
|
366
553
|
row.appendChild(labelSpan);
|
|
367
554
|
let pathSpan = null;
|
|
368
555
|
if (it.kind === "route" && it.route.path !== it.label) {
|
|
369
|
-
pathSpan = el(
|
|
370
|
-
"
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
color: "#6b7280",
|
|
374
|
-
fontFamily: "ui-monospace, SFMono-Regular, monospace",
|
|
375
|
-
flexShrink: "0"
|
|
376
|
-
},
|
|
377
|
-
{ textContent: it.route.path }
|
|
378
|
-
);
|
|
556
|
+
pathSpan = el("span", {
|
|
557
|
+
className: cls("rowPath"),
|
|
558
|
+
textContent: it.route.path
|
|
559
|
+
});
|
|
379
560
|
row.appendChild(pathSpan);
|
|
380
561
|
}
|
|
381
562
|
let checkSpan = null;
|
|
382
563
|
if (it.kind === "command" && it.checked !== null) {
|
|
383
564
|
row.setAttribute("role", "checkbox");
|
|
384
|
-
checkSpan = el("span", {
|
|
385
|
-
flexShrink: "0",
|
|
386
|
-
width: "12px",
|
|
387
|
-
textAlign: "center",
|
|
388
|
-
color: "#22c55e"
|
|
389
|
-
});
|
|
565
|
+
checkSpan = el("span", { className: cls("check") });
|
|
390
566
|
row.appendChild(checkSpan);
|
|
391
567
|
}
|
|
392
568
|
const rec = { item: it, node: row, labelSpan, pathSpan, checkSpan };
|
|
@@ -415,11 +591,14 @@ function createDevDock(initial = {}) {
|
|
|
415
591
|
};
|
|
416
592
|
const renderViews = () => {
|
|
417
593
|
const keyed = keyViews(opts.views ?? []);
|
|
418
|
-
const sig =
|
|
419
|
-
(
|
|
420
|
-
|
|
594
|
+
const sig = [
|
|
595
|
+
classSig(),
|
|
596
|
+
...keyed.map(
|
|
597
|
+
({ view, key }) => [key, viewOrder(view), view.group ?? "", view.label ?? ""].join(
|
|
598
|
+
"\0"
|
|
599
|
+
)
|
|
421
600
|
)
|
|
422
|
-
|
|
601
|
+
].join("\n");
|
|
423
602
|
if (sig === viewsSig) return;
|
|
424
603
|
viewsSig = sig;
|
|
425
604
|
const live = new Set(keyed.map(({ key }) => key));
|
|
@@ -447,7 +626,7 @@ function createDevDock(initial = {}) {
|
|
|
447
626
|
});
|
|
448
627
|
}
|
|
449
628
|
for (const section of sections.values()) {
|
|
450
|
-
const wrap = el("div", {
|
|
629
|
+
const wrap = el("div", { className: cls("section") });
|
|
451
630
|
if (section.heading) wrap.appendChild(sectionHeading(section.heading));
|
|
452
631
|
for (const { view, key } of section.items) {
|
|
453
632
|
if (view.group != null && view.label)
|
|
@@ -457,7 +636,7 @@ function createDevDock(initial = {}) {
|
|
|
457
636
|
wrap.appendChild(existing.host);
|
|
458
637
|
continue;
|
|
459
638
|
}
|
|
460
|
-
const viewHost = el("div", {
|
|
639
|
+
const viewHost = el("div", { className: cls("view") });
|
|
461
640
|
viewHost.setAttribute("data-devdock-view", view.id ?? "");
|
|
462
641
|
wrap.appendChild(viewHost);
|
|
463
642
|
pending.push({ view, key, host: viewHost });
|
|
@@ -484,7 +663,9 @@ function createDevDock(initial = {}) {
|
|
|
484
663
|
}
|
|
485
664
|
}
|
|
486
665
|
const sheets = [
|
|
487
|
-
...document.querySelectorAll(
|
|
666
|
+
...document.querySelectorAll(
|
|
667
|
+
`style:not([${STYLE_MARKER}]), link[rel~="stylesheet" i]`
|
|
668
|
+
)
|
|
488
669
|
];
|
|
489
670
|
const sig = sheets.map((n) => `${n.tagName}\0${n.getAttribute("href") ?? n.textContent}`).join("\n");
|
|
490
671
|
if (sig === clonesSig) return;
|
|
@@ -526,12 +707,17 @@ function createDevDock(initial = {}) {
|
|
|
526
707
|
right: ""
|
|
527
708
|
});
|
|
528
709
|
Object.assign(root.style, cornerStyle(position));
|
|
529
|
-
|
|
710
|
+
headingText.textContent = opts.title ?? "Dev Menu";
|
|
530
711
|
panel.setAttribute("aria-label", opts.title ?? "Dev Menu");
|
|
531
712
|
Object.assign(panel.style, panelAnchor(position));
|
|
532
713
|
buttonLabel.textContent = opts.label ?? "DEV";
|
|
533
|
-
|
|
714
|
+
const spec = hotkey();
|
|
715
|
+
const chord = spec ? formatHotkey(spec) : "";
|
|
716
|
+
hotkeyHint.textContent = chord;
|
|
717
|
+
hotkeyHint.hidden = !chord;
|
|
718
|
+
button.title = chord ? `${opts.title ?? "Dev Menu"} (${chord})` : opts.title ?? "Dev Menu";
|
|
534
719
|
button.setAttribute("aria-expanded", String(open));
|
|
720
|
+
paintClasses();
|
|
535
721
|
};
|
|
536
722
|
function setOpen(next) {
|
|
537
723
|
if (open === next) return;
|
|
@@ -578,7 +764,8 @@ function createDevDock(initial = {}) {
|
|
|
578
764
|
if (open && !e.composedPath().includes(root)) setOpen(false);
|
|
579
765
|
};
|
|
580
766
|
const onKeyDown = (e) => {
|
|
581
|
-
|
|
767
|
+
const spec = hotkey();
|
|
768
|
+
if (spec && matchHotkey(spec, e)) {
|
|
582
769
|
e.preventDefault();
|
|
583
770
|
setOpen(!open);
|
|
584
771
|
}
|
|
@@ -593,6 +780,8 @@ function createDevDock(initial = {}) {
|
|
|
593
780
|
};
|
|
594
781
|
const mount = () => {
|
|
595
782
|
if (mounted) return;
|
|
783
|
+
if (!shadowRoot)
|
|
784
|
+
(document.head ?? document.documentElement).prepend(baseStyle);
|
|
596
785
|
(opts.container ?? document.body).appendChild(host);
|
|
597
786
|
addListeners();
|
|
598
787
|
syncStyles();
|
|
@@ -603,6 +792,7 @@ function createDevDock(initial = {}) {
|
|
|
603
792
|
if (!mounted) return;
|
|
604
793
|
removeListeners();
|
|
605
794
|
unwatchStyles();
|
|
795
|
+
if (!shadowRoot) baseStyle.remove();
|
|
606
796
|
host.remove();
|
|
607
797
|
mounted = false;
|
|
608
798
|
};
|