@visulima/dev-toolbar 0.0.1 → 1.0.0-alpha.1

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 (95) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE.md +77 -0
  3. package/README.md +277 -29
  4. package/dist/apps/a11y/a11y-app.d.ts +5 -0
  5. package/dist/apps/a11y/a11y-store.d.ts +46 -0
  6. package/dist/apps/a11y/a11y-tooltip.d.ts +11 -0
  7. package/dist/apps/a11y/index.d.ts +3 -0
  8. package/dist/apps/a11y/index.js +21 -0
  9. package/dist/apps/module-graph/index.d.ts +3 -0
  10. package/dist/apps/module-graph/index.js +20 -0
  11. package/dist/apps/module-graph/module-graph-app.d.ts +5 -0
  12. package/dist/apps/more/index.d.ts +3 -0
  13. package/dist/apps/more/index.js +19 -0
  14. package/dist/apps/more/more-app.d.ts +5 -0
  15. package/dist/apps/performance/index.d.ts +3 -0
  16. package/dist/apps/performance/index.js +17 -0
  17. package/dist/apps/performance/performance-app.d.ts +5 -0
  18. package/dist/apps/performance/performance-tooltip.d.ts +5 -0
  19. package/dist/apps/seo/index.d.ts +3 -0
  20. package/dist/apps/seo/index.js +17 -0
  21. package/dist/apps/seo/seo-app.d.ts +5 -0
  22. package/dist/apps/settings/index.d.ts +3 -0
  23. package/dist/apps/settings/index.js +17 -0
  24. package/dist/apps/settings/settings-app.d.ts +5 -0
  25. package/dist/apps/timeline/index.d.ts +3 -0
  26. package/dist/apps/timeline/index.js +18 -0
  27. package/dist/apps/timeline/timeline-app.d.ts +5 -0
  28. package/dist/apps/vite-config/index.d.ts +3 -0
  29. package/dist/apps/vite-config/index.js +16 -0
  30. package/dist/apps/vite-config/vite-config-app.d.ts +5 -0
  31. package/dist/client/overlay.d.ts +1 -0
  32. package/dist/client/overlay.js +1 -0
  33. package/dist/hooks/create-hook.d.ts +10 -0
  34. package/dist/hooks/events.d.ts +5 -0
  35. package/dist/hooks/global-hook.d.ts +15 -0
  36. package/dist/hooks/index.d.ts +6 -0
  37. package/dist/index.d.ts +6 -0
  38. package/dist/index.js +1 -0
  39. package/dist/packem_shared/TimelineStore-BgBrirKd.js +1 -0
  40. package/dist/packem_shared/cn-BEsR6GkP.js +1 -0
  41. package/dist/packem_shared/createClientRPCContext-DzKQpKTk.js +1 -0
  42. package/dist/packem_shared/createDevToolbarHook-DGNxqk8N.js +1 -0
  43. package/dist/packem_shared/createServerRPCContext-BVSesPXu.js +1 -0
  44. package/dist/packem_shared/icon-BUQ92HaT.js +1 -0
  45. package/dist/packem_shared/loadSettings-hvjR4fcS.js +1 -0
  46. package/dist/packem_shared/setupGlobalHook-CFuxsCyl.js +1 -0
  47. package/dist/packem_shared/store-BxE0w51s.js +1 -0
  48. package/dist/performance/monitor.d.ts +115 -0
  49. package/dist/rpc/client.d.ts +7 -0
  50. package/dist/rpc/functions/module-graph.d.ts +17 -0
  51. package/dist/rpc/functions/open-in-editor.d.ts +9 -0
  52. package/dist/rpc/functions/vite-config.d.ts +7 -0
  53. package/dist/rpc/index.d.ts +8 -0
  54. package/dist/rpc/server.d.ts +9 -0
  55. package/dist/timeline/index.d.ts +6 -0
  56. package/dist/timeline/store.d.ts +52 -0
  57. package/dist/toolbar/app-manager.d.ts +95 -0
  58. package/dist/toolbar/components/app-button.d.ts +19 -0
  59. package/dist/toolbar/components/app-canvas.d.ts +13 -0
  60. package/dist/toolbar/components/app-tooltip-overlay.d.ts +13 -0
  61. package/dist/toolbar/components/first-visit-hint.d.ts +16 -0
  62. package/dist/toolbar/components/index.d.ts +4 -0
  63. package/dist/toolbar/components/pinned-tooltip-card.d.ts +23 -0
  64. package/dist/toolbar/components/toolbar-bar.d.ts +15 -0
  65. package/dist/toolbar/components/toolbar-container.d.ts +55 -0
  66. package/dist/toolbar/components/vite-overlay-button.d.ts +15 -0
  67. package/dist/toolbar/context/index.d.ts +2 -0
  68. package/dist/toolbar/context/toolbar-context.d.ts +106 -0
  69. package/dist/toolbar/global-api.d.ts +23 -0
  70. package/dist/toolbar/helpers.d.ts +6 -0
  71. package/dist/toolbar/hooks/index.d.ts +10 -0
  72. package/dist/toolbar/hooks/use-apps.d.ts +13 -0
  73. package/dist/toolbar/hooks/use-frame-state.d.ts +94 -0
  74. package/dist/toolbar/hooks/use-panel-visible.d.ts +21 -0
  75. package/dist/toolbar/hooks/use-position.d.ts +22 -0
  76. package/dist/toolbar/hooks/use-theme.d.ts +13 -0
  77. package/dist/toolbar/hooks/use-toolbar.d.ts +14 -0
  78. package/dist/toolbar/index.d.ts +58 -0
  79. package/dist/toolbar/index.js +22 -0
  80. package/dist/toolbar/settings.d.ts +17 -0
  81. package/dist/toolbar/stylesheet.d.ts +1 -0
  82. package/dist/toolbar/utils/index.d.ts +12 -0
  83. package/dist/types/app.d.ts +163 -0
  84. package/dist/types/global-api.d.ts +95 -0
  85. package/dist/types/hooks.d.ts +88 -0
  86. package/dist/types/index.d.ts +12 -0
  87. package/dist/types/messaging.d.ts +43 -0
  88. package/dist/types/rpc.d.ts +95 -0
  89. package/dist/types/timeline.d.ts +62 -0
  90. package/dist/types/toolbar.d.ts +56 -0
  91. package/dist/ui/components/icon.d.ts +21 -0
  92. package/dist/utils/cn.d.ts +8 -0
  93. package/dist/vite-plugin.d.ts +106 -0
  94. package/dist/vite-plugin.js +2 -0
  95. package/package.json +105 -7
package/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## @visulima/dev-toolbar 1.0.0-alpha.1 (2026-02-28)
2
+
3
+ ### Features
4
+
5
+ * **dev-toolbar:** initialize dev-toolbar package ([#586](https://github.com/visulima/visulima/issues/586)) ([a3ab9d6](https://github.com/visulima/visulima/commit/a3ab9d6e6c768853854b95fa8eee908b95235ea5))
package/LICENSE.md ADDED
@@ -0,0 +1,77 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 visulima
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
23
+ <!-- DEPENDENCIES -->
24
+
25
+ # Licenses of bundled dependencies
26
+ The published @visulima/dev-toolbar artifact additionally contains code with the following licenses:
27
+ ISC
28
+
29
+ # Bundled dependencies:
30
+ ## lucide-static
31
+ License: ISC
32
+ Repository: https://github.com/lucide-icons/lucide.git
33
+
34
+ > ISC License
35
+ >
36
+ > Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2026 as part of Feather (MIT). All other copyright (c) for Lucide are held by Lucide Contributors 2026.
37
+ >
38
+ > Permission to use, copy, modify, and/or distribute this software for any
39
+ > purpose with or without fee is hereby granted, provided that the above
40
+ > copyright notice and this permission notice appear in all copies.
41
+ >
42
+ > THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
43
+ > WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
44
+ > MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
45
+ > ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
46
+ > WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
47
+ > ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
48
+ > OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
49
+ >
50
+ > ---
51
+ >
52
+ > The MIT License (MIT) (for portions derived from Feather)
53
+ >
54
+ > Copyright (c) 2013-2026 Cole Bemis
55
+ >
56
+ > Permission is hereby granted, free of charge, to any person obtaining a copy
57
+ > of this software and associated documentation files (the "Software"), to deal
58
+ > in the Software without restriction, including without limitation the rights
59
+ > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
60
+ > copies of the Software, and to permit persons to whom the Software is
61
+ > furnished to do so, subject to the following conditions:
62
+ >
63
+ > The above copyright notice and this permission notice shall be included in all
64
+ > copies or substantial portions of the Software.
65
+ >
66
+ > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
67
+ > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
68
+ > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
69
+ > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
70
+ > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
71
+ > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
72
+ > SOFTWARE.
73
+
74
+ <!-- /DEPENDENCIES -->
75
+
76
+ <!-- TYPE_DEPENDENCIES -->
77
+ <!-- /TYPE_DEPENDENCIES -->
package/README.md CHANGED
@@ -1,45 +1,293 @@
1
- # @visulima/dev-toolbar
1
+ <!-- START_PACKAGE_OG_IMAGE_PLACEHOLDER --><!-- END_PACKAGE_OG_IMAGE_PLACEHOLDER -->
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
3
+ <br />
4
4
 
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
5
+ <div align="center">
6
6
 
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
7
+ [![typescript-image][typescript-badge]][typescript-url]
8
+ [![mit licence][license-badge]][license]
9
+ [![npm downloads][npm-downloads-badge]][npm-downloads]
10
+ [![Chat][chat-badge]][chat]
11
+ [![PRs Welcome][prs-welcome-badge]][prs-welcome]
8
12
 
9
- ## Purpose
13
+ </div>
10
14
 
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@visulima/dev-toolbar`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
15
+ ---
16
+
17
+ <div align="center">
18
+ <p>
19
+ <sup>
20
+ Daniel Bannert's open source work is supported by the community on <a href="https://github.com/sponsors/prisis">GitHub Sponsors</a>
21
+ </sup>
22
+ </p>
23
+ </div>
15
24
 
16
- ## What is OIDC Trusted Publishing?
25
+ ---
17
26
 
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
27
+ ## Overview
19
28
 
20
- ## Setup Instructions
29
+ `@visulima/dev-toolbar` is a framework-agnostic development toolbar for **any Vite project** — React, Vue, Svelte, SolidJS, or plain HTML. Inspired by Astro DevToolbar, Vue DevTools, and Nuxt DevTools, it provides a consistent developer experience regardless of your framework.
21
30
 
22
- To properly configure OIDC trusted publishing for this package:
31
+ The toolbar renders inside a Shadow DOM custom element (zero style leakage), communicates with the Vite dev server over type-safe RPC, and ships **seven built-in apps** covering the most common development workflows.
23
32
 
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
33
+ ## Install
28
34
 
29
- ## DO NOT USE THIS PACKAGE
35
+ ```sh
36
+ npm install -D @visulima/dev-toolbar
37
+ ```
30
38
 
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
39
+ ```sh
40
+ pnpm add -D @visulima/dev-toolbar
41
+ ```
36
42
 
37
- ## More Information
43
+ ```sh
44
+ yarn add -D @visulima/dev-toolbar
45
+ ```
38
46
 
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
47
+ ## Quick Start
42
48
 
43
- ---
49
+ Add the plugin to your `vite.config.ts`:
50
+
51
+ ```ts
52
+ import { defineConfig } from "vite";
53
+ import { devToolbar } from "@visulima/dev-toolbar/vite";
54
+
55
+ export default defineConfig({
56
+ plugins: [
57
+ devToolbar(),
58
+ ],
59
+ });
60
+ ```
61
+
62
+ Start your dev server and press **`Alt`+`Shift`+`D`** to open the toolbar.
63
+
64
+ ## Built-in Apps
65
+
66
+ | App | What it does |
67
+ |---|---|
68
+ | **Accessibility** | axe-core WCAG audit with live element overlays and sessionStorage persistence |
69
+ | **Performance** | Web Vitals (LCP, INP, CLS, FCP, TTFB), resource timing, navigation waterfall |
70
+ | **SEO** | Social preview cards for 7 platforms + full meta tag audit |
71
+ | **Timeline** | Chronological event log from your app and integrated libraries |
72
+ | **Module Graph** | Browse and filter Vite's live module dependency graph |
73
+ | **Vite Config** | Inspect the fully resolved Vite configuration |
74
+ | **Settings** | Theme, toolbar behaviour, panel sizing, and custom keyboard shortcuts |
75
+
76
+ All apps are enabled by default. Disable individual apps via plugin options:
77
+
78
+ ```ts
79
+ devToolbar({
80
+ apps: {
81
+ performance: false,
82
+ seo: false,
83
+ },
84
+ })
85
+ ```
86
+
87
+ ## Plugin Options
88
+
89
+ ```ts
90
+ devToolbar({
91
+ // Built-in apps (all true by default)
92
+ apps: {
93
+ a11y: true,
94
+ moduleGraph: true,
95
+ performance: true,
96
+ seo: true,
97
+ settings: true,
98
+ timeline: true,
99
+ viteConfig: true,
100
+ },
101
+
102
+ // Register custom apps
103
+ customApps: [],
104
+
105
+ // Toolbar pill placement
106
+ placement: "bottom-center", // "bottom-left" | "bottom-center" | "bottom-right"
107
+ position: "bottom", // "bottom" | "top" | "left" | "right"
108
+
109
+ // Panel defaults (users can override via Settings app)
110
+ height: 60, // % of viewport height
111
+ width: 80, // % of viewport width
112
+ minimizePanelInactive: 5000, // ms; -1 = never auto-hide
113
+ closeOnOutsideClick: true,
114
+
115
+ // Keyboard shortcuts (project-level defaults)
116
+ keybindings: {
117
+ toggle: "Alt+Shift+D",
118
+ close: "Escape",
119
+ },
120
+ })
121
+ ```
122
+
123
+ See the [full configuration reference](./docs/configuration.mdx) for all options.
124
+
125
+ ## Keyboard Shortcuts
126
+
127
+ | Action | Default |
128
+ |---|---|
129
+ | Toggle toolbar open/close | `Alt`+`Shift`+`D` |
130
+ | Close active app / panel | `Escape` |
131
+
132
+ Both shortcuts are configurable in the Settings app or via plugin options.
133
+
134
+ ## Custom Apps
135
+
136
+ Build your own devtools panel with a Preact component:
137
+
138
+ ```tsx
139
+ /** @jsxImportSource preact */
140
+ import type { ComponentChildren } from "preact";
141
+ import type { AppComponentProps } from "@visulima/dev-toolbar";
142
+
143
+ const MyApp = ({ helpers }: AppComponentProps): ComponentChildren => {
144
+ return <div class="p-5">Hello from My App!</div>;
145
+ };
146
+ ```
147
+
148
+ ```ts
149
+ // vite.config.ts
150
+ devToolbar({
151
+ customApps: [
152
+ {
153
+ id: "my-package:my-app",
154
+ name: "My App",
155
+ icon: myIconSvg, // raw SVG string
156
+ component: MyApp,
157
+ tooltip: MyTooltip, // optional hover summary
158
+ },
159
+ ],
160
+ })
161
+ ```
162
+
163
+ See the [custom apps guide](./docs/custom-apps/creating-apps.mdx) for a step-by-step walkthrough including RPC, tooltips, and styling.
164
+
165
+ ## RPC — Server ↔ Client Communication
166
+
167
+ Call Node.js functions from your app component over the Vite HMR WebSocket:
168
+
169
+ ```ts
170
+ // Add server functions in vite.config.ts
171
+ devToolbar({
172
+ serverFunctions: {
173
+ async getRoutes() {
174
+ const files = await fs.readdir("src/pages");
175
+ return files.map((f) => `/${f.replace(/\.(tsx?|jsx?)$/, "")}`);
176
+ },
177
+ },
178
+ })
179
+
180
+ // Call from your app component
181
+ const routes = await helpers.rpc.getRoutes();
182
+ ```
183
+
184
+ Built-in RPC functions: `getViteConfig()`, `getModuleGraph()`, `openInEditor(file, line, col)`.
185
+
186
+ ## Global API
187
+
188
+ Programmatic control from any script or the browser console:
189
+
190
+ ```ts
191
+ const api = (window as any).__VISULIMA_DEVTOOLS__;
192
+
193
+ // Open an app
194
+ await api.openApp("dev-toolbar:a11y");
195
+
196
+ // Show a notification badge on an app button
197
+ api.notify("my-package:monitor", "warning");
198
+
199
+ // Update toolbar settings
200
+ api.updateSettings({ viewMode: "fullscreen" });
201
+
202
+ // Access RPC from outside a component
203
+ const config = await api.rpc.getViteConfig();
204
+ ```
205
+
206
+ ## Library Integration
207
+
208
+ Add zero-dependency devtools support to your library. Users get devtools automatically when they install the toolbar — no extra configuration needed:
209
+
210
+ ```ts
211
+ function installDevTools(instance: MyLibrary): void {
212
+ const hook = (window as any).__DEV_TOOLBAR_HOOK__;
213
+ if (!hook) return;
214
+
215
+ hook.registerApp({
216
+ id: "my-library:devtools",
217
+ name: "My Library",
218
+ icon: iconSvg,
219
+ component: MyLibraryPanel,
220
+ });
221
+
222
+ instance.on("action", (action) => {
223
+ hook.addTimelineEvent("my-library", {
224
+ id: crypto.randomUUID(),
225
+ title: action.type,
226
+ time: Date.now(),
227
+ level: "info",
228
+ data: action,
229
+ });
230
+ });
231
+ }
232
+ ```
233
+
234
+ See the [library integration guide](./docs/integrations/library-integration.mdx) for the full pattern.
235
+
236
+ ## Documentation
237
+
238
+ All docs are in the [`docs/`](./docs/) folder in Fumadocs MDX format:
239
+
240
+ | Page | Contents |
241
+ |---|---|
242
+ | [Getting Started](./docs/getting-started.mdx) | Install, framework examples, first steps |
243
+ | [Configuration](./docs/configuration.mdx) | Full plugin options reference |
244
+ | [Accessibility](./docs/built-in-apps/accessibility.mdx) | axe-core, overlays, WCAG standards |
245
+ | [Performance](./docs/built-in-apps/performance.mdx) | Web Vitals thresholds, timing APIs |
246
+ | [SEO](./docs/built-in-apps/seo.mdx) | Social previews, meta tag audit |
247
+ | [Timeline](./docs/built-in-apps/timeline.mdx) | Event structure, emitting events |
248
+ | [Module Graph](./docs/built-in-apps/module-graph.mdx) | Search, ext badges, importer view |
249
+ | [Vite Config](./docs/built-in-apps/vite-config.mdx) | Resolved config sections |
250
+ | [Settings](./docs/built-in-apps/settings.mdx) | All settings, localStorage schema |
251
+ | [Creating Apps](./docs/custom-apps/creating-apps.mdx) | Step-by-step custom app guide |
252
+ | [App API](./docs/custom-apps/app-api.mdx) | TypeScript interface reference |
253
+ | [RPC](./docs/custom-apps/rpc.mdx) | Server functions, type-safe pattern |
254
+ | [Global API](./docs/custom-apps/global-api.mdx) | `__VISULIMA_DEVTOOLS__` reference |
255
+ | [Library Integration](./docs/integrations/library-integration.mdx) | Zero-dependency hook pattern |
256
+
257
+ ## Supported Node.js Versions
258
+
259
+ Libraries in this ecosystem make the best effort to track
260
+ [Node.js' release schedule](https://github.com/nodejs/release#release-schedule).
261
+ Here's [a post on why we think this is important](https://medium.com/the-node-js-collection/maintainers-should-consider-following-node-js-release-schedule-ab08ed4de71a).
262
+
263
+ ## Contributing
264
+
265
+ If you would like to help take a look at the [list of issues](https://github.com/visulima/visulima/issues) and check our [Contributing](https://github.com/visulima/visulima/blob/main/.github/CONTRIBUTING.md) guidelines.
266
+
267
+ > **Note:** please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
268
+
269
+ ## Credits
270
+
271
+ - [Daniel Bannert](https://github.com/prisis)
272
+ - [All Contributors](https://github.com/visulima/visulima/graphs/contributors)
273
+
274
+ ## Made with ❤️ at Anolilab
275
+
276
+ This is an open-source project and will always remain free to use. If you think it's cool, please star it 🌟. [Anolilab](https://www.anolilab.com/open-source) is a Development and AI Studio. Contact us at [hello@anolilab.com](mailto:hello@anolilab.com) if you need any help with these technologies or just want to say hi!
277
+
278
+ ## License
279
+
280
+ The visulima dev-toolbar is open-sourced software licensed under the [MIT][license]
281
+
282
+ <!-- badges -->
44
283
 
45
- **Maintained for OIDC setup purposes only**
284
+ [license-badge]: https://img.shields.io/npm/l/@visulima/dev-toolbar?style=for-the-badge
285
+ [license]: https://github.com/visulima/visulima/blob/main/LICENSE
286
+ [npm-downloads-badge]: https://img.shields.io/npm/dm/@visulima/dev-toolbar?style=for-the-badge
287
+ [npm-downloads]: https://www.npmjs.com/package/@visulima/dev-toolbar
288
+ [prs-welcome-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge
289
+ [prs-welcome]: https://github.com/visulima/visulima/blob/main/.github/CONTRIBUTING.md
290
+ [chat-badge]: https://img.shields.io/discord/932323359193186354.svg?style=for-the-badge
291
+ [chat]: https://discord.gg/TtFJY8xkFK
292
+ [typescript-badge]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
293
+ [typescript-url]: https://www.typescriptlang.org/
@@ -0,0 +1,5 @@
1
+ /** @jsxImportSource preact */
2
+ import type { ComponentChildren } from "preact";
3
+ import type { AppComponentProps } from "../../types/app.d.ts";
4
+ declare const A11yApp: (_props: AppComponentProps) => ComponentChildren;
5
+ export default A11yApp;
@@ -0,0 +1,46 @@
1
+ export type Severity = "critical" | "minor" | "moderate" | "serious";
2
+ export type Standard = "best-practice" | "wcag21aa" | "wcag22aa" | "wcag2a";
3
+ export interface A11yNode {
4
+ html: string;
5
+ selector: string;
6
+ }
7
+ export interface A11yIssue {
8
+ helpUrl: string;
9
+ id: string;
10
+ impact: Severity;
11
+ message: string;
12
+ nodes: A11yNode[];
13
+ wcagTags: string[];
14
+ }
15
+ export interface A11yStoreState {
16
+ isScanning: boolean;
17
+ issues: A11yIssue[];
18
+ lastScan: null | string;
19
+ scanError: null | string;
20
+ showOverlays: boolean;
21
+ standard: Standard;
22
+ }
23
+ export declare const SEVERITY_ORDER: Severity[];
24
+ type Listener = () => void;
25
+ declare class A11yStore {
26
+ private listeners;
27
+ private state;
28
+ constructor();
29
+ /** Remove all outline highlights from the page */
30
+ clearHighlights(): void;
31
+ getState(): Readonly<A11yStoreState>;
32
+ /** Scroll to and outline a single issue's elements */
33
+ highlightIssue(issue: A11yIssue): void;
34
+ /** Run an axe-core scan and persist results */
35
+ scan(disabledRules?: string[]): Promise<void>;
36
+ /** Toggle overlay highlights on all affected elements */
37
+ setShowOverlays(show: boolean): void;
38
+ /** Change the WCAG standard used for future scans */
39
+ setStandard(standard: Standard): void;
40
+ subscribe(fn: Listener): () => void;
41
+ private notify;
42
+ private persist;
43
+ private update;
44
+ }
45
+ export declare const a11yStore: A11yStore;
46
+ export {};
@@ -0,0 +1,11 @@
1
+ /** @jsxImportSource preact */
2
+ import type { ComponentChildren } from "preact";
3
+ import type { AppTooltipProps } from "../../types/app.d.ts";
4
+ /**
5
+ * Hover tooltip for the Accessibility app button.
6
+ * Shows a summary of scan results and quick action buttons.
7
+ * @param _props - Tooltip props (unused; reads from a11yStore directly)
8
+ * @returns Rendered tooltip component
9
+ */
10
+ declare const A11yTooltip: (_props: AppTooltipProps) => ComponentChildren;
11
+ export default A11yTooltip;
@@ -0,0 +1,3 @@
1
+ import type { DevToolbarApp } from "../../types/app.d.ts";
2
+ declare const a11yApp: DevToolbarApp;
3
+ export default a11yApp;
@@ -0,0 +1,21 @@
1
+ var K=Object.defineProperty;var C=(s,e)=>K(s,"name",{value:e,configurable:!0});import{addHookName as v}from"preact/devtools";import{useState as S,useEffect as U}from"preact/hooks";import{m as u}from"../../packem_shared/cn-BEsR6GkP.js";import{jsxs as a,jsx as t,Fragment as G}from"preact/jsx-runtime";const Q=`<!-- @license lucide-static v0.575.0 - ISC -->
2
+ <svg
3
+ class="lucide lucide-accessibility"
4
+ xmlns="http://www.w3.org/2000/svg"
5
+ width="24"
6
+ height="24"
7
+ viewBox="0 0 24 24"
8
+ fill="none"
9
+ stroke="currentColor"
10
+ stroke-width="2"
11
+ stroke-linecap="round"
12
+ stroke-linejoin="round"
13
+ >
14
+ <circle cx="16" cy="4" r="1" />
15
+ <path d="m18 19 1-7-6 1" />
16
+ <path d="m5 8 3-3 5.5 3-2.36 3.5" />
17
+ <path d="M4.24 14.5a5 5 0 0 0 6.88 6" />
18
+ <path d="M13.76 17.5a5 5 0 0 0-6.88-6" />
19
+ </svg>
20
+ `;var X=Object.defineProperty,b=C((s,e)=>X(s,"name",{value:e,configurable:!0}),"i$2");const M=["critical","serious","moderate","minor"],Z={critical:"rgb(239,68,68)",minor:"rgb(100,116,139)",moderate:"rgb(249,115,22)",serious:"rgb(234,179,8)"},ee={"best-practice":["best-practice"],wcag21aa:["wcag2a","wcag2aa","wcag21a","wcag21aa"],wcag22aa:["wcag2a","wcag2aa","wcag21a","wcag21aa","wcag22a","wcag22aa"],wcag2a:["wcag2a"]},H="__vdt_a11y__",te=b(()=>{try{const s=sessionStorage.getItem(H);if(s){const e=JSON.parse(s);if(Array.isArray(e.issues))return{issues:e.issues,lastScan:e.lastScan??null}}}catch{}return{issues:[],lastScan:null}},"loadFromSession"),_=b((s,e)=>{const o=s;o.dataset.vdtA11y=e,o.style.setProperty("outline",`2px solid ${Z[e]}`,"important"),o.style.setProperty("outline-offset","2px","important")},"setHighlight"),E=b(()=>{for(const s of document.querySelectorAll("[data-vdt-a11y]")){const e=s;delete e.dataset.vdtA11y,e.style.removeProperty("outline"),e.style.removeProperty("outline-offset")}},"clearHighlightsDOM"),B=b(s=>{E();for(const e of s)for(const o of e.nodes)try{const r=document.querySelector(o.selector);r&&_(r,e.impact)}catch{}},"applyOverlaysDOM"),re=b(s=>{const e=s[s.length-1];return Array.isArray(e)?e.join(" "):String(e??"")},"nodeSelector"),ne=b((s,e)=>{const o=[];for(const r of s)e.includes(r.id)||o.push({helpUrl:r.helpUrl,id:r.id,impact:r.impact??"minor",message:r.help,nodes:r.nodes.map(i=>({html:i.html,selector:re(i.target)})),wcagTags:r.tags.filter(i=>i.startsWith("wcag")||i==="best-practice")});return o},"convertViolations"),se=b(async s=>{const e=await import("axe-core");return(e.default??e).run(document,{exclude:[["dev-toolbar"]],runOnly:{type:"tag",values:ee[s]}})},"runAxeScan");class oe{static{C(this,"v")}static{b(this,"A11yStore")}listeners=new Set;state;constructor(){const{issues:e,lastScan:o}=te();this.state={isScanning:!1,issues:e,lastScan:o,scanError:null,showOverlays:!1,standard:"wcag21aa"}}clearHighlights(){E()}getState(){return this.state}highlightIssue(e){E();let o=!1;for(const r of e.nodes)try{const i=document.querySelector(r.selector);i&&(_(i,e.impact),o||(i.scrollIntoView({behavior:"smooth",block:"center"}),o=!0))}catch{}}async scan(e=[]){if(!this.state.isScanning){this.update({isScanning:!0,scanError:null});try{const o=await se(this.state.standard),r=ne(o.violations,e);this.update({isScanning:!1,issues:r,lastScan:new Date().toISOString()}),this.persist(),this.state.showOverlays&&B(r)}catch(o){this.update({isScanning:!1,scanError:o instanceof Error?o.message:String(o)})}}}setShowOverlays(e){this.update({showOverlays:e}),e?B(this.state.issues):E()}setStandard(e){this.update({standard:e})}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}notify(){for(const e of this.listeners)e()}persist(){try{sessionStorage.setItem(H,JSON.stringify({issues:this.state.issues,lastScan:this.state.lastScan}))}catch{}}update(e){this.state={...this.state,...e},this.notify()}}const c=new oe;var ae=Object.defineProperty,l=C((s,e)=>ae(s,"name",{value:e,configurable:!0}),"n");const $={critical:"Critical",minor:"Minor",moderate:"Moderate",serious:"Serious"},W={critical:"text-destructive",minor:"text-muted-foreground",moderate:"text-warning-foreground",serious:"text-warning-foreground"},ie={critical:"bg-destructive/10 border-destructive/30",minor:"bg-foreground/4 border-border",moderate:"bg-warning/10 border-warning/30",serious:"bg-warning/10 border-warning/30"},le={critical:"bg-destructive",minor:"bg-muted-foreground/50",moderate:"bg-warning",serious:"bg-warning"},ce=l(({count:s,isActive:e,onClick:o,severity:r})=>a("button",{class:u("flex flex-col items-center gap-1 px-3 py-2.5 border cursor-pointer transition-colors",e?"ring-1 ring-inset ring-primary/40":"hover:bg-foreground/6",ie[r]),onClick:o,title:`${e?"Clear":"Filter by"} ${$[r]}`,type:"button",children:[t("span",{class:u("text-xl font-bold tabular-nums leading-none",W[r]),children:s}),t("span",{class:"text-[0.6rem] font-semibold uppercase tracking-wider text-muted-foreground",children:$[r]})]}),"SeverityBucket"),de=l(({isSelected:s,issue:e,onClick:o,onDisable:r})=>a("div",{class:u("p-3 border cursor-pointer transition-colors",s?"bg-foreground/6 border-primary/30":"border-border hover:bg-foreground/3"),onClick:o,children:[a("div",{class:"flex items-start gap-2 mb-1.5",children:[t("span",{class:u("mt-1 size-2 rounded-full shrink-0",le[e.impact])}),t("span",{class:"text-[0.75rem] font-semibold text-foreground flex-1 leading-snug",children:e.id}),t("span",{class:u("text-[0.6rem] font-bold uppercase tracking-wide shrink-0",W[e.impact]),children:$[e.impact]})]}),t("p",{class:"text-[0.7rem] text-muted-foreground leading-relaxed mb-2 ml-4",children:e.message}),e.nodes.length>0&&a("div",{class:"mb-2 ml-4 space-y-0.5",children:[e.nodes.slice(0,3).map((i,p)=>t("code",{class:"block text-[0.65rem] text-foreground/70 font-mono bg-foreground/5 px-2 py-1 truncate",children:i.selector},p)),e.nodes.length>3&&a("span",{class:"text-[0.62rem] text-muted-foreground/60",children:["+",e.nodes.length-3," more element",e.nodes.length>4?"s":""]})]}),a("div",{class:"flex items-center gap-2 flex-wrap ml-4",children:[e.wcagTags.slice(0,3).map(i=>t("span",{class:"text-[0.58rem] font-mono uppercase bg-primary/8 text-primary/70 border border-primary/20 px-1.5 py-0.5",children:i},i)),t("span",{class:"flex-1"}),t("a",{class:"text-[0.62rem] text-primary/70 hover:text-primary transition-colors",href:e.helpUrl,onClick:l(i=>i.stopPropagation(),"onClick"),rel:"noopener noreferrer",target:"_blank",children:"Learn more ↗"}),t("button",{class:"text-[0.62rem] text-muted-foreground/60 hover:text-muted-foreground transition-colors cursor-pointer bg-transparent border-0 p-0",onClick:l(i=>{i.stopPropagation(),r(e.id)},"onClick"),title:"Disable this rule for current session",type:"button",children:"Disable"})]})]}),"IssueCard"),ue=l(s=>{const[e,o]=v(S(()=>c.getState()),"storeState"),[r,i]=v(S([]),"disabledRules"),[p,A]=v(S(null),"minSeverity"),[y,w]=v(S(null),"activeIssueId"),[m,d]=v(S(null),"filterSeverity");U(()=>c.subscribe(()=>o(c.getState())),[]),U(()=>c.clearHighlights.bind(c),[]);const{isScanning:h,issues:f,lastScan:J,scanError:j,showOverlays:I,standard:V}=e,N=J!==null||j!==null,L=l(()=>{d(null),w(null),c.scan(r)},"handleScan"),q=l(n=>{y===n.id?(w(null),c.clearHighlights(),I&&c.setShowOverlays(!0)):(w(n.id),c.highlightIssue(n))},"handleIssueClick"),F=l(n=>{i(g=>[...g,n])},"handleDisableRule"),R=f.filter(n=>!(r.includes(n.id)||m&&n.impact!==m||p&&M.indexOf(n.impact)>M.indexOf(p))),Y=l(n=>f.filter(g=>!r.includes(g.id)&&g.impact===n).length,"countBy");return a("div",{class:"flex flex-col h-full",children:[a("div",{class:"shrink-0 flex items-center gap-2 px-4 py-2.5 border-b border-border bg-foreground/2 flex-wrap",children:[t("button",{class:u("px-3 py-1.5 text-[0.7rem] font-medium border transition-colors cursor-pointer",h?"border-primary/30 text-primary/50 bg-primary/5 cursor-not-allowed":"border-border text-foreground bg-transparent hover:bg-foreground/5"),disabled:h,onClick:L,type:"button",children:h?"Scanning…":"Scan page"}),a("label",{class:"flex items-center gap-1.5 text-[0.7rem] text-muted-foreground",children:["Standard",a("select",{class:"bg-card border border-border text-foreground text-[0.7rem] px-1.5 py-1 cursor-pointer",onChange:l(n=>c.setStandard(n.target.value),"onChange"),style:"color-scheme: dark",value:V,children:[t("option",{value:"wcag21aa",children:"WCAG 2.1 AA"}),t("option",{value:"wcag22aa",children:"WCAG 2.2 AA"}),t("option",{value:"wcag2a",children:"WCAG 2.0 A"}),t("option",{value:"best-practice",children:"Best Practice"})]})]}),a("label",{class:"flex items-center gap-1.5 text-[0.7rem] text-muted-foreground",children:["Min",a("select",{class:"bg-card border border-border text-foreground text-[0.7rem] px-1.5 py-1 cursor-pointer",onChange:l(n=>{const g=n.target.value;A(g||null)},"onChange"),style:"color-scheme: dark",value:p??"",children:[t("option",{value:"",children:"All"}),t("option",{value:"critical",children:"Critical only"}),t("option",{value:"serious",children:"Serious+"}),t("option",{value:"moderate",children:"Moderate+"})]})]}),t("button",{class:u("px-2.5 py-1.5 text-[0.7rem] border transition-colors cursor-pointer",I?"border-primary/30 text-primary bg-primary/8":"border-border text-muted-foreground bg-transparent hover:text-foreground"),onClick:l(()=>c.setShowOverlays(!I),"onClick"),title:"Toggle visual highlights on affected elements",type:"button",children:"Overlays"}),N&&f.length>0&&a(G,{children:[t("button",{class:"ml-auto px-2 py-1.5 text-[0.7rem] border border-border text-muted-foreground bg-transparent hover:text-foreground transition-colors cursor-pointer",onClick:l(()=>{const n=new Blob([JSON.stringify(f,null,2)],{type:"application/json"}),g=URL.createObjectURL(n),k=document.createElement("a");k.href=g,k.download="a11y-audit.json",k.click(),URL.revokeObjectURL(g)},"onClick"),title:"Export audit results as JSON",type:"button",children:"JSON"}),t("button",{class:"px-2 py-1.5 text-[0.7rem] border border-border text-muted-foreground bg-transparent hover:text-foreground transition-colors cursor-pointer",onClick:l(()=>{const n=l(x=>`"${x.replaceAll('"','""')}"`,"q"),g=["Rule ID","Severity","Message","Selector","HTML","WCAG Tags"].join(","),k=f.flatMap(x=>x.nodes.map(T=>[n(x.id),n(x.impact),n(x.message),n(T.selector),n(T.html),n(x.wcagTags.join("; "))].join(","))),z=new Blob([[g,...k].join(`
21
+ `)],{type:"text/csv"}),P=URL.createObjectURL(z),D=document.createElement("a");D.href=P,D.download="a11y-audit.csv",D.click(),URL.revokeObjectURL(P)},"onClick"),title:"Export audit results as CSV",type:"button",children:"CSV"})]})]}),a("div",{class:"flex-1 overflow-y-auto devtools-content-scroll",children:[j&&t("div",{class:"p-4 bg-destructive/10 border-b border-destructive/30",children:a("p",{class:"text-[0.72rem] text-destructive font-medium",children:["Scan failed: ",j]})}),!N&&!h&&a("div",{class:"flex flex-col items-center justify-center gap-4 p-8 min-h-48 text-center",children:[t("p",{class:"text-[0.8125rem] text-muted-foreground max-w-sm",children:"Run an accessibility audit using axe-core to detect WCAG violations on this page."}),t("button",{class:"px-4 py-2 text-[0.75rem] font-medium border border-border text-foreground bg-transparent hover:bg-foreground/5 transition-colors cursor-pointer",onClick:L,type:"button",children:"Start scan"})]}),h&&t("div",{class:"flex items-center justify-center gap-3 p-8 min-h-48",children:t("span",{class:"text-[0.8rem] text-muted-foreground",children:"Scanning for accessibility issues…"})}),N&&!h&&!j&&a("div",{class:"p-5 space-y-4",children:[t("div",{class:"grid grid-cols-4 gap-2",children:M.map(n=>t(ce,{count:Y(n),isActive:m===n,onClick:l(()=>d(m===n?null:n),"onClick"),severity:n},n))}),R.length===0?a("div",{class:"p-6 text-center border border-border",children:[t("p",{class:"text-[0.8125rem] font-medium text-foreground/70",children:f.length===0?"No violations found!":"No issues match the current filters."}),f.length===0&&t("p",{class:"mt-1 text-[0.7rem] text-muted-foreground",children:"Great — the page passes all rules for the selected standard."})]}):a("section",{children:[a("div",{class:"flex items-center gap-2 mb-2",children:[a("span",{class:"text-[0.65rem] font-bold uppercase tracking-[0.1em] text-muted-foreground",children:[t("span",{"aria-hidden":"true",class:"text-primary/50",children:"//"})," ",R.length," issue",R.length!==1?"s":"",m?` · ${$[m]} only`:""]}),m&&t("button",{class:"text-[0.62rem] text-primary/70 hover:text-primary cursor-pointer bg-transparent border-0 p-0 transition-colors",onClick:l(()=>d(null),"onClick"),type:"button",children:"Clear ×"})]}),t("div",{class:"space-y-2",children:R.map(n=>t(de,{isSelected:y===n.id,issue:n,onClick:l(()=>q(n),"onClick"),onDisable:F},n.id))})]}),r.length>0&&a("div",{class:"flex items-center gap-2 text-[0.65rem] text-muted-foreground/60",children:[a("span",{children:[r.length," rule",r.length!==1?"s":""," disabled this session."]}),t("button",{class:"text-primary/60 hover:text-primary cursor-pointer bg-transparent border-0 p-0 transition-colors",onClick:l(()=>i([]),"onClick"),type:"button",children:"Reset"})]})]})]})]})},"A11yApp");var ge=Object.defineProperty,O=C((s,e)=>ge(s,"name",{value:e,configurable:!0}),"i$1");const pe={critical:"text-destructive",minor:"text-muted-foreground",moderate:"text-warning-foreground",serious:"text-warning-foreground"},me={critical:"Crit",minor:"Min",moderate:"Mod",serious:"Ser"},he=O(s=>{const e=new Date(s).getTime();if(Number.isNaN(e))return"unknown";const o=Math.max(0,Math.floor((Date.now()-e)/1e3));if(o<10)return"just now";if(o<60)return`${o}s ago`;const r=Math.floor(o/60);return r<60?`${r} min ago`:`${Math.floor(r/60)} hr ago`},"formatElapsed"),be=O(s=>{const[e,o]=v(S(()=>c.getState()),"state");U(()=>c.subscribe(()=>o(c.getState())),[]);const{isScanning:r,issues:i,lastScan:p,showOverlays:A}=e,y=i.length,w=i.reduce((d,h)=>(d[h.impact]=(d[h.impact]??0)+1,d),{critical:0,minor:0,moderate:0,serious:0}),m=O(d=>w[d],"countBy");return a("div",{class:"space-y-3 min-w-[200px]",children:[p?a(G,{children:[a("div",{class:"flex items-baseline gap-2",children:[t("span",{class:u("text-2xl font-bold tabular-nums leading-none",y>0?"text-destructive":"text-success-foreground"),children:y}),a("span",{class:"text-[0.65rem] text-muted-foreground",children:["violation",y!==1?"s":""]})]}),t("div",{class:"grid grid-cols-4 gap-1.5",children:M.map(d=>a("div",{class:"flex flex-col items-center gap-0.5",children:[t("span",{class:u("text-[0.85rem] font-bold tabular-nums leading-none",pe[d]),children:m(d)}),t("span",{class:"text-[0.55rem] uppercase tracking-wide text-muted-foreground/70",children:me[d]})]},d))}),a("p",{class:"text-[0.62rem] text-muted-foreground/50",children:["Scanned ",he(p)]})]}):a("div",{children:[t("p",{class:"text-[0.72rem] text-muted-foreground",children:"No scan run yet."}),t("p",{class:"text-[0.65rem] text-muted-foreground/50 mt-0.5",children:"Scan this page to detect WCAG violations."})]}),a("div",{class:"flex items-center gap-2 pt-2 border-t border-border/50",children:[t("button",{class:u("flex-1 px-2.5 py-1.5 text-[0.7rem] font-medium border transition-colors cursor-pointer",r?"border-primary/30 text-primary/50 bg-primary/5 cursor-not-allowed":"border-border text-foreground bg-transparent hover:bg-foreground/5"),disabled:r,onClick:O(()=>{c.scan()},"onClick"),type:"button",children:r?"Scanning…":p?"Re-scan":"Scan"}),t("button",{class:u("px-2.5 py-1.5 text-[0.7rem] border transition-colors",i.length===0?"border-border/50 text-muted-foreground/40 bg-transparent cursor-not-allowed":u("cursor-pointer",A?"border-primary/30 text-primary bg-primary/8":"border-border text-muted-foreground bg-transparent hover:text-foreground")),disabled:i.length===0,onClick:O(()=>c.setShowOverlays(!A),"onClick"),title:"Toggle visual highlights on affected elements",type:"button",children:"Overlays"})]})]})},"A11yTooltip"),we={component:ue,icon:Q,id:"dev-toolbar:a11y",name:"Accessibility",tooltip:be};export{we as default};
@@ -0,0 +1,3 @@
1
+ import type { DevToolbarApp } from "../../types/app.d.ts";
2
+ declare const moduleGraphApp: DevToolbarApp;
3
+ export default moduleGraphApp;
@@ -0,0 +1,20 @@
1
+ var U=Object.defineProperty;var k=(o,d)=>U(o,"name",{value:d,configurable:!0});import{addHookName as s}from"preact/devtools";import{useState as i,useRef as A,useEffect as E}from"preact/hooks";import{m as h}from"../../packem_shared/cn-BEsR6GkP.js";import{jsx as r,jsxs as t}from"preact/jsx-runtime";const S=`<!-- @license lucide-static v0.575.0 - ISC -->
2
+ <svg
3
+ class="lucide lucide-network"
4
+ xmlns="http://www.w3.org/2000/svg"
5
+ width="24"
6
+ height="24"
7
+ viewBox="0 0 24 24"
8
+ fill="none"
9
+ stroke="currentColor"
10
+ stroke-width="2"
11
+ stroke-linecap="round"
12
+ stroke-linejoin="round"
13
+ >
14
+ <rect x="16" y="16" width="6" height="6" rx="1" />
15
+ <rect x="2" y="16" width="6" height="6" rx="1" />
16
+ <rect x="9" y="2" width="6" height="6" rx="1" />
17
+ <path d="M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3" />
18
+ <path d="M12 12V8" />
19
+ </svg>
20
+ `;var $=Object.defineProperty,l=k((o,d)=>$(o,"name",{value:d,configurable:!0}),"n");const z={css:"bg-purple-500/15 text-purple-400 border-purple-500/30",json:"bg-yellow-500/15 text-yellow-400 border-yellow-500/30",ts:"bg-blue-500/15 text-blue-400 border-blue-500/30",tsx:"bg-blue-500/15 text-blue-400 border-blue-500/30",js:"bg-green-500/15 text-green-400 border-green-500/30",jsx:"bg-green-500/15 text-green-400 border-green-500/30",vue:"bg-emerald-500/15 text-emerald-400 border-emerald-500/30",svg:"bg-orange-500/15 text-orange-400 border-orange-500/30"},B=l(o=>o.match(/\.([a-z]+)(?:\?|$)/i)?.[1]?.toLowerCase()??"?","getExt"),C=l(({ext:o})=>r("span",{class:h("inline-flex px-1.5 py-0.5 text-[0.6rem] font-mono font-bold uppercase border",z[o]??"bg-foreground/6 text-muted-foreground border-border"),children:o}),"ExtBadge"),F=l(({helpers:o})=>{const[d,j]=s(i([]),"modules"),[I,x]=s(i(!0),"loading"),[v,y]=s(i(null),"error"),[m,M]=s(i(""),"search"),[a,u]=s(i(null),"selectedId"),[w,f]=s(i([]),"importersList"),L=s(A(null),"searchRef"),g=l(()=>{x(!0),y(null),u(null),o.rpc.getModuleGraph().then(e=>{const c=e.map(n=>({id:n.id??n.url??"",url:n.url??n.id??"",ext:B(n.url??n.id??""),importers:n.importerCount??0,importerUrls:Array.isArray(n.importerUrls)?n.importerUrls:[]}));j(c),x(!1)}).catch(e=>{y(e.message??"Failed to load module graph"),x(!1)})},"load");E(()=>{g()},[]);const b=d.filter(e=>{const c=m.toLowerCase();return!c||e.url.toLowerCase().includes(c)||e.ext.includes(c)}),p=a?d.find(e=>e.id===a):null,R=l(e=>{if(a===e.id){u(null),f([]);return}u(e.id),f(e.importerUrls)},"showImporters");return I?t("div",{class:"flex flex-col items-center justify-center h-full gap-3 p-8 select-none",children:[r("div",{class:"flex gap-1.5 items-center","aria-hidden":"true",children:[0,160,320].map(e=>r("span",{class:"size-1.5 bg-primary/50 rounded-full animate-pulse",style:{animationDelay:`${e}ms`}},e))}),r("span",{class:"text-[0.75rem] text-muted-foreground",children:"Scanning module graph…"})]}):v?t("div",{class:"flex flex-col items-center justify-center h-full gap-3 p-8 text-center",children:[r("p",{class:"text-[0.8rem] text-destructive",children:v}),r("button",{class:"px-3 py-1.5 text-[0.75rem] border border-border text-muted-foreground hover:text-foreground cursor-pointer bg-transparent",onClick:g,type:"button",children:"Retry"})]}):t("div",{class:"flex flex-col h-full",children:[t("div",{class:"flex items-center gap-2 px-4 py-2.5 border-b border-border shrink-0",children:[r("input",{ref:L,class:h("flex-1 bg-foreground/4 border border-border px-3 py-1.5","text-[0.8rem] font-mono text-foreground placeholder:text-muted-foreground/50","focus:outline-none focus:border-primary/50 transition-colors"),onInput:l(e=>M(e.target.value),"onInput"),placeholder:"Filter modules…",type:"text",value:m}),t("span",{class:"text-[0.7rem] text-muted-foreground shrink-0",children:[b.length," / ",d.length]}),r("button",{class:"px-2.5 py-1.5 text-[0.725rem] border border-border text-muted-foreground hover:text-foreground cursor-pointer bg-transparent transition-colors",onClick:g,type:"button",children:"Refresh"})]}),t("div",{class:"flex flex-1 min-h-0 overflow-hidden",children:[r("div",{class:"flex-1 overflow-auto divide-y divide-border/30",children:b.length===0?t("div",{class:"flex items-center justify-center p-8 text-[0.8rem] text-muted-foreground",children:['No modules match "',m,'"']}):b.map(e=>t("button",{class:h("w-full flex items-center gap-3 px-4 py-2.5 text-left border-0 bg-transparent cursor-pointer","hover:bg-foreground/4 transition-colors duration-100",a===e.id&&"bg-primary/6"),onClick:l(()=>R(e),"onClick"),type:"button",children:[r(C,{ext:e.ext}),r("span",{class:"flex-1 text-[0.775rem] font-mono text-foreground/80 truncate min-w-0",children:e.url}),e.importers>0&&t("span",{class:"shrink-0 text-[0.65rem] text-muted-foreground px-1.5 py-0.5 bg-foreground/6 border border-border/50",children:[e.importers,"↑"]})]},e.id))}),p&&t("div",{class:"border-l border-border bg-background w-72 shrink-0 flex flex-col overflow-hidden",children:[t("div",{class:"flex items-center justify-between gap-2 px-4 py-3 border-b border-border shrink-0",children:[r("span",{class:"text-[0.7rem] font-semibold text-foreground uppercase tracking-wide",children:"Module Info"}),r("button",{"aria-label":"Close",class:"text-muted-foreground hover:text-foreground cursor-pointer border-0 bg-transparent text-xs",onClick:l(()=>{u(null),f([])},"onClick"),type:"button",children:"✕"})]}),t("div",{class:"flex-1 overflow-auto p-4 space-y-3",children:[t("div",{children:[r("div",{class:"text-[0.6rem] uppercase tracking-wider text-muted-foreground mb-1",children:"URL"}),r("code",{class:"text-[0.7rem] font-mono text-foreground/80 break-all",children:p.url})]}),t("div",{children:[r("div",{class:"text-[0.6rem] uppercase tracking-wider text-muted-foreground mb-1",children:"Type"}),r(C,{ext:p.ext})]}),t("div",{children:[r("div",{class:"text-[0.6rem] uppercase tracking-wider text-muted-foreground mb-1",children:"Importers"}),r("span",{class:"text-[0.8rem] font-mono text-foreground",children:p.importers})]}),w.length>0&&t("div",{children:[r("div",{class:"text-[0.6rem] uppercase tracking-wider text-muted-foreground mb-1",children:"Imported by"}),r("div",{class:"space-y-1",children:w.map(e=>r("code",{class:"block text-[0.65rem] font-mono text-muted-foreground break-all",children:e},e))})]})]})]})]})]})},"ModuleGraphApp"),O={component:F,icon:S,id:"dev-toolbar:module-graph",name:"Modules"};export{O as default};
@@ -0,0 +1,5 @@
1
+ /** @jsxImportSource preact */
2
+ import type { ComponentChildren } from "preact";
3
+ import type { AppComponentProps } from "../../types/app.d.ts";
4
+ declare const ModuleGraphApp: ({ helpers }: AppComponentProps) => ComponentChildren;
5
+ export default ModuleGraphApp;
@@ -0,0 +1,3 @@
1
+ import type { DevToolbarApp } from "../../types/app.d.ts";
2
+ declare const moreApp: DevToolbarApp;
3
+ export default moreApp;
@@ -0,0 +1,19 @@
1
+ var p=Object.defineProperty;var s=(n,t)=>p(n,"name",{value:t,configurable:!0});import{addHookName as m}from"preact/devtools";import{useState as u,useEffect as f}from"preact/hooks";import{m as g}from"../../packem_shared/cn-BEsR6GkP.js";import{jsxs as o,jsx as r}from"preact/jsx-runtime";const h=`<!-- @license lucide-static v0.575.0 - ISC -->
2
+ <svg
3
+ class="lucide lucide-more-horizontal"
4
+ xmlns="http://www.w3.org/2000/svg"
5
+ width="24"
6
+ height="24"
7
+ viewBox="0 0 24 24"
8
+ fill="none"
9
+ stroke="currentColor"
10
+ stroke-width="2"
11
+ stroke-linecap="round"
12
+ stroke-linejoin="round"
13
+ >
14
+ <circle cx="12" cy="12" r="1" />
15
+ <circle cx="19" cy="12" r="1" />
16
+ <circle cx="5" cy="12" r="1" />
17
+ </svg>
18
+ `;var x=Object.defineProperty,i=s((n,t)=>x(n,"name",{value:t,configurable:!0}),"s");const b=i(n=>{const[t,c]=m(u([]),"apps");f(()=>{const e=globalThis.__VISULIMA_DEVTOOLS__;if(!e)return;const a=(e.getApps()??[]).filter(d=>!["dev-toolbar:a11y","dev-toolbar:settings","dev-toolbar:timeline","dev-toolbar:more","dev-toolbar:vite-config","dev-toolbar:module-graph","dev-toolbar:seo","dev-toolbar:performance"].includes(d.id));c(a)},[]);const l=i(e=>{globalThis.__VISULIMA_DEVTOOLS__?.openApp(e).catch(console.error)},"openApp");return t.length===0?o("div",{class:"p-8 flex flex-col items-center justify-center min-h-48 gap-5 text-center select-none",children:[r("div",{class:"size-14 bg-primary/5 border border-primary/20 flex items-center justify-center",children:r("svg",{"aria-hidden":"true",class:"size-6 text-primary/40",fill:"none",stroke:"currentColor","stroke-width":"1.5",viewBox:"0 0 24 24",children:r("path",{d:"M12 6v6m0 0v6m0-6h6m-6 0H6","stroke-linecap":"round","stroke-linejoin":"round"})})}),o("div",{class:"space-y-1.5",children:[r("p",{class:"text-[0.8125rem] font-medium text-foreground/70",children:"No additional apps registered"}),r("p",{class:"text-[0.725rem] text-muted-foreground",children:"Register a custom app to see it here"}),r("pre",{class:"mt-3 text-[0.65rem] font-mono text-primary/70 bg-primary/5 border border-primary/15 px-3 py-2 text-left",children:`window.__VISULIMA_DEVTOOLS__
19
+ .registerApp({ id, name, icon })`})]})]}):o("div",{class:"p-5",children:[o("h2",{class:"text-[0.65rem] font-bold uppercase tracking-[0.1em] text-muted-foreground mb-3 flex items-center gap-1.5",children:[r("span",{"aria-hidden":"true",class:"text-primary/50",children:"//"}),"Additional Apps"]}),r("div",{class:"grid grid-cols-2 gap-2",children:t.map(e=>o("button",{class:g("flex items-center gap-3 p-3","border border-border bg-card hover:bg-foreground/4","text-left cursor-pointer transition-colors duration-150"),onClick:i(()=>l(e.id),"onClick"),title:e.name,type:"button",children:[r("span",{class:"size-5 shrink-0 flex items-center justify-center text-[0.65rem] font-bold uppercase bg-foreground/8 text-foreground/70",children:e.name.slice(0,2)}),r("span",{class:"text-[0.8125rem] font-medium text-foreground truncate",children:e.name})]},e.id))})]})},"MoreApp"),A={component:b,icon:h,id:"dev-toolbar:more",name:"More"};export{A as default};
@@ -0,0 +1,5 @@
1
+ /** @jsxImportSource preact */
2
+ import type { ComponentChildren } from "preact";
3
+ import type { AppComponentProps } from "../../types/app.d.ts";
4
+ declare const MoreApp: (_props: AppComponentProps) => ComponentChildren;
5
+ export default MoreApp;
@@ -0,0 +1,3 @@
1
+ import type { DevToolbarApp } from "../../types/app.d.ts";
2
+ declare const performanceApp: DevToolbarApp;
3
+ export default performanceApp;