diff --git a/.changeset/chilled-brooms-grow.md b/.changeset/chilled-brooms-grow.md new file mode 100644 index 00000000000..73d033b8b38 --- /dev/null +++ b/.changeset/chilled-brooms-grow.md @@ -0,0 +1,7 @@ +--- +"@primer/react": patch +--- + +`MarkdownEditor` is now SSR-compatible. + +Warning: In this new implementation, `MarkdownEditor.Toolbar`, `MarkdownEditor.Actions`, and `MarkdownEditor.Label` must be direct children of `MarkdownEditor`. diff --git a/src/drafts/MarkdownEditor/Actions.tsx b/src/drafts/MarkdownEditor/Actions.tsx index 5a0c8f3f97d..25055e623b9 100644 --- a/src/drafts/MarkdownEditor/Actions.tsx +++ b/src/drafts/MarkdownEditor/Actions.tsx @@ -1,11 +1,8 @@ import React, {forwardRef, useContext} from 'react' import {Button, ButtonProps} from '../../Button' -import {MarkdownEditorSlot} from './MarkdownEditor' import {MarkdownEditorContext} from './_MarkdownEditorContext' -export const Actions = ({children}: {children?: React.ReactNode}) => ( - {children} -) +export const Actions = ({children}: {children?: React.ReactNode}) => <>{children} Actions.displayName = 'MarkdownEditor.Actions' export const ActionButton = forwardRef((props, ref) => { diff --git a/src/drafts/MarkdownEditor/Label.tsx b/src/drafts/MarkdownEditor/Label.tsx index 5cc36a55485..bf55398b86e 100644 --- a/src/drafts/MarkdownEditor/Label.tsx +++ b/src/drafts/MarkdownEditor/Label.tsx @@ -1,7 +1,6 @@ import React, {FC, useContext} from 'react' -import {SxProp} from '../../sx' import InputLabel from '../../_InputLabel' -import {MarkdownEditorSlot} from './MarkdownEditor' +import {SxProp} from '../../sx' import {MarkdownEditorContext} from './_MarkdownEditorContext' type LabelProps = SxProp & { @@ -20,8 +19,4 @@ const Legend: FC = ({sx, ...props}) => { } Legend.displayName = 'MarkdownEditor.Label' -export const Label: FC = props => ( - - - -) +export const Label: FC = props => diff --git a/src/drafts/MarkdownEditor/MarkdownEditor.tsx b/src/drafts/MarkdownEditor/MarkdownEditor.tsx index f077d1a1cb3..e126270f716 100644 --- a/src/drafts/MarkdownEditor/MarkdownEditor.tsx +++ b/src/drafts/MarkdownEditor/MarkdownEditor.tsx @@ -9,31 +9,33 @@ import React, { useState, } from 'react' import Box from '../../Box' -import {FileType} from '../hooks/useUnifiedFileSelect' +import VisuallyHidden from '../../_VisuallyHidden' import {useId} from '../../hooks/useId' -import {useIgnoreKeyboardActionsWhileComposing} from '../hooks/useIgnoreKeyboardActionsWhileComposing' import {useResizeObserver} from '../../hooks/useResizeObserver' -import {useSyntheticChange} from '../hooks/useSyntheticChange' -import MarkdownViewer from '../MarkdownViewer' +import {useSlots} from '../../hooks/useSlots' import {SxProp} from '../../sx' -import createSlots from '../../utils/create-slots' -import VisuallyHidden from '../../_VisuallyHidden' +import MarkdownViewer from '../MarkdownViewer' +import {useIgnoreKeyboardActionsWhileComposing} from '../hooks/useIgnoreKeyboardActionsWhileComposing' +import {useSafeAsyncCallback} from '../hooks/useSafeAsyncCallback' +import {useSyntheticChange} from '../hooks/useSyntheticChange' +import {FileType} from '../hooks/useUnifiedFileSelect' +import {Actions} from './Actions' +import {Label} from './Label' +import {CoreToolbar, DefaultToolbarButtons, Toolbar} from './Toolbar' +import {Footer} from './_Footer' import {FormattingTools} from './_FormattingTools' import {MarkdownEditorContext} from './_MarkdownEditorContext' -import {CoreToolbar, DefaultToolbarButtons} from './Toolbar' -import {Footer} from './_Footer' import {MarkdownInput} from './_MarkdownInput' +import {SavedRepliesContext, SavedRepliesHandle, SavedReply} from './_SavedReplies' +import {MarkdownViewMode, ViewSwitch} from './_ViewSwitch' import {FileUploadResult, useFileHandling} from './_useFileHandling' import {useIndenting} from './_useIndenting' import {useListEditing} from './_useListEditing' -import {MarkdownViewMode, ViewSwitch} from './_ViewSwitch' -import {useSafeAsyncCallback} from '../hooks/useSafeAsyncCallback' -import {SavedRepliesContext, SavedRepliesHandle, SavedReply} from './_SavedReplies' +import {SuggestionOptions} from './suggestions' import {Emoji} from './suggestions/_useEmojiSuggestions' import {Mentionable} from './suggestions/_useMentionSuggestions' import {Reference} from './suggestions/_useReferenceSuggestions' import {isModifierKey} from './utils' -import {SuggestionOptions} from './suggestions' export type MarkdownEditorProps = SxProp & { /** Current value of the editor as a multiline markdown string. */ @@ -143,9 +145,6 @@ const a11yOnlyStyle = {clipPath: 'Circle(0)', position: 'absolute'} as const const CONDENSED_WIDTH_THRESHOLD = 675 -const {Slot, Slots} = createSlots(['Toolbar', 'Actions', 'Label']) -export const MarkdownEditorSlot = Slot - /** * We want to switch editors from preview mode on cmd/ctrl+shift+P. But in preview mode, * there's no input to focus so we have to bind the event to the document. If there are @@ -189,6 +188,11 @@ const MarkdownEditor = forwardRef( }, ref, ) => { + const [slots, childrenWithoutSlots] = useSlots(children, { + toolbar: Toolbar, + actions: Actions, + label: Label, + }) const [uncontrolledViewMode, uncontrolledSetViewMode] = useState('edit') const [view, setView] = controlledViewMode === undefined @@ -352,123 +356,117 @@ const MarkdownEditor = forwardRef( // We are using MarkdownEditorContext instead of the built-in Slots context because Slots' context is not typesafe return ( - - {slots => ( - -
- -
{children}
- - {slots.Label} - + +
+ +
{childrenWithoutSlots}
+ + {slots.label} + + + + Markdown input: + {view === 'preview' ? ' preview mode selected.' : ' edit mode selected.'} + + + + + + + + {view === 'edit' && + (slots.toolbar ?? ( + + + + ))} + + + + + + + {view === 'preview' && ( - - Markdown input: - {view === 'preview' ? ' preview mode selected.' : ' edit mode selected.'} - - - - - - - - {view === 'edit' && - (slots.Toolbar ?? ( - - - - ))} - - - - - - - {view === 'preview' && ( - -

Rendered Markdown Preview

- -
- )} - -
Rendered Markdown Preview + -
-
- )} - + )} + +
+ +
+
) }, ) diff --git a/src/drafts/MarkdownEditor/Toolbar.tsx b/src/drafts/MarkdownEditor/Toolbar.tsx index ccf37a44ba0..0b975733298 100644 --- a/src/drafts/MarkdownEditor/Toolbar.tsx +++ b/src/drafts/MarkdownEditor/Toolbar.tsx @@ -18,7 +18,6 @@ import {isMacOS} from '@primer/behaviors/utils' import Box from '../../Box' import {IconButton, IconButtonProps} from '../../Button' import {useFocusZone} from '../../hooks/useFocusZone' -import {MarkdownEditorSlot} from './MarkdownEditor' import {MarkdownEditorContext} from './_MarkdownEditorContext' import {SavedRepliesButton} from './_SavedReplies' @@ -143,9 +142,5 @@ export const CoreToolbar = ({children}: {children?: React.ReactNode}) => { ) } -export const Toolbar = ({children}: {children?: React.ReactNode}) => ( - - {children} - -) +export const Toolbar = ({children}: {children?: React.ReactNode}) => {children} Toolbar.displayName = 'MarkdownEditor.Toolbar'