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