autumnnote 1.6.5 → 1.6.7

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.
@@ -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,7 +388,7 @@ 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
393
  if (this._sizePopover?.parentNode) {
392
394
  this._sizePopover.remove();
@@ -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');
@@ -747,7 +750,7 @@ export class TableTooltip {
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;
@@ -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 = '';
@@ -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');
@@ -700,13 +703,13 @@ export class Toolbar {
700
703
  // Fallback: when no selection/font set, use the configured default font
701
704
  if (!raw) {
702
705
  raw = this.options.defaultFontFamily
703
- || (this.options.fontFamilies && this.options.fontFamilies[0])
706
+ || this.options.fontFamilies?.[0]
704
707
  || '';
705
708
  }
706
709
  // Try to match against available options (case-insensitive)
707
710
  const sel = /** @type {HTMLSelectElement} */ (select);
708
711
  const matched = Array.from(sel.options).find(
709
- (opt) => opt.value && opt.value.toLowerCase() === raw.toLowerCase()
712
+ (opt) => opt.value?.toLowerCase() === raw.toLowerCase()
710
713
  );
711
714
  sel.value = matched ? matched.value : '';
712
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
  }