lexical-medium-editor 1.2.16 → 1.2.18
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 +272 -30
- package/dist-lib/index.es.js +1995 -829
- package/dist-lib/index.es.js.map +1 -1
- package/dist-lib/lexical-medium-editor.css +1 -1
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -3,63 +3,305 @@ Please refer to the [guide](https://medium-editor-lmr5y.ondigitalocean.app/) for
|
|
|
3
3
|
|
|
4
4
|
## Installation
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
The first step is to install peer dependencies in your project. This package assumes you are working within a React environment, so `react` and `react-dom` should ideally already be part of your project setup. The primary peer dependencies you need to install are:
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
* `@lexical/react`: ">=0.39.0"
|
|
9
|
+
* `@tabler/icons-react`: ">=3.31.0"
|
|
10
|
+
* `lexical`: ">=0.39.0"
|
|
11
|
+
* `react-aria-components`: ">=1.8.0"
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
You can install them using npm. Adjust the versions if needed to match your project's requirements, ensuring they meet the minimum versions specified above. The command to add to install the peer dependencies using npm is:
|
|
11
14
|
|
|
12
|
-
* `@lexical/react`: ">=0.39.0"
|
|
13
|
-
* `@tabler/icons-react`: ">=3.31.0"
|
|
14
|
-
* `lexical`: ">=0.39.0"
|
|
15
|
-
* `react-aria-components`: ">=1.8.0"
|
|
16
|
-
|
|
17
|
-
You can install them using npm. Adjust the versions if needed to match your project's requirements, ensuring they meet the minimum versions specified above.
|
|
18
|
-
|
|
19
|
-
**Using npm:**
|
|
20
15
|
```bash
|
|
21
16
|
npm install @lexical/react @tabler/icons-react lexical react-aria-components
|
|
22
17
|
```
|
|
23
18
|
|
|
24
|
-
|
|
19
|
+
There are other dependencies as well which are listed in the `package.json` file. However, they will be automatically installed by npm. You don't need to manually install them.
|
|
25
20
|
|
|
26
|
-
Once the peer dependencies are installed, you can proceed to install the main package.
|
|
27
|
-
|
|
28
|
-
To install the `lexical-medium-editor` package, run the following command:
|
|
21
|
+
Once the peer dependencies are installed, you can proceed to install the main package. To install using npm, the command is:
|
|
29
22
|
|
|
30
23
|
```bash
|
|
31
|
-
npm install lexical-medium-editor
|
|
24
|
+
npm install lexical-medium-editor@latest
|
|
32
25
|
```
|
|
33
26
|
|
|
34
27
|
## Usage
|
|
35
28
|
|
|
36
|
-
|
|
29
|
+
Once the setup is done, you can create and use an `Editor` component that closely resembles this page as follows:
|
|
30
|
+
|
|
31
|
+
First create an `Editor` component and the associated css as follows:
|
|
32
|
+
|
|
33
|
+
- `src`
|
|
34
|
+
- `components`
|
|
35
|
+
- `Editor.jsx`
|
|
36
|
+
- `editor_styles.css`
|
|
37
|
+
- `App.jsx`
|
|
38
|
+
|
|
39
|
+
The `Editor.jsx` file should look like this:
|
|
37
40
|
|
|
38
41
|
```jsx
|
|
39
42
|
import { useRef } from "react";
|
|
40
|
-
import
|
|
43
|
+
import { Button } from "react-aria-components";
|
|
44
|
+
import { $getRoot } from "lexical";
|
|
45
|
+
import { $generateHtmlFromNodes } from "@lexical/html";
|
|
46
|
+
import LexicalEditor from "lexical-medium-editor";
|
|
41
47
|
import { initialConfig } from "lexical-medium-editor/config";
|
|
42
48
|
import "lexical-medium-editor/styles.css";
|
|
49
|
+
import "./editor_styles.css";
|
|
43
50
|
|
|
44
|
-
|
|
51
|
+
function Navbar({ onCopyHTML, onCopyJSON, onCopyText }) {
|
|
52
|
+
return (
|
|
53
|
+
<nav className="navbar">
|
|
54
|
+
<div className="navbar-links" />
|
|
55
|
+
<div className="action-grp">
|
|
56
|
+
<Button className="navbar-btn" onPress={onCopyHTML}>
|
|
57
|
+
Copy HTML
|
|
58
|
+
</Button>
|
|
59
|
+
<Button className="navbar-btn" onPress={onCopyJSON}>
|
|
60
|
+
Copy JSON
|
|
61
|
+
</Button>
|
|
62
|
+
<Button className="navbar-btn" onPress={onCopyText}>
|
|
63
|
+
Copy Text
|
|
64
|
+
</Button>
|
|
65
|
+
</div>
|
|
66
|
+
</nav>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export default function Editor() {
|
|
71
|
+
const editorStateRef = useRef(null);
|
|
45
72
|
const editorRef = useRef(null);
|
|
46
73
|
|
|
47
74
|
const handleOnChange = (editorState) => {
|
|
48
|
-
|
|
75
|
+
editorStateRef.current = editorState;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const copyToClipboard = async (text) => {
|
|
79
|
+
await navigator.clipboard.writeText(text);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const handleCopyHTML = () => {
|
|
83
|
+
const editor = editorRef.current;
|
|
84
|
+
if (editor) {
|
|
85
|
+
editor.read(() => {
|
|
86
|
+
const htmlString = $generateHtmlFromNodes(editor, null);
|
|
87
|
+
copyToClipboard(htmlString);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const handleCopyJSON = () => {
|
|
93
|
+
if (editorStateRef.current) {
|
|
94
|
+
const jsonString = JSON.stringify(editorStateRef.current.toJSON(), null, 2);
|
|
95
|
+
copyToClipboard(jsonString);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const handleCopyText = () => {
|
|
100
|
+
if (editorStateRef.current) {
|
|
101
|
+
editorStateRef.current.read(() => {
|
|
102
|
+
const textContent = $getRoot().getTextContent();
|
|
103
|
+
copyToClipboard(textContent);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
49
106
|
};
|
|
50
107
|
|
|
51
108
|
return (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
109
|
+
<>
|
|
110
|
+
<Navbar
|
|
111
|
+
onCopyHTML={handleCopyHTML}
|
|
112
|
+
onCopyJSON={handleCopyJSON}
|
|
113
|
+
onCopyText={handleCopyText}
|
|
114
|
+
/>
|
|
115
|
+
<div className="editor-wrapper">
|
|
116
|
+
<LexicalEditor
|
|
117
|
+
initialConfig={initialConfig}
|
|
118
|
+
onChange={handleOnChange}
|
|
119
|
+
editorRef={editorRef}
|
|
120
|
+
blockToolbarGap={32}
|
|
121
|
+
isHeadingOneFirst={false}
|
|
122
|
+
spellCheck={false}
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
</>
|
|
60
126
|
);
|
|
61
127
|
}
|
|
62
128
|
```
|
|
63
129
|
|
|
64
|
-
|
|
65
|
-
|
|
130
|
+
The `editor_styles.css` file should look like this:
|
|
131
|
+
|
|
132
|
+
```css
|
|
133
|
+
.editor-wrapper {
|
|
134
|
+
margin: 0 auto;
|
|
135
|
+
width: 50%;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@media (max-width: 1200px) {
|
|
139
|
+
.editor-wrapper {
|
|
140
|
+
width: 65%;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@media (max-width: 992px) {
|
|
145
|
+
.editor-wrapper {
|
|
146
|
+
width: 75%;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@media (max-width: 768px) {
|
|
151
|
+
.editor-wrapper {
|
|
152
|
+
width: 85%;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.navbar {
|
|
157
|
+
display: flex;
|
|
158
|
+
justify-content: space-between;
|
|
159
|
+
align-items: center;
|
|
160
|
+
padding: 8px 16px;
|
|
161
|
+
background-color: white;
|
|
162
|
+
border-bottom: 4px solid #fff34e;
|
|
163
|
+
margin-bottom: 32px;
|
|
164
|
+
height: 64px;
|
|
165
|
+
box-sizing: border-box;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.action-grp {
|
|
169
|
+
gap: 8px;
|
|
170
|
+
display: flex;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.navbar-btn {
|
|
174
|
+
color: var(--text-color-dark);
|
|
175
|
+
background: var(--button-background-dark);
|
|
176
|
+
border: 1px solid var(--border-color-dark);
|
|
177
|
+
border-radius: 4px;
|
|
178
|
+
appearance: none;
|
|
179
|
+
vertical-align: middle;
|
|
180
|
+
font-size: 1rem;
|
|
181
|
+
text-align: center;
|
|
182
|
+
margin: 0;
|
|
183
|
+
outline: none;
|
|
184
|
+
padding: 6px 10px;
|
|
185
|
+
text-decoration: none;
|
|
186
|
+
font-family: "firacode", monospace;
|
|
187
|
+
cursor: pointer;
|
|
188
|
+
|
|
189
|
+
&[data-pressed] {
|
|
190
|
+
box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.1);
|
|
191
|
+
background: var(--button-background-pressed-dark);
|
|
192
|
+
border-color: var(--border-color-pressed-dark);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
&[data-focus-visible] {
|
|
196
|
+
outline: 2px solid var(--focus-ring-color-dark);
|
|
197
|
+
outline-offset: -1px;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@media (max-width: 576px) {
|
|
202
|
+
.navbar {
|
|
203
|
+
padding: 8px;
|
|
204
|
+
margin-bottom: 16px;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.action-grp {
|
|
208
|
+
gap: 4px;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.navbar-btn {
|
|
212
|
+
padding: 4px 8px;
|
|
213
|
+
font-size: 0.875rem;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
.editor-wrapper {
|
|
218
|
+
width: 95%;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@media (max-width: 400px) {
|
|
223
|
+
.navbar {
|
|
224
|
+
flex-direction: column;
|
|
225
|
+
height: auto;
|
|
226
|
+
padding: 8px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.action-grp {
|
|
230
|
+
margin-top: 8px;
|
|
231
|
+
width: 100%;
|
|
232
|
+
justify-content: space-between;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.editor-wrapper {
|
|
236
|
+
width: 100%;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Now you can import and use this component into your main `App.jsx` component and use it like so:
|
|
242
|
+
|
|
243
|
+
```jsx
|
|
244
|
+
import Editor from "./components/Editor";
|
|
245
|
+
import "./App.css";
|
|
246
|
+
|
|
247
|
+
function App() {
|
|
248
|
+
return (
|
|
249
|
+
<div className="app-container">
|
|
250
|
+
<Editor />
|
|
251
|
+
</div>
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export default App;
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
One final change. To use LaTeX, you need to load MathJax v4 into your `index.html` file. This can be done by adding the following tags:
|
|
259
|
+
|
|
260
|
+
```html
|
|
261
|
+
<!doctype html>
|
|
262
|
+
<html lang="en">
|
|
263
|
+
<head>
|
|
264
|
+
<meta charset="UTF-8" />
|
|
265
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
266
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
267
|
+
<title>medium-blog-editor</title>
|
|
268
|
+
<script>
|
|
269
|
+
window.MathJax = {
|
|
270
|
+
tex: {
|
|
271
|
+
inlineMath: [
|
|
272
|
+
["$", "$"],
|
|
273
|
+
["\\(", "\\)"],
|
|
274
|
+
],
|
|
275
|
+
displayMath: [
|
|
276
|
+
["$$", "$$"],
|
|
277
|
+
["\\[", "\\]"],
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
chtml: {
|
|
281
|
+
displayOverflow: "scroll",
|
|
282
|
+
linebreaks: {
|
|
283
|
+
inline: true,
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
startup: {
|
|
287
|
+
typeset: false,
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
</script>
|
|
291
|
+
<script
|
|
292
|
+
type="text/javascript"
|
|
293
|
+
id="MathJax-script"
|
|
294
|
+
async
|
|
295
|
+
src="https://cdn.jsdelivr.net/npm/mathjax@4.1.0/tex-mml-chtml.js"
|
|
296
|
+
></script>
|
|
297
|
+
</head>
|
|
298
|
+
<body>
|
|
299
|
+
<div id="root"></div>
|
|
300
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
301
|
+
</body>
|
|
302
|
+
</html>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
That's it. You're ready to go!
|
|
306
|
+
|
|
307
|
+
Note that this was tested on vite build. It was not thoroughly tested for each scenario. So there's a good chance that you'll encounter errors. If you do, please email them to me at ms.neerajkrishna@gmail.com or you can also raise an issue in the GitHub repository.
|