Um editor baseado em React e Prosemirror que alimenta o Outline e também pode ser usado para exibir conteúdo somente leitura. O editor é WYSIWYG e inclui ferramentas de formatação, mantendo a capacidade de escrever atalhos de markdown in-line e gerar Markdown simples. Veja o livro de histórias da demonstração ao vivo .
Nota importante: Este projeto não tenta ser um editor Markdown para todos os fins . Ele foi desenvolvido para a base de conhecimento do Outline e, embora outros possam usar ou usar este pacote em seus próprios produtos, as decisões de desenvolvimento são centradas nas necessidades do Outline.
yarn add rich-markdown-editor
ou
npm install rich-markdown-editor
Observe que react
, react-dom
e styled-components
são dependências de pares obrigatórias .
import Editor from "rich-markdown-editor" ;
< Editor
defaultValue = "Hello world!"
/>
Clone este repositório e execute o Storybook com yarn start
para ver uma grande variedade de exemplos de uso.
id
Um ID exclusivo para este editor, usado para persistir as configurações no armazenamento local. Se nenhum id
for passado, o editor usará como padrão o nome do caminho do local.
defaultValue
Uma string de redução que representa o valor inicial do editor. Use isso para restaurar o conteúdo salvo anteriormente para o usuário continuar editando.
value
Uma string de redução que representa o valor do editor. Use esta propriedade para alterar o valor do editor uma vez montado, isso irá renderizar novamente todo o editor e, como tal, só é adequado quando também estiver no modo readOnly
. Não canalize o valor de onChange
de volta para value
, o editor mantém seu próprio estado interno e isso resultará em efeitos colaterais inesperados.
placeholder
Permite a substituição do espaço reservado. O padrão é "Escreva algo legal…".
readOnly
Com readOnly
definido como false
o editor é otimizado para composição. Quando true
o editor pode ser usado para exibir conteúdo escrito anteriormente – os títulos ganham âncoras e os links tornam-se clicáveis.
readOnlyWriteCheckboxes
Com readOnlyWriteCheckboxes
definido como true
as caixas de seleção ainda podem ser marcadas ou desmarcadas como um caso especial, enquanto readOnly
está definido como true
e o editor não poderá ser editado de outra forma.
autoFocus
Quando definido true
junto com readOnly
definido como false
, o foco é automaticamente no final do documento.
maxLength
Quando definido impõe um comprimento máximo de caracteres no documento, sem incluir a sintaxe de redução.
extensions
Permite que plug-ins adicionais do Prosemirror sejam passados para a instância subjacente do Prosemirror.
disableExtensions
Lista de nomes de extensões incluídas para desabilitar. Remove itens de menu e comandos correspondentes. Por exemplo, defina como ["em", "blockquote"]
para desativar o texto em itálico e aspas.
theme
Permite substituir o tema embutido para marcar o editor, por exemplo, use sua própria fonte e cores de marca para que o editor se ajuste ao seu aplicativo. Veja o tema embutido para ver um exemplo das chaves que devem ser fornecidas.
dictionary
Permite substituir o dicionário de cópia embutido, por exemplo, para internacionalizar o editor. Consulte o dicionário embutido para obter um exemplo das chaves que devem ser fornecidas.
dark
Com dark
definido como true
o editor usará um tema escuro padrão incluído. Veja a fonte aqui.
dir
Padrão: auto
Controla a direção do documento. Os valores possíveis são:
ltr
: o layout do editor é otimizado para documentos LTR e o conteúdo é explicitamente marcado como LTR.rtl
: O layout do editor é otimizado para documentos RTL e o conteúdo é explicitamente marcado como RTL.auto
: o layout do editor é decidido pelo navegador com base no conteúdo do documento. tooltip
Um componente React que envolverá itens que possuem uma dica de ferramenta opcional. Você pode usar isso para injetar sua própria biblioteca de dicas de ferramentas no editor – o componente receberá os seguintes adereços:
tooltip
: um nó React com o conteúdo da dica de ferramentaplacement
: Enum top
, bottom
, left
, right
children
: o componente que a dica de ferramenta envolve deve ser renderizado headingsOffset
Um número que compensará os títulos do documento em vários níveis. Por exemplo, se você já aninhar o editor sob um título h1
principal, você pode querer que o usuário só possa criar títulos h2
e abaixo, neste caso você definiria a propriedade como 1
.
scrollTo
Uma string representando uma âncora de título – o documento irá rolar suavemente para que o título fique visível na janela de visualização.
embeds
Opcionalmente, defina incorporações que serão inseridas no lugar dos links quando a função matcher
retornar um valor verdadeiro. O valor de retorno do método matcher estará disponível no componente em props.attrs.matches
. Se title
e icon
forem fornecidos, a incorporação também aparecerá no menu de bloqueio.
< Editor
embeds = { [
{
title : "Google Doc" ,
keywords : "google docs gdocs" ,
icon : < GoogleDocIcon /> ,
defaultHidden : false ,
matcher : href => href . matches ( / docs.google.com / i ) ,
component : GoogleDocEmbed
}
] }
/>
uploadImage(file: Blob): Promise<string>
Se você deseja que o editor suporte imagens, esse retorno de chamada deve ser fornecido. O retorno de chamada deve aceitar um único objeto File
e retornar uma promessa que resolve para um URL quando a imagem for carregada em um local de armazenamento, por exemplo, S3. por exemplo:
< Editor
uploadImage = { async file => {
const result = await s3 . upload ( file ) ;
return result . url ;
} }
/>
onBlur(): void
Esse retorno de chamada é acionado quando o usuário perde o foco no conteúdo editável do editor e em todos os elementos da interface do usuário associados, como o menu de bloco e as barras de ferramentas flutuantes. Se você quiser ouvir eventos de desfoque apenas na área editável de conteúdo, use os adereços handleDOMEvents
.
onFocus(): void
Esse retorno de chamada é acionado quando o usuário ganha foco no conteúdo editável do editor ou em qualquer elemento de interface do usuário associado, como o menu de bloco ou barras de ferramentas flutuantes. Se você deseja ouvir eventos de foco apenas na área editável por conteúdo, use os adereços handleDOMEvents
.
onSave({ done: boolean }): void
Esse retorno de chamada é acionado quando o usuário solicita explicitamente para salvar usando um atalho de teclado, Cmd+S
ou Cmd+Enter
. Você pode usar isso como um sinal para salvar o documento em um servidor remoto.
onCancel(): void
Este retorno de chamada é acionado quando Cmd+Escape
é atingido no editor. Você pode usá-lo para cancelar a edição.
onChange(() => value): void
Esse retorno de chamada é acionado quando o conteúdo do editor é alterado, geralmente devido a uma entrada do usuário, como um pressionamento de tecla ou o uso de opções de formatação. Você pode usar isso para persistir localmente o estado dos editores.
Ele retorna uma função que quando chamada retorna o valor do texto atual do documento. Essa otimização é feita para evitar a serialização do estado do documento em texto em cada evento de alteração, permitindo que o aplicativo host escolha quando precisa do valor serializado.
onImageUploadStart(): void
Esse retorno de chamada é acionado antes de uploadImage
e pode ser usado para mostrar alguma IU que indica que um upload está em andamento.
onImageUploadStop(): void
Acionado quando o upload de uma imagem foi bem-sucedido ou falhou.
onSearchLink(term: string): Promise<{ title: string, subtitle?: string, url: string }[]>
O editor oferece a capacidade de pesquisar links para inserir na barra de ferramentas de formatação. Se esse retorno de chamada for fornecido, ele deverá aceitar um termo de pesquisa como único parâmetro e retornar uma promessa que resolve para uma matriz de objetos. por exemplo:
< Editor
onSearchLink = { async searchTerm => {
const results = await MyAPI . search ( searchTerm ) ;
return results . map ( result => {
title : result . name ,
subtitle : `Created ${ result . createdAt } ` ,
url : result . url
} )
} }
/>
onCreateLink(title: string): Promise<string>
O editor oferece a capacidade de criar links a partir da barra de ferramentas de formatação para criação imediata de documentos. Se esse retorno de chamada for fornecido, ele deverá aceitar um link "título" como único parâmetro e retornar uma promessa que resolva uma URL para o link criado, por exemplo:
< Editor
onCreateLink = { async title => {
const url = await MyAPI . create ( {
title
} ) ;
return url ;
} }
/>
onShowToast(message: string, type: ToastType): void
Disparado quando o editor deseja mostrar uma mensagem ao usuário. Conecte-se ao sistema de notificação do seu aplicativo ou use de forma simplista window.alert(message)
. O segundo parâmetro é o tipo de brinde: 'error' ou 'info'.
onClickLink(href: string, event: MouseEvent): void
Este retorno de chamada permite substituir o tratamento do link. Muitas vezes você deseja que links externos abram uma nova janela e que links internos usem algo como react-router
para navegar. Se nenhum retorno de chamada for fornecido, o comportamento padrão de abrir uma nova guia será aplicado a todos os links. por exemplo:
import { history } from "react-router" ;
< Editor
onClickLink = { ( href , event ) => {
if ( isInternalLink ( href ) ) {
history . push ( href ) ;
} else {
window . location . href = href ;
}
} }
/>
onHoverLink(event: MouseEvent): boolean
Este retorno de chamada permite detectar quando o usuário passa o mouse sobre um link no documento.
< Editor
onHoverLink = { event => {
console . log ( `Hovered link ${ event . target . href } ` ) ;
} }
/>
onClickHashtag(tag: string, event: MouseEvent): void
Este retorno de chamada permite lidar com cliques em hashtags no texto do documento. Se nenhum retorno de chamada for fornecido, as hashtags serão renderizadas como texto normal, então você pode escolher se deseja apoiá-las ou não, passando esta propriedade.
import { history } from "react-router" ;
< Editor
onClickHashtag = { tag => {
history . push ( `/hashtags/ ${ tag } ` ) ;
} }
/>
handleDOMEvents: {[name: string]: (view: EditorView, event: Event) => boolean;}
Este objeto mapeia nomes de eventos ( focus
, paste
, touchstart
, etc.) para funções de retorno de chamada.
< Editor
handleDOMEvents = { {
focus : ( ) => console . log ( "FOCUS" ) ,
blur : ( ) => console . log ( "BLUR" ) ,
paste : ( ) => console . log ( "PASTE" ) ,
touchstart : ( ) => console . log ( "TOUCH START" ) ,
} }
/>
O componente Editor expõe alguns métodos para interagir com o editor montado.
focusAtStart(): void
Coloque o cursor no início do documento e foque-o.
focusAtEnd(): void
Coloque o cursor no final do documento e foque-o.
getHeadings(): { title: string, level: number, id: string }[]
Retorna uma matriz de objetos com o conteúdo de texto de todos os títulos do documento, seu nível na hierarquia e o ID da âncora. Isso é útil para construir seu próprio índice, já que a opção toc
foi removida na v10.
Este projeto usa fio para gerenciar dependências. Você pode usar o npm, mas ele não respeitará o arquivo de bloqueio do fio e poderá instalar versões ligeiramente diferentes.
yarn install
Ao executar em desenvolvimento, o Storybook é incluído em editores de exemplo com recarga a quente. Depois de instalar as dependências, execute yarn start
para prosseguir.
Ao desenvolver usando yarn link
, você pode usar yarn watch
para reconstruir continuamente as alterações em dist
conforme você faz alterações.
Este projeto é licenciado pelo BSD.