Skip to content

Commit

Permalink
feat(browser): add browser iframe mouse interaction (#5815)
Browse files Browse the repository at this point in the history
  • Loading branch information
userquin authored Jun 2, 2024
1 parent f9d9b3b commit f29b9d4
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 22 deletions.
3 changes: 1 addition & 2 deletions packages/browser/src/client/orchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ function createIframe(container: HTMLDivElement, file: string) {

iframe.style.display = 'block'
iframe.style.border = 'none'
iframe.style.pointerEvents = 'none'
iframe.setAttribute('allowfullscreen', 'true')
iframe.setAttribute('allow', 'clipboard-write;')

Expand Down Expand Up @@ -187,7 +186,7 @@ async function createTesters(testFiles: string[]) {
const container = await getContainer(config)

if (config.browser.ui) {
container.className = ''
container.className = 'scrolls'
container.textContent = ''
}

Expand Down
6 changes: 5 additions & 1 deletion packages/ui/client/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,22 @@ declare global {
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const provide: typeof import('vue')['provide']
const provideLocal: typeof import('@vueuse/core')['provideLocal']
const provideResizing: typeof import('./composables/browser')['provideResizing']
const reactify: typeof import('@vueuse/core')['reactify']
const reactifyObject: typeof import('@vueuse/core')['reactifyObject']
const reactive: typeof import('vue')['reactive']
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
const reactivePick: typeof import('@vueuse/core')['reactivePick']
const readonly: typeof import('vue')['readonly']
const recalculateDetailPanels: typeof import('./composables/navigation')['recalculateDetailPanels']
const recalculateDetailPanels: typeof import('./composables/browser')['recalculateDetailPanels']
const ref: typeof import('vue')['ref']
const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
const refDebounced: typeof import('@vueuse/core')['refDebounced']
const refDefault: typeof import('@vueuse/core')['refDefault']
const refThrottled: typeof import('@vueuse/core')['refThrottled']
const refWithControl: typeof import('@vueuse/core')['refWithControl']
const registerResizingListener: typeof import('./composables/browser')['registerResizingListener']
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveRef: typeof import('@vueuse/core')['resolveRef']
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
Expand Down Expand Up @@ -239,6 +241,7 @@ declare global {
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
const useNetwork: typeof import('@vueuse/core')['useNetwork']
const useNotifyResizing: typeof import('./composables/browser')['useNotifyResizing']
const useNow: typeof import('@vueuse/core')['useNow']
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']
Expand All @@ -260,6 +263,7 @@ declare global {
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
const useResizing: typeof import('./composables/browser')['useResizing']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
Expand Down
20 changes: 13 additions & 7 deletions packages/ui/client/components/BrowserIframe.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
<script setup lang="ts">
const viewport = ref('custom')
import { recalculateDetailPanels } from '~/composables/navigation'
import { useResizing } from '~/composables/browser'
const sizes = {
type ViewportSize = 'small-mobile' | 'large-mobile' | 'tablet' | 'custom'
const sizes: Record<ViewportSize, [width: string, height: string]> = {
'small-mobile': ['320px', '568px'],
'large-mobile': ['414px', '896px'],
tablet: ['834px', '1112px'],
custom: ['100%', '100%'],
}
async function changeViewport(name: string) {
const testerRef = ref<HTMLDivElement | undefined>()
const viewport = ref<ViewportSize>('custom')
const { recalculateDetailPanels } = useResizing(testerRef)
async function changeViewport(name: ViewportSize) {
if (viewport.value === name) {
viewport.value = 'custom'
} else {
viewport.value = name
}
const iframe = document.querySelector('#tester-ui iframe[data-vitest]')
const iframe = document.querySelector<HTMLIFrameElement>('#tester-ui iframe[data-vitest]')
if (!iframe) {
console.warn('Iframe not found')
return
Expand Down Expand Up @@ -84,8 +90,8 @@ async function changeViewport(name: string) {
@click="changeViewport('tablet')"
/>
</div>
<div flex-auto overflow-auto>
<div id="tester-ui" class="flex h-full justify-center items-center font-light op70" style="overflow: auto; width: 100%; height: 100%">
<div flex-auto class="scrolls">
<div id="tester-ui" ref="testerRef" class="flex h-full justify-center items-center font-light op70" style="overflow: auto; width: 100%; height: 100%">
Select a test to run
</div>
</div>
Expand Down
45 changes: 45 additions & 0 deletions packages/ui/client/composables/browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Ref } from 'vue'
import { detailSizes } from '~/composables/navigation'

type ResizingListener = (isResizing: boolean) => void

const resizingListeners = new Set<ResizingListener>()

export function recalculateDetailPanels() {
const iframe = document.querySelector('#tester-ui iframe[data-vitest]')!
const panel = document.querySelector('#details-splitpanes')!
const panelWidth = panel.clientWidth
const iframeWidth = iframe.clientWidth
const iframePercent = Math.min((iframeWidth / panelWidth) * 100, 95)
const detailsPercent = 100 - iframePercent
detailSizes.value = [iframePercent, detailsPercent]
}

export function useResizing(testerRef: Ref<HTMLDivElement | undefined>) {
function onResizing(isResizing: boolean) {
const tester = testerRef.value
if (!tester)
return

tester.style.pointerEvents = isResizing ? 'none' : ''
}

onMounted(() => {
resizingListeners.add(onResizing)
})

onUnmounted(() => {
resizingListeners.delete(onResizing)
})

return { recalculateDetailPanels }
}

export function useNotifyResizing() {
function notifyResizing(isResizing: boolean) {
for (const listener of resizingListeners)
listener(isResizing)
}

return { notifyResizing }
}
10 changes: 0 additions & 10 deletions packages/ui/client/composables/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,6 @@ export const detailSizes = useLocalStorage<[left: number, right: number]>('vites
initOnMounted: true,
})

export function recalculateDetailPanels() {
const iframe = document.querySelector('#tester-ui iframe[data-vitest]')!
const panel = document.querySelector('#details-splitpanes')!
const panelWidth = panel.clientWidth
const iframeWidth = iframe.clientWidth
const iframePercent = Math.min((iframeWidth / panelWidth) * 100, 95)
const detailsPercent = 100 - iframePercent
detailSizes.value = [iframePercent, detailsPercent]
}

// @ts-expect-error not typed global
window.__vitest_ui_api__ = {
get currentModule() {
Expand Down
8 changes: 6 additions & 2 deletions packages/ui/client/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
// @ts-expect-error missing types
import { Pane, Splitpanes } from 'splitpanes'
import { browserState } from '~/composables/client';
import { coverageUrl, coverageVisible, initializeNavigation, detailSizes } from '../composables/navigation'
import { coverageUrl, coverageVisible, initializeNavigation, detailSizes } from '~/composables/navigation'
import { useNotifyResizing } from '~/composables/browser'
const { notifyResizing } = useNotifyResizing()
const dashboardVisible = initializeNavigation()
const mainSizes = useLocalStorage<[left: number, right: number]>('vitest-ui_splitpanes-mainSizes', [33, 67], {
initOnMounted: true,
})
Expand All @@ -18,6 +21,7 @@ const onModuleResized = useDebounceFn((event: { size: number }[]) => {
event.forEach((e, i) => {
detailSizes.value[i] = e.size
})
notifyResizing(false)
}, 0)
function resizeMain() {
Expand All @@ -41,7 +45,7 @@ function resizeMain() {
<Coverage v-else-if="coverageVisible" key="coverage" :src="coverageUrl" />
<FileDetails v-else />
</transition>
<Splitpanes v-else key="detail" id="details-splitpanes" @resized="onModuleResized">
<Splitpanes v-else key="detail" id="details-splitpanes" @resize="notifyResizing(true)" @resized="onModuleResized">
<Pane :size="detailSizes[0]">
<BrowserIframe v-once />
</Pane>
Expand Down

0 comments on commit f29b9d4

Please sign in to comment.