diff --git a/docs/src/demos/Experiments/Linter/extension/Linter.ts b/docs/src/demos/Experiments/Linter/extension/Linter.ts index 7da886b3..ab5edc5b 100644 --- a/docs/src/demos/Experiments/Linter/extension/Linter.ts +++ b/docs/src/demos/Experiments/Linter/extension/Linter.ts @@ -1,10 +1,15 @@ -// @ts-nocheck import { Extension } from '@tiptap/core' import { Decoration, DecorationSet } from 'prosemirror-view' import { Plugin, PluginKey, TextSelection } from 'prosemirror-state' +import { Node as ProsemirrorNode } from 'prosemirror-model' +import LinterPlugin, { Result as Issue } from './LinterPlugin' -function renderIcon(issue) { - const icon = document.createElement('div') +interface IconDivElement extends HTMLDivElement { + issue?: Issue +} + +function renderIcon(issue: Issue) { + const icon: IconDivElement = document.createElement('div') icon.className = 'lint-icon' icon.title = issue.message @@ -13,11 +18,11 @@ function renderIcon(issue) { return icon } -function runAllLinterPlugins(doc, plugins) { +function runAllLinterPlugins(doc: ProsemirrorNode, plugins: Array) { const decorations: [any?] = [] - const results = plugins.map(LinterPlugin => { - return new LinterPlugin(doc).scan().getResults() + const results = plugins.map(RegisteredLinterPlugin => { + return new RegisteredLinterPlugin(doc).scan().getResults() }).flat() results.forEach(issue => { @@ -31,7 +36,7 @@ function runAllLinterPlugins(doc, plugins) { } export interface LinterOptions { - plugins: [any], + plugins: Array, } export const Linter = Extension.create({ @@ -62,8 +67,9 @@ export const Linter = Extension.create({ return this.getState(state) }, handleClick(view, _, event) { - if (/lint-icon/.test(event.target.className)) { - const { from, to } = event.target.issue + const target = (event.target as IconDivElement) + if (/lint-icon/.test(target.className) && target.issue) { + const { from, to } = target.issue view.dispatch( view.state.tr @@ -73,17 +79,22 @@ export const Linter = Extension.create({ return true } + + return false }, handleDoubleClick(view, _, event) { - if (/lint-icon/.test(event.target.className)) { - const prob = event.target.issue + const target = (event.target as IconDivElement) + if (/lint-icon/.test((event.target as HTMLElement).className) && target.issue) { + const prob = target.issue if (prob.fix) { - prob.fix(view) + prob.fix(view, prob) view.focus() return true } } + + return false }, }, }), diff --git a/docs/src/demos/Experiments/Linter/extension/LinterPlugin.ts b/docs/src/demos/Experiments/Linter/extension/LinterPlugin.ts index 809c6601..200b146b 100644 --- a/docs/src/demos/Experiments/Linter/extension/LinterPlugin.ts +++ b/docs/src/demos/Experiments/Linter/extension/LinterPlugin.ts @@ -1,8 +1,10 @@ -interface Result { +import { Node as ProsemirrorNode } from 'prosemirror-model' + +export interface Result { message: string, from: number, to: number, - fix?: null + fix?: Function } export default class LinterPlugin { @@ -10,11 +12,11 @@ export default class LinterPlugin { private results: Array = [] - constructor(doc: any) { + constructor(doc: ProsemirrorNode) { this.doc = doc } - record(message: string, from: number, to: number, fix?: null) { + record(message: string, from: number, to: number, fix?: Function) { this.results.push({ message, from, @@ -23,6 +25,10 @@ export default class LinterPlugin { }) } + scan() { + return this + } + getResults() { return this.results } diff --git a/docs/src/demos/Experiments/Linter/extension/plugins/BadWords.ts b/docs/src/demos/Experiments/Linter/extension/plugins/BadWords.ts index 59194c21..6111b4d8 100644 --- a/docs/src/demos/Experiments/Linter/extension/plugins/BadWords.ts +++ b/docs/src/demos/Experiments/Linter/extension/plugins/BadWords.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import LinterPlugin from '../LinterPlugin' export class BadWords extends LinterPlugin { @@ -6,7 +5,7 @@ export class BadWords extends LinterPlugin { public regex = /\b(obviously|clearly|evidently|simply)\b/ig scan() { - this.doc.descendants((node: any, position: any) => { + this.doc.descendants((node: any, position: number) => { if (!node.isText) { return } diff --git a/docs/src/demos/Experiments/Linter/extension/plugins/HeadingLevel.ts b/docs/src/demos/Experiments/Linter/extension/plugins/HeadingLevel.ts index df78dacf..001d5122 100644 --- a/docs/src/demos/Experiments/Linter/extension/plugins/HeadingLevel.ts +++ b/docs/src/demos/Experiments/Linter/extension/plugins/HeadingLevel.ts @@ -1,15 +1,15 @@ -// @ts-nocheck -import LinterPlugin from '../LinterPlugin' +import { EditorView } from 'prosemirror-view' +import LinterPlugin, { Result as Issue } from '../LinterPlugin' export class HeadingLevel extends LinterPlugin { - fixHeader(level) { - return function ({ state, dispatch }) { - dispatch(state.tr.setNodeMarkup(this.from - 1, null, { level })) + fixHeader(level: number) { + return function ({ state, dispatch }: EditorView, issue: Issue) { + dispatch(state.tr.setNodeMarkup(issue.from - 1, undefined, { level })) } } scan() { - let lastHeadLevel = null + let lastHeadLevel: number | null = null this.doc.descendants((node, position) => { if (node.type.name === 'heading') { diff --git a/docs/src/demos/Experiments/Linter/extension/plugins/Punctuation.ts b/docs/src/demos/Experiments/Linter/extension/plugins/Punctuation.ts index d3a228d7..befd7d63 100644 --- a/docs/src/demos/Experiments/Linter/extension/plugins/Punctuation.ts +++ b/docs/src/demos/Experiments/Linter/extension/plugins/Punctuation.ts @@ -1,14 +1,14 @@ -// @ts-nocheck -import LinterPlugin from '../LinterPlugin' +import { EditorView } from 'prosemirror-view' +import LinterPlugin, { Result as Issue } from '../LinterPlugin' export class Punctuation extends LinterPlugin { public regex = / ([,.!?:]) ?/g fix(replacement: any) { - return function ({ state, dispatch }) { + return function ({ state, dispatch }: EditorView, issue: Issue) { dispatch( state.tr.replaceWith( - this.from, this.to, + issue.from, issue.to, state.schema.text(replacement), ), ) @@ -17,9 +17,9 @@ export class Punctuation extends LinterPlugin { scan() { this.doc.descendants((node, position) => { - if (!node.isText) { - return - } + if (!node.isText) return + + if (!node.text) return const matches = this.regex.exec(node.text) diff --git a/docs/src/docPages/experiments/linter.md b/docs/src/docPages/experiments/linter.md index 8335903a..f66f9502 100644 --- a/docs/src/docPages/experiments/linter.md +++ b/docs/src/docPages/experiments/linter.md @@ -1,6 +1,8 @@ # Linter -⚠️ Experiment +⚠️ Experiment, currently not supported or maintained + +Linter can be used to check the content as per your wish and highlight it to the user. Linter extension can have multiple plugins for each task you want to achieve. ## Issues * There is no decoration API in tiptap, that’s why this is a lot of ProseMirror work. Before we’ll publish that example, we’d need to find a few ways to make it more tiptap-like. For example, it would be great to use Vue/React components for the widget.