@bangle.dev/core
Advanced tools
Comparing version 0.29.0 to 0.29.1-alpha.0
/** | ||
* @jest-environment jsdom | ||
*/ | ||
import { domSerializationHelpers } from '../src/dom-serialization-helpers'; | ||
import { criticalComponents } from '../src/index'; | ||
import { RawSpecs, SpecRegistry } from '../src/spec-registry'; | ||
import { domSerializationHelpers } from '../src/dom-serialization-helpers'; | ||
@@ -23,3 +23,3 @@ const { paragraph, doc, text } = criticalComponents; | ||
const parseDOM = result.parseDOM[0]; | ||
expect(parseDOM.tag).toMatchInlineSnapshot( | ||
expect(parseDOM?.tag).toMatchInlineSnapshot( | ||
`"span[data-bangle-name=\\"dummy\\"]"`, | ||
@@ -30,3 +30,3 @@ ); | ||
dom.setAttribute('data-bangle-attrs', JSON.stringify({ has: 'value' })); | ||
const attrs = parseDOM.getAttrs(dom); | ||
const attrs = parseDOM?.getAttrs(dom); | ||
expect(attrs).toMatchInlineSnapshot(` | ||
@@ -66,3 +66,3 @@ Object { | ||
const paraNode = specRegistry.schema.nodes['codeBlock'].create({}); | ||
const paraNode = specRegistry.schema.nodes['codeBlock']!.create({}); | ||
@@ -69,0 +69,0 @@ expect(toDOM(paraNode)).toMatchInlineSnapshot(` |
@@ -0,7 +1,8 @@ | ||
import { Plugin, PluginKey } from '@bangle.dev/pm'; | ||
import { criticalComponents } from '../src/index'; | ||
import { Plugin, PluginKey } from '@bangle.dev/pm'; | ||
import { RawSpecs, SpecRegistry } from '../src/spec-registry'; | ||
import { NodeView } from '../src/node-view'; | ||
import { PluginGroup } from '../src/plugin-group'; | ||
import { pluginLoader, RawPlugins } from '../src/plugin-loader'; | ||
import { PluginGroup } from '../src/plugin-group'; | ||
import { RawSpecs, SpecRegistry } from '../src/spec-registry'; | ||
@@ -8,0 +9,0 @@ const { paragraph } = criticalComponents; |
import * as pmHistory from '@bangle.dev/pm'; | ||
import { NodeSpec, Node, MarkSpec, Mark, Schema, Plugin, InputRule, Command, EditorState, PluginKey, EditorProps, Selection, dropCursor, EditorView, DirectEditorProps, DOMOutputSpec, Decoration } from '@bangle.dev/pm'; | ||
import { NodeSpec, MarkSpec, Schema, Plugin, InputRule, PluginKey, Command, EditorState, EditorProps, Selection, Mark, dropCursor, Node, EditorView, DirectEditorProps, DOMOutputSpec, Decoration } from '@bangle.dev/pm'; | ||
export { Plugin, PluginKey } from '@bangle.dev/pm'; | ||
import { MarkdownSerializerState } from 'prosemirror-markdown'; | ||
import { UnnestObjValue, MarkdownSerializer, MarkdownParser } from '@bangle.dev/shared-types'; | ||
declare type PMSpec = NodeSpec | MarkSpec; | ||
declare type BaseSpec = BaseRawNodeSpec | BaseRawMarkSpec; | ||
interface BaseRawNodeSpec { | ||
@@ -13,6 +13,4 @@ name: string; | ||
markdown?: { | ||
toMarkdown: (state: MarkdownSerializerState, node: Node, parent: Node, index: number) => void; | ||
parseMarkdown?: { | ||
[key: string]: any; | ||
}; | ||
toMarkdown: UnnestObjValue<MarkdownSerializer['nodes']>; | ||
parseMarkdown?: MarkdownParser['tokens']; | ||
}; | ||
@@ -28,12 +26,4 @@ options?: { | ||
markdown?: { | ||
toMarkdown: { | ||
open: string | ((_state: MarkdownSerializerState, mark: Mark, parent: Node, index: number) => void); | ||
close: string | ((_state: MarkdownSerializerState, mark: Mark, parent: Node, index: number) => void); | ||
mixable?: boolean; | ||
escape?: boolean; | ||
expelEnclosingWhitespace?: boolean; | ||
}; | ||
parseMarkdown?: { | ||
[k: string]: any; | ||
}; | ||
toMarkdown: UnnestObjValue<MarkdownSerializer['marks']>; | ||
parseMarkdown?: MarkdownParser['tokens']; | ||
}; | ||
@@ -46,15 +36,15 @@ options?: { | ||
declare class SpecRegistry<N extends string = any, M extends string = any> { | ||
_spec: PMSpec[]; | ||
_schema: Schema<N, M>; | ||
_options: { | ||
[key: string]: any; | ||
}; | ||
_schema: Schema<N, M>; | ||
_spec: BaseSpec[]; | ||
constructor(rawSpecs?: RawSpecs, { defaultSpecs }?: { | ||
defaultSpecs?: boolean | undefined; | ||
}); | ||
get spec(): PMSpec[]; | ||
get schema(): Schema<N, M>; | ||
get options(): { | ||
[key: string]: any; | ||
}; | ||
get schema(): Schema<N, M>; | ||
get spec(): BaseSpec[]; | ||
} | ||
@@ -89,5 +79,53 @@ | ||
declare const spec$1: typeof specFactory$1; | ||
declare const plugins$2: typeof pluginsFactory$2; | ||
declare const docChangedKey: PluginKey<any>; | ||
declare const selectionChangedKey: PluginKey<any>; | ||
declare function pluginsFactory$2(): RawPlugins; | ||
declare const editorStateCounter_docChangedKey: typeof docChangedKey; | ||
declare const editorStateCounter_selectionChangedKey: typeof selectionChangedKey; | ||
declare namespace editorStateCounter { | ||
export { | ||
plugins$2 as plugins, | ||
editorStateCounter_docChangedKey as docChangedKey, | ||
editorStateCounter_selectionChangedKey as selectionChangedKey, | ||
}; | ||
} | ||
declare const plugins$1: typeof pluginsFactory$1; | ||
declare const commands$1: { | ||
undo: typeof undo; | ||
redo: typeof redo; | ||
}; | ||
declare const defaultKeys$1: { | ||
undo: string; | ||
redo: string; | ||
redoAlt: string; | ||
}; | ||
declare function pluginsFactory$1({ historyOpts, keybindings, }?: { | ||
historyOpts?: {} | undefined; | ||
keybindings?: { | ||
undo: string; | ||
redo: string; | ||
redoAlt: string; | ||
} | undefined; | ||
}): RawPlugins; | ||
declare function undo(): pmHistory.Command; | ||
declare function redo(): pmHistory.Command; | ||
declare const history_undo: typeof undo; | ||
declare const history_redo: typeof redo; | ||
declare namespace history { | ||
export { | ||
plugins$1 as plugins, | ||
commands$1 as commands, | ||
defaultKeys$1 as defaultKeys, | ||
history_undo as undo, | ||
history_redo as redo, | ||
}; | ||
} | ||
declare const spec$1: typeof specFactory$1; | ||
declare const plugins: typeof pluginsFactory; | ||
declare const commands: { | ||
convertToParagraph: typeof convertToParagraph; | ||
@@ -101,3 +139,3 @@ jumpToStartOfParagraph: typeof jumpToStartOfParagraph; | ||
}; | ||
declare const defaultKeys$1: { | ||
declare const defaultKeys: { | ||
jumpToEndOfParagraph: string; | ||
@@ -114,3 +152,3 @@ jumpToStartOfParagraph: string; | ||
declare function specFactory$1(): BaseRawNodeSpec; | ||
declare function pluginsFactory$2({ keybindings }?: { | ||
declare function pluginsFactory({ keybindings }?: { | ||
keybindings?: { | ||
@@ -136,2 +174,5 @@ jumpToEndOfParagraph: string; | ||
declare const paragraph_plugins: typeof plugins; | ||
declare const paragraph_commands: typeof commands; | ||
declare const paragraph_defaultKeys: typeof defaultKeys; | ||
declare const paragraph_convertToParagraph: typeof convertToParagraph; | ||
@@ -147,5 +188,5 @@ declare const paragraph_queryIsTopLevelParagraph: typeof queryIsTopLevelParagraph; | ||
spec$1 as spec, | ||
plugins$2 as plugins, | ||
commands$1 as commands, | ||
defaultKeys$1 as defaultKeys, | ||
paragraph_plugins as plugins, | ||
paragraph_commands as commands, | ||
paragraph_defaultKeys as defaultKeys, | ||
paragraph_convertToParagraph as convertToParagraph, | ||
@@ -171,53 +212,2 @@ paragraph_queryIsTopLevelParagraph as queryIsTopLevelParagraph, | ||
declare const plugins$1: typeof pluginsFactory$1; | ||
declare const commands: { | ||
undo: typeof undo; | ||
redo: typeof redo; | ||
}; | ||
declare const defaultKeys: { | ||
undo: string; | ||
redo: string; | ||
redoAlt: string; | ||
}; | ||
declare function pluginsFactory$1({ historyOpts, keybindings, }?: { | ||
historyOpts?: {} | undefined; | ||
keybindings?: { | ||
undo: string; | ||
redo: string; | ||
redoAlt: string; | ||
} | undefined; | ||
}): RawPlugins; | ||
declare function undo(): pmHistory.Command; | ||
declare function redo(): pmHistory.Command; | ||
declare const history_commands: typeof commands; | ||
declare const history_defaultKeys: typeof defaultKeys; | ||
declare const history_undo: typeof undo; | ||
declare const history_redo: typeof redo; | ||
declare namespace history { | ||
export { | ||
plugins$1 as plugins, | ||
history_commands as commands, | ||
history_defaultKeys as defaultKeys, | ||
history_undo as undo, | ||
history_redo as redo, | ||
}; | ||
} | ||
declare const plugins: typeof pluginsFactory; | ||
declare const docChangedKey: PluginKey<any>; | ||
declare const selectionChangedKey: PluginKey<any>; | ||
declare function pluginsFactory(): RawPlugins; | ||
declare const editorStateCounter_plugins: typeof plugins; | ||
declare const editorStateCounter_docChangedKey: typeof docChangedKey; | ||
declare const editorStateCounter_selectionChangedKey: typeof selectionChangedKey; | ||
declare namespace editorStateCounter { | ||
export { | ||
editorStateCounter_plugins as plugins, | ||
editorStateCounter_docChangedKey as docChangedKey, | ||
editorStateCounter_selectionChangedKey as selectionChangedKey, | ||
}; | ||
} | ||
declare type InitialContent = string | Node | object; | ||
@@ -253,4 +243,4 @@ interface BangleEditorStateProps<PluginMetadata = any> { | ||
constructor(element: HTMLElement, { focusOnInit, state, pmViewOpts, }: BangleEditorProps<PluginMetadata>); | ||
destroy(): void; | ||
focusView(): void; | ||
destroy(): void; | ||
toHTMLString(): string; | ||
@@ -261,2 +251,29 @@ } | ||
/** | ||
* Creates a bare bone `toDOM` and `parseDOM` handlers for the PM schema. | ||
* The use case is for nodes or marks who already have a nodeView | ||
* and want to get basic `toDOM`, `parseDOM` to enable drag n drop or | ||
* copy paste. | ||
* | ||
* @param {*} spec | ||
* @param {Object} opts | ||
* @param {string} opts.tag | ||
* @param {string|0|(node)=>string} opts.content - `0` signals content that PM will inject. | ||
* @param {string} opts.ignoreAttrs | ||
* @param {Number} opts.parsingPriority https://prosemirror.net/docs/ref/#model.ParseRule.priority | ||
*/ | ||
declare function domSerializationHelpers(name: string, { tag, content, ignoreAttrs, parsingPriority, }?: { | ||
tag?: string; | ||
content?: DOMOutputSpec | ((node: Node) => DOMOutputSpec); | ||
ignoreAttrs?: string[]; | ||
parsingPriority?: number; | ||
}): { | ||
toDOM: (node: Node) => DOMOutputSpec; | ||
parseDOM: { | ||
priority: number; | ||
tag: string; | ||
getAttrs: (dom: any) => any; | ||
}[]; | ||
}; | ||
declare type GetPosFunction = () => number; | ||
@@ -280,7 +297,2 @@ declare type UpdateAttrsFunction = (attrs: Node['attrs']) => void; | ||
declare abstract class BaseNodeView { | ||
_node: Node; | ||
_view: EditorView; | ||
_getPos: () => number; | ||
_decorations: readonly Decoration[]; | ||
_selected: boolean; | ||
contentDOM?: HTMLElement; | ||
@@ -292,5 +304,7 @@ containerDOM?: HTMLElement; | ||
}; | ||
getAttrs(): Node['attrs']; | ||
getNodeViewProps(): NodeViewProps; | ||
get dom(): InstanceType<typeof window.Node>; | ||
_decorations: readonly Decoration[]; | ||
_getPos: () => number; | ||
_node: Node; | ||
_selected: boolean; | ||
_view: EditorView; | ||
constructor({ node, view, getPos, decorations, containerDOM, contentDOM, renderHandlers, }: { | ||
@@ -307,2 +321,5 @@ node: Node; | ||
}); | ||
get dom(): InstanceType<typeof window.Node>; | ||
getAttrs(): Node['attrs']; | ||
getNodeViewProps(): NodeViewProps; | ||
} | ||
@@ -328,5 +345,4 @@ declare class NodeView extends BaseNodeView { | ||
}): Plugin<any>; | ||
update(node: Node, decorations: readonly Decoration[]): boolean; | ||
selectNode(): void; | ||
deselectNode(): void; | ||
destroy(): void; | ||
ignoreMutation(mutation: MutationRecord | { | ||
@@ -336,3 +352,4 @@ type: 'selection'; | ||
}): boolean; | ||
destroy(): void; | ||
selectNode(): void; | ||
update(node: Node, decorations: readonly Decoration[]): boolean; | ||
} | ||
@@ -342,29 +359,2 @@ declare function saveRenderHandlers(editorContainer: HTMLElement, handlers: RenderHandlers): void; | ||
/** | ||
* Creates a bare bone `toDOM` and `parseDOM` handlers for the PM schema. | ||
* The use case is for nodes or marks who already have a nodeView | ||
* and want to get basic `toDOM`, `parseDOM` to enable drag n drop or | ||
* copy paste. | ||
* | ||
* @param {*} spec | ||
* @param {Object} opts | ||
* @param {string} opts.tag | ||
* @param {string|0|(node)=>string} opts.content - `0` signals content that PM will inject. | ||
* @param {string} opts.ignoreAttrs | ||
* @param {Number} opts.parsingPriority https://prosemirror.net/docs/ref/#model.ParseRule.priority | ||
*/ | ||
declare function domSerializationHelpers(name: string, { tag, content, ignoreAttrs, parsingPriority, }?: { | ||
tag?: string; | ||
content?: DOMOutputSpec | ((node: Node) => DOMOutputSpec); | ||
ignoreAttrs?: string[]; | ||
parsingPriority?: number; | ||
}): { | ||
toDOM: (node: Node) => DOMOutputSpec; | ||
parseDOM: { | ||
priority: number; | ||
tag: string; | ||
getAttrs: (dom: any) => any; | ||
}[]; | ||
}; | ||
declare const criticalComponents: { | ||
@@ -378,2 +368,2 @@ doc: typeof doc; | ||
export { BangleEditor, BangleEditorProps, BangleEditorState, BangleEditorStateProps, BaseRawMarkSpec, BaseRawNodeSpec, NodeView, NodeViewProps, RawPlugins, RawSpecs, RenderHandlerFunction, RenderHandlers, SpecRegistry, UpdateAttrsFunction, createElement, criticalComponents, doc, domSerializationHelpers, editorStateCounter, getRenderHandlers, history, paragraph, saveRenderHandlers, text }; | ||
export { BangleEditor, BangleEditorProps, BangleEditorState, BangleEditorStateProps, BaseRawMarkSpec, BaseRawNodeSpec, BaseSpec, NodeView, NodeViewProps, RawPlugins, RawSpecs, RenderHandlerFunction, RenderHandlers, SpecRegistry, UpdateAttrsFunction, createElement, criticalComponents, doc, domSerializationHelpers, editorStateCounter, getRenderHandlers, history, paragraph, saveRenderHandlers, text }; |
import * as pmHistory from '@bangle.dev/pm'; | ||
import { keymap, setBlockType, PluginKey, Plugin, Schema, baseKeymap, dropCursor, gapCursor, InputRule, inputRules, undoInputRule, EditorState, Node, DOMParser, EditorView, DOMSerializer } from '@bangle.dev/pm'; | ||
import { PluginKey, Plugin, keymap, setBlockType, baseKeymap, dropCursor, gapCursor, InputRule, inputRules, undoInputRule, Schema, EditorState, Node, DOMParser, EditorView, DOMSerializer } from '@bangle.dev/pm'; | ||
export { Plugin, PluginKey } from '@bangle.dev/pm'; | ||
import { browser, createObject, filter, insertEmpty, findParentNodeOfType, bangleWarn, isTestEnv, toHTMLString, objectFilter } from '@bangle.dev/utils'; | ||
import { createObject, browser, getParaNodeType, getNodeType, filter, insertEmpty, findParentNodeOfType, bangleWarn, isTestEnv, toHTMLString, objectFilter } from '@bangle.dev/utils'; | ||
import { parentHasDirectParentOfType, moveNode, jumpToStartOfNode, jumpToEndOfNode, copyEmptyCommand, cutEmptyCommand } from '@bangle.dev/pm-commands'; | ||
@@ -25,5 +25,94 @@ | ||
const spec$1 = specFactory$1; | ||
class PluginGroup { | ||
constructor(name, plugins) { | ||
this.name = name; | ||
this.plugins = plugins; | ||
} | ||
} | ||
const name$3 = 'editorStateCounter'; | ||
const plugins$2 = pluginsFactory$2; | ||
const docChangedKey = new PluginKey(name$3); | ||
const selectionChangedKey = new PluginKey(name$3); | ||
function pluginsFactory$2() { | ||
return () => { | ||
return new PluginGroup(name$3, [ | ||
new Plugin({ | ||
key: docChangedKey, | ||
state: { | ||
init(_, _state) { | ||
return 0; | ||
}, | ||
apply(tr, pluginState, _oldState, _newState) { | ||
return tr.docChanged ? pluginState + 1 : pluginState; | ||
}, | ||
}, | ||
}), | ||
new Plugin({ | ||
key: selectionChangedKey, | ||
state: { | ||
init(_, _state) { | ||
return 0; | ||
}, | ||
apply(_tr, pluginState, oldState, newState) { | ||
return newState.selection.eq(oldState && oldState.selection) | ||
? pluginState | ||
: pluginState + 1; | ||
}, | ||
}, | ||
}), | ||
]); | ||
}; | ||
} | ||
var editorStateCounter = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
plugins: plugins$2, | ||
docChangedKey: docChangedKey, | ||
selectionChangedKey: selectionChangedKey | ||
}); | ||
const plugins$1 = pluginsFactory$1; | ||
const commands$1 = { | ||
undo, | ||
redo, | ||
}; | ||
const defaultKeys$1 = { | ||
undo: 'Mod-z', | ||
redo: 'Mod-y', | ||
redoAlt: 'Shift-Mod-z', | ||
}; | ||
const name$2 = 'history'; | ||
function pluginsFactory$1({ historyOpts = {}, keybindings = defaultKeys$1, } = {}) { | ||
return () => { | ||
return new PluginGroup(name$2, [ | ||
pmHistory.history(historyOpts), | ||
keybindings && | ||
keymap(createObject([ | ||
[keybindings.undo, undo()], | ||
[keybindings.redo, redo()], | ||
[keybindings.redoAlt, redo()], | ||
])), | ||
]); | ||
}; | ||
} | ||
function undo() { | ||
return pmHistory.undo; | ||
} | ||
function redo() { | ||
return pmHistory.redo; | ||
} | ||
var history = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
plugins: plugins$1, | ||
commands: commands$1, | ||
defaultKeys: defaultKeys$1, | ||
undo: undo, | ||
redo: redo | ||
}); | ||
const spec$1 = specFactory$1; | ||
const plugins = pluginsFactory; | ||
const commands = { | ||
convertToParagraph, | ||
@@ -37,3 +126,3 @@ jumpToStartOfParagraph, | ||
}; | ||
const defaultKeys$1 = { | ||
const defaultKeys = { | ||
jumpToEndOfParagraph: browser.mac ? 'Ctrl-e' : 'Ctrl-End', | ||
@@ -49,8 +138,7 @@ jumpToStartOfParagraph: browser.mac ? 'Ctrl-a' : 'Ctrl-Home', | ||
}; | ||
const name$3 = 'paragraph'; | ||
const getTypeFromSchema = (schema) => schema.nodes[name$3]; | ||
const name$1 = 'paragraph'; | ||
function specFactory$1() { | ||
return { | ||
type: 'node', | ||
name: name$3, | ||
name: name$1, | ||
schema: { | ||
@@ -80,7 +168,7 @@ content: 'inline*', | ||
} | ||
function pluginsFactory$2({ keybindings = defaultKeys$1 } = {}) { | ||
function pluginsFactory({ keybindings = defaultKeys } = {}) { | ||
return ({ schema }) => { | ||
const type = getTypeFromSchema(schema); | ||
const type = getParaNodeType(schema); | ||
// Enables certain command to only work if paragraph is direct child of the `doc` node | ||
const isTopLevel = parentHasDirectParentOfType(type, schema.nodes.doc); | ||
const isTopLevel = parentHasDirectParentOfType(type, getNodeType(schema, 'doc')); | ||
return [ | ||
@@ -110,8 +198,8 @@ keybindings && | ||
function convertToParagraph() { | ||
return (state, dispatch) => setBlockType(getTypeFromSchema(state.schema))(state, dispatch); | ||
return (state, dispatch) => setBlockType(getParaNodeType(state))(state, dispatch); | ||
} | ||
function queryIsTopLevelParagraph() { | ||
return (state) => { | ||
const type = getTypeFromSchema(state.schema); | ||
return parentHasDirectParentOfType(type, state.schema.nodes.doc)(state); | ||
const type = getParaNodeType(state); | ||
return parentHasDirectParentOfType(type, getNodeType(state, 'doc'))(state); | ||
}; | ||
@@ -121,3 +209,3 @@ } | ||
return (state) => { | ||
const type = getTypeFromSchema(state.schema); | ||
const type = getParaNodeType(state); | ||
return Boolean(findParentNodeOfType(type)(state.selection)); | ||
@@ -128,4 +216,4 @@ }; | ||
return (state, dispatch, view) => { | ||
const type = getTypeFromSchema(state.schema); | ||
return filter(parentHasDirectParentOfType(type, state.schema.nodes.doc), insertEmpty(type, 'above'))(state, dispatch, view); | ||
const type = getParaNodeType(state); | ||
return filter(parentHasDirectParentOfType(type, getNodeType(state, 'doc')), insertEmpty(type, 'above'))(state, dispatch, view); | ||
}; | ||
@@ -135,4 +223,4 @@ } | ||
return (state, dispatch, view) => { | ||
const type = getTypeFromSchema(state.schema); | ||
return filter(parentHasDirectParentOfType(type, state.schema.nodes.doc), insertEmpty(type, 'below'))(state, dispatch, view); | ||
const type = getParaNodeType(state); | ||
return filter(parentHasDirectParentOfType(type, getNodeType(state, 'doc')), insertEmpty(type, 'below'))(state, dispatch, view); | ||
}; | ||
@@ -142,3 +230,3 @@ } | ||
return (state, dispatch) => { | ||
const type = getTypeFromSchema(state.schema); | ||
const type = getParaNodeType(state); | ||
return jumpToStartOfNode(type)(state, dispatch); | ||
@@ -149,3 +237,3 @@ }; | ||
return (state, dispatch) => { | ||
const type = getTypeFromSchema(state.schema); | ||
const type = getParaNodeType(state); | ||
return jumpToEndOfNode(type)(state, dispatch); | ||
@@ -158,5 +246,5 @@ }; | ||
spec: spec$1, | ||
plugins: plugins$2, | ||
commands: commands$1, | ||
defaultKeys: defaultKeys$1, | ||
plugins: plugins, | ||
commands: commands, | ||
defaultKeys: defaultKeys, | ||
convertToParagraph: convertToParagraph, | ||
@@ -172,7 +260,7 @@ queryIsTopLevelParagraph: queryIsTopLevelParagraph, | ||
const spec = specFactory; | ||
const name$2 = 'text'; | ||
const name = 'text'; | ||
function specFactory() { | ||
return { | ||
type: 'node', | ||
name: name$2, | ||
name, | ||
schema: { | ||
@@ -194,180 +282,3 @@ group: 'inline', | ||
class PluginGroup { | ||
constructor(name, plugins) { | ||
this.name = name; | ||
this.plugins = plugins; | ||
} | ||
} | ||
const plugins$1 = pluginsFactory$1; | ||
const commands = { | ||
undo, | ||
redo, | ||
}; | ||
const defaultKeys = { | ||
undo: 'Mod-z', | ||
redo: 'Mod-y', | ||
redoAlt: 'Shift-Mod-z', | ||
}; | ||
const name$1 = 'history'; | ||
function pluginsFactory$1({ historyOpts = {}, keybindings = defaultKeys, } = {}) { | ||
return () => { | ||
return new PluginGroup(name$1, [ | ||
pmHistory.history(historyOpts), | ||
keybindings && | ||
keymap(createObject([ | ||
[keybindings.undo, undo()], | ||
[keybindings.redo, redo()], | ||
[keybindings.redoAlt, redo()], | ||
])), | ||
]); | ||
}; | ||
} | ||
function undo() { | ||
return pmHistory.undo; | ||
} | ||
function redo() { | ||
return pmHistory.redo; | ||
} | ||
var history = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
plugins: plugins$1, | ||
commands: commands, | ||
defaultKeys: defaultKeys, | ||
undo: undo, | ||
redo: redo | ||
}); | ||
const name = 'editorStateCounter'; | ||
const plugins = pluginsFactory; | ||
const docChangedKey = new PluginKey(name); | ||
const selectionChangedKey = new PluginKey(name); | ||
function pluginsFactory() { | ||
return () => { | ||
return new PluginGroup(name, [ | ||
new Plugin({ | ||
key: docChangedKey, | ||
state: { | ||
init(_, _state) { | ||
return 0; | ||
}, | ||
apply(tr, pluginState, _oldState, _newState) { | ||
return tr.docChanged ? pluginState + 1 : pluginState; | ||
}, | ||
}, | ||
}), | ||
new Plugin({ | ||
key: selectionChangedKey, | ||
state: { | ||
init(_, _state) { | ||
return 0; | ||
}, | ||
apply(_tr, pluginState, oldState, newState) { | ||
return newState.selection.eq(oldState && oldState.selection) | ||
? pluginState | ||
: pluginState + 1; | ||
}, | ||
}, | ||
}), | ||
]); | ||
}; | ||
} | ||
var editorStateCounter = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
plugins: plugins, | ||
docChangedKey: docChangedKey, | ||
selectionChangedKey: selectionChangedKey | ||
}); | ||
class SpecRegistry { | ||
constructor(rawSpecs = [], { defaultSpecs = true } = {}) { | ||
let flattenedSpecs = flatten$1(rawSpecs); | ||
flattenedSpecs.forEach(validateSpec); | ||
const names = new Set(flattenedSpecs.map((r) => r.name)); | ||
if (flattenedSpecs.length !== names.size) { | ||
bangleWarn('The specRegistry has one or more specs with the same name', flattenedSpecs); | ||
throw new Error('Duplicate spec error, please check your specRegistry'); | ||
} | ||
if (defaultSpecs) { | ||
const defaultSpecsArray = []; | ||
if (!names.has('paragraph')) { | ||
defaultSpecsArray.unshift(spec$1()); | ||
} | ||
if (!names.has('text')) { | ||
defaultSpecsArray.unshift(spec()); | ||
} | ||
if (!names.has('doc')) { | ||
defaultSpecsArray.unshift(spec$2()); | ||
} | ||
flattenedSpecs = [...flatten$1(defaultSpecsArray), ...flattenedSpecs]; | ||
} | ||
this._spec = flattenedSpecs; | ||
this._schema = createSchema(this._spec); | ||
this._options = Object.fromEntries(this._spec | ||
.filter((spec) => spec.options) | ||
.map((spec) => [spec.name, spec.options])); | ||
} | ||
get spec() { | ||
return this._spec; | ||
} | ||
get schema() { | ||
return this._schema; | ||
} | ||
get options() { | ||
return this._options; | ||
} | ||
} | ||
function createSchema(specRegistry) { | ||
let nodes = []; | ||
let marks = []; | ||
let topNode; | ||
for (const spec of specRegistry) { | ||
if (spec.type === 'node') { | ||
nodes.push([spec.name, spec.schema]); | ||
} | ||
else if (spec.type === 'mark') { | ||
marks.push([spec.name, spec.schema]); | ||
} | ||
else if (spec.type === 'component') ; | ||
else { | ||
throw new Error(spec.name + ' unknown type: ' + spec.type); | ||
} | ||
if (spec.topNode === true) { | ||
topNode = spec.name; | ||
} | ||
} | ||
return new Schema({ | ||
topNode, | ||
nodes: Object.fromEntries(nodes), | ||
marks: Object.fromEntries(marks), | ||
}); | ||
} | ||
function validateSpec(spec) { | ||
if (!spec.name) { | ||
bangleWarn("The spec didn't have a name field", spec); | ||
throw new Error('Invalid spec. Spec must have a name'); | ||
} | ||
if (!['node', 'mark', 'component'].includes(spec.type)) { | ||
bangleWarn('The spec must be of type node, mark or component ', spec); | ||
throw new Error('Invalid spec type'); | ||
} | ||
if (['node', 'mark'].includes(spec.type) && !spec.schema) { | ||
bangleWarn("The spec of type 'mark' or 'node' must have a schema field", spec); | ||
throw new Error('Invalid spec schema'); | ||
} | ||
} | ||
function flatten$1(data) { | ||
const recurse = (d) => { | ||
if (Array.isArray(d)) { | ||
return d.flatMap((i) => recurse(i)).filter(Boolean); | ||
} | ||
// @ts-ignore really hard to annotate recursive functions | ||
return d; | ||
}; | ||
return recurse(data); | ||
} | ||
function pluginLoader(specRegistry, plugins$2, { metadata, editorProps, defaultPlugins = true, dropCursorOpts, transformPlugins = (p) => p, } = {}) { | ||
function pluginLoader(specRegistry, plugins, { metadata, editorProps, defaultPlugins = true, dropCursorOpts, transformPlugins = (p) => p, } = {}) { | ||
const schema = specRegistry.schema; | ||
@@ -379,3 +290,3 @@ const pluginPayload = { | ||
}; | ||
let [flatPlugins, pluginGroupNames] = flatten(plugins$2, pluginPayload); | ||
let [flatPlugins, pluginGroupNames] = flatten$1(plugins, pluginPayload); | ||
if (defaultPlugins) { | ||
@@ -387,7 +298,7 @@ let defaultPluginGroups = []; | ||
if (!pluginGroupNames.has('editorStateCounter')) { | ||
defaultPluginGroups.push(plugins()); | ||
defaultPluginGroups.push(plugins$2()); | ||
} | ||
flatPlugins = flatPlugins.concat( | ||
// TODO: deprecate the ability pass a callback to the plugins param of pluginGroup | ||
flatten(defaultPluginGroups, pluginPayload)[0]); | ||
flatten$1(defaultPluginGroups, pluginPayload)[0]); | ||
flatPlugins = processInputRules(flatPlugins); | ||
@@ -452,3 +363,3 @@ flatPlugins.push(keymap(baseKeymap), dropCursor(dropCursorOpts), gapCursor()); | ||
} | ||
function flatten(rawPlugins, callbackPayload) { | ||
function flatten$1(rawPlugins, callbackPayload) { | ||
const pluginGroupNames = new Set(); | ||
@@ -477,2 +388,94 @@ const recurse = (plugins) => { | ||
class SpecRegistry { | ||
constructor(rawSpecs = [], { defaultSpecs = true } = {}) { | ||
let flattenedSpecs = flatten(rawSpecs); | ||
flattenedSpecs.forEach(validateSpec); | ||
const names = new Set(flattenedSpecs.map((r) => r.name)); | ||
if (flattenedSpecs.length !== names.size) { | ||
bangleWarn('The specRegistry has one or more specs with the same name', flattenedSpecs); | ||
throw new Error('Duplicate spec error, please check your specRegistry'); | ||
} | ||
if (defaultSpecs) { | ||
const defaultSpecsArray = []; | ||
if (!names.has('paragraph')) { | ||
defaultSpecsArray.unshift(spec$1()); | ||
} | ||
if (!names.has('text')) { | ||
defaultSpecsArray.unshift(spec()); | ||
} | ||
if (!names.has('doc')) { | ||
defaultSpecsArray.unshift(spec$2()); | ||
} | ||
flattenedSpecs = [...defaultSpecsArray, ...flattenedSpecs]; | ||
} | ||
this._spec = flattenedSpecs; | ||
this._schema = createSchema(this._spec); | ||
this._options = Object.fromEntries(this._spec | ||
.filter((spec) => spec.options) | ||
.map((spec) => [spec.name, spec.options])); | ||
} | ||
get options() { | ||
return this._options; | ||
} | ||
get schema() { | ||
return this._schema; | ||
} | ||
get spec() { | ||
return this._spec; | ||
} | ||
} | ||
function createSchema(specRegistry) { | ||
let nodes = []; | ||
let marks = []; | ||
let topNode; | ||
for (const spec of specRegistry) { | ||
if (spec.type === 'node') { | ||
nodes.push([spec.name, spec.schema]); | ||
if (spec.topNode === true) { | ||
topNode = spec.name; | ||
} | ||
} | ||
else if (spec.type === 'mark') { | ||
marks.push([spec.name, spec.schema]); | ||
} | ||
else { | ||
let r = spec; | ||
throw new Error('Unknown type: ' + r.type); | ||
} | ||
} | ||
return new Schema({ | ||
topNode, | ||
nodes: Object.fromEntries(nodes), | ||
marks: Object.fromEntries(marks), | ||
}); | ||
} | ||
function validateSpec(spec) { | ||
if (!spec.name) { | ||
bangleWarn("The spec didn't have a name field", spec); | ||
throw new Error('Invalid spec. Spec must have a name'); | ||
} | ||
if (!['node', 'mark'].includes(spec.type)) { | ||
bangleWarn('The spec must be of type node, mark or component ', spec); | ||
throw new Error('Invalid spec type'); | ||
} | ||
if (['node', 'mark'].includes(spec.type) && !spec.schema) { | ||
bangleWarn("The spec of type 'mark' or 'node' must have a schema field", spec); | ||
throw new Error('Invalid spec schema'); | ||
} | ||
} | ||
function flatten(data) { | ||
const recurse = (d) => { | ||
if (Array.isArray(d)) { | ||
return d | ||
.flatMap((i) => recurse(i)) | ||
.filter((r) => Boolean(r)); | ||
} | ||
if (d == null || d === false) { | ||
return []; | ||
} | ||
return [d]; | ||
}; | ||
return recurse(data); | ||
} | ||
class BangleEditorState { | ||
@@ -539,8 +542,2 @@ constructor({ specRegistry, specs, plugins = () => [], initialValue, editorProps, pmStateOpts, pluginMetadata, dropCursorOpts, } = {}) { | ||
} | ||
focusView() { | ||
if (isTestEnv || this.view.hasFocus()) { | ||
return; | ||
} | ||
this.view.focus(); | ||
} | ||
destroy() { | ||
@@ -557,2 +554,8 @@ if (this.destroyed) { | ||
} | ||
focusView() { | ||
if (isTestEnv || this.view.hasFocus()) { | ||
return; | ||
} | ||
this.view.focus(); | ||
} | ||
toHTMLString() { | ||
@@ -571,4 +574,55 @@ return toHTMLString(this.view.state); | ||
/** | ||
* Creates a bare bone `toDOM` and `parseDOM` handlers for the PM schema. | ||
* The use case is for nodes or marks who already have a nodeView | ||
* and want to get basic `toDOM`, `parseDOM` to enable drag n drop or | ||
* copy paste. | ||
* | ||
* @param {*} spec | ||
* @param {Object} opts | ||
* @param {string} opts.tag | ||
* @param {string|0|(node)=>string} opts.content - `0` signals content that PM will inject. | ||
* @param {string} opts.ignoreAttrs | ||
* @param {Number} opts.parsingPriority https://prosemirror.net/docs/ref/#model.ParseRule.priority | ||
*/ | ||
function domSerializationHelpers(name, { tag = 'div', content, ignoreAttrs = [], parsingPriority = 51, } = {}) { | ||
const serializer = (node) => JSON.stringify(objectFilter(node.attrs || {}, (_value, key) => !ignoreAttrs.includes(key))); | ||
return { | ||
toDOM: (node) => { | ||
const domSpec = [ | ||
tag, | ||
{ | ||
'data-bangle-name': name, | ||
'data-bangle-attrs': serializer(node), | ||
}, | ||
]; | ||
if (content !== undefined) { | ||
if (typeof content === 'function') { | ||
domSpec.push(content(node)); | ||
} | ||
else { | ||
domSpec.push(content); | ||
} | ||
} | ||
return domSpec; | ||
}, | ||
parseDOM: [ | ||
{ | ||
priority: parsingPriority, | ||
tag: `${tag}[data-bangle-name="${name}"]`, | ||
getAttrs: (dom) => { | ||
const attrs = dom.getAttribute('data-bangle-attrs'); | ||
if (!attrs) { | ||
return {}; | ||
} | ||
return JSON.parse(attrs); | ||
}, | ||
}, | ||
], | ||
}; | ||
} | ||
const renderHandlersCache = new WeakMap(); | ||
class BaseNodeView { | ||
// for pm to get hold of containerDOM | ||
constructor({ node, view, getPos, decorations, containerDOM, contentDOM, | ||
@@ -609,2 +663,6 @@ // Defaults to whatever is set by the rendering framework which ideally | ||
} | ||
// this exists as the name `dom` is too ambiguous | ||
get dom() { | ||
return this.containerDOM; | ||
} | ||
getAttrs() { | ||
@@ -626,7 +684,2 @@ return this._node.attrs; | ||
} | ||
// for pm to get hold of containerDOM | ||
// this exists as the name `dom` is too ambiguous | ||
get dom() { | ||
return this.containerDOM; | ||
} | ||
} | ||
@@ -676,20 +729,2 @@ // TODO this is adds unneeded abstraction | ||
} | ||
update(node, decorations) { | ||
// https://github.com/ProseMirror/prosemirror/issues/648 | ||
if (this._node.type !== node.type) { | ||
return false; | ||
} | ||
if (this._node === node && this._decorations === decorations) { | ||
return true; | ||
} | ||
this._node = node; | ||
this._decorations = decorations; | ||
this.renderHandlers.update(this, this.getNodeViewProps()); | ||
return true; | ||
} | ||
selectNode() { | ||
this.containerDOM.classList.add('ProseMirror-selectednode'); | ||
this._selected = true; | ||
this.renderHandlers.update(this, this.getNodeViewProps()); | ||
} | ||
deselectNode() { | ||
@@ -700,7 +735,8 @@ this.containerDOM.classList.remove('ProseMirror-selectednode'); | ||
} | ||
// Donot unset it if you donot have an implementation. | ||
// Unsetting this is dangerous as it fucks up elements who have editable content inside them. | ||
// setSelection(...args) { | ||
// console.log('hi', ...args); | ||
// } | ||
destroy() { | ||
this.renderHandlers.destroy(this, this.getNodeViewProps()); | ||
this.containerDOM = undefined; | ||
this.contentDOM = undefined; | ||
} | ||
// PM essentially works by watching mutation and then syncing the two states: its own and the DOM. | ||
@@ -731,10 +767,20 @@ ignoreMutation(mutation) { | ||
} | ||
// stopEvent() { | ||
// return true; | ||
// } | ||
destroy() { | ||
this.renderHandlers.destroy(this, this.getNodeViewProps()); | ||
this.containerDOM = undefined; | ||
this.contentDOM = undefined; | ||
selectNode() { | ||
this.containerDOM.classList.add('ProseMirror-selectednode'); | ||
this._selected = true; | ||
this.renderHandlers.update(this, this.getNodeViewProps()); | ||
} | ||
update(node, decorations) { | ||
// https://github.com/ProseMirror/prosemirror/issues/648 | ||
if (this._node.type !== node.type) { | ||
return false; | ||
} | ||
if (this._node === node && this._decorations === decorations) { | ||
return true; | ||
} | ||
this._node = node; | ||
this._decorations = decorations; | ||
this.renderHandlers.update(this, this.getNodeViewProps()); | ||
return true; | ||
} | ||
} | ||
@@ -759,52 +805,2 @@ function saveRenderHandlers(editorContainer, handlers) { | ||
/** | ||
* Creates a bare bone `toDOM` and `parseDOM` handlers for the PM schema. | ||
* The use case is for nodes or marks who already have a nodeView | ||
* and want to get basic `toDOM`, `parseDOM` to enable drag n drop or | ||
* copy paste. | ||
* | ||
* @param {*} spec | ||
* @param {Object} opts | ||
* @param {string} opts.tag | ||
* @param {string|0|(node)=>string} opts.content - `0` signals content that PM will inject. | ||
* @param {string} opts.ignoreAttrs | ||
* @param {Number} opts.parsingPriority https://prosemirror.net/docs/ref/#model.ParseRule.priority | ||
*/ | ||
function domSerializationHelpers(name, { tag = 'div', content, ignoreAttrs = [], parsingPriority = 51, } = {}) { | ||
const serializer = (node) => JSON.stringify(objectFilter(node.attrs || {}, (_value, key) => !ignoreAttrs.includes(key))); | ||
return { | ||
toDOM: (node) => { | ||
const domSpec = [ | ||
tag, | ||
{ | ||
'data-bangle-name': name, | ||
'data-bangle-attrs': serializer(node), | ||
}, | ||
]; | ||
if (content !== undefined) { | ||
if (typeof content === 'function') { | ||
domSpec.push(content(node)); | ||
} | ||
else { | ||
domSpec.push(content); | ||
} | ||
} | ||
return domSpec; | ||
}, | ||
parseDOM: [ | ||
{ | ||
priority: parsingPriority, | ||
tag: `${tag}[data-bangle-name="${name}"]`, | ||
getAttrs: (dom) => { | ||
const attrs = dom.getAttribute('data-bangle-attrs'); | ||
if (!attrs) { | ||
return {}; | ||
} | ||
return JSON.parse(attrs); | ||
}, | ||
}, | ||
], | ||
}; | ||
} | ||
// components | ||
@@ -811,0 +807,0 @@ const criticalComponents = { |
{ | ||
"name": "@bangle.dev/core", | ||
"version": "0.29.0", | ||
"version": "0.29.1-alpha.0", | ||
"homepage": "https://bangle.dev", | ||
@@ -40,12 +40,12 @@ "authors": [ | ||
"dependencies": { | ||
"@bangle.dev/pm-commands": "0.29.0", | ||
"@bangle.dev/utils": "0.29.0", | ||
"@types/jest": "^27.0.4" | ||
"@bangle.dev/pm-commands": "0.29.1-alpha.0", | ||
"@bangle.dev/shared-types": "0.29.1-alpha.0", | ||
"@bangle.dev/utils": "0.29.1-alpha.0" | ||
}, | ||
"devDependencies": { | ||
"@bangle.dev/pm": "0.29.0", | ||
"@bangle.dev/pm": "0.29.1-alpha.0", | ||
"@types/jest": "^27.0.4", | ||
"@types/markdown-it": "^12.0.3", | ||
"markdown-it": "^10.0.0", | ||
"prettier": "^2.6.2", | ||
"prosemirror-markdown": "^1.9.1" | ||
"prettier": "^2.6.2" | ||
}, | ||
@@ -52,0 +52,0 @@ "publishConfig": { |
import { | ||
DOMParser, | ||
dropCursor as pmDropCursor, | ||
EditorProps, | ||
@@ -10,6 +11,6 @@ EditorState, | ||
Selection, | ||
dropCursor as pmDropCursor, | ||
} from '@bangle.dev/pm'; | ||
import { pluginLoader, RawPlugins } from './plugin-loader'; | ||
import { RawSpecs, SpecRegistry } from './spec-registry'; | ||
import { pluginLoader, RawPlugins } from './plugin-loader'; | ||
@@ -16,0 +17,0 @@ type InitialContent = string | Node | object; |
import { DirectEditorProps, EditorView } from '@bangle.dev/pm'; | ||
import { isTestEnv, toHTMLString } from '@bangle.dev/utils'; | ||
import { BangleEditorState } from './bangle-editor-state'; | ||
@@ -50,9 +51,2 @@ | ||
focusView() { | ||
if (isTestEnv || this.view.hasFocus()) { | ||
return; | ||
} | ||
this.view.focus(); | ||
} | ||
destroy() { | ||
@@ -72,2 +66,9 @@ if (this.destroyed) { | ||
focusView() { | ||
if (isTestEnv || this.view.hasFocus()) { | ||
return; | ||
} | ||
this.view.focus(); | ||
} | ||
toHTMLString() { | ||
@@ -74,0 +75,0 @@ return toHTMLString(this.view.state); |
@@ -1,5 +0,6 @@ | ||
import type { RawPlugins } from './plugin-loader'; | ||
import { PluginGroup } from './plugin-group'; | ||
import { Plugin, PluginKey } from '@bangle.dev/pm'; | ||
import { PluginGroup } from './plugin-group'; | ||
import type { RawPlugins } from './plugin-loader'; | ||
const name = 'editorStateCounter'; | ||
@@ -6,0 +7,0 @@ export const plugins = pluginsFactory; |
@@ -1,3 +0,1 @@ | ||
import type { RawPlugins } from './plugin-loader'; | ||
import { PluginGroup } from './plugin-group'; | ||
import * as pmHistory from '@bangle.dev/pm'; | ||
@@ -7,2 +5,5 @@ import { keymap } from '@bangle.dev/pm'; | ||
import { PluginGroup } from './plugin-group'; | ||
import type { RawPlugins } from './plugin-loader'; | ||
export const plugins = pluginsFactory; | ||
@@ -9,0 +10,0 @@ export const commands = { |
// components | ||
import * as doc from './doc'; | ||
import * as editorStateCounter from './editor-state-counter'; | ||
import * as history from './history'; | ||
import * as paragraph from './paragraph'; | ||
import * as text from './text'; | ||
import * as history from './history'; | ||
import * as editorStateCounter from './editor-state-counter'; | ||
@@ -11,9 +11,9 @@ export * from './bangle-editor'; | ||
export * from './create-element'; | ||
export * from './dom-serialization-helpers'; | ||
export * from './node-view'; | ||
export * from './plugin'; | ||
export type { RawPlugins } from './plugin-loader'; | ||
export * from './spec-registry'; | ||
export * from './dom-serialization-helpers'; | ||
export type { RawPlugins } from './plugin-loader'; | ||
export { doc, paragraph, text, history, editorStateCounter }; | ||
export { doc, editorStateCounter, history, paragraph, text }; | ||
@@ -20,0 +20,0 @@ export const criticalComponents = { |
@@ -11,2 +11,3 @@ import { | ||
import { bangleWarn } from '@bangle.dev/utils'; | ||
import { createElement } from './create-element'; | ||
@@ -45,7 +46,2 @@ | ||
abstract class BaseNodeView { | ||
_node: Node; | ||
_view: EditorView; | ||
_getPos: () => number; | ||
_decorations: readonly Decoration[]; | ||
_selected: boolean; | ||
contentDOM?: HTMLElement; | ||
@@ -55,29 +51,9 @@ containerDOM?: HTMLElement; | ||
opts: { selectionSensitive: boolean }; | ||
_decorations: readonly Decoration[]; | ||
_getPos: () => number; | ||
_node: Node; | ||
_selected: boolean; | ||
_view: EditorView; | ||
getAttrs(): Node['attrs'] { | ||
return this._node.attrs; | ||
} | ||
getNodeViewProps(): NodeViewProps { | ||
return { | ||
node: this._node, | ||
view: this._view, | ||
getPos: this._getPos, | ||
decorations: this._decorations, | ||
selected: this._selected, | ||
attrs: this._node.attrs, | ||
updateAttrs: (attrs: Node['attrs']) => { | ||
this._view.dispatch( | ||
updateAttrs(this._getPos(), this._node, attrs, this._view.state.tr), | ||
); | ||
}, | ||
}; | ||
} | ||
// for pm to get hold of containerDOM | ||
// this exists as the name `dom` is too ambiguous | ||
get dom(): InstanceType<typeof window.Node> { | ||
return this.containerDOM!; | ||
} | ||
constructor( | ||
@@ -153,2 +129,27 @@ { | ||
} | ||
// this exists as the name `dom` is too ambiguous | ||
get dom(): InstanceType<typeof window.Node> { | ||
return this.containerDOM!; | ||
} | ||
getAttrs(): Node['attrs'] { | ||
return this._node.attrs; | ||
} | ||
getNodeViewProps(): NodeViewProps { | ||
return { | ||
node: this._node, | ||
view: this._view, | ||
getPos: this._getPos, | ||
decorations: this._decorations, | ||
selected: this._selected, | ||
attrs: this._node.attrs, | ||
updateAttrs: (attrs: Node['attrs']) => { | ||
this._view.dispatch( | ||
updateAttrs(this._getPos(), this._node, attrs, this._view.state.tr), | ||
); | ||
}, | ||
}; | ||
} | ||
} | ||
@@ -210,30 +211,2 @@ // TODO this is adds unneeded abstraction | ||
update(node: Node, decorations: readonly Decoration[]) { | ||
log('update node'); | ||
// https://github.com/ProseMirror/prosemirror/issues/648 | ||
if (this._node.type !== node.type) { | ||
return false; | ||
} | ||
if (this._node === node && this._decorations === decorations) { | ||
log('update node no change'); | ||
return true; | ||
} | ||
this._node = node; | ||
this._decorations = decorations; | ||
log('update node execute'); | ||
this.renderHandlers.update(this, this.getNodeViewProps()); | ||
return true; | ||
} | ||
selectNode() { | ||
this.containerDOM!.classList.add('ProseMirror-selectednode'); | ||
this._selected = true; | ||
log('select node'); | ||
this.renderHandlers.update(this, this.getNodeViewProps()); | ||
} | ||
deselectNode() { | ||
@@ -246,7 +219,8 @@ this.containerDOM!.classList.remove('ProseMirror-selectednode'); | ||
// Donot unset it if you donot have an implementation. | ||
// Unsetting this is dangerous as it fucks up elements who have editable content inside them. | ||
// setSelection(...args) { | ||
// console.log('hi', ...args); | ||
// } | ||
destroy() { | ||
this.renderHandlers.destroy(this, this.getNodeViewProps()); | ||
this.containerDOM = undefined; | ||
this.contentDOM = undefined; | ||
} | ||
@@ -290,11 +264,38 @@ // PM essentially works by watching mutation and then syncing the two states: its own and the DOM. | ||
selectNode() { | ||
this.containerDOM!.classList.add('ProseMirror-selectednode'); | ||
this._selected = true; | ||
log('select node'); | ||
this.renderHandlers.update(this, this.getNodeViewProps()); | ||
} | ||
update(node: Node, decorations: readonly Decoration[]) { | ||
log('update node'); | ||
// https://github.com/ProseMirror/prosemirror/issues/648 | ||
if (this._node.type !== node.type) { | ||
return false; | ||
} | ||
if (this._node === node && this._decorations === decorations) { | ||
log('update node no change'); | ||
return true; | ||
} | ||
this._node = node; | ||
this._decorations = decorations; | ||
log('update node execute'); | ||
this.renderHandlers.update(this, this.getNodeViewProps()); | ||
return true; | ||
} | ||
// Donot unset it if you donot have an implementation. | ||
// Unsetting this is dangerous as it fucks up elements who have editable content inside them. | ||
// setSelection(...args) { | ||
// console.log('hi', ...args); | ||
// } | ||
// stopEvent() { | ||
// return true; | ||
// } | ||
destroy() { | ||
this.renderHandlers.destroy(this, this.getNodeViewProps()); | ||
this.containerDOM = undefined; | ||
this.contentDOM = undefined; | ||
} | ||
} | ||
@@ -301,0 +302,0 @@ |
@@ -1,3 +0,1 @@ | ||
import type { RawPlugins } from './plugin-loader'; | ||
import type { BaseRawNodeSpec, RawSpecs } from './spec-registry'; | ||
import { | ||
@@ -12,9 +10,2 @@ Command, | ||
import { | ||
browser, | ||
createObject, | ||
filter, | ||
findParentNodeOfType, | ||
insertEmpty, | ||
} from '@bangle.dev/utils'; | ||
import { | ||
copyEmptyCommand, | ||
@@ -27,3 +18,15 @@ cutEmptyCommand, | ||
} from '@bangle.dev/pm-commands'; | ||
import { | ||
browser, | ||
createObject, | ||
filter, | ||
findParentNodeOfType, | ||
getNodeType, | ||
getParaNodeType, | ||
insertEmpty, | ||
} from '@bangle.dev/utils'; | ||
import type { RawPlugins } from './plugin-loader'; | ||
import type { BaseRawNodeSpec, RawSpecs } from './spec-registry'; | ||
export const spec = specFactory; | ||
@@ -54,3 +57,2 @@ export const plugins = pluginsFactory; | ||
const name = 'paragraph'; | ||
const getTypeFromSchema = (schema: Schema) => schema.nodes[name]; | ||
@@ -88,5 +90,8 @@ function specFactory(): BaseRawNodeSpec { | ||
return ({ schema }) => { | ||
const type = getTypeFromSchema(schema); | ||
const type = getParaNodeType(schema); | ||
// Enables certain command to only work if paragraph is direct child of the `doc` node | ||
const isTopLevel = parentHasDirectParentOfType(type, schema.nodes.doc); | ||
const isTopLevel = parentHasDirectParentOfType( | ||
type, | ||
getNodeType(schema, 'doc'), | ||
); | ||
return [ | ||
@@ -124,3 +129,3 @@ keybindings && | ||
return (state, dispatch) => | ||
setBlockType(getTypeFromSchema(state.schema))(state, dispatch); | ||
setBlockType(getParaNodeType(state))(state, dispatch); | ||
} | ||
@@ -130,4 +135,4 @@ | ||
return (state: EditorState) => { | ||
const type = getTypeFromSchema(state.schema); | ||
return parentHasDirectParentOfType(type, state.schema.nodes.doc)(state); | ||
const type = getParaNodeType(state); | ||
return parentHasDirectParentOfType(type, getNodeType(state, 'doc'))(state); | ||
}; | ||
@@ -138,3 +143,3 @@ } | ||
return (state: EditorState) => { | ||
const type = getTypeFromSchema(state.schema); | ||
const type = getParaNodeType(state); | ||
return Boolean(findParentNodeOfType(type)(state.selection)); | ||
@@ -146,5 +151,5 @@ }; | ||
return (state, dispatch, view) => { | ||
const type = getTypeFromSchema(state.schema); | ||
const type = getParaNodeType(state); | ||
return filter( | ||
parentHasDirectParentOfType(type, state.schema.nodes.doc), | ||
parentHasDirectParentOfType(type, getNodeType(state, 'doc')), | ||
insertEmpty(type, 'above'), | ||
@@ -157,5 +162,5 @@ )(state, dispatch, view); | ||
return (state, dispatch, view) => { | ||
const type = getTypeFromSchema(state.schema); | ||
const type = getParaNodeType(state); | ||
return filter( | ||
parentHasDirectParentOfType(type, state.schema.nodes.doc), | ||
parentHasDirectParentOfType(type, getNodeType(state, 'doc')), | ||
insertEmpty(type, 'below'), | ||
@@ -168,3 +173,3 @@ )(state, dispatch, view); | ||
return (state, dispatch) => { | ||
const type = getTypeFromSchema(state.schema); | ||
const type = getParaNodeType(state); | ||
return jumpToStartOfNode(type)(state, dispatch); | ||
@@ -176,5 +181,5 @@ }; | ||
return (state, dispatch) => { | ||
const type = getTypeFromSchema(state.schema); | ||
const type = getParaNodeType(state); | ||
return jumpToEndOfNode(type)(state, dispatch); | ||
}; | ||
} |
@@ -6,2 +6,3 @@ import type { EditorProps } from '@bangle.dev/pm'; | ||
gapCursor as pmGapCursor, | ||
InputRule, | ||
inputRules as pmInputRules, | ||
@@ -11,6 +12,6 @@ keymap, | ||
Schema, | ||
InputRule, | ||
undoInputRule as pmUndoInputRule, | ||
} from '@bangle.dev/pm'; | ||
import { bangleWarn } from '@bangle.dev/utils'; | ||
import * as editorStateCounter from './editor-state-counter'; | ||
@@ -17,0 +18,0 @@ import * as history from './history'; |
@@ -1,3 +0,9 @@ | ||
import { Mark, MarkSpec, NodeSpec, Schema, Node } from '@bangle.dev/pm'; | ||
import { MarkSpec, NodeSpec, Schema } from '@bangle.dev/pm'; | ||
import type { | ||
MarkdownParser, | ||
MarkdownSerializer, | ||
UnnestObjValue, | ||
} from '@bangle.dev/shared-types'; | ||
import { bangleWarn } from '@bangle.dev/utils'; | ||
import * as doc from './doc'; | ||
@@ -7,8 +13,6 @@ import * as paragraph from './paragraph'; | ||
import type { MarkdownSerializerState } from 'prosemirror-markdown'; | ||
const LOG = false; | ||
let log = LOG ? console.log.bind(console, 'SpecRegistry') : () => {}; | ||
type PMSpec = NodeSpec | MarkSpec; | ||
export type BaseSpec = BaseRawNodeSpec | BaseRawMarkSpec; | ||
@@ -21,11 +25,4 @@ export interface BaseRawNodeSpec { | ||
markdown?: { | ||
toMarkdown: ( | ||
state: MarkdownSerializerState, | ||
node: Node, | ||
parent: Node, | ||
index: number, | ||
) => void; | ||
parseMarkdown?: { | ||
[key: string]: any; | ||
}; | ||
toMarkdown: UnnestObjValue<MarkdownSerializer['nodes']>; | ||
parseMarkdown?: MarkdownParser['tokens']; | ||
}; | ||
@@ -40,26 +37,4 @@ options?: { [k: string]: any }; | ||
markdown?: { | ||
toMarkdown: { | ||
open: | ||
| string | ||
| (( | ||
_state: MarkdownSerializerState, | ||
mark: Mark, | ||
parent: Node, | ||
index: number, | ||
) => void); | ||
close: | ||
| string | ||
| (( | ||
_state: MarkdownSerializerState, | ||
mark: Mark, | ||
parent: Node, | ||
index: number, | ||
) => void); | ||
mixable?: boolean; | ||
escape?: boolean; | ||
expelEnclosingWhitespace?: boolean; | ||
}; | ||
parseMarkdown?: { | ||
[k: string]: any; | ||
}; | ||
toMarkdown: UnnestObjValue<MarkdownSerializer['marks']>; | ||
parseMarkdown?: MarkdownParser['tokens']; | ||
}; | ||
@@ -78,5 +53,5 @@ options?: { [k: string]: any }; | ||
export class SpecRegistry<N extends string = any, M extends string = any> { | ||
_spec: PMSpec[]; | ||
_options: { [key: string]: any }; | ||
_schema: Schema<N, M>; | ||
_options: { [key: string]: any }; | ||
_spec: BaseSpec[]; | ||
@@ -88,3 +63,3 @@ constructor(rawSpecs: RawSpecs = [], { defaultSpecs = true } = {}) { | ||
const names = new Set(flattenedSpecs.map((r: PMSpec) => r.name)); | ||
const names = new Set(flattenedSpecs.map((r) => r.name)); | ||
@@ -100,3 +75,3 @@ if (flattenedSpecs.length !== names.size) { | ||
if (defaultSpecs) { | ||
const defaultSpecsArray: RawSpecs[] = []; | ||
const defaultSpecsArray: BaseSpec[] = []; | ||
if (!names.has('paragraph')) { | ||
@@ -111,3 +86,3 @@ defaultSpecsArray.unshift(paragraph.spec()); | ||
} | ||
flattenedSpecs = [...flatten(defaultSpecsArray), ...flattenedSpecs]; | ||
flattenedSpecs = [...defaultSpecsArray, ...flattenedSpecs]; | ||
} | ||
@@ -124,4 +99,4 @@ | ||
get spec() { | ||
return this._spec; | ||
get options() { | ||
return this._options; | ||
} | ||
@@ -133,4 +108,4 @@ | ||
get options() { | ||
return this._options; | ||
get spec() { | ||
return this._spec; | ||
} | ||
@@ -140,4 +115,4 @@ } | ||
function createSchema(specRegistry: SpecRegistry['_spec']) { | ||
let nodes = []; | ||
let marks = []; | ||
let nodes: Array<[string, NodeSpec]> = []; | ||
let marks: Array<[string, MarkSpec]> = []; | ||
let topNode; | ||
@@ -147,11 +122,11 @@ for (const spec of specRegistry) { | ||
nodes.push([spec.name, spec.schema]); | ||
if (spec.topNode === true) { | ||
topNode = spec.name; | ||
} | ||
} else if (spec.type === 'mark') { | ||
marks.push([spec.name, spec.schema]); | ||
} else if (spec.type === 'component') { | ||
} else { | ||
throw new Error(spec.name + ' unknown type: ' + spec.type); | ||
let r: any = spec; | ||
throw new Error('Unknown type: ' + r.type); | ||
} | ||
if (spec.topNode === true) { | ||
topNode = spec.name; | ||
} | ||
} | ||
@@ -166,3 +141,3 @@ | ||
function validateSpec(spec: any) { | ||
function validateSpec(spec: BaseSpec) { | ||
if (!spec.name) { | ||
@@ -172,3 +147,3 @@ bangleWarn("The spec didn't have a name field", spec); | ||
} | ||
if (!['node', 'mark', 'component'].includes(spec.type)) { | ||
if (!['node', 'mark'].includes(spec.type)) { | ||
bangleWarn('The spec must be of type node, mark or component ', spec); | ||
@@ -186,9 +161,15 @@ throw new Error('Invalid spec type'); | ||
function flatten(data: RawSpecs): PMSpec[] { | ||
const recurse = (d: RawSpecs): PMSpec[] => { | ||
function flatten(data: RawSpecs): BaseSpec[] { | ||
const recurse = (d: RawSpecs): BaseSpec[] => { | ||
if (Array.isArray(d)) { | ||
return d.flatMap((i) => recurse(i)).filter(Boolean); | ||
return d | ||
.flatMap((i) => recurse(i)) | ||
.filter((r): r is BaseSpec => Boolean(r)); | ||
} | ||
// @ts-ignore really hard to annotate recursive functions | ||
return d; | ||
if (d == null || d === false) { | ||
return []; | ||
} | ||
return [d]; | ||
}; | ||
@@ -195,0 +176,0 @@ |
@@ -1,4 +0,5 @@ | ||
import type { BaseRawNodeSpec } from './spec-registry'; | ||
import { Node } from '@bangle.dev/pm'; | ||
import type { BaseRawNodeSpec } from './spec-registry'; | ||
export const spec = specFactory; | ||
@@ -5,0 +6,0 @@ |
Sorry, the diff of this file is not supported yet
125884
3542
+ Added@bangle.dev/pm-commands@0.29.1-alpha.0(transitive)
+ Added@bangle.dev/shared-types@0.29.1-alpha.0(transitive)
+ Added@bangle.dev/utils@0.29.1-alpha.0(transitive)
+ Added@types/linkify-it@5.0.0(transitive)
+ Added@types/markdown-it@14.1.2(transitive)
+ Added@types/mdurl@2.0.0(transitive)
+ Addedargparse@2.0.1(transitive)
+ Addedentities@4.5.0(transitive)
+ Addedlinkify-it@5.0.0(transitive)
+ Addedmarkdown-it@14.1.0(transitive)
+ Addedmdurl@2.0.0(transitive)
+ Addedprosemirror-markdown@1.13.1(transitive)
+ Addedpunycode.js@2.3.1(transitive)
+ Addeduc.micro@2.1.0(transitive)
- Removed@types/jest@^27.0.4
- Removed@bangle.dev/pm-commands@0.29.0(transitive)
- Removed@bangle.dev/utils@0.29.0(transitive)