Respect native input ownership before canvas keyboard cancellation

This commit is contained in:
2026-11-09 19:33:40 +08:00
parent 9efe6e7c9f
commit fd6c166f4b
8 changed files with 70 additions and 10 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ export type * from './compat-types.ts';
export {createSelectorStore} from './selectors.ts';
export type {ExternalSource} from './selectors.ts';
export {routeCanvasKey} from './input-router.ts';
export {routeCanvasKey,canvasKeyContext} from './input-router.ts';
export type {CanvasKeyInput,InputClaim,KeyHandler} from './input-router.ts';
export {createFrameQueue} from './frame-queue.ts';
export type {FrameClock} from './frame-queue.ts';
+14
View File
@@ -2,6 +2,20 @@
export type CanvasKeyInput={readonly key:string;readonly composing?:boolean;readonly textEditing?:boolean;readonly overlay?:boolean;readonly defaultPrevented?:boolean;readonly ctrl?:boolean;readonly meta?:boolean;readonly alt?:boolean;readonly shift?:boolean};
export type InputClaim='text'|'overlay'|'gesture'|'tool'|'shortcut'|'unclaimed';
export type KeyHandler=(input:CanvasKeyInput)=>boolean;
const textTarget = 'input,textarea,select,[contenteditable]:not([contenteditable="false"]),[role="textbox"]';
const overlayTarget = '[data-canvas-overlay-view],[role="dialog"],[role="menu"],[role="listbox"],[role="combobox"]';
/** Inspect the composed path as well as the retargeted host (portals/shadow DOM).
* This uses a structural DOM port so pure consumers need no browser globals. */
export function canvasKeyContext(event:{readonly target?:unknown;composedPath?:()=>readonly unknown[]}):Pick<CanvasKeyInput,'textEditing'|'overlay'>{
let textEditing=false,overlay=false;
for(const target of [event.target,...(event.composedPath?.()??[])]){
if(!target||typeof (target as {closest?:unknown}).closest!=='function')continue;
const element=target as {closest(selector:string):unknown};
textEditing ||= !!element.closest(textTarget);
overlay ||= !!element.closest(overlayTarget);
}
return {textEditing,overlay};
}
export function routeCanvasKey(input:CanvasKeyInput,handlers:{gesture?:KeyHandler;tool?:KeyHandler;shortcut?:KeyHandler}):InputClaim{
if(input.defaultPrevented)return 'unclaimed';
if(input.composing||input.textEditing)return 'text';