Skip to content

Commit e5e585e

Browse files
feat: respect preferred-reduce-motion (#744)
1 parent a9c56bd commit e5e585e

File tree

9 files changed

+56
-6
lines changed

9 files changed

+56
-6
lines changed

packages/client/src/App.vue

+6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ onRpcConnected(() => {
3030
minimizePanelInteractive: devtoolsClientState.value.minimizePanelInteractive,
3131
closeOnOutsideClick: devtoolsClientState.value.interactionCloseOnOutsideClick,
3232
showFloatingPanel: devtoolsClientState.value.showPanel,
33+
reduceMotion: devtoolsClientState.value.reduceMotion,
3334
})
3435
})
3536
})
@@ -125,6 +126,11 @@ function toggleDevToolsClientVisible(params: { visible: boolean, host: string })
125126
[host]: visible,
126127
})
127128
}
129+
130+
watchEffect(() => {
131+
const html = document.documentElement
132+
html.classList.toggle('reduce-motion', devtoolsClientState.value.reduceMotion)
133+
})
128134
</script>
129135

130136
<template>

packages/client/src/assets/styles/main.css

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ html {
88
scrollbar-width: none; /* Firefox */
99
}
1010

11+
html.reduce-motion,
12+
html.reduce-motion * {
13+
transition: none !important;
14+
animation: none !important;
15+
}
16+
1117
html.dark {
1218
color-scheme: dark;
1319
}

packages/client/src/components/common/DockingPanel.vue

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const splitScreenEnabled = computed({
1313
get: () => devtoolsClientState.value.splitScreen.enabled,
1414
set: v => (devtoolsClientState.value.splitScreen.enabled = v),
1515
})
16+
const reduceMotion = computed(() => devtoolsClientState.value.reduceMotion)
1617
1718
function refreshPage() {
1819
location.reload()
@@ -46,7 +47,7 @@ function toggleApp(id: string) {
4647
<template>
4748
<div>
4849
<div px3 py2 border="b base" flex="~ gap-2">
49-
<VueDarkToggle>
50+
<VueDarkToggle :animation="!reduceMotion">
5051
<template #default="{ isDark, toggle }">
5152
<VueButton outlined type="primary" @click="toggle">
5253
<div i-carbon-sun dark:i-carbon-moon translate-y--1px /> {{ isDark ? 'Dark' : 'Light' }}

packages/client/src/composables/state.ts

+8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ interface DevtoolsClientState {
1818
interactionCloseOnOutsideClick: boolean
1919
showPanel: boolean
2020
minimizePanelInteractive: number
21+
reduceMotion: boolean
2122
}
2223

2324
function clientStateFactory(): DevtoolsClientState {
@@ -45,6 +46,7 @@ function clientStateFactory(): DevtoolsClientState {
4546
interactionCloseOnOutsideClick: false,
4647
showPanel: true,
4748
minimizePanelInteractive: 5000,
49+
reduceMotion: false,
4850
}
4951
}
5052

@@ -66,3 +68,9 @@ watch(() => devtoolsClientState.value.splitScreen.enabled, (enabled, o) => {
6668
}
6769
})
6870
// #endregion
71+
72+
const preferredMotion = usePreferredReducedMotion()
73+
74+
watch(preferredMotion, (value) => {
75+
devtoolsClientState.value.reduceMotion = value === 'reduce'
76+
}, { immediate: true })

packages/client/src/pages/graph.vue

+19-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ onViteRpcConnected(() => {
2020
2121
const container = ref<HTMLDivElement>()
2222
const networkRef = shallowRef<Network>()
23+
const showStabilizingModal = ref(false)
2324
2425
function mountNetwork() {
2526
const node = container.value!
@@ -35,6 +36,14 @@ function mountNetwork() {
3536
toggleGraphDrawer(true)
3637
})
3738
39+
network.on('startStabilizing', () => {
40+
if (devtoolsClientState.value.reduceMotion)
41+
showStabilizingModal.value = true
42+
})
43+
network.on('stabilized', () => {
44+
showStabilizingModal.value = false
45+
})
46+
3847
network.on('deselectNode', () => {
3948
toggleGraphDrawer(false)
4049
})
@@ -61,8 +70,15 @@ const navbarRef = ref<HTMLElement>()
6170
<template>
6271
<div flex="~ col" relative h-full of-hidden panel-grids class="graph-body">
6372
<GraphNavbar ref="navbarRef" />
64-
<div ref="container" class="absolute h-full w-full" />
65-
<GraphFileType />
66-
<GraphDrawer :top="navbarRef" />
73+
<div class="relative flex-1">
74+
<div ref="container" class="absolute inset-0" />
75+
<div v-if="showStabilizingModal" class="absolute inset-0 flex select-none items-center justify-center bg-base text-base">
76+
<div class="flex items-center space-x-2">
77+
<span>Stabilizing...</span>
78+
</div>
79+
</div>
80+
<GraphFileType />
81+
<GraphDrawer :top="navbarRef" />
82+
</div>
6783
</div>
6884
</template>

packages/client/src/pages/settings.vue

+2-2
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 } = toRefs(toReactive(devtoolsClientState))
19+
const { scale, interactionCloseOnOutsideClick, showPanel, minimizePanelInteractive, expandSidebar, scrollableSidebar, reduceMotion } = toRefs(toReactive(devtoolsClientState))
2020
2121
// #region settings
2222
const scaleOptions = [
@@ -163,7 +163,7 @@ const minimizePanelInteractiveLabel = computed(() => {
163163
</h3>
164164
<VueCard p4 flex="~ col gap-2">
165165
<div flex="~ gap2">
166-
<VueDarkToggle v-slot="{ isDark, toggle }">
166+
<VueDarkToggle v-slot="{ isDark, toggle }" :animation="!reduceMotion">
167167
<VueButton outlined type="primary" @click="toggle">
168168
<div i-carbon-sun dark:i-carbon-moon translate-y--1px /> {{ isDark ? 'Dark' : 'Light' }}
169169
</VueButton>

packages/overlay/src/App.vue

+10
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ const { iframe, getIframe } = useIframe(clientUrl, async () => {
103103
'vue-devtools__anchor--vertical': isVertical,
104104
'vue-devtools__anchor--hide': isHidden,
105105
'fullscreen': panelState.viewMode === 'fullscreen',
106+
'reduce-motion': state.reduceMotion,
106107
}" @mousemove="bringUp"
107108
>
108109
<div
@@ -162,6 +163,15 @@ const { iframe, getIframe } = useIframe(clientUrl, async () => {
162163
transform-origin: center center;
163164
transform: translate(-50%, -50%) rotate(0);
164165
166+
&.reduce-motion {
167+
transition: none !important;
168+
animation: none !important;
169+
* {
170+
transition: none !important;
171+
animation: none !important;
172+
}
173+
}
174+
165175
&.fullscreen {
166176
transform: none !important;
167177
left: 0 !important;

packages/overlay/src/components/FrameBox.vue

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ onRpcSeverReady(() => {
3232
minimizePanelInactive: v.minimizePanelInteractive,
3333
closeOnOutsideClick: v.closeOnOutsideClick,
3434
preferShowFloatingPanel: v.showFloatingPanel,
35+
reduceMotion: v.reduceMotion,
3536
})
3637
}
3738
})

packages/overlay/src/composables/state.ts

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ interface DevToolsFrameState {
1414
closeOnOutsideClick: boolean
1515
minimizePanelInactive: number
1616
preferShowFloatingPanel: boolean
17+
reduceMotion: boolean
1718
}
1819

1920
export interface UseFrameStateReturn {
@@ -33,6 +34,7 @@ const state = useLocalStorage<DevToolsFrameState>('__vue-devtools-frame-state__'
3334
closeOnOutsideClick: false,
3435
minimizePanelInactive: 5000,
3536
preferShowFloatingPanel: true,
37+
reduceMotion: false,
3638
})
3739

3840
export function useFrameState(): UseFrameStateReturn {

0 commit comments

Comments
 (0)