prosemirror-codemirror-block 0.2.8 → 0.2.9

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 (2) hide show
  1. package/README.md +97 -165
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,20 +1,21 @@
1
1
  # prosemirror-codemirror-block
2
2
 
3
- ![alt text](https://gitlab.com/emergence-engineering/prosemirror-image-plugin/-/raw/master/public/editorScreenshot.png)
3
+ ![alt text](https://gitlab.com/emergence-engineering/prosemirror-codemirror-block/-/raw/main/public/editorScreenshot.png)
4
+
5
+ Sponsored by [Skiff](https://www.skiff.org/), the _best_ end-to-end encrypted Private & decentralized
6
+ workspace.
7
+
4
8
 
5
9
  By [Viktor Váczi](https://emergence-engineering.com/cv/viktor) at [Emergence Engineering](https://emergence-engineering.com/)
6
10
 
7
- Try it out at <https://emergence-engineering.com/blog/prosemirror-image-plugin>
11
+ Try it out at <https://emergence-engineering.com/blog/prosemirror-codemirror-block>
8
12
 
9
13
  # Features
10
14
 
11
- - Drag and drop or paste images from anywhere
12
- - Upload images to endpoints, showing placeholder until the upload finishes, and optionally delete
13
- images when the image is removed from the document
14
- - Customizable overlay for alignment ( or whatever you think of! )
15
- - Optional image title
16
- - Image resizing with body resize listeners, so the image always fits the editor ( inspired by czi-prosemirror )
17
- - Scaling images with editor size ( when resizing is enabled )
15
+ - CodeMirror 6 `code_block` in ProseMirror
16
+ - Customizable language selector
17
+ - Lazy-loaded language support
18
+ - Legacy ( CodeMirror 5 ) language support trough `@codemirror/legacy-modes`
18
19
 
19
20
  # How to use
20
21
 
@@ -22,46 +23,70 @@ Try it out at <https://emergence-engineering.com/blog/prosemirror-image-plugin>
22
23
  import { schema } from "prosemirror-schema-basic";
23
24
  import { EditorState } from "prosemirror-state";
24
25
  import { EditorView } from "prosemirror-view";
25
- import { defaultSettings, updateImageNode, imagePlugin } from "prosemirror-image-plugin";
26
-
27
- import "prosemirror-image-plugin/dist/styles/common.css";
28
- import "prosemirror-image-plugin/dist/styles/withResize.css";
29
- import "prosemirror-image-plugin/dist/styles/sideResize.css";
30
-
31
- // Update your settings here!
32
- const imageSettings = {...defaultSettings};
33
-
34
- const imageSchema = new Schema({
35
- nodes: updateImageNode(schema.spec.nodes, {
36
- ...imageSettings,
37
- }),
38
- marks: schema.spec.marks,
26
+ import { exampleSetup } from "prosemirror-example-setup";
27
+ import {
28
+ codeMirrorBlockPlugin,
29
+ defaultSettings,
30
+ languageLoaders,
31
+ codeBlockArrowHandlers,
32
+ legacyLanguageLoaders,
33
+ } from "prosemirror-codemirror-block";
34
+ import { undo, redo } from "prosemirror-history";
35
+
36
+
37
+ const codeBlockSpec = schema.spec.nodes.get("code_block");
38
+
39
+ export default new Schema({
40
+ nodes: schema.spec.nodes.update("code_block", {
41
+ ...(codeBlockSpec || {}),
42
+ attrs: { ...codeBlockSpec?.attrs, lang: { default: null } },
43
+ }),
44
+ marks: schema.spec.marks,
39
45
  });
40
46
 
41
- const initialDoc = {
42
- content: [
43
- {
44
- content: [
47
+
48
+ const codeBlockDoc = {
49
+ content: [
45
50
  {
46
- text: "Start typing!",
47
- type: "text",
51
+ content: [
52
+ {
53
+ text: "prosemirror-codemirror-block",
54
+ type: "text",
55
+ },
56
+ ],
57
+ type: "paragraph",
48
58
  },
49
- ],
50
- type: "paragraph",
51
- },
52
- ],
53
- type: "doc",
59
+ {
60
+ content: [
61
+ {
62
+ text: "const jsFun = (arg) => {\n console.log(arg); \n}",
63
+ type: "text",
64
+ },
65
+ ],
66
+ attrs: {
67
+ lang: "javascript",
68
+ },
69
+ type: "code_block",
70
+ },
71
+ ],
72
+ type: "doc",
54
73
  };
55
74
 
56
- const state = EditorState.create({
57
- doc: imageSchema.nodeFromJSON(initialDoc),
58
- plugins: [
59
- ...exampleSetup({
60
- schema: imageSchema,
61
- menuContent: menu,
62
- }),
63
- imagePlugin(imageSchema, { ...imageSettings }),
64
- ],
75
+
76
+ const state = EditorState.create<typeof schema>({
77
+ doc: schema.nodeFromJSON(codeBlockDoc),
78
+ plugins: [
79
+ ...exampleSetup({
80
+ schema,
81
+ }),
82
+ codeMirrorBlockPlugin({
83
+ ...defaultSettings,
84
+ languageLoaders: { ...languageLoaders, ...legacyLanguageLoaders },
85
+ undo,
86
+ redo,
87
+ }),
88
+ keymap(codeBlockArrowHandlers),
89
+ ],
65
90
  });
66
91
 
67
92
  const view: EditorView = new EditorView(document.getElementById("editor"), {
@@ -70,133 +95,41 @@ const view: EditorView = new EditorView(document.getElementById("editor"), {
70
95
  ```
71
96
 
72
97
  # Configuration
73
- ### ImagePluginSettings
98
+ ### CodeBlockSettings
74
99
 
75
100
  Interface for the settings used by this plugin.
76
101
 
77
- | name | type | description |
78
- | ------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
79
- | uploadFile | (file: File) => Promise\<string> | Uploads the image file to a remote server and returns the uploaded image URL. By default it returns the dataURI of the image. |
80
- | deleteSrc | (src: string) => Promise\<void> | Deletes the image from the server. |
81
- | hasTitle | boolean | If set to `true` then the image has a title field. True by default. `isBlock` should be `true` if set. |
82
- | extraAttributes | Record\<string, string &#124; null> | Extra attributes on the new `image` node. By default is `defaultExtraAttributes`. |
83
- | createOverlay | ( node: PMNode, getPos: (() => number) &#124; boolean, view: EditorView) => Node &#124; undefined | create an overlay DOM Node for the `image` node. The default is the one you see in the intro image. |
84
- | updateOverlay | ( overlayRoot: Node, getPos: (() => number) &#124; boolean, view: EditorView, node: PMNode) => void | The function that runs whenever the `image` ProseMirror node changes to update the overlay. |
85
- | defaultTitle | string | Default title on new images. |
86
- | defaultAlt | string | Default alt on new images ( when it's not defined ). |
87
- | downloadImage | (url: string) => Promise\<string> | Download image data with a callback function. Useful for images with behind auth. |
88
- | downloadPlaceholder | string | If `downloadImage` is defined then this image is showed while the download is in progress. |
89
- | isBlock | boolean | `true` if you want block images, `false` if you want inline ( ProseMirror default ). Titles are only possible with block images. Default `true`. |
90
- | enableResize | boolean | Enables resize features. Default `true`. |
91
- | resizeCallback | (el: Element, updateCallback: () => void) => () => void | Creates & destroys resize listeners |
92
- | imageMargin | number | Space in `px` on the side an image. Default 50. |
93
- | minSize | number | Minimum size in `px` of an image. Default 50. |
94
- | maxSize | number | Maximum size in `px` of an image. Default 2000. |
95
- | scaleImage | boolean | If `true` then images scale proportionally with editor width. Default `true`. |
96
-
97
- ### updateImageNode
98
- Returns the updated nodes ( `Schema["spec"]["nodes"] type` )
99
-
100
- Arguments:
101
-
102
- | index | name | type | description |
103
- |-------|----------------|---------------------------|----------------------------------------------------------|
104
- | 1 | nodes | Schema ["spec"] ["nodes"] | nodes from the to-be-updated Schema spec |
105
- | 2 | pluginSettings | ImagePluginSettings | same plugin settings the plugin will be initialized with |
106
-
107
- ### startImageUpload
108
-
109
- Dispatches a transaction in the editor view which starts the image upload process ( and places placeholder etc ).
110
- Returns `undefined`
111
-
112
- Arguments:
113
-
114
- | index | name | type | description |
115
- | ----- | -------------- | -------------------- | --------------------------------------------------- |
116
- | 1 | view | EditorView | Reference of the mounted editor view |
117
- | 2 | file | File | image file to be uploaded |
118
- | 3 | alt | string | alt of the file ( file.name usually works ) |
119
- | 4 | pluginSettings | ImagePluginSettings | same plugin settings the plugin was initialized with |
120
- | 5 | schema | Schema | updated schema used by the editor |
121
- | 6 | pos | number | insert position in the document |
122
-
123
-
124
-
125
- ### Uploading files
126
- Be aware that the default `uploadFile` inserts the dataURI of the image directly into the
127
- ProseMirror document. That can cause issues with large files, for ex. `gif`s with long animations.
128
-
129
- ### Upload placeholder
130
- The plugin creates a widget decoration while the upload process is still in progress. The widget decoration's
131
- dom node is a `<placeholder>`, an example style could be:
132
- ```css
133
- placeholder {
134
- color: #ccc;
135
- position: relative;
136
- top: 6px;
137
- }
138
- placeholder:after {
139
- content: "☁";
140
- font-size: 200%;
141
- line-height: 0.1;
142
- font-weight: bold;
143
- }
144
- ```
145
-
146
- ### Uploading images from a file picker
147
-
148
- A small React example
149
-
150
- In the "html" / JSX part:
151
- ```typescript jsx
152
- <input type="file" id="imageselector" onChange={onInputChange} />
153
- ```
154
-
155
- The `onInputChange` callback:
156
- ```typescript
157
- const onInputChange = useCallback(
158
- (e: ChangeEvent<HTMLInputElement>) => {
159
- if (
160
- pmView?.state.selection.$from.parent.inlineContent &&
161
- e.target.files?.length
162
- ) {
163
- const file = e.target.files[0];
164
- startImageUpload(
165
- pmView,
166
- file,
167
- file.name,
168
- defaultSettings,
169
- imageSchema,
170
- pmView.state.selection.from,
171
- );
172
- }
173
- },
174
- [pmView],
175
- );
176
- ```
102
+ | name | type | description |
103
+ |-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
104
+ | createSelect | (settings: CodeBlockSettings, dom: HTMLElement, node: ProseMirrorNode, view: EditorView, getPos: (() => number) &#124; boolean) => ()=> void) | Callback to create lanaguge selector. Returns function that is called when the NodeView is cleaned up. Has default. |
105
+ | updateSelect | (settings: CodeBlockSettings, dom: HTMLElement, node: ProseMirrorNode, view: EditorView, getPos: (() => number) &#124; boolean, oldNode: ProseMirrorNode) => ()=> void) | Called when the codeblock node is updated. Should update the select value to reflect the `lang` property of the node. |
106
+ | languageLoaders | ?LanguageLoaders | Record of functions which return a code extension for a given language. |
107
+ | languageNameMap | ?Record<string, string> | Can be used to give aliases to languages in the selector. |
108
+ | languageWhitelist | ?string[] | List of used languages. |
109
+ | undo | (state: EditorState, dispatch: (tr: Transaction) => void) => void | Undo provided by `prosemirror-history`. YJS uses a different one! |
110
+ | redo | (state: EditorState, dispatch: (tr: Transaction) => void) => void | Redo provided by `prosemirror-history`. YJS uses a different one! |
111
+ | theme | Extension[] | Insert codemirror theme here. Or any other extension you want! |
177
112
 
178
113
  ### CSS & Styles
179
114
 
180
- The following styles are in the bundle:
181
- ```typescript
182
- import "prosemirror-image-plugin/dist/styles/common.css";
183
- import "prosemirror-image-plugin/dist/styles/withResize.css";
184
- import "prosemirror-image-plugin/dist/styles/sideResize.css";
185
- import "prosemirror-image-plugin/dist/styles/withoutResize.css";
186
- ```
187
-
188
- ## Known issues
189
-
190
- - titles and inline nodes do not work well together. If `hasTitle` is true then
191
- `isBlock` should also be true.
192
-
193
- ## Development
115
+ The following is a good starter style for the language selector:
116
+ ```css
117
+ .codeblock-select {
118
+ position: absolute;
119
+ right: 0;
120
+ z-index: 100;
121
+ opacity: 0;
122
+ transition: all 0.3s ease;
123
+ margin: 6px 14px;
124
+ }
125
+ .codeblock-root {
126
+ position: relative;
127
+ }
194
128
 
195
- ### Running & linking locally
196
- 1. install plugin dependencies: `npm install`
197
- 2. install peer dependencies: `npm run install-peers`
198
- 3. link local lib: `npm run link`
199
- 4. link the package from the project you want to use it: `npm run link prosemirror-image-plugin`
129
+ .codeblock-root:hover .codeblock-select {
130
+ opacity: 1;
131
+ }
132
+ ```
200
133
 
201
134
  ### About us
202
135
 
@@ -205,5 +138,4 @@ Emergence Engineering is dev shop from the EU:
205
138
 
206
139
  We're looking for work, especially with ProseMirror ;)
207
140
 
208
- Feel free to contact me at
209
- <viktor.vaczi@emergence-engineering.com>
141
+ Feel free to contact me at viktor.vaczi@emergence-engineering.com
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-codemirror-block",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "ProseMirror CodeMirror code block plugin",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.es.js",