prosemirror-suggestcat-plugin 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +96 -0
- package/dist/createUpdatePopup.d.ts +2 -0
- package/dist/defaults.d.ts +2 -0
- package/dist/eventHandlers.d.ts +9 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/makeRequest.d.ts +4 -0
- package/dist/mapping.d.ts +7 -0
- package/dist/mapping.test.d.ts +1 -0
- package/dist/mergeDiffs.d.ts +11 -0
- package/dist/mergeDiffs.test.d.ts +1 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/styles/styles.css +64 -0
- package/dist/types.d.ts +75 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.test.d.ts +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Emergence Engineering
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# prosemirror-suggestcat-plugin
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
[**Made by Emergence-Engineering**](https://emergence-engineering.com/)
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Adds AI features to your ProseMirror editor
|
|
10
|
+
- Coming soon: text completion, rewriting with a given style, YJS support and more!
|
|
11
|
+
|
|
12
|
+
## How to use?
|
|
13
|
+
|
|
14
|
+
- Create your API_KEY on [SuggestCat](https://www.suggestcat.com/)
|
|
15
|
+
- Add `grammarSuggestPlugin`
|
|
16
|
+
- Add your api key
|
|
17
|
+
- And `defaultOptions` which you can override
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import {
|
|
21
|
+
grammarSuggestPlugin,
|
|
22
|
+
defaultOptions,
|
|
23
|
+
} from "prosemirror-suggestcat-plugin";
|
|
24
|
+
|
|
25
|
+
const view = new EditorView(document.querySelector("#editor"), {
|
|
26
|
+
state: EditorState.create({
|
|
27
|
+
doc: schema.nodeFromJSON(initialDoc),
|
|
28
|
+
plugins: [
|
|
29
|
+
...exampleSetup({schema}),
|
|
30
|
+
grammarSuggestPlugin(PROSEMIRROR_SUGGESTCAT_PLUGIN_API_KEY, {
|
|
31
|
+
...defaultOptions,
|
|
32
|
+
}),
|
|
33
|
+
],
|
|
34
|
+
}),
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Options
|
|
39
|
+
|
|
40
|
+
- `GrammarSuggestPluginOptions`
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
export type GrammarSuggestPluginOptions = {
|
|
44
|
+
debounceMs: number;
|
|
45
|
+
createUpdatePopup: (
|
|
46
|
+
view: EditorView,
|
|
47
|
+
decoration: Decoration,
|
|
48
|
+
pos: number,
|
|
49
|
+
applySuggestion: (view: EditorView, decoration: Decoration) => void,
|
|
50
|
+
discardSuggestion: (view: EditorView, decoration: Decoration) => void,
|
|
51
|
+
) => HTMLElement;
|
|
52
|
+
};
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- `defaultOptions` which you can import from our library
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
export const defaultOptions: GrammarSuggestPluginOptions = {
|
|
59
|
+
debounceMs: 2000,
|
|
60
|
+
createUpdatePopup,
|
|
61
|
+
};
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Styles
|
|
65
|
+
|
|
66
|
+
- Add our css for the popup, or you can create your own using `createUpdatePopup` option
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import "prosemirror-suggestcat-plugin/dist/styles/styles.css";
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- Our popup structure:
|
|
73
|
+
|
|
74
|
+
```html
|
|
75
|
+
|
|
76
|
+
<div classname="grammar-suggest-tooltip ProseMirror-widget">
|
|
77
|
+
<div classname="grammar-suggest-tooltip-apply">
|
|
78
|
+
suggestion
|
|
79
|
+
</div
|
|
80
|
+
<div classname="grammar-suggest-tooltip-discard">
|
|
81
|
+
<svg/>
|
|
82
|
+
</div
|
|
83
|
+
</div
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- Style the editor decorations with the follwing classnames
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
.grammarSuggestion {
|
|
90
|
+
background-color: green;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.grammarSuggestion .removalSuggestion {
|
|
94
|
+
background-color: red;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { Decoration, EditorView } from "prosemirror-view";
|
|
2
|
+
export declare const createUpdatePopup: (view: EditorView, decoration: Decoration, pos: number, applySuggestion: (view: EditorView, decoration: Decoration) => void, discardSuggestion: (view: EditorView, decoration: Decoration) => void) => HTMLDivElement;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EditorView } from "prosemirror-view";
|
|
2
|
+
import { EditorState, Transaction } from "prosemirror-state";
|
|
3
|
+
import { AcceptSuggestionMeta, DiscardSuggestionMeta, GrammarSuggestPluginOptions, GrammarSuggestPluginState, OpenSuggestionMeta, UpdateSuggestionMeta } from "./types";
|
|
4
|
+
export declare const handleUpdate: (pluginState: GrammarSuggestPluginState, meta: UpdateSuggestionMeta, tr: Transaction) => GrammarSuggestPluginState;
|
|
5
|
+
export declare const handleAccept: (pluginState: GrammarSuggestPluginState, meta: AcceptSuggestionMeta, tr: Transaction) => GrammarSuggestPluginState;
|
|
6
|
+
export declare const handleDocChange: (pluginState: GrammarSuggestPluginState, tr: Transaction, oldState: EditorState) => GrammarSuggestPluginState;
|
|
7
|
+
export declare const handleOpenSuggestion: (pluginState: GrammarSuggestPluginState, meta: OpenSuggestionMeta, tr: Transaction, options: GrammarSuggestPluginOptions) => GrammarSuggestPluginState;
|
|
8
|
+
export declare const handleClick: (view: EditorView, pos: number) => boolean;
|
|
9
|
+
export declare const handleDiscardSuggestion: (pluginState: GrammarSuggestPluginState, meta: DiscardSuggestionMeta, tr: Transaction) => GrammarSuggestPluginState;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("prosemirror-state"),t=require("prosemirror-view"),n=require("fast-diff"),o=require("lodash.debounce");const r=new e.PluginKey("grammarSuggestPlugin"),i=e=>{let t="";return e.descendants(((e,n)=>{e.isText&&(t+=`${e.text}\n`)})),t},a=(e,t)=>{if(e===t)return{start:e.length,end:e.length,oldStart:e.length,oldEnd:e.length,oldText:"",newText:""};const o=n(e,t),r=o[0],i=r[0]===n.EQUAL?r[1].length-1:0,a=((e,t)=>{if(t[t.length-1][0]!==n.EQUAL)return e.length;const o=t.slice(0,t.length-1);let r=0;for(const e of o){const[t,o]=e;t===n.EQUAL&&(r+=o.length),t===n.DELETE&&(r+=o.length)}return r})(e,o),s=e.lastIndexOf("\n",i),c=e.indexOf("\n",a),l=-1===s?0:s+1,g=-1===c?e.length:c,p=e.slice(l,g),d=t.slice(l,t.length-(e.length-g));return{start:l,end:l+d.length,oldStart:l,oldEnd:g,oldText:p,newText:d}};var s,c;function l(e,t,n,o){return new(n||(n=Promise))((function(r,i){function a(e){try{c(o.next(e))}catch(e){i(e)}}function s(e){try{c(o.throw(e))}catch(e){i(e)}}function c(e){var t;e.done?r(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(a,s)}c((o=o.apply(e,t||[])).next())}))}!function(e){e.suggestionUpdate="suggestionUpdate",e.acceptSuggestion="acceptSuggestion",e.openSuggestion="openSuggestion",e.closeSuggestion="closeSuggestion",e.discardSuggestion="discardSuggestion"}(s||(s={})),function(e){e.grammarSuggestPopup="grammar-suggest-popup"}(c||(c={}));const g=[{docPos:1,textPos:0}],p=e=>{let t="";const n=[];return e.descendants(((e,o)=>{e.isText&&(n.push({docPos:o,textPos:t.length}),t+=`${e.text}\n`)})),{text:t,mapping:n.length?n:g}},d=(e,t)=>{for(let n=0;n<t.length;n++)if(e>=t[n].textPos&&(void 0===t[n+1]||e<t[n+1].textPos))return t[n].docPos+(e-t[n].textPos);throw new Error("textPositionToDocumentPosition: textPos not found in mapping")},u=(e,t)=>l(void 0,void 0,void 0,(function*(){const n=[...t.split("\n")];return fetch("https://openairequest-gw5lxik4dq-uc.a.run.app",{method:"POST",cache:"no-cache",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({model:"gpt-3.5-turbo",modelParams:{input:n}})}).then((e=>e.json())).then((e=>e&&e.some((e=>(e=>{try{JSON.parse(e)}catch(e){return!1}return!0})(e)))?{result:e.map((e=>JSON.parse(e).result)).join("\n"),fixed:!0}:{fixed:!1,result:t}))})),m=e=>e.replacement===e.original,f=e=>e.reduce(((e,t)=>{const n=e[e.length-1],o=e.slice(0,e.length-1);if(!n)return[t];return[...o,...((e,t)=>{if(e.to!==t.from)throw new Error(`Replace pairs must be adjacent\n\n, ${JSON.stringify({leftReplace:e,rightReplace:t})}`);if(e.replacement.endsWith("\n"))return[e,t];if(m(e)&&m(t))return[{from:e.from,to:t.to,original:e.original+t.original,replacement:e.replacement+t.replacement}];if(m(e)){if(t.replacement.startsWith(" ")&&""===t.original||t.original.startsWith(" ")&&""===t.replacement)return[e,t];const n=e.original.split(" "),o=n.pop()||"",r=n.join(" ")+(n.length?" ":"");return[...r.length?[{from:e.from,to:e.from+r.length,original:r,replacement:r}]:[],{from:e.from+r.length,to:t.to,original:o+t.original,replacement:o+t.replacement}]}if(m(t)){if(e.replacement.endsWith(" ")&&""===e.original||e.original.endsWith(" ")&&""===e.replacement)return[e,t];const n=t.original.split(" "),o=n.shift()||"",r=(n.length?" ":"")+n.join(" ");return" "===r?[{from:e.from,to:t.to,original:e.original+t.original,replacement:e.replacement+t.replacement}]:[{from:e.from,to:e.to+o.length,original:e.original+o,replacement:e.replacement+o},...r.length?[{from:e.to+o.length,to:t.to,original:r,replacement:r}]:[]]}return[{from:e.from,to:t.to,original:e.original+t.original,replacement:e.replacement+t.replacement}]})(n,t)]}),[]),h=(e,t)=>{const o=(e=>{let t=0;return e.map((([e,o])=>{switch(e){case n.EQUAL:const e=o.lastIndexOf("\n"),r={from:t,to:t+o.length,original:o,replacement:o};if(-1!==e&&"\n"!==o){const n=[{from:t,to:t+e+1,original:o.slice(0,e+1),replacement:o.slice(0,e+1)},{from:t+e+1,to:t+o.length,original:o.slice(e+1),replacement:o.slice(e+1)}];return t+=o.length,n}return t+=o.length,[r];case n.DELETE:const i={from:t,to:t+o.length,original:o,replacement:""};return t+=o.length,[i];case n.INSERT:return[{from:t,to:t,original:"",replacement:o}]}})).flat()})(n(e,t));return f(f(o))},x=(e,t)=>{var n;const o=null===(n=r.getState(e.state))||void 0===n?void 0:n.decorations.find(0,e.state.doc.nodeSize,(e=>e.id===t.spec.id))[0];if(!o)return;const{text:i}=o.spec,{from:a,to:c}=o,l={type:s.acceptSuggestion,id:t.spec.id},g=e.state.tr.insertText(i,a,c).setMeta(r,l);e.dispatch(g)},S=(e,t)=>{const{spec:n}=t,o={type:s.discardSuggestion,id:n.id},i=e.state.tr.setMeta(r,o);e.dispatch(i)},v=(e,t)=>{const n=r.getState(e.state);if(!n)return!1;const{decorations:o}=n,i=o.find(t,t)[0];if(!i){const t={type:s.closeSuggestion};return e.dispatch(e.state.tr.setMeta(r,t)),!1}const a=n.popupDecoration.find()[0];if((null==a?void 0:a.spec.id)===i.spec.id)return!1;const c={type:s.openSuggestion,decoration:i};return e.dispatch(e.state.tr.setMeta(r,c)),!1},y={debounceMs:2e3,createUpdatePopup:(e,t,n,o,r)=>{const i=document.createElement("div");i.className="grammar-suggest-tooltip";const{spec:a}=t,s=e.dom.getBoundingClientRect();i.id=c.grammarSuggestPopup;const l=e.coordsAtPos(n);i.style.left=l.left-s.left+"px",i.style.top=l.bottom-s.top+5+"px";const g=document.createElement("div");g.className="grammar-suggest-tooltip-apply",g.innerText=a.text,g.onclick=()=>{o(e,t)},i.appendChild(g);const p=document.createElement("div");return p.innerHTML="<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20C16.4183 20 20 16.4183 20 12C20 7.58172 16.4183 4 12 4C7.58172 4 4 7.58172 4 12C4 16.4183 7.58172 20 12 20ZM12 10.5858L14.8284 7.75736L16.2426 9.17157L13.4142 12L16.2426 14.8284L14.8284 16.2426L12 13.4142L9.17157 16.2426L7.75736 14.8284L10.5858 12L7.75736 9.17157L9.17157 7.75736L12 10.5858Z'></path></svg>",p.className="grammar-suggest-tooltip-discard",p.onclick=()=>{r(e,t)},i.appendChild(p),i}};exports.defaultOptions=y,exports.grammarSuggestPlugin=(n,c=y)=>{console.log(Object.assign({apiKey:n},c));let l=!1;return new e.Plugin({key:r,state:{init:()=>({lastText:"",decorations:t.DecorationSet.empty,popupDecoration:t.DecorationSet.empty}),apply(e,n,o,l){const g=e.getMeta(r);return(null==g?void 0:g.type)===s.suggestionUpdate?((e,n,o)=>{const{changedRegion:r,fix:i,mapping:a,text:s}=n,c=h(r.newText,i.result).filter((e=>!m(e))).filter((e=>e.original!==`${e.replacement}\n`)).map((({from:e,to:n,original:o,replacement:i})=>{const s=d(r.start+e,a),c=d(r.start+(i.endsWith("\n")?n-1:n),a),l={text:i.endsWith("\n")?i.slice(0,-1):i,originalText:o,id:{}};return t.Decoration.inline(s,c,{class:"grammarSuggestion"+(""===o?"removalSuggestion":"")},l)}));return Object.assign(Object.assign({},e),{decorations:e.decorations.add(o.doc,c),lastText:s})})(n,g,e):(null==g?void 0:g.type)===s.acceptSuggestion?((e,n,o)=>{const r=e.decorations.remove(e.decorations.find(0,o.doc.nodeSize,(e=>e.id===n.id)));return Object.assign(Object.assign({},e),{lastText:i(o.doc),decorations:r.map(o.mapping,o.doc),popupDecoration:t.DecorationSet.empty})})(n,g,e):(null==g?void 0:g.type)===s.openSuggestion?((e,n,o,r)=>{const{decoration:i}=n,a={id:i.spec.id};return Object.assign(Object.assign({},e),{popupDecoration:t.DecorationSet.create(o.doc,[t.Decoration.widget(i.from,((e,t)=>{const n=t();return n?r.createUpdatePopup(e,i,n,x,S):document.createElement("div")}),Object.assign(Object.assign({},a),{stopEvent:()=>!0}))])})})(n,g,e,c):(null==g?void 0:g.type)===s.closeSuggestion?Object.assign(Object.assign({},n),{popupDecoration:t.DecorationSet.empty}):(null==g?void 0:g.type)===s.discardSuggestion?((e,n,o)=>Object.assign(Object.assign({},e),{decorations:e.decorations.remove(e.decorations.find(0,o.doc.nodeSize,(e=>e.id===n.id))),popupDecoration:t.DecorationSet.empty}))(n,g,e):e.docChanged?((e,t,n)=>{const o=p(n.doc).text,{text:r,mapping:i}=p(t.doc);if(r===o)return e;const s=a(o,r),c=e.decorations.map(t.mapping,t.doc),l=d(s.start,i),g=d(s.end,i),u=e.popupDecoration.map(t.mapping,t.doc);return Object.assign(Object.assign({},e),{decorations:c.remove(c.find(l,g)),popupDecoration:u.remove(u.find(l,g))})})(n,e,o):n}},props:{handleClick:v,decorations:e=>{const t=r.getState(e);return t?t.decorations.add(e.doc,t.popupDecoration.find()):null}},view(){const e=((e,t)=>o((e=>{var n;const o=p(e.state.doc),c=(null===(n=r.getState(e.state))||void 0===n?void 0:n.lastText)||"",l=a(c,o.text);u(t,l.newText).then((t=>{if(i(e.state.doc)!==o.text)return;const n={type:s.suggestionUpdate,fix:t,changedRegion:l,mapping:o.mapping,text:o.text};e.dispatch(e.state.tr.setMeta(r,n))})).catch((e=>{console.error("Grammar suggest API error",e)}))}),e.debounceMs))(c,n);return{update(t,n){const o=r.getState(t.state);t.state.doc.textBetween(0,t.state.doc.nodeSize-2,"/n")===n.doc.textBetween(0,n.doc.nodeSize-2,"/n")&&l||!o||o.lastText===i(t.state.doc)||(l=!0,e(t))}}}})};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/// <reference types="lodash" />
|
|
2
|
+
import { EditorView } from "prosemirror-view";
|
|
3
|
+
import { GrammarSuggestPluginOptions } from "./types";
|
|
4
|
+
export declare const createMakeRequest: (options: GrammarSuggestPluginOptions, apiKey: string) => import("lodash").DebouncedFunc<(view: EditorView) => void>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Node } from "prosemirror-model";
|
|
2
|
+
import { TextMappingItem } from "./types";
|
|
3
|
+
export declare const docToTextWithMapping: (doc: Node) => {
|
|
4
|
+
text: string;
|
|
5
|
+
mapping: TextMappingItem[];
|
|
6
|
+
};
|
|
7
|
+
export declare const textPosToDocPos: (textPos: number, mapping: TextMappingItem[]) => number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import diff from "fast-diff";
|
|
2
|
+
export interface Replace {
|
|
3
|
+
from: number;
|
|
4
|
+
to: number;
|
|
5
|
+
original: string;
|
|
6
|
+
replacement: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const isIdentity: (replace: Replace) => boolean;
|
|
9
|
+
export declare const convertDiffToReplaceSet: (diffSet: diff.Diff[]) => Replace[];
|
|
10
|
+
export declare const mergeReplacePair: (leftReplace: Replace, rightReplace: Replace) => Replace[];
|
|
11
|
+
export declare const getDiff: (original: string, fixed: string) => Replace[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
.cm-editor.cm-focused {
|
|
2
|
+
outline: none;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.grammarSuggestion {
|
|
6
|
+
background-color: green;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.grammarSuggestion .removalSuggestion {
|
|
10
|
+
background-color: red;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.grammar-suggest-tooltip {
|
|
14
|
+
display: flex;
|
|
15
|
+
gap: 0.5rem;
|
|
16
|
+
position: absolute;
|
|
17
|
+
padding: 5px;
|
|
18
|
+
border-radius: 5px;
|
|
19
|
+
z-index: 1000;
|
|
20
|
+
background: white;
|
|
21
|
+
height: 50px;
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
align-items: center;
|
|
25
|
+
box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.grammar-suggest-tooltip-apply {
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
padding: 0.5rem;
|
|
31
|
+
border-radius: 0.5rem;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.grammar-suggest-tooltip-apply:hover {
|
|
35
|
+
background-color: #e6e6e6;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.grammar-suggest-tooltip-discard-content {
|
|
39
|
+
height: 1.5rem;
|
|
40
|
+
width: 2rem;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.grammar-suggest-tooltip-discard {
|
|
44
|
+
display: flex;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
align-items: center;
|
|
47
|
+
padding: 0.3rem;
|
|
48
|
+
height: 2rem;
|
|
49
|
+
width: 2rem;
|
|
50
|
+
cursor: pointer;
|
|
51
|
+
border-radius: 50%;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.grammar-suggest-tooltip-discard > path {
|
|
55
|
+
fill: grey;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.grammar-suggest-tooltip-discard:hover > path {
|
|
59
|
+
fill: black;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.grammar-suggest-tooltip-discard:hover {
|
|
63
|
+
background: #e6e6e6;
|
|
64
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Decoration, DecorationSet, EditorView } from "prosemirror-view";
|
|
2
|
+
export type TextMappingItem = {
|
|
3
|
+
docPos: number;
|
|
4
|
+
textPos: number;
|
|
5
|
+
};
|
|
6
|
+
export interface ChangedRegion {
|
|
7
|
+
oldStart: number;
|
|
8
|
+
oldEnd: number;
|
|
9
|
+
start: number;
|
|
10
|
+
end: number;
|
|
11
|
+
oldText: string;
|
|
12
|
+
newText: string;
|
|
13
|
+
}
|
|
14
|
+
export type GrammarSuggestPluginState = {
|
|
15
|
+
lastText?: string;
|
|
16
|
+
timer?: number;
|
|
17
|
+
decorations: DecorationSet;
|
|
18
|
+
popupDecoration: DecorationSet;
|
|
19
|
+
currentSuggestionId?: object;
|
|
20
|
+
};
|
|
21
|
+
export type GrammarSuggestPluginOptions = {
|
|
22
|
+
debounceMs: number;
|
|
23
|
+
createUpdatePopup: (view: EditorView, decoration: Decoration, pos: number, applySuggestion: (view: EditorView, decoration: Decoration) => void, discardSuggestion: (view: EditorView, decoration: Decoration) => void) => HTMLElement;
|
|
24
|
+
};
|
|
25
|
+
export declare enum GrammarSuggestMetaType {
|
|
26
|
+
suggestionUpdate = "suggestionUpdate",
|
|
27
|
+
acceptSuggestion = "acceptSuggestion",
|
|
28
|
+
openSuggestion = "openSuggestion",
|
|
29
|
+
closeSuggestion = "closeSuggestion",
|
|
30
|
+
discardSuggestion = "discardSuggestion"
|
|
31
|
+
}
|
|
32
|
+
export interface AcceptSuggestionMeta {
|
|
33
|
+
type: GrammarSuggestMetaType.acceptSuggestion;
|
|
34
|
+
id: object;
|
|
35
|
+
}
|
|
36
|
+
export type FixMistakeResultData = {
|
|
37
|
+
result: string;
|
|
38
|
+
fixed: boolean;
|
|
39
|
+
mod?: {
|
|
40
|
+
original: string;
|
|
41
|
+
fixed: string;
|
|
42
|
+
position: number;
|
|
43
|
+
type: string;
|
|
44
|
+
}[];
|
|
45
|
+
};
|
|
46
|
+
export interface UpdateSuggestionMeta {
|
|
47
|
+
type: GrammarSuggestMetaType.suggestionUpdate;
|
|
48
|
+
fix: FixMistakeResultData;
|
|
49
|
+
changedRegion: ChangedRegion;
|
|
50
|
+
mapping: TextMappingItem[];
|
|
51
|
+
text: string;
|
|
52
|
+
}
|
|
53
|
+
export interface OpenSuggestionMeta {
|
|
54
|
+
type: GrammarSuggestMetaType.openSuggestion;
|
|
55
|
+
decoration: Decoration;
|
|
56
|
+
}
|
|
57
|
+
export interface DiscardSuggestionMeta {
|
|
58
|
+
type: GrammarSuggestMetaType.discardSuggestion;
|
|
59
|
+
id: object;
|
|
60
|
+
}
|
|
61
|
+
export interface CloseSuggestionMeta {
|
|
62
|
+
type: GrammarSuggestMetaType.closeSuggestion;
|
|
63
|
+
}
|
|
64
|
+
export type GrammarPluginMeta = UpdateSuggestionMeta | AcceptSuggestionMeta | OpenSuggestionMeta | CloseSuggestionMeta | DiscardSuggestionMeta;
|
|
65
|
+
export type GrammarSuggestDecorationSpec = {
|
|
66
|
+
originalText: string;
|
|
67
|
+
text: string;
|
|
68
|
+
id: object;
|
|
69
|
+
};
|
|
70
|
+
export type PopupDecorationSpec = {
|
|
71
|
+
id: object;
|
|
72
|
+
};
|
|
73
|
+
export declare enum GrammarSuggestElementClass {
|
|
74
|
+
grammarSuggestPopup = "grammar-suggest-popup"
|
|
75
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { PluginKey } from "prosemirror-state";
|
|
2
|
+
import { Node } from "prosemirror-model";
|
|
3
|
+
import { ChangedRegion, GrammarSuggestPluginState } from "./types";
|
|
4
|
+
export declare const grammarSuggestPluginKey: PluginKey<GrammarSuggestPluginState>;
|
|
5
|
+
export declare const getTextWithNewlines: (node: Node) => string;
|
|
6
|
+
export declare const getChangedRegions: (oldText: string, newText: string) => ChangedRegion;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "prosemirror-suggestcat-plugin",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"prebuild": "rimraf dist",
|
|
9
|
+
"build": "rollup -c --bundleConfigAsCjs",
|
|
10
|
+
"dev": "rollup -c -w --bundleConfigAsCjs",
|
|
11
|
+
"format": "eslint src --ext .ts --fix",
|
|
12
|
+
"prepublishOnly": "npm run build && npm run lint",
|
|
13
|
+
"version": "npm run format && git add -A src",
|
|
14
|
+
"postversion": "git push && git push --tags",
|
|
15
|
+
"lint": "tsc --noEmit && eslint src --ext .ts",
|
|
16
|
+
"test": "jest",
|
|
17
|
+
"upgrade-interactive": "npm-check --update",
|
|
18
|
+
"publish:np": "np"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/emergence-engineering/prosemirror-suggestcat-plugin.git"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist/**/*"
|
|
26
|
+
],
|
|
27
|
+
"author": "Emergence Engineering",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/emergence-engineering/prosemirror-suggestcat-plugin/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/emergence-engineering/prosemirror-suggestcat-plugin#readme",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"eslint": "^8.29.0",
|
|
35
|
+
"eslint-config-airbnb": "^19.0.4",
|
|
36
|
+
"eslint-config-prettier": "^8.5.0",
|
|
37
|
+
"eslint-plugin-import": "^2.26.0",
|
|
38
|
+
"eslint-plugin-jest": "^27.1.6",
|
|
39
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
40
|
+
"fast-diff": "^1.3.0",
|
|
41
|
+
"lodash.debounce": "^4.0.8",
|
|
42
|
+
"prosemirror-model": "^1.18.3",
|
|
43
|
+
"prosemirror-state": "^1.4.2",
|
|
44
|
+
"prosemirror-test-builder": "^1.1.1",
|
|
45
|
+
"prosemirror-view": "^1.29.1"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/jest": "^29.5.1",
|
|
49
|
+
"@types/lodash.debounce": "^4.0.7",
|
|
50
|
+
"@types/prosemirror-model": "^1.17.0",
|
|
51
|
+
"@types/prosemirror-state": "^1.4.0",
|
|
52
|
+
"@types/prosemirror-view": "^1.24.0",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
|
54
|
+
"jest": "^29.5.0",
|
|
55
|
+
"np": "^7.6.2",
|
|
56
|
+
"npm-check": "^6.0.1",
|
|
57
|
+
"prettier": "^2.8.1",
|
|
58
|
+
"rollup": "^3.7.4",
|
|
59
|
+
"rollup-plugin-copy": "^3.4.0",
|
|
60
|
+
"rollup-plugin-minification": "^0.2.0",
|
|
61
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
62
|
+
"rollup-plugin-typescript2": "^0.34.1",
|
|
63
|
+
"ts-jest": "^29.1.0",
|
|
64
|
+
"typescript": "^4.9.4"
|
|
65
|
+
}
|
|
66
|
+
}
|