Remove editor, use welshman editor again

This commit is contained in:
Jon Staab
2025-02-04 20:29:12 -08:00
parent fd99866b1e
commit 565ccb399a
18 changed files with 44 additions and 1016 deletions
+34 -140
View File
@@ -24,7 +24,7 @@
"@welshman/app": "~0.0.41",
"@welshman/content": "~0.0.16",
"@welshman/dvm": "~0.0.14",
"@welshman/editor": "~0.0.10",
"@welshman/editor": "~0.0.11-pre.4",
"@welshman/feeds": "~0.0.30",
"@welshman/lib": "~0.0.38",
"@welshman/net": "~0.0.46",
@@ -3103,7 +3103,6 @@
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"license": "MIT",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
@@ -3124,8 +3123,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz",
"integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@rollup/plugin-node-resolve": {
"version": "15.3.1",
@@ -3924,7 +3922,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.11.5.tgz",
"integrity": "sha512-jb0KTdUJaJY53JaN7ooY3XAxHQNoMYti/H6ANo707PsLXVeEqJ9o8+eBup1JU5CuwzrgnDc2dECt2WIGX9f8Jw==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -3933,30 +3930,11 @@
"@tiptap/pm": "^2.7.0"
}
},
"node_modules/@tiptap/extension-bubble-menu": {
"version": "2.11.5",
"resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.11.5.tgz",
"integrity": "sha512-rx+rMd7EEdht5EHLWldpkzJ56SWYA9799b33ustePqhXd6linnokJCzBqY13AfZ9+xp3RsR6C0ZHI9GGea0tIA==",
"license": "MIT",
"peer": true,
"dependencies": {
"tippy.js": "^6.3.7"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"peerDependencies": {
"@tiptap/core": "^2.7.0",
"@tiptap/pm": "^2.7.0"
}
},
"node_modules/@tiptap/extension-code": {
"version": "2.11.5",
"resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.11.5.tgz",
"integrity": "sha512-xOvHevNIQIcCCVn9tpvXa1wBp0wHN/2umbAZGTVzS+AQtM7BTo0tz8IyzwxkcZJaImONcUVYLOLzt2AgW1LltA==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -3970,7 +3948,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.11.5.tgz",
"integrity": "sha512-ksxMMvqLDlC+ftcQLynqZMdlJT1iHYZorXsXw/n+wuRd7YElkRkd6YWUX/Pq/njFY6lDjKiqFLEXBJB8nrzzBA==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -3985,7 +3962,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.11.5.tgz",
"integrity": "sha512-7I4BRTpIux2a0O2qS3BDmyZ5LGp3pszKbix32CmeVh7lN9dV7W5reDqtJJ9FCZEEF+pZ6e1/DQA362dflwZw2g==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -3999,25 +3975,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.11.5.tgz",
"integrity": "sha512-uIN7L3FU0904ec7FFFbndO7RQE/yiON4VzAMhNn587LFMyWO8US139HXIL4O8dpZeYwYL3d1FnDTflZl6CwLlg==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"peerDependencies": {
"@tiptap/core": "^2.7.0",
"@tiptap/pm": "^2.7.0"
}
},
"node_modules/@tiptap/extension-floating-menu": {
"version": "2.11.5",
"resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.11.5.tgz",
"integrity": "sha512-HsMI0hV5Lwzm530Z5tBeyNCBNG38eJ3qjfdV2OHlfSf3+KOEfn6a5AUdoNaZO02LF79/8+7BaYU2drafag9cxQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"tippy.js": "^6.3.7"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4032,7 +3989,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.11.5.tgz",
"integrity": "sha512-kcWa+Xq9cb6lBdiICvLReuDtz/rLjFKHWpW3jTTF3FiP3wx4H8Rs6bzVtty7uOVTfwupxZRiKICAMEU6iT0xrQ==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4047,7 +4003,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.11.5.tgz",
"integrity": "sha512-q9doeN+Yg9F5QNTG8pZGYfNye3tmntOwch683v0CCVCI4ldKaLZ0jG3NbBTq+mosHYdgOH2rNbIORlRRsQ+iYQ==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4061,7 +4016,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.11.5.tgz",
"integrity": "sha512-b+wOS33Dz1azw6F1i9LFTEIJ/gUui0Jwz5ZvmVDpL2ZHBhq1Ui0/spTT+tuZOXq7Y/uCbKL8Liu4WoedIvhboQ==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4108,7 +4062,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.11.5.tgz",
"integrity": "sha512-YFBWeg7xu/sBnsDIF/+nh9Arf7R0h07VZMd0id5Ydd2Qe3c1uIZwXxeINVtH0SZozuPIQFAT8ICe9M0RxmE+TA==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4122,7 +4075,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.11.5.tgz",
"integrity": "sha512-Pr+0Ju/l2ZvXMd9VQxtaoSZbs0BBp1jbBDqwms88ctpyvQFRfLSfSkqudQcSHyw2ROOz2E31p/7I7fpI8Y0CLA==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4137,7 +4089,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.11.5.tgz",
"integrity": "sha512-Gq1WwyhFpCbEDrLPIHt5A8aLSlf8bfz4jm417c8F/JyU0J5dtYdmx0RAxjnLw1i7ZHE7LRyqqAoS0sl7JHDNSQ==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4151,7 +4102,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.11.5.tgz",
"integrity": "sha512-z9JFtqc5ZOsdQLd9vRnXfTCQ8v5ADAfRt9Nm7SqP6FUHII8E1hs38ACzf5xursmth/VonJYb5+73Pqxk1hGIPw==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-changeset": "^2.2.1",
"prosemirror-collab": "^1.3.1",
@@ -4182,7 +4132,6 @@
"resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-2.11.5.tgz",
"integrity": "sha512-uafwGgB5YuKX/xLRjnt2H5eA21I8HcNXpdbH4Du2gg3KM71RpUbkyjaV7KEMA/5qwCEo+sddlpuErj4wBycZ5Q==",
"license": "MIT",
"peer": true,
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
@@ -4422,15 +4371,13 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@types/markdown-it": {
"version": "14.1.2",
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/linkify-it": "^5",
"@types/mdurl": "^2"
@@ -4440,8 +4387,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@types/minimist": {
"version": "1.2.5",
@@ -4847,29 +4793,29 @@
}
},
"node_modules/@welshman/editor": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/@welshman/editor/-/editor-0.0.10.tgz",
"integrity": "sha512-685+KUYrGHzSgz2V6hRRltyp3LMhdHKvYBqkc9DyDNZoz3qqn4pUsOF+SMGSBnisiXBEZrKj2d52Jv46FT81iQ==",
"peerDependencies": {
"@tiptap/core": "^2.9.1",
"@tiptap/extension-code": "^2.9.1",
"@tiptap/extension-code-block": "^2.9.1",
"@tiptap/extension-document": "^2.9.1",
"@tiptap/extension-dropcursor": "^2.9.1",
"@tiptap/extension-gapcursor": "^2.9.1",
"@tiptap/extension-hard-break": "^2.9.1",
"@tiptap/extension-history": "^2.9.1",
"@tiptap/extension-paragraph": "^2.9.1",
"@tiptap/extension-placeholder": "^2.9.1",
"@tiptap/extension-text": "^2.9.1",
"@tiptap/pm": "^2.9.1",
"@tiptap/suggestion": "^2.9.1",
"@welshman/lib": "~0.0.36",
"@welshman/util": "~0.0.53",
"nostr-editor": "^0.0.4-pre.7",
"nostr-tools": "^2.8.1",
"svelte": "^4.0.0",
"svelte-tiptap": "^1.0.0"
"version": "0.0.11-pre.4",
"resolved": "https://registry.npmjs.org/@welshman/editor/-/editor-0.0.11-pre.4.tgz",
"integrity": "sha512-V2DETqs0OgBHAwvtj3bEXiKXXhtSwEKviSSH0j7I1v4abnoWAa7OyNPoQYeuJ9g3fC7CgvoFCcBTbNaeNcKtLw==",
"license": "MIT",
"dependencies": {
"@tiptap/core": "^2.11.5",
"@tiptap/extension-code": "^2.11.5",
"@tiptap/extension-code-block": "^2.11.5",
"@tiptap/extension-document": "^2.11.5",
"@tiptap/extension-dropcursor": "^2.11.5",
"@tiptap/extension-gapcursor": "^2.11.5",
"@tiptap/extension-hard-break": "^2.11.5",
"@tiptap/extension-history": "^2.11.5",
"@tiptap/extension-paragraph": "^2.11.5",
"@tiptap/extension-placeholder": "^2.11.5",
"@tiptap/extension-text": "^2.11.5",
"@tiptap/pm": "^2.11.5",
"@tiptap/suggestion": "^2.11.5",
"@welshman/lib": "^0.0.39",
"@welshman/util": "^0.0.60",
"nostr-editor": "^0.0.4-pre.12",
"nostr-tools": "^2.10.4",
"tippy.js": "^6.3.7"
}
},
"node_modules/@welshman/feeds": {
@@ -6284,8 +6230,7 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/cross-spawn": {
"version": "7.0.6",
@@ -9402,7 +9347,6 @@
"resolved": "https://registry.npmjs.org/light-bolt11-decoder/-/light-bolt11-decoder-3.2.0.tgz",
"integrity": "sha512-3QEofgiBOP4Ehs9BI+RkZdXZNtSys0nsJ6fyGeSiAGCBsMwHGUDS/JQlY/sTnWs91A2Nh0S9XXfA8Sy9g6QpuQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@scure/base": "1.1.1"
}
@@ -9417,8 +9361,7 @@
"url": "https://paulmillr.com/funding/"
}
],
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/lilconfig": {
"version": "2.1.0",
@@ -9442,7 +9385,6 @@
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"uc.micro": "^2.0.0"
}
@@ -9583,7 +9525,6 @@
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
"license": "MIT",
"peer": true,
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.4.0",
@@ -9608,7 +9549,6 @@
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"peer": true,
"engines": {
"node": ">=0.12"
},
@@ -9636,8 +9576,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/meow": {
"version": "8.1.2",
@@ -10217,7 +10156,6 @@
"resolved": "https://registry.npmjs.org/nostr-editor/-/nostr-editor-0.0.4-pre.12.tgz",
"integrity": "sha512-vztmbEKxt2jnO1JEoprwVf3s4TN4D3B0fcsrhckOITR1KaDX88QhIG+qTee92xp+n96vYj4GQt0W06rSv3NXHA==",
"license": "MIT",
"peer": true,
"dependencies": {
"light-bolt11-decoder": "^3.1.1"
},
@@ -10449,8 +10387,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz",
"integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/own-keys": {
"version": "1.0.1",
@@ -11164,7 +11101,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz",
"integrity": "sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-transform": "^1.0.0"
}
@@ -11174,7 +11110,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz",
"integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-state": "^1.0.0"
}
@@ -11184,7 +11119,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.6.2.tgz",
"integrity": "sha512-0nDHH++qcf/BuPLYvmqZTUUsPJUCPBUXt0J1ErTcDIS369CTp773itzLGIgIXG4LJXOlwYCr44+Mh4ii6MP1QA==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-model": "^1.0.0",
"prosemirror-state": "^1.0.0",
@@ -11196,7 +11130,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz",
"integrity": "sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-state": "^1.0.0",
"prosemirror-transform": "^1.1.0",
@@ -11208,7 +11141,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz",
"integrity": "sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-keymap": "^1.0.0",
"prosemirror-model": "^1.0.0",
@@ -11221,7 +11153,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.4.1.tgz",
"integrity": "sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-state": "^1.2.2",
"prosemirror-transform": "^1.0.0",
@@ -11234,7 +11165,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz",
"integrity": "sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-state": "^1.0.0",
"prosemirror-transform": "^1.0.0"
@@ -11245,7 +11175,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz",
"integrity": "sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-state": "^1.0.0",
"w3c-keyname": "^2.2.0"
@@ -11256,7 +11185,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.1.tgz",
"integrity": "sha512-Sl+oMfMtAjWtlcZoj/5L/Q39MpEnVZ840Xo330WJWUvgyhNmLBLN7MsHn07s53nG/KImevWHSE6fEj4q/GihHw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/markdown-it": "^14.0.0",
"markdown-it": "^14.0.0",
@@ -11268,7 +11196,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz",
"integrity": "sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==",
"license": "MIT",
"peer": true,
"dependencies": {
"crelt": "^1.0.0",
"prosemirror-commands": "^1.0.0",
@@ -11281,7 +11208,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.24.1.tgz",
"integrity": "sha512-YM053N+vTThzlWJ/AtPtF1j0ebO36nvbmDy4U7qA2XQB8JVaQp1FmB9Jhrps8s+z+uxhhVTny4m20ptUvhk0Mg==",
"license": "MIT",
"peer": true,
"dependencies": {
"orderedmap": "^2.0.0"
}
@@ -11291,7 +11217,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.3.tgz",
"integrity": "sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-model": "^1.19.0"
}
@@ -11301,7 +11226,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.0.tgz",
"integrity": "sha512-gg1tAfH1sqpECdhIHOA/aLg2VH3ROKBWQ4m8Qp9mBKrOxQRW61zc+gMCI8nh22gnBzd1t2u1/NPLmO3nAa3ssg==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-model": "^1.0.0",
"prosemirror-state": "^1.0.0",
@@ -11313,7 +11237,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.3.tgz",
"integrity": "sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-model": "^1.0.0",
"prosemirror-transform": "^1.0.0",
@@ -11325,7 +11248,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.6.3.tgz",
"integrity": "sha512-8B0X6PjAkXaHKntKndetNquxLIhWDDTybON1N4flKMY9Bq8/rm5k2ddW6X6LvFpqJBQeiKRp4yG3FqI/zOyQuA==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-keymap": "^1.2.2",
"prosemirror-model": "^1.24.1",
@@ -11339,7 +11261,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz",
"integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@remirror/core-constants": "3.0.0",
"escape-string-regexp": "^4.0.0"
@@ -11355,7 +11276,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.2.tgz",
"integrity": "sha512-2iUq0wv2iRoJO/zj5mv8uDUriOHWzXRnOTVgCzSXnktS/2iQRa3UUQwVlkBlYZFtygw6Nh1+X4mGqoYBINn5KQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-model": "^1.21.0"
}
@@ -11365,7 +11285,6 @@
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.37.2.tgz",
"integrity": "sha512-ApcyrfV/cRcaL65on7TQcfWElwLyOgIjnIynfAuV+fIdlpbSvSWRwfuPaH7T5mo4AbO/FID29qOtjiDIKGWyog==",
"license": "MIT",
"peer": true,
"dependencies": {
"prosemirror-model": "^1.20.0",
"prosemirror-state": "^1.0.0",
@@ -11403,7 +11322,6 @@
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6"
}
@@ -12349,8 +12267,7 @@
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
"integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/run-parallel": {
"version": "1.2.0",
@@ -13437,26 +13354,6 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/svelte-tiptap": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/svelte-tiptap/-/svelte-tiptap-1.1.3.tgz",
"integrity": "sha512-Wx4d57SLC5bgx8/hOmdt28CflW17DbiqQWgv4pUUT1Z3o5u9lInNsY8OMQWx24EYPEUyzJsjxj2OejSEoKafcg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/sibiraj-s"
}
],
"license": "MIT",
"peer": true,
"peerDependencies": {
"@tiptap/core": "^2.0.3",
"@tiptap/extension-bubble-menu": "^2.0.3",
"@tiptap/extension-floating-menu": "^2.0.3",
"@tiptap/pm": "^2.0.3",
"svelte": "^4.0.1"
}
},
"node_modules/svgo": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz",
@@ -13937,7 +13834,6 @@
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@popperjs/core": "^2.9.0"
}
@@ -14294,8 +14190,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/uglify-js": {
"version": "3.19.3",
@@ -14646,8 +14541,7 @@
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
+1 -1
View File
@@ -53,7 +53,7 @@
"@welshman/app": "~0.0.41",
"@welshman/content": "~0.0.16",
"@welshman/dvm": "~0.0.14",
"@welshman/editor": "~0.0.10",
"@welshman/editor": "~0.0.11-pre.4",
"@welshman/feeds": "~0.0.30",
"@welshman/lib": "~0.0.38",
"@welshman/net": "~0.0.46",
+6 -6
View File
@@ -1,14 +1,14 @@
import type {NodeViewProps} from '@tiptap/core'
import type {NodeViewProps} from "@tiptap/core"
import {deriveProfileDisplay} from "@welshman/app"
export const MentionNodeView = ({node}: NodeViewProps) => {
const dom = document.createElement('span')
const dom = document.createElement("span")
const display = deriveProfileDisplay(node.attrs.pubkey)
dom.classList.add('tiptap-object')
dom.classList.add("tiptap-object")
const unsubDisplay = display.subscribe($display => {
dom.textContent = '@' + $display
dom.textContent = "@" + $display
})
return {
@@ -17,10 +17,10 @@ export const MentionNodeView = ({node}: NodeViewProps) => {
unsubDisplay()
},
selectNode() {
dom.classList.add('tiptap-active')
dom.classList.add("tiptap-active")
},
deselectNode() {
dom.classList.remove('tiptap-active')
dom.classList.remove("tiptap-active")
},
}
}
+3 -1
View File
@@ -1,3 +1,5 @@
import "@welshman/editor/index.css"
import {mount} from "svelte"
import type {Writable} from "svelte/store"
import {get} from "svelte/store"
@@ -5,7 +7,7 @@ import {Editor} from "@tiptap/core"
import {ctx} from "@welshman/lib"
import type {StampedEvent} from "@welshman/util"
import {signer, profileSearch} from "@welshman/app"
import {MentionSuggestion, WelshmanExtension} from "@lib/editor"
import {MentionSuggestion, WelshmanExtension} from "@welshman/editor"
import {getSetting, userSettingValues} from "@app/state"
import {MentionNodeView} from "./MentionNodeView"
import ProfileSuggestion from "./ProfileSuggestion.svelte"
@@ -1,31 +0,0 @@
import {HardBreak, type HardBreakOptions} from "@tiptap/extension-hard-break"
export interface BreakOrSubmitOptions extends HardBreakOptions {
/** Handler for when enter is pressed. */
submit: () => void
/** Whether to call `submit` on unmodified Enter */
aggressive?: boolean
}
export const BreakOrSubmit = HardBreak.extend<BreakOrSubmitOptions>({
addKeyboardShortcuts() {
return {
"Shift-Enter": () => this.editor.commands.setHardBreak(),
"Mod-Enter": () => {
this.options.submit()
return true
},
Enter: () => {
if (this.options.aggressive) {
this.options.submit()
return true
}
return false
},
}
},
})
-75
View File
@@ -1,75 +0,0 @@
import {InputRule, mergeAttributes, Node, PasteRule} from "@tiptap/core"
import type {CodeOptions} from "@tiptap/extension-code"
const inputRegex = /(?:^|\s)(`(?!\s+`)((?:[^`]+))`(?!\s+`))$/
const pasteRegex = /(?:^|\s)(`(?!\s+`)((?:[^`]+))`(?!\s+`))/g
export type CodeInlineOptions = object
export const CodeInline = Node.create<CodeOptions>({
name: "codeInline",
content: "text*",
marks: "",
group: "inline",
inline: true,
code: true,
defining: true,
addOptions() {
return {
HTMLAttributes: {},
}
},
parseHTML() {
return [{tag: "code"}]
},
renderHTML({HTMLAttributes}) {
return ["code", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]
},
addKeyboardShortcuts() {
return {
// remove code block when at start of document or code block is empty
Backspace: () => {
const {empty, $anchor, $from} = this.editor.state.selection
const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2
if (!empty || $anchor.parent.type.name !== this.name) {
return false
}
if (isAtEnd) {
const {tr} = this.editor.state
tr.delete($from.start(), $from.end() + 1)
this.editor.view.dispatch(tr)
}
return false
},
}
},
addInputRules() {
return [
new InputRule({
find: inputRegex,
handler: ({state, range, match}) => {
const textNode = state.schema.text(match[2])
const codeNode = this.type.create(null, textNode)
state.tr.replaceWith(range.from, range.to, codeNode).insertText(" ")
},
}),
]
},
addPasteRules() {
return [
new PasteRule({
find: pasteRegex,
handler: ({state, range, match}) => {
const textNode = state.schema.text(match[2])
const codeNode = this.type.create(null, textNode)
state.tr.replaceWith(range.from, range.to, codeNode).insertText(" ")
},
}),
]
},
})
-227
View File
@@ -1,227 +0,0 @@
import type {StampedEvent, SignedEvent} from "@welshman/util"
import {deepMergeLeft} from "@welshman/lib"
import type {Extensions, AnyExtension} from "@tiptap/core"
import {CodeBlock} from "@tiptap/extension-code-block"
import type {CodeBlockOptions} from "@tiptap/extension-code-block"
import {Document} from "@tiptap/extension-document"
import {Dropcursor} from "@tiptap/extension-dropcursor"
import type {DropcursorOptions} from "@tiptap/extension-dropcursor"
import {Gapcursor} from "@tiptap/extension-gapcursor"
import {History} from "@tiptap/extension-history"
import type {HistoryOptions} from "@tiptap/extension-history"
import {Paragraph} from "@tiptap/extension-paragraph"
import type {ParagraphOptions} from "@tiptap/extension-paragraph"
import {Text} from "@tiptap/extension-text"
import {Placeholder} from "@tiptap/extension-placeholder"
import type {PlaceholderOptions} from "@tiptap/extension-placeholder"
import type {
NostrOptions,
FileUploadOptions,
ImageOptions,
LinkOptions,
NSecRejectOptions,
} from "nostr-editor"
import {
NostrExtension,
Bolt11Extension,
FileUploadExtension,
ImageExtension,
LinkExtension,
NAddrExtension,
NEventExtension,
NProfileExtension,
TagExtension,
VideoExtension,
NSecRejectExtension,
} from "nostr-editor"
import {WordCount} from "./WordCount.js"
import {CodeInline, type CodeInlineOptions} from "./CodeInline.js"
import {BreakOrSubmit, type BreakOrSubmitOptions} from "./BreakOrSubmit.js"
import {MentionNodeView, Bolt11NodeView, MediaNodeView, EventNodeView} from "../nodeviews/index.js"
export type ChildExtensionOptions<C = any, E = any> =
| false
| {
extend?: Partial<E>
config?: Partial<C>
}
export type EmptyOptions = object
export type WelshmanExtensionOptions = {
bolt11?: false
breakOrSubmit?: ChildExtensionOptions<BreakOrSubmitOptions>
codeInline?: ChildExtensionOptions<CodeInlineOptions>
codeBlock?: ChildExtensionOptions<CodeBlockOptions>
document?: false
dropcursor?: ChildExtensionOptions<DropcursorOptions>
fileUpload?: ChildExtensionOptions<FileUploadOptions>
gapcursor?: false
history?: ChildExtensionOptions<HistoryOptions>
image?: ChildExtensionOptions<ImageOptions>
link?: ChildExtensionOptions<LinkOptions>
naddr?: ChildExtensionOptions<EmptyOptions>
nevent?: ChildExtensionOptions<EmptyOptions>
nprofile?: ChildExtensionOptions<EmptyOptions>
nsecReject?: ChildExtensionOptions<NSecRejectOptions>
paragraph?: ChildExtensionOptions<ParagraphOptions>
placeholder?: ChildExtensionOptions<PlaceholderOptions>
tag?: false
text?: false
video?: false
wordCount?: false
}
export interface WelshmanOptions extends NostrOptions {
submit?: () => void
sign?: (event: StampedEvent) => Promise<SignedEvent>
defaultUploadUrl?: string
defaultUploadType?: "nip96" | "blossom"
extensions?: WelshmanExtensionOptions
}
export const WelshmanExtension = NostrExtension.extend<WelshmanOptions>({
// Return an empty object or else options can't be passed
addOptions() {
return {}
},
addExtensions() {
const {
sign,
submit,
defaultUploadUrl = "https://nostr.build",
defaultUploadType = "nip96",
} = this.options
if (!sign) throw new Error("sign is a required argument to WelshmanExtension")
if (!submit) throw new Error("submit is a required argument to WelshmanExtension")
const extensionOptions = deepMergeLeft(this.options.extensions || {}, {
codeInline: {
extend: {
renderText: (props: any) => "`" + props.node.textContent + "`",
},
},
codeBlock: {
extend: {
renderText: (props: any) => "```" + props.node.textContent + "```",
},
},
bolt11: {
config: {
inline: true,
group: "inline",
},
extend: {
addNodeView: () => Bolt11NodeView,
},
},
image: {
config: {
inline: true,
group: "inline",
defaultUploadUrl,
defaultUploadType,
},
extend: {
addNodeView: () => MediaNodeView,
},
},
video: {
config: {
inline: true,
group: "inline",
defaultUploadUrl,
defaultUploadType,
},
extend: {
addNodeView: () => MediaNodeView,
},
},
nevent: {
config: {
inline: true,
group: "inline",
},
extend: {
addNodeView: () => EventNodeView,
},
},
naddr: {
config: {
inline: true,
group: "inline",
},
extend: {
addNodeView: () => EventNodeView,
},
},
nprofile: {
extend: {
addNodeView: () => MentionNodeView,
},
},
breakOrSubmit: {
config: {
submit,
},
},
fileUpload: {
config: {
sign,
immediateUpload: true,
allowedMimeTypes: [
"image/jpeg",
"image/png",
"image/gif",
"image/webp",
"video/mp4",
"video/mpeg",
"video/webm",
],
},
},
}) as WelshmanExtensionOptions
const extensions: Extensions = []
const addExtension = (extension: AnyExtension, options?: ChildExtensionOptions | false) => {
if (options === false) return
if (options?.extend) {
extension = extension.extend(options.extend)
}
if (options?.config) {
extension = extension.configure(options.config)
}
extensions.push(extension)
}
addExtension(Document, extensionOptions.document)
addExtension(Text, extensionOptions.text)
addExtension(Paragraph, extensionOptions.paragraph)
addExtension(History, extensionOptions.history)
addExtension(CodeBlock, extensionOptions.codeBlock)
addExtension(CodeInline, extensionOptions.codeInline)
addExtension(Dropcursor, extensionOptions.dropcursor)
addExtension(FileUploadExtension, extensionOptions.fileUpload)
addExtension(Gapcursor, extensionOptions.gapcursor)
addExtension(BreakOrSubmit, extensionOptions.breakOrSubmit)
addExtension(ImageExtension, extensionOptions.image)
addExtension(LinkExtension, extensionOptions.link)
addExtension(NAddrExtension, extensionOptions.naddr)
addExtension(NEventExtension, extensionOptions.nevent)
addExtension(NProfileExtension, extensionOptions.nprofile)
addExtension(NSecRejectExtension, extensionOptions.nsecReject)
addExtension(Placeholder, extensionOptions.placeholder)
addExtension(TagExtension, extensionOptions.tag)
addExtension(VideoExtension, extensionOptions.video)
addExtension(Bolt11Extension, extensionOptions.bolt11)
addExtension(WordCount, extensionOptions.wordCount)
return extensions
},
})
-19
View File
@@ -1,19 +0,0 @@
import {Extension} from "@tiptap/core"
export const WordCount = Extension.create({
name: "wordCount",
addStorage() {
return {
words: 0,
chars: 0,
}
},
onUpdate() {
const text = this.editor.state.doc.textContent
this.storage.words = text.split(/\s+/).filter(word => word.length > 0).length
this.storage.chars = text.length
},
})
-4
View File
@@ -1,4 +0,0 @@
export * from "./BreakOrSubmit.js"
export * from "./CodeInline.js"
export * from "./Welshman.js"
export * from "./WordCount.js"
-105
View File
@@ -1,105 +0,0 @@
:root {
--tiptap-object-bg: #eee;
--tiptap-object-fg: #111;
--tiptap-active-bg: #ddd;
--tiptap-active-fg: #111;
}
.tiptap {
outline: none;
min-height: 0;
height: 100%;
}
.tiptap p.is-editor-empty:first-child::before {
color: #adb5bd;
content: attr(data-placeholder);
float: left;
height: 0;
pointer-events: none;
}
.tiptap pre code {
display: block;
max-width: 100%;
overflow: auto;
padding: 0.25rem;
background-color: var(--tiptap-object-bg);
color: var(--tiptap-object-fg);
}
.tiptap .tiptap-object,
.tiptap p code,
.tiptap [tag] {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
border-radius: 3px;
padding: 0 0.25rem;
background-color: var(--tiptap-object-bg);
color: var(--tiptap-object-fg);
}
.tiptap .tiptap-active {
background-color: var(--tiptap-active-bg);
color: var(--tiptap-active-fg);
}
.tiptap .tiptap-uploading {
animation: tiptapFileUpload 1.5s infinite;
}
.tiptap-suggestions {
margin-top: 0.5rem;
max-height: 350px;
}
.tiptap-suggestions__content {
border-radius: 3px;
box-shadow: 0px 5px 8px 0px rgba(0, 0, 0, 0.2);
overflow-y: auto;
overflow-x: hidden;
}
.tiptap-suggestions__create,
.tiptap-suggestions__item {
white-space: nowrap;
display: block;
width: 100%;
min-width: 0px;
cursor: pointer;
overflow-x: hidden;
text-overflow: ellipsis;
padding: 0.5rem 1rem;
text-align: left;
transition-duration: 100ms;
transition-property: color, background-color;
background-color: var(--tiptap-object-bg);
color: var(--tiptap-object-fg);
}
.tiptap-suggestions__selected,
.tiptap-suggestions__create:hover,
.tiptap-suggestions__item:hover {
background-color: var(--tiptap-active-bg);
color: var(--tiptap-active-fg);
}
.tiptap-suggestions__empty {
display: flex;
gap: 0.5rem;
padding: 0.5rem 1rem;
}
@keyframes tiptapFileUpload {
0% {
opacity: 0.2;
}
50% {
opacity: 1;
}
100% {
opacity: 0.2;
}
}
-5
View File
@@ -1,5 +0,0 @@
import "./index.css"
export * from "./nodeviews/index.js"
export * from "./extensions/index.js"
export * from "./plugins/index.js"
@@ -1,18 +0,0 @@
import type {NodeViewProps} from '@tiptap/core'
export const Bolt11NodeView = ({node}: NodeViewProps) => {
const dom = document.createElement('span')
dom.classList.add('tiptap-object')
dom.innerText = `${node.attrs.lnbc.slice(0, 16)}...`
return {
dom,
selectNode() {
dom.classList.add('tiptap-active')
},
deselectNode() {
dom.classList.remove('tiptap-active')
},
}
}
-19
View File
@@ -1,19 +0,0 @@
import type {NodeViewProps} from '@tiptap/core'
import {fromNostrURI} from "@welshman/util"
export const EventNodeView = ({node}: NodeViewProps) => {
const dom = document.createElement('span')
dom.classList.add('tiptap-object')
dom.innerText = `${fromNostrURI(node.attrs.bech32).slice(0, 16)}...`
return {
dom,
selectNode() {
dom.classList.add('tiptap-active')
},
deselectNode() {
dom.classList.remove('tiptap-active')
},
}
}
-32
View File
@@ -1,32 +0,0 @@
import type {Node, NodeViewProps} from '@tiptap/core'
import {fromNostrURI} from "@welshman/util"
export const MediaNodeView = ({node}: NodeViewProps) => {
const dom = document.createElement('span')
const syncUploading = (node: NodeViewProps['node']) => {
if (node.attrs.uploading) {
dom.classList.add('tiptap-uploading')
} else {
dom.classList.remove('tiptap-uploading')
}
}
dom.classList.add('tiptap-object')
dom.innerText = node.attrs.file?.name || node.attrs.src
syncUploading(node)
return {
dom,
update(node: NodeViewProps['node']) {
syncUploading(node)
},
selectNode() {
dom.classList.add('tiptap-active')
},
deselectNode() {
dom.classList.remove('tiptap-active')
},
}
}
@@ -1,18 +0,0 @@
import type {NodeViewProps} from '@tiptap/core'
export const MentionNodeView = ({node}: NodeViewProps) => {
const dom = document.createElement('span')
dom.classList.add('tiptap-object')
dom.textContent = `@${node.attrs.bech32.slice(0, 16)}...`
return {
dom,
selectNode() {
dom.classList.add('tiptap-active')
},
deselectNode() {
dom.classList.remove('tiptap-active')
},
}
}
-4
View File
@@ -1,4 +0,0 @@
export * from './MentionNodeView.js'
export * from './Bolt11NodeView.js'
export * from './EventNodeView.js'
export * from './MediaNodeView.js'
-310
View File
@@ -1,310 +0,0 @@
import type {Instance} from "tippy.js"
import tippy from "tippy.js"
import {nprofileEncode} from "nostr-tools/nip19"
import type {Editor} from "@tiptap/core"
import {makeNProfileAttrs} from "nostr-editor"
import {PluginKey} from "@tiptap/pm/state"
import Suggestion from "@tiptap/suggestion"
import {throttle, enumerate, clamp} from "@welshman/lib"
export type CreateSuggestion = (item: string) => HTMLElement
export const defaultCreateSuggestion = (item: string) => {
const span = document.createElement("span")
span.textContent = item
return span
}
export type SuggestionsWrapperProps = {
term: string
allowCreate: boolean
select: (value: string) => void
search: (term: string) => string[]
createSuggestion: CreateSuggestion
}
export interface ISuggestionsWrapperConstructor {
new (target: HTMLElement, props: SuggestionsWrapperProps): ISuggestionsWrapper
}
export interface ISuggestionsWrapper {
setProps: (props: SuggestionsWrapperProps) => void
onKeyDown: (event: Event) => boolean
destroy: () => void
}
function createSuggestionsWrapper(
ctor: ISuggestionsWrapperConstructor,
target: HTMLElement,
props: SuggestionsWrapperProps,
): ISuggestionsWrapper {
return new ctor(target, props)
}
export class DefaultSuggestionsWrapper implements ISuggestionsWrapper {
index = 0
items: string[] = []
target: HTMLElement
content: HTMLElement
props: SuggestionsWrapperProps
constructor(target: HTMLElement, props: SuggestionsWrapperProps) {
this.target = target
this.props = props
this.content = document.createElement("div")
this.content.classList.add("tiptap-suggestions__content")
target.appendChild(this.content)
target.classList.add("tiptap-suggestions")
this.search()
this.render()
}
search = throttle(300, () => {
const {term, search} = this.props
this.items = search(term).slice(0, 5)
})
render() {
const {index} = this
const {select, term, allowCreate, createSuggestion} = this.props
this.content.innerHTML = ""
if (term && allowCreate && this.items.includes(term)) {
const button = document.createElement("button")
button.classList.add("tiptap-suggestions__create")
button.addEventListener("mousedown", (event: Event) => {
event.preventDefault()
event.stopPropagation()
})
button.addEventListener("click", (event: Event) => {
event.preventDefault()
event.stopPropagation()
select(term)
})
this.content.appendChild(button)
}
for (const [i, item] of enumerate(this.items)) {
const button = document.createElement("button")
button.classList.add("tiptap-suggestions__item")
if (i === index) {
button.classList.add("tiptap-suggestions__selected")
}
button.addEventListener("mousedown", (event: Event) => {
event.preventDefault()
event.stopPropagation()
})
button.addEventListener("click", (event: Event) => {
event.preventDefault()
event.stopPropagation()
select(item)
})
button.appendChild(createSuggestion(item))
this.content.appendChild(button)
}
}
setIndex(index: number) {
this.index = clamp([0, this.items.length - 1], index)
this.render()
}
setProps(props: SuggestionsWrapperProps) {
this.props = props
this.search()
this.render()
}
onKeyDown(event: any) {
const {index, items} = this
const {term, select, allowCreate} = this.props
if (["Enter", "Tab"].includes(event.code)) {
const value = items[index]
if (value) {
select(value)
return true
} else if (term && allowCreate) {
select(term)
return true
}
}
if (event.code === "Space" && term && allowCreate) {
select(term)
return true
}
if (event.code === "ArrowUp") {
this.setIndex(index - 1)
return true
}
if (event.code === "ArrowDown") {
this.setIndex(index + 1)
return true
}
return false
}
destroy() {
this.target.remove()
}
}
export type TippySuggestionOptions = {
char: string
name: string
editor: Editor
search: (term: string) => string[]
select: (value: string, props: any) => void
allowCreate?: boolean
createSuggestion?: CreateSuggestion
suggestionsWrapper?: ISuggestionsWrapperConstructor
}
export const TippySuggestion = ({
char,
name,
editor,
search,
select,
allowCreate = false,
createSuggestion = defaultCreateSuggestion,
suggestionsWrapper = DefaultSuggestionsWrapper,
}: TippySuggestionOptions) =>
Suggestion({
char,
editor,
pluginKey: new PluginKey(`suggest-${name}`),
command: ({editor, range, props}) => {
// increase range.to by one when the next node is of type "text"
// and starts with a space character
const nodeAfter = editor.view.state.selection.$to.nodeAfter
const overrideSpace = nodeAfter?.text?.startsWith(" ")
if (overrideSpace) {
range.to += 1
}
editor
.chain()
.focus()
.insertContentAt(range, [
{type: name, attrs: props},
{type: "text", text: " "},
])
.run()
window.getSelection()?.collapseToEnd()
},
allow: ({state, range}) => {
const $from = state.doc.resolve(range.from)
const type = state.schema.nodes[name]
return !!$from.parent.type.contentMatch.matchType(type)
},
render: () => {
let popover: Instance[]
let wrapper: ISuggestionsWrapper
const mapProps = (props: any) => ({
term: props.query,
search,
allowCreate,
createSuggestion,
select: (value: string) => select(value, props),
})
return {
onStart: props => {
const target = document.createElement("div")
// @ts-ignore
popover = tippy("body", {
getReferenceClientRect: props.clientRect as any,
appendTo: document.querySelector("dialog[open]") || document.body,
content: target,
showOnCreate: true,
interactive: true,
trigger: "manual",
placement: "bottom-start",
})
if (!props.query) popover[0].hide()
wrapper = createSuggestionsWrapper(suggestionsWrapper, target, mapProps(props))
},
onUpdate: props => {
if (props.query) {
popover[0].show()
} else {
popover[0].hide()
}
wrapper.setProps(mapProps(props))
if (props.clientRect) {
popover[0].setProps({
getReferenceClientRect: props.clientRect as any,
})
}
},
onKeyDown: props => {
if (props.event.key === "Escape") {
popover[0].hide()
return true
}
return Boolean(wrapper.onKeyDown(props.event))
},
onExit: () => {
popover[0].destroy()
wrapper.destroy()
},
}
},
})
export type MentionSuggestionOptions = Partial<TippySuggestionOptions> & {
editor: Editor
search: (term: string) => string[]
getRelays: (pubkey: string) => string[]
}
export const MentionSuggestion = (options: MentionSuggestionOptions) =>
TippySuggestion({
char: "@",
name: "nprofile",
select: (pubkey: string, props: any) => {
const relays = options.getRelays(pubkey)
const bech32 = nprofileEncode({pubkey, relays})
return props.command(makeNProfileAttrs(bech32, {}))
},
...options,
})
-1
View File
@@ -1 +0,0 @@
export * from "./TippySuggestion.js"