Skip to content

feat(hub-ui,json-render-ui): session-scoped dock UI state across reloads - #221

Closed
antfubot wants to merge 2 commits into
mainfrom
feat/session-scoped-dock-ui-state
Closed

feat(hub-ui,json-render-ui): session-scoped dock UI state across reloads#221
antfubot wants to merge 2 commits into
mainfrom
feat/session-scoped-dock-ui-state

Conversation

@antfubot

Copy link
Copy Markdown
Collaborator

Why

Reloading the page (dev-server restart, an HMR full-reload, etc.) always dropped the embedded dock back to nothing selected, and lost the active spec tab / scroll position inside a json-render dock — annoying mid-debugging.

What changed

  • Dock selection. selectedId now lives on the same localStorage-backed panelStore as open/mode/geometry (packages/hub-ui/src/client/state/docks.ts's new HubDockPanelStorage), instead of resetting to nothing every time createDocksContext runs. A restored id that no longer resolves to a selectable entry (removed, or pointing at a group/subTabs anchor) is cleared once on boot without forcing the panel open; DockEmbedded.vue falls back to the first available entry if the panel is open with nothing selected, mirroring DockStandalone's existing boot guard.
  • json-render uncontrolled state. Tabs/Select/Switch/TextInput fall back to a local, uncontrolled value when a spec element has no $bindState binding — that fallback is now sessionStorage-backed via a new useUncontrolledValue composable, keyed by the current dock (a new DOCK_ENTRY_ID_KEY provide()d by JsonRenderView) plus a signature of the element's own static props. Switch/TextInput previously had no working uncontrolled fallback at all (useBoundProp's setter is a no-op without a binding) — both now get one, matching Tabs/Select.
  • Scroll position. JsonRenderView restores/persists its own scroll position per dock the same way.
  • Adds packages/hub-ui's first vitest suite (registered in the root vitest.config.ts), covering the selection restore/validation behavior via the existing createMockDocksContext story helper.

Context

Ports vitejs/devtools#527 ("session-scoped dock UI state — restore open/selected dock, tab, and scroll across reloads") by @dvcolomban, adapted to this repo's post-migration shape:

  • packages/core/src/client/inject/runtime.tspackages/hub-ui/src/client/embedded/index.ts
  • webcomponents/components/dock/DockEmbedded.vuepackages/hub-ui/src/client/components/dock/DockEmbedded.vue
  • webcomponents/state/{context,docks}.tspackages/hub-ui/src/client/state/{context,docks}.ts
  • webcomponents/components/views/ViewJsonRender.vue + its json-render Select/Switch/Tabs/TextInput + dock-entry-id/useUncontrolledValue composables → this repo's split json-render package, packages/json-render-ui/src/renderer.ts (JsonRenderView) + packages/json-render-ui/src/components/{Select,Switch,Tabs,TextInput}.ts + new packages/json-render-ui/src/composables/

Upstream's registry components receive a ctx.element carrying an id; this package's BaseComponentProps (from @json-render/vue) carries only props/children/emit/on/bindings, with no element identity — useUncontrolledValue here derives its key from a caller-supplied (kind, signature) pair (the component name + its own static props) instead.

This PR is coupled to #211 (the vitejs/devtools#525 port, mirroring the dock panel's localStorage state into shared state) via the shared panelStore/HubDockPanelStorage object — #211 is still open, so this lands the selectedId field first; #211 will need to cover the merged shape when it lands.

Closes #213.


Created with the help of an agent.

antfubot and others added 2 commits August 14, 2026 06:00
`selectedId` used to reset to nothing every time the embedded dock
mounted. It now lives on the same localStorage-backed `panelStore` as
`open`/mode/geometry, so a dev-server restart or HMR full-reload keeps
the dock open on whatever was selected.

A restored id that no longer resolves to a selectable entry (removed,
or pointing at a group/subTabs anchor) is cleared once on boot without
forcing the panel open; `DockEmbedded` then falls back to the first
available entry if the panel is open with nothing selected, mirroring
`DockStandalone`'s existing boot guard.

Adds `packages/hub-ui`'s first vitest suite (registered in the root
`vitest.config.ts`) covering the restore/validation behavior via the
existing `createMockDocksContext` story helper.

Co-authored-by: dvcolomban <90617742+dvcolomban@users.noreply.github.com>
…osition

`Tabs`/`Select`/`Switch`/`TextInput` fall back to a local, uncontrolled
value when a spec element has no `$bindState` binding on it — that
fallback used to be lost on every reload (and, for `Switch`/`TextInput`,
didn't exist at all: an unbound `value` had no working fallback since
`useBoundProp`'s setter is a no-op without a binding). `useSessionStorage`
now backs all four, keyed by the current dock (via a new
`DOCK_ENTRY_ID_KEY` `provide()`d by `JsonRenderView`) plus a signature of
the element's own static props, so it survives a reload without bleeding
into a different element of the same kind.

`JsonRenderView` also restores/persists its own scroll position per dock,
the same way.

Context: ports vitejs/devtools#527's `sessionStorage`-keyed uncontrolled-
value and scroll restoration to this package's registry component shape
(no `ctx.element` here, so the key is a caller-supplied signature instead
of an element id).

Co-authored-by: dvcolomban <90617742+dvcolomban@users.noreply.github.com>
@netlify

netlify Bot commented Aug 14, 2026

Copy link
Copy Markdown

Deploy Preview for devfra ready!

Name Link
🔨 Latest commit 292ae3c
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a7eaf5823271200084fc3dd
😎 Deploy Preview https://deploy-preview-221--devfra.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@antfubot

Copy link
Copy Markdown
Collaborator Author

Splitting this into two independent PRs since the hub-ui and json-render-ui changes touch disjoint files:

Closing this one in favor of those.

@antfubot antfubot closed this Aug 14, 2026
@antfubot
antfubot deleted the feat/session-scoped-dock-ui-state branch August 14, 2026 06:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Port feature from vitejs/devtools#527: session-scoped dock UI state across reloads

1 participant