@milkdown/crepe 7.3.3

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.
Files changed (241) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -0
  3. package/lib/apl-p0IPP13W.js +76 -0
  4. package/lib/asciiarmor-lJsBxlJJ.js +34 -0
  5. package/lib/asn1-Q9v1zIy5.js +102 -0
  6. package/lib/asterisk-foNkeTjy.js +273 -0
  7. package/lib/brainfuck-0XqyXpNS.js +35 -0
  8. package/lib/clike-ak6Z6Yhe.js +639 -0
  9. package/lib/clojure-iYO8U8Sg.js +810 -0
  10. package/lib/clsx-7d8NmkQq.js +21 -0
  11. package/lib/cmake-SVzjkxV_.js +28 -0
  12. package/lib/cobol-APHEnAOX.js +74 -0
  13. package/lib/coffeescript-KqQa0SYG.js +182 -0
  14. package/lib/commonlisp-bwqNqR5V.js +79 -0
  15. package/lib/core/crepe.d.ts +21 -0
  16. package/lib/core/crepe.d.ts.map +1 -0
  17. package/lib/core/index.d.ts +3 -0
  18. package/lib/core/index.d.ts.map +1 -0
  19. package/lib/core/slice.d.ts +12 -0
  20. package/lib/core/slice.d.ts.map +1 -0
  21. package/lib/crystal-BViWuDpA.js +217 -0
  22. package/lib/css-KHXHXfXg.js +1572 -0
  23. package/lib/cypher-XpTt4zQ3.js +69 -0
  24. package/lib/d-fLig6yqY.js +139 -0
  25. package/lib/diff-WoKGLpy6.js +18 -0
  26. package/lib/dockerfile-u6f6Vw2s.js +194 -0
  27. package/lib/dtd-SIJRUW6K.js +91 -0
  28. package/lib/dylan-4HCLhpWP.js +238 -0
  29. package/lib/ebnf-h_0lged5.js +77 -0
  30. package/lib/ecl-Lf4FF0lf.js +133 -0
  31. package/lib/eiffel-qlw8KUyf.js +112 -0
  32. package/lib/elm-QRnB3zXs.js +108 -0
  33. package/lib/erlang-fyVKb7eK.js +488 -0
  34. package/lib/factor-BEeN4upY.js +65 -0
  35. package/lib/fcl-lRek3hEb.js +106 -0
  36. package/lib/feature/block-edit/handle/component.d.ts +9 -0
  37. package/lib/feature/block-edit/handle/component.d.ts.map +1 -0
  38. package/lib/feature/block-edit/handle/index.d.ts +12 -0
  39. package/lib/feature/block-edit/handle/index.d.ts.map +1 -0
  40. package/lib/feature/block-edit/index.d.ts +3 -0
  41. package/lib/feature/block-edit/index.d.ts.map +1 -0
  42. package/lib/feature/block-edit/menu/component.d.ts +14 -0
  43. package/lib/feature/block-edit/menu/component.d.ts.map +1 -0
  44. package/lib/feature/block-edit/menu/config.d.ts +21 -0
  45. package/lib/feature/block-edit/menu/config.d.ts.map +1 -0
  46. package/lib/feature/block-edit/menu/icons.d.ts +14 -0
  47. package/lib/feature/block-edit/menu/icons.d.ts.map +1 -0
  48. package/lib/feature/block-edit/menu/index.d.ts +9 -0
  49. package/lib/feature/block-edit/menu/index.d.ts.map +1 -0
  50. package/lib/feature/code-mirror/index.d.ts +3 -0
  51. package/lib/feature/code-mirror/index.d.ts.map +1 -0
  52. package/lib/feature/gap-cursor/index.d.ts +3 -0
  53. package/lib/feature/gap-cursor/index.d.ts.map +1 -0
  54. package/lib/feature/image-block/index.d.ts +3 -0
  55. package/lib/feature/image-block/index.d.ts.map +1 -0
  56. package/lib/feature/index.d.ts +18 -0
  57. package/lib/feature/index.d.ts.map +1 -0
  58. package/lib/feature/link-tooltip/consts.d.ts +5 -0
  59. package/lib/feature/link-tooltip/consts.d.ts.map +1 -0
  60. package/lib/feature/link-tooltip/index.d.ts +3 -0
  61. package/lib/feature/link-tooltip/index.d.ts.map +1 -0
  62. package/lib/feature/list-item/consts.d.ts +2 -0
  63. package/lib/feature/list-item/consts.d.ts.map +1 -0
  64. package/lib/feature/list-item/index.d.ts +3 -0
  65. package/lib/feature/list-item/index.d.ts.map +1 -0
  66. package/lib/feature/placeholder/index.d.ts +10 -0
  67. package/lib/feature/placeholder/index.d.ts.map +1 -0
  68. package/lib/feature/shared.d.ts +3 -0
  69. package/lib/feature/shared.d.ts.map +1 -0
  70. package/lib/feature/toolbar/component.d.ts +13 -0
  71. package/lib/feature/toolbar/component.d.ts.map +1 -0
  72. package/lib/feature/toolbar/consts.d.ts +5 -0
  73. package/lib/feature/toolbar/consts.d.ts.map +1 -0
  74. package/lib/feature/toolbar/index.d.ts +3 -0
  75. package/lib/feature/toolbar/index.d.ts.map +1 -0
  76. package/lib/forth-ua2bRd8T.js +60 -0
  77. package/lib/fortran-WnF7znuN.js +443 -0
  78. package/lib/gas-wowve1o7.js +183 -0
  79. package/lib/gherkin-m7GIChu3.js +34 -0
  80. package/lib/go-th443Dhb.js +158 -0
  81. package/lib/groovy-tR4RiZnc.js +161 -0
  82. package/lib/haskell-jxVBofv5.js +375 -0
  83. package/lib/haxe-kWPI2tq3.js +390 -0
  84. package/lib/hooks-82sqkbtE.js +21 -0
  85. package/lib/http-3GIFWUlG.js +45 -0
  86. package/lib/icons-HYkfuR-O.js +50 -0
  87. package/lib/idl-PvpMZg-l.js +947 -0
  88. package/lib/index-0RbcZMbq.js +8 -0
  89. package/lib/index-4afXjFMY.js +517 -0
  90. package/lib/index-7MeyepDG.js +78 -0
  91. package/lib/index-7QgQq3x3.js +551 -0
  92. package/lib/index-7pgP6qYs.js +107 -0
  93. package/lib/index-8DvtgRVa.js +19511 -0
  94. package/lib/index-8Gg-jEP4.js +288 -0
  95. package/lib/index-8S8qcncB.js +507 -0
  96. package/lib/index-9A_GmGh4.js +1039 -0
  97. package/lib/index-EJJfYLzA.js +928 -0
  98. package/lib/index-Eg39w5kL.js +984 -0
  99. package/lib/index-FIk_7oPb.js +168 -0
  100. package/lib/index-LlbrXb_n.js +368 -0
  101. package/lib/index-MovKtgMG.js +121 -0
  102. package/lib/index-N9GtIS4X.js +64 -0
  103. package/lib/index-Pwn25-kf.js +8 -0
  104. package/lib/index-SdFSDosa.js +1295 -0
  105. package/lib/index-W5Th22-Z.js +1744 -0
  106. package/lib/index-XiXSFLmI.js +20975 -0
  107. package/lib/index-bknOViGv.js +47 -0
  108. package/lib/index-bkuIUPFS.js +275 -0
  109. package/lib/index-jPA8J9Eo.js +8 -0
  110. package/lib/index-lsG76a9s.js +552 -0
  111. package/lib/index-oTRzPo3B.js +146 -0
  112. package/lib/index-rrf6_6DC.js +317 -0
  113. package/lib/index-vJbZIHYF.js +81 -0
  114. package/lib/index-vPRh55CO.js +137 -0
  115. package/lib/index-vxy63hib.js +323 -0
  116. package/lib/index-wn1_LgCS.js +99 -0
  117. package/lib/index-xHADmDT3.js +12 -0
  118. package/lib/index-yt2EpMtv.js +141 -0
  119. package/lib/index.d.ts +4 -0
  120. package/lib/index.d.ts.map +1 -0
  121. package/lib/index.es.js +7 -0
  122. package/lib/javascript-8ZHqHagw.js +758 -0
  123. package/lib/jinja2-vsOFe0qD.js +154 -0
  124. package/lib/julia-dlp_pbN1.js +241 -0
  125. package/lib/livescript-Gf5R-LT6.js +273 -0
  126. package/lib/lua-c5Y_JsBp.js +221 -0
  127. package/lib/mathematica-iiGTGmUs.js +35 -0
  128. package/lib/mbox-ZJh86H8B.js +78 -0
  129. package/lib/meta-tAGyVRPE.js +511 -0
  130. package/lib/mirc-i0qkCa0y.js +73 -0
  131. package/lib/mllike-Dy551fZW.js +275 -0
  132. package/lib/modelica-n6tGqUT9.js +94 -0
  133. package/lib/mscgen-aKSbB7D9.js +104 -0
  134. package/lib/mumps-lNiKA6sp.js +25 -0
  135. package/lib/nginx--YmuCfDj.js +93 -0
  136. package/lib/nsis-zhS8iA09.js +62 -0
  137. package/lib/ntriples-E3jQl3MC.js +79 -0
  138. package/lib/octave-EQvkGIeG.js +144 -0
  139. package/lib/oz-W2cpqFf6.js +152 -0
  140. package/lib/pascal-lCh6ouNZ.js +79 -0
  141. package/lib/perl-PxEQBX0B.js +915 -0
  142. package/lib/pig-Y_bNcrzS.js +56 -0
  143. package/lib/powershell-GaQP-TZr.js +249 -0
  144. package/lib/properties-mbRyn54L.js +26 -0
  145. package/lib/prosemirror-noTDkx-k.js +4 -0
  146. package/lib/protobuf-8CJideyJ.js +49 -0
  147. package/lib/puppet-ABBaChNZ.js +45 -0
  148. package/lib/python-sKdHg3Ka.js +321 -0
  149. package/lib/q-_1yG40Nm.js +89 -0
  150. package/lib/r-Ziz56bHT.js +108 -0
  151. package/lib/rpm-ORjGOHaQ.js +57 -0
  152. package/lib/ruby-jlbYq0dT.js +233 -0
  153. package/lib/sas-2n7xeUuO.js +107 -0
  154. package/lib/schema-tKk3m1fu.js +62 -0
  155. package/lib/scheme-XCs-NPeU.js +126 -0
  156. package/lib/shell-0_1Um7Dq.js +184 -0
  157. package/lib/sieve-7uyJD1x1.js +73 -0
  158. package/lib/simple-mode--HIzBxba.js +95 -0
  159. package/lib/smalltalk-PEFzrlQ-.js +48 -0
  160. package/lib/solr-BLBaHahN.js +41 -0
  161. package/lib/sparql-4F9ZWf1b.js +204 -0
  162. package/lib/spreadsheet-SGSo6blj.js +49 -0
  163. package/lib/sql-tebLBzN0.js +291 -0
  164. package/lib/stex-SFJcFGOO.js +130 -0
  165. package/lib/stylus-rwwWYWFm.js +256 -0
  166. package/lib/swift-eorJ0tCv.js +238 -0
  167. package/lib/tcl-IwXMB8U4.js +82 -0
  168. package/lib/textile-ok2VyjwC.js +299 -0
  169. package/lib/theme/classic/index.d.ts +3 -0
  170. package/lib/theme/classic/index.d.ts.map +1 -0
  171. package/lib/theme/classic-dark/index.d.ts +3 -0
  172. package/lib/theme/classic-dark/index.d.ts.map +1 -0
  173. package/lib/theme/headless/index.d.ts +3 -0
  174. package/lib/theme/headless/index.d.ts.map +1 -0
  175. package/lib/theme/index.d.ts +8 -0
  176. package/lib/theme/index.d.ts.map +1 -0
  177. package/lib/theme/shared.d.ts +3 -0
  178. package/lib/theme/shared.d.ts.map +1 -0
  179. package/lib/tiddlywiki-DLhz8_pc.js +156 -0
  180. package/lib/tiki-DFAqFElY.js +183 -0
  181. package/lib/tippy.esm-MZ2vxByW.js +1813 -0
  182. package/lib/toml-ryxpTZEV.js +49 -0
  183. package/lib/tooltip-plugin-gcwyQdiT.js +119 -0
  184. package/lib/troff-ZzZyvNct.js +36 -0
  185. package/lib/ttcn-6gvkqqpW.js +136 -0
  186. package/lib/ttcn-cfg-oSu-Dq5C.js +98 -0
  187. package/lib/turtle-10ofr5au.js +87 -0
  188. package/lib/use-css-light-dom-EKWZDmbJ.js +82 -0
  189. package/lib/utils/index.d.ts +4 -0
  190. package/lib/utils/index.d.ts.map +1 -0
  191. package/lib/vb-a6n6fzrD.js +74 -0
  192. package/lib/vbscript-dgvo8jPt.js +324 -0
  193. package/lib/velocity-CBncCrwO.js +97 -0
  194. package/lib/verilog-KlcACt6C.js +271 -0
  195. package/lib/vhdl-NMd7Gf35.js +117 -0
  196. package/lib/webidl-z1UE5DN_.js +160 -0
  197. package/lib/xquery-hDt5jWTp.js +431 -0
  198. package/lib/yacas-ftgh_qwr.js +74 -0
  199. package/lib/yaml-DnNTfjXK.js +53 -0
  200. package/lib/z80-dA1PqWe1.js +62 -0
  201. package/package.json +87 -0
  202. package/src/core/crepe.ts +98 -0
  203. package/src/core/index.ts +4 -0
  204. package/src/core/slice.ts +44 -0
  205. package/src/feature/block-edit/handle/component.ts +68 -0
  206. package/src/feature/block-edit/handle/index.ts +81 -0
  207. package/src/feature/block-edit/index.ts +17 -0
  208. package/src/feature/block-edit/menu/component.ts +210 -0
  209. package/src/feature/block-edit/menu/config.ts +335 -0
  210. package/src/feature/block-edit/menu/icons.ts +171 -0
  211. package/src/feature/block-edit/menu/index.ts +113 -0
  212. package/src/feature/block-edit/style.css +126 -0
  213. package/src/feature/code-mirror/index.ts +60 -0
  214. package/src/feature/code-mirror/style.css +159 -0
  215. package/src/feature/gap-cursor/index.ts +31 -0
  216. package/src/feature/image-block/index.ts +59 -0
  217. package/src/feature/image-block/style.css +215 -0
  218. package/src/feature/index.ts +66 -0
  219. package/src/feature/link-tooltip/consts.ts +47 -0
  220. package/src/feature/link-tooltip/index.ts +22 -0
  221. package/src/feature/link-tooltip/style.css +107 -0
  222. package/src/feature/list-item/consts.ts +15 -0
  223. package/src/feature/list-item/index.ts +30 -0
  224. package/src/feature/list-item/style.css +23 -0
  225. package/src/feature/placeholder/index.ts +87 -0
  226. package/src/feature/placeholder/style.css +9 -0
  227. package/src/feature/shared.ts +4 -0
  228. package/src/feature/toolbar/component.ts +101 -0
  229. package/src/feature/toolbar/consts.ts +26 -0
  230. package/src/feature/toolbar/index.ts +92 -0
  231. package/src/feature/toolbar/style.css +37 -0
  232. package/src/index.ts +5 -0
  233. package/src/theme/classic/index.ts +12 -0
  234. package/src/theme/classic/style.css +192 -0
  235. package/src/theme/classic-dark/index.ts +12 -0
  236. package/src/theme/classic-dark/style.css +197 -0
  237. package/src/theme/headless/index.ts +9 -0
  238. package/src/theme/index.ts +26 -0
  239. package/src/theme/shared.ts +4 -0
  240. package/src/utils/index.ts +12 -0
  241. package/src/vite-env.d.ts +2 -0
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@milkdown/crepe",
3
+ "type": "module",
4
+ "version": "7.3.3",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Milkdown/milkdown.git",
9
+ "directory": "packages/plugin-cursor"
10
+ },
11
+ "keywords": [
12
+ "milkdown",
13
+ "milkdown plugin",
14
+ "crepe",
15
+ "editor"
16
+ ],
17
+ "sideEffects": false,
18
+ "exports": {
19
+ ".": {
20
+ "import": "./lib/index.es.js",
21
+ "types": "./lib/index.d.ts"
22
+ }
23
+ },
24
+ "main": "./lib/index.es.js",
25
+ "files": [
26
+ "lib",
27
+ "src"
28
+ ],
29
+ "dependencies": {
30
+ "atomico": "^1.75.1"
31
+ },
32
+ "devDependencies": {
33
+ "@codemirror/commands": "^6.2.4",
34
+ "@codemirror/language-data": "^6.3.1",
35
+ "@codemirror/view": "^6.16.0",
36
+ "@emotion/css": "^11.11.2",
37
+ "clsx": "^2.0.0",
38
+ "codemirror": "^6.0.1",
39
+ "nanoid": "^5.0.0",
40
+ "thememirror": "^2.0.1",
41
+ "tslib": "^2.5.0",
42
+ "@milkdown/components": "7.3.3",
43
+ "@milkdown/core": "7.3.3",
44
+ "@milkdown/ctx": "7.3.3",
45
+ "@milkdown/plugin-block": "7.3.3",
46
+ "@milkdown/plugin-clipboard": "7.3.3",
47
+ "@milkdown/plugin-cursor": "7.3.3",
48
+ "@milkdown/plugin-indent": "7.3.3",
49
+ "@milkdown/plugin-history": "7.3.3",
50
+ "@milkdown/plugin-tooltip": "7.3.3",
51
+ "@milkdown/plugin-slash": "7.3.3",
52
+ "@milkdown/preset-commonmark": "7.3.3",
53
+ "@milkdown/prose": "7.3.3",
54
+ "@milkdown/utils": "7.3.3"
55
+ },
56
+ "nx": {
57
+ "targets": {
58
+ "build": {
59
+ "outputs": [
60
+ "{projectRoot}/lib"
61
+ ],
62
+ "dependsOn": [
63
+ {
64
+ "target": "build",
65
+ "projects": "dependencies"
66
+ }
67
+ ]
68
+ },
69
+ "tsc": {
70
+ "outputs": [],
71
+ "dependsOn": [
72
+ {
73
+ "target": "build",
74
+ "projects": "dependencies"
75
+ }
76
+ ]
77
+ }
78
+ }
79
+ },
80
+ "scripts": {
81
+ "start": "concurrently -n es,dts \"vite build --watch\" \"tsc --emitDeclarationOnly --watch\"",
82
+ "test": "vitest",
83
+ "tsc": "tsc --noEmit && echo",
84
+ "build": "vite build && tsc --emitDeclarationOnly"
85
+ },
86
+ "types": "./lib/index.d.ts"
87
+ }
@@ -0,0 +1,98 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import type { DefaultValue } from '@milkdown/core'
3
+ import { Editor, defaultValueCtx, editorViewOptionsCtx, rootCtx } from '@milkdown/core'
4
+
5
+ import { history } from '@milkdown/plugin-history'
6
+ import { commonmark } from '@milkdown/preset-commonmark'
7
+ import { indent, indentConfig } from '@milkdown/plugin-indent'
8
+ import { clipboard } from '@milkdown/plugin-clipboard'
9
+ import { getMarkdown } from '@milkdown/utils'
10
+ import { CrepeTheme, loadTheme } from '../theme'
11
+ import type { CrepeFeature, CrepeFeatureConfig } from '../feature'
12
+ import { defaultFeatures, loadFeature } from '../feature'
13
+ import { configureEmotion, configureFeatures, configureTheme } from './slice'
14
+
15
+ export interface CrepeConfig {
16
+ theme?: CrepeTheme
17
+ features?: Partial<Record<CrepeFeature, boolean>>
18
+ featureConfigs?: CrepeFeatureConfig
19
+ root?: Node | string | null
20
+ defaultValue?: DefaultValue
21
+ }
22
+
23
+ export class Crepe {
24
+ readonly #editor: Editor
25
+ readonly #initPromise: Promise<unknown>
26
+ readonly #rootElement: Node
27
+ #editable = true
28
+
29
+ constructor({
30
+ theme = CrepeTheme.Classic,
31
+ root,
32
+ features = {},
33
+ featureConfigs = {},
34
+ defaultValue = '',
35
+ }: CrepeConfig) {
36
+ const enabledFeatures = Object
37
+ .entries({
38
+ ...defaultFeatures,
39
+ ...features,
40
+ })
41
+ .filter(([, enabled]) => enabled)
42
+ .map(([feature]) => feature as CrepeFeature)
43
+
44
+ this.#rootElement = (typeof root === 'string' ? document.querySelector(root) : root) ?? document.body
45
+ this.#editor = Editor.make()
46
+ .config(configureFeatures(enabledFeatures))
47
+ .config(configureEmotion(this.#rootElement))
48
+ .config(configureTheme(theme))
49
+ .config((ctx) => {
50
+ ctx.set(rootCtx, this.#rootElement)
51
+ ctx.set(defaultValueCtx, defaultValue)
52
+ ctx.set(editorViewOptionsCtx, {
53
+ editable: () => this.#editable,
54
+ })
55
+ ctx.update(indentConfig.key, value => ({
56
+ ...value,
57
+ size: 4,
58
+ }))
59
+ })
60
+ .use(commonmark)
61
+ .use(history)
62
+ .use(indent)
63
+ .use(clipboard)
64
+
65
+ const promiseList: Promise<unknown>[] = [loadTheme(theme, this.#editor)]
66
+
67
+ enabledFeatures.forEach((feature) => {
68
+ const config = (featureConfigs as Partial<Record<CrepeFeature, never>>)[feature]
69
+ promiseList.push(
70
+ loadFeature(feature, this.#editor, config),
71
+ )
72
+ })
73
+
74
+ this.#initPromise = Promise.all(promiseList)
75
+ }
76
+
77
+ async create() {
78
+ await this.#initPromise
79
+ return this.#editor.create()
80
+ }
81
+
82
+ async destroy() {
83
+ await this.#initPromise
84
+ return this.#editor.destroy()
85
+ }
86
+
87
+ get editor(): Editor {
88
+ return this.#editor
89
+ }
90
+
91
+ setReadonly(value: boolean) {
92
+ this.#editable = !value
93
+ }
94
+
95
+ getMarkdown() {
96
+ return this.#editor.action(getMarkdown())
97
+ }
98
+ }
@@ -0,0 +1,4 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+
3
+ export { EmotionCtx } from './slice'
4
+ export { Crepe, type CrepeConfig } from './crepe'
@@ -0,0 +1,44 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import type { Ctx } from '@milkdown/ctx'
3
+ import { createSlice } from '@milkdown/ctx'
4
+ import type { Emotion } from '@emotion/css/create-instance'
5
+ import createEmotion from '@emotion/css/create-instance'
6
+ import { customAlphabet } from 'nanoid'
7
+ import { CrepeTheme } from '../theme'
8
+ import type { CrepeFeature } from '../feature'
9
+
10
+ export const ThemeCtx = createSlice(CrepeTheme.Classic, 'ThemeCtx')
11
+
12
+ export const FeaturesCtx = createSlice([] as CrepeFeature[], 'FeaturesCtx')
13
+
14
+ export const EmotionCtx = createSlice(null as unknown as Emotion, 'EmotionCtx')
15
+
16
+ export function configureTheme(theme: CrepeTheme) {
17
+ return (ctx: Ctx) => {
18
+ ctx.inject(ThemeCtx, theme)
19
+ }
20
+ }
21
+
22
+ const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz', 6)
23
+ export function configureEmotion(container: Node) {
24
+ return (ctx: Ctx) => {
25
+ const emotion = createEmotion({
26
+ key: `crepe-${nanoid()}`,
27
+ container,
28
+ })
29
+ ctx.inject(EmotionCtx, emotion)
30
+ }
31
+ }
32
+
33
+ export function injectStyle(style: string) {
34
+ return (ctx: Ctx) => {
35
+ const emotion = ctx.get(EmotionCtx)
36
+ emotion.injectGlobal(style)
37
+ }
38
+ }
39
+
40
+ export function configureFeatures(features: CrepeFeature[]) {
41
+ return (ctx: Ctx) => {
42
+ ctx.inject(FeaturesCtx, features)
43
+ }
44
+ }
@@ -0,0 +1,68 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { type Component, c, html, useEffect, useRef } from 'atomico'
3
+
4
+ const menuIcon = html`
5
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
6
+ <g clip-path="url(#clip0_971_7680)">
7
+ <path d="M11 18C11 19.1 10.1 20 9 20C7.9 20 7 19.1 7 18C7 16.9 7.9 16 9 16C10.1 16 11 16.9 11 18ZM9 10C7.9 10 7 10.9 7 12C7 13.1 7.9 14 9 14C10.1 14 11 13.1 11 12C11 10.9 10.1 10 9 10ZM9 4C7.9 4 7 4.9 7 6C7 7.1 7.9 8 9 8C10.1 8 11 7.1 11 6C11 4.9 10.1 4 9 4ZM15 8C16.1 8 17 7.1 17 6C17 4.9 16.1 4 15 4C13.9 4 13 4.9 13 6C13 7.1 13.9 8 15 8ZM15 10C13.9 10 13 10.9 13 12C13 13.1 13.9 14 15 14C16.1 14 17 13.1 17 12C17 10.9 16.1 10 15 10ZM15 16C13.9 16 13 16.9 13 18C13 19.1 13.9 20 15 20C16.1 20 17 19.1 17 18C17 16.9 16.1 16 15 16Z" fill="#817567"/>
8
+ </g>
9
+ <defs>
10
+ <clipPath id="clip0_971_7680">
11
+ <rect width="24" height="24" fill="white"/>
12
+ </clipPath>
13
+ </defs>
14
+ </svg>
15
+ `
16
+
17
+ const plusIcon = html`
18
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
19
+ <g clip-path="url(#clip0_971_7676)">
20
+ <path d="M18 13H13V18C13 18.55 12.55 19 12 19C11.45 19 11 18.55 11 18V13H6C5.45 13 5 12.55 5 12C5 11.45 5.45 11 6 11H11V6C11 5.45 11.45 5 12 5C12.55 5 13 5.45 13 6V11H18C18.55 11 19 11.45 19 12C19 12.55 18.55 13 18 13Z" fill="#817567"/>
21
+ </g>
22
+ <defs>
23
+ <clipPath id="clip0_971_7676">
24
+ <rect width="24" height="24" fill="white"/>
25
+ </clipPath>
26
+ </defs>
27
+ </svg>
28
+ `
29
+
30
+ export interface BlockHandleProps {
31
+ show: boolean
32
+ onAdd: () => void
33
+ }
34
+
35
+ const blockHandleComponent: Component<BlockHandleProps> = ({ onAdd }) => {
36
+ const ref = useRef<HTMLDivElement>()
37
+ useEffect(() => {
38
+ ref.current?.classList.remove('active')
39
+ })
40
+ const onMouseDown = (e: MouseEvent) => {
41
+ e.preventDefault()
42
+ e.stopPropagation()
43
+ ref.current?.classList.add('active')
44
+ }
45
+ const onMouseUp = (e: MouseEvent) => {
46
+ e.preventDefault()
47
+ e.stopPropagation()
48
+ onAdd?.()
49
+ ref.current?.classList.remove('active')
50
+ }
51
+ return html`
52
+ <host>
53
+ <div ref=${ref} onmousedown=${onMouseDown} onmouseup=${onMouseUp} class="operation-item">
54
+ ${plusIcon}
55
+ </div>
56
+ <div class="operation-item">
57
+ ${menuIcon}
58
+ </div>
59
+ </host>
60
+ `
61
+ }
62
+
63
+ blockHandleComponent.props = {
64
+ show: Boolean,
65
+ onAdd: Function,
66
+ }
67
+
68
+ export const BlockHandleElement = c(blockHandleComponent)
@@ -0,0 +1,81 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import type { PluginView } from '@milkdown/prose/state'
3
+ import { TextSelection } from '@milkdown/prose/state'
4
+ import { BlockProvider, block } from '@milkdown/plugin-block'
5
+ import type { Ctx } from '@milkdown/ctx'
6
+ import type { EditorView } from '@milkdown/prose/view'
7
+ import type { AtomicoThis } from 'atomico/types/dom'
8
+ import { editorViewCtx } from '@milkdown/core'
9
+ import { paragraphSchema } from '@milkdown/preset-commonmark'
10
+ import { menuAPI } from '../menu'
11
+ import type { BlockHandleProps } from './component'
12
+ import { BlockHandleElement } from './component'
13
+
14
+ export class BlockHandleView implements PluginView {
15
+ #content: AtomicoThis<BlockHandleProps>
16
+ #provider: BlockProvider
17
+ #ctx: Ctx
18
+
19
+ constructor(ctx: Ctx, view: EditorView) {
20
+ this.#ctx = ctx
21
+ const content = new BlockHandleElement()
22
+ this.#content = content
23
+ this.#content.onAdd = this.onAdd
24
+ this.#provider = new BlockProvider({
25
+ ctx,
26
+ content,
27
+ tippyOptions: {
28
+ arrow: false,
29
+ delay: 0,
30
+ duration: 0,
31
+ onShow: () => {
32
+ this.#content.show = true
33
+ },
34
+ onHidden: () => {
35
+ this.#content.show = false
36
+ },
37
+ },
38
+ })
39
+ this.update(view)
40
+ }
41
+
42
+ update = (view: EditorView) => {
43
+ this.#provider.update(view)
44
+ }
45
+
46
+ destroy = () => {
47
+ this.#provider.destroy()
48
+ this.#content.remove()
49
+ }
50
+
51
+ onAdd = () => {
52
+ const ctx = this.#ctx
53
+ const view = ctx.get(editorViewCtx)
54
+ if (!view.hasFocus())
55
+ view.focus()
56
+
57
+ const { state, dispatch } = view
58
+ const active = this.#provider.activeNode
59
+ if (!active)
60
+ return
61
+ const pos = active.$pos
62
+ const isNoneTextBlock = ['hr', 'image-block'].includes(active.node.type.name)
63
+ const nodeSize = isNoneTextBlock ? active.node.nodeSize : active.node.content.size
64
+ const side = pos.pos + nodeSize + (['blockquote'].includes(pos.parent.type.name) ? 1 : 0)
65
+ const offset
66
+ = ['blockquote'].includes(pos.parent.type.name) ? 1 : isNoneTextBlock ? 1 : 2
67
+ let tr = state.tr.insert(side, paragraphSchema.type(ctx).create())
68
+ tr = tr.setSelection(TextSelection.create(tr.doc, side + offset))
69
+ dispatch(tr.scrollIntoView())
70
+
71
+ this.#provider.hide()
72
+ ctx.get(menuAPI.key).show(tr.selection.from)
73
+ }
74
+ }
75
+
76
+ customElements.define('milkdown-block-handle', BlockHandleElement)
77
+ export function configureBlockHandle(ctx: Ctx) {
78
+ ctx.set(block.key, {
79
+ view: view => new BlockHandleView(ctx, view),
80
+ })
81
+ }
@@ -0,0 +1,17 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import { block } from '@milkdown/plugin-block'
3
+ import type { DefineFeature } from '../shared'
4
+ import { injectStyle } from '../../core/slice'
5
+ import { configureBlockHandle } from './handle'
6
+ import { configureMenu, menu, menuAPI } from './menu'
7
+ import style from './style.css?inline'
8
+
9
+ export const defineFeature: DefineFeature = (editor) => {
10
+ editor
11
+ .config(injectStyle(style))
12
+ .config(configureBlockHandle)
13
+ .config(configureMenu)
14
+ .use(menuAPI)
15
+ .use(block)
16
+ .use(menu)
17
+ }
@@ -0,0 +1,210 @@
1
+ /* Copyright 2021, Milkdown by Mirone. */
2
+ import type { Component } from 'atomico'
3
+ import { c, html, useCallback, useEffect, useHost, useMemo, useRef, useState } from 'atomico'
4
+ import type { Ctx } from '@milkdown/ctx'
5
+ import { getGroups } from './config'
6
+
7
+ export interface MenuProps {
8
+ ctx: Ctx
9
+ show: boolean
10
+ filter: string
11
+ hide: () => void
12
+ }
13
+
14
+ export const menuComponent: Component<MenuProps> = ({
15
+ show,
16
+ hide,
17
+ ctx,
18
+ filter,
19
+ }) => {
20
+ const { groups, size } = useMemo(() => getGroups(filter), [filter])
21
+
22
+ const host = useHost()
23
+ const [hoverIndex, setHoverIndex] = useState(0)
24
+
25
+ const prevMousePosition = useRef({ x: -999, y: -999 })
26
+
27
+ const onMouseMove = useCallback((e: MouseEvent) => {
28
+ const prevPos = prevMousePosition.current
29
+ if (!prevPos)
30
+ return
31
+
32
+ const { x, y } = e
33
+ prevPos.x = x
34
+ prevPos.y = y
35
+ }, [])
36
+
37
+ useEffect(() => {
38
+ if (size === 0 && show)
39
+ hide?.()
40
+ }, [size, show])
41
+
42
+ const onHover = useCallback((
43
+ index: number | ((prev: number) => number),
44
+ after?: (index: number) => void,
45
+ ) => {
46
+ setHoverIndex((prev) => {
47
+ const next = typeof index === 'function' ? index(prev) : index
48
+
49
+ after?.(next)
50
+ return next
51
+ })
52
+ }, [])
53
+
54
+ const scrollToIndex = useCallback((index: number) => {
55
+ host
56
+ .current
57
+ .querySelector(`[data-index="${index}"]`)
58
+ ?.scrollIntoView({
59
+ behavior: 'smooth',
60
+ block: 'end',
61
+ })
62
+ }, [])
63
+
64
+ const runByIndex = useCallback((index: number) => {
65
+ const item = groups.flatMap(group => group.items).at(index)
66
+ if (item && ctx)
67
+ item.onRun(ctx)
68
+
69
+ hide?.()
70
+ }, [groups])
71
+
72
+ const onKeydown = useCallback((e: KeyboardEvent) => {
73
+ if (e.key === 'Escape') {
74
+ e.preventDefault()
75
+ hide?.()
76
+ return
77
+ }
78
+
79
+ if (e.key === 'ArrowDown') {
80
+ e.preventDefault()
81
+ return onHover(index => (index < size - 1) ? index + 1 : index, scrollToIndex)
82
+ }
83
+
84
+ if (e.key === 'ArrowUp') {
85
+ e.preventDefault()
86
+ return onHover(index => index <= 0 ? index : index - 1, scrollToIndex)
87
+ }
88
+
89
+ if (e.key === 'ArrowLeft') {
90
+ e.preventDefault()
91
+ return onHover((index) => {
92
+ const group = groups.find(group => group.range[0] <= index && group.range[1] > index)
93
+ if (!group)
94
+ return index
95
+
96
+ const prevGroup = groups[groups.indexOf(group) - 1]
97
+ if (!prevGroup)
98
+ return index
99
+
100
+ return prevGroup.range[1] - 1
101
+ }, scrollToIndex)
102
+ }
103
+
104
+ if (e.key === 'ArrowRight') {
105
+ e.preventDefault()
106
+ return onHover((index) => {
107
+ const group = groups.find(group => group.range[0] <= index && group.range[1] > index)
108
+ if (!group)
109
+ return index
110
+
111
+ const nextGroup = groups[groups.indexOf(group) + 1]
112
+ if (!nextGroup)
113
+ return index
114
+
115
+ return nextGroup.range[0]
116
+ }, scrollToIndex)
117
+ }
118
+
119
+ if (e.key === 'Enter') {
120
+ e.preventDefault()
121
+ runByIndex(hoverIndex)
122
+ }
123
+ }, [hide, groups, hoverIndex])
124
+
125
+ const onMouseEnter = useCallback((index: number) => {
126
+ return (e: MouseEvent) => {
127
+ const prevPos = prevMousePosition.current
128
+ if (!prevPos)
129
+ return
130
+
131
+ const { x, y } = e
132
+ if (x === prevPos.x && y === prevPos.y)
133
+ return
134
+
135
+ onHover(index)
136
+ }
137
+ }, [])
138
+
139
+ useEffect(() => {
140
+ if (show)
141
+ document.addEventListener('keydown', onKeydown, { capture: true })
142
+
143
+ else document.removeEventListener('keydown', onKeydown, { capture: true })
144
+
145
+ return () => {
146
+ document.removeEventListener('keydown', onKeydown, { capture: true })
147
+ }
148
+ }, [show, onKeydown])
149
+
150
+ return html`
151
+ <host onmousedown=${(e: MouseEvent) => e.preventDefault()}>
152
+ <nav class="tab-group">
153
+ <ul>
154
+ ${groups.map(group =>
155
+ html`<li
156
+ key=${group.key}
157
+ onmousedown=${() => onHover(group.range[0], scrollToIndex)}
158
+ class=${hoverIndex >= group.range[0] && hoverIndex < group.range[1] ? 'selected' : ''}
159
+ >
160
+ ${group.label}
161
+ </li>`)}
162
+ </ul>
163
+ </nav>
164
+ <div class="menu-groups" onmousemove=${onMouseMove}>
165
+ ${groups.map((group) => {
166
+ return html`
167
+ <div key=${group.key} class="menu-group">
168
+ <h6>${group.label}</h6>
169
+ <ul>
170
+ ${group.items.map(item =>
171
+ html`<li
172
+ key=${item.key}
173
+ data-index=${item.index}
174
+ class=${hoverIndex === item.index ? 'hover' : ''}
175
+ onmouseenter=${onMouseEnter(item.index)}
176
+ onmousedown=${() => {
177
+ host
178
+ .current
179
+ .querySelector(`[data-index="${item.index}"]`)
180
+ ?.classList.add('active')
181
+ }}
182
+ onmouseup=${() => {
183
+ host
184
+ .current
185
+ .querySelector(`[data-index="${item.index}"]`)
186
+ ?.classList.remove('active')
187
+ runByIndex(item.index)
188
+ }}
189
+ >
190
+ ${item.icon}
191
+ <span>${item.label}</span>
192
+ </li>`,
193
+ )}
194
+ </ul>
195
+ </div>
196
+ `
197
+ })}
198
+ </div>
199
+ </host>
200
+ `
201
+ }
202
+
203
+ menuComponent.props = {
204
+ ctx: Object,
205
+ show: Boolean,
206
+ filter: String,
207
+ hide: Function,
208
+ }
209
+
210
+ export const MenuElement = c(menuComponent)