Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"dompurify": "catalog:frontend",
"fuse.js": "catalog:frontend",
"human-id": "catalog:inlined",
"iframe-pane": "catalog:frontend",
"tsdown": "catalog:build",
"typescript": "catalog:devtools",
"unplugin-vue": "catalog:build",
Expand All @@ -103,6 +104,7 @@
"fast-wrap-ansi": "0.2.0",
"fuse.js": "7.3.0",
"get-port-please": "3.2.0",
"iframe-pane": "1.1.0",
"sisteransi": "1.0.5",
"zod": "4.3.6"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script setup lang="ts">
import type { DocksContext } from '@vitejs/devtools-kit/client'
import type { CSSProperties } from 'vue'
import { computed, h, markRaw, useTemplateRef } from 'vue'
import { computed, h, useTemplateRef } from 'vue'
import { getEntryGroup } from '../../state/dock-settings'
import { setEdgePositionDropdown, setFloatingTooltip, useEdgePositionDropdown } from '../../state/floating-tooltip'
import { PersistedDomViewsManager } from '../../utils/PersistedDomViewsManager'
import { useIframePanes } from '../../utils/useIframePanes'
import ViewEntry from '../views/ViewEntry.vue'
import DockEntriesWithCategories from './DockEntriesWithCategories.vue'
import DockGroupSidebar from './DockGroupSidebar.vue'
Expand All @@ -18,7 +18,7 @@ const context = props.context
const store = context.panel.store

const viewsContainer = useTemplateRef<HTMLElement>('viewsContainer')
const persistedDoms = markRaw(new PersistedDomViewsManager(viewsContainer))
const panes = useIframePanes(viewsContainer, context.panel)

const isVertical = computed(() => store.position === 'left' || store.position === 'right')

Expand Down Expand Up @@ -264,11 +264,11 @@ const contentClass = computed(() => {
/>
<div class="relative flex-1 min-w-0 h-full">
<ViewEntry
v-if="hasPanelContent && viewsContainer && selectedEntry"
v-if="hasPanelContent && panes && selectedEntry"
:key="selectedEntry.id"
:context
:entry="selectedEntry"
:persisted-doms="persistedDoms"
:panes="panes"
/>
<div
id="vite-devtools-views-container"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import type { DevToolsDockEntry } from '@vitejs/devtools-kit'
import type { DocksContext } from '@vitejs/devtools-kit/client'
import type { CSSProperties } from 'vue'
import { useElementBounding, useWindowSize } from '@vueuse/core'
import { computed, markRaw, onMounted, reactive, ref, toRefs, useTemplateRef } from 'vue'
import { computed, onMounted, reactive, ref, toRefs, useTemplateRef } from 'vue'
import { getEntryGroup } from '../../state/dock-settings'
import { PersistedDomViewsManager } from '../../utils/PersistedDomViewsManager'
import { useIframePanes } from '../../utils/useIframePanes'
import ViewEntry from '../views/ViewEntry.vue'
import { openDockContextMenu } from './DockContextMenu'
import DockGroupSidebar from './DockGroupSidebar.vue'
Expand All @@ -30,7 +30,7 @@ const mousePosition = reactive({ x: 0, y: 0 })

const dockPanel = useTemplateRef<HTMLDivElement>('dockPanel')
const viewsContainer = useTemplateRef<HTMLElement>('viewsContainer')
const persistedDoms = markRaw(new PersistedDomViewsManager(viewsContainer))
const panes = useIframePanes(viewsContainer, context.panel)

function clamp(value: number, min: number, max: number) {
return Math.min(Math.max(value, min), max)
Expand Down Expand Up @@ -198,11 +198,11 @@ onMounted(() => {
/>
<div class="relative flex-1 min-w-0 h-full">
<ViewEntry
v-if="selected && viewsContainer"
v-if="selected && panes"
:key="selected.id"
:context
:entry="selected"
:persisted-doms="persistedDoms"
:panes="panes"
:iframe-style="{
border: 'none',
borderRadius: '0.5rem',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script setup lang="ts">
import type { DocksContext } from '@vitejs/devtools-kit/client'
import { computed, markRaw, ref, useTemplateRef, watch } from 'vue'
import { computed, ref, useTemplateRef, watch } from 'vue'
import { getEntryGroup } from '../../state/dock-settings'
import { PersistedDomViewsManager } from '../../utils/PersistedDomViewsManager'
import { useIframePanes } from '../../utils/useIframePanes'
import CommandPalette from '../command-palette/CommandPalette.vue'
import Confirm from '../display/Confirm.vue'
import ToastOverlay from '../display/ToastOverlay.vue'
Expand All @@ -19,7 +19,7 @@ const props = defineProps<{

const context = props.context
const viewsContainer = useTemplateRef<HTMLElement>('viewsContainer')
const persistedDoms = markRaw(new PersistedDomViewsManager(viewsContainer))
const panes = useIframePanes(viewsContainer, context.panel)

const isRpcTrusted = ref(context.rpc.isTrusted)
context.rpc.events.on('rpc:is-trusted:updated', (isTrusted) => {
Expand Down Expand Up @@ -80,11 +80,11 @@ function switchEntry(id: string | undefined) {
<div class="relative flex-1 min-w-0 min-h-0">
<div id="vite-devtools-views-container" ref="viewsContainer" class="pointer-events-auto" />
<ViewEntry
v-if="context.docks.selected && viewsContainer"
v-if="context.docks.selected && panes"
:key="context.docks.selected.id"
:entry="context.docks.selected"
:context
:persisted-doms="persistedDoms"
:panes="panes"
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,55 +1,35 @@
<script setup lang="ts">
import type { DevToolsViewCustomRender } from '@vitejs/devtools-kit'
import type { DocksContext } from '@vitejs/devtools-kit/client'
import type { IframePanes } from 'iframe-pane'
import type { CSSProperties } from 'vue'
import type { PersistedDomViewsManager } from '../../utils/PersistedDomViewsManager'
import { nextTick, onMounted, onUnmounted, ref, useTemplateRef, watch, watchEffect } from 'vue'
import { onMounted, onUnmounted, useTemplateRef } from 'vue'

const props = defineProps<{
context: DocksContext
entry: DevToolsViewCustomRender
persistedDoms: PersistedDomViewsManager
panes: IframePanes
divStyle?: CSSProperties
}>()

const isLoading = ref(true)
const viewFrame = useTemplateRef<HTMLDivElement>('viewFrame')

onMounted(() => {
const holder = props.persistedDoms.getOrCreateHolder(props.entry.id, 'div')
holder.element.style.boxShadow = 'none'
holder.element.style.outline = 'none'
Object.assign(holder.element.style, props.divStyle)
const pane = props.panes.ensure(props.entry.id, { tagName: 'div' })
const el = pane.element
el.style.boxShadow = 'none'
el.style.outline = 'none'
Object.assign(el.style, props.divStyle)

const entryState = props.context.docks.getStateById(props.entry.id)
if (entryState)
entryState.domElements.panel = holder.element
entryState.domElements.panel = el

holder.mount(viewFrame.value!)
isLoading.value = false
nextTick(() => {
holder.update()
})

watch(
() => props.context.panel,
() => {
holder.update()
},
{ deep: true },
)

watchEffect(
() => {
holder.element.style.pointerEvents = (props.context.panel.isDragging || props.context.panel.isResizing) ? 'none' : 'auto'
},
{ flush: 'sync' },
)
pane.mount(viewFrame.value!)
})

onUnmounted(() => {
const holder = props.persistedDoms.getHolder(props.entry.id, 'div')
holder?.unmount()
props.panes.get(props.entry.id)?.unmount()
})
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script setup lang="ts">
import type { DevToolsDockEntry } from '@vitejs/devtools-kit'
import type { DocksContext } from '@vitejs/devtools-kit/client'
import type { IframePanes } from 'iframe-pane'
import type { CSSProperties } from 'vue'
import type { PersistedDomViewsManager } from '../../utils/PersistedDomViewsManager'
import { defineAsyncComponent } from 'vue'
import ViewBuiltinClientAuthNotice from '../views-builtin/ViewBuiltinClientAuthNotice.vue'
import ViewBuiltinSettings from '../views-builtin/ViewBuiltinSettings.vue'
Expand All @@ -13,7 +13,7 @@ import ViewLauncher from './ViewLauncher.vue'
defineProps<{
context: DocksContext
entry: DevToolsDockEntry
persistedDoms: PersistedDomViewsManager
panes: IframePanes
iframeStyle?: CSSProperties
divStyle?: CSSProperties
}>()
Expand Down Expand Up @@ -59,14 +59,14 @@ const ViewJsonRender = defineAsyncComponent(() => import('./ViewJsonRender.vue')
v-else-if="entry.type === 'iframe'"
:context
:entry
:persisted-doms="persistedDoms"
:panes="panes"
:iframe-style="iframeStyle"
/>
<ViewCustomRenderer
v-else-if="entry.type === 'custom-render'"
:context
:entry
:persisted-doms="persistedDoms"
:panes="panes"
:div-style="divStyle"
/>
<ViewLauncher
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<script setup lang="ts">
import type { DevToolsViewIframe } from '@vitejs/devtools-kit'
import type { DocksContext } from '@vitejs/devtools-kit/client'
import type { IframePanes } from 'iframe-pane'
import type { CSSProperties } from 'vue'
import type { PersistedDomViewsManager } from '../../utils/PersistedDomViewsManager'
import { REMOTE_CONNECTION_KEY } from '@vitejs/devtools-kit/constants'
import { computed, nextTick, onMounted, onUnmounted, ref, useTemplateRef, watch, watchEffect } from 'vue'
import { computed, nextTick, onMounted, onUnmounted, ref, useTemplateRef, watchEffect } from 'vue'
import { sharedStateToRef } from '../../state/docks'

const props = defineProps<{
context: DocksContext
entry: DevToolsViewIframe
persistedDoms: PersistedDomViewsManager
panes: IframePanes
iframeStyle?: CSSProperties
}>()

Expand Down Expand Up @@ -58,7 +58,7 @@ const editingUrl = ref(props.entry.url)
const isEditing = ref(false)

const iframeElement = computed(() => {
return props.persistedDoms.getHolder(props.entry.id, 'iframe')?.element
return props.panes.get(props.entry.id)?.iframe
})

// Get current page's origin for comparison
Expand Down Expand Up @@ -183,72 +183,63 @@ function refresh() {
iframe.src = src
}

let onIframeLoad: (() => void) | undefined

onMounted(() => {
if (props.persistedDoms.getHolder(props.entry.id, 'iframe')) {
updateCurrentUrl()
}
const holder = props.persistedDoms.getOrCreateHolder(props.entry.id, 'iframe')
holder.element.style.boxShadow = 'none'
holder.element.style.outline = 'none'
const existed = props.panes.has(props.entry.id)
// `src` is only assigned when the pane is first created, so re-mounting an
// existing iframe (tab switch) preserves its navigation/scroll/JS state.
const pane = props.panes.ensure(props.entry.id, {
src: props.entry.url,
style: { boxShadow: 'none', outline: 'none' },
})
const iframe = pane.iframe

if (!holder.element.src)
holder.element.src = props.entry.url
if (existed)
updateCurrentUrl()

// Listen for iframe load events
holder.element.addEventListener('load', () => {
onIframeLoad = () => {
isIframeLoading.value = false
updateCurrentUrl()
})
}
iframe.addEventListener('load', onIframeLoad)

const entryState = props.context.docks.getStateById(props.entry.id)
if (entryState)
entryState.domElements.iframe = holder.element
entryState.domElements.iframe = iframe

// iframe-pane positions the iframe exactly over the mount target (the view
// frame below the address bar), so no manual offset is needed — only the
// cosmetic borders differ between edge/float and address-bar states.
watchEffect(() => {
Object.assign(holder.element.style, props.iframeStyle)
if (showAddressBar.value) {
holder.element.style.marginTop = `${ADDRESS_BAR_HEIGHT}px`
if (!isEdgeMode.value) {
holder.element.style.borderTopLeftRadius = '0px'
holder.element.style.borderTopRightRadius = '0px'
}
Object.assign(iframe.style, props.iframeStyle)
if (showAddressBar.value && !isEdgeMode.value) {
iframe.style.borderTopLeftRadius = '0px'
iframe.style.borderTopRightRadius = '0px'
}
else {
holder.element.style.marginTop = '0px'
holder.element.style.borderTopLeftRadius = ''
holder.element.style.borderTopRightRadius = ''
iframe.style.borderTopLeftRadius = ''
iframe.style.borderTopRightRadius = ''
}
if (isEdgeMode.value) {
holder.element.style.borderRadius = '0px'
holder.element.style.border = 'none'
iframe.style.borderRadius = '0px'
iframe.style.border = 'none'
}
})

watch(
() => props.context.panel,
() => {
holder.update()
},
{ deep: true },
)

watchEffect(
() => {
holder.element.style.pointerEvents = (props.context.panel.isDragging || props.context.panel.isResizing) ? 'none' : 'auto'
},
{ flush: 'sync' },
)

holder.mount(viewFrame.value!)
pane.mount(viewFrame.value!)
isLoading.value = false
nextTick(() => {
holder.update()
pane.update()
})
})

onUnmounted(() => {
const holder = props.persistedDoms.getHolder(props.entry.id, 'iframe')
holder?.unmount()
const pane = props.panes.get(props.entry.id)
if (pane && onIframeLoad)
pane.iframe?.removeEventListener('load', onIframeLoad)
pane?.unmount()
})
</script>

Expand Down
1 change: 0 additions & 1 deletion packages/core/src/client/webcomponents/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './components/DockEmbedded'
export * from './components/DockStandalone'
export * from './state/docks'
export * from './utils/PersistedDomViewsManager'
Loading
Loading