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 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
- ### 1. Install Peer Dependencies
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
- Before installing the main package, you need to ensure that all its peer dependencies are present 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.
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
- The primary peer dependencies you need to install are:
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
- ### 2. Install Package
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
- Here is an example of how to use the editor in your project:
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 Editor from "lexical-medium-editor";
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
- export default function App() {
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
- console.log(editorState);
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
- <Editor
53
- initialConfig={initialConfig}
54
- onChange={handleOnChange}
55
- editorRef={editorRef}
56
- blockToolbarGap={32}
57
- isHeadingOneFirst={false}
58
- spellCheck={false}
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
- > [!TIP]
65
- > You can also copy the CSS from `node_modules/lexical-medium-editor/dist-lib/lexical-medium-editor.css` into your own project and modify it to customize the editor's appearance.
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.