@chuvenger/devdock 0.4.0 → 0.5.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 (44) hide show
  1. package/README.md +171 -16
  2. package/dist/chunk-3MVFATRN.js +60 -0
  3. package/dist/chunk-3MVFATRN.js.map +1 -0
  4. package/dist/{chunk-F2KWDPMA.js → chunk-NXZNFF34.js} +238 -42
  5. package/dist/chunk-NXZNFF34.js.map +1 -0
  6. package/dist/{dock-CvTtAelh.d.ts → dock-P6l6pKjS.d.ts} +1 -1
  7. package/dist/{dock-Du6Im767.d.cts → dock-d3HqT25k.d.cts} +1 -1
  8. package/dist/index.cjs +235 -39
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +2 -2
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +1 -1
  13. package/dist/{match-B6LN1RRP.d.cts → match-DDSJIRYW.d.cts} +1 -1
  14. package/dist/{match-C-mY8W8T.d.ts → match-DwGIF1Xt.d.ts} +1 -1
  15. package/dist/react-router.cjs +276 -47
  16. package/dist/react-router.cjs.map +1 -1
  17. package/dist/react-router.d.cts +2 -2
  18. package/dist/react-router.d.ts +2 -2
  19. package/dist/react-router.js +2 -2
  20. package/dist/react.cjs +277 -47
  21. package/dist/react.cjs.map +1 -1
  22. package/dist/react.d.cts +28 -8
  23. package/dist/react.d.ts +28 -8
  24. package/dist/react.js +2 -2
  25. package/dist/svelte.cjs +235 -39
  26. package/dist/svelte.cjs.map +1 -1
  27. package/dist/svelte.d.cts +3 -3
  28. package/dist/svelte.d.ts +3 -3
  29. package/dist/svelte.js +2 -2
  30. package/dist/svelte.js.map +1 -1
  31. package/dist/sveltekit.cjs +235 -39
  32. package/dist/sveltekit.cjs.map +1 -1
  33. package/dist/sveltekit.d.cts +4 -4
  34. package/dist/sveltekit.d.ts +4 -4
  35. package/dist/sveltekit.js +2 -2
  36. package/dist/sveltekit.js.map +1 -1
  37. package/dist/types-B_SpF32A.d.cts +157 -0
  38. package/dist/types-B_SpF32A.d.ts +157 -0
  39. package/package.json +1 -1
  40. package/dist/chunk-D5IQBV2K.js +0 -24
  41. package/dist/chunk-D5IQBV2K.js.map +0 -1
  42. package/dist/chunk-F2KWDPMA.js.map +0 -1
  43. package/dist/types-fhhRek-e.d.cts +0 -88
  44. package/dist/types-fhhRek-e.d.ts +0 -88
@@ -19,7 +19,16 @@ function matchHotkey(spec, e) {
19
19
  }
20
20
 
21
21
  // src/core/dock.ts
22
+ var viteDevFlag = () => {
23
+ try {
24
+ if (typeof undefined.DEV === "boolean") return undefined.DEV;
25
+ } catch {
26
+ }
27
+ return void 0;
28
+ };
22
29
  var isDevBuild = () => {
30
+ const vite = viteDevFlag();
31
+ if (vite !== void 0) return vite;
23
32
  try {
24
33
  return process.env.NODE_ENV !== "production";
25
34
  } catch {
@@ -45,6 +54,27 @@ function el(tag, styles, props) {
45
54
  if (props) Object.assign(node, props);
46
55
  return node;
47
56
  }
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
+ }
48
78
  function cornerStyle(position) {
49
79
  const gap = "16px";
50
80
  switch (position) {
@@ -68,6 +98,15 @@ function panelAnchor(position) {
68
98
  };
69
99
  }
70
100
  var FONT = "ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif";
101
+ function keyViews(views) {
102
+ const used = /* @__PURE__ */ new Set();
103
+ return views.map((view, i) => {
104
+ let key = view.id ?? `#${i}`;
105
+ while (used.has(key)) key = `${key}#${i}`;
106
+ used.add(key);
107
+ return { view, key };
108
+ });
109
+ }
71
110
  function createDevDock(initial = {}) {
72
111
  if (typeof document === "undefined") {
73
112
  return { update() {
@@ -81,9 +120,12 @@ function createDevDock(initial = {}) {
81
120
  let mounted = false;
82
121
  const host = el("div");
83
122
  host.setAttribute("data-devdock", "");
84
- const useShadow = (initial.shadow ?? true) && typeof host.attachShadow === "function";
123
+ const shadowMode = initial.shadow ?? true;
124
+ const useShadow = shadowMode !== false && typeof host.attachShadow === "function";
85
125
  const shadowRoot = useShadow ? host.attachShadow({ mode: "open" }) : null;
86
126
  const mountPoint = shadowRoot ?? host;
127
+ const styleSlot = shadowRoot && shadowMode === "inherit" ? el("div", { display: "contents" }) : null;
128
+ if (styleSlot) mountPoint.appendChild(styleSlot);
87
129
  const root = el("div", { fontFamily: FONT });
88
130
  mountPoint.appendChild(root);
89
131
  const panel = el("div", {
@@ -122,8 +164,19 @@ function createDevDock(initial = {}) {
122
164
  });
123
165
  input.placeholder = "Filter\u2026";
124
166
  inputWrap.appendChild(input);
125
- const list = el("div", { overflowY: "auto", padding: "0 6px 8px" });
126
- panel.append(heading, inputWrap, list);
167
+ const list = el("div", { padding: "0 6px 8px" });
168
+ list.setAttribute("data-devdock-list", "");
169
+ const viewsBefore = el("div");
170
+ viewsBefore.setAttribute("data-devdock-views", "before");
171
+ const viewsAfter = el("div");
172
+ viewsAfter.setAttribute("data-devdock-views", "after");
173
+ const body = el("div", {
174
+ overflowY: "auto",
175
+ display: "flex",
176
+ flexDirection: "column"
177
+ });
178
+ body.append(viewsBefore, list, viewsAfter);
179
+ panel.append(heading, inputWrap, body);
127
180
  const button = el("button", {
128
181
  display: "inline-flex",
129
182
  alignItems: "center",
@@ -164,20 +217,35 @@ function createDevDock(initial = {}) {
164
217
  const buildItems = () => {
165
218
  const out = [];
166
219
  (opts.routes ?? []).forEach((r, i) => {
220
+ const key = `route:${r.path}:${i}`;
221
+ const label = r.label ?? r.path;
167
222
  out.push({
168
223
  kind: "route",
169
- key: `route:${r.path}:${i}`,
170
- label: r.label ?? r.path,
224
+ key,
225
+ label,
171
226
  group: r.group ?? "Routes",
227
+ sig: [key, r.group ?? "Routes", label, r.path].join("\0"),
172
228
  route: r
173
229
  });
174
230
  });
175
231
  (opts.commands ?? []).forEach((c, i) => {
232
+ const live = typeof c.label === "function";
233
+ const label = typeof c.label === "function" ? c.label() : c.label;
234
+ const checked = c.checked ? c.checked() === true : null;
235
+ const key = `cmd:${c.id ?? (live ? "" : label)}:${i}`;
236
+ const group = c.group ?? "Commands";
176
237
  out.push({
177
238
  kind: "command",
178
- key: `cmd:${c.id ?? c.label}:${i}`,
179
- label: c.label,
180
- group: c.group ?? "Commands",
239
+ key,
240
+ label,
241
+ group,
242
+ sig: [
243
+ key,
244
+ group,
245
+ live ? "\0live" : label,
246
+ checked === null ? "" : "\0checkable"
247
+ ].join("\0"),
248
+ checked,
181
249
  command: c
182
250
  });
183
251
  });
@@ -205,9 +273,17 @@ function createDevDock(initial = {}) {
205
273
  };
206
274
  let rows = [];
207
275
  let rowsSig = null;
208
- const itemSig = (it) => [it.key, it.group, it.label, it.kind === "route" ? it.route.path : ""].join(
209
- "\0"
210
- );
276
+ const itemSig = (it) => it.sig;
277
+ const paintRow = (row) => {
278
+ const it = row.item;
279
+ if (row.labelSpan.textContent !== it.label)
280
+ row.labelSpan.textContent = it.label;
281
+ if (row.checkSpan && it.kind === "command") {
282
+ const on = it.checked === true;
283
+ row.checkSpan.textContent = on ? "\u2713" : "";
284
+ row.node.setAttribute("aria-checked", String(on));
285
+ }
286
+ };
211
287
  const paintActive = () => {
212
288
  rows.forEach((row, idx) => {
213
289
  const isActive = idx === active;
@@ -229,7 +305,9 @@ function createDevDock(initial = {}) {
229
305
  if (sig === rowsSig) {
230
306
  filtered.forEach((it, idx) => {
231
307
  const row = rows[idx];
232
- if (row) row.item = it;
308
+ if (!row) return;
309
+ row.item = it;
310
+ paintRow(row);
233
311
  });
234
312
  paintActive();
235
313
  return;
@@ -255,20 +333,7 @@ function createDevDock(initial = {}) {
255
333
  }
256
334
  for (const [groupName, groupItems] of groups) {
257
335
  const section = el("div", { marginTop: "6px" });
258
- section.appendChild(
259
- el(
260
- "div",
261
- {
262
- padding: "6px 8px 2px",
263
- fontSize: "10px",
264
- fontWeight: "700",
265
- letterSpacing: "0.6px",
266
- textTransform: "uppercase",
267
- color: "#6b7280"
268
- },
269
- { textContent: groupName }
270
- )
271
- );
336
+ section.appendChild(sectionHeading(groupName));
272
337
  for (const it of groupItems) {
273
338
  const idx = filtered.indexOf(it);
274
339
  const row = el("button", {
@@ -287,15 +352,11 @@ function createDevDock(initial = {}) {
287
352
  cursor: "pointer"
288
353
  });
289
354
  row.type = "button";
290
- const labelSpan = el(
291
- "span",
292
- {
293
- overflow: "hidden",
294
- textOverflow: "ellipsis",
295
- whiteSpace: "nowrap"
296
- },
297
- { textContent: it.label }
298
- );
355
+ const labelSpan = el("span", {
356
+ overflow: "hidden",
357
+ textOverflow: "ellipsis",
358
+ whiteSpace: "nowrap"
359
+ });
299
360
  row.appendChild(labelSpan);
300
361
  let pathSpan = null;
301
362
  if (it.kind === "route" && it.route.path !== it.label) {
@@ -311,8 +372,20 @@ function createDevDock(initial = {}) {
311
372
  );
312
373
  row.appendChild(pathSpan);
313
374
  }
314
- const rec = { item: it, node: row, pathSpan };
375
+ let checkSpan = null;
376
+ if (it.kind === "command" && it.checked !== null) {
377
+ row.setAttribute("role", "checkbox");
378
+ checkSpan = el("span", {
379
+ flexShrink: "0",
380
+ width: "12px",
381
+ textAlign: "center",
382
+ color: "#22c55e"
383
+ });
384
+ row.appendChild(checkSpan);
385
+ }
386
+ const rec = { item: it, node: row, labelSpan, pathSpan, checkSpan };
315
387
  rows[idx] = rec;
388
+ paintRow(rec);
316
389
  row.addEventListener("mouseenter", () => setActive(idx));
317
390
  row.addEventListener("click", () => void runItem(rec.item));
318
391
  section.appendChild(row);
@@ -321,6 +394,120 @@ function createDevDock(initial = {}) {
321
394
  }
322
395
  paintActive();
323
396
  };
397
+ const mountedViews = /* @__PURE__ */ new Map();
398
+ let viewsSig = null;
399
+ const viewOrder = (v) => v.order === "after" ? "after" : "before";
400
+ const unmountViews = () => {
401
+ for (const mv of mountedViews.values()) {
402
+ mv.teardown?.();
403
+ mv.host.remove();
404
+ }
405
+ mountedViews.clear();
406
+ viewsBefore.replaceChildren();
407
+ viewsAfter.replaceChildren();
408
+ viewsSig = null;
409
+ };
410
+ const renderViews = () => {
411
+ const keyed = keyViews(opts.views ?? []);
412
+ const sig = keyed.map(
413
+ ({ view, key }) => [key, viewOrder(view), view.group ?? "", view.label ?? ""].join(
414
+ "\0"
415
+ )
416
+ ).join("\n");
417
+ if (sig === viewsSig) return;
418
+ viewsSig = sig;
419
+ const live = new Set(keyed.map(({ key }) => key));
420
+ for (const [key, mv] of mountedViews) {
421
+ if (live.has(key)) continue;
422
+ mv.teardown?.();
423
+ mv.host.remove();
424
+ mountedViews.delete(key);
425
+ }
426
+ viewsBefore.replaceChildren();
427
+ viewsAfter.replaceChildren();
428
+ const pending = [];
429
+ for (const placement of ["before", "after"]) {
430
+ const container = placement === "before" ? viewsBefore : viewsAfter;
431
+ const here = keyed.filter(({ view }) => viewOrder(view) === placement);
432
+ const sections = /* @__PURE__ */ new Map();
433
+ for (const entry of here) {
434
+ const groupKey = entry.view.group ?? `\0${entry.key}`;
435
+ const section = sections.get(groupKey);
436
+ if (section) section.items.push(entry);
437
+ else
438
+ sections.set(groupKey, {
439
+ heading: entry.view.group ?? entry.view.label,
440
+ items: [entry]
441
+ });
442
+ }
443
+ for (const section of sections.values()) {
444
+ const wrap = el("div", { marginTop: "6px" });
445
+ if (section.heading) wrap.appendChild(sectionHeading(section.heading));
446
+ for (const { view, key } of section.items) {
447
+ if (view.group != null && view.label)
448
+ wrap.appendChild(viewLabel(view.label));
449
+ const existing = mountedViews.get(key);
450
+ if (existing) {
451
+ wrap.appendChild(existing.host);
452
+ continue;
453
+ }
454
+ const viewHost = el("div", { padding: "2px 8px 6px" });
455
+ viewHost.setAttribute("data-devdock-view", view.id ?? "");
456
+ wrap.appendChild(viewHost);
457
+ pending.push({ view, key, host: viewHost });
458
+ }
459
+ container.appendChild(wrap);
460
+ }
461
+ }
462
+ for (const { view, key, host: viewHost } of pending) {
463
+ const mv = { host: viewHost };
464
+ mountedViews.set(key, mv);
465
+ const teardown = view.mount(viewHost);
466
+ if (typeof teardown === "function") mv.teardown = teardown;
467
+ }
468
+ };
469
+ let clonesSig = null;
470
+ const syncStyles = () => {
471
+ if (!styleSlot || !shadowRoot) return;
472
+ const adopted = document.adoptedStyleSheets;
473
+ if (Array.isArray(adopted)) {
474
+ try {
475
+ const sr = shadowRoot;
476
+ sr.adoptedStyleSheets = [...adopted];
477
+ } catch {
478
+ }
479
+ }
480
+ const sheets = [
481
+ ...document.querySelectorAll('style, link[rel~="stylesheet" i]')
482
+ ];
483
+ const sig = sheets.map((n) => `${n.tagName}\0${n.getAttribute("href") ?? n.textContent}`).join("\n");
484
+ if (sig === clonesSig) return;
485
+ clonesSig = sig;
486
+ styleSlot.replaceChildren(...sheets.map((n) => n.cloneNode(true)));
487
+ };
488
+ let styleObserver = null;
489
+ let syncQueued = false;
490
+ const watchStyles = () => {
491
+ if (!styleSlot || styleObserver || !document.head || typeof MutationObserver === "undefined")
492
+ return;
493
+ styleObserver = new MutationObserver(() => {
494
+ if (syncQueued) return;
495
+ syncQueued = true;
496
+ queueMicrotask(() => {
497
+ syncQueued = false;
498
+ syncStyles();
499
+ });
500
+ });
501
+ styleObserver.observe(document.head, {
502
+ childList: true,
503
+ subtree: true,
504
+ characterData: true
505
+ });
506
+ };
507
+ const unwatchStyles = () => {
508
+ styleObserver?.disconnect();
509
+ styleObserver = null;
510
+ };
324
511
  const renderShell = () => {
325
512
  const position = opts.position ?? "bottom-right";
326
513
  const zIndex = opts.zIndex ?? 2147483e3;
@@ -350,9 +537,12 @@ function createDevDock(initial = {}) {
350
537
  panel.isConnected || root.insertBefore(panel, button);
351
538
  renderShell();
352
539
  renderList();
540
+ syncStyles();
541
+ renderViews();
353
542
  requestAnimationFrame(() => input.focus());
354
- } else if (panel.isConnected) {
355
- panel.remove();
543
+ } else {
544
+ unmountViews();
545
+ if (panel.isConnected) panel.remove();
356
546
  }
357
547
  renderShell();
358
548
  }
@@ -399,11 +589,14 @@ function createDevDock(initial = {}) {
399
589
  if (mounted) return;
400
590
  (opts.container ?? document.body).appendChild(host);
401
591
  addListeners();
592
+ syncStyles();
593
+ watchStyles();
402
594
  mounted = true;
403
595
  };
404
596
  const unmount = () => {
405
597
  if (!mounted) return;
406
598
  removeListeners();
599
+ unwatchStyles();
407
600
  host.remove();
408
601
  mounted = false;
409
602
  };
@@ -415,7 +608,10 @@ function createDevDock(initial = {}) {
415
608
  if (enabled()) {
416
609
  mount();
417
610
  renderShell();
418
- if (open) renderList();
611
+ if (open) {
612
+ renderList();
613
+ renderViews();
614
+ }
419
615
  } else {
420
616
  setOpen(false);
421
617
  unmount();