@primer/react
Version:
An implementation of GitHub's Primer Design System using React
204 lines (203 loc) • 9.55 kB
TypeScript
import React from 'react';
import { SxProp } from '../../sx';
import { FileType } from '../hooks/useUnifiedFileSelect';
import { SavedReply } from './_SavedReplies';
import { MarkdownViewMode } from './_ViewSwitch';
import { FileUploadResult } from './_useFileHandling';
import { SuggestionOptions } from './suggestions';
import { Emoji } from './suggestions/_useEmojiSuggestions';
import { Mentionable } from './suggestions/_useMentionSuggestions';
import { Reference } from './suggestions/_useReferenceSuggestions';
export type MarkdownEditorProps = SxProp & {
/** Current value of the editor as a multiline markdown string. */
value: string;
/** Called when the value changes. */
onChange: (newMarkdown: string) => void;
/**
* Accepts Markdown and returns rendered HTML. To prevent XSS attacks,
* the HTML should be sanitized and/or come from a trusted source.
*/
onRenderPreview: (markdown: string) => Promise<string>;
children: React.ReactNode;
/** Disable the editor and all related buttons. Users can still switch between preview & edit modes. */
disabled?: boolean;
/** Placeholder text to show when the editor is empty. By default, no placeholder will be shown. */
placeholder?: string;
/** Maximum number of characters the markdown can hold (includes formatting characters like `*`). */
maxLength?: number;
/**
* Force the editor to take up the full height of the container and disallow resizing. Only
* use when the container height is tall enough that the user will never want to expand the
* input further, ie when it takes the full height of the viewport.
*/
fullHeight?: boolean;
/** ID of the describing element. */
'aria-describedby'?: string;
/** Optionally control the view mode. If uncontrolled, leave this `undefined`. */
viewMode?: MarkdownViewMode;
/** If `viewMode` is controlled, this will be called on change. */
onChangeViewMode?: (newViewMode: MarkdownViewMode) => void;
/**
* Called when the user presses `Ctrl`/`Cmd` + `Enter`. Should almost always be wired to
* the same event as clicking the primary `actionButton`.
*/
onPrimaryAction?: () => void;
/**
* Minimum number of visible lines of text in the editor.
* @default 5
*/
minHeightLines?: number;
/**
* Maximum number of visible lines of text in the editor. Has no effect if `fullHeight = true`.
* @default 35
*/
maxHeightLines?: number;
/**
* Array of all possible emojis to suggest. Leave `undefined` to disable emoji autocomplete.
* For lazy-loading suggestions, an async function can be provided instead.
*/
emojiSuggestions?: SuggestionOptions<Emoji>;
/**
* Array of all possible mention suggestions. Leave `undefined` to disable `@`-mention autocomplete.
* For lazy-loading suggestions, an async function can be provided instead.
*/
mentionSuggestions?: SuggestionOptions<Mentionable>;
/**
* Array of all possible references to suggest. Leave `undefined` to disable `#`-reference autocomplete.
* For lazy-loading suggestions, an async function can be provided instead.
*/
referenceSuggestions?: SuggestionOptions<Reference>;
/**
* Uploads a file to a hosting service and returns the URL. If not provided, file uploads
* will be disabled.
*/
onUploadFile?: (file: File) => Promise<FileUploadResult>;
/**
* Array of allowed file types. If `onUploadFile` is defined but this array is not, all
* file types will be accepted. You can still reject file types by rejecting the `onUploadFile`
* promise, but setting this array provides a better user experience by preventing the
* upload in the first place.
*/
acceptedFileTypes?: FileType[];
/** Control whether the editor font is monospace. */
monospace?: boolean;
/** Control whether the input is required. */
required?: boolean;
/** The name that will be given to the `textarea`. */
name?: string;
/** To enable the saved replies feature, provide an array of replies. */
savedReplies?: SavedReply[];
/**
* Control whether URLs are pasted as plain text instead of as formatted links (if the
* user has selected some text before pasting). Defaults to `false` (URLs will paste as
* links). This should typically be controlled by user settings.
*
* Users can always toggle this behavior by holding `shift` when pasting.
*/
pasteUrlsAsPlainText?: boolean;
};
declare const handleBrand: unique symbol;
export interface MarkdownEditorHandle {
/** Focus on the markdown textarea (has no effect in preview mode). */
focus: (options?: FocusOptions) => void;
/** Scroll to the editor. */
scrollIntoView: (options?: ScrollIntoViewOptions) => void;
/**
* This 'fake' member prevents other types from being assigned to this, thus
* disallowing broader ref types like `HTMLTextAreaElement`.
* @private
*/
[handleBrand]: undefined;
}
/**
* Markdown textarea with controls & keyboard shortcuts.
*/
declare const MarkdownEditor: React.ForwardRefExoticComponent<SxProp & {
/** Current value of the editor as a multiline markdown string. */
value: string;
/** Called when the value changes. */
onChange: (newMarkdown: string) => void;
/**
* Accepts Markdown and returns rendered HTML. To prevent XSS attacks,
* the HTML should be sanitized and/or come from a trusted source.
*/
onRenderPreview: (markdown: string) => Promise<string>;
children: React.ReactNode;
/** Disable the editor and all related buttons. Users can still switch between preview & edit modes. */
disabled?: boolean | undefined;
/** Placeholder text to show when the editor is empty. By default, no placeholder will be shown. */
placeholder?: string | undefined;
/** Maximum number of characters the markdown can hold (includes formatting characters like `*`). */
maxLength?: number | undefined;
/**
* Force the editor to take up the full height of the container and disallow resizing. Only
* use when the container height is tall enough that the user will never want to expand the
* input further, ie when it takes the full height of the viewport.
*/
fullHeight?: boolean | undefined;
/** ID of the describing element. */
'aria-describedby'?: string | undefined;
/** Optionally control the view mode. If uncontrolled, leave this `undefined`. */
viewMode?: MarkdownViewMode | undefined;
/** If `viewMode` is controlled, this will be called on change. */
onChangeViewMode?: ((newViewMode: MarkdownViewMode) => void) | undefined;
/**
* Called when the user presses `Ctrl`/`Cmd` + `Enter`. Should almost always be wired to
* the same event as clicking the primary `actionButton`.
*/
onPrimaryAction?: (() => void) | undefined;
/**
* Minimum number of visible lines of text in the editor.
* @default 5
*/
minHeightLines?: number | undefined;
/**
* Maximum number of visible lines of text in the editor. Has no effect if `fullHeight = true`.
* @default 35
*/
maxHeightLines?: number | undefined;
/**
* Array of all possible emojis to suggest. Leave `undefined` to disable emoji autocomplete.
* For lazy-loading suggestions, an async function can be provided instead.
*/
emojiSuggestions?: SuggestionOptions<Emoji> | undefined;
/**
* Array of all possible mention suggestions. Leave `undefined` to disable `@`-mention autocomplete.
* For lazy-loading suggestions, an async function can be provided instead.
*/
mentionSuggestions?: SuggestionOptions<Mentionable> | undefined;
/**
* Array of all possible references to suggest. Leave `undefined` to disable `#`-reference autocomplete.
* For lazy-loading suggestions, an async function can be provided instead.
*/
referenceSuggestions?: SuggestionOptions<Reference> | undefined;
/**
* Uploads a file to a hosting service and returns the URL. If not provided, file uploads
* will be disabled.
*/
onUploadFile?: ((file: File) => Promise<FileUploadResult>) | undefined;
/**
* Array of allowed file types. If `onUploadFile` is defined but this array is not, all
* file types will be accepted. You can still reject file types by rejecting the `onUploadFile`
* promise, but setting this array provides a better user experience by preventing the
* upload in the first place.
*/
acceptedFileTypes?: FileType[] | undefined;
/** Control whether the editor font is monospace. */
monospace?: boolean | undefined;
/** Control whether the input is required. */
required?: boolean | undefined;
/** The name that will be given to the `textarea`. */
name?: string | undefined;
/** To enable the saved replies feature, provide an array of replies. */
savedReplies?: SavedReply[] | undefined;
/**
* Control whether URLs are pasted as plain text instead of as formatted links (if the
* user has selected some text before pasting). Defaults to `false` (URLs will paste as
* links). This should typically be controlled by user settings.
*
* Users can always toggle this behavior by holding `shift` when pasting.
*/
pasteUrlsAsPlainText?: boolean | undefined;
} & React.RefAttributes<MarkdownEditorHandle>>;
export default MarkdownEditor;