1- import { isMacOS } from '@primer/behaviors/utils'
21import { useSSRSafeId } from '@react-aria/ssr'
32import React , { forwardRef , useCallback , useEffect , useImperativeHandle , useMemo , useRef , useState } from 'react'
43import Box from '../../Box'
@@ -24,6 +23,7 @@ import {SavedRepliesContext, SavedRepliesHandle, SavedReply} from './_SavedRepli
2423import { Emoji } from './suggestions/_useEmojiSuggestions'
2524import { Mentionable } from './suggestions/_useMentionSuggestions'
2625import { Reference } from './suggestions/_useReferenceSuggestions'
26+ import { isModifierKey } from './utils'
2727
2828export type MarkdownEditorProps = SxProp & {
2929 /** Current value of the editor as a multiline markdown string. */
@@ -119,6 +119,15 @@ const CONDENSED_WIDTH_THRESHOLD = 675
119119const { Slot, Slots} = createSlots ( [ 'Toolbar' , 'Actions' , 'Label' ] )
120120export const MarkdownEditorSlot = Slot
121121
122+ /**
123+ * We want to switch editors from preview mode on cmd/ctrl+shift+P. But in preview mode,
124+ * there's no input to focus so we have to bind the event to the document. If there are
125+ * multiple editors, we want the most recent one to switch to preview mode to be the one
126+ * that we switch back to edit mode, so we maintain a LIFO stack of IDs of editors in
127+ * preview mode.
128+ */
129+ let editorsInPreviewMode : string [ ] = [ ]
130+
122131/**
123132 * Markdown textarea with controls & keyboard shortcuts.
124133 */
@@ -245,7 +254,7 @@ const MarkdownEditor = forwardRef<MarkdownEditorHandle, MarkdownEditorProps>(
245254 savedRepliesRef . current ?. openMenu ( )
246255 e . preventDefault ( )
247256 e . stopPropagation ( )
248- } else if ( isMacOS ( ) ? e . metaKey : e . ctrlKey ) {
257+ } else if ( isModifierKey ( e ) ) {
249258 if ( e . key === 'Enter' ) onPrimaryAction ?.( )
250259 else if ( e . key === 'b' ) format ?. bold ( )
251260 else if ( e . key === 'i' ) format ?. italic ( )
@@ -255,6 +264,7 @@ const MarkdownEditor = forwardRef<MarkdownEditorHandle, MarkdownEditorProps>(
255264 else if ( e . key === '8' ) format ?. unorderedList ( )
256265 else if ( e . shiftKey && e . key === '7' ) format ?. orderedList ( )
257266 else if ( e . shiftKey && e . key === 'l' ) format ?. taskList ( )
267+ else if ( e . shiftKey && e . key === 'p' ) setView ?.( 'preview' )
258268 else return
259269
260270 e . preventDefault ( )
@@ -266,6 +276,34 @@ const MarkdownEditor = forwardRef<MarkdownEditorHandle, MarkdownEditorProps>(
266276 }
267277 )
268278
279+ useEffect ( ( ) => {
280+ if ( view === 'preview' ) {
281+ editorsInPreviewMode . push ( id )
282+
283+ const handler = ( e : KeyboardEvent ) => {
284+ if (
285+ ! e . defaultPrevented &&
286+ editorsInPreviewMode . at ( - 1 ) === id &&
287+ isModifierKey ( e ) &&
288+ e . shiftKey &&
289+ e . key === 'p'
290+ ) {
291+ setView ?.( 'edit' )
292+ requestAnimationFrame ( ( ) => inputRef . current ?. focus ( ) )
293+ e . preventDefault ( )
294+ }
295+ }
296+ document . addEventListener ( 'keydown' , handler )
297+
298+ return ( ) => {
299+ document . removeEventListener ( 'keydown' , handler )
300+ // Performing the filtering in the cleanup callback allows it to happen also when
301+ // the user clicks the toggle button, not just on keyboard shortcut
302+ editorsInPreviewMode = editorsInPreviewMode . filter ( id_ => id_ !== id )
303+ }
304+ }
305+ } , [ view , setView , id ] )
306+
269307 // If we don't memoize the context object, every child will rerender on every render even if memoized
270308 const context = useMemo (
271309 ( ) => ( { disabled, formattingToolsRef, condensed, required} ) ,
@@ -366,6 +404,7 @@ const MarkdownEditor = forwardRef<MarkdownEditorHandle, MarkdownEditorProps>(
366404 boxSizing : 'border-box'
367405 } }
368406 aria-live = "polite"
407+ tabIndex = { - 1 }
369408 >
370409 < h2 style = { a11yOnlyStyle } > Rendered Markdown Preview</ h2 >
371410 < MarkdownViewer
@@ -392,6 +431,5 @@ const MarkdownEditor = forwardRef<MarkdownEditorHandle, MarkdownEditorProps>(
392431 )
393432 }
394433)
395- MarkdownEditor . displayName = 'MarkdownEditor'
396434
397435export default MarkdownEditor
0 commit comments