diff --git a/demo/src/app/app.component.scss b/demo/src/app/app.component.scss index f9465321..e2b5683a 100644 --- a/demo/src/app/app.component.scss +++ b/demo/src/app/app.component.scss @@ -33,3 +33,22 @@ } } } + +.CustomMenuItem { + padding: 0 0.3rem; + border-radius: 2px; + + &.NgxEditor-MenuItem__Active { + background-color: #e8f0fe; + color: #1a73e8; + } +} + +.CodeMirror { + border: 1px solid #eee; + height: auto; + + pre { + white-space: pre !important; + } +} diff --git a/demo/src/app/app.component.ts b/demo/src/app/app.component.ts index 041bda71..e8702f50 100644 --- a/demo/src/app/app.component.ts +++ b/demo/src/app/app.component.ts @@ -1,10 +1,11 @@ -import { Component } from '@angular/core'; +import { Component, ViewEncapsulation } from '@angular/core'; import { environment } from '../environments/environment'; @Component({ selector: 'app-root', templateUrl: 'app.component.html', - styleUrls: ['app.component.scss'] + styleUrls: ['app.component.scss'], + encapsulation: ViewEncapsulation.None }) export class AppComponent { diff --git a/demo/src/app/app.module.ts b/demo/src/app/app.module.ts index 2da10f16..524d74f5 100644 --- a/demo/src/app/app.module.ts +++ b/demo/src/app/app.module.ts @@ -6,7 +6,9 @@ import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { NgxEditorModule } from 'ngx-editor'; -import { getPlugins } from './plugin'; +import schema from './schema'; +import plugins from './plugins'; +import nodeViews from './nodeviews'; @NgModule({ declarations: [ @@ -17,7 +19,9 @@ import { getPlugins } from './plugin'; BrowserModule, FormsModule, NgxEditorModule.forRoot({ - plugins: getPlugins() + schema, + plugins, + nodeViews }), ], bootstrap: [AppComponent] diff --git a/demo/src/app/nodeviews/CodeMirror.ts b/demo/src/app/nodeviews/CodeMirror.ts new file mode 100644 index 00000000..a21daf46 --- /dev/null +++ b/demo/src/app/nodeviews/CodeMirror.ts @@ -0,0 +1,164 @@ +import { exitCode } from 'prosemirror-commands'; +import { undo, redo } from 'prosemirror-history'; +import { TextSelection, Selection } from 'prosemirror-state'; +import { Node as ProsemirrorNode } from 'prosemirror-model'; +import { EditorView } from 'prosemirror-view'; + +import CodeMirror from 'codemirror'; +import 'codemirror/mode/javascript/javascript'; + +import schema from '../schema'; + +function computeChange(oldVal: string, newVal: string) { + if (oldVal === newVal) { return null; } + let start = 0; + let oldEnd = oldVal.length; + let newEnd = newVal.length; + while (start < oldEnd && oldVal.charCodeAt(start) === newVal.charCodeAt(start)) { + ++start; + } + while (oldEnd > start && newEnd > start && oldVal.charCodeAt(oldEnd - 1) === newVal.charCodeAt(newEnd - 1)) { + oldEnd--; newEnd--; + } + return { from: start, to: oldEnd, text: newVal.slice(start, newEnd) }; +} + +type GetPos = () => number; + +class CodeMirrorView { + node: ProsemirrorNode; + getPos: GetPos; + incomingChanges: boolean; + + cm: CodeMirror; + + view: EditorView; + dom: HTMLElement; + updating: boolean; + + constructor(node: ProsemirrorNode, view: EditorView, getPos: GetPos) { + // Store for later + this.node = node; + this.view = view; + this.getPos = getPos; + this.incomingChanges = false; + + // Create a CodeMirror instance + this.cm = new CodeMirror(null, { + value: this.node.textContent, + lineNumbers: true, + extraKeys: this.codeMirrorKeymap() + }); + + // The editor's outer node is our DOM representation + this.dom = this.cm.getWrapperElement(); + // CodeMirror needs to be in the DOM to properly initialize, so + // schedule it to update itself + setTimeout(() => this.cm.refresh(), 20); + + // This flag is used to avoid an update loop between the outer and + // inner editor + this.updating = false; + // Track whether changes are have been made but not yet propagated + this.cm.on('beforeChange', () => this.incomingChanges = true); + // Propagate updates from the code editor to ProseMirror + this.cm.on('cursorActivity', () => { + if (!this.updating && !this.incomingChanges) { this.forwardSelection(); } + }); + + this.cm.on('changes', () => { + if (!this.updating) { + this.valueChanged(); + this.forwardSelection(); + } + this.incomingChanges = false; + }); + + this.cm.on('focus', () => this.forwardSelection()); + } + + forwardSelection() { + if (!this.cm.hasFocus()) { + return; + } + + const state = this.view.state; + const selection = this.asProseMirrorSelection(state.doc); + + if (!selection.eq(state.selection)) { + this.view.dispatch(state.tr.setSelection(selection)); + } + } + + asProseMirrorSelection(doc: ProsemirrorNode) { + const offset = this.getPos() + 1; + const anchor = this.cm.indexFromPos(this.cm.getCursor('anchor')) + offset; + const head = this.cm.indexFromPos(this.cm.getCursor('head')) + offset; + return TextSelection.create(doc, anchor, head); + } + + setSelection(anchor: number, head: number) { + this.cm.focus(); + this.updating = true; + this.cm.setSelection(this.cm.posFromIndex(anchor), this.cm.posFromIndex(head)); + this.updating = false; + } + + valueChanged() { + const change = computeChange(this.node.textContent, this.cm.getValue()); + if (change) { + const start = this.getPos() + 1; + const tr = this.view.state.tr.replaceWith( + start + change.from, start + change.to, + change.text ? schema.text(change.text) : null); + this.view.dispatch(tr); + } + } + codeMirrorKeymap() { + const view = this.view; + const mod = /Mac/.test(navigator.platform) ? 'Cmd' : 'Ctrl'; + return CodeMirror.normalizeKeyMap({ + Up: () => this.maybeEscape('line', -1), + Left: () => this.maybeEscape('char', -1), + Down: () => this.maybeEscape('line', 1), + Right: () => this.maybeEscape('char', 1), + [`${mod}-Z`]: () => undo(view.state, view.dispatch), + [`Shift-${mod}-Z`]: () => redo(view.state, view.dispatch), + [`${mod}-Y`]: () => redo(view.state, view.dispatch), + 'Ctrl-Enter': () => { + if (exitCode(view.state, view.dispatch)) { view.focus(); } + } + }); + } + + maybeEscape(unit: string, dir: number) { + const pos = this.cm.getCursor(); + if (this.cm.somethingSelected() || + pos.line !== (dir < 0 ? this.cm.firstLine() : this.cm.lastLine()) || + (unit === 'char' && + pos.ch !== (dir < 0 ? 0 : this.cm.getLine(pos.line).length))) { + return CodeMirror.Pass; + } + + this.view.focus(); + const targetPos = this.getPos() + (dir < 0 ? 0 : this.node.nodeSize); + const selection = Selection.near(this.view.state.doc.resolve(targetPos), dir); + this.view.dispatch(this.view.state.tr.setSelection(selection).scrollIntoView()); + this.view.focus(); + } + + update(node: ProsemirrorNode) { + if (node.type !== this.node.type) { return false; } + this.node = node; + const change = computeChange(this.cm.getValue(), node.textContent); + if (change) { + this.updating = true; + this.cm.replaceRange(change.text, this.cm.posFromIndex(change.from), + this.cm.posFromIndex(change.to)); + this.updating = false; + } + return true; + } +} + +export default CodeMirrorView; diff --git a/demo/src/app/nodeviews/index.ts b/demo/src/app/nodeviews/index.ts new file mode 100644 index 00000000..c948a0c4 --- /dev/null +++ b/demo/src/app/nodeviews/index.ts @@ -0,0 +1,11 @@ +import CodeBlockView from './CodeMirror'; +import { Node as ProsemirrorNode } from 'prosemirror-model'; +import { EditorView } from 'prosemirror-view'; + +const nodeViews = { + code_block: (node: ProsemirrorNode, view: EditorView, getPos: () => number) => { + return new CodeBlockView(node, view, getPos); + } +}; + +export default nodeViews; diff --git a/demo/src/app/plugin.ts b/demo/src/app/plugins/index.ts similarity index 89% rename from demo/src/app/plugin.ts rename to demo/src/app/plugins/index.ts index 8efe91a0..d586bce6 100644 --- a/demo/src/app/plugin.ts +++ b/demo/src/app/plugins/index.ts @@ -6,6 +6,8 @@ import { keymap } from 'prosemirror-keymap'; import { toggleMark, baseKeymap } from 'prosemirror-commands'; import { Plugin } from 'prosemirror-state'; +import codemirrorMenu from './menu/codemirror'; + const isMacOs = /Mac/.test(navigator.platform); export type KeyMap = { [key: string]: any }; @@ -35,7 +37,7 @@ const getListKeyMap = (): KeyMap => { return listMap; }; -export const getPlugins = (): Plugin[] => { +const getPlugins = (): Plugin[] => { const historyKeyMap = getHistoryKeyMap(); const listKeyMap = getListKeyMap(); @@ -54,7 +56,8 @@ export const getPlugins = (): Plugin[] => { ['bold', 'italic'], ['code'], ['ordered_list', 'bullet_list'], - [{ heading: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] }] + [{ heading: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] }], + [codemirrorMenu] ], labels: { bold: 'Bold', @@ -70,3 +73,5 @@ export const getPlugins = (): Plugin[] => { return plugins; }; + +export default getPlugins(); diff --git a/demo/src/app/plugins/menu/codemirror.ts b/demo/src/app/plugins/menu/codemirror.ts new file mode 100644 index 00000000..c53397ff --- /dev/null +++ b/demo/src/app/plugins/menu/codemirror.ts @@ -0,0 +1,48 @@ +import { EditorState } from 'prosemirror-state'; +import { isNodeActive, toggleBlockType, ToolbarCustomMenuItem } from 'ngx-editor'; + +import schema from '../../schema'; + +const codeMirror: ToolbarCustomMenuItem = (editorView) => { + const dom: HTMLElement = document.createElement('div'); + dom.innerHTML = 'CodeMirror'; + + dom.classList.add('NgxEditor-MenuItem'); + dom.classList.add('CustomMenuItem'); + + const type = schema.nodes.code_block; + + let command; + + dom.addEventListener('mousedown', (e: MouseEvent) => { + e.preventDefault(); + + // don't execute if not left click + if (e.buttons !== 1) { + return; + } + + command = toggleBlockType(type, schema.nodes.paragraph); + command(editorView.state, editorView.dispatch); + }); + + + const update = (state: EditorState): void => { + const isActive = isNodeActive(state, type); + let canExecute = true; + + if (command) { + canExecute = command(state, null); + } + + dom.classList.toggle(`NgxEditor-MenuItem__Active`, isActive); + dom.classList.toggle(`disabled`, !canExecute); + }; + + return { + dom, + update + }; +}; + +export default codeMirror; diff --git a/demo/src/app/schema.ts b/demo/src/app/schema.ts new file mode 100644 index 00000000..a99b2662 --- /dev/null +++ b/demo/src/app/schema.ts @@ -0,0 +1,38 @@ +import { nodes as basicNodes, marks as basicMarks } from 'ngx-editor'; +import { Schema, Node as ProsemirrorNode, NodeSpec } from 'prosemirror-model'; + +const codeBlock: NodeSpec = { + group: 'block', + attrs: { + text: { default: '' }, + language: { default: 'text/javascript' } + }, + parseDOM: [{ + tag: 'pre', + getAttrs: (dom: HTMLElement) => { + return { + text: dom.textContent, + language: dom.getAttribute('data-language') || 'text/plain' + }; + } + } + ], + toDOM(node: ProsemirrorNode) { + return ['pre', { 'data-language': node.attrs.language }, node.attrs.text]; + } +}; + +const nodes = Object.assign( + {}, + basicNodes, + { + code_mirror: codeBlock + } +); + +const schema = new Schema({ + nodes, + marks: basicMarks +}); + +export default schema; diff --git a/demo/src/styles.scss b/demo/src/styles.scss index e69de29b..27511705 100644 --- a/demo/src/styles.scss +++ b/demo/src/styles.scss @@ -0,0 +1 @@ +@import "~codemirror/lib/codemirror.css"; diff --git a/package-lock.json b/package-lock.json index 114548c6..11bcec43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4032,6 +4032,12 @@ } } }, + "codemirror": { + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.54.0.tgz", + "integrity": "sha512-Pgf3surv4zvw+KaW3doUU7pGjF0BPU8/sj7eglWJjzni46U/DDW8pu3nZY0QgQKUcICDXRkq8jZmq0y6KhxM3Q==", + "dev": true + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", diff --git a/package.json b/package.json index 3e11e896..7a31a04a 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@types/prosemirror-view": "^1.11.4", "chalk": "^4.0.0", "codelyzer": "^5.1.2", + "codemirror": "^5.54.0", "eslint": "^6.8.0", "eslint-config-airbnb-base": "^14.1.0", "eslint-plugin-import": "^2.20.2", diff --git a/src/lib/ngx-editor.component.scss b/src/lib/ngx-editor.component.scss index f22cfdc5..9f703c7b 100644 --- a/src/lib/ngx-editor.component.scss +++ b/src/lib/ngx-editor.component.scss @@ -73,6 +73,7 @@ $icon-size: 30px; border-radius: 4px; background-color: white; display: none; + z-index: 10; .NgxEditor-MenuItem__Dropdown-Item { cursor: pointer; @@ -80,7 +81,7 @@ $icon-size: 30px; white-space: nowrap; &:hover, - &.NgxEditor-MenuItem__active { + &.NgxEditor-MenuItem__Active { background-color: #f1f1f1; } } @@ -114,6 +115,11 @@ $icon-size: 30px; border-left: 1px solid #ccc; margin: 0 5px; } + + .disabled { + opacity: 0.5; + pointer-events: none; + } } .NgxEditor-Content { diff --git a/src/lib/ngx-editor.component.ts b/src/lib/ngx-editor.component.ts index db6b397a..179f2c61 100644 --- a/src/lib/ngx-editor.component.ts +++ b/src/lib/ngx-editor.component.ts @@ -1,6 +1,6 @@ import { Component, ViewChild, ElementRef, - Input, forwardRef, OnDestroy, OnInit, ViewEncapsulation + forwardRef, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; @@ -10,8 +10,6 @@ import { Node as ProsemirrorNode } from 'prosemirror-model'; import { NgxEditorService, NgxEditorServiceConfig } from './ngx-editor.service'; -import schema from './schema'; - @Component({ selector: 'ngx-editor', templateUrl: 'ngx-editor.component.html', @@ -51,6 +49,7 @@ export class NgxEditorComponent implements ControlValueAccessor, OnInit, OnDestr registerOnTouched(): void { } private parseDoc(contentJson: object): ProsemirrorNode { + const { schema } = this.config; return schema.nodeFromJSON(contentJson); } @@ -79,11 +78,14 @@ export class NgxEditorComponent implements ControlValueAccessor, OnInit, OnDestr } createEditor() { + const { schema, plugins, nodeViews } = this.config; + this.view = new EditorView(this.ngxEditor.nativeElement, { state: EditorState.create({ schema, - plugins: this.config.plugins, + plugins, }), + nodeViews, dispatchTransaction: this.handleTransactions.bind(this), attributes: { class: 'NgxEditor-Content' diff --git a/src/lib/ngx-editor.service.ts b/src/lib/ngx-editor.service.ts index ab1d2996..d8b4ee60 100644 --- a/src/lib/ngx-editor.service.ts +++ b/src/lib/ngx-editor.service.ts @@ -1,23 +1,32 @@ import { Injectable, Optional } from '@angular/core'; -import { NgxEditorConfig } from './types'; +import { Schema } from 'prosemirror-model'; +import { Plugin } from 'prosemirror-state'; + +import { NgxEditorConfig, NodeViews } from './types'; import menu from './prosemirror/plugins/menu'; import placeholder from './prosemirror/plugins/placeholder'; +import { schema } from './schema'; @Injectable({ providedIn: 'root' }) + export class NgxEditorServiceConfig { - public plugins = [ + public plugins: Plugin[] = [ menu(), placeholder() ]; + + public nodeViews: NodeViews = {}; + public schema: Schema = schema; } @Injectable({ providedIn: 'root' }) + export class NgxEditorService { config: NgxEditorServiceConfig; @@ -26,6 +35,12 @@ export class NgxEditorService { } } +const defaultConfig: NgxEditorConfig = { + plugins: [], + nodeViews: {}, + schema +}; + export function provideMyServiceOptions(config?: NgxEditorConfig): NgxEditorConfig { - return (config); + return Object.assign({}, defaultConfig, config); } diff --git a/src/lib/prosemirror/plugins/menu/menu.ts b/src/lib/prosemirror/plugins/menu/menu.ts index 6ab4c5b3..c302d16c 100644 --- a/src/lib/prosemirror/plugins/menu/menu.ts +++ b/src/lib/prosemirror/plugins/menu/menu.ts @@ -1,33 +1,31 @@ import { toggleMark } from 'prosemirror-commands'; import { EditorView } from 'prosemirror-view'; import { EditorState } from 'prosemirror-state'; -import { MarkType, NodeType } from 'prosemirror-model'; +import { MarkType, NodeType, Schema } from 'prosemirror-model'; import { MenuItemViewSpec, ToolbarItem, ToolbarDropdownGroupKeys, ToolbarDropdownGroupValues, - MenuOptions + MenuOptions, + Command } from '../../../types'; -import schema from '../../../schema'; - -import isNodeActive from '../../helpers/isNodeActive'; -import isMarkActive from '../../helpers/isMarkActive'; +import { isNodeActive, isMarkActive } from '../../helpers'; import { toggleList, toggleBlockType } from '../../commands'; import { getIconSvg } from '../../../utils/icons'; import flatDeep from '../../../utils/flatDeep'; -import menuItemsMeta, {MenuItemMeta} from './meta'; +import menuItemsMeta, { MenuItemMeta } from './meta'; const MENU_ITEM_CLASSNAME = 'NgxEditor-MenuItem'; const DROPDOWN_ITEMS = new Map(); DROPDOWN_ITEMS.set('heading', ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']); -const isListItem = (type: NodeType) => { +const isListItem = (type: NodeType, schema: Schema) => { return ( type === schema.nodes.list_item || type === schema.nodes.ordered_list || @@ -197,12 +195,15 @@ class MenuItemView { render() { const dom = this.dom = this.getDom(); - this.setupCommandListeners(); + const { schema } = this.editorView.state; + const { command } = this.setupCommandListeners(); const update = (state: EditorState): void => { const menuItem = this.menuItem; let isActive = false; + const canExecute = command(this.editorView.state, null); + if (menuItem.type === 'mark') { const type: MarkType = schema.marks[menuItem.key]; isActive = isMarkActive(state, type); @@ -214,6 +215,7 @@ class MenuItemView { } dom.classList.toggle(`${MENU_ITEM_CLASSNAME}__Active`, isActive); + dom.classList.toggle(`disabled`, !canExecute); }; return { @@ -249,6 +251,26 @@ class MenuItemView { } private setupCommandListeners() { + const { schema } = this.editorView.state; + + let command: Command; + + if (this.menuItem.type === 'mark') { + command = toggleMark(schema.marks[this.menuItem.key]); + } + + if (this.menuItem.type === 'node') { + const type = schema.nodes[this.menuItem.key]; + + if (isListItem(type, schema)) { + command = toggleList(type, schema.nodes.list_item); + } + + if (type === schema.nodes.heading) { + command = toggleBlockType(type, schema.nodes.paragraph, { level: this.menuItem.attrs.level }); + } + } + this.dom.addEventListener('mousedown', (e: MouseEvent) => { e.preventDefault(); @@ -257,28 +279,11 @@ class MenuItemView { return; } - if (this.menuItem.type === 'mark') { - const command = toggleMark(schema.marks[this.menuItem.key]); - command(this.editorView.state, this.editorView.dispatch); - return; - } - - if (this.menuItem.type === 'node') { - const type = schema.nodes[this.menuItem.key]; - - if (isListItem(type)) { - const command = toggleList(type, schema.nodes.list_item); - command(this.editorView.state, this.editorView.dispatch); - return; - } - - if (type === schema.nodes.heading) { - const command = toggleBlockType(type, schema.nodes.paragraph, { level: this.menuItem.attrs.level }); - command(this.editorView.state, this.editorView.dispatch); - return; - } - } + // execute command + command(this.editorView.state, this.editorView.dispatch); }); + + return { command }; } } @@ -342,6 +347,12 @@ export const renderMenu = (options: MenuOptions, editorView: EditorView, menuDom } } + if (typeof toolbarItem === 'function') { + const { dom, update } = toolbarItem(editorView); + menuDom.appendChild(dom); + updates.push(update); + } + if (isLastMenuItem && !isLastMenuGroup) { const seperatorDom = getSeperatorDom(); menuDom.appendChild(seperatorDom); diff --git a/src/lib/schema.ts b/src/lib/schema.ts index 22d63427..ac882362 100644 --- a/src/lib/schema.ts +++ b/src/lib/schema.ts @@ -8,7 +8,7 @@ const listItem = Object.assign({}, schemaList.listItem, { content: 'paragraph bl const orderedList = Object.assign({}, schemaList.orderedList, { content: 'list_item+', group: listGroup }); const bulletList = Object.assign({}, schemaList.bulletList, { content: 'list_item+', group: listGroup }); -const nodes = Object.assign( +export const nodes = Object.assign( {}, schemaBasic.nodes, { @@ -18,9 +18,9 @@ const nodes = Object.assign( } ); -const schema = new Schema({ - marks: schemaBasic.marks, +export const marks = schemaBasic.marks; + +export const schema = new Schema({ + marks, nodes }); - -export default schema; diff --git a/src/lib/types.ts b/src/lib/types.ts index 26ef5d06..7ca3df76 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,9 +1,14 @@ -import { Plugin } from 'prosemirror-state'; +import { Plugin, EditorState, Transaction } from 'prosemirror-state'; +import { Node as ProsemirrorNode, Schema } from 'prosemirror-model'; +import { EditorView, Decoration, NodeView } from 'prosemirror-view'; + +type TCR = { dom: HTMLElement, update: (state: EditorState) => void }; export type ToolbarDropdown = { heading?: string[] }; +export type ToolbarCustomMenuItem = (editorView: EditorView) => TCR; export type ToolbarDropdownGroupKeys = keyof ToolbarDropdown; export type ToolbarDropdownGroupValues = ToolbarDropdown[ToolbarDropdownGroupKeys]; -export type ToolbarItem = string | ToolbarDropdown; +export type ToolbarItem = string | ToolbarDropdown | ToolbarCustomMenuItem; export type Toolbar = Array | null; export interface MenuItemViewSpec { @@ -13,12 +18,26 @@ export interface MenuItemViewSpec { attrs?: { [key: string]: string }; } +export interface NodeViews { + [name: string]: ( + node: ProsemirrorNode, + view: EditorView, + getPos: () => number, + decorations: Decoration[] + ) => NodeView; +} + export interface NgxEditorConfig { - plugins: Plugin[]; + schema?: Schema; + plugins?: Plugin[]; + nodeViews?: NodeViews; } export type MenuLabels = { [key: string]: string }; export interface MenuOptions { toolbar?: Toolbar; labels?: MenuLabels; + schema?: Schema; } + +export type Command = (schema: EditorState, dispatch: (tr: Transaction) => void) => boolean; diff --git a/src/ng-package.json b/src/ng-package.json index 5b16347a..42ac6e88 100644 --- a/src/ng-package.json +++ b/src/ng-package.json @@ -2,7 +2,7 @@ "$schema": "../node_modules/ng-packagr/ng-package.schema.json", "dest": "../dist/ngx-editor", "lib": { - "entryFile": "./public-api.ts", + "entryFile": "./public_api.ts", "umdModuleIds": { "prosemirror-state": "prosemirrorState", "prosemirror-view": "prosemirrorView", diff --git a/src/public-api.ts b/src/public_api.ts similarity index 80% rename from src/public-api.ts rename to src/public_api.ts index 3103cc11..0d702d2e 100644 --- a/src/public-api.ts +++ b/src/public_api.ts @@ -5,7 +5,10 @@ export * from './lib/ngx-editor.component'; export * from './lib/ngx-editor.module'; -export { default as schema } from './lib/schema'; +export * from './lib/schema'; + export * from './lib/prosemirror/plugins'; export * from './lib/prosemirror/commands'; export * from './lib/prosemirror/helpers'; + +export * from './lib/types';