diff --git a/packages/hub-ui/src/client/dock-preferences.ts b/packages/hub-ui/src/client/dock-preferences.ts deleted file mode 100644 index b57a0ad0..00000000 --- a/packages/hub-ui/src/client/dock-preferences.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * The reference UI's dock-bar rendering preferences, set via - * `createUi({ dockPreferences })` and published as - * `ConnectionMeta.configs.ui.dockPreferences`. Read by the embedded dock and - * the standalone viewer at boot. - * - * Like the float/edge dock mode, these seed user-overridable state — the - * config sets the default, the visitor's own choice wins from then on. - */ -export interface DevframeDockPreferences { - /** - * The top-level dock-bar **category** ordering — a map of category id → - * ordering weight (lower sorts earlier), merged beneath - * `DEFAULT_CATEGORIES_ORDER`. - */ - categoryOrder?: Record - /** - * Preferred inline-item capacity for the floating dock bar before entries - * overflow. Edge mode ignores it — it shows every entry with no cutoff. - */ - maxVisibleItems?: number - /** Seeds a first-run visitor's dock mode (float vs edge). */ - defaultMode?: 'float' | 'edge' - /** Seeds a first-run visitor's dock position. */ - defaultPosition?: 'left' | 'right' | 'top' | 'bottom' -} diff --git a/packages/hub-ui/src/client/embedded/visibility.ts b/packages/hub-ui/src/client/embedded/visibility.ts index 50527854..7dd01403 100644 --- a/packages/hub-ui/src/client/embedded/visibility.ts +++ b/packages/hub-ui/src/client/embedded/visibility.ts @@ -1,24 +1,6 @@ +import type { EmbeddedVisibility } from '../../types' import { HUB_UI_HIDE_EVENT } from '../constants' -/** - * How the embedded floating dock reveals itself on a fresh page — the - * reference UI's port of Nuxt DevTools' opt-in overlay, published as - * `ConnectionMeta.configs.ui.embeddedVisibility` and set via - * `createUi({ embeddedVisibility })`. - * - * - `normal` (default) — the dock is shown immediately. - * - `passive` — the dock starts hidden and a console hint offers the reveal - * shortcut; revealing persists per-origin, so later sessions on this - * browser start shown. The "Hide" command returns to passive. - * - `hidden` — the dock starts hidden and the shortcut reveals it for the - * current session only; nothing is persisted. - * - * Whatever the policy, the reveal state is a user-overridable preference — - * the same shape as the float/edge dock mode: the config seeds it, the - * visitor's own reveal/hide wins from then on. - */ -export type EmbeddedVisibility = 'normal' | 'passive' | 'hidden' - /** Per-origin persisted reveal flag for `passive` mode. */ const REVEAL_STORAGE_KEY = 'devframes-dock-revealed' diff --git a/packages/hub-ui/src/client/state/branding.ts b/packages/hub-ui/src/client/state/branding.ts index d9c6ebcb..0467eb0c 100644 --- a/packages/hub-ui/src/client/state/branding.ts +++ b/packages/hub-ui/src/client/state/branding.ts @@ -1,40 +1,8 @@ import type { Ref } from 'vue' +import type { BrandingLogo, DevframeBranding } from '../../types' import { computed, ref } from 'vue' import { isDark } from './color-mode' -/** - * A logo asset — a single URL/data-URI, or per-color-scheme variants. The dark - * variant falls back to the light one when only `light` is given (or a bare - * string is used for both). - */ -export type BrandingLogo = string | { light: string, dark: string } - -/** - * Consumer-facing branding for the reference hub-ui. Every field is optional - * and falls back to devframe's own identity. Published as - * `ConnectionMeta.configs.ui.branding` via `createUi({ branding })`, and - * read from the one connection handshake the dock already performs — - * `ConnectionMeta` has its own cross-realm propagation (see - * `DEVFRAME_CONNECTION_KEY`), so branding needs no globals or query params - * of its own. - */ -export interface DevframeBranding { - /** Product name — the wordmark, window titles, and all user-visible copy. */ - productName?: string - /** Logo mark (URL / data-URI), rendered via ``. */ - logo?: BrandingLogo - /** Optional standalone wordmark image; when absent, mark + productName text is composed. */ - wordmark?: BrandingLogo - /** Brand color; feeds `--devframe-primary` and the whole primary ramp. */ - primaryColor?: string - /** Short line for the auth screen and the standalone meta description. */ - tagline?: string - /** Favicon URL — applied on the standalone viewer and the popped-out window only. */ - favicon?: string - /** Window/tab title; defaults to `productName`. */ - windowTitle?: string -} - /** Branding with defaults resolved — what the UI actually renders. */ export interface ResolvedBranding { productName: string diff --git a/packages/hub-ui/src/index.ts b/packages/hub-ui/src/index.ts index ba198408..4bbff3c2 100644 --- a/packages/hub-ui/src/index.ts +++ b/packages/hub-ui/src/index.ts @@ -1,14 +1,10 @@ import type { DevframeHubUi } from '@devframes/hub/initiate' -import type { DevframeDockPreferences } from './client/dock-preferences' -import type { EmbeddedVisibility } from './client/embedded/visibility' -import type { DevframeBranding } from './client/state/branding' +import type { DevframeBranding, DevframeDockPreferences, EmbeddedVisibility } from './types' import { existsSync } from 'node:fs' import { join } from 'node:path' import { fileURLToPath } from 'node:url' -export type { DevframeDockPreferences } from './client/dock-preferences' -export type { EmbeddedVisibility } from './client/embedded/visibility' -export type { DevframeBranding } from './client/state/branding' +export type { DevframeBranding, DevframeDockPreferences, EmbeddedVisibility } from './types' declare module 'devframe/types' { interface DevframeConnectionConfigsRegistry { diff --git a/packages/hub-ui/src/types.ts b/packages/hub-ui/src/types.ts new file mode 100644 index 00000000..aaf7259f --- /dev/null +++ b/packages/hub-ui/src/types.ts @@ -0,0 +1,86 @@ +/** + * Published `createUi()` config types, kept framework-free so the node + * entry's declaration rollup (`dist/index.d.mts`) never pulls in Vue's type + * surface. Client modules that need these types import them *from* here + * (never the reverse) — see `client/state/branding.ts`, + * `client/embedded/visibility.ts`. + */ + +/** + * A logo asset — a single URL/data-URI, or per-color-scheme variants. The dark + * variant falls back to the light one when only `light` is given (or a bare + * string is used for both). + */ +export type BrandingLogo = string | { light: string, dark: string } + +/** + * Consumer-facing branding for the reference hub-ui. Every field is optional + * and falls back to devframe's own identity. Published as + * `ConnectionMeta.configs.ui.branding` via `createUi({ branding })`, and + * read from the one connection handshake the dock already performs — + * `ConnectionMeta` has its own cross-realm propagation (see + * `DEVFRAME_CONNECTION_KEY`), so branding needs no globals or query params + * of its own. + */ +export interface DevframeBranding { + /** Product name — the wordmark, window titles, and all user-visible copy. */ + productName?: string + /** Logo mark (URL / data-URI), rendered via ``. */ + logo?: BrandingLogo + /** Optional standalone wordmark image; when absent, mark + productName text is composed. */ + wordmark?: BrandingLogo + /** Brand color; feeds `--devframe-primary` and the whole primary ramp. */ + primaryColor?: string + /** Short line for the auth screen and the standalone meta description. */ + tagline?: string + /** Favicon URL — applied on the standalone viewer and the popped-out window only. */ + favicon?: string + /** Window/tab title; defaults to `productName`. */ + windowTitle?: string +} + +/** + * The reference UI's dock-bar rendering preferences, set via + * `createUi({ dockPreferences })` and published as + * `ConnectionMeta.configs.ui.dockPreferences`. Read by the embedded dock and + * the standalone viewer at boot. + * + * Like the float/edge dock mode, these seed user-overridable state — the + * config sets the default, the visitor's own choice wins from then on. + */ +export interface DevframeDockPreferences { + /** + * The top-level dock-bar **category** ordering — a map of category id → + * ordering weight (lower sorts earlier), merged beneath + * `DEFAULT_CATEGORIES_ORDER`. + */ + categoryOrder?: Record + /** + * Preferred inline-item capacity for the floating dock bar before entries + * overflow. Edge mode ignores it — it shows every entry with no cutoff. + */ + maxVisibleItems?: number + /** Seeds a first-run visitor's dock mode (float vs edge). */ + defaultMode?: 'float' | 'edge' + /** Seeds a first-run visitor's dock position. */ + defaultPosition?: 'left' | 'right' | 'top' | 'bottom' +} + +/** + * How the embedded floating dock reveals itself on a fresh page — the + * reference UI's port of Nuxt DevTools' opt-in overlay, published as + * `ConnectionMeta.configs.ui.embeddedVisibility` and set via + * `createUi({ embeddedVisibility })`. + * + * - `normal` (default) — the dock is shown immediately. + * - `passive` — the dock starts hidden and a console hint offers the reveal + * shortcut; revealing persists per-origin, so later sessions on this + * browser start shown. The "Hide" command returns to passive. + * - `hidden` — the dock starts hidden and the shortcut reveals it for the + * current session only; nothing is persisted. + * + * Whatever the policy, the reveal state is a user-overridable preference — + * the same shape as the float/edge dock mode: the config seeds it, the + * visitor's own reveal/hide wins from then on. + */ +export type EmbeddedVisibility = 'normal' | 'passive' | 'hidden' diff --git a/plugins/messages/tsdown.config.ts b/plugins/messages/tsdown.config.ts index f41c21c0..13e92a44 100644 --- a/plugins/messages/tsdown.config.ts +++ b/plugins/messages/tsdown.config.ts @@ -36,6 +36,14 @@ export default defineConfig([ clean: false, platform: 'neutral', tsconfig, + // `client/index.ts` re-exports `useMessages(): Reactive` — + // a genuine Vue reactivity type, not just a documentation import. Without + // this, the dts bundler inlines Vue's entire runtime-core/reactivity type + // surface to describe `Reactive` (≈935 KB); `neverBundle` keeps the + // reference as `import('vue').Reactive<...>` instead. This build is + // `emitDtsOnly`, so it has no effect on the JS output (built separately + // by the Vite lib build for the client, and by the node build above). + deps: { neverBundle: ['vue'] }, dts: { emitDtsOnly: true }, outExtensions: () => ({ dts: '.d.mts' }), entry: { ...clientEntries, ...serverEntries },