@lesjoursfr/edith 2.1.0 → 2.1.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 (58) hide show
  1. package/build/edith.css +1 -0
  2. package/build/edith.js +1 -0
  3. package/dist/core/dom.d.ts +224 -0
  4. package/dist/core/dom.js +480 -0
  5. package/dist/core/edit.d.ts +36 -0
  6. package/dist/core/edit.js +255 -0
  7. package/dist/core/events.d.ts +47 -0
  8. package/dist/core/events.js +100 -0
  9. package/dist/core/history.d.ts +14 -0
  10. package/dist/core/history.js +24 -0
  11. package/dist/core/index.d.ts +7 -0
  12. package/dist/core/index.js +7 -0
  13. package/dist/core/mode.d.ts +4 -0
  14. package/dist/core/mode.js +5 -0
  15. package/dist/core/range.d.ts +45 -0
  16. package/dist/core/range.js +86 -0
  17. package/dist/core/throttle.d.ts +53 -0
  18. package/dist/core/throttle.js +139 -0
  19. package/dist/edith-options.d.ts +17 -0
  20. package/dist/edith-options.js +56 -0
  21. package/dist/edith.d.ts +30 -0
  22. package/dist/edith.js +76 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.js +1 -0
  25. package/dist/ui/button.d.ts +25 -0
  26. package/dist/ui/button.js +165 -0
  27. package/dist/ui/editor.d.ts +37 -0
  28. package/dist/ui/editor.js +322 -0
  29. package/dist/ui/index.d.ts +3 -0
  30. package/dist/ui/index.js +3 -0
  31. package/dist/ui/modal.d.ts +32 -0
  32. package/dist/ui/modal.js +145 -0
  33. package/package.json +49 -32
  34. package/src/core/dom.ts +584 -0
  35. package/src/core/{edit.js → edit.ts} +59 -40
  36. package/src/core/events.ts +148 -0
  37. package/src/core/history.ts +28 -0
  38. package/src/core/index.ts +7 -0
  39. package/src/core/mode.ts +4 -0
  40. package/src/core/{range.js → range.ts} +32 -22
  41. package/src/core/{throttle.js → throttle.ts} +37 -23
  42. package/src/css/edith.scss +283 -0
  43. package/src/edith-options.ts +75 -0
  44. package/src/edith.ts +98 -0
  45. package/src/index.ts +1 -0
  46. package/src/ui/button.ts +197 -0
  47. package/src/ui/editor.ts +403 -0
  48. package/src/ui/index.ts +3 -0
  49. package/src/ui/modal.ts +180 -0
  50. package/src/core/dom.js +0 -353
  51. package/src/core/event.js +0 -4
  52. package/src/core/history.js +0 -27
  53. package/src/core/mode.js +0 -4
  54. package/src/index.js +0 -90
  55. package/src/ui/button.js +0 -200
  56. package/src/ui/editor.js +0 -392
  57. package/src/ui/modal.js +0 -151
  58. /package/{src/css/main.scss → dist/css/edith.scss} +0 -0
@@ -0,0 +1,322 @@
1
+ import { html } from "@codemirror/lang-html";
2
+ import { EditorView, basicSetup } from "codemirror";
3
+ import { EditorModes, Events, History, cleanPastedHtml, clearSelectionStyle, createNodeWith, getSelection, hasClass, hasTagName, isHTMLElement, isSelectionInsideNode, isSelfClosing, removeNodesRecursively, replaceSelectionByHtml, restoreSelection, throttle, unwrapNode, wrapInsideLink, wrapInsideTag, } from "../core/index.js";
4
+ import { EdithModal, createCheckboxModalField, createInputModalField } from "./modal.js";
5
+ export class EdithEditor {
6
+ el;
7
+ ctx;
8
+ content;
9
+ height;
10
+ resizable;
11
+ mode;
12
+ visualEditor;
13
+ codeEditor;
14
+ codeMirror;
15
+ history;
16
+ throttledSnapshots;
17
+ constructor(ctx, options) {
18
+ this.ctx = ctx;
19
+ this.content = options.initialContent;
20
+ this.height = options.height;
21
+ this.resizable = options.resizable;
22
+ this.mode = EditorModes.Visual;
23
+ this.history = new History();
24
+ this.throttledSnapshots = throttle(() => this.takeSnapshot(), 3000, { leading: false, trailing: true });
25
+ // Replace   by the string we use as a visual return
26
+ this.content = this.content.replace(/&nbsp;/g, '<span class="edith-nbsp" contenteditable="false">¶</span>');
27
+ }
28
+ render() {
29
+ // Create a wrapper for the editor
30
+ this.el = createNodeWith("div", {
31
+ attributes: {
32
+ class: "edith-editing-area",
33
+ style: this.resizable ? `min-height: ${this.height}px; resize: vertical` : `height: ${this.height}px`,
34
+ },
35
+ });
36
+ // Create the visual editor
37
+ this.visualEditor = createNodeWith("div", {
38
+ innerHTML: this.content,
39
+ attributes: {
40
+ class: "edith-visual",
41
+ contenteditable: "true",
42
+ style: this.resizable ? `min-height: ${this.height - 10}px` : `height: ${this.height - 10}px`,
43
+ },
44
+ });
45
+ this.el.append(this.visualEditor);
46
+ // Create the code editor
47
+ this.codeEditor = createNodeWith("div", {
48
+ attributes: { class: "edith-code edith-hidden" },
49
+ });
50
+ this.el.append(this.codeEditor);
51
+ // Bind events
52
+ const keyEventsListener = this.onKeyEvent.bind(this);
53
+ this.visualEditor.addEventListener("keydown", keyEventsListener);
54
+ this.visualEditor.addEventListener("keyup", keyEventsListener);
55
+ const pasteEventListener = this.onPasteEvent.bind(this);
56
+ this.visualEditor.addEventListener("paste", pasteEventListener);
57
+ // Return the wrapper
58
+ return this.el;
59
+ }
60
+ getVisualEditorElement() {
61
+ return this.visualEditor;
62
+ }
63
+ getCodeEditorElement() {
64
+ return this.codeEditor;
65
+ }
66
+ setContent(content) {
67
+ // Replace &nbsp; by the string we use as a visual return
68
+ content = content.replace(/&nbsp;/g, '<span class="edith-nbsp" contenteditable="false">¶</span>');
69
+ // Check the current mode
70
+ if (this.mode === EditorModes.Visual) {
71
+ // Update the visual editor content
72
+ this.visualEditor.innerHTML = content;
73
+ }
74
+ else {
75
+ // Update the code editor content
76
+ this.codeMirror.dispatch({
77
+ changes: { from: 0, to: this.codeMirror.state.doc.length, insert: content },
78
+ });
79
+ }
80
+ }
81
+ getContent() {
82
+ // Get the visual editor content or the code editor content
83
+ const code = this.mode === EditorModes.Visual
84
+ ? this.visualEditor.innerHTML
85
+ : this.codeMirror.state.doc.toJSON()
86
+ .map((line) => line.trim())
87
+ .join("\n");
88
+ // Check if there is something in the editor
89
+ if (code === "<p><br></p>") {
90
+ return "";
91
+ }
92
+ // Remove empty tags
93
+ const placeholder = createNodeWith("div", { innerHTML: code });
94
+ removeNodesRecursively(placeholder, (el) => {
95
+ return (isHTMLElement(el) && !isSelfClosing(el.tagName) && (el.textContent === null || el.textContent.length === 0));
96
+ });
97
+ // Remove any style attribute
98
+ for (const el of placeholder.querySelectorAll("[style]")) {
99
+ el.removeAttribute("style");
100
+ }
101
+ // Unwrap span without attributes
102
+ for (const el of placeholder.querySelectorAll("span")) {
103
+ if (el.attributes.length === 0) {
104
+ unwrapNode(el);
105
+ }
106
+ }
107
+ // Return clean code
108
+ return placeholder.innerHTML
109
+ .replace(/\u200B/gi, "")
110
+ .replace(/<\/p>\s*<p>/gi, "<br>")
111
+ .replace(/(<p>|<\/p>)/gi, "")
112
+ .replace(/<span[^>]+class="edith-nbsp"[^>]*>[^<]*<\/span>/gi, "&nbsp;")
113
+ .replace(/(?:<br\s?\/?>)+$/gi, "");
114
+ }
115
+ takeSnapshot() {
116
+ this.history.push(this.visualEditor.innerHTML);
117
+ }
118
+ restoreSnapshot() {
119
+ this.visualEditor.innerHTML = this.history.pop() ?? "";
120
+ }
121
+ wrapInsideTag(tag) {
122
+ if (isSelectionInsideNode(this.visualEditor)) {
123
+ wrapInsideTag(tag);
124
+ this.takeSnapshot();
125
+ }
126
+ }
127
+ replaceByHtml(html) {
128
+ if (isSelectionInsideNode(this.visualEditor)) {
129
+ replaceSelectionByHtml(html);
130
+ this.takeSnapshot();
131
+ }
132
+ }
133
+ clearStyle() {
134
+ clearSelectionStyle();
135
+ this.takeSnapshot();
136
+ }
137
+ insertLink() {
138
+ // Get the caret position
139
+ const { sel, range } = getSelection();
140
+ // Check if the user has selected something
141
+ if (range === undefined) {
142
+ return;
143
+ }
144
+ // Show the modal
145
+ const modal = new EdithModal(this.ctx, {
146
+ title: "Insérer un lien",
147
+ fields: [
148
+ createInputModalField("Texte à afficher", "text", range.toString()),
149
+ createInputModalField("URL du lien", "href"),
150
+ createCheckboxModalField("Ouvrir dans une nouvelle fenêtre", "openInNewTab", true),
151
+ ],
152
+ callback: (data) => {
153
+ // Check if we have something
154
+ if (data === null) {
155
+ // Nothing to do
156
+ return;
157
+ }
158
+ // Restore the selection
159
+ restoreSelection({ sel, range });
160
+ // Insert a link
161
+ wrapInsideLink(data.text, data.href, data.openInNewTab);
162
+ },
163
+ });
164
+ modal.show();
165
+ }
166
+ toggleCodeView() {
167
+ // Check the current mode
168
+ if (this.mode === EditorModes.Visual) {
169
+ // Switch mode
170
+ this.mode = EditorModes.Code;
171
+ // Hide the visual editor
172
+ this.visualEditor.classList.add("edith-hidden");
173
+ // Display the code editor
174
+ this.codeEditor.classList.remove("edith-hidden");
175
+ const codeMirrorEl = document.createElement("div");
176
+ this.codeEditor.append(codeMirrorEl);
177
+ this.codeMirror = new EditorView({
178
+ doc: this.visualEditor.innerHTML,
179
+ extensions: [basicSetup, EditorView.lineWrapping, html({ matchClosingTags: true, autoCloseTags: true })],
180
+ parent: codeMirrorEl,
181
+ });
182
+ }
183
+ else {
184
+ // Switch mode
185
+ this.mode = EditorModes.Visual;
186
+ // Hide the code editor
187
+ this.codeEditor.classList.add("edith-hidden");
188
+ // Display the visual editor
189
+ this.visualEditor.classList.remove("edith-hidden");
190
+ this.visualEditor.innerHTML = this.codeMirror.state.doc.toJSON()
191
+ .map((line) => line.trim())
192
+ .join("\n");
193
+ this.codeMirror.destroy();
194
+ this.codeMirror = undefined;
195
+ this.codeEditor.innerHTML = "";
196
+ }
197
+ // Trigger an event with the new mode
198
+ this.ctx.trigger(Events.modeChanged, { mode: this.mode });
199
+ }
200
+ onKeyEvent(e) {
201
+ // Check if a Meta key is pressed
202
+ const prevent = e.metaKey || e.ctrlKey ? this._processKeyEventWithMeta(e) : this._processKeyEvent(e);
203
+ // Check if we must stop the event here
204
+ if (prevent) {
205
+ e.preventDefault();
206
+ e.stopPropagation();
207
+ }
208
+ }
209
+ _processKeyEvent(e) {
210
+ // Check the key code
211
+ switch (e.keyCode) {
212
+ case 13: // Enter : 13
213
+ if (e.type === "keydown") {
214
+ this.replaceByHtml("<br />"); // Insert a line break
215
+ }
216
+ return true;
217
+ }
218
+ // Save the editor content
219
+ this.throttledSnapshots();
220
+ // Return false
221
+ return false;
222
+ }
223
+ _processKeyEventWithMeta(e) {
224
+ // Check the key code
225
+ switch (e.keyCode) {
226
+ case 13: // Enter : 13
227
+ if (e.type === "keydown") {
228
+ this.replaceByHtml("<br />"); // Insert a line break
229
+ }
230
+ return true;
231
+ case 32: // Space : 32
232
+ if (e.type === "keydown") {
233
+ this.replaceByHtml('<span class="edith-nbsp" contenteditable="false">¶</span>'); // Insert a non-breaking space
234
+ }
235
+ return true;
236
+ case 66: // b : 66
237
+ if (e.type === "keydown") {
238
+ this.wrapInsideTag("b"); // Toggle bold
239
+ }
240
+ return true;
241
+ case 73: // i : 73
242
+ if (e.type === "keydown") {
243
+ this.wrapInsideTag("i"); // Toggle italic
244
+ }
245
+ return true;
246
+ case 85: // u : 85
247
+ if (e.type === "keydown") {
248
+ this.wrapInsideTag("u"); // Toggle underline
249
+ }
250
+ return true;
251
+ case 83: // s : 83
252
+ if (e.type === "keydown") {
253
+ this.wrapInsideTag("s"); // Toggle strikethrough
254
+ }
255
+ return true;
256
+ case 90: // z : 90
257
+ if (e.type === "keydown") {
258
+ this.restoreSnapshot(); // Undo
259
+ }
260
+ return true;
261
+ }
262
+ // Return false
263
+ return false;
264
+ }
265
+ onPasteEvent(e) {
266
+ // Prevent default
267
+ e.preventDefault();
268
+ e.stopPropagation();
269
+ // Get the caret position
270
+ const { sel, range } = getSelection();
271
+ // Check if the user has selected something
272
+ if (range === undefined || e.clipboardData === null) {
273
+ return;
274
+ }
275
+ // Create the fragment to insert
276
+ const frag = document.createDocumentFragment();
277
+ // Check if we try to paste HTML content
278
+ if (!e.clipboardData.types.includes("text/html")) {
279
+ // Get the content as a plain text & split it by lines
280
+ const lines = e.clipboardData.getData("text/plain").split(/[\r\n]+/g);
281
+ // Add the content as text nodes with a <br> node between each line
282
+ for (let i = 0; i < lines.length; i++) {
283
+ if (i !== 0) {
284
+ frag.append(document.createElement("br"));
285
+ }
286
+ frag.append(document.createTextNode(lines[i]));
287
+ }
288
+ }
289
+ else {
290
+ // Detect style blocs in parents
291
+ let dest = sel.anchorNode;
292
+ const style = { B: false, I: false, U: false, S: false, Q: false };
293
+ while (dest !== null && !hasClass(dest, "edith-visual")) {
294
+ // Check if it's a style tag
295
+ if (hasTagName(dest, ["b", "i", "u", "s", "q"])) {
296
+ // Update the style
297
+ style[(dest.tagName, "I", "U", "S", "Q")] = true;
298
+ }
299
+ // Get the parent
300
+ dest = dest.parentNode;
301
+ }
302
+ // We have HTML content
303
+ let html = e.clipboardData.getData("text/html").replace(/[\r\n]+/g, " ");
304
+ // Wrap the HTML content into <html><body></body></html>
305
+ if (!/^<html>\s*<body>/.test(html)) {
306
+ html = "<html><body>" + html + "</body></html>";
307
+ }
308
+ // Clean the content
309
+ const contents = cleanPastedHtml(html, style);
310
+ // Add the content to the frgament
311
+ frag.append(...contents.childNodes);
312
+ }
313
+ // Replace the current selection by the pasted content
314
+ sel.deleteFromDocument();
315
+ range.insertNode(frag);
316
+ }
317
+ destroy() {
318
+ this.codeMirror?.destroy();
319
+ this.codeMirror = undefined;
320
+ this.el.remove();
321
+ }
322
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./button.js";
2
+ export * from "./editor.js";
3
+ export * from "./modal.js";
@@ -0,0 +1,3 @@
1
+ export * from "./button.js";
2
+ export * from "./editor.js";
3
+ export * from "./modal.js";
@@ -0,0 +1,32 @@
1
+ import { Edith } from "../edith.js";
2
+ export declare enum EdithModalFieldType {
3
+ input = 1,
4
+ checkbox = 2
5
+ }
6
+ export type EdithModalField = {
7
+ fieldType: EdithModalFieldType;
8
+ label: string;
9
+ name: string;
10
+ initialState: string | boolean | null;
11
+ };
12
+ export declare function createInputModalField(label: string, name: string, initialState?: string | null): EdithModalField;
13
+ export declare function createCheckboxModalField(label: string, name: string, initialState?: boolean): EdithModalField;
14
+ export type EdithModalCallback = (payload: {
15
+ [keyof: string]: string | boolean;
16
+ } | null) => void;
17
+ export declare class EdithModal {
18
+ private el;
19
+ private ctx;
20
+ private title;
21
+ private fields;
22
+ private callback;
23
+ constructor(ctx: Edith, options: {
24
+ title: string;
25
+ fields?: EdithModalField[];
26
+ callback: EdithModalCallback;
27
+ });
28
+ cancel(event: Event): void;
29
+ submit(event: Event): void;
30
+ close(): void;
31
+ show(): HTMLDivElement;
32
+ }
@@ -0,0 +1,145 @@
1
+ import { createNodeWith, getAttribute, hasAttribute } from "../core/index.js";
2
+ export var EdithModalFieldType;
3
+ (function (EdithModalFieldType) {
4
+ EdithModalFieldType[EdithModalFieldType["input"] = 1] = "input";
5
+ EdithModalFieldType[EdithModalFieldType["checkbox"] = 2] = "checkbox";
6
+ })(EdithModalFieldType || (EdithModalFieldType = {}));
7
+ function renderInputModalField(field) {
8
+ const el = document.createElement("div");
9
+ el.setAttribute("class", "edith-modal-input");
10
+ const label = document.createElement("label");
11
+ label.textContent = field.label;
12
+ const input = document.createElement("input");
13
+ input.setAttribute("name", field.name);
14
+ input.setAttribute("type", "text");
15
+ if (field.initialState !== null) {
16
+ input.value = field.initialState.toString();
17
+ }
18
+ el.append(label);
19
+ el.append(input);
20
+ return el;
21
+ }
22
+ function renderCheckboxModalField(field) {
23
+ const el = document.createElement("div");
24
+ el.setAttribute("class", "edith-modal-checkbox");
25
+ const label = document.createElement("label");
26
+ label.textContent = field.label;
27
+ const input = document.createElement("input");
28
+ input.setAttribute("name", field.name);
29
+ input.setAttribute("type", "checkbox");
30
+ if (field.initialState) {
31
+ input.checked = true;
32
+ }
33
+ label.prepend(input);
34
+ el.append(label);
35
+ return el;
36
+ }
37
+ export function createInputModalField(label, name, initialState = null) {
38
+ return {
39
+ fieldType: EdithModalFieldType.input,
40
+ label,
41
+ name,
42
+ initialState,
43
+ };
44
+ }
45
+ export function createCheckboxModalField(label, name, initialState = false) {
46
+ return {
47
+ fieldType: EdithModalFieldType.checkbox,
48
+ label,
49
+ name,
50
+ initialState,
51
+ };
52
+ }
53
+ export class EdithModal {
54
+ el;
55
+ ctx;
56
+ title;
57
+ fields;
58
+ callback;
59
+ constructor(ctx, options) {
60
+ this.ctx = ctx;
61
+ this.title = options.title;
62
+ this.fields = options.fields || [];
63
+ this.callback = options.callback;
64
+ }
65
+ cancel(event) {
66
+ event.preventDefault();
67
+ // Call the callback with a null value
68
+ this.callback(null);
69
+ // Close the modal
70
+ this.close();
71
+ }
72
+ submit(event) {
73
+ event.preventDefault();
74
+ // Call the callback with the input & checkboxes values
75
+ const payload = {};
76
+ for (const el of this.el.querySelectorAll("input")) {
77
+ if (hasAttribute(el, "name")) {
78
+ payload[getAttribute(el, "name")] = getAttribute(el, "type") === "checkbox" ? el.checked : el.value;
79
+ }
80
+ }
81
+ this.callback(payload);
82
+ // Close the modal
83
+ this.close();
84
+ }
85
+ close() {
86
+ // Remove the element from the dom
87
+ this.el.remove();
88
+ }
89
+ show() {
90
+ // Create the modal
91
+ this.el = createNodeWith("div", {
92
+ attributes: { class: "edith-modal" },
93
+ });
94
+ // Create the header
95
+ const header = createNodeWith("div", {
96
+ attributes: { class: "edith-modal-header" },
97
+ });
98
+ const title = createNodeWith("span", {
99
+ textContent: this.title,
100
+ attributes: { class: "edith-modal-title" },
101
+ });
102
+ header.append(title);
103
+ // Create the content
104
+ const content = createNodeWith("div", {
105
+ attributes: { class: "edith-modal-content" },
106
+ });
107
+ for (const field of this.fields) {
108
+ switch (field.fieldType) {
109
+ case EdithModalFieldType.input:
110
+ content.append(renderInputModalField(field));
111
+ break;
112
+ case EdithModalFieldType.checkbox:
113
+ content.append(renderCheckboxModalField(field));
114
+ break;
115
+ default:
116
+ throw new Error(`Unknown fieldType ${field.fieldType}`);
117
+ }
118
+ }
119
+ // Create the footer
120
+ const footer = createNodeWith("div", {
121
+ attributes: { class: "edith-modal-footer" },
122
+ });
123
+ const cancel = createNodeWith("button", {
124
+ textContent: "Annuler",
125
+ attributes: { class: "edith-modal-cancel", type: "button" },
126
+ });
127
+ footer.append(cancel);
128
+ const submit = createNodeWith("button", {
129
+ textContent: "Valider",
130
+ attributes: { class: "edith-modal-submit", type: "button" },
131
+ });
132
+ footer.append(submit);
133
+ // Append everything
134
+ this.el.append(header);
135
+ this.el.append(content);
136
+ this.el.append(footer);
137
+ // Add the modal to the editor
138
+ this.ctx.modals.append(this.el);
139
+ // Bind events
140
+ cancel.onclick = this.cancel.bind(this);
141
+ submit.onclick = this.submit.bind(this);
142
+ // Return the modal
143
+ return this.el;
144
+ }
145
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lesjoursfr/edith",
3
- "version": "2.1.0",
3
+ "version": "2.1.3",
4
4
  "description": "Simple WYSIWYG editor.",
5
5
  "license": "MIT",
6
6
  "repository": "lesjoursfr/edith",
@@ -15,64 +15,81 @@
15
15
  "node": "18.x || 20.x"
16
16
  },
17
17
  "browserslist": [
18
- "Chrome >= 60",
19
- "Safari >= 12",
20
- "iOS >= 12",
21
- "Firefox >= 60",
22
- "Edge >= 79"
18
+ "> 1%",
19
+ "last 3 versions",
20
+ "not dead"
23
21
  ],
24
- "main": "src/index.js",
22
+ "main": "./dist/index.js",
23
+ "types": "./dist/index.d.ts",
25
24
  "type": "module",
26
25
  "scripts": {
27
26
  "freshlock": "rm -rf node_modules/ && rm .yarn/install-state.gz && rm -r .yarn/cache/ && rm yarn.lock && yarn",
28
- "eslint-check": "eslint-config-prettier src/index.js",
29
- "check-js": "eslint . --ext .js",
30
- "check-sass": "stylelint **/*.scss",
31
- "check-style": "prettier --check .",
32
- "lint-js": "eslint . --fix --ext .js",
33
- "lint-sass": "stylelint **/*.scss --fix",
34
- "format": "prettier --write .",
35
- "test": "npx mocha",
27
+ "eslint-check": "eslint . --ext .js,.jsx,.ts,.tsx",
28
+ "eslint-fix": "eslint . --fix --ext .js,.jsx,.ts,.tsx",
29
+ "stylelint-check": "stylelint **/*.scss",
30
+ "stylelint-fix": "stylelint **/*.scss --fix",
31
+ "prettier-check": "prettier --check .",
32
+ "prettier-fix": "prettier --write .",
33
+ "test": "NODE_OPTIONS='--loader=ts-node/esm' mocha",
34
+ "build-esm": "tsc && node assets.js",
35
+ "build-browser": "webpack --mode production --config ./server/webpack.config.js --progress",
36
+ "build": "npm run build-esm && npm run build-browser",
36
37
  "builddeps": "webpack --mode production --config server/deps/codemirror.webpack.js --progress",
37
- "server": "webpack serve --mode development --config server/editor.webpack.js --hot --open"
38
+ "server": "webpack serve --mode development --config ./server/webpack.config.js --hot --open"
38
39
  },
39
40
  "files": [
40
- "src/**/*"
41
+ "src/**/*",
42
+ "dist/**/*",
43
+ "build/**/*"
41
44
  ],
42
45
  "keywords": [
43
46
  "WYSIWYG",
44
47
  "editor"
45
48
  ],
46
49
  "devDependencies": {
47
- "@babel/core": "^7.22.11",
48
- "@babel/preset-env": "^7.22.14",
49
- "@codemirror/lang-html": "^6.4.6",
50
- "@fortawesome/fontawesome-free": "^6.4.2",
50
+ "@babel/core": "^7.23.5",
51
+ "@babel/preset-env": "^7.23.5",
52
+ "@codemirror/lang-html": "^6.4.7",
53
+ "@fortawesome/fontawesome-free": "^6.5.1",
51
54
  "@popperjs/core": "^2.11.8",
55
+ "@tsconfig/next": "^2.0.1",
56
+ "@types/babel__core": "^7.20.5",
57
+ "@types/babel__preset-env": "^7.9.6",
58
+ "@types/color": "^3.0.6",
59
+ "@types/jsdom": "^21.1.6",
60
+ "@types/mocha": "^10.0.6",
61
+ "@types/node": "^20.10.1",
62
+ "@typescript-eslint/eslint-plugin": "^6.13.1",
63
+ "@typescript-eslint/parser": "^6.13.1",
52
64
  "babel-loader": "^9.1.3",
53
65
  "codemirror": "^6.0.1",
54
66
  "css-loader": "^6.8.1",
55
- "eslint": "^8.48.0",
67
+ "css-minimizer-webpack-plugin": "^5.0.1",
68
+ "eslint": "^8.54.0",
56
69
  "eslint-config-prettier": "^9.0.0",
57
- "jsdom": "^22.1.0",
70
+ "fs-extra": "^11.2.0",
71
+ "jsdom": "^23.0.1",
58
72
  "mini-css-extract-plugin": "^2.7.6",
59
73
  "mocha": "^10.2.0",
60
- "postcss": "^8.4.29",
61
- "prettier": "^3.0.3",
62
- "sass": "^1.66.1",
74
+ "postcss": "^8.4.31",
75
+ "prettier": "^3.1.0",
76
+ "sass": "^1.69.5",
63
77
  "sass-loader": "^13.3.2",
64
- "style-loader": "^3.3.3",
65
- "stylelint": "^15.10.3",
78
+ "stylelint": "^15.11.0",
66
79
  "stylelint-config-sass-guidelines": "^10.0.0",
67
- "webpack": "^5.88.2",
80
+ "terser-webpack-plugin": "^5.3.9",
81
+ "ts-loader": "^9.5.1",
82
+ "ts-node": "^10.9.1",
83
+ "typescript": "^5.3.2",
84
+ "webpack": "^5.89.0",
68
85
  "webpack-cli": "^5.1.4",
69
86
  "webpack-dev-server": "^4.15.1"
70
87
  },
71
88
  "peerDependencies": {
72
- "@codemirror/lang-html": "^6.4.6",
73
- "@fortawesome/fontawesome-free": "^6.4.2",
89
+ "@codemirror/lang-html": "^6.4.7",
90
+ "@fortawesome/fontawesome-free": "^6.5.1",
74
91
  "@popperjs/core": "^2.11.8",
75
92
  "codemirror": "^6.0.1"
76
93
  },
77
- "packageManager": "yarn@3.6.3"
94
+ "packageManager": "yarn@4.0.2"
78
95
  }