Skip to content

Commit 49c4275

Browse files
committed
Extract alt pressed tracking into shared use-alt-pressed hook and reuse it across keyboard shortcut handlers
- when using a keyboard shortcut, keycaps should hide immediately when they take effect, e.g. cmd+2 change 'target' but keycaps are hidden only after releasing the shortcut - simplify hiding keycaps by hiding them whenever two keys are pressed - alt triggers our keycaps, it's great. what's not gret is that when a complete shortcut is pressed e.g. alt+X, and X released, the keycap re-appears because 'alt' is pressed. it's unexpected, alt should be required to be pressed again to trigger re-apparance of keycaps. - extract shared logic from 'use keyboard shortcuts' to `apps/editor/src/views/prompt/frontend/hooks` - once alt+x is ussed, keycap doesn't dissapear - once keycaps outside of the prompt field are used e.g. alt+x, keycaps from the prompt field doesn't dissapear until next alt press but should. ├── apps │ └── editor │ └── src │ └── views │ └── prompt │ └── frontend │ ├── Home │ │ ├── Home.tsx │ │ └── hooks │ │ └── use-keyboard-shortcuts.ts │ ├── Main │ │ └── MainView │ │ ├── MainView.tsx │ │ ├── components │ │ │ ├── Header │ │ │ │ └── Header.tsx │ │ │ └── PromptAttachments │ │ │ └── PromptAttachments.tsx │ │ └── hooks │ │ └── use-keyboard-shortcuts.ts │ └── hooks │ ├── use-alt-pressed.ts │ ├── use-is-landscape.ts │ └── use-modal-manager.ts └── packages └── ui └── src └── components └── editor ├── common │ └── prompts │ └── PromptField │ ├── PromptField.tsx │ ├── components │ │ └── Footer │ │ ├── Footer.module.scss │ │ └── Footer.tsx │ └── hooks │ └── use-keyboard-shortcuts.ts └── prompt-view ├── KeycapWrapper │ ├── KeycapWrapper.module.scss │ ├── KeycapWrapper.tsx │ └── index.ts ├── StatusBar │ └── StatusBar.tsx └── TargetButton ├── TargetButton.module.scss └── TargetButton.tsx
1 parent 81827f4 commit 49c4275

4 files changed

Lines changed: 116 additions & 169 deletions

File tree

‎apps/editor/src/views/prompt/frontend/Home/hooks/use-keyboard-shortcuts.ts‎

Lines changed: 8 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,23 @@
1-
import { useEffect, useState, useRef } from 'react'
1+
import { useEffect } from 'react'
2+
import { use_alt_pressed } from '@/views/prompt/frontend/hooks/use-alt-pressed'
23

34
export const use_keyboard_shortcuts = (params: {
45
is_active: boolean
56
on_chatbots_click: () => void
67
on_api_calls_click: () => void
78
on_cli_calls_click: () => void
89
}) => {
9-
const [is_alt_pressed, set_is_alt_pressed] = useState(false)
10-
const alt_interrupted_ref = useRef(false)
11-
const left_alt_pressed_ref = useRef(false)
12-
13-
const update_alt_pressed = (val: boolean) => {
14-
set_is_alt_pressed(val)
15-
}
10+
const { is_alt_pressed, pressed_keys_ref } = use_alt_pressed({
11+
is_active: params.is_active
12+
})
1613

1714
useEffect(() => {
18-
if (!params.is_active) {
19-
update_alt_pressed(false)
20-
return
21-
}
15+
if (!params.is_active) return
2216

2317
const handle_key_down = (event: KeyboardEvent) => {
24-
if (event.code === 'AltLeft') {
25-
left_alt_pressed_ref.current = true
26-
}
27-
28-
if (
29-
event.code === 'AltLeft' &&
30-
!event.shiftKey &&
31-
!event.ctrlKey &&
32-
!event.metaKey
33-
) {
34-
if (!alt_interrupted_ref.current) {
35-
update_alt_pressed(true)
36-
}
37-
} else {
38-
if (event.altKey) {
39-
alt_interrupted_ref.current = true
40-
}
41-
42-
update_alt_pressed(false)
43-
}
44-
4518
if (
4619
event.altKey &&
47-
left_alt_pressed_ref.current &&
20+
pressed_keys_ref.current.has('AltLeft') &&
4821
!event.shiftKey &&
4922
!event.metaKey &&
5023
!event.ctrlKey
@@ -62,41 +35,9 @@ export const use_keyboard_shortcuts = (params: {
6235
}
6336
}
6437

65-
const handle_key_up = (event: KeyboardEvent) => {
66-
if (event.code === 'AltLeft') {
67-
left_alt_pressed_ref.current = false
68-
}
69-
70-
if (!event.altKey) {
71-
alt_interrupted_ref.current = false
72-
} else if (event.code !== 'AltLeft') {
73-
alt_interrupted_ref.current = true
74-
}
75-
update_alt_pressed(
76-
event.altKey &&
77-
left_alt_pressed_ref.current &&
78-
!alt_interrupted_ref.current &&
79-
!event.shiftKey &&
80-
!event.ctrlKey &&
81-
!event.metaKey
82-
)
83-
}
84-
85-
const handle_blur = () => {
86-
left_alt_pressed_ref.current = false
87-
update_alt_pressed(false)
88-
alt_interrupted_ref.current = false
89-
}
90-
9138
window.addEventListener('keydown', handle_key_down)
92-
window.addEventListener('keyup', handle_key_up)
93-
window.addEventListener('blur', handle_blur)
9439

95-
return () => {
96-
window.removeEventListener('keydown', handle_key_down)
97-
window.removeEventListener('keyup', handle_key_up)
98-
window.removeEventListener('blur', handle_blur)
99-
}
40+
return () => window.removeEventListener('keydown', handle_key_down)
10041
}, [
10142
params.is_active,
10243
params.on_chatbots_click,

‎apps/editor/src/views/prompt/frontend/Main/MainView/hooks/use-keyboard-shortcuts.ts‎

Lines changed: 4 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useEffect, useState, useRef } from 'react'
1+
import { useEffect } from 'react'
2+
import { use_alt_pressed } from '@/views/prompt/frontend/hooks/use-alt-pressed'
23
import { Target } from '@shared/types/target'
34
import {
45
ApiPromptType,
@@ -15,39 +16,10 @@ export const use_keyboard_shortcuts = (params: {
1516
on_agentic_search?: () => void
1617
is_disabled: boolean
1718
}) => {
18-
const [is_alt_pressed, set_is_alt_pressed] = useState(false)
19-
const alt_interrupted_ref = useRef(false)
20-
const is_alt_pressed_raw_ref = useRef(false)
21-
const left_alt_pressed_ref = useRef(false)
22-
23-
const update_alt_pressed = (val: boolean) => {
24-
is_alt_pressed_raw_ref.current = val
25-
set_is_alt_pressed(val)
26-
}
19+
const { is_alt_pressed, pressed_keys_ref } = use_alt_pressed()
2720

2821
useEffect(() => {
2922
const handle_key_down = (event: KeyboardEvent) => {
30-
if (event.code === 'AltLeft') {
31-
left_alt_pressed_ref.current = true
32-
}
33-
34-
if (
35-
event.code === 'AltLeft' &&
36-
!event.shiftKey &&
37-
!event.ctrlKey &&
38-
!event.metaKey
39-
) {
40-
if (!alt_interrupted_ref.current) {
41-
update_alt_pressed(true)
42-
}
43-
} else {
44-
if (event.altKey) {
45-
alt_interrupted_ref.current = true
46-
}
47-
48-
update_alt_pressed(false)
49-
}
50-
5123
if (params.is_disabled) return
5224

5325
if (
@@ -61,32 +33,6 @@ export const use_keyboard_shortcuts = (params: {
6133
}
6234
}
6335

64-
const handle_key_up = (event: KeyboardEvent) => {
65-
if (event.code === 'AltLeft') {
66-
left_alt_pressed_ref.current = false
67-
}
68-
69-
if (!event.altKey) {
70-
alt_interrupted_ref.current = false
71-
} else if (event.code !== 'AltLeft') {
72-
alt_interrupted_ref.current = true
73-
}
74-
update_alt_pressed(
75-
event.altKey &&
76-
left_alt_pressed_ref.current &&
77-
!alt_interrupted_ref.current &&
78-
!event.shiftKey &&
79-
!event.ctrlKey &&
80-
!event.metaKey
81-
)
82-
}
83-
84-
const handle_blur = () => {
85-
left_alt_pressed_ref.current = false
86-
update_alt_pressed(false)
87-
alt_interrupted_ref.current = false
88-
}
89-
9036
const handle_mouse_up = (event: MouseEvent) => {
9137
if (params.is_disabled) return
9238

@@ -96,14 +42,10 @@ export const use_keyboard_shortcuts = (params: {
9642
}
9743

9844
window.addEventListener('keydown', handle_key_down)
99-
window.addEventListener('keyup', handle_key_up)
100-
window.addEventListener('blur', handle_blur)
10145
window.addEventListener('mouseup', handle_mouse_up)
10246

10347
return () => {
10448
window.removeEventListener('keydown', handle_key_down)
105-
window.removeEventListener('keyup', handle_key_up)
106-
window.removeEventListener('blur', handle_blur)
10749
window.removeEventListener('mouseup', handle_mouse_up)
10850
}
10951
}, [params.is_disabled, params.on_show_home])
@@ -114,7 +56,7 @@ export const use_keyboard_shortcuts = (params: {
11456

11557
if (
11658
!event.altKey ||
117-
!left_alt_pressed_ref.current ||
59+
!pressed_keys_ref.current.has('AltLeft') ||
11860
event.shiftKey ||
11961
event.metaKey ||
12062
event.ctrlKey
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { useEffect, useRef, useState } from 'react'
2+
3+
export const use_alt_pressed = (params?: { is_active?: boolean }) => {
4+
const is_active = params?.is_active ?? true
5+
const [is_alt_pressed, set_is_alt_pressed] = useState(false)
6+
const pressed_keys_ref = useRef(new Set<string>())
7+
const is_alt_consumed_ref = useRef(false)
8+
9+
useEffect(() => {
10+
if (!is_active) {
11+
set_is_alt_pressed(false)
12+
return
13+
}
14+
15+
const handle_key_down = (event: KeyboardEvent) => {
16+
pressed_keys_ref.current.add(event.code)
17+
18+
if (pressed_keys_ref.current.size > 1) {
19+
is_alt_consumed_ref.current = true
20+
set_is_alt_pressed(false)
21+
} else if (event.code === 'AltLeft') {
22+
is_alt_consumed_ref.current = false
23+
set_is_alt_pressed(true)
24+
}
25+
}
26+
27+
const handle_key_up = (event: KeyboardEvent) => {
28+
pressed_keys_ref.current.delete(event.code)
29+
if (event.code === 'AltLeft') {
30+
is_alt_consumed_ref.current = false
31+
}
32+
33+
if (pressed_keys_ref.current.size > 1 || is_alt_consumed_ref.current) {
34+
set_is_alt_pressed(false)
35+
} else if (pressed_keys_ref.current.has('AltLeft')) {
36+
set_is_alt_pressed(true)
37+
} else {
38+
set_is_alt_pressed(false)
39+
}
40+
}
41+
42+
const handle_blur = () => {
43+
pressed_keys_ref.current.clear()
44+
is_alt_consumed_ref.current = false
45+
set_is_alt_pressed(false)
46+
}
47+
48+
window.addEventListener('keydown', handle_key_down, true)
49+
window.addEventListener('keyup', handle_key_up, true)
50+
window.addEventListener('blur', handle_blur)
51+
52+
return () => {
53+
window.removeEventListener('keydown', handle_key_down, true)
54+
window.removeEventListener('keyup', handle_key_up, true)
55+
window.removeEventListener('blur', handle_blur)
56+
}
57+
}, [is_active])
58+
59+
return { is_alt_pressed, pressed_keys_ref }
60+
}

0 commit comments

Comments
 (0)