@@ -1146,3 +1146,151 @@ describe('ui.commands.getContextMenuItems', () => {
11461146 ui . destroy ( ) ;
11471147 } ) ;
11481148} ) ;
1149+
1150+ describe ( 'ui.commands.register — shortcut field' , ( ) => {
1151+ function makeStubsWithHost ( ) {
1152+ const stubs = makeStubs ( ) ;
1153+ const host = document . createElement ( 'div' ) ;
1154+ document . body . appendChild ( host ) ;
1155+ // Preserve any existing presentationEditor surface the toolbar
1156+ // resolver expects (`getActiveEditor`) and add the `visibleHost`
1157+ // that the keydown listener scopes to.
1158+ const existing =
1159+ ( stubs . editor as unknown as { presentationEditor ?: Record < string , unknown > } ) . presentationEditor ?? { } ;
1160+ ( stubs . editor as unknown as { presentationEditor : Record < string , unknown > } ) . presentationEditor = {
1161+ getActiveEditor : ( ) => stubs . editor ,
1162+ ...existing ,
1163+ visibleHost : host ,
1164+ } ;
1165+ return { ...stubs , host } ;
1166+ }
1167+
1168+ function fireKey ( target : Node , init : Partial < KeyboardEventInit > & { key : string } ) {
1169+ const ev = new KeyboardEvent ( 'keydown' , { ...init , bubbles : true , cancelable : true } ) ;
1170+ target . dispatchEvent ( ev ) ;
1171+ return ev ;
1172+ }
1173+
1174+ it ( 'dispatches the registered command when the matching combo fires inside the host' , ( ) => {
1175+ const { superdoc, host } = makeStubsWithHost ( ) ;
1176+ const ui = createSuperDocUI ( { superdoc } ) ;
1177+
1178+ const execute = vi . fn ( ( ) => true ) ;
1179+ ui . commands . register ( { id : 'company.insertClause' , execute, shortcut : 'Mod-Shift-C' } ) ;
1180+
1181+ fireKey ( host , { key : 'c' , ctrlKey : true , shiftKey : true } ) ;
1182+
1183+ expect ( execute ) . toHaveBeenCalledTimes ( 1 ) ;
1184+ host . remove ( ) ;
1185+ ui . destroy ( ) ;
1186+ } ) ;
1187+
1188+ it ( "dispatches when focus is in the routed editor's hidden PM DOM (the normal editing path)" , ( ) => {
1189+ const { superdoc, editor, host } = makeStubsWithHost ( ) ;
1190+ // Mount the hidden ProseMirror DOM directly under document.body
1191+ // (mirroring how PresentationEditor appends the hidden host outside
1192+ // the visible host) so a click-into-document keypress lands here.
1193+ const pmDom = document . createElement ( 'div' ) ;
1194+ document . body . appendChild ( pmDom ) ;
1195+ ( editor as unknown as { view : { dom : HTMLElement } } ) . view = { dom : pmDom } ;
1196+ const ui = createSuperDocUI ( { superdoc } ) ;
1197+
1198+ const execute = vi . fn ( ( ) => true ) ;
1199+ ui . commands . register ( { id : 'company.action' , execute, shortcut : 'Mod-K' } ) ;
1200+
1201+ fireKey ( pmDom , { key : 'k' , ctrlKey : true } ) ;
1202+
1203+ expect ( execute ) . toHaveBeenCalledTimes ( 1 ) ;
1204+ pmDom . remove ( ) ;
1205+ host . remove ( ) ;
1206+ ui . destroy ( ) ;
1207+ } ) ;
1208+
1209+ it ( 'does not dispatch when focus is outside the painted host' , ( ) => {
1210+ const { superdoc, host } = makeStubsWithHost ( ) ;
1211+ const ui = createSuperDocUI ( { superdoc } ) ;
1212+
1213+ const execute = vi . fn ( ( ) => true ) ;
1214+ ui . commands . register ( { id : 'company.insertClause' , execute, shortcut : 'Mod-Shift-C' } ) ;
1215+
1216+ const outside = document . createElement ( 'input' ) ;
1217+ document . body . appendChild ( outside ) ;
1218+ fireKey ( outside , { key : 'c' , ctrlKey : true , shiftKey : true } ) ;
1219+
1220+ expect ( execute ) . not . toHaveBeenCalled ( ) ;
1221+ outside . remove ( ) ;
1222+ host . remove ( ) ;
1223+ ui . destroy ( ) ;
1224+ } ) ;
1225+
1226+ it ( 'warns and replaces when two registrations claim the same shortcut' , ( ) => {
1227+ const { superdoc, host } = makeStubsWithHost ( ) ;
1228+ const ui = createSuperDocUI ( { superdoc } ) ;
1229+
1230+ const firstExecute = vi . fn ( ( ) => true ) ;
1231+ const secondExecute = vi . fn ( ( ) => true ) ;
1232+ ui . commands . register ( { id : 'company.first' , execute : firstExecute , shortcut : 'Mod-K' } ) ;
1233+ ui . commands . register ( { id : 'company.second' , execute : secondExecute , shortcut : 'Mod-K' } ) ;
1234+
1235+ expect ( warnSpy ) . toHaveBeenCalled ( ) ;
1236+
1237+ fireKey ( host , { key : 'k' , ctrlKey : true } ) ;
1238+ expect ( firstExecute ) . not . toHaveBeenCalled ( ) ;
1239+ expect ( secondExecute ) . toHaveBeenCalledTimes ( 1 ) ;
1240+
1241+ host . remove ( ) ;
1242+ ui . destroy ( ) ;
1243+ } ) ;
1244+
1245+ it ( 'drops the shortcut on unregister so later keypresses are no-ops' , ( ) => {
1246+ const { superdoc, host } = makeStubsWithHost ( ) ;
1247+ const ui = createSuperDocUI ( { superdoc } ) ;
1248+
1249+ const execute = vi . fn ( ( ) => true ) ;
1250+ const reg = ui . commands . register ( { id : 'company.toggle' , execute, shortcut : 'Mod-J' } ) ;
1251+
1252+ fireKey ( host , { key : 'j' , ctrlKey : true } ) ;
1253+ expect ( execute ) . toHaveBeenCalledTimes ( 1 ) ;
1254+
1255+ reg . unregister ( ) ;
1256+ fireKey ( host , { key : 'j' , ctrlKey : true } ) ;
1257+ expect ( execute ) . toHaveBeenCalledTimes ( 1 ) ;
1258+
1259+ host . remove ( ) ;
1260+ ui . destroy ( ) ;
1261+ } ) ;
1262+
1263+ it ( 'accepts a string[] for multiple shortcuts on the same command' , ( ) => {
1264+ const { superdoc, host } = makeStubsWithHost ( ) ;
1265+ const ui = createSuperDocUI ( { superdoc } ) ;
1266+
1267+ const execute = vi . fn ( ( ) => true ) ;
1268+ ui . commands . register ( {
1269+ id : 'company.action' ,
1270+ execute,
1271+ shortcut : [ 'Mod-1' , 'Mod-Shift-1' ] ,
1272+ } ) ;
1273+
1274+ fireKey ( host , { key : '1' , ctrlKey : true } ) ;
1275+ fireKey ( host , { key : '1' , ctrlKey : true , shiftKey : true } ) ;
1276+
1277+ expect ( execute ) . toHaveBeenCalledTimes ( 2 ) ;
1278+ host . remove ( ) ;
1279+ ui . destroy ( ) ;
1280+ } ) ;
1281+
1282+ it ( 'warns on a malformed shortcut and ignores it' , ( ) => {
1283+ const { superdoc, host } = makeStubsWithHost ( ) ;
1284+ const ui = createSuperDocUI ( { superdoc } ) ;
1285+
1286+ const execute = vi . fn ( ( ) => true ) ;
1287+ ui . commands . register ( { id : 'company.bad' , execute, shortcut : 'Mod-Shift' } ) ;
1288+
1289+ expect ( warnSpy ) . toHaveBeenCalled ( ) ;
1290+ fireKey ( host , { key : 'Shift' , ctrlKey : true } ) ;
1291+ expect ( execute ) . not . toHaveBeenCalled ( ) ;
1292+
1293+ host . remove ( ) ;
1294+ ui . destroy ( ) ;
1295+ } ) ;
1296+ } ) ;
0 commit comments