prosemirror-slash-menu 0.0.1

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/README.md ADDED
@@ -0,0 +1 @@
1
+ TODO
@@ -0,0 +1,23 @@
1
+ import { SlashMenuMeta, SlashMenuState } from "./types";
2
+ export declare const openSubMenu: (state: SlashMenuState, meta: SlashMenuMeta) => SlashMenuState;
3
+ export declare const closeSubMenu: (state: SlashMenuState, meta: SlashMenuMeta, initialState: SlashMenuState) => SlashMenuState;
4
+ export declare const nextItem: (state: SlashMenuState) => SlashMenuState;
5
+ export declare const prevItem: (state: SlashMenuState) => SlashMenuState;
6
+ export declare const filterItems: (state: SlashMenuState, filter: string) => {
7
+ filter: string;
8
+ selected: string;
9
+ filteredElements: import("./types").MenuElement[];
10
+ open: boolean;
11
+ subMenuId?: string | undefined;
12
+ elements: import("./types").MenuElement[];
13
+ ignoredKeys: string[];
14
+ };
15
+ export declare const updateInput: (state: SlashMenuState, meta: SlashMenuMeta, initialState: SlashMenuState) => {
16
+ filteredElements: import("./types").MenuElement[];
17
+ filter: string;
18
+ selected: string;
19
+ open: boolean;
20
+ subMenuId?: string | undefined;
21
+ elements: import("./types").MenuElement[];
22
+ ignoredKeys: string[];
23
+ };
@@ -0,0 +1,14 @@
1
+ import { EditorView } from "prosemirror-view";
2
+ import { SlashMenuState } from "./types";
3
+ export declare enum SlashCases {
4
+ OpenMenu = "openMenu",
5
+ CloseMenu = "closeMenu",
6
+ Execute = "Execute",
7
+ NextItem = "NextItem",
8
+ PrevItem = "PrevItem",
9
+ inputChange = "InputChange",
10
+ addChar = "addChar",
11
+ removeChar = "removeChar",
12
+ Ignore = "Ignore"
13
+ }
14
+ export declare const getCase: (state: SlashMenuState, event: KeyboardEvent, view: EditorView) => SlashCases;
@@ -0,0 +1,10 @@
1
+ export declare enum SlashMetaTypes {
2
+ open = "open",
3
+ close = "close",
4
+ execute = "execute",
5
+ nextItem = "nextItem",
6
+ prevItem = "prevItem",
7
+ openSubMenu = "openSubMenu",
8
+ closeSubMenu = "closeSubMenu",
9
+ inputChange = "inputChange"
10
+ }
@@ -0,0 +1,5 @@
1
+ import { SlashMenuPlugin, SlashMenuKey } from "./plugin";
2
+ import { dispatchWithMeta, getElementById, ignoredKeys } from "./utils";
3
+ import { SlashMenuState, SlashMenuMeta, SubMenu, MenuElement, MenuItem, ItemId, CommandItem, ItemType } from "./types";
4
+ import { SlashMetaTypes } from "./enums";
5
+ export { SlashMenuPlugin, SlashMenuKey, SlashMetaTypes, dispatchWithMeta, getElementById, ignoredKeys, SlashMenuState, SlashMenuMeta, SubMenu, MenuElement, MenuItem, ItemId, CommandItem, ItemType, };
@@ -0,0 +1 @@
1
+ import{PluginKey as e,Plugin as t}from"prosemirror-state";const n=e=>"submenu"===e.type?[e.id,...e.elements.map((e=>n(e)))].flat():[e.id],r=e=>{const t=(e=>e.filteredElements.map((e=>n(e))).flat())(e);return t.length!==new Set(t).size},s=e=>"submenu"===e.type?[e,...e.elements.map((e=>s(e)))].flat():[e],l=e=>e.elements.map((e=>s(e))).flat(),u=(e,t)=>l(t).find((t=>t.id===e)),i=(e,t,n="root")=>{let r="root";return t.forEach((t=>{if("submenu"===t.type){t.id===e&&(r=n);const s=t.elements.map((e=>e.id));r=s.includes(e)?t.id:i(e,t.elements,t.id)}t.id===e&&(r=n)})),r},o=(e,t,n)=>e.dispatch(e.state.tr.setMeta(t,n)),c=(e,t)=>{const n=new RegExp(`${t.toLowerCase().replace(/\s/g,"\\s")}`);return l(e).map((e=>e)).filter((e=>null!==e.label.toLowerCase().match(n)&&"submenu"!==e.type))},a=["Shift","Alt","Control","Pause","CapsLock","Escape","PageUp","PageDown","End","Home","PrintScreen","Insert","Delete","Meta","ContextMenu","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","NumLock","ScrollLock","AudioVolumeMute","AudioVolumeDown","AudioVolumeUp","LaunchMediaPlayer","LaunchApplication1","LaunchApplication2","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"];var d;!function(e){e.OpenMenu="openMenu",e.CloseMenu="closeMenu",e.Execute="Execute",e.NextItem="NextItem",e.PrevItem="PrevItem",e.inputChange="InputChange",e.addChar="addChar",e.removeChar="removeChar",e.Ignore="Ignore"}(d||(d={}));const m=(e,t,n)=>{const r=n.state,s=r.selection.from<0||r.selection.from>r.doc.content.size?null:r.doc.resolve(r.selection.from),l=null==s?void 0:s.parent,u="paragraph"===(null==l?void 0:l.type.name)&&2===(null==l?void 0:l.nodeSize);return!e.open&&"/"===t.key&&u},p=(e,t)=>e.open&&("/"===t.key||"Escape"===t.key||"Backspace"===t.key)&&0===e.filter.length,f=e=>{const t=(e=>{const t=i(e.selected,e.filteredElements),n=u(t,e);if("root"===t){const t=e.filteredElements.findIndex((t=>t.id===e.selected))+1;if(t<e.filteredElements.length)return e.filteredElements[t].id}if(n&&"submenu"===n.type){const t=n.elements.findIndex((t=>t.id===e.selected))+1;if(t<n.elements.length)return n.elements[t].id}})(e);return t?Object.assign(Object.assign({},e),{selected:t}):e},y=e=>{const t=(e=>{const t=i(e.selected,e.filteredElements),n=u(t,e);if("root"===t){const t=e.filteredElements.findIndex((t=>t.id===e.selected))-1;if(t>=0)return e.filteredElements[t].id}if(n&&"submenu"===n.type){const t=n.elements.findIndex((t=>t.id===e.selected))-1;if(t>=0)return n.elements[t].id}})(e);return t?Object.assign(Object.assign({},e),{selected:t}):e};var g;!function(e){e.open="open",e.close="close",e.execute="execute",e.nextItem="nextItem",e.prevItem="prevItem",e.openSubMenu="openSubMenu",e.closeSubMenu="closeSubMenu",e.inputChange="inputChange"}(g||(g={}));const b=new e("slash-menu-plugin"),h=e=>{const n=Object.assign(Object.assign({},e),{elements:e.filteredElements,ignoredKeys:e.ignoredKeys});if(r(n))throw new Error("Menu elements must have unique id's!");return new t({key:b,props:{handleKeyDown(e,t){const r=e.state,s=b.getState(r);if(!s)return!1;const l=((e,t,n)=>{const r=u(e.selected,e);if(m(e,t,n))return d.OpenMenu;if(p(e,t))return d.CloseMenu;if(e.open){if("ArrowDown"===t.key)return d.NextItem;if("ArrowUp"===t.key)return d.PrevItem;if("Enter"===t.key||"Tab"===t.key||"ArrowRight"===t.key&&"submenu"===(null==r?void 0:r.type))return d.Execute;if("Escape"===t.key||"Backspace"===t.key&&0===e.filter.length||"ArrowLeft"===t.key&&e.subMenuId)return d.CloseMenu;if(e.filter.length>0&&"Backspace"===t.key)return d.removeChar;if(!a.includes(t.key))return d.addChar}return d.Ignore})(s,t,e);switch(l){case d.OpenMenu:return o(e,b,{type:g.open}),!0;case d.CloseMenu:{const{subMenuId:l}=s;return l?o(e,b,{type:g.closeSubMenu,element:u(l,n)}):"/"===t.key?e.dispatch(r.tr.insertText("/").setMeta(b,{type:g.close})):o(e,b,{type:g.close}),!0}case d.Execute:{const t=u(s.selected,s);return!!t&&("command"===t.type&&(t.command(e),o(e,b,{type:g.execute})),"submenu"===t.type&&o(e,b,{type:g.openSubMenu,element:t}),!0)}case d.NextItem:return o(e,b,{type:g.nextItem}),!0;case d.PrevItem:return o(e,b,{type:g.prevItem}),!0;case d.addChar:return o(e,b,{type:g.inputChange,filter:s.filter+t.key}),!0;case d.removeChar:{const t=1===s.filter.length?"":s.filter.slice(0,-1);return o(e,b,{type:g.inputChange,filter:t}),!0}default:return!1}}},state:{init:()=>n,apply(e,t){const r=e.getMeta(b);switch(null==r?void 0:r.type){case g.open:return Object.assign(Object.assign({},n),{open:!0});case g.close:case g.execute:return n;case g.openSubMenu:return((e,t)=>{const n=t.element;return"submenu"===(null==n?void 0:n.type)?Object.assign(Object.assign({},e),{filteredElements:n.elements,selected:n.elements[0].id,subMenuId:n.id}):e})(t,r);case g.closeSubMenu:return((e,t,n)=>{const r=t.element;if("submenu"===(null==r?void 0:r.type)){const t=i(r.id,n.filteredElements);if("root"===t)return Object.assign(Object.assign({},n),{open:!0});const s=u(t,n);return"submenu"!==(null==s?void 0:s.type)?e:Object.assign(Object.assign({},e),{filteredElements:s.elements,selected:s.elements[0].id,subMenuId:t})}return e})(t,r,n);case g.nextItem:return f(t);case g.prevItem:return y(t);case g.inputChange:return Object.assign(Object.assign({},t),{filteredElements:r.filter?c(n,r.filter):n.elements,filter:r.filter||""});default:return t}}},initialState:n})};export{b as SlashMenuKey,h as SlashMenuPlugin,g as SlashMetaTypes,o as dispatchWithMeta,u as getElementById,a as ignoredKeys};
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";var e=require("prosemirror-state");const t=e=>"submenu"===e.type?[e.id,...e.elements.map((e=>t(e)))].flat():[e.id],n=e=>{const n=(e=>e.filteredElements.map((e=>t(e))).flat())(e);return n.length!==new Set(n).size},s=e=>"submenu"===e.type?[e,...e.elements.map((e=>s(e)))].flat():[e],r=e=>e.elements.map((e=>s(e))).flat(),l=(e,t)=>r(t).find((t=>t.id===e)),a=(e,t,n="root")=>{let s="root";return t.forEach((t=>{if("submenu"===t.type){t.id===e&&(s=n);const r=t.elements.map((e=>e.id));s=r.includes(e)?t.id:a(e,t.elements,t.id)}t.id===e&&(s=n)})),s},o=(e,t,n)=>e.dispatch(e.state.tr.setMeta(t,n)),u=(e,t)=>{const n=new RegExp(`${t.toLowerCase().replace(/\s/g,"\\s")}`);return r(e).map((e=>e)).filter((e=>null!==e.label.toLowerCase().match(n)&&"submenu"!==e.type))},i=["Shift","Alt","Control","Pause","CapsLock","Escape","PageUp","PageDown","End","Home","PrintScreen","Insert","Delete","Meta","ContextMenu","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","NumLock","ScrollLock","AudioVolumeMute","AudioVolumeDown","AudioVolumeUp","LaunchMediaPlayer","LaunchApplication1","LaunchApplication2","ArrowUp","ArrowDown","ArrowLeft","ArrowRight"];var p;!function(e){e.OpenMenu="openMenu",e.CloseMenu="closeMenu",e.Execute="Execute",e.NextItem="NextItem",e.PrevItem="PrevItem",e.inputChange="InputChange",e.addChar="addChar",e.removeChar="removeChar",e.Ignore="Ignore"}(p||(p={}));const c=(e,t,n)=>{const s=n.state,r=s.selection.from<0||s.selection.from>s.doc.content.size?null:s.doc.resolve(s.selection.from),l=null==r?void 0:r.parent,a="paragraph"===(null==l?void 0:l.type.name)&&2===(null==l?void 0:l.nodeSize);return!e.open&&"/"===t.key&&a},d=(e,t)=>e.open&&("/"===t.key||"Escape"===t.key||"Backspace"===t.key)&&0===e.filter.length,m=e=>{const t=(e=>{const t=a(e.selected,e.filteredElements),n=l(t,e);if("root"===t){const t=e.filteredElements.findIndex((t=>t.id===e.selected))+1;if(t<e.filteredElements.length)return e.filteredElements[t].id}if(n&&"submenu"===n.type){const t=n.elements.findIndex((t=>t.id===e.selected))+1;if(t<n.elements.length)return n.elements[t].id}})(e);return t?Object.assign(Object.assign({},e),{selected:t}):e},y=e=>{const t=(e=>{const t=a(e.selected,e.filteredElements),n=l(t,e);if("root"===t){const t=e.filteredElements.findIndex((t=>t.id===e.selected))-1;if(t>=0)return e.filteredElements[t].id}if(n&&"submenu"===n.type){const t=n.elements.findIndex((t=>t.id===e.selected))-1;if(t>=0)return n.elements[t].id}})(e);return t?Object.assign(Object.assign({},e),{selected:t}):e};var f;exports.SlashMetaTypes=void 0,(f=exports.SlashMetaTypes||(exports.SlashMetaTypes={})).open="open",f.close="close",f.execute="execute",f.nextItem="nextItem",f.prevItem="prevItem",f.openSubMenu="openSubMenu",f.closeSubMenu="closeSubMenu",f.inputChange="inputChange";const h=new e.PluginKey("slash-menu-plugin");exports.SlashMenuKey=h,exports.SlashMenuPlugin=t=>{const s=Object.assign(Object.assign({},t),{elements:t.filteredElements,ignoredKeys:t.ignoredKeys});if(n(s))throw new Error("Menu elements must have unique id's!");return new e.Plugin({key:h,props:{handleKeyDown(e,t){const n=e.state,r=h.getState(n);if(!r)return!1;const a=((e,t,n)=>{const s=l(e.selected,e);if(c(e,t,n))return p.OpenMenu;if(d(e,t))return p.CloseMenu;if(e.open){if("ArrowDown"===t.key)return p.NextItem;if("ArrowUp"===t.key)return p.PrevItem;if("Enter"===t.key||"Tab"===t.key||"ArrowRight"===t.key&&"submenu"===(null==s?void 0:s.type))return p.Execute;if("Escape"===t.key||"Backspace"===t.key&&0===e.filter.length||"ArrowLeft"===t.key&&e.subMenuId)return p.CloseMenu;if(e.filter.length>0&&"Backspace"===t.key)return p.removeChar;if(!i.includes(t.key))return p.addChar}return p.Ignore})(r,t,e);switch(a){case p.OpenMenu:return o(e,h,{type:exports.SlashMetaTypes.open}),!0;case p.CloseMenu:{const{subMenuId:a}=r;return a?o(e,h,{type:exports.SlashMetaTypes.closeSubMenu,element:l(a,s)}):"/"===t.key?e.dispatch(n.tr.insertText("/").setMeta(h,{type:exports.SlashMetaTypes.close})):o(e,h,{type:exports.SlashMetaTypes.close}),!0}case p.Execute:{const t=l(r.selected,r);return!!t&&("command"===t.type&&(t.command(e),o(e,h,{type:exports.SlashMetaTypes.execute})),"submenu"===t.type&&o(e,h,{type:exports.SlashMetaTypes.openSubMenu,element:t}),!0)}case p.NextItem:return o(e,h,{type:exports.SlashMetaTypes.nextItem}),!0;case p.PrevItem:return o(e,h,{type:exports.SlashMetaTypes.prevItem}),!0;case p.addChar:return o(e,h,{type:exports.SlashMetaTypes.inputChange,filter:r.filter+t.key}),!0;case p.removeChar:{const t=1===r.filter.length?"":r.filter.slice(0,-1);return o(e,h,{type:exports.SlashMetaTypes.inputChange,filter:t}),!0}default:return!1}}},state:{init:()=>s,apply(e,t){const n=e.getMeta(h);switch(null==n?void 0:n.type){case exports.SlashMetaTypes.open:return Object.assign(Object.assign({},s),{open:!0});case exports.SlashMetaTypes.close:case exports.SlashMetaTypes.execute:return s;case exports.SlashMetaTypes.openSubMenu:return((e,t)=>{const n=t.element;return"submenu"===(null==n?void 0:n.type)?Object.assign(Object.assign({},e),{filteredElements:n.elements,selected:n.elements[0].id,subMenuId:n.id}):e})(t,n);case exports.SlashMetaTypes.closeSubMenu:return((e,t,n)=>{const s=t.element;if("submenu"===(null==s?void 0:s.type)){const t=a(s.id,n.filteredElements);if("root"===t)return Object.assign(Object.assign({},n),{open:!0});const r=l(t,n);return"submenu"!==(null==r?void 0:r.type)?e:Object.assign(Object.assign({},e),{filteredElements:r.elements,selected:r.elements[0].id,subMenuId:t})}return e})(t,n,s);case exports.SlashMetaTypes.nextItem:return m(t);case exports.SlashMetaTypes.prevItem:return y(t);case exports.SlashMetaTypes.inputChange:return Object.assign(Object.assign({},t),{filteredElements:n.filter?u(s,n.filter):s.elements,filter:n.filter||""});default:return t}}},initialState:s})},exports.dispatchWithMeta=o,exports.getElementById=l,exports.ignoredKeys=i;
@@ -0,0 +1,6 @@
1
+ import { EditorView } from "prosemirror-view";
2
+ import { SlashMenuState } from "./types";
3
+ export declare const keyHandlers: {
4
+ execute: (view: EditorView, state: SlashMenuState) => boolean;
5
+ closeMenu: (view: EditorView, state: SlashMenuState, initialState: SlashMenuState, event: KeyboardEvent) => boolean;
6
+ };
@@ -0,0 +1,4 @@
1
+ import { Plugin, PluginKey } from "prosemirror-state";
2
+ import { SlashMenuState } from "./types";
3
+ export declare const SlashMenuKey: PluginKey<SlashMenuState>;
4
+ export declare const SlashMenuPlugin: (config: Partial<SlashMenuState>) => Plugin<SlashMenuState>;
@@ -0,0 +1,34 @@
1
+ import { EditorView } from "prosemirror-view";
2
+ import { SlashMetaTypes } from "./enums";
3
+ export type ItemId = string | "root";
4
+ export type ItemType = "command" | "submenu";
5
+ export type MenuItem = {
6
+ id: ItemId;
7
+ label: string;
8
+ type: ItemType;
9
+ };
10
+ export interface CommandItem extends MenuItem {
11
+ type: "command";
12
+ command: (view: EditorView) => void;
13
+ available: () => boolean;
14
+ }
15
+ export type MenuElement = CommandItem | SubMenu;
16
+ export interface SubMenu extends MenuItem {
17
+ type: "submenu";
18
+ elements: MenuElement[];
19
+ sideEffect?: () => void;
20
+ }
21
+ export type SlashMenuState = {
22
+ selected: ItemId;
23
+ filteredElements: MenuElement[];
24
+ open: boolean;
25
+ subMenuId?: ItemId;
26
+ filter: string;
27
+ elements: MenuElement[];
28
+ ignoredKeys: string[];
29
+ };
30
+ export interface SlashMenuMeta {
31
+ type: SlashMetaTypes;
32
+ element?: MenuElement;
33
+ filter?: string;
34
+ }
@@ -0,0 +1,14 @@
1
+ import { EditorView } from "prosemirror-view";
2
+ import { PluginKey } from "prosemirror-state";
3
+ import { ItemId, MenuElement, SlashMenuMeta, SlashMenuState } from "./types";
4
+ export declare const getElementIds: (item: MenuElement) => ItemId[];
5
+ export declare const getAllElementIds: (config: SlashMenuState) => string[];
6
+ export declare const hasDuplicateIds: (config: SlashMenuState) => boolean;
7
+ export declare const getAllElements: (state: SlashMenuState) => MenuElement[];
8
+ export declare const getElementById: (id: ItemId, state: SlashMenuState) => MenuElement | undefined;
9
+ export declare const findParent: (id: ItemId, elements: MenuElement[], subMenu?: ItemId | "root") => ItemId | "root";
10
+ export declare const getNextItemId: (state: SlashMenuState) => ItemId | undefined;
11
+ export declare const getPreviousItemId: (state: SlashMenuState) => ItemId | undefined;
12
+ export declare const dispatchWithMeta: (view: EditorView, key: PluginKey, meta: SlashMenuMeta) => void;
13
+ export declare const getFilteredItems: (state: SlashMenuState, input: string) => MenuElement[];
14
+ export declare const ignoredKeys: string[];
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "prosemirror-slash-menu",
3
+ "version": "0.0.1",
4
+ "description": "Slash menu for ProseMirror",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.es.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "prebuild": "rimraf dist",
10
+ "build": "rollup -c --bundleConfigAsCjs",
11
+ "dev": "rollup -c -w --bundleConfigAsCjs",
12
+ "yalc:watch": "nodemon --watch dist --exec 'yalc push'",
13
+ "dev:watch": "npm-run-all --parallel dev yalc:watch",
14
+ "format": "eslint src --ext .ts --fix",
15
+ "prepublishOnly": "npm run build && npm test && npm run lint",
16
+ "version": "npm run format && git add -A src",
17
+ "postversion": "git push && git push --tags",
18
+ "lint": "tsc --noEmit && eslint src --ext .ts",
19
+ "test": "echo \"no test specified\" && exit 0",
20
+ "upgrade-interactive": "npm-check --update",
21
+ "publish:np": "np"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/emergence-engineering/prosemirror-slash-menu.git"
26
+ },
27
+ "files": [
28
+ "dist/**/*"
29
+ ],
30
+ "author": "Emergence Engineering",
31
+ "keywords": [
32
+ "ProseMirror",
33
+ "slash",
34
+ "menu"
35
+ ],
36
+ "license": "ISC",
37
+ "bugs": {
38
+ "url": "https://github.com/emergence-engineering/prosemirror-slash-menu/issues"
39
+ },
40
+ "homepage": "https://github.com/emergence-engineering/prosemirror-slash-menu#readme",
41
+ "dependencies": {
42
+ "prosemirror-state": "^1.4.3",
43
+ "prosemirror-view": "^1.31.4"
44
+ },
45
+ "devDependencies": {
46
+ "@typescript-eslint/eslint-plugin": "^5.46.1",
47
+ "@typescript-eslint/parser": "^5.46.1",
48
+ "eslint": "^8.29.0",
49
+ "eslint-config-airbnb": "^19.0.4",
50
+ "eslint-config-prettier": "^8.5.0",
51
+ "eslint-plugin-import": "^2.26.0",
52
+ "eslint-plugin-jest": "^27.1.6",
53
+ "eslint-plugin-jsx-a11y": "^6.6.1",
54
+ "eslint-plugin-prettier": "^4.2.1",
55
+ "eslint-plugin-react": "^7.31.11",
56
+ "nodemon": "^2.0.22",
57
+ "np": "^8.0.2",
58
+ "npm-check": "^6.0.1",
59
+ "npm-run-all": "^4.1.5",
60
+ "prettier": "^2.8.8",
61
+ "rollup": "^3.24.0",
62
+ "rollup-plugin-minification": "^0.2.0",
63
+ "rollup-plugin-peer-deps-external": "^2.2.4",
64
+ "rollup-plugin-typescript2": "^0.34.1",
65
+ "typescript": "^5.1.3"
66
+ }
67
+ }