Skip to content

Commit 2af9d22

Browse files
committed
Added code for highlighting component boundary
1 parent e7dffa2 commit 2af9d22

File tree

8 files changed

+89
-1
lines changed

8 files changed

+89
-1
lines changed

packages/client/src/App.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ onRpcConnected(() => {
2929
rpc.value.emit('update-client-state', {
3030
minimizePanelInteractive: devtoolsClientState.value.minimizePanelInteractive,
3131
closeOnOutsideClick: devtoolsClientState.value.interactionCloseOnOutsideClick,
32+
highlightComponentTracking: devtoolsClientState.value.highlightComponentTracking,
3233
showFloatingPanel: devtoolsClientState.value.showPanel,
3334
reduceMotion: devtoolsClientState.value.reduceMotion,
3435
})

packages/client/src/composables/state.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface DevtoolsClientState {
1717
scale: number
1818
interactionCloseOnOutsideClick: boolean
1919
showPanel: boolean
20+
highlightComponentTracking: boolean
2021
minimizePanelInteractive: number
2122
reduceMotion: boolean
2223
}
@@ -45,6 +46,7 @@ function clientStateFactory(): DevtoolsClientState {
4546
scale: 1,
4647
interactionCloseOnOutsideClick: false,
4748
showPanel: true,
49+
highlightComponentTracking: false,
4850
minimizePanelInteractive: 5000,
4951
reduceMotion: false,
5052
}

packages/client/src/pages/settings.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const hostEnv = useHostEnv()
1616
*/
1717
const enableFeatureSettings = hostEnv === 'iframe' || hostEnv === 'separate-window'
1818
19-
const { scale, interactionCloseOnOutsideClick, showPanel, minimizePanelInteractive, expandSidebar, scrollableSidebar, reduceMotion } = toRefs(toReactive(devtoolsClientState))
19+
const { scale, interactionCloseOnOutsideClick, showPanel, minimizePanelInteractive, expandSidebar, scrollableSidebar, reduceMotion, highlightComponentTracking } = toRefs(toReactive(devtoolsClientState))
2020
2121
// #region settings
2222
const scaleOptions = [
@@ -210,6 +210,12 @@ const minimizePanelInteractiveLabel = computed(() => {
210210
<div>
211211
<VueSelect v-model="minimizePanelInteractive" :button-props="{ outlined: true }" :options="minimizePanelInteractiveOptions" :placeholder="minimizePanelInteractiveLabel" />
212212
</div>
213+
<div mx--2 my1 h-1px border="b base" op75 />
214+
215+
<div class="flex items-center gap2 text-sm">
216+
<VueCheckbox v-model="highlightComponentTracking" />
217+
<span op75>Highlight Component Re Rendering</span>
218+
</div>
213219
</VueCard>
214220
</template>
215221

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { ComponentHighLighterOptions, VueAppInstance } from '../../../types'
2+
import { getComponentBoundingRect } from '../component/state/bounding-rect'
3+
import { getInstanceName } from '../component/utils'
4+
5+
const CONTAINER_ELEMENT_ID = '__vue-devtools-flash__'
6+
const REMOVE_DELAY_MS = 1000
7+
8+
const containerStyles = {
9+
border: '2px rgba(65, 184, 131, 0.7) solid',
10+
position: 'fixed',
11+
zIndex: '2147483645',
12+
pointerEvents: 'none',
13+
borderRadius: '3px',
14+
boxSizing: 'border-box',
15+
transition: 'none',
16+
opacity: '1',
17+
}
18+
19+
function getStyles(bounds: ComponentHighLighterOptions['bounds']) {
20+
return {
21+
left: `${Math.round(bounds.left)}px`,
22+
top: `${Math.round(bounds.top)}px`,
23+
width: `${Math.round(bounds.width)}px`,
24+
height: `${Math.round(bounds.height)}px`,
25+
} satisfies Partial<CSSStyleDeclaration>
26+
}
27+
28+
function create(options: ComponentHighLighterOptions & { elementId?: string, style?: Partial<CSSStyleDeclaration> }) {
29+
const containerEl = document.createElement('div')
30+
containerEl.id = options?.elementId ?? CONTAINER_ELEMENT_ID
31+
32+
Object.assign(containerEl.style, {
33+
...containerStyles,
34+
...getStyles(options.bounds),
35+
...options.style,
36+
})
37+
38+
document.body.appendChild(containerEl)
39+
40+
requestAnimationFrame(() => {
41+
containerEl.style.transition = 'opacity 1s'
42+
containerEl.style.opacity = '0'
43+
})
44+
45+
clearTimeout((containerEl as any)?._timer);
46+
(containerEl as any)._timer = setTimeout(() => {
47+
document.body.removeChild(containerEl)
48+
}, REMOVE_DELAY_MS)
49+
50+
return containerEl
51+
}
52+
53+
export function flashComponent(instance: VueAppInstance) {
54+
const bounds = getComponentBoundingRect(instance)
55+
56+
if (!bounds.width && !bounds.height)
57+
return
58+
59+
const name = getInstanceName(instance)
60+
create({ bounds, name })
61+
}

packages/devtools-kit/src/core/plugin/components.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ComponentWalker } from '../../core/component/tree/walker'
66
import { getAppRecord, getComponentId, getComponentInstance } from '../../core/component/utils'
77
import { activeAppRecord, devtoolsContext, devtoolsState, DevToolsV6PluginAPIHookKeys } from '../../ctx'
88
import { hook } from '../../hook'
9+
import { flashComponent } from '../component-flash'
910
import { setupBuiltinTimelineLayers } from '../timeline'
1011
import { exposeInstanceToWindow } from '../vm'
1112

@@ -115,6 +116,10 @@ export function createComponentsDevToolsPlugin(app: App): [PluginDescriptor, Plu
115116
}
116117
}
117118

119+
if (devtoolsState.flashUpdates) {
120+
flashComponent(component)
121+
}
122+
118123
if (!appRecord)
119124
return
120125

@@ -150,6 +155,10 @@ export function createComponentsDevToolsPlugin(app: App): [PluginDescriptor, Plu
150155
}
151156
}
152157

158+
if (devtoolsState.flashUpdates) {
159+
flashComponent(component)
160+
}
161+
153162
if (!appRecord)
154163
return
155164

@@ -166,6 +175,10 @@ export function createComponentsDevToolsPlugin(app: App): [PluginDescriptor, Plu
166175
if (!app || (typeof uid !== 'number' && !uid) || !component)
167176
return
168177

178+
if (devtoolsState.flashUpdates) {
179+
flashComponent(component)
180+
}
181+
169182
const appRecord = await getAppRecord(app)
170183

171184
if (!appRecord)

packages/devtools-kit/src/ctx/state.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface DevToolsState {
1616
tabs: CustomTab[]
1717
commands: CustomCommand[]
1818
highPerfModeEnabled: boolean
19+
flashUpdates: boolean
1920
devtoolsClientDetected: {
2021
[key: string]: boolean
2122
}
@@ -40,6 +41,7 @@ function initStateFactory() {
4041
tabs: [],
4142
commands: [],
4243
highPerfModeEnabled: true,
44+
flashUpdates: true,
4345
devtoolsClientDetected: {},
4446
perfUniqueGroupId: 0,
4547
timelineLayersState: getTimelineLayersStateFromStorage(),

packages/overlay/src/components/FrameBox.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ onRpcSeverReady(() => {
3131
updateState({
3232
minimizePanelInactive: v.minimizePanelInteractive,
3333
closeOnOutsideClick: v.closeOnOutsideClick,
34+
highlightComponentTracking: v.highlightComponentTracking,
3435
preferShowFloatingPanel: v.showFloatingPanel,
3536
reduceMotion: v.reduceMotion,
3637
})

packages/overlay/src/composables/state.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ interface DevToolsFrameState {
1515
minimizePanelInactive: number
1616
preferShowFloatingPanel: boolean
1717
reduceMotion: boolean
18+
highlightComponentTracking: boolean
1819
}
1920

2021
export interface UseFrameStateReturn {
@@ -35,6 +36,7 @@ const state = useLocalStorage<DevToolsFrameState>('__vue-devtools-frame-state__'
3536
minimizePanelInactive: 5000,
3637
preferShowFloatingPanel: true,
3738
reduceMotion: false,
39+
highlightComponentTracking: false,
3840
})
3941

4042
export function useFrameState(): UseFrameStateReturn {

0 commit comments

Comments
 (0)