@chuvenger/devdock 0.1.3 → 0.2.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 CHANGED
@@ -8,7 +8,7 @@ app, **only renders in development**, and opens a popup to jump between dev
8
8
  routes and run custom commands.
9
9
 
10
10
  - 🔒 **Dev-gated by default** — hidden when `process.env.NODE_ENV === "production"`. Fully overridable.
11
- - 🧭 **Route jumper** — list routes manually, or auto-detect them from React Router.
11
+ - 🧭 **Route jumper** — list routes manually, or auto-detect your `/dev` routes from React Router.
12
12
  - ⚡ **Custom commands** — register any action (reset DB, toggle a flag, copy a token…).
13
13
  - 🔎 Filter box + keyboard nav (↑/↓/Enter/Esc) and an optional global hotkey.
14
14
  - 🎨 Zero CSS to import — inline-styled, high z-index, no runtime dependencies.
@@ -92,21 +92,42 @@ The adapter imports `useNavigate` / `UNSAFE_DataRouterContext` from
92
92
  package comes in via `react-router-dom`; with a strict package manager (pnpm)
93
93
  add `react-router` to your own deps so it resolves.
94
94
 
95
- Render it inside the router tree. Dynamic (`:id`) and splat (`*`) routes are
96
- skipped since they need arguments. Customize per route via React Router's
97
- `handle`:
95
+ Render it inside the router tree. **Only dev routes are listed by default.** A
96
+ route counts as one if it lives under `/dev`, or if you opt it in via React
97
+ Router's `handle`:
98
98
 
99
99
  ```tsx
100
- { path: "reports", element: <Reports />, handle: { devLabel: "Reports", devGroup: "Internal", hidden: false } }
100
+ { path: "/dev/inspector", element: <Inspector /> } // by convention
101
+ { path: "reports", element: <Reports />, handle: { dev: true } } // opted in
102
+ { path: "flags", element: <Flags />, handle: { devLabel: "Feature Flags", devGroup: "Internal" } }
101
103
  ```
102
104
 
103
- **Scope which routes are detected** with `match` — a glob (`*` = any
104
- characters), a `RegExp`, or a predicate. Manual `routes` are always included:
105
+ Any of `dev`, `devLabel` or `devGroup` marks a route, and both the convention
106
+ and the mark cover the whole subtree — put one on a section's layout route and
107
+ every page inside shows up (inheriting its `devGroup`). Use `handle.hidden` to
108
+ drop one back out.
109
+
110
+ **Want the whole app listed?** Set `staticRoutes` and every static route is
111
+ detected, marked or not:
112
+
113
+ ```tsx
114
+ <ReactRouterDevDock staticRoutes />
115
+ ```
116
+
117
+ Dynamic (`:id`) and splat (`*`) routes are always skipped since they need
118
+ arguments — to reach one, use a command that navigates to a known id:
119
+
120
+ ```tsx
121
+ <ReactRouterDevDock commands={[{ label: "Sample user", run: () => navigate("/users/42") }]} />
122
+ ```
123
+
124
+ **Scope what's detected** with `match` — a glob (`*` = any characters), a
125
+ `RegExp`, or a predicate. Manual `routes` are always included:
105
126
 
106
127
  ```tsx
107
- <ReactRouterDevDock match="/dev/*" /> // only routes under /dev
108
- <ReactRouterDevDock match={/^\/(admin|dev)/} />
109
- <ReactRouterDevDock match={(r) => r.path.length < 20} />
128
+ <ReactRouterDevDock staticRoutes match="/dev/*" /> // only routes under /dev
129
+ <ReactRouterDevDock staticRoutes match={/^\/(admin|dev)/} />
130
+ <ReactRouterDevDock staticRoutes match={(r) => r.path.length < 20} />
110
131
  ```
111
132
 
112
133
  ## Svelte
@@ -184,7 +205,7 @@ a `data-devdock` attribute either way.
184
205
  | `commands` | `DevCommand[]` | `[]` | Custom actions. |
185
206
  | `enabled` | `boolean \| (() => boolean)` | `NODE_ENV !== "production"` | Whether to render at all. A predicate is re-checked on every update. |
186
207
  | `onNavigate` | `(path: string) => void` | `window.location.assign` | How to navigate on route select. |
187
- | `position` | `"bottom-left" \| "bottom-right" \| "top-left" \| "top-right"` | `"bottom-left"` | Corner. |
208
+ | `position` | `"bottom-left" \| "bottom-right" \| "top-left" \| "top-right"` | `"bottom-right"` | Corner. |
188
209
  | `label` | `string` | `"DEV"` | Button text. |
189
210
  | `title` | `string` | `"Dev Menu"` | Popup heading. |
190
211
  | `hotkey` | `string \| null` | `null` | Toggle shortcut, e.g. `"mod+."`. |
@@ -203,9 +224,9 @@ a `data-devdock` attribute either way.
203
224
 
204
225
  ### `@chuvenger/devdock/react-router`
205
226
 
206
- - `ReactRouterDevDock(props)` — `DevDock` wired to `useNavigate()` + auto-detected routes. Extra prop: `match?: RouteMatcher`.
207
- - `useDetectedRoutes(match?): DevRoute[]` — the detected routes, optionally scoped (build your own UI).
208
- - `flattenRoutes(routes, parent?): DevRoute[]` — pure helper that flattens a route tree.
227
+ - `ReactRouterDevDock(props)` — `DevDock` wired to `useNavigate()` + auto-detected routes. Extra props: `match?: RouteMatcher`, `staticRoutes?: boolean`.
228
+ - `useDetectedRoutes(options?): DevRoute[]` — the detected routes (build your own UI). Takes `{ match?, staticRoutes? }`, or a bare matcher.
229
+ - `flattenRoutes(routes, parent?, options?): DevRoute[]` — pure helper that flattens a route tree.
209
230
  - `RouteMatcher` — `string | RegExp | ((route: DevRoute) => boolean)`.
210
231
 
211
232
  ## Examples
@@ -33,14 +33,14 @@ function el(tag, styles, props) {
33
33
  function cornerStyle(position) {
34
34
  const gap = "16px";
35
35
  switch (position) {
36
- case "bottom-right":
37
- return { bottom: gap, right: gap };
36
+ case "bottom-left":
37
+ return { bottom: gap, left: gap };
38
38
  case "top-left":
39
39
  return { top: gap, left: gap };
40
40
  case "top-right":
41
41
  return { top: gap, right: gap };
42
42
  default:
43
- return { bottom: gap, left: gap };
43
+ return { bottom: gap, right: gap };
44
44
  }
45
45
  }
46
46
  function panelAnchor(position) {
@@ -306,7 +306,7 @@ function createDevDock(initial = {}) {
306
306
  paintActive();
307
307
  };
308
308
  const renderShell = () => {
309
- const position = opts.position ?? "bottom-left";
309
+ const position = opts.position ?? "bottom-right";
310
310
  const zIndex = opts.zIndex ?? 2147483e3;
311
311
  Object.assign(root.style, {
312
312
  position: "fixed",
@@ -413,5 +413,5 @@ function createDevDock(initial = {}) {
413
413
  }
414
414
 
415
415
  export { createDevDock, matchHotkey };
416
- //# sourceMappingURL=chunk-TROB6P6B.js.map
417
- //# sourceMappingURL=chunk-TROB6P6B.js.map
416
+ //# sourceMappingURL=chunk-DUHEBT6Q.js.map
417
+ //# sourceMappingURL=chunk-DUHEBT6Q.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/hotkey.ts","../src/core/dock.ts"],"names":[],"mappings":"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","file":"chunk-TROB6P6B.js","sourcesContent":["/** Parse a hotkey string like \"mod+.\" into a matcher predicate. */\nexport function matchHotkey(spec: string, e: KeyboardEvent): boolean {\n const parts = spec\n .toLowerCase()\n .split(\"+\")\n .map((p) => p.trim())\n .filter(Boolean);\n if (parts.length === 0) return false;\n\n const key = parts[parts.length - 1];\n const mods = new Set(parts.slice(0, -1));\n\n const isMac =\n typeof navigator !== \"undefined\" && /mac/i.test(navigator.platform);\n\n const wantMeta = mods.has(\"meta\") || mods.has(\"cmd\") || (mods.has(\"mod\") && isMac);\n const wantCtrl = mods.has(\"ctrl\") || mods.has(\"control\") || (mods.has(\"mod\") && !isMac);\n const wantShift = mods.has(\"shift\");\n const wantAlt = mods.has(\"alt\") || mods.has(\"option\");\n\n if (e.metaKey !== wantMeta) return false;\n if (e.ctrlKey !== wantCtrl) return false;\n if (e.shiftKey !== wantShift) return false;\n if (e.altKey !== wantAlt) return false;\n\n return e.key.toLowerCase() === key;\n}\n","import { matchHotkey } from \"./hotkey\";\nimport type {\n DevCommand,\n DevDockInstance,\n DevDockOptions,\n DevRoute,\n DockPosition,\n} from \"./types\";\n\nconst isDev = (): boolean => {\n // Bundlers (Vite, webpack, Next, esbuild…) statically replace the full\n // `process.env.NODE_ENV` token, even in browser builds where `process`\n // itself is undefined. Reading it directly lets that replacement work;\n // the try/catch covers runtimes where it's left as a real (missing) global.\n try {\n return process.env.NODE_ENV !== \"production\";\n } catch {\n return false;\n }\n};\n\ntype Item =\n | { kind: \"route\"; key: string; label: string; group: string; route: DevRoute }\n | {\n kind: \"command\";\n key: string;\n label: string;\n group: string;\n command: DevCommand;\n };\n\ntype Styles = Partial<CSSStyleDeclaration>;\n\nfunction el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n styles?: Styles,\n props?: Partial<HTMLElementTagNameMap[K]>,\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (styles) Object.assign(node.style, styles);\n if (props) Object.assign(node, props);\n return node;\n}\n\nfunction cornerStyle(position: DockPosition): Styles {\n const gap = \"16px\";\n switch (position) {\n case \"bottom-right\":\n return { bottom: gap, right: gap };\n case \"top-left\":\n return { top: gap, left: gap };\n case \"top-right\":\n return { top: gap, right: gap };\n default:\n return { bottom: gap, left: gap };\n }\n}\n\nfunction panelAnchor(position: DockPosition): Styles {\n const isTop = position.startsWith(\"top\");\n const isRight = position.endsWith(\"right\");\n return {\n position: \"absolute\",\n [isTop ? \"top\" : \"bottom\"]: \"calc(100% + 8px)\",\n [isRight ? \"right\" : \"left\"]: \"0\",\n } as Styles;\n}\n\nconst FONT =\n \"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif\";\n\n/**\n * Create a framework-agnostic dev dock: a floating button that opens a popup\n * to jump between routes and run commands. Returns a handle to update its\n * options or tear it down. No-ops on the server (when there is no `document`).\n */\nexport function createDevDock(initial: DevDockOptions = {}): DevDockInstance {\n if (typeof document === \"undefined\") {\n return { update() {}, destroy() {} };\n }\n\n let opts: DevDockOptions = { ...initial };\n let open = false;\n let query = \"\";\n let active = 0;\n let mounted = false;\n\n // Light-DOM host that gets appended to the page. When shadow DOM is used,\n // the actual UI lives inside its shadow root — fully isolated from the host\n // page's CSS. `data-devdock` stays on the host so it's discoverable.\n const host = el(\"div\");\n host.setAttribute(\"data-devdock\", \"\");\n const useShadow =\n (initial.shadow ?? true) && typeof host.attachShadow === \"function\";\n const shadowRoot = useShadow ? host.attachShadow({ mode: \"open\" }) : null;\n const mountPoint: Node = shadowRoot ?? host;\n\n const root = el(\"div\", { fontFamily: FONT });\n mountPoint.appendChild(root);\n\n const panel = el(\"div\", {\n width: \"280px\",\n maxHeight: \"min(70vh, 480px)\",\n display: \"flex\",\n flexDirection: \"column\",\n background: \"#16181d\",\n color: \"#e7e9ee\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"12px\",\n boxShadow: \"0 12px 40px rgba(0,0,0,0.45)\",\n overflow: \"hidden\",\n });\n panel.setAttribute(\"role\", \"dialog\");\n\n const heading = el(\"div\", {\n padding: \"10px 12px\",\n borderBottom: \"1px solid #2a2e37\",\n fontSize: \"12px\",\n fontWeight: \"600\",\n letterSpacing: \"0.4px\",\n textTransform: \"uppercase\",\n color: \"#8b909c\",\n });\n\n const inputWrap = el(\"div\", { padding: \"8px\" });\n const input = el(\"input\", {\n width: \"100%\",\n boxSizing: \"border-box\",\n padding: \"8px 10px\",\n fontSize: \"13px\",\n color: \"#e7e9ee\",\n background: \"#0f1115\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"8px\",\n outline: \"none\",\n });\n input.placeholder = \"Filter…\";\n inputWrap.appendChild(input);\n\n const list = el(\"div\", { overflowY: \"auto\", padding: \"0 6px 8px\" });\n\n panel.append(heading, inputWrap, list);\n\n const button = el(\"button\", {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n padding: \"8px 12px\",\n fontSize: \"12px\",\n fontWeight: \"700\",\n letterSpacing: \"0.6px\",\n color: \"#fff\",\n background: \"#111317\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"999px\",\n boxShadow: \"0 4px 14px rgba(0,0,0,0.35)\",\n cursor: \"pointer\",\n });\n button.type = \"button\";\n button.setAttribute(\"aria-label\", \"Toggle dev menu\");\n const dot = el(\"span\", {\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"999px\",\n background: \"#22c55e\",\n display: \"inline-block\",\n });\n const buttonLabel = el(\"span\");\n button.append(dot, buttonLabel);\n\n root.appendChild(button);\n\n // ---- behavior ---------------------------------------------------------\n\n const enabled = (): boolean => {\n const e = opts.enabled;\n if (typeof e === \"function\") return e();\n return e ?? isDev();\n };\n\n const navigate = (path: string) => {\n if (opts.onNavigate) opts.onNavigate(path);\n else if (typeof window !== \"undefined\") window.location.assign(path);\n };\n\n const buildItems = (): Item[] => {\n const out: Item[] = [];\n (opts.routes ?? []).forEach((r, i) => {\n out.push({\n kind: \"route\",\n key: `route:${r.path}:${i}`,\n label: r.label ?? r.path,\n group: r.group ?? \"Routes\",\n route: r,\n });\n });\n (opts.commands ?? []).forEach((c, i) => {\n out.push({\n kind: \"command\",\n key: `cmd:${c.id ?? c.label}:${i}`,\n label: c.label,\n group: c.group ?? \"Commands\",\n command: c,\n });\n });\n return out;\n };\n\n const getFiltered = (): Item[] => {\n const q = query.trim().toLowerCase();\n const items = buildItems();\n if (!q) return items;\n return items.filter(\n (it) =>\n it.label.toLowerCase().includes(q) ||\n (it.kind === \"route\" && it.route.path.toLowerCase().includes(q)),\n );\n };\n\n const runItem = async (it: Item) => {\n if (it.kind === \"route\") {\n navigate(it.route.path);\n setOpen(false);\n return;\n }\n try {\n await it.command.run();\n } finally {\n if (!it.command.keepOpen) setOpen(false);\n }\n };\n\n type Row = {\n item: Item;\n node: HTMLButtonElement;\n pathSpan: HTMLSpanElement | null;\n };\n\n // The rendered rows, parallel to the current filtered list. They are kept\n // around so hovering or arrowing only repaints the highlight: rebuilding the\n // rows would destroy the node under the pointer, and the browser then never\n // dispatches a `click` on it (mousedown/mouseup retarget to the parent).\n let rows: Row[] = [];\n // Signature of the item list the rows were built from; identical signature\n // means the existing nodes can be reused as-is.\n let rowsSig: string | null = null;\n\n const itemSig = (it: Item): string =>\n [it.key, it.group, it.label, it.kind === \"route\" ? it.route.path : \"\"].join(\n \"\\u0000\",\n );\n\n const paintActive = () => {\n rows.forEach((row, idx) => {\n const isActive = idx === active;\n row.node.style.background = isActive ? \"#2563eb\" : \"transparent\";\n if (row.pathSpan)\n row.pathSpan.style.color = isActive ? \"#cfe0ff\" : \"#6b7280\";\n });\n };\n\n const setActive = (next: number, scroll = false) => {\n if (next === active || next < 0 || next >= rows.length) return;\n active = next;\n paintActive();\n // `scrollIntoView` is absent in jsdom, hence the optional call.\n if (scroll) rows[active]?.node.scrollIntoView?.({ block: \"nearest\" });\n };\n\n const renderList = () => {\n const filtered = getFiltered();\n active = Math.min(active, Math.max(0, filtered.length - 1));\n\n const sig = filtered.map(itemSig).join(\"\\n\");\n if (sig === rowsSig) {\n // Same items in the same order: keep the nodes, refresh the highlight.\n // The items themselves are rebuilt on every call, so re-point each row\n // at its current one (its `run`/`route` may have been swapped by\n // `update()`).\n filtered.forEach((it, idx) => {\n const row = rows[idx];\n if (row) row.item = it;\n });\n paintActive();\n return;\n }\n rowsSig = sig;\n rows = [];\n list.replaceChildren();\n\n if (filtered.length === 0) {\n list.appendChild(\n el(\n \"div\",\n { padding: \"12px\", fontSize: \"13px\", color: \"#6b7280\" },\n { textContent: \"Nothing here.\" },\n ),\n );\n return;\n }\n\n const groups = new Map<string, Item[]>();\n for (const it of filtered) {\n const arr = groups.get(it.group) ?? [];\n arr.push(it);\n groups.set(it.group, arr);\n }\n\n for (const [groupName, groupItems] of groups) {\n const section = el(\"div\", { marginTop: \"6px\" });\n section.appendChild(\n el(\n \"div\",\n {\n padding: \"6px 8px 2px\",\n fontSize: \"10px\",\n fontWeight: \"700\",\n letterSpacing: \"0.6px\",\n textTransform: \"uppercase\",\n color: \"#6b7280\",\n },\n { textContent: groupName },\n ),\n );\n\n for (const it of groupItems) {\n const idx = filtered.indexOf(it);\n const row = el(\"button\", {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: \"8px\",\n width: \"100%\",\n textAlign: \"left\",\n padding: \"8px 10px\",\n fontSize: \"13px\",\n color: \"#e7e9ee\",\n background: \"transparent\",\n border: \"none\",\n borderRadius: \"8px\",\n cursor: \"pointer\",\n });\n row.type = \"button\";\n\n const labelSpan = el(\n \"span\",\n {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n },\n { textContent: it.label },\n );\n row.appendChild(labelSpan);\n\n let pathSpan: HTMLSpanElement | null = null;\n if (it.kind === \"route\" && it.route.path !== it.label) {\n pathSpan = el(\n \"span\",\n {\n fontSize: \"11px\",\n color: \"#6b7280\",\n fontFamily: \"ui-monospace, SFMono-Regular, monospace\",\n flexShrink: \"0\",\n },\n { textContent: it.route.path },\n );\n row.appendChild(pathSpan);\n }\n\n const rec: Row = { item: it, node: row, pathSpan };\n rows[idx] = rec;\n\n row.addEventListener(\"mouseenter\", () => setActive(idx));\n row.addEventListener(\"click\", () => void runItem(rec.item));\n section.appendChild(row);\n }\n list.appendChild(section);\n }\n\n paintActive();\n };\n\n const renderShell = () => {\n const position = opts.position ?? \"bottom-left\";\n const zIndex = opts.zIndex ?? 2147483000;\n\n Object.assign(root.style, {\n position: \"fixed\",\n zIndex: String(zIndex),\n top: \"\",\n bottom: \"\",\n left: \"\",\n right: \"\",\n });\n Object.assign(root.style, cornerStyle(position));\n\n heading.textContent = opts.title ?? \"Dev Menu\";\n panel.setAttribute(\"aria-label\", opts.title ?? \"Dev Menu\");\n Object.assign(panel.style, panelAnchor(position));\n\n buttonLabel.textContent = opts.label ?? \"DEV\";\n button.style.background = open ? \"#2563eb\" : \"#111317\";\n button.setAttribute(\"aria-expanded\", String(open));\n };\n\n function setOpen(next: boolean) {\n if (open === next) return;\n open = next;\n if (open) {\n query = \"\";\n input.value = \"\";\n active = 0;\n panel.isConnected || root.insertBefore(panel, button);\n renderShell();\n renderList();\n requestAnimationFrame(() => input.focus());\n } else if (panel.isConnected) {\n panel.remove();\n }\n renderShell();\n }\n\n // ---- listeners --------------------------------------------------------\n\n input.addEventListener(\"input\", () => {\n query = input.value;\n active = 0;\n renderList();\n });\n\n panel.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n setOpen(false);\n } else if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive(Math.min(active + 1, rows.length - 1), true);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive(Math.max(active - 1, 0), true);\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n const it = rows[active]?.item;\n if (it) void runItem(it);\n }\n });\n\n button.addEventListener(\"click\", () => setOpen(!open));\n\n const onDocMouseDown = (e: MouseEvent) => {\n // composedPath() sees through the shadow boundary; a plain\n // `contains(e.target)` would miss clicks inside the shadow root.\n if (open && !e.composedPath().includes(root)) setOpen(false);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (opts.hotkey && matchHotkey(opts.hotkey, e)) {\n e.preventDefault();\n setOpen(!open);\n }\n };\n\n const addListeners = () => {\n document.addEventListener(\"mousedown\", onDocMouseDown);\n window.addEventListener(\"keydown\", onKeyDown);\n };\n const removeListeners = () => {\n document.removeEventListener(\"mousedown\", onDocMouseDown);\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n\n const mount = () => {\n if (mounted) return;\n (opts.container ?? document.body).appendChild(host);\n addListeners();\n mounted = true;\n };\n const unmount = () => {\n if (!mounted) return;\n removeListeners();\n host.remove();\n mounted = false;\n };\n\n // ---- init -------------------------------------------------------------\n\n renderShell();\n if (enabled()) mount();\n\n return {\n update(next: DevDockOptions) {\n opts = { ...opts, ...next };\n if (enabled()) {\n mount();\n renderShell();\n if (open) renderList();\n } else {\n setOpen(false);\n unmount();\n }\n },\n destroy() {\n setOpen(false);\n unmount();\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/core/hotkey.ts","../src/core/dock.ts"],"names":[],"mappings":"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","file":"chunk-DUHEBT6Q.js","sourcesContent":["/** Parse a hotkey string like \"mod+.\" into a matcher predicate. */\nexport function matchHotkey(spec: string, e: KeyboardEvent): boolean {\n const parts = spec\n .toLowerCase()\n .split(\"+\")\n .map((p) => p.trim())\n .filter(Boolean);\n if (parts.length === 0) return false;\n\n const key = parts[parts.length - 1];\n const mods = new Set(parts.slice(0, -1));\n\n const isMac =\n typeof navigator !== \"undefined\" && /mac/i.test(navigator.platform);\n\n const wantMeta = mods.has(\"meta\") || mods.has(\"cmd\") || (mods.has(\"mod\") && isMac);\n const wantCtrl = mods.has(\"ctrl\") || mods.has(\"control\") || (mods.has(\"mod\") && !isMac);\n const wantShift = mods.has(\"shift\");\n const wantAlt = mods.has(\"alt\") || mods.has(\"option\");\n\n if (e.metaKey !== wantMeta) return false;\n if (e.ctrlKey !== wantCtrl) return false;\n if (e.shiftKey !== wantShift) return false;\n if (e.altKey !== wantAlt) return false;\n\n return e.key.toLowerCase() === key;\n}\n","import { matchHotkey } from \"./hotkey\";\nimport type {\n DevCommand,\n DevDockInstance,\n DevDockOptions,\n DevRoute,\n DockPosition,\n} from \"./types\";\n\nconst isDev = (): boolean => {\n // Bundlers (Vite, webpack, Next, esbuild…) statically replace the full\n // `process.env.NODE_ENV` token, even in browser builds where `process`\n // itself is undefined. Reading it directly lets that replacement work;\n // the try/catch covers runtimes where it's left as a real (missing) global.\n try {\n return process.env.NODE_ENV !== \"production\";\n } catch {\n return false;\n }\n};\n\ntype Item =\n | { kind: \"route\"; key: string; label: string; group: string; route: DevRoute }\n | {\n kind: \"command\";\n key: string;\n label: string;\n group: string;\n command: DevCommand;\n };\n\ntype Styles = Partial<CSSStyleDeclaration>;\n\nfunction el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n styles?: Styles,\n props?: Partial<HTMLElementTagNameMap[K]>,\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (styles) Object.assign(node.style, styles);\n if (props) Object.assign(node, props);\n return node;\n}\n\nfunction cornerStyle(position: DockPosition): Styles {\n const gap = \"16px\";\n switch (position) {\n case \"bottom-left\":\n return { bottom: gap, left: gap };\n case \"top-left\":\n return { top: gap, left: gap };\n case \"top-right\":\n return { top: gap, right: gap };\n default:\n return { bottom: gap, right: gap };\n }\n}\n\nfunction panelAnchor(position: DockPosition): Styles {\n const isTop = position.startsWith(\"top\");\n const isRight = position.endsWith(\"right\");\n return {\n position: \"absolute\",\n [isTop ? \"top\" : \"bottom\"]: \"calc(100% + 8px)\",\n [isRight ? \"right\" : \"left\"]: \"0\",\n } as Styles;\n}\n\nconst FONT =\n \"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif\";\n\n/**\n * Create a framework-agnostic dev dock: a floating button that opens a popup\n * to jump between routes and run commands. Returns a handle to update its\n * options or tear it down. No-ops on the server (when there is no `document`).\n */\nexport function createDevDock(initial: DevDockOptions = {}): DevDockInstance {\n if (typeof document === \"undefined\") {\n return { update() {}, destroy() {} };\n }\n\n let opts: DevDockOptions = { ...initial };\n let open = false;\n let query = \"\";\n let active = 0;\n let mounted = false;\n\n // Light-DOM host that gets appended to the page. When shadow DOM is used,\n // the actual UI lives inside its shadow root — fully isolated from the host\n // page's CSS. `data-devdock` stays on the host so it's discoverable.\n const host = el(\"div\");\n host.setAttribute(\"data-devdock\", \"\");\n const useShadow =\n (initial.shadow ?? true) && typeof host.attachShadow === \"function\";\n const shadowRoot = useShadow ? host.attachShadow({ mode: \"open\" }) : null;\n const mountPoint: Node = shadowRoot ?? host;\n\n const root = el(\"div\", { fontFamily: FONT });\n mountPoint.appendChild(root);\n\n const panel = el(\"div\", {\n width: \"280px\",\n maxHeight: \"min(70vh, 480px)\",\n display: \"flex\",\n flexDirection: \"column\",\n background: \"#16181d\",\n color: \"#e7e9ee\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"12px\",\n boxShadow: \"0 12px 40px rgba(0,0,0,0.45)\",\n overflow: \"hidden\",\n });\n panel.setAttribute(\"role\", \"dialog\");\n\n const heading = el(\"div\", {\n padding: \"10px 12px\",\n borderBottom: \"1px solid #2a2e37\",\n fontSize: \"12px\",\n fontWeight: \"600\",\n letterSpacing: \"0.4px\",\n textTransform: \"uppercase\",\n color: \"#8b909c\",\n });\n\n const inputWrap = el(\"div\", { padding: \"8px\" });\n const input = el(\"input\", {\n width: \"100%\",\n boxSizing: \"border-box\",\n padding: \"8px 10px\",\n fontSize: \"13px\",\n color: \"#e7e9ee\",\n background: \"#0f1115\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"8px\",\n outline: \"none\",\n });\n input.placeholder = \"Filter…\";\n inputWrap.appendChild(input);\n\n const list = el(\"div\", { overflowY: \"auto\", padding: \"0 6px 8px\" });\n\n panel.append(heading, inputWrap, list);\n\n const button = el(\"button\", {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n padding: \"8px 12px\",\n fontSize: \"12px\",\n fontWeight: \"700\",\n letterSpacing: \"0.6px\",\n color: \"#fff\",\n background: \"#111317\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"999px\",\n boxShadow: \"0 4px 14px rgba(0,0,0,0.35)\",\n cursor: \"pointer\",\n });\n button.type = \"button\";\n button.setAttribute(\"aria-label\", \"Toggle dev menu\");\n const dot = el(\"span\", {\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"999px\",\n background: \"#22c55e\",\n display: \"inline-block\",\n });\n const buttonLabel = el(\"span\");\n button.append(dot, buttonLabel);\n\n root.appendChild(button);\n\n // ---- behavior ---------------------------------------------------------\n\n const enabled = (): boolean => {\n const e = opts.enabled;\n if (typeof e === \"function\") return e();\n return e ?? isDev();\n };\n\n const navigate = (path: string) => {\n if (opts.onNavigate) opts.onNavigate(path);\n else if (typeof window !== \"undefined\") window.location.assign(path);\n };\n\n const buildItems = (): Item[] => {\n const out: Item[] = [];\n (opts.routes ?? []).forEach((r, i) => {\n out.push({\n kind: \"route\",\n key: `route:${r.path}:${i}`,\n label: r.label ?? r.path,\n group: r.group ?? \"Routes\",\n route: r,\n });\n });\n (opts.commands ?? []).forEach((c, i) => {\n out.push({\n kind: \"command\",\n key: `cmd:${c.id ?? c.label}:${i}`,\n label: c.label,\n group: c.group ?? \"Commands\",\n command: c,\n });\n });\n return out;\n };\n\n const getFiltered = (): Item[] => {\n const q = query.trim().toLowerCase();\n const items = buildItems();\n if (!q) return items;\n return items.filter(\n (it) =>\n it.label.toLowerCase().includes(q) ||\n (it.kind === \"route\" && it.route.path.toLowerCase().includes(q)),\n );\n };\n\n const runItem = async (it: Item) => {\n if (it.kind === \"route\") {\n navigate(it.route.path);\n setOpen(false);\n return;\n }\n try {\n await it.command.run();\n } finally {\n if (!it.command.keepOpen) setOpen(false);\n }\n };\n\n type Row = {\n item: Item;\n node: HTMLButtonElement;\n pathSpan: HTMLSpanElement | null;\n };\n\n // The rendered rows, parallel to the current filtered list. They are kept\n // around so hovering or arrowing only repaints the highlight: rebuilding the\n // rows would destroy the node under the pointer, and the browser then never\n // dispatches a `click` on it (mousedown/mouseup retarget to the parent).\n let rows: Row[] = [];\n // Signature of the item list the rows were built from; identical signature\n // means the existing nodes can be reused as-is.\n let rowsSig: string | null = null;\n\n const itemSig = (it: Item): string =>\n [it.key, it.group, it.label, it.kind === \"route\" ? it.route.path : \"\"].join(\n \"\\u0000\",\n );\n\n const paintActive = () => {\n rows.forEach((row, idx) => {\n const isActive = idx === active;\n row.node.style.background = isActive ? \"#2563eb\" : \"transparent\";\n if (row.pathSpan)\n row.pathSpan.style.color = isActive ? \"#cfe0ff\" : \"#6b7280\";\n });\n };\n\n const setActive = (next: number, scroll = false) => {\n if (next === active || next < 0 || next >= rows.length) return;\n active = next;\n paintActive();\n // `scrollIntoView` is absent in jsdom, hence the optional call.\n if (scroll) rows[active]?.node.scrollIntoView?.({ block: \"nearest\" });\n };\n\n const renderList = () => {\n const filtered = getFiltered();\n active = Math.min(active, Math.max(0, filtered.length - 1));\n\n const sig = filtered.map(itemSig).join(\"\\n\");\n if (sig === rowsSig) {\n // Same items in the same order: keep the nodes, refresh the highlight.\n // The items themselves are rebuilt on every call, so re-point each row\n // at its current one (its `run`/`route` may have been swapped by\n // `update()`).\n filtered.forEach((it, idx) => {\n const row = rows[idx];\n if (row) row.item = it;\n });\n paintActive();\n return;\n }\n rowsSig = sig;\n rows = [];\n list.replaceChildren();\n\n if (filtered.length === 0) {\n list.appendChild(\n el(\n \"div\",\n { padding: \"12px\", fontSize: \"13px\", color: \"#6b7280\" },\n { textContent: \"Nothing here.\" },\n ),\n );\n return;\n }\n\n const groups = new Map<string, Item[]>();\n for (const it of filtered) {\n const arr = groups.get(it.group) ?? [];\n arr.push(it);\n groups.set(it.group, arr);\n }\n\n for (const [groupName, groupItems] of groups) {\n const section = el(\"div\", { marginTop: \"6px\" });\n section.appendChild(\n el(\n \"div\",\n {\n padding: \"6px 8px 2px\",\n fontSize: \"10px\",\n fontWeight: \"700\",\n letterSpacing: \"0.6px\",\n textTransform: \"uppercase\",\n color: \"#6b7280\",\n },\n { textContent: groupName },\n ),\n );\n\n for (const it of groupItems) {\n const idx = filtered.indexOf(it);\n const row = el(\"button\", {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: \"8px\",\n width: \"100%\",\n textAlign: \"left\",\n padding: \"8px 10px\",\n fontSize: \"13px\",\n color: \"#e7e9ee\",\n background: \"transparent\",\n border: \"none\",\n borderRadius: \"8px\",\n cursor: \"pointer\",\n });\n row.type = \"button\";\n\n const labelSpan = el(\n \"span\",\n {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n },\n { textContent: it.label },\n );\n row.appendChild(labelSpan);\n\n let pathSpan: HTMLSpanElement | null = null;\n if (it.kind === \"route\" && it.route.path !== it.label) {\n pathSpan = el(\n \"span\",\n {\n fontSize: \"11px\",\n color: \"#6b7280\",\n fontFamily: \"ui-monospace, SFMono-Regular, monospace\",\n flexShrink: \"0\",\n },\n { textContent: it.route.path },\n );\n row.appendChild(pathSpan);\n }\n\n const rec: Row = { item: it, node: row, pathSpan };\n rows[idx] = rec;\n\n row.addEventListener(\"mouseenter\", () => setActive(idx));\n row.addEventListener(\"click\", () => void runItem(rec.item));\n section.appendChild(row);\n }\n list.appendChild(section);\n }\n\n paintActive();\n };\n\n const renderShell = () => {\n const position = opts.position ?? \"bottom-right\";\n const zIndex = opts.zIndex ?? 2147483000;\n\n Object.assign(root.style, {\n position: \"fixed\",\n zIndex: String(zIndex),\n top: \"\",\n bottom: \"\",\n left: \"\",\n right: \"\",\n });\n Object.assign(root.style, cornerStyle(position));\n\n heading.textContent = opts.title ?? \"Dev Menu\";\n panel.setAttribute(\"aria-label\", opts.title ?? \"Dev Menu\");\n Object.assign(panel.style, panelAnchor(position));\n\n buttonLabel.textContent = opts.label ?? \"DEV\";\n button.style.background = open ? \"#2563eb\" : \"#111317\";\n button.setAttribute(\"aria-expanded\", String(open));\n };\n\n function setOpen(next: boolean) {\n if (open === next) return;\n open = next;\n if (open) {\n query = \"\";\n input.value = \"\";\n active = 0;\n panel.isConnected || root.insertBefore(panel, button);\n renderShell();\n renderList();\n requestAnimationFrame(() => input.focus());\n } else if (panel.isConnected) {\n panel.remove();\n }\n renderShell();\n }\n\n // ---- listeners --------------------------------------------------------\n\n input.addEventListener(\"input\", () => {\n query = input.value;\n active = 0;\n renderList();\n });\n\n panel.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n setOpen(false);\n } else if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive(Math.min(active + 1, rows.length - 1), true);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive(Math.max(active - 1, 0), true);\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n const it = rows[active]?.item;\n if (it) void runItem(it);\n }\n });\n\n button.addEventListener(\"click\", () => setOpen(!open));\n\n const onDocMouseDown = (e: MouseEvent) => {\n // composedPath() sees through the shadow boundary; a plain\n // `contains(e.target)` would miss clicks inside the shadow root.\n if (open && !e.composedPath().includes(root)) setOpen(false);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (opts.hotkey && matchHotkey(opts.hotkey, e)) {\n e.preventDefault();\n setOpen(!open);\n }\n };\n\n const addListeners = () => {\n document.addEventListener(\"mousedown\", onDocMouseDown);\n window.addEventListener(\"keydown\", onKeyDown);\n };\n const removeListeners = () => {\n document.removeEventListener(\"mousedown\", onDocMouseDown);\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n\n const mount = () => {\n if (mounted) return;\n (opts.container ?? document.body).appendChild(host);\n addListeners();\n mounted = true;\n };\n const unmount = () => {\n if (!mounted) return;\n removeListeners();\n host.remove();\n mounted = false;\n };\n\n // ---- init -------------------------------------------------------------\n\n renderShell();\n if (enabled()) mount();\n\n return {\n update(next: DevDockOptions) {\n opts = { ...opts, ...next };\n if (enabled()) {\n mount();\n renderShell();\n if (open) renderList();\n } else {\n setOpen(false);\n unmount();\n }\n },\n destroy() {\n setOpen(false);\n unmount();\n },\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { createDevDock } from './chunk-TROB6P6B.js';
1
+ import { createDevDock } from './chunk-DUHEBT6Q.js';
2
2
  import { useRef, useEffect } from 'react';
3
3
 
4
4
  function DevDock(props) {
@@ -20,5 +20,5 @@ function DevDock(props) {
20
20
  }
21
21
 
22
22
  export { DevDock };
23
- //# sourceMappingURL=chunk-KFWO54VP.js.map
24
- //# sourceMappingURL=chunk-KFWO54VP.js.map
23
+ //# sourceMappingURL=chunk-JZWITFNK.js.map
24
+ //# sourceMappingURL=chunk-JZWITFNK.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react/DevDock.tsx"],"names":[],"mappings":";;;AAWO,SAAS,QAAQ,KAAA,EAAqB;AAC3C,EAAA,MAAM,QAAA,GAAW,OAA+B,IAAI,CAAA;AACpD,EAAA,MAAM,MAAA,GAAS,OAAO,KAAK,CAAA;AAC3B,EAAA,MAAA,CAAO,OAAA,GAAU,KAAA;AAEjB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,MAAA,CAAO,OAAO,CAAA;AACzC,IAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,OAAA,EAAQ;AACb,MAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AAAA,IACrB,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,QAAA,CAAS,OAAA,EAAS,OAAO,KAAK,CAAA;AAAA,EAChC,CAAC,CAAA;AAED,EAAA,OAAO,IAAA;AACT","file":"chunk-KFWO54VP.js","sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { createDevDock } from \"../core/dock\";\nimport type { DevDockInstance, DevDockOptions } from \"../core/types\";\n\nexport type DevDockProps = DevDockOptions;\n\n/**\n * React wrapper around the framework-agnostic core. Renders nothing itself —\n * the dock mounts into `document.body` (or `container`) and is torn down on\n * unmount. Safe to leave mounted; it renders nothing in production.\n */\nexport function DevDock(props: DevDockProps) {\n const instance = useRef<DevDockInstance | null>(null);\n const latest = useRef(props);\n latest.current = props;\n\n useEffect(() => {\n const inst = createDevDock(latest.current);\n instance.current = inst;\n return () => {\n inst.destroy();\n instance.current = null;\n };\n }, []);\n\n useEffect(() => {\n instance.current?.update(props);\n });\n\n return null;\n}\n"]}
1
+ {"version":3,"sources":["../src/react/DevDock.tsx"],"names":[],"mappings":";;;AAWO,SAAS,QAAQ,KAAA,EAAqB;AAC3C,EAAA,MAAM,QAAA,GAAW,OAA+B,IAAI,CAAA;AACpD,EAAA,MAAM,MAAA,GAAS,OAAO,KAAK,CAAA;AAC3B,EAAA,MAAA,CAAO,OAAA,GAAU,KAAA;AAEjB,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,MAAA,CAAO,OAAO,CAAA;AACzC,IAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,IAAA,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,OAAA,EAAQ;AACb,MAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AAAA,IACrB,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,QAAA,CAAS,OAAA,EAAS,OAAO,KAAK,CAAA;AAAA,EAChC,CAAC,CAAA;AAED,EAAA,OAAO,IAAA;AACT","file":"chunk-JZWITFNK.js","sourcesContent":["import { useEffect, useRef } from \"react\";\nimport { createDevDock } from \"../core/dock\";\nimport type { DevDockInstance, DevDockOptions } from \"../core/types\";\n\nexport type DevDockProps = DevDockOptions;\n\n/**\n * React wrapper around the framework-agnostic core. Renders nothing itself —\n * the dock mounts into `document.body` (or `container`) and is torn down on\n * unmount. Safe to leave mounted; it renders nothing in production.\n */\nexport function DevDock(props: DevDockProps) {\n const instance = useRef<DevDockInstance | null>(null);\n const latest = useRef(props);\n latest.current = props;\n\n useEffect(() => {\n const inst = createDevDock(latest.current);\n instance.current = inst;\n return () => {\n inst.destroy();\n instance.current = null;\n };\n }, []);\n\n useEffect(() => {\n instance.current?.update(props);\n });\n\n return null;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { b as DevDockOptions, a as DevDockInstance } from './types-DYQBDvfK.js';
1
+ import { b as DevDockOptions, a as DevDockInstance } from './types-DWX2w51R.js';
2
2
 
3
3
  /**
4
4
  * Create a framework-agnostic dev dock: a floating button that opens a popup
@@ -1,4 +1,4 @@
1
- import { b as DevDockOptions, a as DevDockInstance } from './types-DYQBDvfK.cjs';
1
+ import { b as DevDockOptions, a as DevDockInstance } from './types-DWX2w51R.cjs';
2
2
 
3
3
  /**
4
4
  * Create a framework-agnostic dev dock: a floating button that opens a popup
package/dist/index.cjs CHANGED
@@ -35,14 +35,14 @@ function el(tag, styles, props) {
35
35
  function cornerStyle(position) {
36
36
  const gap = "16px";
37
37
  switch (position) {
38
- case "bottom-right":
39
- return { bottom: gap, right: gap };
38
+ case "bottom-left":
39
+ return { bottom: gap, left: gap };
40
40
  case "top-left":
41
41
  return { top: gap, left: gap };
42
42
  case "top-right":
43
43
  return { top: gap, right: gap };
44
44
  default:
45
- return { bottom: gap, left: gap };
45
+ return { bottom: gap, right: gap };
46
46
  }
47
47
  }
48
48
  function panelAnchor(position) {
@@ -308,7 +308,7 @@ function createDevDock(initial = {}) {
308
308
  paintActive();
309
309
  };
310
310
  const renderShell = () => {
311
- const position = opts.position ?? "bottom-left";
311
+ const position = opts.position ?? "bottom-right";
312
312
  const zIndex = opts.zIndex ?? 2147483e3;
313
313
  Object.assign(root.style, {
314
314
  position: "fixed",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/hotkey.ts","../src/core/dock.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/** Parse a hotkey string like \"mod+.\" into a matcher predicate. */\nexport function matchHotkey(spec: string, e: KeyboardEvent): boolean {\n const parts = spec\n .toLowerCase()\n .split(\"+\")\n .map((p) => p.trim())\n .filter(Boolean);\n if (parts.length === 0) return false;\n\n const key = parts[parts.length - 1];\n const mods = new Set(parts.slice(0, -1));\n\n const isMac =\n typeof navigator !== \"undefined\" && /mac/i.test(navigator.platform);\n\n const wantMeta = mods.has(\"meta\") || mods.has(\"cmd\") || (mods.has(\"mod\") && isMac);\n const wantCtrl = mods.has(\"ctrl\") || mods.has(\"control\") || (mods.has(\"mod\") && !isMac);\n const wantShift = mods.has(\"shift\");\n const wantAlt = mods.has(\"alt\") || mods.has(\"option\");\n\n if (e.metaKey !== wantMeta) return false;\n if (e.ctrlKey !== wantCtrl) return false;\n if (e.shiftKey !== wantShift) return false;\n if (e.altKey !== wantAlt) return false;\n\n return e.key.toLowerCase() === key;\n}\n","import { matchHotkey } from \"./hotkey\";\nimport type {\n DevCommand,\n DevDockInstance,\n DevDockOptions,\n DevRoute,\n DockPosition,\n} from \"./types\";\n\nconst isDev = (): boolean => {\n // Bundlers (Vite, webpack, Next, esbuild…) statically replace the full\n // `process.env.NODE_ENV` token, even in browser builds where `process`\n // itself is undefined. Reading it directly lets that replacement work;\n // the try/catch covers runtimes where it's left as a real (missing) global.\n try {\n return process.env.NODE_ENV !== \"production\";\n } catch {\n return false;\n }\n};\n\ntype Item =\n | { kind: \"route\"; key: string; label: string; group: string; route: DevRoute }\n | {\n kind: \"command\";\n key: string;\n label: string;\n group: string;\n command: DevCommand;\n };\n\ntype Styles = Partial<CSSStyleDeclaration>;\n\nfunction el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n styles?: Styles,\n props?: Partial<HTMLElementTagNameMap[K]>,\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (styles) Object.assign(node.style, styles);\n if (props) Object.assign(node, props);\n return node;\n}\n\nfunction cornerStyle(position: DockPosition): Styles {\n const gap = \"16px\";\n switch (position) {\n case \"bottom-right\":\n return { bottom: gap, right: gap };\n case \"top-left\":\n return { top: gap, left: gap };\n case \"top-right\":\n return { top: gap, right: gap };\n default:\n return { bottom: gap, left: gap };\n }\n}\n\nfunction panelAnchor(position: DockPosition): Styles {\n const isTop = position.startsWith(\"top\");\n const isRight = position.endsWith(\"right\");\n return {\n position: \"absolute\",\n [isTop ? \"top\" : \"bottom\"]: \"calc(100% + 8px)\",\n [isRight ? \"right\" : \"left\"]: \"0\",\n } as Styles;\n}\n\nconst FONT =\n \"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif\";\n\n/**\n * Create a framework-agnostic dev dock: a floating button that opens a popup\n * to jump between routes and run commands. Returns a handle to update its\n * options or tear it down. No-ops on the server (when there is no `document`).\n */\nexport function createDevDock(initial: DevDockOptions = {}): DevDockInstance {\n if (typeof document === \"undefined\") {\n return { update() {}, destroy() {} };\n }\n\n let opts: DevDockOptions = { ...initial };\n let open = false;\n let query = \"\";\n let active = 0;\n let mounted = false;\n\n // Light-DOM host that gets appended to the page. When shadow DOM is used,\n // the actual UI lives inside its shadow root — fully isolated from the host\n // page's CSS. `data-devdock` stays on the host so it's discoverable.\n const host = el(\"div\");\n host.setAttribute(\"data-devdock\", \"\");\n const useShadow =\n (initial.shadow ?? true) && typeof host.attachShadow === \"function\";\n const shadowRoot = useShadow ? host.attachShadow({ mode: \"open\" }) : null;\n const mountPoint: Node = shadowRoot ?? host;\n\n const root = el(\"div\", { fontFamily: FONT });\n mountPoint.appendChild(root);\n\n const panel = el(\"div\", {\n width: \"280px\",\n maxHeight: \"min(70vh, 480px)\",\n display: \"flex\",\n flexDirection: \"column\",\n background: \"#16181d\",\n color: \"#e7e9ee\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"12px\",\n boxShadow: \"0 12px 40px rgba(0,0,0,0.45)\",\n overflow: \"hidden\",\n });\n panel.setAttribute(\"role\", \"dialog\");\n\n const heading = el(\"div\", {\n padding: \"10px 12px\",\n borderBottom: \"1px solid #2a2e37\",\n fontSize: \"12px\",\n fontWeight: \"600\",\n letterSpacing: \"0.4px\",\n textTransform: \"uppercase\",\n color: \"#8b909c\",\n });\n\n const inputWrap = el(\"div\", { padding: \"8px\" });\n const input = el(\"input\", {\n width: \"100%\",\n boxSizing: \"border-box\",\n padding: \"8px 10px\",\n fontSize: \"13px\",\n color: \"#e7e9ee\",\n background: \"#0f1115\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"8px\",\n outline: \"none\",\n });\n input.placeholder = \"Filter…\";\n inputWrap.appendChild(input);\n\n const list = el(\"div\", { overflowY: \"auto\", padding: \"0 6px 8px\" });\n\n panel.append(heading, inputWrap, list);\n\n const button = el(\"button\", {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n padding: \"8px 12px\",\n fontSize: \"12px\",\n fontWeight: \"700\",\n letterSpacing: \"0.6px\",\n color: \"#fff\",\n background: \"#111317\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"999px\",\n boxShadow: \"0 4px 14px rgba(0,0,0,0.35)\",\n cursor: \"pointer\",\n });\n button.type = \"button\";\n button.setAttribute(\"aria-label\", \"Toggle dev menu\");\n const dot = el(\"span\", {\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"999px\",\n background: \"#22c55e\",\n display: \"inline-block\",\n });\n const buttonLabel = el(\"span\");\n button.append(dot, buttonLabel);\n\n root.appendChild(button);\n\n // ---- behavior ---------------------------------------------------------\n\n const enabled = (): boolean => {\n const e = opts.enabled;\n if (typeof e === \"function\") return e();\n return e ?? isDev();\n };\n\n const navigate = (path: string) => {\n if (opts.onNavigate) opts.onNavigate(path);\n else if (typeof window !== \"undefined\") window.location.assign(path);\n };\n\n const buildItems = (): Item[] => {\n const out: Item[] = [];\n (opts.routes ?? []).forEach((r, i) => {\n out.push({\n kind: \"route\",\n key: `route:${r.path}:${i}`,\n label: r.label ?? r.path,\n group: r.group ?? \"Routes\",\n route: r,\n });\n });\n (opts.commands ?? []).forEach((c, i) => {\n out.push({\n kind: \"command\",\n key: `cmd:${c.id ?? c.label}:${i}`,\n label: c.label,\n group: c.group ?? \"Commands\",\n command: c,\n });\n });\n return out;\n };\n\n const getFiltered = (): Item[] => {\n const q = query.trim().toLowerCase();\n const items = buildItems();\n if (!q) return items;\n return items.filter(\n (it) =>\n it.label.toLowerCase().includes(q) ||\n (it.kind === \"route\" && it.route.path.toLowerCase().includes(q)),\n );\n };\n\n const runItem = async (it: Item) => {\n if (it.kind === \"route\") {\n navigate(it.route.path);\n setOpen(false);\n return;\n }\n try {\n await it.command.run();\n } finally {\n if (!it.command.keepOpen) setOpen(false);\n }\n };\n\n type Row = {\n item: Item;\n node: HTMLButtonElement;\n pathSpan: HTMLSpanElement | null;\n };\n\n // The rendered rows, parallel to the current filtered list. They are kept\n // around so hovering or arrowing only repaints the highlight: rebuilding the\n // rows would destroy the node under the pointer, and the browser then never\n // dispatches a `click` on it (mousedown/mouseup retarget to the parent).\n let rows: Row[] = [];\n // Signature of the item list the rows were built from; identical signature\n // means the existing nodes can be reused as-is.\n let rowsSig: string | null = null;\n\n const itemSig = (it: Item): string =>\n [it.key, it.group, it.label, it.kind === \"route\" ? it.route.path : \"\"].join(\n \"\\u0000\",\n );\n\n const paintActive = () => {\n rows.forEach((row, idx) => {\n const isActive = idx === active;\n row.node.style.background = isActive ? \"#2563eb\" : \"transparent\";\n if (row.pathSpan)\n row.pathSpan.style.color = isActive ? \"#cfe0ff\" : \"#6b7280\";\n });\n };\n\n const setActive = (next: number, scroll = false) => {\n if (next === active || next < 0 || next >= rows.length) return;\n active = next;\n paintActive();\n // `scrollIntoView` is absent in jsdom, hence the optional call.\n if (scroll) rows[active]?.node.scrollIntoView?.({ block: \"nearest\" });\n };\n\n const renderList = () => {\n const filtered = getFiltered();\n active = Math.min(active, Math.max(0, filtered.length - 1));\n\n const sig = filtered.map(itemSig).join(\"\\n\");\n if (sig === rowsSig) {\n // Same items in the same order: keep the nodes, refresh the highlight.\n // The items themselves are rebuilt on every call, so re-point each row\n // at its current one (its `run`/`route` may have been swapped by\n // `update()`).\n filtered.forEach((it, idx) => {\n const row = rows[idx];\n if (row) row.item = it;\n });\n paintActive();\n return;\n }\n rowsSig = sig;\n rows = [];\n list.replaceChildren();\n\n if (filtered.length === 0) {\n list.appendChild(\n el(\n \"div\",\n { padding: \"12px\", fontSize: \"13px\", color: \"#6b7280\" },\n { textContent: \"Nothing here.\" },\n ),\n );\n return;\n }\n\n const groups = new Map<string, Item[]>();\n for (const it of filtered) {\n const arr = groups.get(it.group) ?? [];\n arr.push(it);\n groups.set(it.group, arr);\n }\n\n for (const [groupName, groupItems] of groups) {\n const section = el(\"div\", { marginTop: \"6px\" });\n section.appendChild(\n el(\n \"div\",\n {\n padding: \"6px 8px 2px\",\n fontSize: \"10px\",\n fontWeight: \"700\",\n letterSpacing: \"0.6px\",\n textTransform: \"uppercase\",\n color: \"#6b7280\",\n },\n { textContent: groupName },\n ),\n );\n\n for (const it of groupItems) {\n const idx = filtered.indexOf(it);\n const row = el(\"button\", {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: \"8px\",\n width: \"100%\",\n textAlign: \"left\",\n padding: \"8px 10px\",\n fontSize: \"13px\",\n color: \"#e7e9ee\",\n background: \"transparent\",\n border: \"none\",\n borderRadius: \"8px\",\n cursor: \"pointer\",\n });\n row.type = \"button\";\n\n const labelSpan = el(\n \"span\",\n {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n },\n { textContent: it.label },\n );\n row.appendChild(labelSpan);\n\n let pathSpan: HTMLSpanElement | null = null;\n if (it.kind === \"route\" && it.route.path !== it.label) {\n pathSpan = el(\n \"span\",\n {\n fontSize: \"11px\",\n color: \"#6b7280\",\n fontFamily: \"ui-monospace, SFMono-Regular, monospace\",\n flexShrink: \"0\",\n },\n { textContent: it.route.path },\n );\n row.appendChild(pathSpan);\n }\n\n const rec: Row = { item: it, node: row, pathSpan };\n rows[idx] = rec;\n\n row.addEventListener(\"mouseenter\", () => setActive(idx));\n row.addEventListener(\"click\", () => void runItem(rec.item));\n section.appendChild(row);\n }\n list.appendChild(section);\n }\n\n paintActive();\n };\n\n const renderShell = () => {\n const position = opts.position ?? \"bottom-left\";\n const zIndex = opts.zIndex ?? 2147483000;\n\n Object.assign(root.style, {\n position: \"fixed\",\n zIndex: String(zIndex),\n top: \"\",\n bottom: \"\",\n left: \"\",\n right: \"\",\n });\n Object.assign(root.style, cornerStyle(position));\n\n heading.textContent = opts.title ?? \"Dev Menu\";\n panel.setAttribute(\"aria-label\", opts.title ?? \"Dev Menu\");\n Object.assign(panel.style, panelAnchor(position));\n\n buttonLabel.textContent = opts.label ?? \"DEV\";\n button.style.background = open ? \"#2563eb\" : \"#111317\";\n button.setAttribute(\"aria-expanded\", String(open));\n };\n\n function setOpen(next: boolean) {\n if (open === next) return;\n open = next;\n if (open) {\n query = \"\";\n input.value = \"\";\n active = 0;\n panel.isConnected || root.insertBefore(panel, button);\n renderShell();\n renderList();\n requestAnimationFrame(() => input.focus());\n } else if (panel.isConnected) {\n panel.remove();\n }\n renderShell();\n }\n\n // ---- listeners --------------------------------------------------------\n\n input.addEventListener(\"input\", () => {\n query = input.value;\n active = 0;\n renderList();\n });\n\n panel.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n setOpen(false);\n } else if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive(Math.min(active + 1, rows.length - 1), true);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive(Math.max(active - 1, 0), true);\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n const it = rows[active]?.item;\n if (it) void runItem(it);\n }\n });\n\n button.addEventListener(\"click\", () => setOpen(!open));\n\n const onDocMouseDown = (e: MouseEvent) => {\n // composedPath() sees through the shadow boundary; a plain\n // `contains(e.target)` would miss clicks inside the shadow root.\n if (open && !e.composedPath().includes(root)) setOpen(false);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (opts.hotkey && matchHotkey(opts.hotkey, e)) {\n e.preventDefault();\n setOpen(!open);\n }\n };\n\n const addListeners = () => {\n document.addEventListener(\"mousedown\", onDocMouseDown);\n window.addEventListener(\"keydown\", onKeyDown);\n };\n const removeListeners = () => {\n document.removeEventListener(\"mousedown\", onDocMouseDown);\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n\n const mount = () => {\n if (mounted) return;\n (opts.container ?? document.body).appendChild(host);\n addListeners();\n mounted = true;\n };\n const unmount = () => {\n if (!mounted) return;\n removeListeners();\n host.remove();\n mounted = false;\n };\n\n // ---- init -------------------------------------------------------------\n\n renderShell();\n if (enabled()) mount();\n\n return {\n update(next: DevDockOptions) {\n opts = { ...opts, ...next };\n if (enabled()) {\n mount();\n renderShell();\n if (open) renderList();\n } else {\n setOpen(false);\n unmount();\n }\n },\n destroy() {\n setOpen(false);\n unmount();\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/core/hotkey.ts","../src/core/dock.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/** Parse a hotkey string like \"mod+.\" into a matcher predicate. */\nexport function matchHotkey(spec: string, e: KeyboardEvent): boolean {\n const parts = spec\n .toLowerCase()\n .split(\"+\")\n .map((p) => p.trim())\n .filter(Boolean);\n if (parts.length === 0) return false;\n\n const key = parts[parts.length - 1];\n const mods = new Set(parts.slice(0, -1));\n\n const isMac =\n typeof navigator !== \"undefined\" && /mac/i.test(navigator.platform);\n\n const wantMeta = mods.has(\"meta\") || mods.has(\"cmd\") || (mods.has(\"mod\") && isMac);\n const wantCtrl = mods.has(\"ctrl\") || mods.has(\"control\") || (mods.has(\"mod\") && !isMac);\n const wantShift = mods.has(\"shift\");\n const wantAlt = mods.has(\"alt\") || mods.has(\"option\");\n\n if (e.metaKey !== wantMeta) return false;\n if (e.ctrlKey !== wantCtrl) return false;\n if (e.shiftKey !== wantShift) return false;\n if (e.altKey !== wantAlt) return false;\n\n return e.key.toLowerCase() === key;\n}\n","import { matchHotkey } from \"./hotkey\";\nimport type {\n DevCommand,\n DevDockInstance,\n DevDockOptions,\n DevRoute,\n DockPosition,\n} from \"./types\";\n\nconst isDev = (): boolean => {\n // Bundlers (Vite, webpack, Next, esbuild…) statically replace the full\n // `process.env.NODE_ENV` token, even in browser builds where `process`\n // itself is undefined. Reading it directly lets that replacement work;\n // the try/catch covers runtimes where it's left as a real (missing) global.\n try {\n return process.env.NODE_ENV !== \"production\";\n } catch {\n return false;\n }\n};\n\ntype Item =\n | { kind: \"route\"; key: string; label: string; group: string; route: DevRoute }\n | {\n kind: \"command\";\n key: string;\n label: string;\n group: string;\n command: DevCommand;\n };\n\ntype Styles = Partial<CSSStyleDeclaration>;\n\nfunction el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n styles?: Styles,\n props?: Partial<HTMLElementTagNameMap[K]>,\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (styles) Object.assign(node.style, styles);\n if (props) Object.assign(node, props);\n return node;\n}\n\nfunction cornerStyle(position: DockPosition): Styles {\n const gap = \"16px\";\n switch (position) {\n case \"bottom-left\":\n return { bottom: gap, left: gap };\n case \"top-left\":\n return { top: gap, left: gap };\n case \"top-right\":\n return { top: gap, right: gap };\n default:\n return { bottom: gap, right: gap };\n }\n}\n\nfunction panelAnchor(position: DockPosition): Styles {\n const isTop = position.startsWith(\"top\");\n const isRight = position.endsWith(\"right\");\n return {\n position: \"absolute\",\n [isTop ? \"top\" : \"bottom\"]: \"calc(100% + 8px)\",\n [isRight ? \"right\" : \"left\"]: \"0\",\n } as Styles;\n}\n\nconst FONT =\n \"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif\";\n\n/**\n * Create a framework-agnostic dev dock: a floating button that opens a popup\n * to jump between routes and run commands. Returns a handle to update its\n * options or tear it down. No-ops on the server (when there is no `document`).\n */\nexport function createDevDock(initial: DevDockOptions = {}): DevDockInstance {\n if (typeof document === \"undefined\") {\n return { update() {}, destroy() {} };\n }\n\n let opts: DevDockOptions = { ...initial };\n let open = false;\n let query = \"\";\n let active = 0;\n let mounted = false;\n\n // Light-DOM host that gets appended to the page. When shadow DOM is used,\n // the actual UI lives inside its shadow root — fully isolated from the host\n // page's CSS. `data-devdock` stays on the host so it's discoverable.\n const host = el(\"div\");\n host.setAttribute(\"data-devdock\", \"\");\n const useShadow =\n (initial.shadow ?? true) && typeof host.attachShadow === \"function\";\n const shadowRoot = useShadow ? host.attachShadow({ mode: \"open\" }) : null;\n const mountPoint: Node = shadowRoot ?? host;\n\n const root = el(\"div\", { fontFamily: FONT });\n mountPoint.appendChild(root);\n\n const panel = el(\"div\", {\n width: \"280px\",\n maxHeight: \"min(70vh, 480px)\",\n display: \"flex\",\n flexDirection: \"column\",\n background: \"#16181d\",\n color: \"#e7e9ee\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"12px\",\n boxShadow: \"0 12px 40px rgba(0,0,0,0.45)\",\n overflow: \"hidden\",\n });\n panel.setAttribute(\"role\", \"dialog\");\n\n const heading = el(\"div\", {\n padding: \"10px 12px\",\n borderBottom: \"1px solid #2a2e37\",\n fontSize: \"12px\",\n fontWeight: \"600\",\n letterSpacing: \"0.4px\",\n textTransform: \"uppercase\",\n color: \"#8b909c\",\n });\n\n const inputWrap = el(\"div\", { padding: \"8px\" });\n const input = el(\"input\", {\n width: \"100%\",\n boxSizing: \"border-box\",\n padding: \"8px 10px\",\n fontSize: \"13px\",\n color: \"#e7e9ee\",\n background: \"#0f1115\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"8px\",\n outline: \"none\",\n });\n input.placeholder = \"Filter…\";\n inputWrap.appendChild(input);\n\n const list = el(\"div\", { overflowY: \"auto\", padding: \"0 6px 8px\" });\n\n panel.append(heading, inputWrap, list);\n\n const button = el(\"button\", {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: \"6px\",\n padding: \"8px 12px\",\n fontSize: \"12px\",\n fontWeight: \"700\",\n letterSpacing: \"0.6px\",\n color: \"#fff\",\n background: \"#111317\",\n border: \"1px solid #2a2e37\",\n borderRadius: \"999px\",\n boxShadow: \"0 4px 14px rgba(0,0,0,0.35)\",\n cursor: \"pointer\",\n });\n button.type = \"button\";\n button.setAttribute(\"aria-label\", \"Toggle dev menu\");\n const dot = el(\"span\", {\n width: \"8px\",\n height: \"8px\",\n borderRadius: \"999px\",\n background: \"#22c55e\",\n display: \"inline-block\",\n });\n const buttonLabel = el(\"span\");\n button.append(dot, buttonLabel);\n\n root.appendChild(button);\n\n // ---- behavior ---------------------------------------------------------\n\n const enabled = (): boolean => {\n const e = opts.enabled;\n if (typeof e === \"function\") return e();\n return e ?? isDev();\n };\n\n const navigate = (path: string) => {\n if (opts.onNavigate) opts.onNavigate(path);\n else if (typeof window !== \"undefined\") window.location.assign(path);\n };\n\n const buildItems = (): Item[] => {\n const out: Item[] = [];\n (opts.routes ?? []).forEach((r, i) => {\n out.push({\n kind: \"route\",\n key: `route:${r.path}:${i}`,\n label: r.label ?? r.path,\n group: r.group ?? \"Routes\",\n route: r,\n });\n });\n (opts.commands ?? []).forEach((c, i) => {\n out.push({\n kind: \"command\",\n key: `cmd:${c.id ?? c.label}:${i}`,\n label: c.label,\n group: c.group ?? \"Commands\",\n command: c,\n });\n });\n return out;\n };\n\n const getFiltered = (): Item[] => {\n const q = query.trim().toLowerCase();\n const items = buildItems();\n if (!q) return items;\n return items.filter(\n (it) =>\n it.label.toLowerCase().includes(q) ||\n (it.kind === \"route\" && it.route.path.toLowerCase().includes(q)),\n );\n };\n\n const runItem = async (it: Item) => {\n if (it.kind === \"route\") {\n navigate(it.route.path);\n setOpen(false);\n return;\n }\n try {\n await it.command.run();\n } finally {\n if (!it.command.keepOpen) setOpen(false);\n }\n };\n\n type Row = {\n item: Item;\n node: HTMLButtonElement;\n pathSpan: HTMLSpanElement | null;\n };\n\n // The rendered rows, parallel to the current filtered list. They are kept\n // around so hovering or arrowing only repaints the highlight: rebuilding the\n // rows would destroy the node under the pointer, and the browser then never\n // dispatches a `click` on it (mousedown/mouseup retarget to the parent).\n let rows: Row[] = [];\n // Signature of the item list the rows were built from; identical signature\n // means the existing nodes can be reused as-is.\n let rowsSig: string | null = null;\n\n const itemSig = (it: Item): string =>\n [it.key, it.group, it.label, it.kind === \"route\" ? it.route.path : \"\"].join(\n \"\\u0000\",\n );\n\n const paintActive = () => {\n rows.forEach((row, idx) => {\n const isActive = idx === active;\n row.node.style.background = isActive ? \"#2563eb\" : \"transparent\";\n if (row.pathSpan)\n row.pathSpan.style.color = isActive ? \"#cfe0ff\" : \"#6b7280\";\n });\n };\n\n const setActive = (next: number, scroll = false) => {\n if (next === active || next < 0 || next >= rows.length) return;\n active = next;\n paintActive();\n // `scrollIntoView` is absent in jsdom, hence the optional call.\n if (scroll) rows[active]?.node.scrollIntoView?.({ block: \"nearest\" });\n };\n\n const renderList = () => {\n const filtered = getFiltered();\n active = Math.min(active, Math.max(0, filtered.length - 1));\n\n const sig = filtered.map(itemSig).join(\"\\n\");\n if (sig === rowsSig) {\n // Same items in the same order: keep the nodes, refresh the highlight.\n // The items themselves are rebuilt on every call, so re-point each row\n // at its current one (its `run`/`route` may have been swapped by\n // `update()`).\n filtered.forEach((it, idx) => {\n const row = rows[idx];\n if (row) row.item = it;\n });\n paintActive();\n return;\n }\n rowsSig = sig;\n rows = [];\n list.replaceChildren();\n\n if (filtered.length === 0) {\n list.appendChild(\n el(\n \"div\",\n { padding: \"12px\", fontSize: \"13px\", color: \"#6b7280\" },\n { textContent: \"Nothing here.\" },\n ),\n );\n return;\n }\n\n const groups = new Map<string, Item[]>();\n for (const it of filtered) {\n const arr = groups.get(it.group) ?? [];\n arr.push(it);\n groups.set(it.group, arr);\n }\n\n for (const [groupName, groupItems] of groups) {\n const section = el(\"div\", { marginTop: \"6px\" });\n section.appendChild(\n el(\n \"div\",\n {\n padding: \"6px 8px 2px\",\n fontSize: \"10px\",\n fontWeight: \"700\",\n letterSpacing: \"0.6px\",\n textTransform: \"uppercase\",\n color: \"#6b7280\",\n },\n { textContent: groupName },\n ),\n );\n\n for (const it of groupItems) {\n const idx = filtered.indexOf(it);\n const row = el(\"button\", {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: \"8px\",\n width: \"100%\",\n textAlign: \"left\",\n padding: \"8px 10px\",\n fontSize: \"13px\",\n color: \"#e7e9ee\",\n background: \"transparent\",\n border: \"none\",\n borderRadius: \"8px\",\n cursor: \"pointer\",\n });\n row.type = \"button\";\n\n const labelSpan = el(\n \"span\",\n {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n },\n { textContent: it.label },\n );\n row.appendChild(labelSpan);\n\n let pathSpan: HTMLSpanElement | null = null;\n if (it.kind === \"route\" && it.route.path !== it.label) {\n pathSpan = el(\n \"span\",\n {\n fontSize: \"11px\",\n color: \"#6b7280\",\n fontFamily: \"ui-monospace, SFMono-Regular, monospace\",\n flexShrink: \"0\",\n },\n { textContent: it.route.path },\n );\n row.appendChild(pathSpan);\n }\n\n const rec: Row = { item: it, node: row, pathSpan };\n rows[idx] = rec;\n\n row.addEventListener(\"mouseenter\", () => setActive(idx));\n row.addEventListener(\"click\", () => void runItem(rec.item));\n section.appendChild(row);\n }\n list.appendChild(section);\n }\n\n paintActive();\n };\n\n const renderShell = () => {\n const position = opts.position ?? \"bottom-right\";\n const zIndex = opts.zIndex ?? 2147483000;\n\n Object.assign(root.style, {\n position: \"fixed\",\n zIndex: String(zIndex),\n top: \"\",\n bottom: \"\",\n left: \"\",\n right: \"\",\n });\n Object.assign(root.style, cornerStyle(position));\n\n heading.textContent = opts.title ?? \"Dev Menu\";\n panel.setAttribute(\"aria-label\", opts.title ?? \"Dev Menu\");\n Object.assign(panel.style, panelAnchor(position));\n\n buttonLabel.textContent = opts.label ?? \"DEV\";\n button.style.background = open ? \"#2563eb\" : \"#111317\";\n button.setAttribute(\"aria-expanded\", String(open));\n };\n\n function setOpen(next: boolean) {\n if (open === next) return;\n open = next;\n if (open) {\n query = \"\";\n input.value = \"\";\n active = 0;\n panel.isConnected || root.insertBefore(panel, button);\n renderShell();\n renderList();\n requestAnimationFrame(() => input.focus());\n } else if (panel.isConnected) {\n panel.remove();\n }\n renderShell();\n }\n\n // ---- listeners --------------------------------------------------------\n\n input.addEventListener(\"input\", () => {\n query = input.value;\n active = 0;\n renderList();\n });\n\n panel.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n setOpen(false);\n } else if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActive(Math.min(active + 1, rows.length - 1), true);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActive(Math.max(active - 1, 0), true);\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n const it = rows[active]?.item;\n if (it) void runItem(it);\n }\n });\n\n button.addEventListener(\"click\", () => setOpen(!open));\n\n const onDocMouseDown = (e: MouseEvent) => {\n // composedPath() sees through the shadow boundary; a plain\n // `contains(e.target)` would miss clicks inside the shadow root.\n if (open && !e.composedPath().includes(root)) setOpen(false);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (opts.hotkey && matchHotkey(opts.hotkey, e)) {\n e.preventDefault();\n setOpen(!open);\n }\n };\n\n const addListeners = () => {\n document.addEventListener(\"mousedown\", onDocMouseDown);\n window.addEventListener(\"keydown\", onKeyDown);\n };\n const removeListeners = () => {\n document.removeEventListener(\"mousedown\", onDocMouseDown);\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n\n const mount = () => {\n if (mounted) return;\n (opts.container ?? document.body).appendChild(host);\n addListeners();\n mounted = true;\n };\n const unmount = () => {\n if (!mounted) return;\n removeListeners();\n host.remove();\n mounted = false;\n };\n\n // ---- init -------------------------------------------------------------\n\n renderShell();\n if (enabled()) mount();\n\n return {\n update(next: DevDockOptions) {\n opts = { ...opts, ...next };\n if (enabled()) {\n mount();\n renderShell();\n if (open) renderList();\n } else {\n setOpen(false);\n unmount();\n }\n },\n destroy() {\n setOpen(false);\n unmount();\n },\n };\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- export { c as createDevDock } from './dock-mQl2WU8n.cjs';
2
- export { D as DevCommand, a as DevDockInstance, b as DevDockOptions, c as DevRoute, d as DockPosition } from './types-DYQBDvfK.cjs';
1
+ export { c as createDevDock } from './dock-BTK1OArl.cjs';
2
+ export { D as DevCommand, a as DevDockInstance, b as DevDockOptions, c as DevRoute, d as DockPosition } from './types-DWX2w51R.cjs';
3
3
 
4
4
  /** Parse a hotkey string like "mod+." into a matcher predicate. */
5
5
  declare function matchHotkey(spec: string, e: KeyboardEvent): boolean;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { c as createDevDock } from './dock-elbtMGsE.js';
2
- export { D as DevCommand, a as DevDockInstance, b as DevDockOptions, c as DevRoute, d as DockPosition } from './types-DYQBDvfK.js';
1
+ export { c as createDevDock } from './dock-BQEAjL0s.js';
2
+ export { D as DevCommand, a as DevDockInstance, b as DevDockOptions, c as DevRoute, d as DockPosition } from './types-DWX2w51R.js';
3
3
 
4
4
  /** Parse a hotkey string like "mod+." into a matcher predicate. */
5
5
  declare function matchHotkey(spec: string, e: KeyboardEvent): boolean;
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { createDevDock, matchHotkey } from './chunk-TROB6P6B.js';
1
+ export { createDevDock, matchHotkey } from './chunk-DUHEBT6Q.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
@@ -41,14 +41,14 @@ function el(tag, styles, props) {
41
41
  function cornerStyle(position) {
42
42
  const gap = "16px";
43
43
  switch (position) {
44
- case "bottom-right":
45
- return { bottom: gap, right: gap };
44
+ case "bottom-left":
45
+ return { bottom: gap, left: gap };
46
46
  case "top-left":
47
47
  return { top: gap, left: gap };
48
48
  case "top-right":
49
49
  return { top: gap, right: gap };
50
50
  default:
51
- return { bottom: gap, left: gap };
51
+ return { bottom: gap, right: gap };
52
52
  }
53
53
  }
54
54
  function panelAnchor(position) {
@@ -314,7 +314,7 @@ function createDevDock(initial = {}) {
314
314
  paintActive();
315
315
  };
316
316
  const renderShell = () => {
317
- const position = opts.position ?? "bottom-left";
317
+ const position = opts.position ?? "bottom-right";
318
318
  const zIndex = opts.zIndex ?? 2147483e3;
319
319
  Object.assign(root.style, {
320
320
  position: "fixed",
@@ -453,39 +453,57 @@ function joinPath(parent, child) {
453
453
  const base = parent.endsWith("/") ? parent.slice(0, -1) : parent;
454
454
  return `${base}/${child}`;
455
455
  }
456
- function flattenRoutes(routes, parent = "") {
456
+ function isDevMarked(handle) {
457
+ return handle?.dev === true || handle?.devLabel != null || handle?.devGroup != null;
458
+ }
459
+ function isDevPath(path) {
460
+ return path === "/dev" || path.startsWith("/dev/");
461
+ }
462
+ function flattenRoutes(routes, parent = "", options = {}) {
463
+ return walk(routes, parent, options.staticRoutes === true, { dev: false });
464
+ }
465
+ function walk(routes, parent, staticRoutes, inherited) {
457
466
  const out = [];
458
467
  for (const r of routes) {
459
468
  const full = r.index ? parent : joinPath(parent, r.path ?? "");
460
- const navigable = !r.index && r.path != null && !full.includes(":") && !full.includes("*") && r.handle?.hidden !== true;
469
+ const dev = inherited.dev || isDevMarked(r.handle) || isDevPath(full);
470
+ const group = r.handle?.devGroup ?? inherited.group;
471
+ const navigable = !r.index && r.path != null && !full.includes(":") && !full.includes("*") && r.handle?.hidden !== true && (dev || staticRoutes);
461
472
  if (navigable) {
462
473
  out.push({
463
474
  path: full || "/",
464
475
  label: r.handle?.devLabel ?? (full || "/"),
465
- group: r.handle?.devGroup
476
+ group
466
477
  });
467
478
  }
468
- if (r.children?.length) out.push(...flattenRoutes(r.children, full));
479
+ if (r.children?.length)
480
+ out.push(...walk(r.children, full, staticRoutes, { dev, group }));
469
481
  }
470
482
  return out;
471
483
  }
472
- function useDetectedRoutes(match) {
484
+ function isMatcher(value) {
485
+ return typeof value === "string" || typeof value === "function" || value instanceof RegExp;
486
+ }
487
+ function useDetectedRoutes(options = {}) {
488
+ const opts = isMatcher(options) ? { match: options } : options;
489
+ const { match, staticRoutes } = opts;
473
490
  const ctx = react.useContext(reactRouter.UNSAFE_DataRouterContext);
474
491
  const routes = ctx?.router?.routes ?? [];
475
492
  return react.useMemo(() => {
476
493
  const seen = /* @__PURE__ */ new Set();
477
- const deduped = flattenRoutes(routes).filter(
494
+ const deduped = flattenRoutes(routes, "", { staticRoutes }).filter(
478
495
  (r) => seen.has(r.path) ? false : (seen.add(r.path), true)
479
496
  );
480
497
  return match ? deduped.filter(toPredicate(match)) : deduped;
481
- }, [routes, match]);
498
+ }, [routes, match, staticRoutes]);
482
499
  }
483
500
  function ReactRouterDevDock({
484
501
  match,
502
+ staticRoutes,
485
503
  ...props
486
504
  }) {
487
505
  const navigate = reactRouter.useNavigate();
488
- const detected = useDetectedRoutes(match);
506
+ const detected = useDetectedRoutes({ match, staticRoutes });
489
507
  const routes = react.useMemo(
490
508
  () => [...detected, ...props.routes ?? []],
491
509
  [detected, props.routes]