88 getBlockBadgeAtom ,
99} from "@/app/store/badge" ;
1010import { ClientModel } from "@/app/store/client-model" ;
11+ import { FocusManager } from "@/app/store/focusManager" ;
1112import { GlobalModel } from "@/app/store/global-model" ;
1213import { globalStore } from "@/app/store/jotaiStore" ;
1314import { getTabModelByTabId , TabModelContext } from "@/app/store/tab-model" ;
@@ -16,7 +17,7 @@ import { makeWaveEnvImpl } from "@/app/waveenv/waveenvimpl";
1617import { Workspace } from "@/app/workspace/workspace" ;
1718import { getLayoutModelForStaticTab } from "@/layout/index" ;
1819import { ContextMenuModel } from "@/store/contextmenu" ;
19- import { atoms , createBlock , getSettingsPrefixAtom } from "@/store/global" ;
20+ import { atoms , createBlock , getSettingsPrefixAtom , refocusNode } from "@/store/global" ;
2021import { appHandleKeyDown , keyboardMouseDownHandler } from "@/store/keymodel" ;
2122import { getElemAsStr } from "@/util/focusutil" ;
2223import * as keyutil from "@/util/keyutil" ;
@@ -203,6 +204,83 @@ function AppFocusHandler() {
203204 return null ;
204205}
205206
207+ const MacOSFirstClickHandler = ( ) => {
208+ useEffect ( ( ) => {
209+ if ( PLATFORM !== "darwin" ) {
210+ return ;
211+ }
212+ let windowFocusTime : number = null ;
213+ let cancelNextClick = false ;
214+ const handleWindowFocus = ( e : FocusEvent ) => {
215+ windowFocusTime = Date . now ( ) ;
216+ } ;
217+ const getBlockIdFromTarget = ( target : EventTarget ) : string => {
218+ let elem = target as HTMLElement ;
219+ while ( elem != null ) {
220+ const blockId = elem . dataset ?. blockid ;
221+ if ( blockId ) {
222+ return blockId ;
223+ }
224+ elem = elem . parentElement ;
225+ }
226+ return null ;
227+ } ;
228+ const isAIPanelTarget = ( target : EventTarget ) : boolean => {
229+ let elem = target as HTMLElement ;
230+ while ( elem != null ) {
231+ if ( elem . dataset ?. aipanel ) {
232+ return true ;
233+ }
234+ elem = elem . parentElement ;
235+ }
236+ return false ;
237+ } ;
238+ const handleMouseDown = ( e : MouseEvent ) => {
239+ const timeDiff = Date . now ( ) - windowFocusTime ;
240+ if ( windowFocusTime != null && timeDiff < 50 ) {
241+ e . preventDefault ( ) ;
242+ e . stopPropagation ( ) ;
243+ e . stopImmediatePropagation ( ) ;
244+ cancelNextClick = true ;
245+ const blockId = getBlockIdFromTarget ( e . target ) ;
246+ if ( blockId != null ) {
247+ setTimeout ( ( ) => {
248+ console . log ( "macos first-click, focusing block" , blockId ) ;
249+ refocusNode ( blockId ) ;
250+ } , 10 ) ;
251+ } else if ( isAIPanelTarget ( e . target ) ) {
252+ setTimeout ( ( ) => {
253+ console . log ( "macos first-click, focusing AI panel" ) ;
254+ FocusManager . getInstance ( ) . setWaveAIFocused ( true ) ;
255+ } , 10 ) ;
256+ }
257+ console . log ( "macos first-click detected, canceled" , timeDiff + "ms" ) ;
258+ return ;
259+ }
260+ cancelNextClick = false ;
261+ } ;
262+ const handleClick = ( e : MouseEvent ) => {
263+ if ( ! cancelNextClick ) {
264+ return ;
265+ }
266+ cancelNextClick = false ;
267+ e . preventDefault ( ) ;
268+ e . stopPropagation ( ) ;
269+ e . stopImmediatePropagation ( ) ;
270+ console . log ( "macos first-click (click event) canceled" ) ;
271+ } ;
272+ window . addEventListener ( "focus" , handleWindowFocus ) ;
273+ window . addEventListener ( "mousedown" , handleMouseDown , true ) ;
274+ window . addEventListener ( "click" , handleClick , true ) ;
275+ return ( ) => {
276+ window . removeEventListener ( "focus" , handleWindowFocus ) ;
277+ window . removeEventListener ( "mousedown" , handleMouseDown , true ) ;
278+ window . removeEventListener ( "click" , handleClick , true ) ;
279+ } ;
280+ } , [ ] ) ;
281+ return null ;
282+ } ;
283+
206284const AppKeyHandlers = ( ) => {
207285 useEffect ( ( ) => {
208286 const staticKeyDownHandler = keyutil . keydownWrapper ( appHandleKeyDown ) ;
@@ -300,6 +378,7 @@ const AppInner = () => {
300378 onContextMenu = { handleContextMenu }
301379 >
302380 < AppBackground />
381+ < MacOSFirstClickHandler />
303382 < AppKeyHandlers />
304383 < AppFocusHandler />
305384 < AppSettingsUpdater />
0 commit comments