add core extensions
This commit is contained in:
@@ -16,7 +16,7 @@ import ExtensionManager from './ExtensionManager'
|
|||||||
import EventEmitter from './EventEmitter'
|
import EventEmitter from './EventEmitter'
|
||||||
import { Extensions, UnionToIntersection, PickValue } from './types'
|
import { Extensions, UnionToIntersection, PickValue } from './types'
|
||||||
import defaultPlugins from './plugins'
|
import defaultPlugins from './plugins'
|
||||||
import * as coreCommands from './commands'
|
import * as extensions from './extensions'
|
||||||
import style from './style'
|
import style from './style'
|
||||||
|
|
||||||
export type Command = (props: {
|
export type Command = (props: {
|
||||||
@@ -56,7 +56,7 @@ interface HTMLElement {
|
|||||||
interface EditorOptions {
|
interface EditorOptions {
|
||||||
element: Element,
|
element: Element,
|
||||||
content: EditorContent,
|
content: EditorContent,
|
||||||
extensions: Extensions[],
|
extensions: Extensions,
|
||||||
injectCSS: boolean,
|
injectCSS: boolean,
|
||||||
autoFocus: 'start' | 'end' | number | boolean | null,
|
autoFocus: 'start' | 'end' | number | boolean | null,
|
||||||
editable: boolean,
|
editable: boolean,
|
||||||
@@ -110,7 +110,7 @@ export class Editor extends EventEmitter {
|
|||||||
this.createExtensionManager()
|
this.createExtensionManager()
|
||||||
this.createSchema()
|
this.createSchema()
|
||||||
this.createView()
|
this.createView()
|
||||||
this.registerCommands(coreCommands)
|
// this.registerCommands(coreCommands)
|
||||||
this.injectCSS()
|
this.injectCSS()
|
||||||
|
|
||||||
window.setTimeout(() => this.proxy.focus(this.options.autoFocus), 0)
|
window.setTimeout(() => this.proxy.focus(this.options.autoFocus), 0)
|
||||||
@@ -226,7 +226,10 @@ export class Editor extends EventEmitter {
|
|||||||
* Creates an extension manager.
|
* Creates an extension manager.
|
||||||
*/
|
*/
|
||||||
private createExtensionManager() {
|
private createExtensionManager() {
|
||||||
this.extensionManager = new ExtensionManager(this.options.extensions, this.proxy)
|
const coreExtensions = Object.entries(extensions).map(([, extension]) => extension())
|
||||||
|
const allExtensions = [...coreExtensions, ...this.options.extensions]
|
||||||
|
|
||||||
|
this.extensionManager = new ExtensionManager(allExtensions, this.proxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,11 +4,6 @@ import { Editor } from './Editor'
|
|||||||
import { GlobalAttributes } from './types'
|
import { GlobalAttributes } from './types'
|
||||||
|
|
||||||
export interface ExtensionSpec<Options = {}, Commands = {}> {
|
export interface ExtensionSpec<Options = {}, Commands = {}> {
|
||||||
/**
|
|
||||||
* The name of your extension
|
|
||||||
*/
|
|
||||||
name: string,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default options
|
* Default options
|
||||||
*/
|
*/
|
||||||
@@ -84,7 +79,6 @@ export type Extension = Required<Omit<ExtensionSpec, 'defaultOptions'> & {
|
|||||||
*/
|
*/
|
||||||
export const defaultExtension: Extension = {
|
export const defaultExtension: Extension = {
|
||||||
type: 'extension',
|
type: 'extension',
|
||||||
name: 'extension',
|
|
||||||
options: {},
|
options: {},
|
||||||
addGlobalAttributes: () => [],
|
addGlobalAttributes: () => [],
|
||||||
addCommands: () => ({}),
|
addCommands: () => ({}),
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { Command } from '../Editor'
|
|
||||||
|
|
||||||
type BlurCommand = () => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
blur: BlurCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const blur: BlurCommand = () => ({ view }) => {
|
|
||||||
const element = view.dom as HTMLElement
|
|
||||||
|
|
||||||
element.blur()
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { Command } from '../Editor'
|
|
||||||
|
|
||||||
type ClearContentCommand = (emitUpdate?: Boolean) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
clearContent: ClearContentCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const clearContent: ClearContentCommand = (emitUpdate = false) => ({ commands }) => {
|
|
||||||
return commands.setContent('', emitUpdate)
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { deleteSelection as originalDeleteSelection } from 'prosemirror-commands'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
|
|
||||||
type DeleteSelectionCommand = () => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
deleteSelection: DeleteSelectionCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const deleteSelection: DeleteSelectionCommand = () => ({ state, dispatch }) => {
|
|
||||||
return originalDeleteSelection(state, dispatch)
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
export { blur } from './blur'
|
|
||||||
export { clearContent } from './clearContent'
|
|
||||||
export { deleteSelection } from './deleteSelection'
|
|
||||||
export { focus } from './focus'
|
|
||||||
export { insertHTML } from './insertHTML'
|
|
||||||
export { insertText } from './insertText'
|
|
||||||
export { liftListItem } from './liftListItem'
|
|
||||||
export { removeMark } from './removeMark'
|
|
||||||
export { removeMarks } from './removeMarks'
|
|
||||||
export { scrollIntoView } from './scrollIntoView'
|
|
||||||
export { selectAll } from './selectAll'
|
|
||||||
export { selectParentNode } from './selectParentNode'
|
|
||||||
export { setBlockType } from './setBlockType'
|
|
||||||
export { setContent } from './setContent'
|
|
||||||
export { sinkListItem } from './sinkListItem'
|
|
||||||
export { splitListItem } from './splitListItem'
|
|
||||||
export { toggleBlockType } from './toggleBlockType'
|
|
||||||
export { toggleList } from './toggleList'
|
|
||||||
export { toggleMark } from './toggleMark'
|
|
||||||
export { updateMark } from './updateMark'
|
|
||||||
export { toggleWrap } from './toggleWrap'
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { Command } from '../Editor'
|
|
||||||
|
|
||||||
type InsertTextCommand = (value: string) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
insertText: InsertTextCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const insertText: InsertTextCommand = value => ({ tr }) => {
|
|
||||||
tr.insertText(value)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { liftListItem as originalLiftListItem } from 'prosemirror-schema-list'
|
|
||||||
import { NodeType } from 'prosemirror-model'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
import getNodeType from '../utils/getNodeType'
|
|
||||||
|
|
||||||
type LiftListItem = (typeOrName: string | NodeType) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
liftListItem: LiftListItem,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const liftListItem: LiftListItem = typeOrName => ({ state, dispatch }) => {
|
|
||||||
const type = getNodeType(typeOrName, state.schema)
|
|
||||||
|
|
||||||
return originalLiftListItem(type)(state, dispatch)
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import { MarkType } from 'prosemirror-model'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
import getMarkType from '../utils/getMarkType'
|
|
||||||
import getMarkRange from '../utils/getMarkRange'
|
|
||||||
|
|
||||||
type RemoveMarkCommand = (typeOrName: string | MarkType) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
removeMark: RemoveMarkCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const removeMark: RemoveMarkCommand = typeOrName => ({ tr, state }) => {
|
|
||||||
const { selection } = tr
|
|
||||||
const type = getMarkType(typeOrName, state.schema)
|
|
||||||
let { from, to } = selection
|
|
||||||
const { $from, empty } = selection
|
|
||||||
|
|
||||||
if (empty) {
|
|
||||||
const range = getMarkRange($from, type)
|
|
||||||
|
|
||||||
if (range) {
|
|
||||||
from = range.from
|
|
||||||
to = range.to
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.removeMark(from, to, type)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { Command } from '../Editor'
|
|
||||||
|
|
||||||
type RemoveMarksCommand = () => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
removeMarks: RemoveMarksCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const removeMarks: RemoveMarksCommand = () => ({ tr, state }) => {
|
|
||||||
const { selection } = tr
|
|
||||||
const { from, to, empty } = selection
|
|
||||||
|
|
||||||
if (empty) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
Object
|
|
||||||
.entries(state.schema.marks)
|
|
||||||
.forEach(([, mark]) => {
|
|
||||||
tr.removeMark(from, to, mark as any)
|
|
||||||
})
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { Command } from '../Editor'
|
|
||||||
|
|
||||||
type ScrollIntoViewCommand = () => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
scrollIntoView: ScrollIntoViewCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const scrollIntoView: ScrollIntoViewCommand = () => ({ tr }) => {
|
|
||||||
tr.scrollIntoView()
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { selectAll as originalSelectAll } from 'prosemirror-commands'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
|
|
||||||
type SelectAllCommand = () => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
selectAll: SelectAllCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const selectAll: SelectAllCommand = () => ({ state, dispatch }) => {
|
|
||||||
return originalSelectAll(state, dispatch)
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { selectParentNode as originalSelectParentNode } from 'prosemirror-commands'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
|
|
||||||
type SelectParentNodeCommand = () => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
selectParentNode: SelectParentNodeCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const selectParentNode: SelectParentNodeCommand = () => ({ state, dispatch }) => {
|
|
||||||
return originalSelectParentNode(state, dispatch)
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import { NodeType } from 'prosemirror-model'
|
|
||||||
import { setBlockType as originalSetBlockType } from 'prosemirror-commands'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
import getNodeType from '../utils/getNodeType'
|
|
||||||
|
|
||||||
type SetBlockTypeCommand = (
|
|
||||||
typeOrName: string | NodeType,
|
|
||||||
attrs?: {},
|
|
||||||
) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
setBlockType: SetBlockTypeCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const setBlockType: SetBlockTypeCommand = (typeOrName, attrs = {}) => ({ state, dispatch }) => {
|
|
||||||
const type = getNodeType(typeOrName, state.schema)
|
|
||||||
|
|
||||||
return originalSetBlockType(type, attrs)(state, dispatch)
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import { TextSelection } from 'prosemirror-state'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
|
|
||||||
type SetContentCommand = (
|
|
||||||
content: string,
|
|
||||||
emitUpdate?: Boolean,
|
|
||||||
parseOptions?: any,
|
|
||||||
) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
setContent: SetContentCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const setContent: SetContentCommand = (content = '', emitUpdate = false, parseOptions = {}) => ({ tr, editor }) => {
|
|
||||||
const { createDocument } = editor
|
|
||||||
const { doc } = tr
|
|
||||||
const document = createDocument(content, parseOptions)
|
|
||||||
const selection = TextSelection.create(doc, 0, doc.content.size)
|
|
||||||
|
|
||||||
tr.setSelection(selection)
|
|
||||||
.replaceSelectionWith(document, false)
|
|
||||||
.setMeta('preventUpdate', !emitUpdate)
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { sinkListItem as originalSinkListItem } from 'prosemirror-schema-list'
|
|
||||||
import { NodeType } from 'prosemirror-model'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
import getNodeType from '../utils/getNodeType'
|
|
||||||
|
|
||||||
type SinkListItem = (typeOrName: string | NodeType) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
sinkListItem: SinkListItem,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sinkListItem: SinkListItem = typeOrName => ({ state, dispatch }) => {
|
|
||||||
const type = getNodeType(typeOrName, state.schema)
|
|
||||||
|
|
||||||
return originalSinkListItem(type)(state, dispatch)
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { splitListItem as originalSplitListItem } from 'prosemirror-schema-list'
|
|
||||||
import { NodeType } from 'prosemirror-model'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
import getNodeType from '../utils/getNodeType'
|
|
||||||
|
|
||||||
type SplitListItem = (typeOrName: string | NodeType) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
splitListItem: SplitListItem,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const splitListItem: SplitListItem = typeOrName => ({ state, dispatch }) => {
|
|
||||||
const type = getNodeType(typeOrName, state.schema)
|
|
||||||
|
|
||||||
return originalSplitListItem(type)(state, dispatch)
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
import { NodeType } from 'prosemirror-model'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
import nodeIsActive from '../utils/nodeIsActive'
|
|
||||||
import getNodeType from '../utils/getNodeType'
|
|
||||||
|
|
||||||
type ToggleBlockTypeCommand = (
|
|
||||||
typeOrName: string | NodeType,
|
|
||||||
toggleType: string | NodeType,
|
|
||||||
attrs?: {}
|
|
||||||
) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
toggleBlockType: ToggleBlockTypeCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const toggleBlockType: ToggleBlockTypeCommand = (typeOrName, toggleTypeOrName, attrs = {}) => ({ state, commands }) => {
|
|
||||||
const type = getNodeType(typeOrName, state.schema)
|
|
||||||
const toggleType = getNodeType(toggleTypeOrName, state.schema)
|
|
||||||
const isActive = nodeIsActive(state, type, attrs)
|
|
||||||
|
|
||||||
if (isActive) {
|
|
||||||
return commands.setBlockType(toggleType)
|
|
||||||
}
|
|
||||||
|
|
||||||
return commands.setBlockType(type, attrs)
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
import { wrapInList, liftListItem } from 'prosemirror-schema-list'
|
|
||||||
import { findParentNode } from 'prosemirror-utils'
|
|
||||||
import { Node, NodeType, Schema } from 'prosemirror-model'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
import getNodeType from '../utils/getNodeType'
|
|
||||||
|
|
||||||
type ToggleListCommand = (
|
|
||||||
listType: string | NodeType,
|
|
||||||
itemType: string | NodeType,
|
|
||||||
) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
toggleList: ToggleListCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isList(node: Node, schema: Schema) {
|
|
||||||
return (node.type === schema.nodes.bullet_list
|
|
||||||
|| node.type === schema.nodes.ordered_list
|
|
||||||
|| node.type === schema.nodes.todo_list)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const toggleList: ToggleListCommand = (listTypeOrName, itemTypeOrName) => ({ tr, state, dispatch }) => {
|
|
||||||
const listType = getNodeType(listTypeOrName, state.schema)
|
|
||||||
const itemType = getNodeType(itemTypeOrName, state.schema)
|
|
||||||
const { schema, selection } = state
|
|
||||||
const { $from, $to } = selection
|
|
||||||
const range = $from.blockRange($to)
|
|
||||||
|
|
||||||
if (!range) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const parentList = findParentNode(node => isList(node, schema))(selection)
|
|
||||||
|
|
||||||
if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {
|
|
||||||
if (parentList.node.type === listType) {
|
|
||||||
return liftListItem(itemType)(state, dispatch)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isList(parentList.node, schema) && listType.validContent(parentList.node.content)) {
|
|
||||||
tr.setNodeMarkup(parentList.pos, listType)
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return wrapInList(listType)(state, dispatch)
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { toggleMark as originalToggleMark } from 'prosemirror-commands'
|
|
||||||
import { MarkType } from 'prosemirror-model'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
import getMarkType from '../utils/getMarkType'
|
|
||||||
|
|
||||||
type ToggleMarkCommand = (typeOrName: string | MarkType) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
toggleMark: ToggleMarkCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const toggleMark: ToggleMarkCommand = typeOrName => ({ state, dispatch }) => {
|
|
||||||
const type = getMarkType(typeOrName, state.schema)
|
|
||||||
|
|
||||||
return originalToggleMark(type)(state, dispatch)
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
import { wrapIn, lift } from 'prosemirror-commands'
|
|
||||||
import { NodeType } from 'prosemirror-model'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
import nodeIsActive from '../utils/nodeIsActive'
|
|
||||||
import getNodeType from '../utils/getNodeType'
|
|
||||||
|
|
||||||
type ToggleWrapCommand = (typeOrName: string | NodeType, attrs?: {}) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
toggleWrap: ToggleWrapCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const toggleWrap: ToggleWrapCommand = (typeOrName, attrs) => ({
|
|
||||||
state, dispatch,
|
|
||||||
}) => {
|
|
||||||
const type = getNodeType(typeOrName, state.schema)
|
|
||||||
const isActive = nodeIsActive(state, type, attrs)
|
|
||||||
|
|
||||||
if (isActive) {
|
|
||||||
return lift(state, dispatch)
|
|
||||||
}
|
|
||||||
|
|
||||||
return wrapIn(type, attrs)(state, dispatch)
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
import { MarkType } from 'prosemirror-model'
|
|
||||||
import { Command } from '../Editor'
|
|
||||||
import getMarkType from '../utils/getMarkType'
|
|
||||||
import getMarkRange from '../utils/getMarkRange'
|
|
||||||
|
|
||||||
type UpdateMarkCommand = (
|
|
||||||
typeOrName: string | MarkType,
|
|
||||||
attrs: {},
|
|
||||||
) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
updateMark: UpdateMarkCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const updateMark: UpdateMarkCommand = (typeOrName, attrs = {}) => ({ tr, state }) => {
|
|
||||||
const { selection, doc } = tr
|
|
||||||
let { from, to } = selection
|
|
||||||
const { $from, empty } = selection
|
|
||||||
const type = getMarkType(typeOrName, state.schema)
|
|
||||||
|
|
||||||
if (empty) {
|
|
||||||
const range = getMarkRange($from, type)
|
|
||||||
|
|
||||||
if (range) {
|
|
||||||
from = range.from
|
|
||||||
to = range.to
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasMark = doc.rangeHasMark(from, to, type)
|
|
||||||
|
|
||||||
if (hasMark) {
|
|
||||||
tr.removeMark(from, to, type)
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.addMark(from, to, type.create(attrs))
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
22
packages/core/src/extensions/blur.ts
Normal file
22
packages/core/src/extensions/blur.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
|
||||||
|
export const Blur = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
blur: (): Command => ({ view }) => {
|
||||||
|
const element = view.dom as HTMLElement
|
||||||
|
|
||||||
|
element.blur()
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
Blur: typeof Blur,
|
||||||
|
}
|
||||||
|
}
|
||||||
18
packages/core/src/extensions/clearContent.ts
Normal file
18
packages/core/src/extensions/clearContent.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
|
||||||
|
export const ClearContent = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
clearContent: (emitUpdate: Boolean = false): Command => ({ commands }) => {
|
||||||
|
return commands.setContent('', emitUpdate)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
ClearContent: typeof ClearContent,
|
||||||
|
}
|
||||||
|
}
|
||||||
19
packages/core/src/extensions/deleteSelection.ts
Normal file
19
packages/core/src/extensions/deleteSelection.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { deleteSelection as originalDeleteSelection } from 'prosemirror-commands'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
|
||||||
|
export const DeleteSelection = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
deleteSelection: (): Command => ({ state, dispatch }) => {
|
||||||
|
return originalDeleteSelection(state, dispatch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
DeleteSelection: typeof DeleteSelection,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,9 @@
|
|||||||
import { TextSelection } from 'prosemirror-state'
|
import { TextSelection } from 'prosemirror-state'
|
||||||
import { Editor, Command } from '../Editor'
|
import { Editor, Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
import minMax from '../utils/minMax'
|
import minMax from '../utils/minMax'
|
||||||
|
|
||||||
type Position = 'start' | 'end' | number | boolean | null
|
type Position = 'start' | 'end' | number | boolean | null
|
||||||
type FocusCommand = (position?: Position) => Command
|
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
focus: FocusCommand
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ResolvedSelection {
|
interface ResolvedSelection {
|
||||||
from: number,
|
from: number,
|
||||||
@@ -43,19 +37,31 @@ function resolveSelection(editor: Editor, position: Position = null): ResolvedSe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const focus: FocusCommand = (position = null) => ({ editor, view, tr }) => {
|
export const Focus = createExtension({
|
||||||
if ((view.hasFocus() && position === null) || position === false) {
|
addCommands() {
|
||||||
return true
|
return {
|
||||||
|
focus: (position: Position = null): Command => ({ editor, view, tr }) => {
|
||||||
|
if ((view.hasFocus() && position === null) || position === false) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const { from, to } = resolveSelection(editor, position)
|
||||||
|
const { doc } = tr
|
||||||
|
const resolvedFrom = minMax(from, 0, doc.content.size)
|
||||||
|
const resolvedEnd = minMax(to, 0, doc.content.size)
|
||||||
|
const selection = TextSelection.create(doc, resolvedFrom, resolvedEnd)
|
||||||
|
|
||||||
|
tr.setSelection(selection)
|
||||||
|
view.focus()
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
Focus: typeof Focus,
|
||||||
}
|
}
|
||||||
|
|
||||||
const { from, to } = resolveSelection(editor, position)
|
|
||||||
const { doc } = tr
|
|
||||||
const resolvedFrom = minMax(from, 0, doc.content.size)
|
|
||||||
const resolvedEnd = minMax(to, 0, doc.content.size)
|
|
||||||
const selection = TextSelection.create(doc, resolvedFrom, resolvedEnd)
|
|
||||||
|
|
||||||
tr.setSelection(selection)
|
|
||||||
view.focus()
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
21
packages/core/src/extensions/index.ts
Normal file
21
packages/core/src/extensions/index.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
export { Blur } from './blur'
|
||||||
|
export { ClearContent } from './clearContent'
|
||||||
|
export { DeleteSelection } from './deleteSelection'
|
||||||
|
export { Focus } from './focus'
|
||||||
|
export { InsertHTML } from './insertHTML'
|
||||||
|
export { InsertText } from './insertText'
|
||||||
|
export { LiftListItem } from './liftListItem'
|
||||||
|
export { RemoveMark } from './removeMark'
|
||||||
|
export { RemoveMarks } from './removeMarks'
|
||||||
|
export { ScrollIntoView } from './scrollIntoView'
|
||||||
|
export { SelectAll } from './selectAll'
|
||||||
|
export { SelectParentNode } from './selectParentNode'
|
||||||
|
export { SetBlockType } from './setBlockType'
|
||||||
|
export { SetContent } from './setContent'
|
||||||
|
export { SinkListItem } from './sinkListItem'
|
||||||
|
export { SplitListItem } from './splitListItem'
|
||||||
|
export { ToggleBlockType } from './toggleBlockType'
|
||||||
|
export { ToggleList } from './toggleList'
|
||||||
|
export { ToggleMark } from './toggleMark'
|
||||||
|
export { UpdateMark } from './updateMark'
|
||||||
|
export { ToggleWrap } from './toggleWrap'
|
||||||
@@ -1,16 +1,9 @@
|
|||||||
import { DOMParser } from 'prosemirror-model'
|
import { DOMParser } from 'prosemirror-model'
|
||||||
import { Selection, Transaction } from 'prosemirror-state'
|
import { Selection, Transaction } from 'prosemirror-state'
|
||||||
import { ReplaceStep, ReplaceAroundStep } from 'prosemirror-transform'
|
import { ReplaceStep, ReplaceAroundStep } from 'prosemirror-transform'
|
||||||
import { Command } from '../Editor'
|
|
||||||
import elementFromString from '../utils/elementFromString'
|
import elementFromString from '../utils/elementFromString'
|
||||||
|
import { Command } from '../Editor'
|
||||||
type InsertHTMLCommand = (value: string) => Command
|
import { createExtension } from '../Extension'
|
||||||
|
|
||||||
declare module '../Editor' {
|
|
||||||
interface Commands {
|
|
||||||
insertHTML: InsertHTMLCommand,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: move to utils
|
// TODO: move to utils
|
||||||
// https://github.com/ProseMirror/prosemirror-state/blob/master/src/selection.js#L466
|
// https://github.com/ProseMirror/prosemirror-state/blob/master/src/selection.js#L466
|
||||||
@@ -25,13 +18,25 @@ function selectionToInsertionEnd(tr: Transaction, startLen: number, bias: number
|
|||||||
tr.setSelection(Selection.near(tr.doc.resolve(end as unknown as number), bias))
|
tr.setSelection(Selection.near(tr.doc.resolve(end as unknown as number), bias))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const insertHTML: InsertHTMLCommand = value => ({ tr, state }) => {
|
export const InsertHTML = createExtension({
|
||||||
const { selection } = tr
|
addCommands() {
|
||||||
const element = elementFromString(value)
|
return {
|
||||||
const slice = DOMParser.fromSchema(state.schema).parseSlice(element)
|
insertHTML: (value: string): Command => ({ tr, state }) => {
|
||||||
|
const { selection } = tr
|
||||||
|
const element = elementFromString(value)
|
||||||
|
const slice = DOMParser.fromSchema(state.schema).parseSlice(element)
|
||||||
|
|
||||||
tr.insert(selection.anchor, slice.content)
|
tr.insert(selection.anchor, slice.content)
|
||||||
selectionToInsertionEnd(tr, tr.steps.length - 1, -1)
|
selectionToInsertionEnd(tr, tr.steps.length - 1, -1)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
InsertHTML: typeof InsertHTML,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
20
packages/core/src/extensions/insertText.ts
Normal file
20
packages/core/src/extensions/insertText.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
|
||||||
|
export const InsertText = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
insertText: (value: string): Command => ({ tr }) => {
|
||||||
|
tr.insertText(value)
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
InsertText: typeof InsertText,
|
||||||
|
}
|
||||||
|
}
|
||||||
23
packages/core/src/extensions/liftListItem.ts
Normal file
23
packages/core/src/extensions/liftListItem.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { liftListItem as originalLiftListItem } from 'prosemirror-schema-list'
|
||||||
|
import { NodeType } from 'prosemirror-model'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
import getNodeType from '../utils/getNodeType'
|
||||||
|
|
||||||
|
export const LiftListItem = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
liftListItem: (typeOrName: string | NodeType): Command => ({ state, dispatch }) => {
|
||||||
|
const type = getNodeType(typeOrName, state.schema)
|
||||||
|
|
||||||
|
return originalLiftListItem(type)(state, dispatch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
LiftListItem: typeof LiftListItem,
|
||||||
|
}
|
||||||
|
}
|
||||||
37
packages/core/src/extensions/removeMark.ts
Normal file
37
packages/core/src/extensions/removeMark.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { MarkType } from 'prosemirror-model'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
import getMarkType from '../utils/getMarkType'
|
||||||
|
import getMarkRange from '../utils/getMarkRange'
|
||||||
|
|
||||||
|
export const RemoveMark = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
removeMark: (typeOrName: string | MarkType): Command => ({ tr, state }) => {
|
||||||
|
const { selection } = tr
|
||||||
|
const type = getMarkType(typeOrName, state.schema)
|
||||||
|
let { from, to } = selection
|
||||||
|
const { $from, empty } = selection
|
||||||
|
|
||||||
|
if (empty) {
|
||||||
|
const range = getMarkRange($from, type)
|
||||||
|
|
||||||
|
if (range) {
|
||||||
|
from = range.from
|
||||||
|
to = range.to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.removeMark(from, to, type)
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
RemoveMark: typeof RemoveMark,
|
||||||
|
}
|
||||||
|
}
|
||||||
31
packages/core/src/extensions/removeMarks.ts
Normal file
31
packages/core/src/extensions/removeMarks.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
|
||||||
|
export const RemoveMarks = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
removeMarks: (): Command => ({ tr, state }) => {
|
||||||
|
const { selection } = tr
|
||||||
|
const { from, to, empty } = selection
|
||||||
|
|
||||||
|
if (empty) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
Object
|
||||||
|
.entries(state.schema.marks)
|
||||||
|
.forEach(([, mark]) => {
|
||||||
|
tr.removeMark(from, to, mark as any)
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
RemoveMarks: typeof RemoveMarks,
|
||||||
|
}
|
||||||
|
}
|
||||||
20
packages/core/src/extensions/scrollIntoView.ts
Normal file
20
packages/core/src/extensions/scrollIntoView.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
|
||||||
|
export const ScrollIntoView = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
scrollIntoView: (): Command => ({ tr }) => {
|
||||||
|
tr.scrollIntoView()
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
ScrollIntoView: typeof ScrollIntoView,
|
||||||
|
}
|
||||||
|
}
|
||||||
19
packages/core/src/extensions/selectAll.ts
Normal file
19
packages/core/src/extensions/selectAll.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { selectAll as originalSelectAll } from 'prosemirror-commands'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
|
||||||
|
export const SelectAll = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
selectAll: (): Command => ({ state, dispatch }) => {
|
||||||
|
return originalSelectAll(state, dispatch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
SelectAll: typeof SelectAll,
|
||||||
|
}
|
||||||
|
}
|
||||||
19
packages/core/src/extensions/selectParentNode.ts
Normal file
19
packages/core/src/extensions/selectParentNode.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { selectParentNode as originalSelectParentNode } from 'prosemirror-commands'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
|
||||||
|
export const SelectParentNode = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
selectParentNode: (): Command => ({ state, dispatch }) => {
|
||||||
|
return originalSelectParentNode(state, dispatch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
SelectParentNode: typeof SelectParentNode,
|
||||||
|
}
|
||||||
|
}
|
||||||
23
packages/core/src/extensions/setBlockType.ts
Normal file
23
packages/core/src/extensions/setBlockType.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { NodeType } from 'prosemirror-model'
|
||||||
|
import { setBlockType as originalSetBlockType } from 'prosemirror-commands'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
import getNodeType from '../utils/getNodeType'
|
||||||
|
|
||||||
|
export const SetBlockType = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
setBlockType: (typeOrName: string | NodeType, attrs = {}): Command => ({ state, dispatch }) => {
|
||||||
|
const type = getNodeType(typeOrName, state.schema)
|
||||||
|
|
||||||
|
return originalSetBlockType(type, attrs)(state, dispatch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
SetBlockType: typeof SetBlockType,
|
||||||
|
}
|
||||||
|
}
|
||||||
28
packages/core/src/extensions/setContent.ts
Normal file
28
packages/core/src/extensions/setContent.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { TextSelection } from 'prosemirror-state'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
|
||||||
|
export const SetContent = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
setContent: (content: string, emitUpdate: Boolean = false, parseOptions = {}): Command => ({ tr, editor }) => {
|
||||||
|
const { createDocument } = editor
|
||||||
|
const { doc } = tr
|
||||||
|
const document = createDocument(content, parseOptions)
|
||||||
|
const selection = TextSelection.create(doc, 0, doc.content.size)
|
||||||
|
|
||||||
|
tr.setSelection(selection)
|
||||||
|
.replaceSelectionWith(document, false)
|
||||||
|
.setMeta('preventUpdate', !emitUpdate)
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
SetContent: typeof SetContent,
|
||||||
|
}
|
||||||
|
}
|
||||||
23
packages/core/src/extensions/sinkListItem.ts
Normal file
23
packages/core/src/extensions/sinkListItem.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { sinkListItem as originalSinkListItem } from 'prosemirror-schema-list'
|
||||||
|
import { NodeType } from 'prosemirror-model'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
import getNodeType from '../utils/getNodeType'
|
||||||
|
|
||||||
|
export const SinkListItem = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
sinkListItem: (typeOrName: string | NodeType): Command => ({ state, dispatch }) => {
|
||||||
|
const type = getNodeType(typeOrName, state.schema)
|
||||||
|
|
||||||
|
return originalSinkListItem(type)(state, dispatch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
SinkListItem: typeof SinkListItem,
|
||||||
|
}
|
||||||
|
}
|
||||||
23
packages/core/src/extensions/splitListItem.ts
Normal file
23
packages/core/src/extensions/splitListItem.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { splitListItem as originalSplitListItem } from 'prosemirror-schema-list'
|
||||||
|
import { NodeType } from 'prosemirror-model'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
import getNodeType from '../utils/getNodeType'
|
||||||
|
|
||||||
|
export const SplitListItem = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
splitListItem: (typeOrName: string | NodeType): Command => ({ state, dispatch }) => {
|
||||||
|
const type = getNodeType(typeOrName, state.schema)
|
||||||
|
|
||||||
|
return originalSplitListItem(type)(state, dispatch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
SplitListItem: typeof SplitListItem,
|
||||||
|
}
|
||||||
|
}
|
||||||
29
packages/core/src/extensions/toggleBlockType.ts
Normal file
29
packages/core/src/extensions/toggleBlockType.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { NodeType } from 'prosemirror-model'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
import nodeIsActive from '../utils/nodeIsActive'
|
||||||
|
import getNodeType from '../utils/getNodeType'
|
||||||
|
|
||||||
|
export const ToggleBlockType = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
toggleBlockType: (typeOrName: string | NodeType, toggleTypeOrName: string | NodeType, attrs = {}): Command => ({ state, commands }) => {
|
||||||
|
const type = getNodeType(typeOrName, state.schema)
|
||||||
|
const toggleType = getNodeType(toggleTypeOrName, state.schema)
|
||||||
|
const isActive = nodeIsActive(state, type, attrs)
|
||||||
|
|
||||||
|
if (isActive) {
|
||||||
|
return commands.setBlockType(toggleType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return commands.setBlockType(type, attrs)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
ToggleBlockType: typeof ToggleBlockType,
|
||||||
|
}
|
||||||
|
}
|
||||||
52
packages/core/src/extensions/toggleList.ts
Normal file
52
packages/core/src/extensions/toggleList.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { wrapInList, liftListItem } from 'prosemirror-schema-list'
|
||||||
|
import { findParentNode } from 'prosemirror-utils'
|
||||||
|
import { Node, NodeType, Schema } from 'prosemirror-model'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
import getNodeType from '../utils/getNodeType'
|
||||||
|
|
||||||
|
function isList(node: Node, schema: Schema) {
|
||||||
|
return (node.type === schema.nodes.bullet_list
|
||||||
|
|| node.type === schema.nodes.ordered_list
|
||||||
|
|| node.type === schema.nodes.todo_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ToggleList = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
toggleList: (listTypeOrName: string | NodeType, itemTypeOrName: string | NodeType): Command => ({ tr, state, dispatch }) => {
|
||||||
|
const listType = getNodeType(listTypeOrName, state.schema)
|
||||||
|
const itemType = getNodeType(itemTypeOrName, state.schema)
|
||||||
|
const { schema, selection } = state
|
||||||
|
const { $from, $to } = selection
|
||||||
|
const range = $from.blockRange($to)
|
||||||
|
|
||||||
|
if (!range) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentList = findParentNode(node => isList(node, schema))(selection)
|
||||||
|
|
||||||
|
if (range.depth >= 1 && parentList && range.depth - parentList.depth <= 1) {
|
||||||
|
if (parentList.node.type === listType) {
|
||||||
|
return liftListItem(itemType)(state, dispatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isList(parentList.node, schema) && listType.validContent(parentList.node.content)) {
|
||||||
|
tr.setNodeMarkup(parentList.pos, listType)
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapInList(listType)(state, dispatch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
ToggleList: typeof ToggleList,
|
||||||
|
}
|
||||||
|
}
|
||||||
23
packages/core/src/extensions/toggleMark.ts
Normal file
23
packages/core/src/extensions/toggleMark.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { toggleMark as originalToggleMark } from 'prosemirror-commands'
|
||||||
|
import { MarkType } from 'prosemirror-model'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
import getMarkType from '../utils/getMarkType'
|
||||||
|
|
||||||
|
export const ToggleMark = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
toggleMark: (typeOrName: string | MarkType): Command => ({ state, dispatch }) => {
|
||||||
|
const type = getMarkType(typeOrName, state.schema)
|
||||||
|
|
||||||
|
return originalToggleMark(type)(state, dispatch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
ToggleMark: typeof ToggleMark,
|
||||||
|
}
|
||||||
|
}
|
||||||
29
packages/core/src/extensions/toggleWrap.ts
Normal file
29
packages/core/src/extensions/toggleWrap.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { wrapIn, lift } from 'prosemirror-commands'
|
||||||
|
import { NodeType } from 'prosemirror-model'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
import nodeIsActive from '../utils/nodeIsActive'
|
||||||
|
import getNodeType from '../utils/getNodeType'
|
||||||
|
|
||||||
|
export const ToggleWrap = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
toggleWrap: (typeOrName: string | NodeType, attrs = {}): Command => ({ state, dispatch }) => {
|
||||||
|
const type = getNodeType(typeOrName, state.schema)
|
||||||
|
const isActive = nodeIsActive(state, type, attrs)
|
||||||
|
|
||||||
|
if (isActive) {
|
||||||
|
return lift(state, dispatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
return wrapIn(type, attrs)(state, dispatch)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
ToggleWrap: typeof ToggleWrap,
|
||||||
|
}
|
||||||
|
}
|
||||||
43
packages/core/src/extensions/updateMark.ts
Normal file
43
packages/core/src/extensions/updateMark.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { MarkType } from 'prosemirror-model'
|
||||||
|
import { Command } from '../Editor'
|
||||||
|
import { createExtension } from '../Extension'
|
||||||
|
import getMarkType from '../utils/getMarkType'
|
||||||
|
import getMarkRange from '../utils/getMarkRange'
|
||||||
|
|
||||||
|
export const UpdateMark = createExtension({
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
updateMark: (typeOrName: string | MarkType, attrs: {}): Command => ({ tr, state }) => {
|
||||||
|
const { selection, doc } = tr
|
||||||
|
let { from, to } = selection
|
||||||
|
const { $from, empty } = selection
|
||||||
|
const type = getMarkType(typeOrName, state.schema)
|
||||||
|
|
||||||
|
if (empty) {
|
||||||
|
const range = getMarkRange($from, type)
|
||||||
|
|
||||||
|
if (range) {
|
||||||
|
from = range.from
|
||||||
|
to = range.to
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasMark = doc.rangeHasMark(from, to, type)
|
||||||
|
|
||||||
|
if (hasMark) {
|
||||||
|
tr.removeMark(from, to, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.addMark(from, to, type.create(attrs))
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
declare module '../Editor' {
|
||||||
|
interface AllExtensions {
|
||||||
|
UpdateMark: typeof UpdateMark,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,8 +9,6 @@ export interface CollaborationCursorOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CollaborationCursor = createExtension({
|
const CollaborationCursor = createExtension({
|
||||||
name: 'collaboration_cursor',
|
|
||||||
|
|
||||||
defaultOptions: <CollaborationCursorOptions>{
|
defaultOptions: <CollaborationCursorOptions>{
|
||||||
provider: null,
|
provider: null,
|
||||||
name: 'Someone',
|
name: 'Someone',
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ export interface CollaborationOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Collaboration = createExtension({
|
const Collaboration = createExtension({
|
||||||
name: 'collaboration',
|
|
||||||
|
|
||||||
defaultOptions: <CollaborationOptions>{
|
defaultOptions: <CollaborationOptions>{
|
||||||
provider: null,
|
provider: null,
|
||||||
type: null,
|
type: null,
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ export interface FocusOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Focus = createExtension({
|
const Focus = createExtension({
|
||||||
name: 'focus',
|
|
||||||
|
|
||||||
defaultOptions: <FocusOptions>{
|
defaultOptions: <FocusOptions>{
|
||||||
className: 'has-focus',
|
className: 'has-focus',
|
||||||
nested: false,
|
nested: false,
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ export interface HistoryOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const History = createExtension({
|
const History = createExtension({
|
||||||
name: 'history',
|
|
||||||
|
|
||||||
defaultOptions: <HistoryOptions>{
|
defaultOptions: <HistoryOptions>{
|
||||||
depth: 100,
|
depth: 100,
|
||||||
newGroupDelay: 500,
|
newGroupDelay: 500,
|
||||||
|
|||||||
Reference in New Issue
Block a user