@@ -228,6 +228,86 @@ function useEntityAutocomplete ({
228
228
}
229
229
}
230
230
231
+ export function useDualAutocomplete ( { meta, helpers, innerRef, setSelectionRange } ) {
232
+ const userAutocomplete = useEntityAutocomplete ( {
233
+ prefix : '@' ,
234
+ meta,
235
+ helpers,
236
+ innerRef,
237
+ setSelectionRange,
238
+ SuggestComponent : UserSuggest
239
+ } )
240
+
241
+ const territoryAutocomplete = useEntityAutocomplete ( {
242
+ prefix : '~' ,
243
+ meta,
244
+ helpers,
245
+ innerRef,
246
+ setSelectionRange,
247
+ SuggestComponent : TerritorySuggest
248
+ } )
249
+
250
+ const handleTextChange = useCallback ( ( e ) => {
251
+ // Try to match user mentions first, then territories
252
+ if ( ! userAutocomplete . handleTextChange ( e ) ) {
253
+ territoryAutocomplete . handleTextChange ( e )
254
+ }
255
+ } , [ userAutocomplete , territoryAutocomplete ] )
256
+
257
+ const handleKeyDown = useCallback ( ( e , userOnKeyDown , territoryOnKeyDown ) => {
258
+ const metaOrCtrl = e . metaKey || e . ctrlKey
259
+ if ( ! metaOrCtrl ) {
260
+ if ( userAutocomplete . entityData ) {
261
+ return userOnKeyDown ( e )
262
+ } else if ( territoryAutocomplete . entityData ) {
263
+ return territoryOnKeyDown ( e )
264
+ }
265
+ }
266
+ return false // Didn't handle the event
267
+ } , [ userAutocomplete . entityData , territoryAutocomplete . entityData ] )
268
+
269
+ const handleBlur = useCallback ( ( resetUserSuggestions , resetTerritorySuggestions ) => {
270
+ setTimeout ( resetUserSuggestions , 500 )
271
+ setTimeout ( resetTerritorySuggestions , 500 )
272
+ } , [ ] )
273
+
274
+ return {
275
+ userAutocomplete,
276
+ territoryAutocomplete,
277
+ handleTextChange,
278
+ handleKeyDown,
279
+ handleBlur
280
+ }
281
+ }
282
+
283
+ export function DualAutocompleteWrapper ( {
284
+ userAutocomplete,
285
+ territoryAutocomplete,
286
+ children
287
+ } ) {
288
+ return (
289
+ < UserSuggest
290
+ query = { userAutocomplete . entityData ?. query }
291
+ onSelect = { userAutocomplete . handleSelect }
292
+ dropdownStyle = { userAutocomplete . entityData ?. style }
293
+ > { ( { onKeyDown : userSuggestOnKeyDown , resetSuggestions : resetUserSuggestions } ) => (
294
+ < TerritorySuggest
295
+ query = { territoryAutocomplete . entityData ?. query }
296
+ onSelect = { territoryAutocomplete . handleSelect }
297
+ dropdownStyle = { territoryAutocomplete . entityData ?. style }
298
+ > { ( { onKeyDown : territorySuggestOnKeyDown , resetSuggestions : resetTerritorySuggestions } ) =>
299
+ children ( {
300
+ userSuggestOnKeyDown,
301
+ territorySuggestOnKeyDown,
302
+ resetUserSuggestions,
303
+ resetTerritorySuggestions
304
+ } ) }
305
+ </ TerritorySuggest >
306
+ ) }
307
+ </ UserSuggest >
308
+ )
309
+ }
310
+
231
311
export function MarkdownInput ( { label, topLevel, groupClassName, onChange, onKeyDown, innerRef, ...props } ) {
232
312
const [ tab , setTab ] = useState ( 'write' )
233
313
const [ , meta , helpers ] = useField ( props )
@@ -287,22 +367,11 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, onKe
287
367
}
288
368
} , [ innerRef , selectionRange . start , selectionRange . end ] )
289
369
290
- const userAutocomplete = useEntityAutocomplete ( {
291
- prefix : '@' ,
292
- meta,
293
- helpers,
294
- innerRef,
295
- setSelectionRange,
296
- SuggestComponent : UserSuggest
297
- } )
298
-
299
- const territoryAutocomplete = useEntityAutocomplete ( {
300
- prefix : '~' ,
370
+ const { userAutocomplete, territoryAutocomplete, handleTextChange, handleKeyDown, handleBlur } = useDualAutocomplete ( {
301
371
meta,
302
372
helpers,
303
373
innerRef,
304
- setSelectionRange,
305
- SuggestComponent : TerritorySuggest
374
+ setSelectionRange
306
375
} )
307
376
308
377
const uploadFeesUpdate = useDebounceCallback (
@@ -313,56 +382,9 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, onKe
313
382
314
383
const onChangeInner = useCallback ( ( formik , e ) => {
315
384
if ( onChange ) onChange ( formik , e )
316
- // check for mentions and territory suggestions
317
385
uploadFeesUpdate ( e . target . value )
318
-
319
- // Try to match user mentions first, then territories
320
- if ( ! userAutocomplete . handleTextChange ( e ) ) {
321
- territoryAutocomplete . handleTextChange ( e )
322
- }
323
- } , [ onChange , uploadFeesUpdate , userAutocomplete , territoryAutocomplete ] )
324
-
325
- const onKeyDownInner = useCallback ( ( userSuggestOnKeyDown , territorySuggestOnKeyDown ) => {
326
- return ( e ) => {
327
- const metaOrCtrl = e . metaKey || e . ctrlKey
328
- if ( metaOrCtrl ) {
329
- if ( e . key === 'k' ) {
330
- // some browsers use CTRL+K to focus search bar so we have to prevent that behavior
331
- e . preventDefault ( )
332
- insertMarkdownLinkFormatting ( innerRef . current , helpers . setValue , setSelectionRange )
333
- }
334
- if ( e . key === 'b' ) {
335
- // some browsers use CTRL+B to open bookmarks so we have to prevent that behavior
336
- e . preventDefault ( )
337
- insertMarkdownBoldFormatting ( innerRef . current , helpers . setValue , setSelectionRange )
338
- }
339
- if ( e . key === 'i' ) {
340
- // some browsers might use CTRL+I to do something else so prevent that behavior too
341
- e . preventDefault ( )
342
- insertMarkdownItalicFormatting ( innerRef . current , helpers . setValue , setSelectionRange )
343
- }
344
- if ( e . key === 'u' ) {
345
- // some browsers might use CTRL+U to do something else so prevent that behavior too
346
- e . preventDefault ( )
347
- imageUploadRef . current ?. click ( )
348
- }
349
- if ( e . key === 'Tab' && e . altKey ) {
350
- e . preventDefault ( )
351
- insertMarkdownTabFormatting ( innerRef . current , helpers . setValue , setSelectionRange )
352
- }
353
- }
354
-
355
- if ( ! metaOrCtrl ) {
356
- if ( userAutocomplete . entityData ) {
357
- userSuggestOnKeyDown ( e )
358
- } else if ( territoryAutocomplete . entityData ) {
359
- territorySuggestOnKeyDown ( e )
360
- }
361
- }
362
-
363
- if ( onKeyDown ) onKeyDown ( e )
364
- }
365
- } , [ innerRef , helpers ?. setValue , setSelectionRange , onKeyDown , userAutocomplete . entityData , territoryAutocomplete . entityData ] )
386
+ handleTextChange ( e )
387
+ } , [ onChange , uploadFeesUpdate , handleTextChange ] )
366
388
367
389
const onPaste = useCallback ( ( event ) => {
368
390
const items = event . clipboardData . items
@@ -406,6 +428,44 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, onKe
406
428
setDragStyle ( null )
407
429
} , [ setDragStyle ] )
408
430
431
+ const onKeyDownInner = useCallback ( ( userSuggestOnKeyDown , territorySuggestOnKeyDown ) => {
432
+ return ( e ) => {
433
+ const metaOrCtrl = e . metaKey || e . ctrlKey
434
+
435
+ // Handle markdown shortcuts first
436
+ if ( metaOrCtrl ) {
437
+ if ( e . key === 'k' ) {
438
+ // some browsers use CTRL+K to focus search bar so we have to prevent that behavior
439
+ e . preventDefault ( )
440
+ insertMarkdownLinkFormatting ( innerRef . current , helpers . setValue , setSelectionRange )
441
+ }
442
+ if ( e . key === 'b' ) {
443
+ // some browsers use CTRL+B to open bookmarks so we have to prevent that behavior
444
+ e . preventDefault ( )
445
+ insertMarkdownBoldFormatting ( innerRef . current , helpers . setValue , setSelectionRange )
446
+ }
447
+ if ( e . key === 'i' ) {
448
+ // some browsers might use CTRL+I to do something else so prevent that behavior too
449
+ e . preventDefault ( )
450
+ insertMarkdownItalicFormatting ( innerRef . current , helpers . setValue , setSelectionRange )
451
+ }
452
+ if ( e . key === 'u' ) {
453
+ // some browsers might use CTRL+U to do something else so prevent that behavior too
454
+ e . preventDefault ( )
455
+ imageUploadRef . current ?. click ( )
456
+ }
457
+ if ( e . key === 'Tab' && e . altKey ) {
458
+ e . preventDefault ( )
459
+ insertMarkdownTabFormatting ( innerRef . current , helpers . setValue , setSelectionRange )
460
+ }
461
+ } else {
462
+ handleKeyDown ( e , userSuggestOnKeyDown , territorySuggestOnKeyDown )
463
+ }
464
+
465
+ if ( onKeyDown ) onKeyDown ( e )
466
+ }
467
+ } , [ innerRef , helpers ?. setValue , setSelectionRange , onKeyDown , handleKeyDown , imageUploadRef ] )
468
+
409
469
return (
410
470
< FormGroup label = { label } className = { groupClassName } >
411
471
< div className = { `${ styles . markdownInput } ${ tab === 'write' ? styles . noTopLeftRadius : '' } ` } >
@@ -472,34 +532,25 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, onKe
472
532
</ span >
473
533
</ Nav >
474
534
< div className = { `position-relative ${ tab === 'write' ? '' : 'd-none' } ` } >
475
- < UserSuggest
476
- query = { userAutocomplete . entityData ?. query }
477
- onSelect = { userAutocomplete . handleSelect }
478
- dropdownStyle = { userAutocomplete . entityData ?. style }
479
- > { ( { onKeyDown : userSuggestOnKeyDown , resetSuggestions : resetUserSuggestions } ) => (
480
- < TerritorySuggest
481
- query = { territoryAutocomplete . entityData ?. query }
482
- onSelect = { territoryAutocomplete . handleSelect }
483
- dropdownStyle = { territoryAutocomplete . entityData ?. style }
484
- > { ( { onKeyDown : territorySuggestOnKeyDown , resetSuggestions : resetTerritorySuggestions } ) => (
535
+ < DualAutocompleteWrapper
536
+ userAutocomplete = { userAutocomplete }
537
+ territoryAutocomplete = { territoryAutocomplete }
538
+ >
539
+ { ( { userSuggestOnKeyDown, territorySuggestOnKeyDown, resetUserSuggestions, resetTerritorySuggestions } ) => (
485
540
< InputInner
486
541
innerRef = { innerRef }
487
542
{ ...props }
488
543
onChange = { onChangeInner }
489
544
onKeyDown = { onKeyDownInner ( userSuggestOnKeyDown , territorySuggestOnKeyDown ) }
490
- onBlur = { ( ) => {
491
- setTimeout ( resetUserSuggestions , 500 )
492
- setTimeout ( resetTerritorySuggestions , 500 )
493
- } }
545
+ onBlur = { ( ) => handleBlur ( resetUserSuggestions , resetTerritorySuggestions ) }
494
546
onDragEnter = { onDragEnter }
495
547
onDragLeave = { onDragLeave }
496
548
onDrop = { onDrop }
497
549
onPaste = { onPaste }
498
550
className = { dragStyle === 'over' ? styles . dragOver : '' }
499
- /> ) }
500
- </ TerritorySuggest >
501
- ) }
502
- </ UserSuggest >
551
+ />
552
+ ) }
553
+ </ DualAutocompleteWrapper >
503
554
</ div >
504
555
{ tab !== 'write' &&
505
556
< div className = 'form-group' >
0 commit comments