diff --git a/docs/guide/index.md b/docs/guide/index.md
index a04cfcc58..4546ecac4 100644
--- a/docs/guide/index.md
+++ b/docs/guide/index.md
@@ -99,7 +99,7 @@ pnpm dev
Open your app in the browser; the floating docks appear in the corner.
-The `visibility` option sets the starting mode. The default `'normal'` shows the docks immediately. `'passive'` keeps them out of the way and prints a console hint to reveal them with Shift + Alt + D (⇧ ⌥ D on macOS); revealing once is remembered in the project's `node_modules`, so later dev sessions on this machine open straight into the docks, and the "Hide DevTools" command returns to passive mode. `'hidden'` also starts hidden but never remembers — the shortcut reveals the docks for the current session only.
+The `embeddedVisibility` option sets the starting mode. The default `'normal'` shows the docks immediately. `'passive'` keeps them out of the way and prints a console hint to reveal them with Shift + Alt + D (⇧ ⌥ D on macOS); revealing once persists per-origin in the browser, so later sessions on this browser open straight into the docks, and the "Hide DevTools" command returns to passive mode. `'hidden'` also starts hidden but never remembers — the shortcut reveals the docks for the current session only.
```ts [vite.config.ts] twoslash
import { DevTools } from '@vitejs/devtools'
@@ -108,7 +108,25 @@ import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
DevTools({
- visibility: 'passive',
+ embeddedVisibility: 'passive',
+ }),
+ ],
+})
+```
+
+The `dockPreferences` option seeds the dock bar's first-run layout — category ordering, the floating dock's inline-item capacity, and the default float/edge mode and position. Each is a user-overridable preference, so the visitor's own choice wins from then on.
+
+```ts [vite.config.ts] twoslash
+import { DevTools } from '@vitejs/devtools'
+import { defineConfig } from 'vite'
+
+export default defineConfig({
+ plugins: [
+ DevTools({
+ dockPreferences: {
+ defaultMode: 'edge',
+ defaultPosition: 'bottom',
+ },
}),
],
})
diff --git a/packages/core/src/node/build-static.ts b/packages/core/src/node/build-static.ts
index fcf0c149f..737aa6650 100644
--- a/packages/core/src/node/build-static.ts
+++ b/packages/core/src/node/build-static.ts
@@ -1,6 +1,7 @@
/* eslint-disable no-console */
import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit'
+import type { ViteDevToolsUiOptions } from './ui'
import { existsSync } from 'node:fs'
import fs from 'node:fs/promises'
import { DOCK_RENDERERS_STATE_KEY } from '@devframes/hub/constants'
@@ -22,6 +23,8 @@ export interface BuildStaticOptions {
context: ViteDevToolsNodeContext
outDir: string
withApp?: boolean
+ /** Reference-UI options forwarded to `createUi`. */
+ ui?: ViteDevToolsUiOptions
}
export async function buildStaticDevTools(options: BuildStaticOptions): Promise {
@@ -36,7 +39,7 @@ export async function buildStaticDevTools(options: BuildStaticOptions): Promise<
// Bake the branded `@devframes/hub-ui` client into the snapshot: the
// standalone viewer SPA, its embedded bootstrap, and the UI-owned assets
// (e.g. `branding.json`) — the same `ui` slot the hub serves in dev.
- const ui = createViteDevToolsUi()
+ const ui = createViteDevToolsUi(options.ui)
if (ui.viewer)
await fs.cp(ui.viewer.distDir, devToolsRoot, { recursive: true })
if (ui.embedded)
diff --git a/packages/core/src/node/plugins/__tests__/injection.test.ts b/packages/core/src/node/plugins/__tests__/injection.test.ts
index d6fc97c42..2fc3125af 100644
--- a/packages/core/src/node/plugins/__tests__/injection.test.ts
+++ b/packages/core/src/node/plugins/__tests__/injection.test.ts
@@ -17,11 +17,5 @@ describe('devToolsInjection', () => {
expect(tag.injectTo).toBe('body')
expect(tag.children).toContain(`${DEVTOOLS_MOUNT_PATH}embedded.js`)
expect(tag.children).toContain('document.body.appendChild(s)')
- expect(tag.children).toContain(`s.dataset.visibility = "normal"`)
- })
-
- it('forwards the visibility hint to the embedded bootstrap', () => {
- const tag = injectedTags(DevToolsInjection({ visibility: 'passive' }))[0]!
- expect(tag.children).toContain(`s.dataset.visibility = "passive"`)
})
})
diff --git a/packages/core/src/node/plugins/build.ts b/packages/core/src/node/plugins/build.ts
index 45ca1736e..80bd851eb 100644
--- a/packages/core/src/node/plugins/build.ts
+++ b/packages/core/src/node/plugins/build.ts
@@ -2,12 +2,15 @@
import type { ViteDevToolsNodeContext } from '@vitejs/devtools-kit'
import type { Plugin, ResolvedConfig } from 'vite'
+import type { ViteDevToolsUiOptions } from '../ui'
import { colors as c } from 'devframe/utils/colors'
import { resolve } from 'pathe'
import { MARK_NODE } from '../constants'
export interface DevToolsBuildOptions {
outDir?: string
+ /** Reference-UI options forwarded to the static snapshot's `createUi`. */
+ ui?: ViteDevToolsUiOptions
}
export function DevToolsBuild(options: DevToolsBuildOptions = {}): Plugin {
@@ -35,7 +38,7 @@ export function DevToolsBuild(options: DevToolsBuildOptions = {}): Plugin {
: resolve(resolvedConfig.root, resolvedConfig.build.outDir)
const { buildStaticDevTools } = await import('../build-static')
- await buildStaticDevTools({ context, outDir, withApp: true })
+ await buildStaticDevTools({ context, outDir, withApp: true, ui: options.ui })
},
}
}
diff --git a/packages/core/src/node/plugins/index.ts b/packages/core/src/node/plugins/index.ts
index 912cfae30..0d3b4f5cf 100644
--- a/packages/core/src/node/plugins/index.ts
+++ b/packages/core/src/node/plugins/index.ts
@@ -1,5 +1,5 @@
import type { Plugin } from 'vite'
-import type { DevToolsVisibility } from './injection'
+import type { ViteDevToolsUiOptions } from '../ui'
import { DevToolsBuild } from './build'
import { DevToolsBuiltin } from './builtin'
import { DevToolsInjection } from './injection'
@@ -16,19 +16,30 @@ export interface DevToolsOptions {
builtinDevTools?: boolean
/**
- * Initial visibility of the injected overlay.
+ * How the embedded floating dock reveals itself on a fresh page.
*
* - `'normal'` — show the docks immediately.
* - `'passive'` — the floating docks stay hidden and a console hint invites
- * the developer to reveal them with a keyboard shortcut. Activating once
- * persists a flag in the project's `node_modules`, so later dev sessions on
- * this machine boot straight into normal mode.
+ * the developer to reveal them with a keyboard shortcut. Revealing once
+ * persists per-origin, so later dev sessions on this browser start shown;
+ * the "Hide DevTools" command returns to passive mode.
* - `'hidden'` — always keep the docks hidden; the shortcut reveals them for
* the current session only, without remembering the choice.
*
+ * Seeds a user-overridable preference published as
+ * `ConnectionMeta.configs.ui.embeddedVisibility`.
+ *
* @default 'normal'
*/
- visibility?: DevToolsVisibility
+ embeddedVisibility?: ViteDevToolsUiOptions['embeddedVisibility']
+
+ /**
+ * Dock-bar rendering preferences — category ordering, floating-dock
+ * inline-item capacity, and the first-run float/edge mode and position.
+ * Each seeds a user-overridable preference published as
+ * `ConnectionMeta.configs.ui.dockPreferences`.
+ */
+ dockPreferences?: ViteDevToolsUiOptions['dockPreferences']
/**
* Options for building static DevTools output alongside `vite build`.
@@ -52,16 +63,19 @@ export async function DevTools(options: DevToolsOptions = {}): Promise
const {
builtinDevTools = true,
build,
- visibility = 'normal',
+ embeddedVisibility = 'normal',
+ dockPreferences,
} = options
+ const ui = { embeddedVisibility, dockPreferences }
+
const plugins = [
- DevToolsInjection({ visibility }),
- DevToolsServer(),
+ DevToolsInjection(),
+ DevToolsServer(ui),
]
if (build?.withApp) {
- plugins.push(DevToolsBuild({ outDir: build.outDir }))
+ plugins.push(DevToolsBuild({ outDir: build.outDir, ui }))
}
plugins.unshift(
diff --git a/packages/core/src/node/plugins/injection.ts b/packages/core/src/node/plugins/injection.ts
index 81b2a55cc..165d8885f 100644
--- a/packages/core/src/node/plugins/injection.ts
+++ b/packages/core/src/node/plugins/injection.ts
@@ -1,23 +1,13 @@
import type { Plugin } from 'vite'
import { DEVTOOLS_MOUNT_PATH } from '@vitejs/devtools-kit/constants'
-export type DevToolsVisibility = 'passive' | 'normal' | 'hidden'
-
-export interface DevToolsInjectionOptions {
- /**
- * Initial visibility of the injected overlay, forwarded to the
- * `@devframes/hub-ui` embedded bootstrap as a `data-visibility` hint.
- *
- * @default 'normal'
- */
- visibility?: DevToolsVisibility
-}
-
/**
* Inject the `@devframes/hub-ui` embedded bootstrap into the host app's HTML.
* The hub serves the prebuilt, self-contained module at `embedded.js`
* (the `ui.embedded` slot); the client bundles its own framework and styles
- * and owns its visibility policy, so the host app's build never processes it.
+ * and reads its reveal policy and dock preferences from the connection meta
+ * (`ConnectionMeta.configs.ui`, seeded by `createUi`), so the host app's build
+ * never processes it.
*
* The bootstrap is loaded by an **inline** module that creates the `