@mdaemon/html-editor 1.0.11 → 1.0.13

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/dist/index.d.ts CHANGED
@@ -369,6 +369,8 @@ export declare interface MDHTMLEditor {
369
369
  getTipTap(): Editor | null;
370
370
  }
371
371
 
372
+ export declare const Mention: Node_2<any, any>;
373
+
372
374
  /**
373
375
  * Reset the global translation function to the default identity function.
374
376
  * This also clears the customized flag so that the next editor created
@@ -471,6 +473,7 @@ export declare class Toolbar {
471
473
  private state;
472
474
  private buttonElements;
473
475
  private dropdowns;
476
+ private bodyMenus;
474
477
  private charMap;
475
478
  private emojiPicker;
476
479
  private imageUpload;
@@ -521,6 +524,7 @@ export declare class Toolbar {
521
524
  private toggleFullscreen;
522
525
  rebuild(): void;
523
526
  destroy(): void;
527
+ private removeBodyMenus;
524
528
  }
525
529
 
526
530
  export declare interface ToolbarButtonAPI {
package/dist/index.js CHANGED
@@ -42788,6 +42788,7 @@ class Toolbar {
42788
42788
  state;
42789
42789
  buttonElements = /* @__PURE__ */ new Map();
42790
42790
  dropdowns = /* @__PURE__ */ new Map();
42791
+ bodyMenus = [];
42791
42792
  charMap = null;
42792
42793
  emojiPicker = null;
42793
42794
  imageUpload = null;
@@ -43160,7 +43161,7 @@ class Toolbar {
43160
43161
  button.title = label;
43161
43162
  button.innerHTML = `
43162
43163
  <span class="md-toolbar-dropdown-label">${label}</span>
43163
- <span class="md-toolbar-dropdown-arrow">▼</span>
43164
+ <span class="md-toolbar-dropdown-arrow"><svg width="8" height="8" viewBox="0 0 8 8" fill="currentColor"><path d="M0 2l4 4 4-4z"/></svg></span>
43164
43165
  `;
43165
43166
  const menu = document.createElement("div");
43166
43167
  menu.className = "md-toolbar-dropdown-menu";
@@ -43192,11 +43193,12 @@ class Toolbar {
43192
43193
  e.stopPropagation();
43193
43194
  this.dropdowns.forEach((dropdown, key) => {
43194
43195
  if (key !== name) {
43195
- dropdown.classList.remove("md-toolbar-dropdown-open");
43196
- const m = dropdown.querySelector(".md-toolbar-dropdown-menu");
43197
- if (m) m.style.display = "none";
43196
+ dropdown.classList.remove("md-toolbar-dropdown-open", "md-toolbar-colorpicker-open");
43198
43197
  }
43199
43198
  });
43199
+ this.bodyMenus.forEach((m) => {
43200
+ if (m !== menu) m.style.display = "none";
43201
+ });
43200
43202
  const isOpen = menu.style.display !== "none";
43201
43203
  menu.style.display = isOpen ? "none" : "block";
43202
43204
  wrapper.classList.toggle("md-toolbar-dropdown-open", !isOpen);
@@ -43212,7 +43214,8 @@ class Toolbar {
43212
43214
  }
43213
43215
  });
43214
43216
  wrapper.appendChild(button);
43215
- wrapper.appendChild(menu);
43217
+ document.body.appendChild(menu);
43218
+ this.bodyMenus.push(menu);
43216
43219
  this.dropdowns.set(name, wrapper);
43217
43220
  return wrapper;
43218
43221
  }
@@ -43227,7 +43230,7 @@ class Toolbar {
43227
43230
  button.innerHTML = `
43228
43231
  <span class="md-toolbar-colorpicker-icon md-icon-${name}">A</span>
43229
43232
  <span class="md-toolbar-colorpicker-preview" style="background-color: ${name === "forecolor" ? "#000" : "#ff0"}"></span>
43230
- <span class="md-toolbar-dropdown-arrow">▼</span>
43233
+ <span class="md-toolbar-dropdown-arrow"><svg width="8" height="8" viewBox="0 0 8 8" fill="currentColor"><path d="M0 2l4 4 4-4z"/></svg></span>
43231
43234
  `;
43232
43235
  const menu = document.createElement("div");
43233
43236
  menu.className = "md-toolbar-colorpicker-menu";
@@ -43278,6 +43281,14 @@ class Toolbar {
43278
43281
  button.addEventListener("click", (e) => {
43279
43282
  e.preventDefault();
43280
43283
  e.stopPropagation();
43284
+ this.dropdowns.forEach((dropdown, key) => {
43285
+ if (key !== name) {
43286
+ dropdown.classList.remove("md-toolbar-dropdown-open", "md-toolbar-colorpicker-open");
43287
+ }
43288
+ });
43289
+ this.bodyMenus.forEach((m) => {
43290
+ if (m !== menu) m.style.display = "none";
43291
+ });
43281
43292
  const isOpen = menu.style.display !== "none";
43282
43293
  menu.style.display = isOpen ? "none" : "block";
43283
43294
  wrapper.classList.toggle("md-toolbar-colorpicker-open", !isOpen);
@@ -43286,7 +43297,8 @@ class Toolbar {
43286
43297
  }
43287
43298
  });
43288
43299
  wrapper.appendChild(button);
43289
- wrapper.appendChild(menu);
43300
+ document.body.appendChild(menu);
43301
+ this.bodyMenus.push(menu);
43290
43302
  this.dropdowns.set(name, wrapper);
43291
43303
  return wrapper;
43292
43304
  }
@@ -43294,7 +43306,9 @@ class Toolbar {
43294
43306
  this.unbindEvents();
43295
43307
  this.boundClickHandler = (e) => {
43296
43308
  const target = e.target;
43297
- if (!target.closest(".md-toolbar-dropdown, .md-toolbar-colorpicker")) {
43309
+ const inDropdown = target.closest(".md-toolbar-dropdown, .md-toolbar-colorpicker");
43310
+ const inBodyMenu = this.bodyMenus.some((m) => m.contains(target));
43311
+ if (!inDropdown && !inBodyMenu) {
43298
43312
  this.closeAllDropdowns();
43299
43313
  }
43300
43314
  };
@@ -43338,10 +43352,9 @@ class Toolbar {
43338
43352
  closeAllDropdowns() {
43339
43353
  this.dropdowns.forEach((dropdown) => {
43340
43354
  dropdown.classList.remove("md-toolbar-dropdown-open", "md-toolbar-colorpicker-open");
43341
- const menu = dropdown.querySelector(".md-toolbar-dropdown-menu, .md-toolbar-colorpicker-menu");
43342
- if (menu) {
43343
- menu.style.display = "none";
43344
- }
43355
+ });
43356
+ this.bodyMenus.forEach((menu) => {
43357
+ menu.style.display = "none";
43345
43358
  });
43346
43359
  }
43347
43360
  startStateUpdates() {
@@ -43507,6 +43520,7 @@ class Toolbar {
43507
43520
  this.searchReplace = null;
43508
43521
  this.buttonElements.clear();
43509
43522
  this.dropdowns.clear();
43523
+ this.removeBodyMenus();
43510
43524
  this.buttonsEl = null;
43511
43525
  this.toggleBtn = null;
43512
43526
  this.render();
@@ -43527,8 +43541,15 @@ class Toolbar {
43527
43541
  this.searchReplace?.destroy();
43528
43542
  this.buttonElements.clear();
43529
43543
  this.dropdowns.clear();
43544
+ this.removeBodyMenus();
43530
43545
  this.container.innerHTML = "";
43531
43546
  }
43547
+ removeBodyMenus() {
43548
+ this.bodyMenus.forEach((menu) => {
43549
+ menu.remove();
43550
+ });
43551
+ this.bodyMenus = [];
43552
+ }
43532
43553
  }
43533
43554
  const SVG_ALIGN_LEFT = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="15" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>';
43534
43555
  const SVG_ALIGN_CENTER = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="6" y1="12" x2="18" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>';
@@ -43753,6 +43774,54 @@ const SignatureBlock = Node3.create({
43753
43774
  return ["div", mergeAttributes(HTMLAttributes), 0];
43754
43775
  }
43755
43776
  });
43777
+ const Mention = Node3.create({
43778
+ name: "mention",
43779
+ group: "inline",
43780
+ inline: true,
43781
+ atom: true,
43782
+ selectable: true,
43783
+ draggable: false,
43784
+ addAttributes() {
43785
+ return {
43786
+ jid: {
43787
+ default: null,
43788
+ parseHTML: (element) => element.getAttribute("data-jid"),
43789
+ renderHTML: (attributes) => {
43790
+ if (!attributes.jid) return {};
43791
+ return { "data-jid": attributes.jid };
43792
+ }
43793
+ },
43794
+ display: {
43795
+ default: null,
43796
+ parseHTML: (element) => element.getAttribute("data-display"),
43797
+ renderHTML: (attributes) => {
43798
+ if (!attributes.display) return {};
43799
+ return { "data-display": attributes.display };
43800
+ }
43801
+ }
43802
+ };
43803
+ },
43804
+ parseHTML() {
43805
+ return [
43806
+ {
43807
+ tag: "span.composer-mention"
43808
+ }
43809
+ ];
43810
+ },
43811
+ renderHTML({ node, HTMLAttributes }) {
43812
+ return [
43813
+ "span",
43814
+ mergeAttributes(
43815
+ {
43816
+ class: "composer-mention",
43817
+ contenteditable: "false"
43818
+ },
43819
+ HTMLAttributes
43820
+ ),
43821
+ `@${node.attrs.display}`
43822
+ ];
43823
+ }
43824
+ });
43756
43825
  const en = {
43757
43826
  "Bold": "Bold",
43758
43827
  "Italic": "Italic",
@@ -46283,6 +46352,7 @@ class HTMLEditor {
46283
46352
  // We use CodeBlockLowlight instead
46284
46353
  }),
46285
46354
  SignatureBlock,
46355
+ Mention,
46286
46356
  Underline,
46287
46357
  TextStyle,
46288
46358
  FontFamily,
@@ -46544,6 +46614,7 @@ exports.FontSize = FontSize;
46544
46614
  exports.HTMLEditor = HTMLEditor;
46545
46615
  exports.LineHeight = LineHeight;
46546
46616
  exports.LinkEditor = LinkEditor;
46617
+ exports.Mention = Mention;
46547
46618
  exports.SearchReplace = SearchReplace;
46548
46619
  exports.SignatureBlock = SignatureBlock;
46549
46620
  exports.SourceEditor = SourceEditor;
package/dist/index.mjs CHANGED
@@ -42786,6 +42786,7 @@ class Toolbar {
42786
42786
  state;
42787
42787
  buttonElements = /* @__PURE__ */ new Map();
42788
42788
  dropdowns = /* @__PURE__ */ new Map();
42789
+ bodyMenus = [];
42789
42790
  charMap = null;
42790
42791
  emojiPicker = null;
42791
42792
  imageUpload = null;
@@ -43158,7 +43159,7 @@ class Toolbar {
43158
43159
  button.title = label;
43159
43160
  button.innerHTML = `
43160
43161
  <span class="md-toolbar-dropdown-label">${label}</span>
43161
- <span class="md-toolbar-dropdown-arrow">▼</span>
43162
+ <span class="md-toolbar-dropdown-arrow"><svg width="8" height="8" viewBox="0 0 8 8" fill="currentColor"><path d="M0 2l4 4 4-4z"/></svg></span>
43162
43163
  `;
43163
43164
  const menu = document.createElement("div");
43164
43165
  menu.className = "md-toolbar-dropdown-menu";
@@ -43190,11 +43191,12 @@ class Toolbar {
43190
43191
  e.stopPropagation();
43191
43192
  this.dropdowns.forEach((dropdown, key) => {
43192
43193
  if (key !== name) {
43193
- dropdown.classList.remove("md-toolbar-dropdown-open");
43194
- const m = dropdown.querySelector(".md-toolbar-dropdown-menu");
43195
- if (m) m.style.display = "none";
43194
+ dropdown.classList.remove("md-toolbar-dropdown-open", "md-toolbar-colorpicker-open");
43196
43195
  }
43197
43196
  });
43197
+ this.bodyMenus.forEach((m) => {
43198
+ if (m !== menu) m.style.display = "none";
43199
+ });
43198
43200
  const isOpen = menu.style.display !== "none";
43199
43201
  menu.style.display = isOpen ? "none" : "block";
43200
43202
  wrapper.classList.toggle("md-toolbar-dropdown-open", !isOpen);
@@ -43210,7 +43212,8 @@ class Toolbar {
43210
43212
  }
43211
43213
  });
43212
43214
  wrapper.appendChild(button);
43213
- wrapper.appendChild(menu);
43215
+ document.body.appendChild(menu);
43216
+ this.bodyMenus.push(menu);
43214
43217
  this.dropdowns.set(name, wrapper);
43215
43218
  return wrapper;
43216
43219
  }
@@ -43225,7 +43228,7 @@ class Toolbar {
43225
43228
  button.innerHTML = `
43226
43229
  <span class="md-toolbar-colorpicker-icon md-icon-${name}">A</span>
43227
43230
  <span class="md-toolbar-colorpicker-preview" style="background-color: ${name === "forecolor" ? "#000" : "#ff0"}"></span>
43228
- <span class="md-toolbar-dropdown-arrow">▼</span>
43231
+ <span class="md-toolbar-dropdown-arrow"><svg width="8" height="8" viewBox="0 0 8 8" fill="currentColor"><path d="M0 2l4 4 4-4z"/></svg></span>
43229
43232
  `;
43230
43233
  const menu = document.createElement("div");
43231
43234
  menu.className = "md-toolbar-colorpicker-menu";
@@ -43276,6 +43279,14 @@ class Toolbar {
43276
43279
  button.addEventListener("click", (e) => {
43277
43280
  e.preventDefault();
43278
43281
  e.stopPropagation();
43282
+ this.dropdowns.forEach((dropdown, key) => {
43283
+ if (key !== name) {
43284
+ dropdown.classList.remove("md-toolbar-dropdown-open", "md-toolbar-colorpicker-open");
43285
+ }
43286
+ });
43287
+ this.bodyMenus.forEach((m) => {
43288
+ if (m !== menu) m.style.display = "none";
43289
+ });
43279
43290
  const isOpen = menu.style.display !== "none";
43280
43291
  menu.style.display = isOpen ? "none" : "block";
43281
43292
  wrapper.classList.toggle("md-toolbar-colorpicker-open", !isOpen);
@@ -43284,7 +43295,8 @@ class Toolbar {
43284
43295
  }
43285
43296
  });
43286
43297
  wrapper.appendChild(button);
43287
- wrapper.appendChild(menu);
43298
+ document.body.appendChild(menu);
43299
+ this.bodyMenus.push(menu);
43288
43300
  this.dropdowns.set(name, wrapper);
43289
43301
  return wrapper;
43290
43302
  }
@@ -43292,7 +43304,9 @@ class Toolbar {
43292
43304
  this.unbindEvents();
43293
43305
  this.boundClickHandler = (e) => {
43294
43306
  const target = e.target;
43295
- if (!target.closest(".md-toolbar-dropdown, .md-toolbar-colorpicker")) {
43307
+ const inDropdown = target.closest(".md-toolbar-dropdown, .md-toolbar-colorpicker");
43308
+ const inBodyMenu = this.bodyMenus.some((m) => m.contains(target));
43309
+ if (!inDropdown && !inBodyMenu) {
43296
43310
  this.closeAllDropdowns();
43297
43311
  }
43298
43312
  };
@@ -43336,10 +43350,9 @@ class Toolbar {
43336
43350
  closeAllDropdowns() {
43337
43351
  this.dropdowns.forEach((dropdown) => {
43338
43352
  dropdown.classList.remove("md-toolbar-dropdown-open", "md-toolbar-colorpicker-open");
43339
- const menu = dropdown.querySelector(".md-toolbar-dropdown-menu, .md-toolbar-colorpicker-menu");
43340
- if (menu) {
43341
- menu.style.display = "none";
43342
- }
43353
+ });
43354
+ this.bodyMenus.forEach((menu) => {
43355
+ menu.style.display = "none";
43343
43356
  });
43344
43357
  }
43345
43358
  startStateUpdates() {
@@ -43505,6 +43518,7 @@ class Toolbar {
43505
43518
  this.searchReplace = null;
43506
43519
  this.buttonElements.clear();
43507
43520
  this.dropdowns.clear();
43521
+ this.removeBodyMenus();
43508
43522
  this.buttonsEl = null;
43509
43523
  this.toggleBtn = null;
43510
43524
  this.render();
@@ -43525,8 +43539,15 @@ class Toolbar {
43525
43539
  this.searchReplace?.destroy();
43526
43540
  this.buttonElements.clear();
43527
43541
  this.dropdowns.clear();
43542
+ this.removeBodyMenus();
43528
43543
  this.container.innerHTML = "";
43529
43544
  }
43545
+ removeBodyMenus() {
43546
+ this.bodyMenus.forEach((menu) => {
43547
+ menu.remove();
43548
+ });
43549
+ this.bodyMenus = [];
43550
+ }
43530
43551
  }
43531
43552
  const SVG_ALIGN_LEFT = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="15" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>';
43532
43553
  const SVG_ALIGN_CENTER = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="6" y1="12" x2="18" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>';
@@ -43751,6 +43772,54 @@ const SignatureBlock = Node3.create({
43751
43772
  return ["div", mergeAttributes(HTMLAttributes), 0];
43752
43773
  }
43753
43774
  });
43775
+ const Mention = Node3.create({
43776
+ name: "mention",
43777
+ group: "inline",
43778
+ inline: true,
43779
+ atom: true,
43780
+ selectable: true,
43781
+ draggable: false,
43782
+ addAttributes() {
43783
+ return {
43784
+ jid: {
43785
+ default: null,
43786
+ parseHTML: (element) => element.getAttribute("data-jid"),
43787
+ renderHTML: (attributes) => {
43788
+ if (!attributes.jid) return {};
43789
+ return { "data-jid": attributes.jid };
43790
+ }
43791
+ },
43792
+ display: {
43793
+ default: null,
43794
+ parseHTML: (element) => element.getAttribute("data-display"),
43795
+ renderHTML: (attributes) => {
43796
+ if (!attributes.display) return {};
43797
+ return { "data-display": attributes.display };
43798
+ }
43799
+ }
43800
+ };
43801
+ },
43802
+ parseHTML() {
43803
+ return [
43804
+ {
43805
+ tag: "span.composer-mention"
43806
+ }
43807
+ ];
43808
+ },
43809
+ renderHTML({ node, HTMLAttributes }) {
43810
+ return [
43811
+ "span",
43812
+ mergeAttributes(
43813
+ {
43814
+ class: "composer-mention",
43815
+ contenteditable: "false"
43816
+ },
43817
+ HTMLAttributes
43818
+ ),
43819
+ `@${node.attrs.display}`
43820
+ ];
43821
+ }
43822
+ });
43754
43823
  const en = {
43755
43824
  "Bold": "Bold",
43756
43825
  "Italic": "Italic",
@@ -46281,6 +46350,7 @@ class HTMLEditor {
46281
46350
  // We use CodeBlockLowlight instead
46282
46351
  }),
46283
46352
  SignatureBlock,
46353
+ Mention,
46284
46354
  Underline,
46285
46355
  TextStyle,
46286
46356
  FontFamily,
@@ -46543,6 +46613,7 @@ export {
46543
46613
  HTMLEditor,
46544
46614
  LineHeight,
46545
46615
  LinkEditor,
46616
+ Mention,
46546
46617
  SearchReplace,
46547
46618
  SignatureBlock,
46548
46619
  SourceEditor,
package/dist/styles.css CHANGED
@@ -175,9 +175,39 @@
175
175
  }
176
176
 
177
177
  .md-toolbar-dropdown-arrow {
178
- font-size: 8px;
178
+ display: inline-flex;
179
+ align-items: center;
179
180
  opacity: 0.6;
180
181
  }
182
+ .md-toolbar-dropdown-arrow svg {
183
+ display: block;
184
+ width: 8px;
185
+ height: 8px;
186
+ }
187
+
188
+ .md-toolbar-dropdown-menu,
189
+ .md-toolbar-colorpicker-menu {
190
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
191
+ font-size: 14px;
192
+ box-sizing: border-box;
193
+ }
194
+ .md-toolbar-dropdown-menu *, .md-toolbar-dropdown-menu *::before, .md-toolbar-dropdown-menu *::after,
195
+ .md-toolbar-colorpicker-menu *,
196
+ .md-toolbar-colorpicker-menu *::before,
197
+ .md-toolbar-colorpicker-menu *::after {
198
+ box-sizing: border-box;
199
+ }
200
+ .md-toolbar-dropdown-menu button:not([class]),
201
+ .md-toolbar-colorpicker-menu button:not([class]) {
202
+ appearance: none;
203
+ font: inherit;
204
+ color: inherit;
205
+ background: transparent;
206
+ border: none;
207
+ padding: 0;
208
+ margin: 0;
209
+ cursor: pointer;
210
+ }
181
211
 
182
212
  .md-toolbar-dropdown-menu {
183
213
  position: fixed;
@@ -191,7 +221,7 @@
191
221
  z-index: 1000;
192
222
  }
193
223
 
194
- .md-editor .md-toolbar-dropdown-item {
224
+ .md-toolbar-dropdown-item {
195
225
  display: block;
196
226
  margin-top: 2px;
197
227
  margin-bottom: 2px;
@@ -204,10 +234,10 @@
204
234
  font-size: 13px;
205
235
  color: #222;
206
236
  }
207
- .md-editor .md-toolbar-dropdown-item:hover {
237
+ .md-toolbar-dropdown-item:hover {
208
238
  background: #f0f0f0;
209
239
  }
210
- .md-editor .md-toolbar-dropdown-item.md-toolbar-dropdown-item-selected {
240
+ .md-toolbar-dropdown-item.md-toolbar-dropdown-item-selected {
211
241
  background: #2271b2;
212
242
  color: #fff;
213
243
  }
@@ -310,9 +340,12 @@
310
340
  min-height: 0;
311
341
  overflow: auto;
312
342
  background: #fff;
343
+ display: flex;
344
+ flex-direction: column;
313
345
  }
314
346
 
315
347
  .md-editor-body {
348
+ flex: 1;
316
349
  padding: 16px;
317
350
  min-height: 200px;
318
351
  outline: none;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mdaemon/html-editor",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "A TinyMCE-compatible HTML editor built on TipTap",
5
5
  "homepage": "https://github.com/mdaemon-technologies/MDHTMLEditor",
6
6
  "repository": {