@layers-app/editor 0.0.1 → 0.0.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.
package/README.md CHANGED
@@ -1,21 +1,39 @@
1
- # Editor
1
+ # LayersTextEditor
2
2
 
3
+ LayersTextEditor is a text editor for web applications written in JavaScript, with a focus on reliability, accessibility, and performance.
3
4
 
4
- Editor is a JavaScript text editor for web applications with a focus on reliability, accessibility, and performance. Editor aims to provide an optimal developer experience so that you can easily prototype and implement features with confidence. Combined with a highly extensible architecture, Editor allows developers to create unique text editors that can scale in both size and functionality.
5
+ <details>
6
+ <summary>
7
+ 🚀 Quick Start
8
+ </summary>
5
9
 
10
+ ## Installation
6
11
 
7
- ## Quick Start
12
+ To install the package, run one of the following commands:
8
13
 
14
+ ### Use npm:
9
15
 
10
- ```js
11
- import { Editor } from '@layers-app/editor';
16
+ ```bash
17
+ npm install @layers-app/editor
18
+ ```
19
+
20
+ ### Use yarn:
21
+
22
+ ```bash
23
+ yarn add @layers-app/editor
24
+ ```
25
+
26
+ ### Initializing the text editor
12
27
 
13
- Initialize the text editor.
28
+ ```
29
+ import { Editor } from '@layers-app/editor';
30
+ ```
14
31
 
15
- By default, Editor works with an object and can return either an object or HTML.
32
+ By default, LayersTextEditor works with an object and can return either an object or HTML.
16
33
 
17
34
  Example with an object:
18
35
 
36
+ ```js
19
37
  const text = 'Hello world';
20
38
 
21
39
  const json = {
@@ -30,32 +48,34 @@ const json = {
30
48
  style: '',
31
49
  text: text,
32
50
  type: 'text',
33
- version: 1
34
- }
51
+ version: 1,
52
+ },
35
53
  ],
36
54
  direction: 'ltr',
37
55
  format: '',
38
56
  indent: 0,
39
57
  type: 'paragraph',
40
- version: 1
41
- }
58
+ version: 1,
59
+ },
42
60
  ],
43
61
  direction: 'ltr',
44
62
  format: '',
45
63
  indent: 0,
46
64
  type: 'root',
47
- version: 1
48
- }
65
+ version: 1,
66
+ },
49
67
  };
50
68
 
51
69
  const onChange = (
52
- data // json
70
+ data, // json
53
71
  ) => <Editor initialContent={json} onChange={onChange} />;
72
+ ```
54
73
 
55
74
  You can also pass an HTML string to the editor.
56
75
 
57
76
  Example with HTML:
58
77
 
78
+ ```
59
79
  const html = `
60
80
  <h2 dir="ltr" style="text-align: left;">
61
81
  <span style="background-color: rgb(248, 231, 28); font-family: &quot;Trebuchet MS&quot;; white-space: pre-wrap;">Hello</span>
@@ -74,9 +94,11 @@ const html = `
74
94
  const onChange = (data) => // json
75
95
 
76
96
  <Editor initialContent={html} onChange={onChange} />
97
+ ```
77
98
 
78
- The outputFormat property controls how the onChange function outputs data. outputFormat can be either "html" or "json". An example with outputFormat:
99
+ The output of the data in the `onChange` function is controlled by the **outputFormat** property. **outputFormat** can be either "html" or "json". Example with **outputFormat**:
79
100
 
101
+ ```
80
102
  const html = `
81
103
  <h2 dir="ltr" style="text-align: left;">
82
104
  <span style="background-color: rgb(248, 231, 28); font-family: &quot;Trebuchet MS&quot;; white-space: pre-wrap;">Hello</span>
@@ -95,246 +117,249 @@ const html = `
95
117
  const onChange = (data) => // html
96
118
 
97
119
  <Editor initialContent={html} outputFormat="html" onChange={onChange} />
120
+ ```
98
121
 
99
- DocSpaceStylesProvider
100
-
101
- Use DocSpaceStylesProvider to add styling to your HTML content:
122
+ </details>
102
123
 
103
- <DocSpaceStylesProvider>
104
- <div
105
- dangerouslySetInnerHTML={{ __html: '<p>Your html here</p>' }}
106
- />
107
- </DocSpaceStylesProvider>
124
+ <details>
125
+ <summary>
126
+ 🎨 StylesProvider
127
+ </summary>
108
128
 
109
- Image Upload
129
+ Use **StylesProvider** to add styling to your HTML content.
110
130
 
111
- To work with image uploads, use the fetchUploadImage function, which takes three parameters: file, success, and error. After your images have been successfully uploaded to your service, you need to call the success function and pass two required arguments: the image URL and ID.
112
-
113
- const fetchUploadImage = async (
114
- file: File,
115
- success: (url: string, id: string) => void,
116
- error?: (error?: Error) => void
117
- ) => {
118
- const formData = new FormData();
119
- formData.append('File', file);
120
- formData.append('FileAccessModifier', '0');
121
-
122
- try {
123
- const response = await fetch('/api/v1/Files/Upload', {
124
- method: 'POST',
125
- body: formData,
126
- credentials: 'include'
127
- });
128
-
129
- if (!response.ok) {
130
- throw new Error('File upload failed');
131
- }
132
-
133
- const data = await response.json();
134
- const { Id, Url } = data;
131
+ ```
132
+ <StylesProvider>
133
+ <div
134
+ dangerouslySetInnerHTML={{ __html: '<p>Your html here</p>' }}
135
+ />
136
+ </StylesProvider>
137
+ ```
138
+
139
+ </details>
140
+
141
+ <details>
142
+ <summary>
143
+ 🖼️ Image upload
144
+ </summary>
145
+
146
+ ## Image upload
147
+
148
+ To start working with image uploads, use the **fetchUploadImage** function, which takes three parameters: **file**, **success**, and **error**. After successfully uploading the image to your service, you should call the **success** function and pass two required arguments: the **URL** of the image and its **ID**.
149
+
150
+ ```
151
+ const fetchUploadImage = async (
152
+ file: File,
153
+ success: (url: string, id: string) => void,
154
+ error?: (error?: Error) => void
155
+ ) => {
156
+ const formData = new FormData();
157
+ formData.append('File', file);
158
+ formData.append('FileAccessModifier', '0');
159
+
160
+ try {
161
+ const response = await fetch('/api/v1/Files/Upload', {
162
+ method: 'POST',
163
+ body: formData,
164
+ credentials: 'include'
165
+ });
166
+
167
+ if (!response.ok) {
168
+ throw new Error('File upload failed');
169
+ }
135
170
 
136
- success(Url, Id);
137
- } catch (err) {
138
- if (error) {
139
- if (err instanceof Error) {
140
- error(err);
141
- } else {
142
- error(new Error('An unknown error occurred'));
171
+ const data = await response.json();
172
+ const { Id, Url } = data;
173
+
174
+ success(Url, Id);
175
+ } catch (err) {
176
+ if (error) {
177
+ if (err instanceof Error) {
178
+ error(err);
179
+ } else {
180
+ error(new Error('An unknown error occurred'));
181
+ }
143
182
  }
144
183
  }
145
- }
146
- };
184
+ };
147
185
 
148
186
  <Editor
149
- {...props}
187
+ ...props
150
188
  fetchUploadImage={fetchUploadImage}
151
189
  />
152
-
153
- Image Deletion
154
-
155
- For greater control over image deletion, pass an optional fetchDeleteImage function to the editor. It takes three parameters: id, success, and error. After the image is successfully removed from your service, call the success function.
156
-
157
- const fetchDeleteImage = async (
158
- id: string,
159
- success: () => void,
160
- error?: (error?: Error) => void
161
- ) => {
162
- const body = { Ids: [id] };
163
-
164
- try {
165
- const response = await fetch('/api/v1/Documents/Delete', {
166
- method: 'POST',
167
- headers: {
168
- 'Content-Type': 'application/json'
169
- },
170
- body: JSON.stringify(body),
171
- credentials: 'include'
172
- });
173
-
174
- await response.json();
175
- success();
176
- } catch (err) {
177
- if (error) {
178
- if (err instanceof Error) {
179
- error(err);
180
- } else {
181
- error(new Error('An unknown error occurred'));
190
+ ```
191
+
192
+ ## Image Deletion
193
+
194
+ To have greater control over image deletion, pass an optional function **fetchDeleteImage** to the editor, which accepts three parameters: **id**, **success**, and **error**. After successfully deleting the image from your service, the **success** function should be called.
195
+
196
+ ```
197
+ const fetchDeleteImage = async (
198
+ id: string,
199
+ success: () => void,
200
+ error?: (error?: Error) => void
201
+ ) => {
202
+ const body = { Ids: [id] };
203
+
204
+ try {
205
+ const response = await fetch('/api/v1/Documents/Delete', {
206
+ method: 'POST',
207
+ headers: {
208
+ 'Content-Type': 'application/json'
209
+ },
210
+ body: JSON.stringify(body),
211
+ credentials: 'include'
212
+ });
213
+
214
+ await response.json();
215
+ success();
216
+ } catch (err) {
217
+ if (error) {
218
+ if (err instanceof Error) {
219
+ error(err);
220
+ } else {
221
+ error(new Error('An unknown error occurred'));
222
+ }
182
223
  }
183
224
  }
184
- }
185
- };
225
+ };
186
226
 
187
227
  <Editor
188
- {...props}
189
- fetchUploadImage={fetchUploadImage}
190
- fetchDeleteImage={fetchDeleteImage}
228
+ ...props
229
+ fetchUploadImage={fetchUploadImage}
230
+ fetchDeleteImage={fetchUploadImage}
191
231
  />
232
+ ```
192
233
 
193
- Additional Options for Image Upload
234
+ ## Additional options for working with image uploads.
194
235
 
195
- import { Editor, Dropzone } from "@layers-app/editor";
236
+ ```
237
+ import { Editor, Dropzone } from "@sinups/editor-dsd";
196
238
 
197
239
  const Content = () => (
198
- <Group justify="center" gap="xl" mih={220} style={{ pointerEvents: 'none' }}>
199
- {/*
200
- Dropzone.Accept, Dropzone.Reject, and Dropzone.Idle components are only visible
201
- when the user performs a specific action:
202
-
203
- Dropzone.Accept is displayed only when a file that can be accepted is dragged over the dropzone.
204
- Dropzone.Reject is displayed only when a file that cannot be accepted is dragged over the dropzone.
205
- Dropzone.Idle is visible when the user is not dragging anything over the dropzone.
206
- */}
207
- <Dropzone.Accept>
208
- <IconUpload
209
- style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-blue-6)' }}
210
- stroke={1.5}
211
- />
212
- </Dropzone.Accept>
213
- <Dropzone.Reject>
214
- <IconX
215
- style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-red-6)' }}
216
- stroke={1.5}
217
- />
218
- </Dropzone.Reject>
219
- <Dropzone.Idle>
220
- <IconPhoto
221
- style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-dimmed)' }}
222
- stroke={1.5}
223
- />
224
- </Dropzone.Idle>
225
-
226
- <div>
227
- <Text size="xl" inline>
228
- Drag images here or click to select files
229
- </Text>
230
- <Text size="sm" c="dimmed" inline mt={7}>
231
- Attach as many files as you like. Each file must not exceed {' '}
232
- {maxImageSize} MB.
233
- </Text>
234
- </div>
235
- </Group>
236
- );
240
+ <Group justify="center" gap="xl" mih={220} style={{ pointerEvents: 'none' }}>
241
+ {/*
242
+ The components Dropzone.Accept, Dropzone.Reject, and Dropzone.Idle are visible only when the user performs specific actions:
243
+
244
+ Dropzone.Accept is visible only when the user drags a file that can be accepted into the drop zone.
245
+ Dropzone.Reject is visible only when the user drags a file that cannot be accepted into the drop zone.
246
+ Dropzone.Idle is visible when the user is not dragging any file into the drop zone.
247
+ */}
248
+ <Dropzone.Accept>
249
+ <IconUpload
250
+ style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-blue-6)' }}
251
+ stroke={1.5}
252
+ />
253
+ </Dropzone.Accept>
254
+ <Dropzone.Reject>
255
+ <IconX
256
+ style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-red-6)' }}
257
+ stroke={1.5}
258
+ />
259
+ </Dropzone.Reject>
260
+ <Dropzone.Idle>
261
+ <IconPhoto
262
+ style={{ width: rem(52), height: rem(52), color: 'var(--mantine-color-dimmed)' }}
263
+ stroke={1.5}
264
+ />
265
+ </Dropzone.Idle>
266
+
267
+ <div>
268
+ <Text size="xl" inline>
269
+ Drag images here or click to select files
270
+ </Text>
271
+ <Text size="sm" c="dimmed" inline mt={7}>
272
+ Attach as many files as you want, each file must not exceed{' '} {maxImageSize} МБ.
273
+ </Text>
274
+ </div>
275
+ </Group>
276
+ );
237
277
 
238
278
  <Editor
239
- {...props}
240
- fetchUploadImage={fetchUploadImage}
241
- contentModalUploadImage={Content}
242
- maxImageSize={5}
243
- maxImageSizeError={() => {}}
279
+ ...props
280
+ fetchUploadImage={fetchUploadImage}
281
+ contentModalUploadImage={Content}
282
+ maxImageSize={5}
283
+ maxImageSizeError={() => {}}
244
284
  />
285
+ ```
245
286
 
246
- Collaboration
287
+ </details>
247
288
 
289
+ <details>
290
+ <summary>
291
+ 👥 Collaboration
292
+ </summary>
293
+
294
+ ```jsx
248
295
  <Editor
249
296
  {...props}
250
297
  ws={{
251
- url: 'https://wss.dudoc.io/', // Websocket URL
298
+ url: 'https://wss.dudoc.io/', // WebSocket URL
252
299
  id: '322323', // Unique document ID
253
300
  user: userProfile, // Current user
254
301
  getActiveUsers: (users) => {
255
- // Returns the users actively editing the document
302
+ // Returns active users editing the document
256
303
  setActiveUsers(users);
257
- }
304
+ },
258
305
  }}
259
306
  />
307
+ ```
260
308
 
261
- Reset Editor Content
309
+ </details>
262
310
 
263
- import { CLEAR_EDITOR_COMMAND } from './EditorLexical';
311
+ <details>
312
+ <summary>
313
+ 📝 Additional options
314
+ </summary>
315
+
316
+ ## Reset editor content
317
+
318
+ ```
319
+
320
+ import { CLEAR_EDITOR_COMMAND } from './EditorLexical';
264
321
 
265
322
  <>
266
- <button
267
- onClick={() => {
268
- if (editorRef.current) {
269
- editorRef.current.update(() => {
270
- editorRef.current?.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined);
271
- });
272
- }
273
- }}
274
- >
275
- Reset
276
- </button>
277
- <Editor
278
- {...props}
279
- editorRef={editorRef}
280
- />
281
- </>
282
-
283
- Properties
284
-
285
- onChange: (value: string | object) => void
286
- // Fires whenever the editor changes, returning an HTML string or an object, depending on outputFormat.
287
-
288
- debounce?: number
289
- // Controls how often the onChange function is called, in milliseconds.
290
-
291
- onBlur: (value: string | object) => void
292
- // Fires when the editor loses focus, returning an HTML string or an object, depending on outputFormat.
293
-
294
- outputFormat?: 'html' | 'json'
295
- // Determines if onChange returns HTML or JSON. Default is JSON.
296
-
297
- initialContent: string | object
298
- // The initial data for the editor.
299
-
300
- maxHeight?: number
301
- // Sets the height of the editor. Default is 100%.
302
-
303
- mode?: 'simple' | 'default' | 'full' | 'editor'
304
- // The editor mode, which can restrict or add functionality. Default is 'default'.
305
-
306
- fetchUploadImage?: (
307
- file: File,
308
- success: (url: string, id: string),
309
- error?: (error?: Error) => void
310
- ) => void
311
- // Function to upload images to your service.
312
-
313
- fetchDeleteImage?: (
314
- id: string,
315
- success: () => void,
316
- error?: (error?: Error) => void
317
- ) => void
318
- // Helper function to delete images.
319
-
320
- maxImageSize?: number
321
- // Maximum image size in MB.
322
-
323
- contentModalUploadImage?: React.FunctionComponent
324
- // React component to replace the DropZone content.
325
-
326
- maxImageSizeError?: () => void
327
- // Function called when the image exceeds maxImageSize.
328
-
329
- disable?: boolean
330
- // Toggles read-only mode.
331
-
332
- ws?: {
333
- url: string, // Websocket URL
334
- id: string, // Unique document ID
335
- user: { color: string; name: string }, // Current user
336
- getActiveUsers: (users) => void // Returns the users actively editing the document
337
- }
338
-
339
- editorRef?: { current: EditorType | null }
340
- // Reference to the editor.
323
+ <button
324
+ onClick={() => {
325
+ if (editorRef.current) {
326
+ editorRef.current.update(() => {
327
+ editorRef.current?.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined);
328
+ });
329
+ }
330
+ }}
331
+ >
332
+ Reset
333
+ </button>
334
+ <Editor
335
+ ...props
336
+ editorRef={editorRef}
337
+ />
338
+ <>
339
+ ```
340
+
341
+ </details>
342
+ <details>
343
+ <summary>
344
+ ⚙️ Properties
345
+ </summary>
346
+
347
+ ```
348
+ onChange: (value: string | object) => undefined - A function that triggers every time the editor content changes and returns an HTML string or an object depending on the outputFormat property.
349
+ debounce?: number - Defines how often the onChange function is called, in milliseconds.
350
+ onBlur: (value: string | object) => undefined - A function that triggers when the editor loses focus and returns an HTML string or an object depending on the outputFormat property.
351
+ outputFormat?: 'html' | 'json' - The outputFormat property defines whether we want to output an HTML string or a JSON object. The default is JSON.
352
+ initialContent: string | object - The initial content for the editor.
353
+ maxHeight?: number - Sets the height of the editor. The default is 100%.
354
+ mode?: 'simple' | 'default' | 'full' | 'editor' - The editor mode. Depending on the chosen mode, functionality may be restricted or extended. The default is default.
355
+ fetchUploadImage?: (file: File, success: (url: string, id: string, error?: (error?: Error) => void) => void) - Function to upload an image to your service.
356
+ fetchDeleteImage?: (id: string, success: () => void, error?: (error?: Error) => void) - Helper function to delete an image.
357
+ maxImageSize?: number - The maximum image size in megabytes.
358
+ contentModalUploadImage?: React.FunctionComponent - A React component to replace content in DropZone.
359
+ maxImageSizeError?: () => void - A function that is called if the image exceeds the maxImageSize.
360
+ disable?: boolean - Toggles the editor into read-only mode.
361
+ ws?: { url: string, id: string, user: { color: string, name: string }, getActiveUsers: (users) => void } - WebSocket settings: URL, document ID, current user details, and function to return active users editing the document.
362
+ editorRef?: { current: EditorType | null } - Reference to the editor.
363
+ ```
364
+
365
+ </details>
@@ -1,6 +1,6 @@
1
1
  import { jsx as o, jsxs as C } from "react/jsx-runtime";
2
2
  import { useMemo as I, useState as D, useRef as S, useCallback as $, useEffect as R } from "react";
3
- import { b as V, a as j, w as P, R as x, C as k, l as b, N as E, k as w, K as v, e as B, r as y, B as A, m as T, n as W } from "./DSD.BSMoqlgJ.js";
3
+ import { b as V, a as j, w as P, R as x, C as k, l as b, N as E, k as w, K as v, e as B, r as y, B as A, m as T, n as W } from "./DSD.NL0fFbop.js";
4
4
  function O(...t) {
5
5
  return t.filter(Boolean).join(" ");
6
6
  }
@@ -115,8 +115,16 @@ function z({
115
115
  },
116
116
  v
117
117
  ),
118
- a.registerCommand(B, h, v),
119
- a.registerCommand(w, h, v)
118
+ a.registerCommand(
119
+ B,
120
+ h,
121
+ v
122
+ ),
123
+ a.registerCommand(
124
+ w,
125
+ h,
126
+ v
127
+ )
120
128
  ), [m, a, r, n, h, _]);
121
129
  const d = (e, l) => {
122
130
  a.update(
@@ -131,24 +139,31 @@ function z({
131
139
  e.addOption(W());
132
140
  });
133
141
  }, N = P(g) && r;
134
- return /* @__PURE__ */ o("div", { className: `PollNode__container ${N ? "focused" : ""}`, ref: i, children: /* @__PURE__ */ C("div", { className: "PollNode__inner", children: [
135
- /* @__PURE__ */ o("h2", { className: "PollNode__heading", children: t }),
136
- c.map((e, l) => {
137
- const s = e.uid;
138
- return /* @__PURE__ */ o(
139
- L,
140
- {
141
- withPollNode: d,
142
- option: e,
143
- index: l,
144
- options: c,
145
- totalVotes: p
146
- },
147
- s
148
- );
149
- }),
150
- /* @__PURE__ */ o("div", { className: "PollNode__footer", children: /* @__PURE__ */ o(A, { onClick: u, small: !0, children: "Add Option" }) })
151
- ] }) });
142
+ return /* @__PURE__ */ o(
143
+ "div",
144
+ {
145
+ className: `PollNode__container ${N ? "focused" : ""}`,
146
+ ref: i,
147
+ children: /* @__PURE__ */ C("div", { className: "PollNode__inner", children: [
148
+ /* @__PURE__ */ o("h2", { className: "PollNode__heading", children: t }),
149
+ c.map((e, l) => {
150
+ const s = e.uid;
151
+ return /* @__PURE__ */ o(
152
+ L,
153
+ {
154
+ withPollNode: d,
155
+ option: e,
156
+ index: l,
157
+ options: c,
158
+ totalVotes: p
159
+ },
160
+ s
161
+ );
162
+ }),
163
+ /* @__PURE__ */ o("div", { className: "PollNode__footer", children: /* @__PURE__ */ o(A, { onClick: u, small: !0, children: "Add Option" }) })
164
+ ] })
165
+ }
166
+ );
152
167
  }
153
168
  export {
154
169
  z as default