autumnnote 1.5.0 → 1.6.0

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 (46) hide show
  1. package/README.md +6 -4
  2. package/dist/autumnnote.css +324 -2
  3. package/dist/autumnnote.es.js +638 -227
  4. package/dist/autumnnote.es.js.map +1 -1
  5. package/dist/autumnnote.umd.js +637 -226
  6. package/dist/autumnnote.umd.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/js/Context.js +8 -3
  9. package/src/js/core/detectLang.js +98 -0
  10. package/src/js/core/dom.js +62 -6
  11. package/src/js/core/markdown.js +14 -13
  12. package/src/js/core/range.js +2 -2
  13. package/src/js/editing/History.js +6 -6
  14. package/src/js/editing/Style.js +19 -19
  15. package/src/js/editing/Table.js +4 -6
  16. package/src/js/editing/Typing.js +6 -6
  17. package/src/js/i18n/en.js +2 -0
  18. package/src/js/i18n/vi.js +2 -0
  19. package/src/js/index.js +3 -2
  20. package/src/js/module/BubbleToolbar.js +30 -13
  21. package/src/js/module/Buttons.js +16 -14
  22. package/src/js/module/Clipboard.js +5 -5
  23. package/src/js/module/CodeTooltip.js +42 -16
  24. package/src/js/module/Codeview.js +2 -2
  25. package/src/js/module/ContextMenu.js +12 -12
  26. package/src/js/module/Editor.js +64 -12
  27. package/src/js/module/EmojiDialog.js +19 -13
  28. package/src/js/module/FindReplace.js +85 -59
  29. package/src/js/module/Fullscreen.js +1 -1
  30. package/src/js/module/IconDialog.js +26 -20
  31. package/src/js/module/ImageCropOverlay.js +6 -6
  32. package/src/js/module/ImageDialog.js +18 -12
  33. package/src/js/module/ImageResizer.js +1 -1
  34. package/src/js/module/ImageTooltip.js +8 -4
  35. package/src/js/module/LinkDialog.js +18 -12
  36. package/src/js/module/LinkTooltip.js +5 -2
  37. package/src/js/module/Mention.js +3 -3
  38. package/src/js/module/Statusbar.js +2 -2
  39. package/src/js/module/TableTooltip.js +180 -18
  40. package/src/js/module/Toolbar.js +16 -15
  41. package/src/js/module/VideoDialog.js +8 -2
  42. package/src/js/module/VideoResizer.js +3 -3
  43. package/src/js/module/VideoTooltip.js +11 -6
  44. package/src/js/renderer.js +4 -2
  45. package/src/js/settings.js +53 -36
  46. package/src/styles/autumnnote.scss +332 -4
@@ -375,16 +375,60 @@ function trapFocus(container, onEscape) {
375
375
  if (e.shiftKey) {
376
376
  if (document.activeElement === first) {
377
377
  e.preventDefault();
378
- last.focus();
378
+ /** @type {HTMLElement} */ last.focus();
379
379
  }
380
380
  } else if (document.activeElement === last) {
381
381
  e.preventDefault();
382
- first.focus();
382
+ /** @type {HTMLElement} */ first.focus();
383
383
  }
384
384
  };
385
385
  document.addEventListener("keydown", handler);
386
386
  return () => document.removeEventListener("keydown", handler);
387
387
  }
388
+ /**
389
+ * Makes a dialog box draggable by its handle element.
390
+ * On first drag the box is pinned to its current viewport coordinates via
391
+ * `position:fixed`, freeing it from the parent flex container's centering.
392
+ * The position is clamped to the visible viewport.
393
+ *
394
+ * @param {HTMLElement} handle Element the user grabs (title bar / header)
395
+ * @param {HTMLElement} box Element that actually moves
396
+ * @returns {Function} Cleanup function (removes the mousedown listener)
397
+ */
398
+ function makeDraggable(handle, box) {
399
+ handle.style.cursor = "grab";
400
+ const onMousedown = (e) => {
401
+ if (e.button !== 0) return;
402
+ if (e.target.closest("button, input, select, textarea, a")) return;
403
+ e.preventDefault();
404
+ if (!box.dataset.anDragPinned) {
405
+ const r = box.getBoundingClientRect();
406
+ box.style.position = "fixed";
407
+ box.style.margin = "0";
408
+ box.style.left = `${r.left}px`;
409
+ box.style.top = `${r.top}px`;
410
+ box.dataset.anDragPinned = "1";
411
+ }
412
+ const startX = e.clientX - parseFloat(box.style.left);
413
+ const startY = e.clientY - parseFloat(box.style.top);
414
+ handle.style.cursor = "grabbing";
415
+ const onMove = (ev) => {
416
+ const bw = box.offsetWidth;
417
+ const bh = box.offsetHeight;
418
+ box.style.left = `${Math.max(0, Math.min(ev.clientX - startX, window.innerWidth - bw))}px`;
419
+ box.style.top = `${Math.max(0, Math.min(ev.clientY - startY, window.innerHeight - bh))}px`;
420
+ };
421
+ const onUp = () => {
422
+ handle.style.cursor = "grab";
423
+ document.removeEventListener("mousemove", onMove);
424
+ document.removeEventListener("mouseup", onUp);
425
+ };
426
+ document.addEventListener("mousemove", onMove);
427
+ document.addEventListener("mouseup", onUp);
428
+ };
429
+ handle.addEventListener("mousedown", onMousedown);
430
+ return () => handle.removeEventListener("mousedown", onMousedown);
431
+ }
388
432
  //#endregion
389
433
  //#region src/js/core/range.js
390
434
  /**
@@ -566,7 +610,7 @@ function underline() {
566
610
  if (!sel || !sel.rangeCount) return;
567
611
  let container = sel.getRangeAt(0).commonAncestorContainer;
568
612
  if (container.nodeType === 3) container = container.parentElement;
569
- const uEl = container && container.closest && container.closest("u");
613
+ const uEl = container && container.closest("u");
570
614
  const nativeState = document.queryCommandState("underline");
571
615
  if (uEl && !nativeState) {
572
616
  const parent = uEl.parentNode;
@@ -586,7 +630,7 @@ function strikethrough() {
586
630
  if (!sel || !sel.rangeCount) return;
587
631
  let sc = sel.getRangeAt(0).startContainer;
588
632
  if (sc.nodeType === 3) sc = sc.parentElement;
589
- const sEl = sc && sc.closest && (sc.closest("s") || sc.closest("strike"));
633
+ const sEl = sc && (sc.closest("s") || sc.closest("strike"));
590
634
  const nativeState = document.queryCommandState("strikeThrough");
591
635
  if (sEl && !nativeState) {
592
636
  const parent = sEl.parentNode;
@@ -623,7 +667,7 @@ var fontName = (name) => execCommand("fontName", name);
623
667
  * Sets the font size (in pt or with unit) for the selection.
624
668
  * Uses a span-based approach to set px sizes precisely.
625
669
  * @param {string} size - e.g. '14px'
626
- * @param {HTMLElement} [editable] - scoping element to avoid touching nodes outside this editor
670
+ * @param {HTMLElement|Document} [editable] - scoping element to avoid touching nodes outside this editor
627
671
  */
628
672
  function fontSize(size, editable = document) {
629
673
  const sel = window.getSelection();
@@ -705,7 +749,7 @@ function outdent() {
705
749
  if (sel && sel.rangeCount) {
706
750
  let container = sel.getRangeAt(0).commonAncestorContainer;
707
751
  if (container.nodeType === 3) container = container.parentElement;
708
- const checkLi = container && container.closest && container.closest(".an-checklist li");
752
+ const checkLi = container && container.closest(".an-checklist li");
709
753
  if (checkLi) {
710
754
  _checklistItemToP(checkLi);
711
755
  return;
@@ -827,15 +871,15 @@ function lineHeight(value) {
827
871
  /**
828
872
  * Wraps the selection in an inline <code> element, or unwraps it if the
829
873
  * cursor is already inside a <code> that is not inside a <pre>.
830
- * @param {HTMLElement} [editable]
874
+ * @param {HTMLElement} [_editable]
831
875
  */
832
- function toggleInlineCode(editable) {
876
+ function toggleInlineCode(_editable) {
833
877
  const sel = window.getSelection();
834
878
  if (!sel || !sel.rangeCount) return;
835
879
  const range = sel.getRangeAt(0);
836
880
  let container = range.commonAncestorContainer;
837
881
  if (container.nodeType === 3) container = container.parentElement;
838
- const codeEl = container && container.closest ? container.closest("code") : null;
882
+ const codeEl = container && container.closest("code");
839
883
  if (codeEl && !codeEl.closest("pre")) {
840
884
  const parent = codeEl.parentNode;
841
885
  const prevSibling = codeEl.previousSibling;
@@ -890,7 +934,7 @@ function isInlineCode() {
890
934
  if (!sel || !sel.rangeCount) return false;
891
935
  let sc = sel.getRangeAt(0).startContainer;
892
936
  if (sc.nodeType === 3) sc = sc.parentElement;
893
- const code = sc && sc.closest ? sc.closest("code") : null;
937
+ const code = sc && sc.closest("code");
894
938
  return !!(code && !code.closest("pre"));
895
939
  }
896
940
  /**
@@ -913,11 +957,11 @@ function toggleChecklist() {
913
957
  const range = sel.getRangeAt(0);
914
958
  let container = range.commonAncestorContainer;
915
959
  if (container.nodeType === 3) container = container.parentElement;
916
- const ul = container.closest && container.closest(".an-checklist");
960
+ const ul = container && container.closest(".an-checklist");
917
961
  if (ul) {
918
962
  const selectedLis = Array.from(ul.querySelectorAll("li")).filter((li) => sel.containsNode(li, true));
919
963
  if (selectedLis.length > 0) {
920
- let firstP = null;
964
+ /** @type {HTMLElement|null} */ let firstP = null;
921
965
  selectedLis.forEach((li) => {
922
966
  const p = document.createElement("p");
923
967
  for (const child of li.childNodes) {
@@ -1015,7 +1059,7 @@ function toggleChecklist() {
1015
1059
  if (blocks.length === 0) return;
1016
1060
  const newUl = document.createElement("ul");
1017
1061
  newUl.className = "an-checklist";
1018
- let lastTextNode = null;
1062
+ /** @type {Text|null} */ let lastTextNode = null;
1019
1063
  blocks.forEach((block) => {
1020
1064
  const li = document.createElement("li");
1021
1065
  const cb = document.createElement("input");
@@ -1048,7 +1092,7 @@ function isInChecklist() {
1048
1092
  if (!sel || !sel.rangeCount) return false;
1049
1093
  let container = sel.getRangeAt(0).commonAncestorContainer;
1050
1094
  if (container.nodeType === 3) container = container.parentElement;
1051
- return !!(container && container.closest && container.closest(".an-checklist li"));
1095
+ return !!(container && container.closest(".an-checklist li"));
1052
1096
  }
1053
1097
  //#endregion
1054
1098
  //#region src/js/module/Buttons.js
@@ -1059,12 +1103,14 @@ function isInChecklist() {
1059
1103
  */
1060
1104
  /**
1061
1105
  * @typedef {object} DropdownDef
1062
- * @property {string} name - unique identifier
1063
- * @property {'select'} type - discriminator for Toolbar renderer
1106
+ * @property {string} name - unique identifier
1107
+ * @property {'select'} type - discriminator for Toolbar renderer
1064
1108
  * @property {string} tooltip
1065
- * @property {string[]} [items] - overridden at render time from options
1066
- * @property {Function} action - called with (context, value)
1067
- * @property {Function} [getValue] - called with (context) to get current value
1109
+ * @property {Array<string|{value:string,label:string,disabled?:boolean}>} [items] - overridden at render time from options
1110
+ * @property {Function} action - called with (context, value)
1111
+ * @property {Function} [getValue] - called with (context) to get current value
1112
+ * @property {string} [selectClass] - extra CSS class(es) for the <select>
1113
+ * @property {string} [placeholder] - placeholder text for the empty option
1068
1114
  */
1069
1115
  /**
1070
1116
  * @typedef {object} ButtonDef
@@ -1132,7 +1178,7 @@ var underlineBtn = btn("underline", "underline", "Underline (Ctrl+U)", () => und
1132
1178
  if (!sel || !sel.rangeCount) return false;
1133
1179
  let sc = sel.getRangeAt(0).startContainer;
1134
1180
  if (sc.nodeType === 3) sc = sc.parentElement;
1135
- return !!(sc && sc.closest && sc.closest("u"));
1181
+ return !!(sc && sc.closest("u"));
1136
1182
  });
1137
1183
  var strikeBtn = btn("strikethrough", "strikethrough", "Strikethrough", () => strikethrough(), () => document.queryCommandState("strikeThrough"));
1138
1184
  var superscriptBtn = btn("superscript", "superscript", "Superscript", () => superscript(), () => document.queryCommandState("superscript"));
@@ -1194,9 +1240,9 @@ var fontSizeBtn = {
1194
1240
  const sel = window.getSelection();
1195
1241
  if (sel && sel.rangeCount) {
1196
1242
  let el = sel.getRangeAt(0).startContainer;
1197
- if (el.nodeType === 3) el = el.parentElement;
1243
+ if (el && el.nodeType === 3) el = el.parentElement;
1198
1244
  while (el && el.nodeType === 1 && !el.style.fontSize) el = el.parentElement;
1199
- const size = el && el.style && el.style.fontSize ? el.style.fontSize : "";
1245
+ const size = el && el.style.fontSize ? el.style.fontSize : "";
1200
1246
  if (size) return size;
1201
1247
  }
1202
1248
  const editable = ctx && ctx.layoutInfo && ctx.layoutInfo.editable;
@@ -1321,8 +1367,11 @@ var lineHeightBtn = {
1321
1367
  "TH"
1322
1368
  ]);
1323
1369
  let el = sel.getRangeAt(0).startContainer;
1324
- if (el.nodeType === 3) el = el.parentElement;
1325
- while (el && !BLOCKS.has(el.tagName)) el = el.parentElement;
1370
+ if (el && el.nodeType === 3) el = el.parentElement;
1371
+ while (el && !BLOCKS.has(
1372
+ /** @type {Element} */
1373
+ el.tagName
1374
+ )) el = el.parentElement;
1326
1375
  if (!el) return "";
1327
1376
  return el.style.lineHeight || getComputedStyle(el).lineHeight || "";
1328
1377
  } catch {
@@ -1416,47 +1465,64 @@ var defaultToolbar = [
1416
1465
  */
1417
1466
  /**
1418
1467
  * @typedef {object} AsnOptions
1419
- * @property {string} [placeholder] - Placeholder text when editor is empty
1420
- * @property {number} [height] - Editor height in px (min)
1421
- * @property {number} [minHeight] - Minimum height in px
1422
- * @property {number} [maxHeight] - Maximum height in px (0 = unlimited)
1423
- * @property {boolean} [focus] - Auto-focus on init
1424
- * @property {boolean} [resizable] - Show resize handle
1425
- * @property {Array} [toolbar] - Toolbar button group config
1426
- * @property {boolean} [pasteAsPlainText] - Force plain-text paste
1427
- * @property {boolean} [pasteCleanHTML] - Sanitise HTML on paste
1468
+ * @property {string} [placeholder] - Placeholder text when editor is empty
1469
+ * @property {number} [height] - Editor height in px (min)
1470
+ * @property {number} [minHeight] - Minimum height in px
1471
+ * @property {number} [maxHeight] - Maximum height in px (0 = unlimited)
1472
+ * @property {boolean} [focus] - Auto-focus on init
1473
+ * @property {boolean} [resizable] - Show resize handle
1474
+ * @property {Array} [toolbar] - Toolbar button group config
1475
+ * @property {boolean} [useBootstrap] - Use Bootstrap button classes on toolbar buttons
1476
+ * @property {string} [toolbarButtonClass] - CSS classes for Bootstrap toolbar buttons
1477
+ * @property {boolean} [useFontAwesome] - Use Font Awesome icons (default: true)
1478
+ * @property {string} [fontAwesomeClass] - Font Awesome prefix class, e.g. 'fas' or 'fa-solid'
1479
+ * @property {boolean} [pasteAsPlainText] - Force plain-text paste
1480
+ * @property {boolean} [pasteCleanHTML] - Sanitise HTML on paste
1428
1481
  * @property {boolean} [pasteStripAttributes] - Strip class/style/data-* from pasted HTML (default: false)
1429
- * @property {boolean} [allowImageUpload] - Allow file upload in image dialog
1430
- * @property {number} [maxImageSize] - Max upload size in MB
1431
- * @property {number} [tabSize] - Spaces per tab in non-list context
1432
- * @property {Function} [onChange] - Callback on content change
1433
- * @property {Function} [onFocus] - Callback on focus
1434
- * @property {Function} [onBlur] - Callback on blur
1435
- * @property {Function} [onImageUpload] - Custom upload handler: (files) => void
1436
- * @property {boolean} [stickyToolbar] - Stick the toolbar to the viewport top when scrolling
1437
- * @property {number} [stickyToolbarOffset] - Top offset in px for sticky toolbar (e.g. fixed nav height)
1438
- * @property {string} [theme] - 'light' (default) | 'dark'
1439
- * @property {boolean} [codeHighlight] - Auto-load Prism.js for syntax highlighting of code blocks
1440
- * @property {string} [codeHighlightCDN] - CDN base URL for Prism assets (defaults to cdnjs)
1441
- * @property {boolean} [markdownPaste] - Convert pasted Markdown text to HTML (default: true)
1442
- * @property {boolean} [readOnly] - Start editor in read-only / non-editable mode
1443
- * @property {boolean} [spellcheck] - Enable browser spellcheck in the editable area (default: true)
1444
- * @property {string} [direction] - Text direction: 'ltr' (default) | 'rtl'
1445
- * @property {string} [toolbarOverflow] - Toolbar overflow strategy: 'wrap' (default) | 'scroll'
1446
- * @property {boolean} [autoSave] - Auto-save content to localStorage on change
1447
- * @property {string} [autoSaveKey] - localStorage key used for auto-save (default: 'autumnnote-autosave')
1448
- * @property {number} [maxChars] - Maximum character count (0 = unlimited). Shows warning in statusbar.
1449
- * @property {number} [maxWords] - Maximum word count (0 = unlimited). Shows warning in statusbar.
1450
- * @property {boolean} [tableHeaderRow] - Insert a header row (<thead><th>) when creating tables
1451
- * @property {Function} [onPaste] - Callback fired on every paste: ({ text, html }) => void
1452
- * @property {Function} [onSelectionChange] - Callback fired on cursor/selection change: (context) => void
1453
- * @property {string[]} [colorSwatches] - Custom brand colour swatches prepended to the colour-picker palette
1482
+ * @property {boolean} [allowImageUpload] - Allow file upload in image dialog
1483
+ * @property {number} [maxImageSize] - Max upload size in MB
1484
+ * @property {number} [tabSize] - Spaces per tab in non-list context
1485
+ * @property {number} [historyLimit] - Maximum undo/redo history steps
1486
+ * @property {string} [defaultFontFamily] - Default font family applied to the editable area on init
1487
+ * @property {string} [defaultFontSize] - Default font size applied to the editable area on init (e.g. '14px')
1488
+ * @property {string[]} [fontFamilies] - Font families shown in the font-family toolbar dropdown
1489
+ * @property {Function} [onChange] - Callback on content change
1490
+ * @property {Function} [onFocus] - Callback on focus
1491
+ * @property {Function} [onBlur] - Callback on blur
1492
+ * @property {Function} [onInit] - Callback after the editor has initialised
1493
+ * @property {Function} [onImageUpload] - Custom upload handler: (files) => void
1494
+ * @property {Function} [onImageError] - Callback when an image upload error occurs
1495
+ * @property {boolean} [stickyToolbar] - Stick the toolbar to the viewport top when scrolling
1496
+ * @property {number} [stickyToolbarOffset] - Top offset in px for sticky toolbar (e.g. fixed nav height)
1497
+ * @property {string} [theme] - 'light' (default) | 'dark'
1498
+ * @property {boolean} [codeHighlight] - Auto-load Prism.js for syntax highlighting of code blocks
1499
+ * @property {string} [codeHighlightCDN] - CDN base URL for Prism assets (defaults to cdnjs)
1500
+ * @property {boolean} [markdownPaste] - Convert pasted Markdown text to HTML (default: true)
1501
+ * @property {boolean} [readOnly] - Start editor in read-only / non-editable mode
1502
+ * @property {boolean} [spellcheck] - Enable browser spellcheck in the editable area (default: true)
1503
+ * @property {string} [direction] - Text direction: 'ltr' (default) | 'rtl'
1504
+ * @property {string} [toolbarOverflow] - Toolbar overflow strategy: 'wrap' (default) | 'scroll'
1505
+ * @property {boolean} [autoSave] - Auto-save content to localStorage on change
1506
+ * @property {string} [autoSaveKey] - localStorage key used for auto-save (default: 'autumnnote-autosave')
1507
+ * @property {number} [maxChars] - Maximum character count (0 = unlimited). Shows warning in statusbar.
1508
+ * @property {number} [maxWords] - Maximum word count (0 = unlimited). Shows warning in statusbar.
1509
+ * @property {boolean} [tableHeaderRow] - Insert a header row (<thead><th>) when creating tables
1510
+ * @property {Function} [onPaste] - Callback fired on every paste: ({ text, html }) => void
1511
+ * @property {Function} [onSelectionChange] - Callback fired on cursor/selection change: (context) => void
1512
+ * @property {string[]} [colorSwatches] - Custom brand colour swatches prepended to the colour-picker palette
1454
1513
  * @property {Function} [onDestroy] - Callback fired when the editor is destroyed: (context) => void
1455
1514
  * @property {Function} [onCharLimitReached] - Callback fired when the character limit is hit: (context) => void
1456
1515
  * @property {Function} [onWordLimitReached] - Callback fired when the word limit is hit: (context) => void
1457
- * @property {string} [focusColor] - Custom focus ring colour, e.g. '#f97316'. Overrides the default blue.
1516
+ * @property {string} [focusColor] - Custom focus ring colour, e.g. '#f97316'. Overrides the default blue.
1517
+ * @property {boolean} [autoSaveRestore] - Show a restore banner when a previously auto-saved draft exists
1518
+ * @property {number} [autoSaveRestoreTimeout] - Maximum age in days for a draft to be offered for restore (0 = no expiry)
1519
+ * @property {Function} [onAutoSaveRestore] - Callback fired after the user chooses to restore a draft
1520
+ * @property {boolean} [markdownShortcuts] - Convert markdown syntax typed inline to HTML
1521
+ * @property {boolean} [bubbleToolbar] - Show a mini floating toolbar above text selections
1522
+ * @property {string[]} [bubbleToolbarItems] - Button names for the bubble toolbar
1523
+ * @property {object|null} [mention] - @mention configuration (onSearch, minChars, ...)
1524
+ * @property {string} [lang] - Display language or partial locale object override
1458
1525
  */
1459
- /** @type {AsnOptions} */
1460
1526
  var defaultOptions = {
1461
1527
  placeholder: "",
1462
1528
  height: 200,
@@ -1855,6 +1921,8 @@ var en = {
1855
1921
  rowHeight: "Row Height",
1856
1922
  tableBorderWidth: "Table Border Width",
1857
1923
  deleteTable: "Delete Table",
1924
+ cellBackground: "Cell Background",
1925
+ noShading: "No Shading",
1858
1926
  columnWidthPx: "Column Width (px)",
1859
1927
  rowHeightPx: "Row Height (px)",
1860
1928
  tableBorderWidthPx: "Table Border Width (px)",
@@ -2210,6 +2278,8 @@ var locales = {
2210
2278
  rowHeight: "Chiều cao hàng",
2211
2279
  tableBorderWidth: "Độ rộng viền bảng",
2212
2280
  deleteTable: "Xóa bảng",
2281
+ cellBackground: "Màu Nền Ô",
2282
+ noShading: "Xóa Màu Nền",
2213
2283
  columnWidthPx: "Chiều rộng cột (px)",
2214
2284
  rowHeightPx: "Chiều cao hàng (px)",
2215
2285
  tableBorderWidthPx: "Độ rộng viền bảng (px)",
@@ -4411,7 +4481,10 @@ function renderLayout(targetEl, options) {
4411
4481
  else if (options.minHeight) editable.style.minHeight = `${options.minHeight}px`;
4412
4482
  if (options.maxHeight) editable.style.maxHeight = `${options.maxHeight}px`;
4413
4483
  container.appendChild(editable);
4414
- if (options.theme === "dark") container.classList.add("an-theme-dark");
4484
+ if (options.theme === "dark") {
4485
+ container.classList.add("an-theme-dark");
4486
+ document.body.classList.add("an-theme-dark");
4487
+ }
4415
4488
  if (options.readOnly) {
4416
4489
  container.classList.add("an-disabled");
4417
4490
  editable.querySelectorAll("ul.an-checklist input[type=\"checkbox\"]").forEach((cb) => {
@@ -4449,7 +4522,7 @@ var History = class {
4449
4522
  constructor(editable, limit = 100) {
4450
4523
  this.editable = editable;
4451
4524
  this._limit = limit;
4452
- /** @type {Array<{html: string, range: {sc: string, so: number, ec: string, eo: number}|null}>} */
4525
+ /** @type {Array<{html: string, images?: Record<string,string>, sel: {start: number, end: number}|null}>} */
4453
4526
  this.stack = [];
4454
4527
  this.stackOffset = -1;
4455
4528
  this._savePoint();
@@ -4648,8 +4721,7 @@ var History = class {
4648
4721
  * Build an HTML table with the given number of columns and rows, optionally including a header row.
4649
4722
  * @param {number} cols - Number of columns in each row.
4650
4723
  * @param {number} rows - Total number of rows to create (including header when `headerRow` is true).
4651
- * @param {{ headerRow?: boolean }} [opts] - Options object.
4652
- * @param {boolean} [opts.headerRow=false] - When true and `rows > 0`, creates a header row (`<thead>`) plus body rows for the remainder.
4724
+ * @param {{ headerRow?: boolean }} [opts] - Options: `headerRow` creates a `<thead>` when true.
4653
4725
  * @returns {HTMLTableElement} The constructed `<table>` element with a `<tbody>` and optional `<thead>`; each cell contains a `<br>` placeholder.
4654
4726
  */
4655
4727
  function createTable(cols, rows, opts = {}) {
@@ -4683,7 +4755,6 @@ function createTable(cols, rows, opts = {}) {
4683
4755
  * @param {number} cols - Number of columns for the new table.
4684
4756
  * @param {number} rows - Number of rows for the new table.
4685
4757
  * @param {{ headerRow?: boolean }} [opts] - Options for table creation.
4686
- * @param {boolean} [opts.headerRow=false] - If true, include a header row as the first row.
4687
4758
  */
4688
4759
  function insertTable(cols, rows, opts = {}) {
4689
4760
  if (cols <= 0 || rows <= 0) return;
@@ -4706,7 +4777,7 @@ function insertTable(cols, rows, opts = {}) {
4706
4777
  "PRE"
4707
4778
  ]);
4708
4779
  let anchor = range.startContainer;
4709
- if (anchor.nodeType === 3) anchor = anchor.parentElement;
4780
+ if (anchor && anchor.nodeType === 3) anchor = anchor.parentElement;
4710
4781
  while (anchor && !BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentElement) anchor = anchor.parentElement;
4711
4782
  if (anchor && BLOCK.has(anchor.tagName?.toUpperCase()) && anchor.parentNode) {
4712
4783
  anchor.after(table);
@@ -4824,7 +4895,7 @@ function handleKeydown(event, editable, options = {}) {
4824
4895
  const textNode = r.startContainer;
4825
4896
  if (r.startOffset === 0 && isFAIcon(textNode.previousSibling)) {
4826
4897
  event.preventDefault();
4827
- textNode.previousSibling.remove();
4898
+ /** @type {ChildNode} */ textNode.previousSibling.remove();
4828
4899
  return true;
4829
4900
  }
4830
4901
  if (r.startOffset === 1 && textNode.textContent === "​" && isFAIcon(textNode.previousSibling)) {
@@ -4970,7 +5041,7 @@ function handleKeydown(event, editable, options = {}) {
4970
5041
  }
4971
5042
  return false;
4972
5043
  }
4973
- const videoWrapper = el && el.closest && el.closest(".an-video-wrapper");
5044
+ const videoWrapper = el && el.closest(".an-video-wrapper");
4974
5045
  if (videoWrapper) {
4975
5046
  event.preventDefault();
4976
5047
  const p = document.createElement("p");
@@ -4984,7 +5055,7 @@ function handleKeydown(event, editable, options = {}) {
4984
5055
  sel.addRange(nr);
4985
5056
  return true;
4986
5057
  }
4987
- const checkLi = el && el.closest && el.closest(".an-checklist li");
5058
+ const checkLi = el && el.closest(".an-checklist li");
4988
5059
  if (checkLi) {
4989
5060
  event.preventDefault();
4990
5061
  const ul = checkLi.closest(".an-checklist");
@@ -5084,8 +5155,9 @@ function htmlToMarkdown(html) {
5084
5155
  function _domToMd(node, depth = 0) {
5085
5156
  if (node.nodeType === 3) return node.textContent.replace(/\s+/g, " ");
5086
5157
  if (node.nodeType !== 1) return "";
5087
- const tag = node.nodeName.toLowerCase();
5088
- const inner = () => Array.from(node.childNodes).map((n) => _domToMd(n, depth)).join("");
5158
+ const el = node;
5159
+ const tag = el.nodeName.toLowerCase();
5160
+ const inner = () => Array.from(el.childNodes).map((n) => _domToMd(n, depth)).join("");
5089
5161
  switch (tag) {
5090
5162
  case "p":
5091
5163
  case "div": return `\n\n${inner()}\n\n`;
@@ -5103,34 +5175,34 @@ function _domToMd(node, depth = 0) {
5103
5175
  case "del":
5104
5176
  case "s":
5105
5177
  case "strike": return `~~${inner()}~~`;
5106
- case "sup": return `^${inner()}`;
5107
- case "sub": return `~${inner()}`;
5178
+ case "sup": return `^${inner()}^`;
5179
+ case "sub": return `~${inner()}~`;
5108
5180
  case "code":
5109
- if (node.closest("pre")) return inner();
5181
+ if (el.closest("pre")) return inner();
5110
5182
  return `\`${inner()}\``;
5111
5183
  case "pre": {
5112
- const codeEl = node.querySelector("code");
5184
+ const codeEl = el.querySelector("code");
5113
5185
  const langMatch = (codeEl && codeEl.className || "").match(/language-(\S+)/);
5114
- return `\n\n\`\`\`${langMatch ? langMatch[1] : ""}\n${(codeEl || node).textContent || ""}\n\`\`\`\n\n`;
5186
+ return `\n\n\`\`\`${langMatch ? langMatch[1] : ""}\n${(codeEl || el).textContent || ""}\n\`\`\`\n\n`;
5115
5187
  }
5116
5188
  case "blockquote": return `\n\n${inner().trim().split("\n").map((l) => `> ${l}`).join("\n")}\n\n`;
5117
5189
  case "a": {
5118
- const href = node.getAttribute("href") || "";
5190
+ const href = el.getAttribute("href") || "";
5119
5191
  return `[${inner()}](${href})`;
5120
5192
  }
5121
5193
  case "img": {
5122
- const src = node.getAttribute("src") || "";
5123
- return `![${node.getAttribute("alt") || ""}](${src})`;
5194
+ const src = el.getAttribute("src") || "";
5195
+ return `![${el.getAttribute("alt") || ""}](${src})`;
5124
5196
  }
5125
5197
  case "ul": {
5126
- const items = Array.from(node.querySelectorAll(":scope > li"));
5198
+ const items = Array.from(el.querySelectorAll(":scope > li"));
5127
5199
  if (!items.length) return inner();
5128
5200
  const indent = " ".repeat(depth);
5129
5201
  const lines = items.map((li) => `${indent}- ${_domToMd(li, depth + 1).trim()}`).join("\n");
5130
5202
  return depth === 0 ? `\n\n${lines}\n\n` : `\n${lines}`;
5131
5203
  }
5132
5204
  case "ol": {
5133
- const items = Array.from(node.querySelectorAll(":scope > li"));
5205
+ const items = Array.from(el.querySelectorAll(":scope > li"));
5134
5206
  if (!items.length) return inner();
5135
5207
  const indent = " ".repeat(depth);
5136
5208
  const lines = items.map((li, i) => `${indent}${i + 1}. ${_domToMd(li, depth + 1).trim()}`).join("\n");
@@ -5139,7 +5211,7 @@ function _domToMd(node, depth = 0) {
5139
5211
  case "li": return inner();
5140
5212
  case "hr": return "\n\n---\n\n";
5141
5213
  case "table": {
5142
- const rows = Array.from(node.querySelectorAll("tr"));
5214
+ const rows = Array.from(el.querySelectorAll("tr"));
5143
5215
  if (!rows.length) return inner();
5144
5216
  const cellTexts = rows.map((tr) => Array.from(tr.querySelectorAll("th, td")).map((c) => c.textContent.trim().replace(/\|/g, "\\|")));
5145
5217
  const cols = Math.max(...cellTexts.map((r) => r.length));
@@ -5287,6 +5359,47 @@ function _escAttr(v) {
5287
5359
  return String(v).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5288
5360
  }
5289
5361
  //#endregion
5362
+ //#region src/js/core/detectLang.js
5363
+ /**
5364
+ * detectLang.js — Heuristic programming-language detection for code snippets.
5365
+ *
5366
+ * Returns a Prism.js language identifier or null when no language can be
5367
+ * determined with reasonable confidence.
5368
+ *
5369
+ * Detection order (conflicts in parentheses):
5370
+ * TypeScript → Rust → PHP → Java → Kotlin → Swift → Go
5371
+ * → JavaScript → HTML → CSS → JSON → SQL → Python → Ruby
5372
+ * → Bash → C++ → C# → C → XML
5373
+ *
5374
+ * @param {string} code
5375
+ * @returns {string|null}
5376
+ */
5377
+ function detectLang(code) {
5378
+ if (!code || !code.trim()) return null;
5379
+ const s = code.trim();
5380
+ if (/(:\s*(string|number|boolean|void|never|any|unknown)\b|interface\s+\w+\s*\{|type\s+\w+\s*[=<(]|<\w+>\s*[;,)]|readonly\s+\w|enum\s+\w+\s*\{|\?\s*:\s*\w|as\s+\w+\s*[;,)\]])/.test(s)) return "typescript";
5381
+ if (/\bprintln!\s*\(|\bprint!\s*\(|\bfn\s+\w+\s*(<[^>]*>)?\s*\(|\blet\s+mut\s|\bpub\s+fn\s|\buse\s+std::|\bimpl\s+\w+|\bOption<|\bResult<\w+/.test(s)) return "rust";
5382
+ if (/(<\?php\b|<\?=|\becho\s+.*\$\w|\$this->|\$\w+\s*=\s*\w|\bforeach\s*\(\s*\$|Illuminate\\)/.test(s)) return "php";
5383
+ if (/\bpublic\s+(class|static|void|int|String)\s+\w|System\.out\.(print|println)\s*\(|@(Override|Autowired|Component|Service|Controller)\b|import\s+java\.(util|io|lang|net)\.|throws\s+\w+Exception/.test(s)) return "java";
5384
+ if (/\bfun\s+\w+\s*\(|\bdata\s+class\s+\w+|\bcompanion\s+object\b|\bval\s+\w+\s*:\s*\w|\bprintln\s*\(/.test(s)) return "kotlin";
5385
+ if (/\bguard\s+(let|var)\b|\bprotocol\s+\w+\s*\{|\bextension\s+\w+|\bfunc\s+\w+[^(]*\([^)]*\)\s*->\s*\w|\blet\s+\w+\s*:\s*[A-Z]\w*|\bSwiftUI\b/.test(s)) return "swift";
5386
+ if (/\bpackage\s+\w+\b|\bfmt\.(Print|Println|Sprintf|Errorf|Fprintf)\s*\(|:=\s*\w|\bgoroutine\b|\bchan\s+\w|\bgo\s+func\b/.test(s)) return "go";
5387
+ if (/\b(const\s+\w|let\s+\w+\s*=|var\s+\w+\s*=|function\s+\w|\=>\s*[{(]|import\s+.*\bfrom\b\s*['"]|require\s*\(|console\.(log|error|warn|info)|document\.\w|window\.\w|async\s+function|\bPromise\b|React\.|useState\s*\(|\.then\s*\()/.test(s)) return "javascript";
5388
+ if (/^<!DOCTYPE html/i.test(s) || /<(html|head|body|div|section|article|nav|p|a|img|ul|ol|li|table|form|input|button|script|style)\b[^>]*>/i.test(s)) return "html";
5389
+ if (/(^|\n)\s*(\/\/\s+\S|&[:.[\w]|\$\w+\s*:|@(mixin|include|extend|each|if|for|use|forward)\b|#\{)/.test(s) && /[\w#.*&[\]:(),>+~ -]+\s*\{/.test(s)) return "scss";
5390
+ if (/(^|\n)\s*[\w#.*:[\]&, +-]+\s*\{[^}]*[\w-]+\s*:[^{}:;]+[;}\n]/m.test(s) && !/<\w|function\s|def\s|:\s*(string|number)/.test(s)) return "css";
5391
+ if (/^\s*[{[]/.test(s) && /"\w[\w\s-]*"\s*:/.test(s) && !/\bfunction\b|\bdef\b/.test(s)) return "json";
5392
+ if (/(^|\n)\s*(SELECT\s|INSERT\s+INTO|UPDATE\s+\w|DELETE\s+FROM|CREATE\s+(TABLE|DATABASE|INDEX|VIEW)|DROP\s+(TABLE|DATABASE)|ALTER\s+TABLE|WITH\s+\w+\s+AS\s*\()/im.test(s)) return "sql";
5393
+ if (/\bdef\s+\w+\s*\([^)]*\)\s*:|(^|\n)\s*class\s+\w+.*:\s*$|(^|\n)\s*import\s+\w|(^|\n)\s*from\s+\w+\s+import\s+|\bprint\s*\(|if\s+__name__\s*==\s*['"]__main__['"]/m.test(s)) return "python";
5394
+ if (/\bputs\s+\S|\battr_(accessor|reader|writer)\s|\.each\s+do\s*\|\w+\s*\||\bdo\s*\|\w+\s*\|.*\bend\b|\bdef\s+\w+[^:]*\n[\s\S]*?\bend\b/.test(s)) return "ruby";
5395
+ if (/^#!.*\/(ba|z|da|fi|k)?sh\b/m.test(s) || /\b(echo\s+["']|grep\s+|awk\s+|sed\s+['"\\/-]|chmod\s+|sudo\s+|apt(-get)?\s+install|brew\s+install|npm\s+(install|run|start|build)|pip\s+(install|3\s)|docker\s+(run|build|compose)|kubectl\s+|git\s+(clone|add|commit|push|pull|checkout))\b/.test(s)) return "bash";
5396
+ if (/\bcout\s*<<|\bcin\s*>>|using\s+namespace\s+std\b|std::\w|\btemplate\s*<\w|\b#include\s*<(iostream|vector|map|set|algorithm|string|memory)>/.test(s)) return "cpp";
5397
+ if (/\busing\s+System\b|Console\.(Write|WriteLine)\s*\(|\bget;\s*set;|\basync\s+Task[<\s]|IEnumerable<|\bLINQ\b|\.Select\s*\(|\.Where\s*\(/.test(s)) return "csharp";
5398
+ if (/\b#include\s*<(stdio|stdlib|string|math|time|ctype)\.h>|\bprintf\s*\(|\bscanf\s*\(|int\s+main\s*\(\s*(void|int\s+argc)|\bmalloc\s*\(|\bfree\s*\(/.test(s) && !/namespace|cout|cin|std::/.test(s)) return "c";
5399
+ if (/^<\?xml\s/i.test(s) || /xmlns:|<\/[\w:]+>/.test(s)) return "xml";
5400
+ return null;
5401
+ }
5402
+ //#endregion
5290
5403
  //#region src/js/module/Editor.js
5291
5404
  /**
5292
5405
  * Editor.js - Core editing command module
@@ -5341,7 +5454,8 @@ var Editor = class {
5341
5454
  if (!r.collapsed) return;
5342
5455
  const sc = r.startContainer;
5343
5456
  if (sc.nodeType !== Node.ELEMENT_NODE) return;
5344
- const li = sc.matches && sc.matches(".an-checklist li") ? sc : null;
5457
+ const scEl = sc;
5458
+ const li = scEl.matches(".an-checklist li") ? scEl : null;
5345
5459
  if (!li) return;
5346
5460
  const cb = li.querySelector("input[type=\"checkbox\"]");
5347
5461
  if (!cb) return;
@@ -5381,7 +5495,7 @@ var Editor = class {
5381
5495
  return;
5382
5496
  }
5383
5497
  const target = e.target;
5384
- if (target && (target.nodeName === "IFRAME" || target.closest && target.closest(".an-video-wrapper"))) e.preventDefault();
5498
+ if (target && (target.nodeName === "IFRAME" || target.closest(".an-video-wrapper"))) e.preventDefault();
5385
5499
  }), on(editable, "drop", (e) => {
5386
5500
  if (isReadOnly()) e.preventDefault();
5387
5501
  }));
@@ -5395,9 +5509,12 @@ var Editor = class {
5395
5509
  }
5396
5510
  let node = sel.getRangeAt(0).startContainer;
5397
5511
  if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
5398
- if (node && node.closest) if (node.closest("sup")) _compositionSupSub = "superscript";
5399
- else if (node.closest("sub")) _compositionSupSub = "subscript";
5400
- else _compositionSupSub = null;
5512
+ if (node) {
5513
+ const el = node;
5514
+ if (el.closest("sup")) _compositionSupSub = "superscript";
5515
+ else if (el.closest("sub")) _compositionSupSub = "subscript";
5516
+ else _compositionSupSub = null;
5517
+ }
5401
5518
  };
5402
5519
  const onCompositionEnd = () => {
5403
5520
  const tag = _compositionSupSub;
@@ -5407,7 +5524,8 @@ var Editor = class {
5407
5524
  if (!sel || !sel.rangeCount) return;
5408
5525
  let node = sel.getRangeAt(0).startContainer;
5409
5526
  if (node.nodeType === Node.TEXT_NODE) node = node.parentElement;
5410
- if (!(node && node.closest && (tag === "superscript" ? node.closest("sup") : node.closest("sub")))) document.execCommand(tag);
5527
+ const el = node;
5528
+ if (!(el && (tag === "superscript" ? el.closest("sup") : el.closest("sub")))) document.execCommand(tag);
5411
5529
  };
5412
5530
  this._disposers.push(on(editable, "compositionstart", onCompositionStart), on(editable, "compositionend", onCompositionEnd));
5413
5531
  }
@@ -5496,6 +5614,7 @@ var Editor = class {
5496
5614
  }
5497
5615
  afterCommand() {
5498
5616
  this._cleanOrphanedFigures();
5617
+ this._ensureTrailingParagraph();
5499
5618
  this.context.invoke("toolbar.refresh");
5500
5619
  this.context.invoke("statusbar.update");
5501
5620
  this._scheduleSnapshot();
@@ -5522,6 +5641,31 @@ var Editor = class {
5522
5641
  if (!fig.querySelector("img")) fig.parentNode.removeChild(fig);
5523
5642
  });
5524
5643
  }
5644
+ /**
5645
+ * Ensures the editable always ends with a plain paragraph so the cursor can
5646
+ * be placed after block elements that do not naturally allow it
5647
+ * (pre, blockquote, table, figure, ul, ol, hr).
5648
+ * Without this, clicking below the last such element does nothing.
5649
+ */
5650
+ _ensureTrailingParagraph() {
5651
+ const editable = this.context.layoutInfo.editable;
5652
+ if (!editable) return;
5653
+ const last = editable.lastElementChild;
5654
+ if (!last) return;
5655
+ if (new Set([
5656
+ "PRE",
5657
+ "BLOCKQUOTE",
5658
+ "TABLE",
5659
+ "FIGURE",
5660
+ "UL",
5661
+ "OL",
5662
+ "HR"
5663
+ ]).has(last.nodeName)) {
5664
+ const p = document.createElement("p");
5665
+ p.innerHTML = "<br>";
5666
+ editable.appendChild(p);
5667
+ }
5668
+ }
5525
5669
  focus() {
5526
5670
  this.context.layoutInfo.editable.focus();
5527
5671
  }
@@ -5705,10 +5849,24 @@ var Editor = class {
5705
5849
  this.context.print();
5706
5850
  }
5707
5851
  /**
5708
- * @param {string} tagName - e.g. 'h1', 'p', 'blockquote'
5852
+ * @param {string} tagName - e.g. 'h1', 'p', 'blockquote', 'pre'
5709
5853
  */
5710
5854
  formatBlock(tagName) {
5711
5855
  formatBlock(tagName);
5856
+ if (tagName === "pre") {
5857
+ const sel = window.getSelection();
5858
+ if (sel && sel.rangeCount > 0) {
5859
+ const container = sel.getRangeAt(0).commonAncestorContainer;
5860
+ const pre = container.nodeType === 1 ? container.closest("pre") : container.parentElement?.closest("pre");
5861
+ if (pre && !pre.getAttribute("data-language")) {
5862
+ const lang = detectLang(pre.textContent || "");
5863
+ if (lang) {
5864
+ this.context.invoke("codeTooltip.applyLanguage", pre, lang);
5865
+ return;
5866
+ }
5867
+ }
5868
+ }
5869
+ }
5712
5870
  this.afterCommand();
5713
5871
  }
5714
5872
  /**
@@ -5765,8 +5923,8 @@ var Editor = class {
5765
5923
  if (openInNewTab) {
5766
5924
  const link = this._getClosestAnchor();
5767
5925
  if (link) {
5768
- link.setAttribute("target", "_blank");
5769
- link.setAttribute("rel", "noopener noreferrer");
5926
+ /** @type {Element} */ link.setAttribute("target", "_blank");
5927
+ /** @type {Element} */ link.setAttribute("rel", "noopener noreferrer");
5770
5928
  }
5771
5929
  }
5772
5930
  }
@@ -6048,13 +6206,13 @@ var Toolbar = class {
6048
6206
  else openPopup();
6049
6207
  });
6050
6208
  const d2 = on(grid, "mouseover", (e) => {
6051
- const cell = e.target.closest(".an-table-cell");
6209
+ const cell = e.target?.closest(".an-table-cell");
6052
6210
  if (!cell) return;
6053
6211
  setHighlight(+cell.getAttribute("data-row"), +cell.getAttribute("data-col"));
6054
6212
  });
6055
6213
  const d3 = on(grid, "mouseleave", () => setHighlight(0, 0));
6056
6214
  const d4 = on(grid, "click", (e) => {
6057
- const cell = e.target.closest(".an-table-cell");
6215
+ const cell = e.target?.closest(".an-table-cell");
6058
6216
  if (!cell) return;
6059
6217
  const rows = +cell.getAttribute("data-row");
6060
6218
  const cols = +cell.getAttribute("data-col");
@@ -6217,11 +6375,17 @@ var Toolbar = class {
6217
6375
  e.preventDefault();
6218
6376
  });
6219
6377
  const d3b = on(swatches, "click", (e) => {
6220
- const sw = e.target.closest(".an-color-swatch");
6221
- if (sw) applyColor(sw.dataset.color);
6378
+ const sw = e.target?.closest(".an-color-swatch");
6379
+ if (sw) applyColor(
6380
+ /** @type {HTMLElement} */
6381
+ sw.dataset.color
6382
+ );
6222
6383
  });
6223
6384
  const d4 = on(colorInput, "change", (e) => {
6224
- applyColor(e.target.value);
6385
+ applyColor(
6386
+ /** @type {HTMLInputElement} */
6387
+ e.target.value
6388
+ );
6225
6389
  });
6226
6390
  const d5 = on(document, "click", (e) => {
6227
6391
  if (isOpen && !wrap.contains(e.target) && !popup.contains(e.target)) closePopup();
@@ -6356,15 +6520,17 @@ var Toolbar = class {
6356
6520
  this.el.querySelectorAll("button[data-btn]").forEach((btn) => {
6357
6521
  const def = btnMap.get(btn.getAttribute("data-btn"));
6358
6522
  if (def && typeof def.isActive === "function") btn.classList.toggle("active", !!def.isActive(this.context));
6359
- if (def && typeof def.isDisabled === "function") btn.disabled = !!def.isDisabled(this.context);
6523
+ if (def && typeof def.isDisabled === "function")
6524
+ /** @type {HTMLButtonElement} */ btn.disabled = !!def.isDisabled(this.context);
6360
6525
  });
6361
6526
  this.el.querySelectorAll("select[data-btn]").forEach((select) => {
6362
6527
  const def = btnMap.get(select.getAttribute("data-btn"));
6363
6528
  if (!def || typeof def.getValue !== "function") return;
6364
6529
  let raw = (def.getValue(this.context) || "").replace(/["']/g, "").trim();
6365
6530
  if (!raw) raw = this.options.defaultFontFamily || this.options.fontFamilies && this.options.fontFamilies[0] || "";
6366
- const matched = Array.from(select.options).find((opt) => opt.value && opt.value.toLowerCase() === raw.toLowerCase());
6367
- select.value = matched ? matched.value : "";
6531
+ const sel = select;
6532
+ const matched = Array.from(sel.options).find((opt) => opt.value && opt.value.toLowerCase() === raw.toLowerCase());
6533
+ sel.value = matched ? matched.value : "";
6368
6534
  });
6369
6535
  }
6370
6536
  /**
@@ -7158,8 +7324,13 @@ var LinkDialog = class {
7158
7324
  "aria-label": L.ariaLabel
7159
7325
  });
7160
7326
  const box = createElement("div", { class: "an-dialog-box" });
7327
+ const header = createElement("div", { class: "an-dialog-header" });
7328
+ const iconEl = createElement("span", { class: "an-dialog-icon" });
7329
+ iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`;
7161
7330
  const title = createElement("h3", { class: "an-dialog-title" });
7162
7331
  title.textContent = L.title;
7332
+ header.appendChild(iconEl);
7333
+ header.appendChild(title);
7163
7334
  const urlLabel = createElement("label", { class: "an-label" });
7164
7335
  urlLabel.textContent = L.url;
7165
7336
  const urlInput = createElement("input", {
@@ -7204,8 +7375,9 @@ var LinkDialog = class {
7204
7375
  cancelBtn.textContent = L.cancelBtn;
7205
7376
  btnRow.appendChild(insertBtn);
7206
7377
  btnRow.appendChild(cancelBtn);
7207
- box.append(title, urlLabel, urlInput, textLabel, textInput, tabLabel, btnRow);
7378
+ box.append(header, urlLabel, urlInput, textLabel, textInput, tabLabel, btnRow);
7208
7379
  overlay.appendChild(box);
7380
+ makeDraggable(header, box);
7209
7381
  const d1 = on(insertBtn, "click", () => this._onInsert());
7210
7382
  const d2 = on(cancelBtn, "click", () => this._close());
7211
7383
  const d3 = on(overlay, "click", (e) => {
@@ -7335,8 +7507,13 @@ var ImageDialog = class {
7335
7507
  "aria-label": L.ariaLabel
7336
7508
  });
7337
7509
  const box = createElement("div", { class: "an-dialog-box" });
7510
+ const header = createElement("div", { class: "an-dialog-header" });
7511
+ const iconEl = createElement("span", { class: "an-dialog-icon" });
7512
+ iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>`;
7338
7513
  const title = createElement("h3", { class: "an-dialog-title" });
7339
7514
  title.textContent = L.title;
7515
+ header.appendChild(iconEl);
7516
+ header.appendChild(title);
7340
7517
  const urlLabel = createElement("label", { class: "an-label" });
7341
7518
  urlLabel.textContent = L.imageUrl;
7342
7519
  const urlInput = createElement("input", {
@@ -7355,7 +7532,7 @@ var ImageDialog = class {
7355
7532
  autocomplete: "off"
7356
7533
  });
7357
7534
  this._altInput = altInput;
7358
- box.append(title, urlLabel, urlInput, altLabel, altInput);
7535
+ box.append(header, urlLabel, urlInput, altLabel, altInput);
7359
7536
  const alignLabel = createElement("label", { class: "an-label" });
7360
7537
  alignLabel.textContent = L.alignment;
7361
7538
  const alignRow = createElement("div", { class: "an-align-row" });
@@ -7424,6 +7601,7 @@ var ImageDialog = class {
7424
7601
  btnRow.appendChild(cancelBtn);
7425
7602
  box.append(btnRow);
7426
7603
  overlay.appendChild(box);
7604
+ makeDraggable(header, box);
7427
7605
  const d1 = on(insertBtn, "click", () => this._onInsert());
7428
7606
  const d2 = on(cancelBtn, "click", () => this._close());
7429
7607
  const d3 = on(overlay, "click", (e) => {
@@ -7561,8 +7739,13 @@ var VideoDialog = class {
7561
7739
  "aria-label": L.ariaLabel
7562
7740
  });
7563
7741
  const box = createElement("div", { class: "an-dialog-box" });
7742
+ const header = createElement("div", { class: "an-dialog-header" });
7743
+ const iconEl = createElement("span", { class: "an-dialog-icon" });
7744
+ iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>`;
7564
7745
  const title = createElement("h3", { class: "an-dialog-title" });
7565
7746
  title.textContent = L.title;
7747
+ header.appendChild(iconEl);
7748
+ header.appendChild(title);
7566
7749
  const urlLabel = createElement("label", { class: "an-label" });
7567
7750
  urlLabel.textContent = L.videoUrl;
7568
7751
  const urlInput = createElement("input", {
@@ -7598,8 +7781,9 @@ var VideoDialog = class {
7598
7781
  cancelBtn.textContent = L.cancelBtn;
7599
7782
  btnRow.appendChild(insertBtn);
7600
7783
  btnRow.appendChild(cancelBtn);
7601
- box.append(title, urlLabel, urlInput, hintEl, widthLabel, widthInput, btnRow);
7784
+ box.append(header, urlLabel, urlInput, hintEl, widthLabel, widthInput, btnRow);
7602
7785
  overlay.appendChild(box);
7786
+ makeDraggable(header, box);
7603
7787
  const d0 = on(urlInput, "input", () => {
7604
7788
  const info = this._parseVideoUrl(urlInput.value.trim());
7605
7789
  hintEl.textContent = info ? this.context.locale.videoDialog.detected(info.type) : urlInput.value ? this.context.locale.videoDialog.unknownFormat : "";
@@ -7782,7 +7966,7 @@ var ImageResizer = class {
7782
7966
  };
7783
7967
  this._disposers.push(on(editable, "click", (e) => this._onEditorClick(e)), on(editable, "contextmenu", (e) => {
7784
7968
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
7785
- const img = e.target.closest("img");
7969
+ const img = e.target?.closest("img");
7786
7970
  if (img) this._select(img);
7787
7971
  }), on(document, "click", (e) => this._onDocClick(e)), on(window, "scroll", () => this._updateOverlayPosition(), { passive: true }), on(window, "resize", onWindowResize, { passive: true }), on(editable, "scroll", () => this._updateOverlayPosition(), { passive: true }));
7788
7972
  return this;
@@ -8192,12 +8376,12 @@ var LinkTooltip = class {
8192
8376
  document.body.appendChild(this._el);
8193
8377
  const editable = this.context.layoutInfo.editable;
8194
8378
  this._disposers.push(on(editable, "mouseover", (e) => {
8195
- const anchor = e.target.closest("a[href]");
8379
+ const anchor = e.target?.closest("a[href]");
8196
8380
  if (anchor && editable.contains(anchor)) this._scheduleShow(anchor);
8197
8381
  }), on(editable, "mouseout", (e) => {
8198
8382
  const to = e.relatedTarget;
8199
8383
  if (!to || !editable.contains(to) && !this._el.contains(to)) this._scheduleHide();
8200
- }));
8384
+ }), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
8201
8385
  return this;
8202
8386
  }
8203
8387
  destroy() {
@@ -8382,14 +8566,15 @@ var ImageTooltip = class {
8382
8566
  const editable = this.context.layoutInfo.editable;
8383
8567
  this._disposers.push(on(editable, "mouseover", (e) => {
8384
8568
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
8385
- const img = e.target.closest("img");
8569
+ const img = e.target?.closest("img");
8386
8570
  if (img && editable.contains(img) && !img.closest("a[href]")) this._scheduleShow(img);
8387
8571
  }, { passive: true }), on(editable, "mouseout", (e) => {
8388
8572
  const to = e.relatedTarget;
8389
8573
  if (!to || !editable.contains(to) && !this._el.contains(to)) this._scheduleHide();
8390
8574
  }, { passive: true }), on(document, "click", (e) => {
8391
- if (this._activeImg && !this._activeImg.contains(e.target) && !this._el.contains(e.target)) this._hide();
8392
- }));
8575
+ const et = e.target;
8576
+ if (this._activeImg && !this._activeImg.contains(et) && !this._el.contains(et)) this._hide();
8577
+ }), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
8393
8578
  return this;
8394
8579
  }
8395
8580
  destroy() {
@@ -8473,7 +8658,7 @@ var ImageTooltip = class {
8473
8658
  clearTimeout(this._hideTimer);
8474
8659
  this._hideTimer = setTimeout(() => this._hide(), HIDE_DELAY$3);
8475
8660
  }
8476
- _show(img) {
8661
+ _show(_img) {
8477
8662
  this._el.style.display = "flex";
8478
8663
  requestAnimationFrame(() => {
8479
8664
  if (this._activeImg) this._positionNear(this._activeImg);
@@ -8665,14 +8850,16 @@ var VideoTooltip = class {
8665
8850
  const editable = this.context.layoutInfo.editable;
8666
8851
  this._disposers.push(on(editable, "mouseover", (e) => {
8667
8852
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
8668
- const wrapper = e.target.closest(".an-video-wrapper");
8853
+ const target = e.target;
8854
+ const wrapper = target && target.closest ? target.closest(".an-video-wrapper") : null;
8669
8855
  if (wrapper && editable.contains(wrapper)) this._scheduleShow(wrapper);
8670
8856
  }, { passive: true }), on(editable, "mouseout", (e) => {
8671
8857
  const to = e.relatedTarget;
8672
8858
  if (!to || !editable.contains(to) && !this._el.contains(to)) this._scheduleHide();
8673
8859
  }, { passive: true }), on(document, "click", (e) => {
8674
- if (this._activeWrapper && !this._activeWrapper.contains(e.target) && !this._el.contains(e.target)) this._hide();
8675
- }));
8860
+ const target = e.target;
8861
+ if (this._activeWrapper && !this._activeWrapper.contains(target) && !this._el.contains(target)) this._hide();
8862
+ }), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
8676
8863
  return this;
8677
8864
  }
8678
8865
  destroy() {
@@ -8752,7 +8939,7 @@ var VideoTooltip = class {
8752
8939
  if (this._hideTimer) return;
8753
8940
  this._hideTimer = setTimeout(() => this._hide(), HIDE_DELAY$2);
8754
8941
  }
8755
- _show(wrapper) {
8942
+ _show(_wrapper) {
8756
8943
  this._el.style.display = "flex";
8757
8944
  requestAnimationFrame(() => {
8758
8945
  if (this._activeWrapper) this._positionNear(this._activeWrapper);
@@ -8976,8 +9163,35 @@ var ICONS$2 = {
8976
9163
  rowHeight: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="17" x2="20" y2="17"/><line x1="12" y1="7" x2="12" y2="17"/><path d="M9 10l3-3 3 3"/><path d="M9 14l3 3 3-3"/></svg>`,
8977
9164
  tableBorder: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round"><line x1="3" y1="6" x2="21" y2="6" stroke-width="1"/><line x1="3" y1="13" x2="21" y2="13" stroke-width="2"/><line x1="3" y1="20" x2="21" y2="20" stroke-width="3"/></svg>`,
8978
9165
  deleteTable: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="1"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="15" y1="3" x2="15" y2="21"/><line x1="16" y1="16" x2="22" y2="22" stroke="#ef4444"/><line x1="22" y1="16" x2="16" y2="22" stroke="#ef4444"/></svg>`,
8979
- selectCells: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4 L4 20 L9 15 L12 21 L14 20 L11 14 L17 14 Z" fill="currentColor" opacity="0.15"/><path d="M4 4 L4 20 L9 15 L12 21 L14 20 L11 14 L17 14 Z"/></svg>`
9166
+ selectCells: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4 L4 20 L9 15 L12 21 L14 20 L11 14 L17 14 Z" fill="currentColor" opacity="0.15"/><path d="M4 4 L4 20 L9 15 L12 21 L14 20 L11 14 L17 14 Z"/></svg>`,
9167
+ cellShade: `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 11L8.93 3.36a1 1 0 0 0-1.29.08L3.22 7.8a1 1 0 0 0-.07 1.29L11 20"/><path d="m5 14 5-5"/><path d="M22 22a2 2 0 0 1-2 2h-3a2 2 0 0 1-2-2c0-1.5 2.5-5 3.5-5s3.5 3.5 3.5 5z"/></svg>`
8980
9168
  };
9169
+ var SHADE_PRESETS = [
9170
+ "#000000",
9171
+ "#434343",
9172
+ "#666666",
9173
+ "#999999",
9174
+ "#b7b7b7",
9175
+ "#cccccc",
9176
+ "#efefef",
9177
+ "#ffffff",
9178
+ "#ff0000",
9179
+ "#ff9900",
9180
+ "#ffff00",
9181
+ "#00ff00",
9182
+ "#00ffff",
9183
+ "#4a86e8",
9184
+ "#9900ff",
9185
+ "#ff00ff",
9186
+ "#f4cccc",
9187
+ "#fce5cd",
9188
+ "#fff2cc",
9189
+ "#d9ead3",
9190
+ "#d0e0e3",
9191
+ "#c9daf8",
9192
+ "#d9d2e9",
9193
+ "#ead1dc"
9194
+ ];
8981
9195
  var TableTooltip = class {
8982
9196
  /** @param {import('../Context.js').Context} context */
8983
9197
  constructor(context) {
@@ -8992,6 +9206,9 @@ var TableTooltip = class {
8992
9206
  this._sizeApply = null;
8993
9207
  this._sizeTitleEl = null;
8994
9208
  this._sizeInputEl = null;
9209
+ this._shadePopover = null;
9210
+ this._shadeTitleEl = null;
9211
+ this._shadeColorStrip = null;
8995
9212
  this._selectMode = false;
8996
9213
  this._selectedCells = [];
8997
9214
  this._selectStart = null;
@@ -9004,6 +9221,8 @@ var TableTooltip = class {
9004
9221
  document.body.appendChild(this._el);
9005
9222
  this._sizePopover = this._buildSizePopover();
9006
9223
  document.body.appendChild(this._sizePopover);
9224
+ this._shadePopover = this._buildCellShadePopover();
9225
+ document.body.appendChild(this._shadePopover);
9007
9226
  const editable = this.context.layoutInfo.editable;
9008
9227
  this._editable = editable;
9009
9228
  const onSelMousedown = (e) => {
@@ -9030,10 +9249,13 @@ var TableTooltip = class {
9030
9249
  this._disposers.push(on(editable, "mousedown", onSelMousedown), on(editable, "mousemove", onSelMousemove), on(document, "mouseup", onSelMouseup));
9031
9250
  this._disposers.push(on(editable, "mouseover", (e) => {
9032
9251
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
9033
- const table = e.target.closest("table");
9252
+ const table = e.target?.closest("table");
9034
9253
  if (table && editable.contains(table)) {
9035
- const cell = e.target.closest("td, th");
9036
- if (cell) this._activeCell = cell;
9254
+ const cell = e.target?.closest("td, th");
9255
+ if (cell) {
9256
+ this._activeCell = cell;
9257
+ this._syncShadeStrip();
9258
+ }
9037
9259
  this._scheduleShow(table);
9038
9260
  }
9039
9261
  }, { passive: true }), on(editable, "mouseout", (e) => {
@@ -9041,9 +9263,10 @@ var TableTooltip = class {
9041
9263
  const to = e.relatedTarget;
9042
9264
  if (!to || !editable.contains(to) && !this._el.contains(to) && !(this._sizePopover && this._sizePopover.contains(to))) this._scheduleHide();
9043
9265
  }, { passive: true }), on(document, "click", (e) => {
9044
- if (this._selectMode && this._activeTable && this._activeTable.contains(e.target)) return;
9045
- if (this._activeTable && !this._activeTable.contains(e.target) && !this._el.contains(e.target) && !(this._sizePopover && this._sizePopover.contains(e.target))) this._hide();
9046
- }));
9266
+ const et = e.target;
9267
+ if (this._selectMode && this._activeTable && this._activeTable.contains(et)) return;
9268
+ if (this._activeTable && !this._activeTable.contains(et) && !this._el.contains(et) && !(this._sizePopover && this._sizePopover.contains(et))) this._hide();
9269
+ }), on(document, "selectionchange", () => this._syncShadeStrip()), on(window, "scroll", () => this._hide(), { passive: true }), on(window, "resize", () => this._hide(), { passive: true }));
9047
9270
  this._initResize();
9048
9271
  return this;
9049
9272
  }
@@ -9173,6 +9396,8 @@ var TableTooltip = class {
9173
9396
  this._el = null;
9174
9397
  if (this._sizePopover && this._sizePopover.parentNode) this._sizePopover.parentNode.removeChild(this._sizePopover);
9175
9398
  this._sizePopover = null;
9399
+ if (this._shadePopover && this._shadePopover.parentNode) this._shadePopover.parentNode.removeChild(this._shadePopover);
9400
+ this._shadePopover = null;
9176
9401
  }
9177
9402
  _buildTooltip() {
9178
9403
  const L = this.context.locale.tooltips.table;
@@ -9200,6 +9425,24 @@ var TableTooltip = class {
9200
9425
  el.appendChild(this._makeBtn(ICONS$2.mergeCells, L.mergeCells, () => this._mergeCells()));
9201
9426
  el.appendChild(this._makeBtn(ICONS$2.unmergeCells, L.unmergeCells, () => this._unmergeCells()));
9202
9427
  el.appendChild(this._sep());
9428
+ const shadeBtn = createElement("button", {
9429
+ type: "button",
9430
+ class: "an-link-tooltip-btn an-link-tooltip-btn--shade",
9431
+ title: L.cellBackground
9432
+ });
9433
+ const shadeSvgWrap = createElement("span", { class: "an-bubble-btn-svg" });
9434
+ shadeSvgWrap.innerHTML = ICONS$2.cellShade;
9435
+ const shadeStrip = createElement("span", { class: "an-link-tooltip-color-strip" });
9436
+ shadeBtn.appendChild(shadeSvgWrap);
9437
+ shadeBtn.appendChild(shadeStrip);
9438
+ this._shadeColorStrip = shadeStrip;
9439
+ this._disposers.push(on(shadeBtn, "click", (e) => {
9440
+ e.preventDefault();
9441
+ e.stopPropagation();
9442
+ this._openCellShadePopover();
9443
+ }));
9444
+ el.appendChild(shadeBtn);
9445
+ el.appendChild(this._sep());
9203
9446
  el.appendChild(this._makeBtn(ICONS$2.colWidth, L.columnWidth, () => this._openSizePopover("col")));
9204
9447
  el.appendChild(this._makeBtn(ICONS$2.rowHeight, L.rowHeight, () => this._openSizePopover("row")));
9205
9448
  el.appendChild(this._makeBtn(ICONS$2.tableBorder, L.tableBorderWidth, () => this._openSizePopover("border")));
@@ -9208,6 +9451,7 @@ var TableTooltip = class {
9208
9451
  this._disposers.push(on(el, "mouseenter", () => this._clearTimers()), on(el, "mouseleave", () => {
9209
9452
  if (this._selectMode) return;
9210
9453
  if (this._sizePopover && this._sizePopover.style.display !== "none") return;
9454
+ if (this._shadePopover && this._shadePopover.style.display !== "none") return;
9211
9455
  this._scheduleHide();
9212
9456
  }));
9213
9457
  return el;
@@ -9254,10 +9498,16 @@ var TableTooltip = class {
9254
9498
  _show() {
9255
9499
  if (!this._activeTable) return;
9256
9500
  this._el.style.display = "flex";
9501
+ this._syncShadeStrip();
9257
9502
  requestAnimationFrame(() => {
9258
9503
  if (this._activeTable) this._positionNear(this._activeTable);
9259
9504
  });
9260
9505
  }
9506
+ _syncShadeStrip() {
9507
+ if (!this._shadeColorStrip || !this._el || this._el.style.display === "none") return;
9508
+ const cell = this._getCell();
9509
+ this._shadeColorStrip.style.background = cell && cell.style.backgroundColor || "transparent";
9510
+ }
9261
9511
  _hide() {
9262
9512
  this._el.style.display = "none";
9263
9513
  this._activeTable = null;
@@ -9296,7 +9546,7 @@ var TableTooltip = class {
9296
9546
  if (sel && sel.rangeCount) {
9297
9547
  let container = sel.getRangeAt(0).commonAncestorContainer;
9298
9548
  if (container.nodeType === 3) container = container.parentElement;
9299
- const cellFromSel = container && container.closest && container.closest("td, th");
9549
+ const cellFromSel = container && container.closest("td, th");
9300
9550
  if (cellFromSel && this._activeTable && this._activeTable.contains(cellFromSel)) return cellFromSel;
9301
9551
  }
9302
9552
  return this._activeCell || this._activeTable && this._activeTable.querySelector("td, th");
@@ -9623,14 +9873,16 @@ var TableTooltip = class {
9623
9873
  });
9624
9874
  const d2 = on(cancelBtn, "click", () => this._hideSizePopover());
9625
9875
  const d3 = on(inputEl, "keydown", (e) => {
9626
- if (e.key === "Enter") {
9876
+ const ke = e;
9877
+ if (ke.key === "Enter") {
9627
9878
  e.preventDefault();
9628
9879
  applyBtn.click();
9629
9880
  }
9630
- if (e.key === "Escape") this._hideSizePopover();
9881
+ if (ke.key === "Escape") this._hideSizePopover();
9631
9882
  });
9632
9883
  const d4 = on(document, "click", (e) => {
9633
- if (this._sizePopover && this._sizePopover.style.display !== "none" && !this._sizePopover.contains(e.target) && !this._el.contains(e.target)) this._hideSizePopover();
9884
+ const et = e.target;
9885
+ if (this._sizePopover && this._sizePopover.style.display !== "none" && !this._sizePopover.contains(et) && !this._el.contains(et)) this._hideSizePopover();
9634
9886
  });
9635
9887
  const d5 = on(popover, "mouseenter", () => this._clearTimers());
9636
9888
  const d6 = on(popover, "mouseleave", () => this._scheduleHide());
@@ -9648,7 +9900,7 @@ var TableTooltip = class {
9648
9900
  this._sizeTitleEl.textContent = this.context.locale.tooltips.table.tableBorderWidthPx;
9649
9901
  this._sizeInputEl.min = "0";
9650
9902
  this._sizeInputEl.max = "10";
9651
- this._sizeInputEl.value = currentPx;
9903
+ this._sizeInputEl.value = String(currentPx);
9652
9904
  this._sizeApply = (val) => {
9653
9905
  const cells = Array.from(table.querySelectorAll("td, th"));
9654
9906
  if (val === 0) cells.forEach((c) => {
@@ -9717,6 +9969,85 @@ var TableTooltip = class {
9717
9969
  if (this._sizePopover) this._sizePopover.style.display = "none";
9718
9970
  this._sizeApply = null;
9719
9971
  }
9972
+ _buildCellShadePopover() {
9973
+ const pop = createElement("div", { class: "an-cell-shade-popover" });
9974
+ pop.style.display = "none";
9975
+ const title = createElement("div", { class: "an-size-popover-title" });
9976
+ pop.appendChild(title);
9977
+ this._shadeTitleEl = title;
9978
+ const palette = createElement("div", { class: "an-context-color-palette" });
9979
+ SHADE_PRESETS.forEach((color) => {
9980
+ const sw = createElement("div", {
9981
+ class: "an-context-color-swatch",
9982
+ title: color
9983
+ });
9984
+ sw.style.background = color;
9985
+ this._disposers.push(on(sw, "click", (e) => {
9986
+ e.stopPropagation();
9987
+ this._applyCellShade(color);
9988
+ }));
9989
+ palette.appendChild(sw);
9990
+ });
9991
+ pop.appendChild(palette);
9992
+ const noShadeRow = createElement("div", { class: "an-context-color-custom" });
9993
+ const noShadeBtn = createElement("button", {
9994
+ type: "button",
9995
+ class: "an-shade-no-color"
9996
+ });
9997
+ this._disposers.push(on(noShadeBtn, "click", () => this._applyCellShade("")));
9998
+ noShadeRow.appendChild(noShadeBtn);
9999
+ pop.appendChild(noShadeRow);
10000
+ this._shadeNoBtn = noShadeBtn;
10001
+ const customRow = createElement("div", { class: "an-context-color-custom" });
10002
+ const colorInput = createElement("input", {
10003
+ type: "color",
10004
+ class: "an-shade-color-input",
10005
+ value: "#ffffff"
10006
+ });
10007
+ const customLabel = createElement("span");
10008
+ customLabel.textContent = "Custom…";
10009
+ this._disposers.push(on(colorInput, "change", () => this._applyCellShade(colorInput.value)));
10010
+ customRow.appendChild(colorInput);
10011
+ customRow.appendChild(customLabel);
10012
+ pop.appendChild(customRow);
10013
+ this._disposers.push(on(pop, "mousedown", (e) => e.preventDefault()));
10014
+ this._disposers.push(on(pop, "mouseenter", () => this._clearTimers()), on(pop, "mouseleave", () => this._scheduleHide()));
10015
+ this._disposers.push(on(document, "click", (e) => {
10016
+ const et = e.target;
10017
+ if (this._shadePopover && this._shadePopover.style.display !== "none" && !this._shadePopover.contains(et) && !(this._el && this._el.contains(et))) this._hideCellShadePopover();
10018
+ }));
10019
+ return pop;
10020
+ }
10021
+ _openCellShadePopover() {
10022
+ if (!this._shadePopover) return;
10023
+ const L = this.context.locale.tooltips.table;
10024
+ if (this._shadeTitleEl) this._shadeTitleEl.textContent = L.cellBackground;
10025
+ if (this._shadeNoBtn) this._shadeNoBtn.textContent = L.noShading;
10026
+ this._shadePopover.style.display = "block";
10027
+ requestAnimationFrame(() => {
10028
+ if (!this._shadePopover || !this._el) return;
10029
+ const pw = this._shadePopover.offsetWidth || 170;
10030
+ const ph = this._shadePopover.offsetHeight || 120;
10031
+ const tipRect = this._el.getBoundingClientRect();
10032
+ let left = tipRect.left;
10033
+ let top = tipRect.bottom + 6;
10034
+ if (left + pw > window.innerWidth - 8) left = window.innerWidth - pw - 8;
10035
+ if (top + ph > window.innerHeight - 8) top = tipRect.top - ph - 6;
10036
+ this._shadePopover.style.left = `${Math.max(8, left)}px`;
10037
+ this._shadePopover.style.top = `${Math.max(8, top)}px`;
10038
+ });
10039
+ }
10040
+ _hideCellShadePopover() {
10041
+ if (this._shadePopover) this._shadePopover.style.display = "none";
10042
+ }
10043
+ _applyCellShade(color) {
10044
+ (this._selectMode ? this._selectedCells : [this._getCell()]).forEach((cell) => {
10045
+ if (cell) cell.style.backgroundColor = color;
10046
+ });
10047
+ if (this._shadeColorStrip) this._shadeColorStrip.style.background = color || "transparent";
10048
+ this._hideCellShadePopover();
10049
+ this.context.invoke("editor.afterCommand");
10050
+ }
9720
10051
  };
9721
10052
  //#endregion
9722
10053
  //#region src/js/module/CodeTooltip.js
@@ -9749,13 +10080,14 @@ var CodeTooltip = class {
9749
10080
  const editable = this.context.layoutInfo.editable;
9750
10081
  this._disposers.push(on(editable, "mouseover", (e) => {
9751
10082
  if (this.context.layoutInfo.container.classList.contains("an-disabled")) return;
9752
- const pre = e.target.closest("pre");
10083
+ const pre = e.target?.closest("pre");
9753
10084
  if (pre && editable.contains(pre)) this._scheduleShow(pre);
9754
10085
  }), on(editable, "mouseout", (e) => {
9755
10086
  const to = e.relatedTarget;
9756
10087
  if (!to || !editable.contains(to) && !this._el.contains(to)) this._scheduleHide();
9757
10088
  }), on(document, "click", (e) => {
9758
- if (this._activePre && !this._activePre.contains(e.target) && !this._el.contains(e.target)) this._hide();
10089
+ const et = e.target;
10090
+ if (this._activePre && !this._activePre.contains(et) && !this._el.contains(et)) this._hide();
9759
10091
  }));
9760
10092
  return this;
9761
10093
  }
@@ -9790,6 +10122,7 @@ var CodeTooltip = class {
9790
10122
  ["python", "Python"],
9791
10123
  ["html", "HTML"],
9792
10124
  ["css", "CSS"],
10125
+ ["scss", "SCSS"],
9793
10126
  ["json", "JSON"],
9794
10127
  ["xml", "XML"],
9795
10128
  ["bash", "Bash / Shell"],
@@ -9945,10 +10278,27 @@ var CodeTooltip = class {
9945
10278
  this.context.invoke("editor.afterCommand");
9946
10279
  this._positionNear(pre);
9947
10280
  }
10281
+ /**
10282
+ * Applies a language to a given <pre> element: sets classes, data-language,
10283
+ * and triggers Prism highlighting. Called by the auto-detect flow.
10284
+ * @param {HTMLElement} pre
10285
+ * @param {string} lang - Prism language identifier, e.g. 'javascript'
10286
+ */
10287
+ applyLanguage(pre, lang) {
10288
+ if (!pre || !lang) return;
10289
+ const savedPre = this._activePre;
10290
+ this._langSelect && this._langSelect.value;
10291
+ this._activePre = pre;
10292
+ if (this._langSelect) this._langSelect.value = lang;
10293
+ this._onLangChange();
10294
+ if (this._langSelect) this._langSelect.value = lang;
10295
+ this._activePre = savedPre || pre;
10296
+ }
9948
10297
  _onLangChange() {
9949
10298
  const pre = this._activePre;
9950
10299
  if (!pre) return;
9951
10300
  const lang = this._langSelect.value;
10301
+ const _w = window;
9952
10302
  let codeEl = pre.querySelector("code");
9953
10303
  if (!codeEl) {
9954
10304
  codeEl = document.createElement("code");
@@ -9962,12 +10312,12 @@ var CodeTooltip = class {
9962
10312
  else pre.removeAttribute("data-language");
9963
10313
  const applyPrism = () => {
9964
10314
  codeEl.querySelectorAll("br").forEach((br) => br.replaceWith("\n"));
9965
- window.Prism.highlightElement(codeEl);
10315
+ _w.Prism.highlightElement(codeEl);
9966
10316
  this.context.invoke("editor.afterCommand");
9967
10317
  };
9968
10318
  if (lang) {
9969
- if (typeof window.Prism !== "undefined") {
9970
- if (window.Prism.languages[lang]) {
10319
+ if (typeof _w.Prism !== "undefined") {
10320
+ if (_w.Prism.languages[lang]) {
9971
10321
  applyPrism();
9972
10322
  return;
9973
10323
  }
@@ -9975,7 +10325,7 @@ var CodeTooltip = class {
9975
10325
  return;
9976
10326
  } else if (this._prismScript) {
9977
10327
  this._prismScript.addEventListener("load", () => {
9978
- if (window.Prism.languages[lang]) applyPrism();
10328
+ if (_w.Prism.languages[lang]) applyPrism();
9979
10329
  else this._loadPrismComponent(lang, applyPrism);
9980
10330
  }, { once: true });
9981
10331
  return;
@@ -9988,7 +10338,8 @@ var CodeTooltip = class {
9988
10338
  * Called once at initialize time. Fire-and-forget; errors are silent.
9989
10339
  */
9990
10340
  _ensurePrism() {
9991
- if (!this.context.options.codeHighlight || window.Prism) return;
10341
+ const _w = window;
10342
+ if (!this.context.options.codeHighlight || _w.Prism) return;
9992
10343
  const cdn = this.context.options.codeHighlightCDN;
9993
10344
  const themeHref = `${cdn}/themes/prism-tomorrow.min.css`;
9994
10345
  const scriptSrc = `${cdn}/prism.min.js`;
@@ -10000,7 +10351,7 @@ var CodeTooltip = class {
10000
10351
  }
10001
10352
  const existingScript = document.querySelector(`script[src="${scriptSrc}"]`);
10002
10353
  if (existingScript) {
10003
- this._prismScript = window.Prism ? null : existingScript;
10354
+ this._prismScript = _w.Prism ? null : existingScript;
10004
10355
  return;
10005
10356
  }
10006
10357
  const script = document.createElement("script");
@@ -10020,10 +10371,11 @@ var CodeTooltip = class {
10020
10371
  * @param {Function} cb – called once the grammar is ready
10021
10372
  */
10022
10373
  _loadPrismComponent(lang, cb) {
10374
+ const _w = window;
10023
10375
  const src = `${this.context.options.codeHighlightCDN}/components/prism-${lang}.min.js`;
10024
10376
  if (document.querySelector(`script[src="${src}"]`)) {
10025
10377
  const poll = setInterval(() => {
10026
- if (window.Prism && window.Prism.languages[lang]) {
10378
+ if (_w.Prism && _w.Prism.languages[lang]) {
10027
10379
  clearInterval(poll);
10028
10380
  cb();
10029
10381
  }
@@ -12436,15 +12788,19 @@ var EmojiDialog = class {
12436
12788
  });
12437
12789
  const box = createElement("div", { class: "an-dialog-box an-emoji-box" });
12438
12790
  const titleRow = createElement("div", { class: "an-icon-title-row" });
12791
+ const titleGroup = createElement("div", { class: "an-dialog-title-group" });
12792
+ const iconEl = createElement("span", { class: "an-dialog-icon an-dialog-icon--sm" });
12793
+ iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M8 13s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>`;
12439
12794
  const title = createElement("h3", { class: "an-dialog-title" });
12440
12795
  title.textContent = L.title;
12796
+ titleGroup.append(iconEl, title);
12441
12797
  const closeBtn = createElement("button", {
12442
12798
  type: "button",
12443
12799
  class: "an-icon-close",
12444
12800
  "aria-label": L.close
12445
12801
  });
12446
12802
  closeBtn.innerHTML = "&times;";
12447
- titleRow.append(title, closeBtn);
12803
+ titleRow.append(titleGroup, closeBtn);
12448
12804
  const searchInput = createElement("input", {
12449
12805
  type: "search",
12450
12806
  class: "an-input an-icon-search",
@@ -12493,6 +12849,7 @@ var EmojiDialog = class {
12493
12849
  btnRow.appendChild(cancelBtn);
12494
12850
  box.append(titleRow, searchInput, catBar, grid, btnRow);
12495
12851
  overlay.appendChild(box);
12852
+ makeDraggable(titleRow, box);
12496
12853
  const d1 = on(closeBtn, "click", () => this._close());
12497
12854
  const d2 = on(cancelBtn, "click", () => this._close());
12498
12855
  const d3 = on(overlay, "click", (e) => {
@@ -12500,7 +12857,7 @@ var EmojiDialog = class {
12500
12857
  });
12501
12858
  const d4 = on(searchInput, "input", () => this._filterEmojis(searchInput.value, this._activeCat));
12502
12859
  const d5 = on(catBar, "click", (e) => {
12503
- const tab = e.target.closest("[data-cat]");
12860
+ const tab = e.target?.closest("[data-cat]");
12504
12861
  if (tab) {
12505
12862
  this._activeCat = tab.dataset.cat;
12506
12863
  this._updateCatTabs();
@@ -12508,7 +12865,7 @@ var EmojiDialog = class {
12508
12865
  }
12509
12866
  });
12510
12867
  const d6 = on(grid, "click", (e) => {
12511
- const cell = e.target.closest(".an-emoji-cell");
12868
+ const cell = e.target?.closest(".an-emoji-cell");
12512
12869
  if (cell) this._onEmojiClick(cell.dataset.char);
12513
12870
  });
12514
12871
  this._disposers.push(d1, d2, d3, d4, d5, d6);
@@ -12516,17 +12873,22 @@ var EmojiDialog = class {
12516
12873
  }
12517
12874
  _updateCatTabs() {
12518
12875
  this._catBar.querySelectorAll(".an-icon-cat").forEach((tab) => {
12519
- tab.classList.toggle("active", tab.dataset.cat === this._activeCat);
12876
+ tab.classList.toggle(
12877
+ "active",
12878
+ /** @type {HTMLElement} */
12879
+ tab.dataset.cat === this._activeCat
12880
+ );
12520
12881
  });
12521
12882
  }
12522
12883
  _filterEmojis(query, cat) {
12523
12884
  const q = (query || "").trim().toLowerCase();
12524
12885
  let count = 0;
12525
12886
  this._grid.querySelectorAll(".an-emoji-cell").forEach((cell) => {
12526
- const matchCat = !cat || cat === "all" || cell.dataset.cat === cat;
12527
- const matchQuery = !q || cell.dataset.keywords.includes(q) || cell.dataset.char === q;
12887
+ const hCell = cell;
12888
+ const matchCat = !cat || cat === "all" || hCell.dataset.cat === cat;
12889
+ const matchQuery = !q || hCell.dataset.keywords.includes(q) || hCell.dataset.char === q;
12528
12890
  const visible = matchCat && matchQuery;
12529
- cell.style.display = visible ? "" : "none";
12891
+ hCell.style.display = visible ? "" : "none";
12530
12892
  if (visible) count++;
12531
12893
  });
12532
12894
  let empty = this._grid.querySelector(".an-icon-empty");
@@ -12535,7 +12897,7 @@ var EmojiDialog = class {
12535
12897
  empty.textContent = "No emojis found";
12536
12898
  this._grid.appendChild(empty);
12537
12899
  }
12538
- empty.style.display = count > 0 ? "none" : "";
12900
+ /** @type {HTMLElement} */ empty.style.display = count > 0 ? "none" : "";
12539
12901
  }
12540
12902
  _onEmojiClick(char) {
12541
12903
  const savedRange = this._savedRange;
@@ -12549,7 +12911,7 @@ var EmojiDialog = class {
12549
12911
  range.collapse(false);
12550
12912
  }
12551
12913
  const _sc = range.startContainer;
12552
- const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest?.("td, th");
12914
+ const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest("td, th");
12553
12915
  range.deleteContents();
12554
12916
  if (_tdAnchor && _tdAnchor.isConnected && !_tdAnchor.contains(range.startContainer)) {
12555
12917
  range.setStart(_tdAnchor, 0);
@@ -12909,15 +13271,19 @@ var IconDialog = class {
12909
13271
  });
12910
13272
  const box = createElement("div", { class: "an-dialog-box an-icon-box" });
12911
13273
  const titleRow = createElement("div", { class: "an-icon-title-row" });
13274
+ const titleGroup = createElement("div", { class: "an-dialog-title-group" });
13275
+ const iconEl = createElement("span", { class: "an-dialog-icon an-dialog-icon--sm" });
13276
+ iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>`;
12912
13277
  const title = createElement("h3", { class: "an-dialog-title" });
12913
13278
  title.textContent = L.title;
13279
+ titleGroup.append(iconEl, title);
12914
13280
  const closeBtn = createElement("button", {
12915
13281
  type: "button",
12916
13282
  class: "an-icon-close",
12917
13283
  "aria-label": L.close
12918
13284
  });
12919
13285
  closeBtn.innerHTML = "&times;";
12920
- titleRow.append(title, closeBtn);
13286
+ titleRow.append(titleGroup, closeBtn);
12921
13287
  const searchInput = createElement("input", {
12922
13288
  type: "search",
12923
13289
  class: "an-input an-icon-search",
@@ -13032,6 +13398,7 @@ var IconDialog = class {
13032
13398
  this._insertBtn = insertBtn;
13033
13399
  box.append(titleRow, searchInput, catBar, grid, optRow, preview, btnRow);
13034
13400
  overlay.appendChild(box);
13401
+ makeDraggable(titleRow, box);
13035
13402
  const d1 = on(closeBtn, "click", () => this._close());
13036
13403
  const d2 = on(cancelBtn, "click", () => this._close());
13037
13404
  const d3 = on(insertBtn, "click", () => this._onInsert());
@@ -13040,7 +13407,7 @@ var IconDialog = class {
13040
13407
  });
13041
13408
  const d5 = on(searchInput, "input", () => this._filterIcons(searchInput.value, this._activeCat));
13042
13409
  const d6 = on(catBar, "click", (e) => {
13043
- const tab = e.target.closest("[data-cat]");
13410
+ const tab = e.target?.closest("[data-cat]");
13044
13411
  if (tab) {
13045
13412
  this._activeCat = tab.dataset.cat;
13046
13413
  this._updateCatTabs();
@@ -13048,7 +13415,7 @@ var IconDialog = class {
13048
13415
  }
13049
13416
  });
13050
13417
  const d7 = on(grid, "click", (e) => {
13051
- const cell = e.target.closest(".an-icon-cell");
13418
+ const cell = e.target?.closest(".an-icon-cell");
13052
13419
  if (cell) this._selectIcon(cell.dataset.name);
13053
13420
  });
13054
13421
  const d8 = on(styleSelect, "change", () => this._updatePreview(this._selectedIcon));
@@ -13060,19 +13427,24 @@ var IconDialog = class {
13060
13427
  }
13061
13428
  _updateCatTabs() {
13062
13429
  this._catBar.querySelectorAll(".an-icon-cat").forEach((tab) => {
13063
- tab.classList.toggle("active", tab.dataset.cat === this._activeCat);
13430
+ tab.classList.toggle(
13431
+ "active",
13432
+ /** @type {HTMLElement} */
13433
+ tab.dataset.cat === this._activeCat
13434
+ );
13064
13435
  });
13065
13436
  }
13066
13437
  _filterIcons(query, cat) {
13067
13438
  const q = (query || "").trim().toLowerCase();
13068
13439
  let visibleCount = 0;
13069
13440
  this._grid.querySelectorAll(".an-icon-cell").forEach((cell) => {
13070
- const name = cell.dataset.name;
13071
- const cellCat = cell.dataset.cat;
13441
+ const hCell = cell;
13442
+ const name = hCell.dataset.name;
13443
+ const cellCat = hCell.dataset.cat;
13072
13444
  const matchesCat = !cat || cat === "all" || cellCat === cat;
13073
13445
  const matchesQuery = !q || name.includes(q);
13074
13446
  const visible = matchesCat && matchesQuery;
13075
- cell.style.display = visible ? "" : "none";
13447
+ hCell.style.display = visible ? "" : "none";
13076
13448
  if (visible) visibleCount++;
13077
13449
  });
13078
13450
  let empty = this._grid.querySelector(".an-icon-empty");
@@ -13081,12 +13453,16 @@ var IconDialog = class {
13081
13453
  empty.textContent = "No icons found";
13082
13454
  this._grid.appendChild(empty);
13083
13455
  }
13084
- empty.style.display = visibleCount > 0 ? "none" : "";
13456
+ /** @type {HTMLElement} */ empty.style.display = visibleCount > 0 ? "none" : "";
13085
13457
  }
13086
13458
  _selectIcon(name) {
13087
13459
  this._selectedIcon = name;
13088
13460
  this._grid.querySelectorAll(".an-icon-cell").forEach((cell) => {
13089
- cell.classList.toggle("active", cell.dataset.name === name);
13461
+ cell.classList.toggle(
13462
+ "active",
13463
+ /** @type {HTMLElement} */
13464
+ cell.dataset.name === name
13465
+ );
13090
13466
  });
13091
13467
  this._insertBtn.removeAttribute("disabled");
13092
13468
  this._updatePreview(name);
@@ -13125,7 +13501,7 @@ var IconDialog = class {
13125
13501
  range.collapse(false);
13126
13502
  }
13127
13503
  const _sc = range.startContainer;
13128
- const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest?.("td, th");
13504
+ const _tdAnchor = (_sc.nodeType === 1 ? _sc : _sc.parentElement)?.closest("td, th");
13129
13505
  range.deleteContents();
13130
13506
  if (_tdAnchor && _tdAnchor.isConnected && !_tdAnchor.contains(range.startContainer)) {
13131
13507
  range.setStart(_tdAnchor, 0);
@@ -13396,13 +13772,13 @@ var ContextMenu = class {
13396
13772
  this._menuDisposers.forEach((d) => {
13397
13773
  try {
13398
13774
  d();
13399
- } catch (e) {}
13775
+ } catch (_e) {}
13400
13776
  });
13401
13777
  this._menuDisposers = [];
13402
13778
  this._disposers.forEach((d) => {
13403
13779
  try {
13404
13780
  d();
13405
- } catch (e) {}
13781
+ } catch (_e) {}
13406
13782
  });
13407
13783
  this._disposers = [];
13408
13784
  if (this.el && this.el.parentNode) this.el.parentNode.removeChild(this.el);
@@ -13593,13 +13969,13 @@ var ContextMenu = class {
13593
13969
  });
13594
13970
  this._menuDisposers.push(offHeader);
13595
13971
  const offMove = on(gridEl, "mousemove", (e) => {
13596
- const cell = e.target.closest("[data-row]");
13972
+ const cell = e.target?.closest("[data-row]");
13597
13973
  if (!cell) return;
13598
13974
  setHighlight(+cell.dataset.row, +cell.dataset.col);
13599
13975
  });
13600
13976
  const offLeave = on(gridEl, "mouseleave", () => setHighlight(0, 0));
13601
13977
  const offClick = on(gridEl, "click", (e) => {
13602
- const cell = e.target.closest("[data-row]");
13978
+ const cell = e.target?.closest("[data-row]");
13603
13979
  if (!cell) return;
13604
13980
  const rows = +cell.dataset.row;
13605
13981
  const cols = +cell.dataset.col;
@@ -13624,7 +14000,7 @@ var ContextMenu = class {
13624
14000
  class: "an-context-item",
13625
14001
  "data-name": it.name || ""
13626
14002
  });
13627
- if (typeof it.disabled === "function" ? it.disabled(this.context) : !!it.disabled) btn.disabled = true;
14003
+ if (typeof it.disabled === "function" ? it.disabled(this.context) : !!it.disabled) /** @type {HTMLButtonElement} */ btn.disabled = true;
13628
14004
  if (it.icon) {
13629
14005
  const iconSpan = createElement("span", {
13630
14006
  class: "an-context-icon",
@@ -13656,7 +14032,7 @@ var ContextMenu = class {
13656
14032
  const winSel = window.getSelection();
13657
14033
  this._savedRange = winSel && winSel.rangeCount > 0 ? winSel.getRangeAt(0).cloneRange() : null;
13658
14034
  this._renderItems(this._items);
13659
- let openX = event.clientX;
14035
+ const openX = event.clientX;
13660
14036
  let openY = event.clientY;
13661
14037
  if (this._savedRange && !this._savedRange.collapsed) try {
13662
14038
  const selRect = this._savedRange.getBoundingClientRect();
@@ -13822,7 +14198,7 @@ var ContextMenu = class {
13822
14198
  while (el = iter.nextNode()) {
13823
14199
  if (!editable.contains(el) || el === editable) continue;
13824
14200
  try {
13825
- if (range.intersectsNode(el)) el.removeAttribute("style");
14201
+ if (range.intersectsNode(el)) /** @type {Element} */ el.removeAttribute("style");
13826
14202
  } catch {}
13827
14203
  }
13828
14204
  this.context.invoke("editor.afterCommand");
@@ -14084,8 +14460,8 @@ var FindReplace = class {
14084
14460
  const replaceActions = this._dialog.querySelector(".an-fr-replace-actions");
14085
14461
  const title = this._dialog.querySelector(".an-dialog-title");
14086
14462
  const isReplace = this._mode === "replace";
14087
- if (replaceRow) replaceRow.style.display = isReplace ? "" : "none";
14088
- if (replaceActions) replaceActions.style.display = isReplace ? "" : "none";
14463
+ if (replaceRow) /** @type {HTMLElement} */ replaceRow.style.display = isReplace ? "" : "none";
14464
+ if (replaceActions) /** @type {HTMLElement} */ replaceActions.style.display = isReplace ? "" : "none";
14089
14465
  if (title) title.textContent = isReplace ? this.context.locale.findReplace.findReplaceTitle : this.context.locale.findReplace.findTitle;
14090
14466
  }
14091
14467
  _buildDialog() {
@@ -14096,106 +14472,123 @@ var FindReplace = class {
14096
14472
  "aria-modal": "true",
14097
14473
  "aria-label": L.findReplaceTitle
14098
14474
  });
14099
- const box = createElement("div", { class: "an-dialog-box" });
14100
- const titleRow = createElement("div", { class: "an-icon-title-row" });
14475
+ const box = createElement("div", { class: "an-dialog-box an-fr-box" });
14476
+ const header = createElement("div", { class: "an-fr-header" });
14477
+ const titleGroup = createElement("div", { class: "an-dialog-title-group" });
14478
+ const iconEl = createElement("span", { class: "an-dialog-icon an-dialog-icon--sm" });
14479
+ iconEl.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>`;
14101
14480
  const title = createElement("h3", { class: "an-dialog-title" });
14102
14481
  title.textContent = L.findTitle;
14482
+ titleGroup.append(iconEl, title);
14103
14483
  const closeBtn = createElement("button", {
14104
14484
  type: "button",
14105
14485
  class: "an-icon-close",
14106
- "aria-label": "Close"
14486
+ title: L.close,
14487
+ "aria-label": L.close
14107
14488
  });
14108
- closeBtn.textContent = L.close;
14489
+ closeBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>`;
14109
14490
  this._closeBtn = closeBtn;
14110
- titleRow.append(title, closeBtn);
14111
- box.appendChild(titleRow);
14112
- const findRow = createElement("div", { class: "an-fr-find-row" });
14491
+ header.append(titleGroup, closeBtn);
14492
+ box.appendChild(header);
14493
+ const searchBar = createElement("div", { class: "an-fr-search-bar" });
14113
14494
  const findInput = createElement("input", {
14114
14495
  type: "text",
14115
- class: "an-input",
14496
+ class: "an-input an-fr-input",
14116
14497
  placeholder: L.findPlaceholder,
14117
14498
  "aria-label": L.searchAriaLabel
14118
14499
  });
14119
14500
  this._findInput = findInput;
14120
- findRow.appendChild(findInput);
14121
- box.appendChild(findRow);
14122
- const optRow = createElement("div", { class: "an-fr-options-row" });
14123
- const caseLabel = createElement("label", { class: "an-label an-label-inline" });
14124
14501
  const caseCheckbox = createElement("input", {
14125
14502
  type: "checkbox",
14126
- "aria-label": "Case sensitive"
14503
+ style: "display:none",
14504
+ "aria-hidden": "true"
14127
14505
  });
14128
14506
  this._caseCheckbox = caseCheckbox;
14129
- caseLabel.append(caseCheckbox, document.createTextNode(L.caseSensitive));
14130
- const counter = createElement("span", { class: "an-fr-counter" });
14131
- this._counterEl = counter;
14132
- optRow.append(caseLabel, counter);
14133
- box.appendChild(optRow);
14134
- const findActions = createElement("div", { class: "an-dialog-actions an-fr-find-actions" });
14507
+ const caseBtn = createElement("button", {
14508
+ type: "button",
14509
+ class: "an-fr-icon-btn",
14510
+ title: "Case sensitive",
14511
+ "aria-label": "Case sensitive"
14512
+ });
14513
+ caseBtn.textContent = "Aa";
14135
14514
  const prevBtn = createElement("button", {
14136
14515
  type: "button",
14137
- class: "an-btn"
14516
+ class: "an-fr-icon-btn",
14517
+ title: "Previous (Shift+Enter)",
14518
+ "aria-label": "Previous"
14138
14519
  });
14139
- prevBtn.textContent = L.prevBtn;
14520
+ prevBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg>`;
14140
14521
  const nextBtn = createElement("button", {
14141
14522
  type: "button",
14142
- class: "an-btn an-btn-primary"
14523
+ class: "an-fr-icon-btn",
14524
+ title: "Next (Enter)",
14525
+ "aria-label": "Next"
14143
14526
  });
14144
- nextBtn.textContent = L.nextBtn;
14145
- findActions.append(prevBtn, nextBtn);
14146
- box.appendChild(findActions);
14527
+ nextBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>`;
14528
+ const counter = createElement("span", { class: "an-fr-counter" });
14529
+ this._counterEl = counter;
14530
+ searchBar.append(findInput, caseCheckbox, caseBtn, prevBtn, nextBtn, counter);
14531
+ box.appendChild(searchBar);
14147
14532
  const replaceRow = createElement("div", { class: "an-fr-replace-row" });
14148
14533
  replaceRow.style.display = "none";
14149
14534
  const replaceInput = createElement("input", {
14150
14535
  type: "text",
14151
- class: "an-input",
14536
+ class: "an-input an-fr-input",
14152
14537
  placeholder: L.replacePlaceholder,
14153
14538
  "aria-label": L.replaceAriaLabel
14154
14539
  });
14155
14540
  this._replaceInput = replaceInput;
14156
- replaceRow.appendChild(replaceInput);
14157
- box.appendChild(replaceRow);
14158
- const replaceActions = createElement("div", { class: "an-dialog-actions an-fr-replace-actions" });
14159
- replaceActions.style.display = "none";
14160
14541
  const replaceBtn = createElement("button", {
14161
14542
  type: "button",
14162
- class: "an-btn"
14543
+ class: "an-btn an-fr-replace-btn"
14163
14544
  });
14164
14545
  replaceBtn.textContent = L.replaceBtn;
14165
14546
  const replaceAllBtn = createElement("button", {
14166
14547
  type: "button",
14167
- class: "an-btn an-btn-primary"
14548
+ class: "an-btn an-btn-primary an-fr-replace-btn"
14168
14549
  });
14169
14550
  replaceAllBtn.textContent = L.replaceAllBtn;
14170
- replaceActions.append(replaceBtn, replaceAllBtn);
14551
+ replaceRow.append(replaceInput, replaceBtn, replaceAllBtn);
14552
+ box.appendChild(replaceRow);
14553
+ const replaceActions = createElement("div", { class: "an-fr-replace-actions" });
14554
+ replaceActions.style.display = "none";
14171
14555
  box.appendChild(replaceActions);
14172
14556
  overlay.appendChild(box);
14557
+ makeDraggable(header, box);
14173
14558
  const d1 = on(closeBtn, "click", () => this._close());
14174
14559
  const d2 = on(overlay, "click", (e) => {
14175
14560
  if (e.target === overlay) this._close();
14176
14561
  });
14177
14562
  const d3 = on(findInput, "input", () => this._onSearch());
14178
- const d4 = on(caseCheckbox, "change", () => {
14563
+ const d4 = on(caseBtn, "click", () => {
14564
+ this._caseSensitive = !this._caseSensitive;
14565
+ caseCheckbox.checked = this._caseSensitive;
14566
+ caseBtn.classList.toggle("an-fr-icon-btn--active", this._caseSensitive);
14567
+ this._onSearch();
14568
+ });
14569
+ const d5 = on(caseCheckbox, "change", () => {
14179
14570
  this._caseSensitive = caseCheckbox.checked;
14571
+ caseBtn.classList.toggle("an-fr-icon-btn--active", this._caseSensitive);
14180
14572
  this._onSearch();
14181
14573
  });
14182
- const d5 = on(nextBtn, "click", () => this._next());
14183
- const d6 = on(prevBtn, "click", () => this._prev());
14184
- const d7 = on(replaceBtn, "click", () => this._replace());
14185
- const d8 = on(replaceAllBtn, "click", () => this._replaceAll());
14186
- const d9 = on(findInput, "keydown", (e) => {
14187
- if (e.key === "Enter") {
14574
+ const d6 = on(nextBtn, "click", () => this._next());
14575
+ const d7 = on(prevBtn, "click", () => this._prev());
14576
+ const d8 = on(replaceBtn, "click", () => this._replace());
14577
+ const d9 = on(replaceAllBtn, "click", () => this._replaceAll());
14578
+ const d10 = on(findInput, "keydown", (e) => {
14579
+ const ke = e;
14580
+ if (ke.key === "Enter") {
14188
14581
  e.preventDefault();
14189
- e.shiftKey ? this._prev() : this._next();
14582
+ ke.shiftKey ? this._prev() : this._next();
14190
14583
  }
14191
14584
  });
14192
- const d10 = on(replaceInput, "keydown", (e) => {
14585
+ const d11 = on(replaceInput, "keydown", (e) => {
14193
14586
  if (e.key === "Enter") {
14194
14587
  e.preventDefault();
14195
14588
  this._replace();
14196
14589
  }
14197
14590
  });
14198
- this._disposers.push(d1, d2, d3, d4, d5, d6, d7, d8, d9, d10);
14591
+ this._disposers.push(d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11);
14199
14592
  return overlay;
14200
14593
  }
14201
14594
  _onSearch() {
@@ -14556,9 +14949,10 @@ var ImageCropOverlay = class {
14556
14949
  }), on(h, "touchstart", (e) => {
14557
14950
  e.preventDefault();
14558
14951
  e.stopPropagation();
14952
+ const te = e;
14559
14953
  this._startHandleDrag({
14560
- clientX: e.touches[0].clientX,
14561
- clientY: e.touches[0].clientY
14954
+ clientX: te.touches[0].clientX,
14955
+ clientY: te.touches[0].clientY
14562
14956
  }, id);
14563
14957
  }, { passive: false }));
14564
14958
  this._handles[id] = h;
@@ -14575,9 +14969,10 @@ var ImageCropOverlay = class {
14575
14969
  if (e.target !== cropBox && e.target !== grid) return;
14576
14970
  e.preventDefault();
14577
14971
  e.stopPropagation();
14972
+ const te2 = e;
14578
14973
  this._startBoxMove({
14579
- clientX: e.touches[0].clientX,
14580
- clientY: e.touches[0].clientY
14974
+ clientX: te2.touches[0].clientX,
14975
+ clientY: te2.touches[0].clientY
14581
14976
  });
14582
14977
  }, { passive: false }));
14583
14978
  const infoEl = document.createElement("div");
@@ -14739,9 +15134,10 @@ var ImageCropOverlay = class {
14739
15134
  _attachDocDrag(onMove) {
14740
15135
  const onTouchMove = (e) => {
14741
15136
  e.preventDefault();
15137
+ const te3 = e;
14742
15138
  onMove({
14743
- clientX: e.touches[0].clientX,
14744
- clientY: e.touches[0].clientY
15139
+ clientX: te3.touches[0].clientX,
15140
+ clientY: te3.touches[0].clientY
14745
15141
  });
14746
15142
  };
14747
15143
  const cleanup = () => {
@@ -15318,7 +15714,9 @@ var BubbleToolbar = class {
15318
15714
  const d6 = this.context.on("contextMenu:hide", () => {
15319
15715
  this._contextMenuOpen = false;
15320
15716
  });
15321
- this._disposers.push(d1, d2, d3, d4, d5, d6);
15717
+ const d7 = on(window, "scroll", () => this._hide(), { passive: true });
15718
+ const d8 = on(window, "resize", () => this._hide(), { passive: true });
15719
+ this._disposers.push(d1, d2, d3, d4, d5, d6, d7, d8);
15322
15720
  return this;
15323
15721
  }
15324
15722
  destroy() {
@@ -15432,20 +15830,22 @@ var BubbleToolbar = class {
15432
15830
  picker.appendChild(customRow);
15433
15831
  document.body.appendChild(picker);
15434
15832
  this._picker = picker;
15435
- this._picker._paletteEl = palette;
15436
- this._picker._noColorBtn = noColorBtn;
15437
- this._picker._colorInput = colorInput;
15833
+ const pickerAny = picker;
15834
+ pickerAny._paletteEl = palette;
15835
+ pickerAny._noColorBtn = noColorBtn;
15836
+ pickerAny._colorInput = colorInput;
15438
15837
  }
15439
15838
  _openColorPicker(type, anchorBtn) {
15440
15839
  const sel = window.getSelection();
15441
15840
  if (sel && sel.rangeCount > 0) this._savedRange = sel.getRangeAt(0).cloneRange();
15442
15841
  this._pickerType = type;
15443
- const palette = this._picker._paletteEl;
15444
- const noColorBtn = this._picker._noColorBtn;
15842
+ const pickerAny = this._picker;
15843
+ const palette = pickerAny._paletteEl;
15844
+ const noColorBtn = pickerAny._noColorBtn;
15445
15845
  if (type === "hiliteColor") {
15446
15846
  if (!palette.contains(noColorBtn)) palette.appendChild(noColorBtn);
15447
15847
  } else if (palette.contains(noColorBtn)) palette.removeChild(noColorBtn);
15448
- this._picker._colorInput.value = type === "foreColor" ? "#000000" : "#ffff00";
15848
+ /** @type {any} */ this._picker._colorInput.value = type === "foreColor" ? "#000000" : "#ffff00";
15449
15849
  this._picker.style.display = "block";
15450
15850
  const pw = this._picker.offsetWidth;
15451
15851
  const ph = this._picker.offsetHeight;
@@ -15479,7 +15879,7 @@ var BubbleToolbar = class {
15479
15879
  const name = type === "hiliteColor" ? "hiliteColor" : "foreColor";
15480
15880
  const btn = this._el && this._el.querySelector(`[data-name="${name}"]`);
15481
15881
  const strip = btn && btn.querySelector(".an-bubble-color-strip");
15482
- if (strip) strip.style.background = color === "transparent" ? "transparent" : color;
15882
+ if (strip) /** @type {HTMLElement} */ strip.style.background = color === "transparent" ? "transparent" : color;
15483
15883
  this._closeColorPicker();
15484
15884
  this._syncActive();
15485
15885
  }
@@ -15495,6 +15895,14 @@ var BubbleToolbar = class {
15495
15895
  let top = rect.top - bh - gap;
15496
15896
  left = Math.max(8, Math.min(left, window.innerWidth - bw - 8));
15497
15897
  if (top < 8) top = rect.bottom + gap;
15898
+ const tableTooltipEl = document.querySelector(".an-table-tooltip");
15899
+ if (tableTooltipEl && tableTooltipEl.style.display !== "none") {
15900
+ const ttRect = tableTooltipEl.getBoundingClientRect();
15901
+ if (top < ttRect.bottom + gap && top + bh > ttRect.top - gap) {
15902
+ top = rect.bottom + gap;
15903
+ if (top + bh > window.innerHeight - 8) top = ttRect.bottom + gap;
15904
+ }
15905
+ }
15498
15906
  el.style.top = `${top}px`;
15499
15907
  el.style.left = `${left}px`;
15500
15908
  el.style.visibility = "";
@@ -15526,12 +15934,12 @@ var BubbleToolbar = class {
15526
15934
  const cs = window.getComputedStyle(node);
15527
15935
  const foreBtn = this._el.querySelector("[data-name=\"foreColor\"]");
15528
15936
  const foreStrip = foreBtn && foreBtn.querySelector(".an-bubble-color-strip");
15529
- if (foreStrip) foreStrip.style.background = cs.color || "#000000";
15937
+ if (foreStrip) /** @type {HTMLElement} */ foreStrip.style.background = cs.color || "#000000";
15530
15938
  const hiliteBtn = this._el.querySelector("[data-name=\"hiliteColor\"]");
15531
15939
  const hiliteStrip = hiliteBtn && hiliteBtn.querySelector(".an-bubble-color-strip");
15532
15940
  if (hiliteStrip) {
15533
15941
  const bg = cs.backgroundColor;
15534
- hiliteStrip.style.background = !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
15942
+ /** @type {HTMLElement} */ hiliteStrip.style.background = !bg || bg === "rgba(0, 0, 0, 0)" || bg === "transparent" ? "transparent" : bg;
15535
15943
  }
15536
15944
  }
15537
15945
  _onSelectionChange() {
@@ -15659,11 +16067,11 @@ var Mention = class {
15659
16067
  el.setAttribute("role", "listbox");
15660
16068
  el.addEventListener("mousedown", (e) => e.preventDefault());
15661
16069
  el.addEventListener("click", (e) => {
15662
- const item = e.target.closest(".an-mention-item");
16070
+ const item = e.target?.closest(".an-mention-item");
15663
16071
  if (item) this._select(+item.dataset.index);
15664
16072
  });
15665
16073
  el.addEventListener("mousemove", (e) => {
15666
- const item = e.target.closest(".an-mention-item");
16074
+ const item = e.target?.closest(".an-mention-item");
15667
16075
  if (item) this._highlightItem(+item.dataset.index);
15668
16076
  });
15669
16077
  document.body.appendChild(el);
@@ -15678,7 +16086,7 @@ var Mention = class {
15678
16086
  const li = document.createElement("div");
15679
16087
  li.className = "an-mention-item";
15680
16088
  li.setAttribute("role", "option");
15681
- li.dataset.index = i;
16089
+ li.dataset.index = String(i);
15682
16090
  if (item.avatar) {
15683
16091
  const img = document.createElement("img");
15684
16092
  img.src = item.avatar;
@@ -15928,7 +16336,7 @@ var Context = class {
15928
16336
  /**
15929
16337
  * Registers and initialises a custom module on this instance.
15930
16338
  * @param {string} name
15931
- * @param {Function} ModuleClass
16339
+ * @param {new (ctx: this) => any} ModuleClass
15932
16340
  * @returns {this}
15933
16341
  */
15934
16342
  registerModule(name, ModuleClass) {
@@ -16235,10 +16643,12 @@ var Context = class {
16235
16643
  this._disposers.forEach((d) => d());
16236
16644
  this._disposers = [];
16237
16645
  const container = this.layoutInfo.container;
16646
+ const wasDark = container && container.classList.contains("an-theme-dark");
16238
16647
  if (container && container.parentNode) {
16239
16648
  this.targetEl.style.display = "";
16240
16649
  container.parentNode.removeChild(container);
16241
16650
  }
16651
+ if (wasDark && !document.querySelector(".an-container.an-theme-dark")) document.body.classList.remove("an-theme-dark");
16242
16652
  if (typeof this.options.onDestroy === "function") this.options.onDestroy(this);
16243
16653
  this._alive = false;
16244
16654
  this._listeners.clear();
@@ -16247,7 +16657,8 @@ var Context = class {
16247
16657
  * Syncs editor HTML back into the original textarea/input for form submission.
16248
16658
  */
16249
16659
  _syncToTarget() {
16250
- if (this.targetEl.tagName === "TEXTAREA" || this.targetEl.tagName === "INPUT") this.targetEl.value = this.getHTML();
16660
+ if (this.targetEl.tagName === "TEXTAREA" || this.targetEl.tagName === "INPUT")
16661
+ /** @type {HTMLInputElement} */ this.targetEl.value = this.getHTML();
16251
16662
  }
16252
16663
  };
16253
16664
  //#endregion
@@ -16504,6 +16915,6 @@ function resolveElements(selector) {
16504
16915
  return [];
16505
16916
  }
16506
16917
  //#endregion
16507
- export { Context, ELEMENT_NODE, TEXT_NODE, WrappedRange, _buttonRegistry, alignCenterBtn, alignJustifyBtn, alignLeftBtn, alignRightBtn, all, ancestors, any, backColorBtn, boldBtn, checklistBtn, children, chunk, clamp, closest, closestPara, codeviewBtn, collapsedRange, compose, createElement, currentRange, debounce, AutumnNote as default, defaultOptions, defaultToolbar, directionBtn, emojiBtn, env, findBtn, findReplaceBtn, first, flatten, fontFamilyBtn, fontSizeBtn, foreColorBtn, fromNativeRange, fullscreenBtn, getButton, groupBy, hrBtn, iconBtn, identity, imageBtn, indentBtn, initial, inlineCodeBtn, insertAfter, isAnchor, isEditable, isElement, isEmpty, isFunction, isImage, isInline, isInsideEditable, isKey, isLi, isList, isModifier, isNil, isPara, isPlainObject, isSelectionInside, isString, isTable, isText, isVoid, italicBtn, key, last, lineHeightBtn, linkBtn, locales, mergeDeep, nextElement, nodeValue, olBtn, on, outdentBtn, outerHtml, paragraphStyleBtn, placeCaret, prevElement, printBtn, rangeFromElement, rect2bnd, redoBtn, registerButton, remove, removeFormatBtn, resolveLocale, sanitiseHTML, sanitiseUrl, shortcutsBtn, splitText, strikeBtn, subscriptBtn, superscriptBtn, tableBtn, tail, throttle, trapFocus, ulBtn, underlineBtn, undoBtn, unique, unwrap, videoBtn, withSavedRange, wrap };
16918
+ export { Context, ELEMENT_NODE, TEXT_NODE, WrappedRange, _buttonRegistry, alignCenterBtn, alignJustifyBtn, alignLeftBtn, alignRightBtn, all, ancestors, any, backColorBtn, boldBtn, checklistBtn, children, chunk, clamp, closest, closestPara, codeviewBtn, collapsedRange, compose, createElement, currentRange, debounce, AutumnNote as default, defaultOptions, defaultToolbar, directionBtn, emojiBtn, env, findBtn, findReplaceBtn, first, flatten, fontFamilyBtn, fontSizeBtn, foreColorBtn, fromNativeRange, fullscreenBtn, getButton, groupBy, hrBtn, iconBtn, identity, imageBtn, indentBtn, initial, inlineCodeBtn, insertAfter, isAnchor, isEditable, isElement, isEmpty, isFunction, isImage, isInline, isInsideEditable, isKey, isLi, isList, isModifier, isNil, isPara, isPlainObject, isSelectionInside, isString, isTable, isText, isVoid, italicBtn, key, last, lineHeightBtn, linkBtn, locales, makeDraggable, mergeDeep, nextElement, nodeValue, olBtn, on, outdentBtn, outerHtml, paragraphStyleBtn, placeCaret, prevElement, printBtn, rangeFromElement, rect2bnd, redoBtn, registerButton, remove, removeFormatBtn, resolveLocale, sanitiseHTML, sanitiseUrl, shortcutsBtn, splitText, strikeBtn, subscriptBtn, superscriptBtn, tableBtn, tail, throttle, trapFocus, ulBtn, underlineBtn, undoBtn, unique, unwrap, videoBtn, withSavedRange, wrap };
16508
16919
 
16509
16920
  //# sourceMappingURL=autumnnote.es.js.map