diff --git a/src/client/auto-imports.d.ts b/src/client/auto-imports.d.ts index 9300ff67..9a84597e 100644 --- a/src/client/auto-imports.d.ts +++ b/src/client/auto-imports.d.ts @@ -1,6 +1,7 @@ /* eslint-disable */ /* prettier-ignore */ // @ts-nocheck +// noinspection JSUnusedGlobalSymbols // Generated by unplugin-auto-import export {} declare global { @@ -98,8 +99,12 @@ declare global { const resolveComponent: typeof import('vue')['resolveComponent'] const resolveRef: typeof import('@vueuse/core')['resolveRef'] const resolveUnref: typeof import('@vueuse/core')['resolveUnref'] + const scrollToComponent: typeof import('./composables/component')['scrollToComponent'] const selected: typeof import('./composables/component')['selected'] const selectedComponent: typeof import('./composables/component')['selectedComponent'] + const selectedComponentName: typeof import('./composables/component')['selectedComponentName'] + const selectedComponentNode: typeof import('./composables/component')['selectedComponentNode'] + const selectedComponentNodeFilePath: typeof import('./composables/component')['selectedComponentNodeFilePath'] const selectedComponentState: typeof import('./composables/component')['selectedComponentState'] const shallowReactive: typeof import('vue')['shallowReactive'] const shallowReadonly: typeof import('vue')['shallowReadonly'] diff --git a/src/client/components/ComponentTreeNode.vue b/src/client/components/ComponentTreeNode.vue index 4ba687cd..c04d349b 100644 --- a/src/client/components/ComponentTreeNode.vue +++ b/src/client/components/ComponentTreeNode.vue @@ -17,7 +17,7 @@ const { highlight, unhighlight } = useHighlightComponent(props.data) }" vue-block :class="[isSelected ? 'vue-block-active' : 'vue-block-hover']" - @click="select(data.id)" + @click="select(data)" @mouseover="highlight" @mouseleave="unhighlight" > diff --git a/src/client/composables/component.ts b/src/client/composables/component.ts index 756fbcf0..d04c2612 100644 --- a/src/client/composables/component.ts +++ b/src/client/composables/component.ts @@ -1,19 +1,25 @@ import type { ComponentInternalInstance } from 'vue' -import { InstanceMap, getInstanceName, getInstanceOrVnodeRect } from '../logic/components' +import { InstanceMap, getInstanceDetails, getInstanceName, getInstanceOrVnodeRect, getRootElementsFromComponentInstance } from '../logic/components' import { useDevtoolsClient } from '../logic/client' export const selected = ref('vue-devtools:root') +export const selectedComponentName = ref('') +export const selectedComponentNode = ref() +export const selectedComponentNodeFilePath = computed(() => getInstanceDetails(selectedComponentNode.value?.instance)?.file) const expandedMap = ref>({ 'vue-devtools:root': true, }) + export const selectedComponent = ref() export const selectedComponentState = shallowRef[]>([]) export function useComponent(instance: ComponentTreeNode & { instance?: ComponentInternalInstance }) { - function select(id: string) { - selected.value = id + function select(data: ComponentTreeNode) { + selected.value = data.id + selectedComponentName.value = data.name // TODO (Refactor): get instance state way - selectedComponentState.value = InstanceMap.get(id) + selectedComponentState.value = InstanceMap.get(data.id) + selectedComponentNode.value = data // selectedComponent.value = instance.instance // selectedComponentState.value = getInstanceState(instance.instance!) } @@ -48,3 +54,33 @@ export function useHighlightComponent(node: ComponentTreeNode): { unhighlight, } } + +scrollToComponent.timer = null +export function scrollToComponent() { + if (scrollToComponent.timer) + clearTimeout(scrollToComponent.timer) + + const client = useDevtoolsClient() + const { highlight, unhighlight } = useHighlightComponent(selectedComponentNode.value!) + + const instance = selectedComponentNode.value!.instance + + const [el] = getRootElementsFromComponentInstance(instance) + if (typeof el.scrollIntoView === 'function') { + el.scrollIntoView({ + behavior: 'smooth', + }) + } + else { + const _bounds = getInstanceOrVnodeRect(instance) + client.value.componentInspector.scrollToComponent(_bounds) + } + + scrollToComponent.timer = setTimeout(() => { + highlight() + scrollToComponent.timer = setTimeout(() => { + unhighlight() + scrollToComponent.timer = null + }, 1500) + }, 1200) +} diff --git a/src/client/logic/client.ts b/src/client/logic/client.ts index 381013aa..2afb42d7 100644 --- a/src/client/logic/client.ts +++ b/src/client/logic/client.ts @@ -9,6 +9,7 @@ const client = ref({ componentInspector: { highlight: () => {}, unHighlight: () => {}, + scrollToComponent: () => {}, }, }) diff --git a/src/client/logic/components/data.ts b/src/client/logic/components/data.ts index 666218f7..e16590ac 100644 --- a/src/client/logic/components/data.ts +++ b/src/client/logic/components/data.ts @@ -63,7 +63,7 @@ export function getInstanceDetails(instance: any): any { return { id: getUniqueComponentId(instance), name: getInstanceName(instance), - file: instance.type?.__file, + file: instance?.type?.__file, state: getInstanceState(instance), } } diff --git a/src/client/logic/components/index.ts b/src/client/logic/components/index.ts index 39f363bb..7b8857ba 100644 --- a/src/client/logic/components/index.ts +++ b/src/client/logic/components/index.ts @@ -1,4 +1,4 @@ export { ComponentWalker, InstanceMap } from './tree' -export { getInstanceState } from './data' -export { getInstanceOrVnodeRect } from './el' +export { getInstanceState, getInstanceDetails } from './data' +export { getInstanceOrVnodeRect, getRootElementsFromComponentInstance } from './el' export { getInstanceName } from './util' diff --git a/src/client/pages/components.vue b/src/client/pages/components.vue index 1c7c510f..adb146c5 100644 --- a/src/client/pages/components.vue +++ b/src/client/pages/components.vue @@ -2,8 +2,9 @@ import { Pane, Splitpanes } from 'splitpanes' import { ComponentWalker, getInstanceState } from '../logic/components' +import { useDevtoolsClient } from '../logic/client' import { instance, onVueInstanceUpdate } from '../logic/app' -import { selected } from '../composables/component' +import { scrollToComponent, selected, selectedComponentName, selectedComponentNode, selectedComponentNodeFilePath } from '../composables/component' const componentTree = ref([]) @@ -49,6 +50,8 @@ function init() { selectedComponentState.value = getInstanceState(instance.value!) walker.getComponentTree(instance.value!).then((res) => { componentTree.value = res + selectedComponentName.value = res?.[0]?.name ?? '' + selectedComponentNode.value = res?.[0] }) } @@ -60,6 +63,11 @@ onMounted(() => { } }) }) + +function openInEditor() { + const client = useDevtoolsClient() + client.value.openInEditor(selectedComponentNodeFilePath.value) +}