autumnnote 1.6.7 → 1.7.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.
- package/README.md +11 -5
- package/dist/autumnnote.css +164 -0
- package/dist/autumnnote.es.js +426 -31
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +426 -31
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/js/Context.js +37 -1
- package/src/js/editing/History.js +10 -0
- package/src/js/i18n/de.js +7 -0
- package/src/js/i18n/en.js +14 -0
- package/src/js/i18n/es.js +7 -0
- package/src/js/i18n/fr.js +7 -0
- package/src/js/i18n/ja.js +7 -0
- package/src/js/i18n/ko.js +7 -0
- package/src/js/i18n/vi.js +7 -0
- package/src/js/i18n/zh.js +7 -0
- package/src/js/index.js +1 -1
- package/src/js/module/BaseDialog.js +7 -0
- package/src/js/module/CodeTooltip.js +23 -0
- package/src/js/module/Editor.js +8 -0
- package/src/js/module/FindReplace.js +31 -6
- package/src/js/module/Mention.js +6 -2
- package/src/js/module/Statusbar.js +3 -3
- package/src/js/module/TableTooltip.js +287 -2
- package/src/js/renderer.js +5 -2
- package/src/styles/autumnnote.scss +181 -0
- package/types/index.d.ts +18 -4
|
@@ -116,6 +116,16 @@ const ICONS = {
|
|
|
116
116
|
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>`,
|
|
117
117
|
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>`,
|
|
118
118
|
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>`,
|
|
119
|
+
borderColor: `<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="14" rx="1"/><line x1="3" y1="10" x2="21" y2="10" stroke-width="1.5"/><line x1="12" y1="3" x2="12" y2="17" stroke-width="1.5"/><path d="M3 21h18" stroke-width="3"/></svg>`,
|
|
120
|
+
alignLeft: `<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="21" y1="6" x2="3" y2="6"/><line x1="15" y1="12" x2="3" y2="12"/><line x1="17" y1="18" x2="3" y2="18"/></svg>`,
|
|
121
|
+
alignCenter: `<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="21" y1="6" x2="3" y2="6"/><line x1="17" y1="12" x2="7" y2="12"/><line x1="19" y1="18" x2="5" y2="18"/></svg>`,
|
|
122
|
+
alignRight: `<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="21" y1="6" x2="3" y2="6"/><line x1="21" y1="12" x2="9" y2="12"/><line x1="21" y1="18" x2="7" y2="18"/></svg>`,
|
|
123
|
+
alignJustify: `<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="21" y1="6" x2="3" y2="6"/><line x1="21" y1="12" x2="3" y2="12"/><line x1="21" y1="18" x2="3" y2="18"/></svg>`,
|
|
124
|
+
headerRow: `<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"/><rect x="3" y="3" width="18" height="8" rx="1" fill="currentColor" opacity="0.2"/><line x1="3" y1="11" x2="21" y2="11"/><line x1="3" y1="16" x2="21" y2="16"/><line x1="9" y1="11" x2="9" y2="21"/><line x1="15" y1="11" x2="15" y2="21"/></svg>`,
|
|
125
|
+
sortAsc: `<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="6" x2="11" y2="6"/><line x1="4" y1="12" x2="11" y2="12"/><line x1="4" y1="18" x2="13" y2="18"/><path d="M15 9l3-3 3 3"/><line x1="18" y1="6" x2="18" y2="18"/></svg>`,
|
|
126
|
+
sortDesc: `<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="6" x2="13" y2="6"/><line x1="4" y1="12" x2="11" y2="12"/><line x1="4" y1="18" x2="11" y2="18"/><path d="M15 15l3 3 3-3"/><line x1="18" y1="6" x2="18" y2="18"/></svg>`,
|
|
127
|
+
exportCSV: `<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="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>`,
|
|
128
|
+
cellPadding: `<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"/><rect x="7" y="7" width="10" height="10" rx="0.5" stroke-dasharray="2 1.5"/></svg>`,
|
|
119
129
|
};
|
|
120
130
|
|
|
121
131
|
const SHADE_PRESETS = [
|
|
@@ -142,6 +152,11 @@ export class TableTooltip {
|
|
|
142
152
|
this._shadePopover = null;
|
|
143
153
|
this._shadeTitleEl = null;
|
|
144
154
|
this._shadeColorStrip = null;
|
|
155
|
+
// Border color popover
|
|
156
|
+
this._borderColorPopover = null;
|
|
157
|
+
this._borderColorTitleEl = null;
|
|
158
|
+
this._borderColorStrip = null;
|
|
159
|
+
this._borderColorNoBtn = null;
|
|
145
160
|
// Cell selection
|
|
146
161
|
this._selectMode = false;
|
|
147
162
|
this._selectedCells = [];
|
|
@@ -161,6 +176,9 @@ export class TableTooltip {
|
|
|
161
176
|
this._shadePopover = this._buildCellShadePopover();
|
|
162
177
|
document.body.appendChild(this._shadePopover);
|
|
163
178
|
|
|
179
|
+
this._borderColorPopover = this._buildBorderColorPopover();
|
|
180
|
+
document.body.appendChild(this._borderColorPopover);
|
|
181
|
+
|
|
164
182
|
const editable = this.context.layoutInfo.editable;
|
|
165
183
|
this._editable = editable;
|
|
166
184
|
|
|
@@ -220,7 +238,8 @@ export class TableTooltip {
|
|
|
220
238
|
if (this._activeTable &&
|
|
221
239
|
!this._activeTable.contains(et) &&
|
|
222
240
|
!this._el.contains(et) &&
|
|
223
|
-
!this._sizePopover?.contains(et)
|
|
241
|
+
!this._sizePopover?.contains(et) &&
|
|
242
|
+
!this._borderColorPopover?.contains(et)) {
|
|
224
243
|
this._hide();
|
|
225
244
|
}
|
|
226
245
|
}),
|
|
@@ -398,6 +417,10 @@ export class TableTooltip {
|
|
|
398
417
|
this._shadePopover.remove();
|
|
399
418
|
}
|
|
400
419
|
this._shadePopover = null;
|
|
420
|
+
if (this._borderColorPopover?.parentNode) {
|
|
421
|
+
this._borderColorPopover.remove();
|
|
422
|
+
}
|
|
423
|
+
this._borderColorPopover = null;
|
|
401
424
|
}
|
|
402
425
|
|
|
403
426
|
// ---------------------------------------------------------------------------
|
|
@@ -437,6 +460,8 @@ export class TableTooltip {
|
|
|
437
460
|
el.appendChild(this._makeBtn(ICONS.colLeft, L.addColumnLeft, () => this._addColumn('left')));
|
|
438
461
|
el.appendChild(this._makeBtn(ICONS.colRight, L.addColumnRight, () => this._addColumn('right')));
|
|
439
462
|
el.appendChild(this._makeBtn(ICONS.deleteCol, L.deleteColumn, () => this._deleteColumn()));
|
|
463
|
+
el.appendChild(this._makeBtn(ICONS.sortAsc, L.sortAsc, () => this._sortColumn('asc')));
|
|
464
|
+
el.appendChild(this._makeBtn(ICONS.sortDesc, L.sortDesc, () => this._sortColumn('desc')));
|
|
440
465
|
|
|
441
466
|
el.appendChild(this._sep());
|
|
442
467
|
|
|
@@ -446,6 +471,15 @@ export class TableTooltip {
|
|
|
446
471
|
|
|
447
472
|
el.appendChild(this._sep());
|
|
448
473
|
|
|
474
|
+
// Cell text alignment
|
|
475
|
+
el.appendChild(this._makeBtn(ICONS.alignLeft, L.cellAlignLeft, () => this._applyCellAlign('left')));
|
|
476
|
+
el.appendChild(this._makeBtn(ICONS.alignCenter, L.cellAlignCenter, () => this._applyCellAlign('center')));
|
|
477
|
+
el.appendChild(this._makeBtn(ICONS.alignRight, L.cellAlignRight, () => this._applyCellAlign('right')));
|
|
478
|
+
el.appendChild(this._makeBtn(ICONS.alignJustify, L.cellAlignJustify, () => this._applyCellAlign('justify')));
|
|
479
|
+
el.appendChild(this._makeBtn(ICONS.headerRow, L.toggleHeaderRow, () => this._toggleHeaderRow()));
|
|
480
|
+
|
|
481
|
+
el.appendChild(this._sep());
|
|
482
|
+
|
|
449
483
|
// Cell background shading — uses color-strip variant like foreColor/hiliteColor buttons
|
|
450
484
|
const shadeBtn = createElement('button', {
|
|
451
485
|
type: 'button',
|
|
@@ -471,12 +505,35 @@ export class TableTooltip {
|
|
|
471
505
|
el.appendChild(this._makeBtn(ICONS.colWidth, L.columnWidth, () => this._openSizePopover('col')));
|
|
472
506
|
el.appendChild(this._makeBtn(ICONS.rowHeight, L.rowHeight, () => this._openSizePopover('row')));
|
|
473
507
|
el.appendChild(this._makeBtn(ICONS.tableBorder,L.tableBorderWidth, () => this._openSizePopover('border')));
|
|
508
|
+
el.appendChild(this._makeBtn(ICONS.cellPadding, L.cellPadding, () => this._openSizePopover('cellPadding')));
|
|
509
|
+
|
|
510
|
+
// Table border color button — color-strip variant like shade button
|
|
511
|
+
const borderColorBtn = createElement('button', {
|
|
512
|
+
type: 'button',
|
|
513
|
+
class: 'an-link-tooltip-btn an-link-tooltip-btn--shade',
|
|
514
|
+
title: L.tableBorderColor,
|
|
515
|
+
});
|
|
516
|
+
const borderColorSvgWrap = createElement('span', { class: 'an-bubble-btn-svg' });
|
|
517
|
+
borderColorSvgWrap.innerHTML = ICONS.borderColor;
|
|
518
|
+
const borderColorStrip = createElement('span', { class: 'an-link-tooltip-color-strip' });
|
|
519
|
+
borderColorBtn.appendChild(borderColorSvgWrap);
|
|
520
|
+
borderColorBtn.appendChild(borderColorStrip);
|
|
521
|
+
this._borderColorStrip = borderColorStrip;
|
|
522
|
+
this._disposers.push(on(borderColorBtn, 'click', (e) => {
|
|
523
|
+
e.preventDefault();
|
|
524
|
+
e.stopPropagation();
|
|
525
|
+
this._openBorderColorPopover();
|
|
526
|
+
}));
|
|
527
|
+
el.appendChild(borderColorBtn);
|
|
474
528
|
|
|
475
529
|
el.appendChild(this._sep());
|
|
476
530
|
|
|
477
531
|
// Delete table (danger)
|
|
478
532
|
el.appendChild(this._makeBtn(ICONS.deleteTable, L.deleteTable, () => this._deleteTable(), true));
|
|
479
533
|
|
|
534
|
+
el.appendChild(this._sep());
|
|
535
|
+
el.appendChild(this._makeBtn(ICONS.exportCSV, L.exportCSV, () => this._exportTableCSV()));
|
|
536
|
+
|
|
480
537
|
// Keep tooltip alive while hovering.
|
|
481
538
|
// Don't schedule hide on mouseleave when the size popover is open —
|
|
482
539
|
// the user is moving the mouse toward it.
|
|
@@ -486,6 +543,7 @@ export class TableTooltip {
|
|
|
486
543
|
if (this._selectMode) return; // keep tooltip alive during cell selection
|
|
487
544
|
if (this._sizePopover && this._sizePopover.style.display !== 'none') return;
|
|
488
545
|
if (this._shadePopover && this._shadePopover.style.display !== 'none') return;
|
|
546
|
+
if (this._borderColorPopover && this._borderColorPopover.style.display !== 'none') return;
|
|
489
547
|
this._scheduleHide();
|
|
490
548
|
}),
|
|
491
549
|
);
|
|
@@ -546,6 +604,7 @@ export class TableTooltip {
|
|
|
546
604
|
if (!this._activeTable) return;
|
|
547
605
|
this._el.style.display = 'flex';
|
|
548
606
|
this._syncShadeStrip();
|
|
607
|
+
this._syncBorderColorStrip();
|
|
549
608
|
// Defer: offsetWidth on a newly-visible element forces layout synchronously
|
|
550
609
|
requestAnimationFrame(() => {
|
|
551
610
|
if (this._activeTable) this._positionNear(this._activeTable);
|
|
@@ -571,6 +630,7 @@ export class TableTooltip {
|
|
|
571
630
|
this._clearSelection();
|
|
572
631
|
this._clearTimers();
|
|
573
632
|
this._hideSizePopover();
|
|
633
|
+
this._hideBorderColorPopover();
|
|
574
634
|
}
|
|
575
635
|
|
|
576
636
|
_clearTimers() {
|
|
@@ -1048,6 +1108,22 @@ export class TableTooltip {
|
|
|
1048
1108
|
}
|
|
1049
1109
|
this.context.invoke('editor.afterCommand');
|
|
1050
1110
|
};
|
|
1111
|
+
} else if (type === 'cellPadding') {
|
|
1112
|
+
const cells = this._getSelectedCells();
|
|
1113
|
+
const firstCell = cells[0] || this._getCell();
|
|
1114
|
+
const currentPad = firstCell
|
|
1115
|
+
? (Number.parseInt(firstCell.style.padding, 10) ||
|
|
1116
|
+
Number.parseInt(firstCell.style.paddingTop, 10) || 4)
|
|
1117
|
+
: 4;
|
|
1118
|
+
this._sizeTitleEl.textContent = this.context.locale.tooltips.table.cellPaddingPx;
|
|
1119
|
+
this._sizeInputEl.min = '0';
|
|
1120
|
+
this._sizeInputEl.max = '40';
|
|
1121
|
+
this._sizeInputEl.value = String(currentPad);
|
|
1122
|
+
this._sizeApply = (val) => {
|
|
1123
|
+
const activeCells = this._getSelectedCells();
|
|
1124
|
+
activeCells.forEach((c) => { if (c) c.style.padding = `${val}px`; });
|
|
1125
|
+
this.context.invoke('editor.afterCommand');
|
|
1126
|
+
};
|
|
1051
1127
|
} else {
|
|
1052
1128
|
const isCol = type === 'col';
|
|
1053
1129
|
const activeCells = this._getSelectedCells().filter((c) => {
|
|
@@ -1148,7 +1224,7 @@ export class TableTooltip {
|
|
|
1148
1224
|
const customRow = createElement('div', { class: 'an-context-color-custom' });
|
|
1149
1225
|
const colorInput = /** @type {HTMLInputElement} */ (createElement('input', { type: 'color', class: 'an-shade-color-input', value: '#ffffff' }));
|
|
1150
1226
|
const customLabel = createElement('span');
|
|
1151
|
-
customLabel.textContent =
|
|
1227
|
+
customLabel.textContent = this.context.locale.contextMenu.customColorLabel;
|
|
1152
1228
|
this._disposers.push(on(colorInput, 'change', () => this._applyCellShade(colorInput.value)));
|
|
1153
1229
|
customRow.appendChild(colorInput);
|
|
1154
1230
|
customRow.appendChild(customLabel);
|
|
@@ -1211,4 +1287,213 @@ export class TableTooltip {
|
|
|
1211
1287
|
this._hideCellShadePopover();
|
|
1212
1288
|
this.context.invoke('editor.afterCommand');
|
|
1213
1289
|
}
|
|
1290
|
+
|
|
1291
|
+
// ---------------------------------------------------------------------------
|
|
1292
|
+
// Table border color popover
|
|
1293
|
+
// ---------------------------------------------------------------------------
|
|
1294
|
+
|
|
1295
|
+
_buildBorderColorPopover() {
|
|
1296
|
+
const pop = createElement('div', { class: 'an-cell-shade-popover' });
|
|
1297
|
+
pop.style.display = 'none';
|
|
1298
|
+
|
|
1299
|
+
const title = createElement('div', { class: 'an-size-popover-title' });
|
|
1300
|
+
pop.appendChild(title);
|
|
1301
|
+
this._borderColorTitleEl = title;
|
|
1302
|
+
|
|
1303
|
+
const palette = createElement('div', { class: 'an-context-color-palette' });
|
|
1304
|
+
SHADE_PRESETS.forEach((color) => {
|
|
1305
|
+
const sw = createElement('div', { class: 'an-context-color-swatch', title: color });
|
|
1306
|
+
sw.style.background = color;
|
|
1307
|
+
this._disposers.push(on(sw, 'click', (e) => {
|
|
1308
|
+
e.stopPropagation();
|
|
1309
|
+
this._applyBorderColor(color);
|
|
1310
|
+
}));
|
|
1311
|
+
palette.appendChild(sw);
|
|
1312
|
+
});
|
|
1313
|
+
pop.appendChild(palette);
|
|
1314
|
+
|
|
1315
|
+
const noColorRow = createElement('div', { class: 'an-context-color-custom' });
|
|
1316
|
+
const noColorBtn = createElement('button', { type: 'button', class: 'an-shade-no-color' });
|
|
1317
|
+
this._disposers.push(on(noColorBtn, 'click', () => this._applyBorderColor('')));
|
|
1318
|
+
noColorRow.appendChild(noColorBtn);
|
|
1319
|
+
pop.appendChild(noColorRow);
|
|
1320
|
+
this._borderColorNoBtn = noColorBtn;
|
|
1321
|
+
|
|
1322
|
+
const customRow = createElement('div', { class: 'an-context-color-custom' });
|
|
1323
|
+
const colorInput = /** @type {HTMLInputElement} */ (createElement('input', { type: 'color', class: 'an-shade-color-input', value: '#000000' }));
|
|
1324
|
+
const customLabel = createElement('span');
|
|
1325
|
+
customLabel.textContent = this.context.locale.contextMenu.customColorLabel;
|
|
1326
|
+
this._disposers.push(on(colorInput, 'change', () => this._applyBorderColor(colorInput.value)));
|
|
1327
|
+
customRow.appendChild(colorInput);
|
|
1328
|
+
customRow.appendChild(customLabel);
|
|
1329
|
+
pop.appendChild(customRow);
|
|
1330
|
+
|
|
1331
|
+
this._disposers.push(
|
|
1332
|
+
on(pop, 'mousedown', (e) => e.preventDefault()),
|
|
1333
|
+
on(pop, 'mouseenter', () => this._clearTimers()),
|
|
1334
|
+
on(pop, 'mouseleave', () => this._scheduleHide()),
|
|
1335
|
+
on(document, 'click', (e) => {
|
|
1336
|
+
const et = /** @type {Node} */ (e.target);
|
|
1337
|
+
if (this._borderColorPopover &&
|
|
1338
|
+
this._borderColorPopover.style.display !== 'none' &&
|
|
1339
|
+
!this._borderColorPopover.contains(et) &&
|
|
1340
|
+
!this._el?.contains(et)) {
|
|
1341
|
+
this._hideBorderColorPopover();
|
|
1342
|
+
}
|
|
1343
|
+
}),
|
|
1344
|
+
);
|
|
1345
|
+
|
|
1346
|
+
return pop;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
_openBorderColorPopover() {
|
|
1350
|
+
if (!this._borderColorPopover) return;
|
|
1351
|
+
const L = this.context.locale.tooltips.table;
|
|
1352
|
+
if (this._borderColorTitleEl) this._borderColorTitleEl.textContent = L.tableBorderColor;
|
|
1353
|
+
if (this._borderColorNoBtn) this._borderColorNoBtn.textContent = L.noBorderColor;
|
|
1354
|
+
|
|
1355
|
+
this._borderColorPopover.style.display = 'block';
|
|
1356
|
+
requestAnimationFrame(() => {
|
|
1357
|
+
if (!this._borderColorPopover || !this._el) return;
|
|
1358
|
+
const pw = this._borderColorPopover.offsetWidth || 170;
|
|
1359
|
+
const ph = this._borderColorPopover.offsetHeight || 120;
|
|
1360
|
+
const tipRect = this._el.getBoundingClientRect();
|
|
1361
|
+
let left = tipRect.left;
|
|
1362
|
+
let top = tipRect.bottom + 6;
|
|
1363
|
+
if (left + pw > globalThis.innerWidth - 8) left = globalThis.innerWidth - pw - 8;
|
|
1364
|
+
if (top + ph > globalThis.innerHeight - 8) top = tipRect.top - ph - 6;
|
|
1365
|
+
this._borderColorPopover.style.left = `${Math.max(8, left)}px`;
|
|
1366
|
+
this._borderColorPopover.style.top = `${Math.max(8, top)}px`;
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
_hideBorderColorPopover() {
|
|
1371
|
+
if (this._borderColorPopover) this._borderColorPopover.style.display = 'none';
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
_applyBorderColor(color) {
|
|
1375
|
+
const table = this._activeTable;
|
|
1376
|
+
if (!table) return;
|
|
1377
|
+
Array.from(table.querySelectorAll('td, th')).forEach((c) => { c.style.borderColor = color; });
|
|
1378
|
+
if (this._borderColorStrip) {
|
|
1379
|
+
this._borderColorStrip.style.background = color || 'transparent';
|
|
1380
|
+
}
|
|
1381
|
+
this._hideBorderColorPopover();
|
|
1382
|
+
this.context.invoke('editor.afterCommand');
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
_syncBorderColorStrip() {
|
|
1386
|
+
if (!this._borderColorStrip || !this._el || this._el.style.display === 'none') return;
|
|
1387
|
+
const firstCell = this._activeTable?.querySelector('td, th');
|
|
1388
|
+
this._borderColorStrip.style.background = firstCell?.style.borderColor || 'transparent';
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
// ---------------------------------------------------------------------------
|
|
1392
|
+
// Cell text alignment
|
|
1393
|
+
// ---------------------------------------------------------------------------
|
|
1394
|
+
|
|
1395
|
+
_applyCellAlign(align) {
|
|
1396
|
+
const cells = this._getSelectedCells();
|
|
1397
|
+
cells.forEach((c) => { if (c) c.style.textAlign = align; });
|
|
1398
|
+
this.context.invoke('editor.afterCommand');
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// ---------------------------------------------------------------------------
|
|
1402
|
+
// Toggle header row
|
|
1403
|
+
// ---------------------------------------------------------------------------
|
|
1404
|
+
|
|
1405
|
+
_toggleHeaderRow() {
|
|
1406
|
+
const table = this._activeTable;
|
|
1407
|
+
if (!table) return;
|
|
1408
|
+
const firstRow = table.querySelector('tr');
|
|
1409
|
+
if (!firstRow) return;
|
|
1410
|
+
|
|
1411
|
+
const isInThead = firstRow.closest('thead') !== null;
|
|
1412
|
+
|
|
1413
|
+
if (isInThead) {
|
|
1414
|
+
// Convert th → td and move row to tbody
|
|
1415
|
+
let tbody = table.querySelector('tbody');
|
|
1416
|
+
if (!tbody) {
|
|
1417
|
+
tbody = document.createElement('tbody');
|
|
1418
|
+
table.appendChild(tbody);
|
|
1419
|
+
}
|
|
1420
|
+
Array.from(firstRow.cells).forEach((cell) => {
|
|
1421
|
+
const td = document.createElement('td');
|
|
1422
|
+
td.innerHTML = cell.innerHTML;
|
|
1423
|
+
td.style.cssText = cell.style.cssText;
|
|
1424
|
+
firstRow.replaceChild(td, cell);
|
|
1425
|
+
});
|
|
1426
|
+
tbody.insertBefore(firstRow, tbody.firstChild);
|
|
1427
|
+
const thead = table.querySelector('thead');
|
|
1428
|
+
if (thead && thead.rows.length === 0) thead.remove();
|
|
1429
|
+
} else {
|
|
1430
|
+
// Convert td → th and move row to thead
|
|
1431
|
+
let thead = table.querySelector('thead');
|
|
1432
|
+
if (!thead) {
|
|
1433
|
+
thead = document.createElement('thead');
|
|
1434
|
+
table.insertBefore(thead, table.firstChild);
|
|
1435
|
+
}
|
|
1436
|
+
Array.from(firstRow.cells).forEach((cell) => {
|
|
1437
|
+
const th = document.createElement('th');
|
|
1438
|
+
th.innerHTML = cell.innerHTML;
|
|
1439
|
+
th.style.cssText = cell.style.cssText;
|
|
1440
|
+
firstRow.replaceChild(th, cell);
|
|
1441
|
+
});
|
|
1442
|
+
thead.appendChild(firstRow);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
this.context.invoke('editor.afterCommand');
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
_sortColumn(direction) {
|
|
1449
|
+
const table = this._activeTable;
|
|
1450
|
+
if (!table) return;
|
|
1451
|
+
const cell = this._getCell();
|
|
1452
|
+
if (!cell) return;
|
|
1453
|
+
const colIdx = getVisualColIndex(cell);
|
|
1454
|
+
if (colIdx === -1) return;
|
|
1455
|
+
const tbody = table.querySelector('tbody') || table;
|
|
1456
|
+
const rows = Array.from(tbody.querySelectorAll(':scope > tr'));
|
|
1457
|
+
if (rows.length < 2) return;
|
|
1458
|
+
rows.sort((a, b) => {
|
|
1459
|
+
const aCell = getCellAtVisualCol(a, colIdx);
|
|
1460
|
+
const bCell = getCellAtVisualCol(b, colIdx);
|
|
1461
|
+
const aText = (aCell?.textContent || '').trim();
|
|
1462
|
+
const bText = (bCell?.textContent || '').trim();
|
|
1463
|
+
const aNum = parseFloat(aText);
|
|
1464
|
+
const bNum = parseFloat(bText);
|
|
1465
|
+
if (!isNaN(aNum) && !isNaN(bNum)) {
|
|
1466
|
+
return direction === 'asc' ? aNum - bNum : bNum - aNum;
|
|
1467
|
+
}
|
|
1468
|
+
return direction === 'asc'
|
|
1469
|
+
? aText.localeCompare(bText)
|
|
1470
|
+
: bText.localeCompare(aText);
|
|
1471
|
+
});
|
|
1472
|
+
rows.forEach((row) => tbody.appendChild(row));
|
|
1473
|
+
this.context.invoke('editor.afterCommand');
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
_exportTableCSV() {
|
|
1477
|
+
const table = this._activeTable;
|
|
1478
|
+
if (!table) return;
|
|
1479
|
+
const rows = Array.from(table.querySelectorAll('tr'));
|
|
1480
|
+
const csv = rows.map((row) =>
|
|
1481
|
+
Array.from(row.querySelectorAll('td, th'))
|
|
1482
|
+
.map((cell) => {
|
|
1483
|
+
const text = (cell.textContent || '').trim().replace(/"/g, '""');
|
|
1484
|
+
return `"${text}"`;
|
|
1485
|
+
})
|
|
1486
|
+
.join(',')
|
|
1487
|
+
).join('\n');
|
|
1488
|
+
const blob = new Blob(['' + csv], { type: 'text/csv;charset=utf-8;' });
|
|
1489
|
+
const url = URL.createObjectURL(blob);
|
|
1490
|
+
const a = document.createElement('a');
|
|
1491
|
+
a.href = url;
|
|
1492
|
+
a.download = 'table.csv';
|
|
1493
|
+
a.style.display = 'none';
|
|
1494
|
+
document.body.appendChild(a);
|
|
1495
|
+
a.click();
|
|
1496
|
+
a.remove();
|
|
1497
|
+
URL.revokeObjectURL(url);
|
|
1498
|
+
}
|
|
1214
1499
|
}
|
package/src/js/renderer.js
CHANGED
|
@@ -70,11 +70,14 @@ export function renderLayout(targetEl, options) {
|
|
|
70
70
|
|
|
71
71
|
container.appendChild(editable);
|
|
72
72
|
|
|
73
|
-
// Apply
|
|
74
|
-
// popovers) appended to document.body inherit the
|
|
73
|
+
// Apply theme — also add to body so floating elements (dialogs, tooltips,
|
|
74
|
+
// popovers) appended to document.body inherit the CSS rules.
|
|
75
75
|
if (options.theme === 'dark') {
|
|
76
76
|
container.classList.add('an-theme-dark');
|
|
77
77
|
document.body.classList.add('an-theme-dark');
|
|
78
|
+
} else if (options.theme === 'auto') {
|
|
79
|
+
container.classList.add('an-theme-auto');
|
|
80
|
+
document.body.classList.add('an-theme-auto');
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
// Read-only mode
|
|
@@ -108,6 +108,12 @@
|
|
|
108
108
|
user-select: none;
|
|
109
109
|
// Round the top corners to match the container border-radius
|
|
110
110
|
border-radius: $an-radius $an-radius 0 0;
|
|
111
|
+
overflow-x: auto;
|
|
112
|
+
scrollbar-width: none;
|
|
113
|
+
|
|
114
|
+
&::-webkit-scrollbar {
|
|
115
|
+
display: none;
|
|
116
|
+
}
|
|
111
117
|
}
|
|
112
118
|
|
|
113
119
|
.an-btn-group {
|
|
@@ -477,6 +483,26 @@
|
|
|
477
483
|
padding: 0;
|
|
478
484
|
}
|
|
479
485
|
}
|
|
486
|
+
|
|
487
|
+
// Code block line numbers (toggled via CodeTooltip)
|
|
488
|
+
.an-code-line-numbers {
|
|
489
|
+
position: relative;
|
|
490
|
+
padding-left: 3.5em !important;
|
|
491
|
+
|
|
492
|
+
&::before {
|
|
493
|
+
content: '';
|
|
494
|
+
position: absolute;
|
|
495
|
+
left: 0;
|
|
496
|
+
top: 0;
|
|
497
|
+
bottom: 0;
|
|
498
|
+
width: 3em;
|
|
499
|
+
background: rgba(0, 0, 0, 0.04);
|
|
500
|
+
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
|
501
|
+
pointer-events: none;
|
|
502
|
+
z-index: 0;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
480
506
|
a { color: $an-primary; }
|
|
481
507
|
hr { border: none; border-top: 2px solid $an-border; margin: 1em 0; }
|
|
482
508
|
img.an-image {
|
|
@@ -1938,6 +1964,11 @@ $an-video-accent: #8b5cf6; // violet-500
|
|
|
1938
1964
|
color: #cdd6f4;
|
|
1939
1965
|
}
|
|
1940
1966
|
|
|
1967
|
+
.an-code-line-numbers::before {
|
|
1968
|
+
background: rgba(255, 255, 255, 0.05);
|
|
1969
|
+
border-right-color: rgba(255, 255, 255, 0.1);
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1941
1972
|
hr { border-color: #3f3f5f; }
|
|
1942
1973
|
|
|
1943
1974
|
table, .an-table {
|
|
@@ -2328,6 +2359,156 @@ $an-video-accent: #8b5cf6; // violet-500
|
|
|
2328
2359
|
color: $an-dark-muted;
|
|
2329
2360
|
}
|
|
2330
2361
|
|
|
2362
|
+
// =============================================================================
|
|
2363
|
+
// Auto theme — mirrors dark theme when OS prefers dark and no explicit theme set
|
|
2364
|
+
// =============================================================================
|
|
2365
|
+
|
|
2366
|
+
@media (prefers-color-scheme: dark) {
|
|
2367
|
+
.an-theme-auto {
|
|
2368
|
+
border-color: #3f3f5f;
|
|
2369
|
+
background: #1e1e2e;
|
|
2370
|
+
color: #cdd6f4;
|
|
2371
|
+
|
|
2372
|
+
&.an-focused {
|
|
2373
|
+
border-color: #89b4fa;
|
|
2374
|
+
box-shadow: 0 0 0 3px rgba(#89b4fa, 0.2);
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
.an-toolbar {
|
|
2378
|
+
background: #181825;
|
|
2379
|
+
border-color: #3f3f5f;
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
.an-btn {
|
|
2383
|
+
color: #cdd6f4;
|
|
2384
|
+
|
|
2385
|
+
&:hover {
|
|
2386
|
+
background: #2a2a3e;
|
|
2387
|
+
border-color: #3f3f5f;
|
|
2388
|
+
color: #cdd6f4;
|
|
2389
|
+
|
|
2390
|
+
svg { stroke: #cdd6f4; }
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
&.active {
|
|
2394
|
+
background: #1a3a5c;
|
|
2395
|
+
border-color: #89b4fa;
|
|
2396
|
+
color: #89b4fa;
|
|
2397
|
+
|
|
2398
|
+
svg { stroke: #89b4fa; }
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
&.an-btn-primary {
|
|
2402
|
+
background: #3b5bdb;
|
|
2403
|
+
border-color: #3b5bdb;
|
|
2404
|
+
color: #fff;
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
.an-select {
|
|
2409
|
+
background-color: #1e1e2e;
|
|
2410
|
+
border-color: #3f3f5f;
|
|
2411
|
+
color: #cdd6f4;
|
|
2412
|
+
|
|
2413
|
+
&:hover, &:focus { border-color: #89b4fa; }
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
.an-editable {
|
|
2417
|
+
background: #1e1e2e;
|
|
2418
|
+
color: #cdd6f4;
|
|
2419
|
+
|
|
2420
|
+
a { color: #89b4fa; }
|
|
2421
|
+
|
|
2422
|
+
blockquote {
|
|
2423
|
+
border-color: #3f3f5f;
|
|
2424
|
+
color: #a6adc8;
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
pre:not([class*='language-']),
|
|
2428
|
+
code:not([class*='language-']) {
|
|
2429
|
+
background: #313244;
|
|
2430
|
+
color: #cdd6f4;
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
hr { border-color: #3f3f5f; }
|
|
2434
|
+
|
|
2435
|
+
table, .an-table {
|
|
2436
|
+
td, th { border-color: #3f3f5f; }
|
|
2437
|
+
th { background: #313244; }
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
&.an-placeholder::before { color: #6c7086; }
|
|
2441
|
+
|
|
2442
|
+
figcaption.an-figcaption { color: #6c7086; }
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
.an-statusbar {
|
|
2446
|
+
background: #181825;
|
|
2447
|
+
border-color: #3f3f5f;
|
|
2448
|
+
color: #6c7086;
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2451
|
+
.an-link-tooltip,
|
|
2452
|
+
.an-contextmenu {
|
|
2453
|
+
background: #24273a;
|
|
2454
|
+
border-color: #3f3f5f;
|
|
2455
|
+
color: #cdd6f4;
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
.an-link-tooltip-url { color: #89b4fa; }
|
|
2459
|
+
|
|
2460
|
+
.an-link-tooltip-btn {
|
|
2461
|
+
color: #a6adc8;
|
|
2462
|
+
|
|
2463
|
+
&:hover {
|
|
2464
|
+
background: #2a2a3e;
|
|
2465
|
+
color: #cdd6f4;
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
.an-dialog-overlay { background: rgba(0, 0, 0, 0.65); }
|
|
2470
|
+
|
|
2471
|
+
.an-dialog-box {
|
|
2472
|
+
background: #24273a;
|
|
2473
|
+
color: #cdd6f4;
|
|
2474
|
+
border: 1px solid #3f3f5f;
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
.an-dialog-title { color: #cdd6f4; }
|
|
2478
|
+
|
|
2479
|
+
.an-input {
|
|
2480
|
+
background: #313244;
|
|
2481
|
+
border-color: #3f3f5f;
|
|
2482
|
+
color: #cdd6f4;
|
|
2483
|
+
|
|
2484
|
+
&:focus {
|
|
2485
|
+
border-color: #89b4fa;
|
|
2486
|
+
box-shadow: 0 0 0 3px rgba(#89b4fa, 0.15);
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
.an-color-popup,
|
|
2491
|
+
.an-table-picker-popup,
|
|
2492
|
+
.an-size-popover,
|
|
2493
|
+
.an-cell-shade-popover {
|
|
2494
|
+
background: #24273a;
|
|
2495
|
+
border-color: #3f3f5f;
|
|
2496
|
+
color: #cdd6f4;
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
.an-context-color-swatch {
|
|
2500
|
+
border-color: rgba(255, 255, 255, 0.15);
|
|
2501
|
+
&:hover { border-color: rgba(255, 255, 255, 0.5); }
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
.an-label { color: #cdd6f4; }
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
.an-theme-auto .an-editable ul.an-checklist li:has(input[type='checkbox']:checked) {
|
|
2508
|
+
color: $an-dark-muted;
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2331
2512
|
// =============================================================================
|
|
2332
2513
|
// Print styles
|
|
2333
2514
|
// =============================================================================
|
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AutumnNote – TypeScript declarations
|
|
3
|
-
* @version 1.0
|
|
3
|
+
* @version 1.7.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
@@ -67,7 +67,7 @@ export interface AsnOptions {
|
|
|
67
67
|
/** Top offset in px for sticky toolbar (e.g. height of a fixed nav bar). */
|
|
68
68
|
stickyToolbarOffset?: number;
|
|
69
69
|
/** Colour theme: 'light' (default) | 'dark'. */
|
|
70
|
-
theme?: 'light' | 'dark';
|
|
70
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
71
71
|
/** Auto-load Prism.js for syntax highlighting inside code blocks. */
|
|
72
72
|
codeHighlight?: boolean;
|
|
73
73
|
/** CDN base URL for Prism assets. */
|
|
@@ -158,8 +158,13 @@ export interface MentionOptions {
|
|
|
158
158
|
maxResults?: number;
|
|
159
159
|
/** Debounce delay in ms before calling onSearch. Default: 200. */
|
|
160
160
|
debounce?: number;
|
|
161
|
-
/**
|
|
162
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Called to fetch matching items for the given query.
|
|
163
|
+
* Supports both callback and Promise styles:
|
|
164
|
+
* - Callback: `onSearch(query, callback) { callback(items); }`
|
|
165
|
+
* - Promise: `async onSearch(query) { return items; }`
|
|
166
|
+
*/
|
|
167
|
+
onSearch: (query: string, callback: (items: MentionItem[]) => void) => void | Promise<MentionItem[]>;
|
|
163
168
|
/** Optional. Return custom HTML string for the inserted chip, or null to use the default. */
|
|
164
169
|
onInsert?: (item: MentionItem) => string | null;
|
|
165
170
|
/** CSS class added to the inserted mention chip. Default: 'an-mention'. */
|
|
@@ -379,6 +384,12 @@ export declare class Context {
|
|
|
379
384
|
*/
|
|
380
385
|
clearHistory(): void;
|
|
381
386
|
|
|
387
|
+
/** Returns the number of available undo steps. */
|
|
388
|
+
getUndoCount(): number;
|
|
389
|
+
|
|
390
|
+
/** Returns the number of available redo steps. */
|
|
391
|
+
getRedoCount(): number;
|
|
392
|
+
|
|
382
393
|
/** Returns true when the editor has no meaningful content. */
|
|
383
394
|
isEmpty(): boolean;
|
|
384
395
|
|
|
@@ -400,6 +411,9 @@ export declare class Context {
|
|
|
400
411
|
/** Returns the current character count (excluding newlines) of the editor content. */
|
|
401
412
|
getCharCount(): number;
|
|
402
413
|
|
|
414
|
+
/** Returns an array of heading objects representing the table of contents. */
|
|
415
|
+
getTableOfContents(): { level: number; text: string; element: HTMLElement }[];
|
|
416
|
+
|
|
403
417
|
/** Downloads the editor content as an HTML file. */
|
|
404
418
|
downloadHTML(filename?: string): void;
|
|
405
419
|
|