autumnnote 1.6.3 → 1.6.6

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.
@@ -298,8 +298,7 @@ export class FindReplace extends BaseDialog {
298
298
  range.surroundContents(mark);
299
299
  this._matches.push({ mark });
300
300
  } catch (_) {
301
- // surroundContents fails when the range crosses element boundaries.
302
- // This can happen with <br> inside matched text — skip safely.
301
+ void _; // surroundContents fails when the range crosses element boundaries
303
302
  this._matches.push({ mark: null });
304
303
  }
305
304
  }
@@ -311,7 +310,7 @@ export class FindReplace extends BaseDialog {
311
310
  if (this._matches.length === 0) return;
312
311
 
313
312
  // Highlight the first (current) match
314
- if (this._matches[0] && this._matches[0].mark) {
313
+ if (this._matches[0]?.mark) {
315
314
  this._matches[0].mark.className = 'an-highlight an-highlight-current';
316
315
  this._matches[0].mark.scrollIntoView({ block: 'center', behavior: 'smooth' });
317
316
  }
@@ -328,7 +327,7 @@ export class FindReplace extends BaseDialog {
328
327
  // Reuse compiled regex when query and case-sensitivity haven't changed
329
328
  if (this._lastQuery !== query || this._lastCaseSensitive !== this._caseSensitive) {
330
329
  const flags = this._caseSensitive ? 'g' : 'gi';
331
- const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
330
+ const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
332
331
  this._queryRegex = new RegExp(escaped, flags);
333
332
  this._lastQuery = query;
334
333
  this._lastCaseSensitive = this._caseSensitive;
@@ -370,7 +369,7 @@ export class FindReplace extends BaseDialog {
370
369
 
371
370
  _scrollToMatch(index) {
372
371
  const match = this._matches[index];
373
- if (!match || !match.mark) return;
372
+ if (!match?.mark) return;
374
373
  // Update CSS classes
375
374
  this._matches.forEach((m, i) => {
376
375
  if (m.mark) {
@@ -389,7 +388,7 @@ export class FindReplace extends BaseDialog {
389
388
  _replace() {
390
389
  if (this._matches.length === 0 || this._currentIndex < 0) return;
391
390
  const match = this._matches[this._currentIndex];
392
- if (!match || !match.mark || !match.mark.parentNode) return;
391
+ if (!match?.mark?.parentNode) return;
393
392
 
394
393
  const replacement = this._replaceInput ? this._replaceInput.value : '';
395
394
  const parent = match.mark.parentNode;
@@ -412,7 +411,7 @@ export class FindReplace extends BaseDialog {
412
411
  const replacement = this._replaceInput ? this._replaceInput.value : '';
413
412
 
414
413
  this._matches.forEach(({ mark }) => {
415
- if (!mark || !mark.parentNode) return;
414
+ if (!mark?.parentNode) return;
416
415
  const textNode = document.createTextNode(replacement);
417
416
  mark.parentNode.insertBefore(textNode, mark);
418
417
  mark.remove();
@@ -570,7 +570,7 @@ export class IconDialog extends BaseDialog {
570
570
  const _tdAnchor = /** @type {Element|null} */ (_sc.nodeType === 1 ? _sc : _sc.parentElement)
571
571
  ?.closest('td, th');
572
572
  range.deleteContents();
573
- if (_tdAnchor && _tdAnchor.isConnected && !_tdAnchor.contains(range.startContainer)) {
573
+ if (_tdAnchor?.isConnected && !_tdAnchor.contains(range.startContainer)) {
574
574
  range.setStart(_tdAnchor, 0);
575
575
  range.collapse(true);
576
576
  }
@@ -580,7 +580,7 @@ export class IconDialog extends BaseDialog {
580
580
  // Keep a text anchor (\u200B) after the icon so ArrowLeft/ArrowRight and
581
581
  // caret placement at end-of-line stay stable across browsers.
582
582
  let caretTextNode = iconEl.nextSibling;
583
- if (!caretTextNode || caretTextNode.nodeType !== Node.TEXT_NODE) {
583
+ if (caretTextNode?.nodeType !== Node.TEXT_NODE) {
584
584
  caretTextNode = document.createTextNode('\u200B');
585
585
  iconEl.parentNode.insertBefore(caretTextNode, iconEl.nextSibling);
586
586
  } else if (!caretTextNode.textContent) {
@@ -58,6 +58,7 @@ function drawCropToCanvas(img, naturalRect, renderW, renderH) {
58
58
  ctx.getImageData(0, 0, 1, 1);
59
59
  resolve(canvas);
60
60
  } catch (_) {
61
+ void _; // canvas tainted — resolve with null
61
62
  resolve(null);
62
63
  }
63
64
  };
@@ -399,7 +400,7 @@ export class ImageCropOverlay {
399
400
  const startY = e.clientY;
400
401
  const orig = { ...this._box };
401
402
  const r = this._imgRect;
402
- const lockAR = this._arCheck && this._arCheck.checked;
403
+ const lockAR = this._arCheck?.checked;
403
404
  const aspect = orig.w / (orig.h || 1);
404
405
 
405
406
  const onMove = (me) => {
@@ -107,8 +107,8 @@ export class ImageDialog extends BaseDialog {
107
107
  // ---------------------------------------------------------------------------
108
108
 
109
109
  _onFileChange() {
110
- const file = this._fileInput && this._fileInput.files && this._fileInput.files[0];
111
- if (!file || !file.type.startsWith('image/')) return;
110
+ const file = this._fileInput?.files?.[0];
111
+ if (!file?.type?.startsWith('image/')) return;
112
112
 
113
113
  // C2: Only allow web-displayable formats. TIFF, BMP, RAW and similar
114
114
  // formats are not rendered by browsers — reject them with a clear message.
@@ -146,7 +146,7 @@ export class ImageDialog extends BaseDialog {
146
146
  _onInsert() {
147
147
  const src = this._urlInput.value.trim();
148
148
  const alt = this._altInput.value.trim();
149
- const alignRadio = this._alignRow && this._alignRow.querySelector('input[name="an-img-align"]:checked');
149
+ const alignRadio = this._alignRow?.querySelector('input[name="an-img-align"]:checked');
150
150
  const align = alignRadio ? /** @type {HTMLInputElement} */ (alignRadio).value : '';
151
151
 
152
152
  if (!src) {
@@ -75,7 +75,7 @@ export class ImageResizer {
75
75
  this._positionRaf = null;
76
76
  }
77
77
  this._deselect();
78
- if (this._overlay && this._overlay.parentNode) {
78
+ if (this._overlay?.parentNode) {
79
79
  this._overlay.remove();
80
80
  }
81
81
  this._overlay = null;
@@ -140,7 +140,7 @@ export class ImageResizer {
140
140
  _onDocClick(e) {
141
141
  if (!this._activeImg) return;
142
142
  if (e.target === this._activeImg) return;
143
- if (this._overlay && this._overlay.contains(e.target)) return;
143
+ if (this._overlay?.contains(e.target)) return;
144
144
  // Don't deselect while interacting with the context menu
145
145
  if (e.target.closest('.an-contextmenu')) return;
146
146
  this._deselect();
@@ -181,7 +181,7 @@ export class ImageResizer {
181
181
 
182
182
  // Skip DOM writes when position hasn't changed (common during non-scroll rAF ticks)
183
183
  const p = this._lastOverlayPos;
184
- if (p && p.l === rect.left && p.t === rect.top && p.w === rect.width && p.h === rect.height) return;
184
+ if (p?.l === rect.left && p.t === rect.top && p.w === rect.width && p.h === rect.height) return;
185
185
  this._lastOverlayPos = { l: rect.left, t: rect.top, w: rect.width, h: rect.height };
186
186
 
187
187
  const left = rect.left - containerRect.left + offsetParent.scrollLeft;
@@ -284,9 +284,11 @@ export class ImageTooltip {
284
284
  const next = (prev + delta + 360) % 360; // normalise to [0, 360)
285
285
  // Preserve any other transform functions (e.g. scale), replace only rotate()
286
286
  const cleaned = current.replace(/rotate\(-?[\d.]+deg\)/, '').trim();
287
- img.style.transform = cleaned
288
- ? `${cleaned} rotate(${next}deg)`
289
- : next === 0 ? '' : `rotate(${next}deg)`;
287
+ if (cleaned) {
288
+ img.style.transform = `${cleaned} rotate(${next}deg)`;
289
+ } else {
290
+ img.style.transform = next === 0 ? '' : `rotate(${next}deg)`;
291
+ }
290
292
  this.context.invoke('editor.afterCommand');
291
293
  this.context.invoke('imageResizer.updateOverlay');
292
294
  requestAnimationFrame(() => { if (this._activeImg) this._positionNear(this._activeImg); });
@@ -88,7 +88,7 @@ export class LinkDialog extends BaseDialog {
88
88
  // Try to find currently selected anchor
89
89
  const sel = globalThis.getSelection();
90
90
  let anchor = null;
91
- if (sel && sel.rangeCount > 0) {
91
+ if (sel?.rangeCount > 0) {
92
92
  let node = sel.getRangeAt(0).startContainer;
93
93
  while (node) {
94
94
  if (node.nodeName === 'A') { anchor = node; break; }
@@ -57,7 +57,7 @@ export class LinkTooltip {
57
57
  this._clearTimers();
58
58
  this._disposers.forEach((d) => d());
59
59
  this._disposers = [];
60
- if (this._el && this._el.parentNode) this._el.remove();
60
+ if (this._el?.parentNode) this._el.remove();
61
61
  this._el = null;
62
62
  }
63
63
 
@@ -178,7 +178,7 @@ export class LinkTooltip {
178
178
  _truncateUrl(url) {
179
179
  try {
180
180
  const u = new URL(url);
181
- const display = u.host + (u.pathname !== '/' ? u.pathname : '');
181
+ const display = u.host + (u.pathname === '/' ? '' : u.pathname);
182
182
  return display.length > 48 ? display.slice(0, 48) + '…' : display;
183
183
  } catch {
184
184
  return url.length > 48 ? url.slice(0, 48) + '…' : url;
@@ -213,7 +213,7 @@ export class LinkTooltip {
213
213
  // Brief visual feedback
214
214
  if (this._copyBtn) {
215
215
  this._copyBtn.classList.add('an-link-tooltip-btn--copied');
216
- setTimeout(() => this._copyBtn && this._copyBtn.classList.remove('an-link-tooltip-btn--copied'), 1000);
216
+ setTimeout(() => this._copyBtn?.classList.remove('an-link-tooltip-btn--copied'), 1000);
217
217
  }
218
218
  }
219
219
 
@@ -205,12 +205,12 @@ export class Mention {
205
205
  this._caretRect = candidate;
206
206
  return;
207
207
  }
208
- } catch (_) {}
208
+ } catch (_) { void _; }
209
209
  }
210
210
 
211
211
  // Fallback: use getClientRects() on the current collapsed selection
212
212
  const sel = globalThis.getSelection();
213
- if (!sel || !sel.rangeCount) return;
213
+ if (!sel?.rangeCount) return;
214
214
  const rects = sel.getRangeAt(0).getClientRects();
215
215
  if (rects.length > 0) {
216
216
  this._caretRect = rects[rects.length - 1];
@@ -223,7 +223,7 @@ export class Mention {
223
223
 
224
224
  _getQueryAtCursor() {
225
225
  const sel = globalThis.getSelection();
226
- if (!sel || !sel.rangeCount) return null;
226
+ if (!sel?.rangeCount) return null;
227
227
  const range = sel.getRangeAt(0);
228
228
  if (!range.collapsed) return null;
229
229
 
@@ -58,7 +58,7 @@ function getCellAfterVisualCol(row, visualIdx) {
58
58
  if (vIdx > visualIdx) {
59
59
  // next cell after the one that starts at / spans visualIdx
60
60
  const next = c.nextElementSibling;
61
- return (next && next.tagName === 'TD' || next && next.tagName === 'TH') ? /** @type {HTMLTableCellElement} */ (next) : null;
61
+ return (next?.tagName === 'TD' || next?.tagName === 'TH') ? /** @type {HTMLTableCellElement} */ (next) : null;
62
62
  }
63
63
  }
64
64
  return null;
@@ -190,10 +190,7 @@ export class TableTooltip {
190
190
  on(editable, 'mousedown', onSelMousedown),
191
191
  on(editable, 'mousemove', onSelMousemove),
192
192
  on(document, 'mouseup', onSelMouseup),
193
- );
194
- // ────────────────────────────────────────────────────────────────────────
195
-
196
- this._disposers.push(
193
+ // ──────────────────────────────────────────────────────────────────────
197
194
  on(editable, 'mouseover', (e) => {
198
195
  if (this.context.layoutInfo.container.classList.contains('an-disabled')) return;
199
196
  const table = /** @type {Element} */ (e.target)?.closest('table');
@@ -309,22 +306,27 @@ export class TableTooltip {
309
306
  _startY = e.clientY;
310
307
  _table = _nearCell.closest('table');
311
308
  if (_edge === 'col') {
312
- _startW = _nearCell.offsetWidth;
313
- _colIdx = getVisualColIndex(_nearCell);
314
- // Cache column cells once so onDocMove never runs querySelectorAll per frame.
315
- // F-1: skip merged cells (colSpan > 1) setting width on a merged cell
316
- // distributes it equally across all spanned columns instead of resizing
317
- // only the target column. Rows that have an individual cell at this
318
- // visual column index are resized independently as expected.
309
+ // Right edge of a merged cell = last spanned column, not the start column
310
+ _colIdx = getVisualColIndex(_nearCell) + (_nearCell.colSpan || 1) - 1;
311
+ // Cache non-merged cells at that column merged cells cannot be individually
312
+ // resized per column (F-1: colSpan > 1 distributes width across all spanned cols)
319
313
  _colCells = _colIdx >= 0
320
314
  ? Array.from(_table.querySelectorAll('tr'))
321
315
  .map(r => getCellAtVisualCol(r, _colIdx))
322
316
  .filter(Boolean)
323
317
  .filter(c => (c.colSpan || 1) === 1)
324
318
  : [];
319
+ // Use the actual column width from a non-merged cell; fall back to per-column estimate
320
+ _startW = _colCells.length > 0
321
+ ? _colCells[0].offsetWidth
322
+ : Math.max(30, Math.round(_nearCell.offsetWidth / (_nearCell.colSpan || 1)));
325
323
  document.body.style.cursor = 'col-resize';
326
324
  } else {
327
- _row = _nearCell.closest('tr');
325
+ // Bottom edge of a merged cell = last spanned row, not the cell's own <tr>
326
+ const tr = _nearCell.closest('tr');
327
+ const rowStart = tr ? Array.from(_table.rows).indexOf(tr) : 0;
328
+ const lastRowIdx = rowStart + (_nearCell.rowSpan || 1) - 1;
329
+ _row = _table.rows[lastRowIdx] || tr;
328
330
  _startH = _row ? _row.offsetHeight : 40;
329
331
  document.body.style.cursor = 'row-resize';
330
332
  }
@@ -386,13 +388,13 @@ export class TableTooltip {
386
388
  this._clearTimers();
387
389
  this._disposers.forEach((d) => d());
388
390
  this._disposers = [];
389
- if (this._el && this._el.parentNode) this._el.remove();
391
+ if (this._el?.parentNode) this._el.remove();
390
392
  this._el = null;
391
- if (this._sizePopover && this._sizePopover.parentNode) {
393
+ if (this._sizePopover?.parentNode) {
392
394
  this._sizePopover.remove();
393
395
  }
394
396
  this._sizePopover = null;
395
- if (this._shadePopover && this._shadePopover.parentNode) {
397
+ if (this._shadePopover?.parentNode) {
396
398
  this._shadePopover.remove();
397
399
  }
398
400
  this._shadePopover = null;
@@ -604,7 +606,7 @@ export class TableTooltip {
604
606
  _getCell() {
605
607
  // Prefer the cell under the current text cursor (most intuitive for operations)
606
608
  const sel = globalThis.getSelection();
607
- if (sel && sel.rangeCount) {
609
+ if (sel?.rangeCount) {
608
610
  let container = sel.getRangeAt(0).commonAncestorContainer;
609
611
  if (container.nodeType === 3) container = container.parentElement;
610
612
  const cellFromSel = /** @type {Element} */ (container)?.closest('td, th');
@@ -659,7 +661,7 @@ export class TableTooltip {
659
661
  if (!startCell) return [];
660
662
  if (!endCell || startCell === endCell) return [startCell];
661
663
  const table = startCell.closest('table');
662
- if (!table || !table.contains(endCell)) return [startCell];
664
+ if (!table?.contains(endCell)) return [startCell];
663
665
 
664
666
  const { gridMap, cellPos } = buildGridMap(table);
665
667
  const sp = cellPos.get(startCell);
@@ -734,7 +736,8 @@ export class TableTooltip {
734
736
  const refRow = selectedRows.reduce((best, r) => {
735
737
  const bi = allRows.indexOf(best);
736
738
  const ri = allRows.indexOf(r);
737
- return position === 'above' ? (ri < bi ? r : best) : (ri > bi ? r : best);
739
+ if (position === 'above') return ri < bi ? r : best;
740
+ return ri > bi ? r : best;
738
741
  }, selectedRows[0]);
739
742
  const colCount = Array.from(refRow.cells).reduce((sum, c) => sum + (c.colSpan || 1), 0);
740
743
  const newRow = document.createElement('tr');
@@ -742,12 +745,12 @@ export class TableTooltip {
742
745
  for (let i = 0; i < colCount; i++) {
743
746
  const td = createElement('td', {}, ['\u00a0']);
744
747
  const ref = refCells[i];
745
- if (ref && ref.style.width) td.style.width = ref.style.width;
746
- if (ref && ref.style.minWidth) td.style.minWidth = ref.style.minWidth;
748
+ if (ref?.style.width) td.style.width = ref.style.width;
749
+ if (ref?.style.minWidth) td.style.minWidth = ref.style.minWidth;
747
750
  newRow.appendChild(td);
748
751
  }
749
752
  if (position === 'above') refRow.parentElement?.insertBefore(newRow, refRow);
750
- else refRow.insertAdjacentElement('afterend', newRow);
753
+ else refRow.after(newRow);
751
754
  requestAnimationFrame(() => this._positionNear(this._activeTable));
752
755
  this.context.invoke('editor.afterCommand');
753
756
  }
@@ -865,8 +868,21 @@ export class TableTooltip {
865
868
  first.colSpan = maxC - minC + 1;
866
869
  first.rowSpan = maxR - minR + 1;
867
870
  first.style.verticalAlign = 'middle';
868
- first.innerHTML = rectCells.map((c) => c.innerHTML).join('');
869
- rectCells.slice(1).forEach((c) => c.remove());
871
+ first.style.height = '';
872
+ first.style.minHeight = '';
873
+
874
+ // Merge content: collect non-empty inner HTML, join with <br> separator
875
+ const parts = rectCells
876
+ .map((c) => c.innerHTML.replace(/^(<br\s*\/?>|\s)+$/i, '').trim())
877
+ .filter((h) => h !== '');
878
+ first.innerHTML = parts.length ? parts.join('<br>') : '<br>';
879
+
880
+ rectCells.slice(1).forEach((c) => {
881
+ const row = c.parentElement;
882
+ c.remove();
883
+ // Remove the parent <tr> if it is now completely empty
884
+ if (row && row.cells.length === 0) row.remove();
885
+ });
870
886
 
871
887
  this._clearSelection();
872
888
  this.context.invoke('editor.afterCommand');
@@ -939,7 +955,7 @@ export class TableTooltip {
939
955
  let ref = null;
940
956
  for (const tc of targetRow.cells) {
941
957
  const tp = cellPos.get(tc);
942
- if (tp && tp.c > c) { ref = tc; break; }
958
+ if (tp?.c > c) { ref = tc; break; }
943
959
  }
944
960
  for (let dc = 0; dc < cs; dc++) {
945
961
  targetRow.insertBefore(createElement(tag, {}, ['\u00a0']), ref);
@@ -1043,9 +1059,12 @@ export class TableTooltip {
1043
1059
  : this.context.locale.tooltips.table.rowHeightPx;
1044
1060
  this._sizeInputEl.min = '1';
1045
1061
  this._sizeInputEl.max = '2000';
1046
- this._sizeInputEl.value = isCol
1047
- ? (cell.offsetWidth || 120)
1048
- : (cell.closest('tr') ? (cell.closest('tr').offsetHeight || 40) : 40);
1062
+ if (isCol) {
1063
+ this._sizeInputEl.value = cell.offsetWidth || 120;
1064
+ } else {
1065
+ const refRow = cell.closest('tr');
1066
+ this._sizeInputEl.value = refRow ? (refRow.offsetHeight || 40) : 40;
1067
+ }
1049
1068
  this._sizeApply = (val) => {
1050
1069
  const table = cell.closest('table');
1051
1070
  if (!table) return;
@@ -1140,19 +1159,18 @@ export class TableTooltip {
1140
1159
  on(pop, 'mousedown', (e) => e.preventDefault()),
1141
1160
  on(pop, 'mouseenter', () => this._clearTimers()),
1142
1161
  on(pop, 'mouseleave', () => this._scheduleHide()),
1162
+ // Close on outside click
1163
+ on(document, 'click', (e) => {
1164
+ const et = /** @type {Node} */ (e.target);
1165
+ if (this._shadePopover &&
1166
+ this._shadePopover.style.display !== 'none' &&
1167
+ !this._shadePopover.contains(et) &&
1168
+ !this._el?.contains(et)) {
1169
+ this._hideCellShadePopover();
1170
+ }
1171
+ }),
1143
1172
  );
1144
1173
 
1145
- // Close on outside click
1146
- this._disposers.push(on(document, 'click', (e) => {
1147
- const et = /** @type {Node} */ (e.target);
1148
- if (this._shadePopover &&
1149
- this._shadePopover.style.display !== 'none' &&
1150
- !this._shadePopover.contains(et) &&
1151
- !this._el?.contains(et)) {
1152
- this._hideCellShadePopover();
1153
- }
1154
- }));
1155
-
1156
1174
  return pop;
1157
1175
  }
1158
1176
 
@@ -145,7 +145,7 @@ export class Toolbar {
145
145
  this._refreshRaf = null;
146
146
  this._disposers.forEach((d) => d());
147
147
  this._disposers = [];
148
- if (this.el && this.el.parentNode) {
148
+ if (this.el?.parentNode) {
149
149
  this.el.remove();
150
150
  }
151
151
  this.el = null;
@@ -399,7 +399,7 @@ export class Toolbar {
399
399
 
400
400
  const saveSelection = () => {
401
401
  const sel = globalThis.getSelection();
402
- savedRange = (sel && sel.rangeCount) ? sel.getRangeAt(0).cloneRange() : null;
402
+ savedRange = sel?.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
403
403
  };
404
404
 
405
405
  const restoreSelection = () => {
@@ -410,7 +410,7 @@ export class Toolbar {
410
410
  sel.removeAllRanges();
411
411
  sel.addRange(savedRange);
412
412
  } catch (_) {
413
- // Range target may be detached if DOM changed while popup was open
413
+ void _; // range may be stale if DOM changed while popup was open
414
414
  }
415
415
  };
416
416
 
@@ -541,11 +541,14 @@ export class Toolbar {
541
541
 
542
542
  items.forEach((item) => {
543
543
  const value = (typeof item === 'object') ? item.value : item;
544
- const label = (typeof item === 'object')
545
- ? (def.name === 'paragraphStyle'
546
- ? ((this.context.locale.toolbar.paragraphItems || {})[item.value] || item.label)
547
- : item.label)
548
- : item;
544
+ let label;
545
+ if (typeof item !== 'object') {
546
+ label = item;
547
+ } else if (def.name === 'paragraphStyle') {
548
+ label = this.context.locale.toolbar.paragraphItems?.[item.value] || item.label;
549
+ } else {
550
+ label = item.label;
551
+ }
549
552
  const isHeader = (typeof item === 'object') && !!item.disabled;
550
553
  const attrs = { value };
551
554
  if (isHeader) attrs.disabled = '';
@@ -563,7 +566,7 @@ export class Toolbar {
563
566
  let _savedRange = null;
564
567
  const dMousedown = on(select, 'mousedown', () => {
565
568
  const sel = globalThis.getSelection();
566
- _savedRange = (sel && sel.rangeCount) ? sel.getRangeAt(0).cloneRange() : null;
569
+ _savedRange = sel?.rangeCount ? sel.getRangeAt(0).cloneRange() : null;
567
570
  });
568
571
 
569
572
  const disposer = on(select, 'change', (e) => {
@@ -576,7 +579,7 @@ export class Toolbar {
576
579
  try {
577
580
  const sel = globalThis.getSelection();
578
581
  if (sel) { sel.removeAllRanges(); sel.addRange(_savedRange); }
579
- } catch (_) { /* range may be stale if DOM changed */ }
582
+ } catch (_) { void _; /* range may be stale if DOM changed */ }
580
583
  }
581
584
  def.action(this.context, value);
582
585
  this.context.invoke('editor.afterCommand');
@@ -617,15 +620,13 @@ export class Toolbar {
617
620
  } else {
618
621
  btn.textContent = btnDef.icon || btnDef.name;
619
622
  }
620
- } else {
623
+ } else if (_SVG_MAP.has(btnDef.icon)) {
621
624
  // FontAwesome absent: use SVG fallback when available
622
- if (_SVG_MAP.has(btnDef.icon)) {
623
- btn.innerHTML = _SVG_MAP.get(btnDef.icon);
624
- } else if (_SVG_MAP.has(btnDef.name)) {
625
- btn.innerHTML = _SVG_MAP.get(btnDef.name);
626
- } else {
627
- btn.textContent = btnDef.icon || btnDef.name;
628
- }
625
+ btn.innerHTML = _SVG_MAP.get(btnDef.icon);
626
+ } else if (_SVG_MAP.has(btnDef.name)) {
627
+ btn.innerHTML = _SVG_MAP.get(btnDef.name);
628
+ } else {
629
+ btn.textContent = btnDef.icon || btnDef.name;
629
630
  }
630
631
 
631
632
  const disposer = on(btn, 'click', (event) => {
@@ -702,13 +703,13 @@ export class Toolbar {
702
703
  // Fallback: when no selection/font set, use the configured default font
703
704
  if (!raw) {
704
705
  raw = this.options.defaultFontFamily
705
- || (this.options.fontFamilies && this.options.fontFamilies[0])
706
+ || this.options.fontFamilies?.[0]
706
707
  || '';
707
708
  }
708
709
  // Try to match against available options (case-insensitive)
709
710
  const sel = /** @type {HTMLSelectElement} */ (select);
710
711
  const matched = Array.from(sel.options).find(
711
- (opt) => opt.value && opt.value.toLowerCase() === raw.toLowerCase()
712
+ (opt) => opt.value?.toLowerCase() === raw.toLowerCase()
712
713
  );
713
714
  sel.value = matched ? matched.value : '';
714
715
  });
@@ -68,7 +68,10 @@ export class VideoDialog extends BaseDialog {
68
68
  // Live URL hint
69
69
  const d0 = on(urlInput, 'input', () => {
70
70
  const info = this._parseVideoUrl(urlInput.value.trim());
71
- hintEl.textContent = info ? this.context.locale.videoDialog.detected(info.type) : (urlInput.value ? this.context.locale.videoDialog.unknownFormat : '');
71
+ let hint = '';
72
+ if (info) { hint = this.context.locale.videoDialog.detected(info.type); }
73
+ else if (urlInput.value) { hint = this.context.locale.videoDialog.unknownFormat; }
74
+ hintEl.textContent = hint;
72
75
  });
73
76
  const d4 = on(urlInput, 'keydown', (e) => { if (/** @type {KeyboardEvent} */ (e).key === 'Enter') { e.preventDefault(); this._onInsert(); } });
74
77
  this._disposers.push(d0, d4);
@@ -167,7 +170,7 @@ export class VideoDialog extends BaseDialog {
167
170
  );
168
171
  }
169
172
 
170
- if (info && info.type === 'Direct video') {
173
+ if (info?.type === 'Direct video') {
171
174
  const src = info.embedUrl.replaceAll('"', '%22');
172
175
  return (
173
176
  `<div class="an-video-wrapper" style="position:relative;display:block;width:${width}px;max-width:100%">` +
@@ -36,7 +36,7 @@ export function renderLayout(targetEl, options) {
36
36
  // Restore auto-saved content when available; fall back to element content
37
37
  let initialContent = '';
38
38
  if (options.autoSave && options.autoSaveKey) {
39
- try { initialContent = localStorage.getItem(options.autoSaveKey) || ''; } catch (_) {}
39
+ try { initialContent = localStorage.getItem(options.autoSaveKey) || ''; } catch (_) { void _; }
40
40
  }
41
41
  if (!initialContent) {
42
42
  initialContent = targetEl.tagName === 'TEXTAREA'
@@ -111,7 +111,7 @@ export function renderLayout(targetEl, options) {
111
111
 
112
112
  // Hide the original element; keep it in DOM for form submission
113
113
  targetEl.style.display = 'none';
114
- targetEl.insertAdjacentElement('afterend', container);
114
+ targetEl.after(container);
115
115
 
116
116
  return { container, editable };
117
117
  }