autumnnote 2.1.0 → 2.3.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 (65) hide show
  1. package/README.md +74 -6
  2. package/dist/autumnnote.cjs +27 -22
  3. package/dist/autumnnote.es.js +474 -591
  4. package/dist/autumnnote.es.js.map +1 -1
  5. package/dist/autumnnote.min.js +27 -22
  6. package/dist/autumnnote.umd.js +27 -22
  7. package/dist/autumnnote.umd.js.map +1 -1
  8. package/dist/icon-data-V0Xqv-wX.js +255 -0
  9. package/dist/icon-data-V0Xqv-wX.js.map +1 -0
  10. package/package.json +12 -3
  11. package/types/index.d.ts +8 -0
  12. package/src/js/Context.js +0 -854
  13. package/src/js/core/detectLang.js +0 -98
  14. package/src/js/core/dom.js +0 -372
  15. package/src/js/core/env.js +0 -38
  16. package/src/js/core/key.js +0 -66
  17. package/src/js/core/lists.js +0 -121
  18. package/src/js/core/markdown.js +0 -695
  19. package/src/js/core/range.js +0 -194
  20. package/src/js/core/sanitise.js +0 -304
  21. package/src/js/editing/History.js +0 -266
  22. package/src/js/editing/Style.js +0 -812
  23. package/src/js/editing/Table.js +0 -105
  24. package/src/js/editing/Typing.js +0 -397
  25. package/src/js/index.js +0 -193
  26. package/src/js/index.umd.js +0 -17
  27. package/src/js/module/AutoSaveRestore.js +0 -125
  28. package/src/js/module/BaseDialog.js +0 -133
  29. package/src/js/module/BaseMediaTooltip.js +0 -142
  30. package/src/js/module/BaseResizer.js +0 -322
  31. package/src/js/module/BubbleToolbar.js +0 -483
  32. package/src/js/module/Buttons.js +0 -399
  33. package/src/js/module/Clipboard.js +0 -579
  34. package/src/js/module/CodeTooltip.js +0 -493
  35. package/src/js/module/Codeview.js +0 -125
  36. package/src/js/module/ContextMenu.js +0 -621
  37. package/src/js/module/Editor.js +0 -747
  38. package/src/js/module/EmojiDialog.js +0 -254
  39. package/src/js/module/FindReplace.js +0 -512
  40. package/src/js/module/Fullscreen.js +0 -80
  41. package/src/js/module/IconDialog.js +0 -618
  42. package/src/js/module/ImageCropOverlay.js +0 -586
  43. package/src/js/module/ImageDialog.js +0 -193
  44. package/src/js/module/ImageResizer.js +0 -42
  45. package/src/js/module/ImageTooltip.js +0 -285
  46. package/src/js/module/LinkDialog.js +0 -145
  47. package/src/js/module/LinkTooltip.js +0 -250
  48. package/src/js/module/MarkdownShortcuts.js +0 -250
  49. package/src/js/module/Mention.js +0 -365
  50. package/src/js/module/Placeholder.js +0 -51
  51. package/src/js/module/ShortcutsDialog.js +0 -111
  52. package/src/js/module/SlashMenu.js +0 -376
  53. package/src/js/module/Statusbar.js +0 -246
  54. package/src/js/module/TableTooltip.js +0 -1392
  55. package/src/js/module/Toolbar.js +0 -855
  56. package/src/js/module/VideoDialog.js +0 -193
  57. package/src/js/module/VideoResizer.js +0 -66
  58. package/src/js/module/VideoTooltip.js +0 -248
  59. package/src/js/module/emoji-data.js +0 -496
  60. package/src/js/module/table-grid.js +0 -102
  61. package/src/js/module/table-icons.js +0 -33
  62. package/src/js/renderer.js +0 -120
  63. package/src/js/settings.js +0 -214
  64. package/src/styles/_variables.scss +0 -48
  65. package/src/styles/autumnnote.scss +0 -2877
@@ -1,17 +0,0 @@
1
- /**
2
- * index.umd.js — UMD entry point for AutumnNote
3
- *
4
- * Re-exports only the default export so the UMD global is the factory object
5
- * directly, enabling the script-tag usage documented in the README:
6
- *
7
- * <script src="dist/autumnnote.umd.js"></script>
8
- * <script>
9
- * const editor = AutumnNote.create('#my-editor');
10
- * </script>
11
- */
12
- // Script-tag consumers have no bundler to tree-shake with, so every locale is
13
- // pre-registered here and `lang: 'vi'` works without extra imports. ESM
14
- // consumers opt in per locale via `autumnnote/i18n/<code>` instead.
15
- import './i18n/all.js';
16
-
17
- export { default } from './index.js';
@@ -1,125 +0,0 @@
1
- /**
2
- * AutoSaveRestore.js — Detects a previously auto-saved draft and offers the
3
- * user a banner to restore or discard it.
4
- *
5
- * Activated when both `autoSave` and `autoSaveRestore` options are true.
6
- * On initialize it checks localStorage for a draft that is within the
7
- * `autoSaveRestoreTimeout` day globalThis. If one is found a dismissible banner
8
- * is prepended to the editor container.
9
- */
10
-
11
- export class AutoSaveRestore {
12
- /** @param {import('../Context.js').Context} context */
13
- constructor(context) {
14
- this.context = context;
15
- this.options = context.options;
16
-
17
- /** @type {HTMLElement|null} */
18
- this._banner = null;
19
- }
20
-
21
- initialize() {
22
- if (!this.options.autoSave || !this.options.autoSaveRestore) return this;
23
-
24
- const key = this.options.autoSaveKey;
25
- const metaKey = key + ':asrmeta';
26
-
27
- let saved;
28
- let meta;
29
- try {
30
- saved = localStorage.getItem(key);
31
- meta = JSON.parse(localStorage.getItem(metaKey) || '{}');
32
- } catch (_) {
33
- void _;
34
- return this;
35
- }
36
-
37
- if (!saved) return this;
38
-
39
- const timeout = this.options.autoSaveRestoreTimeout;
40
- if (timeout > 0) {
41
- const ageMs = Date.now() - (meta.savedAt || 0);
42
- if (ageMs > timeout * 86400000) {
43
- try { localStorage.removeItem(key); localStorage.removeItem(metaKey); } catch (_) { void _; }
44
- return this;
45
- }
46
- }
47
-
48
- this._showBanner(saved, meta);
49
- return this;
50
- }
51
-
52
- destroy() {
53
- this._removeBanner();
54
- }
55
-
56
- // ---------------------------------------------------------------------------
57
- // Internal
58
- // ---------------------------------------------------------------------------
59
-
60
- _showBanner(draftHtml, meta) {
61
- const locale = this.context.locale;
62
- const t = locale.autoSaveRestore || {};
63
- const label = t.found || 'Draft found. Restore?';
64
- const restoreLabel = t.restore || 'Restore';
65
- const discardLabel = t.discard || 'Discard';
66
-
67
- const banner = document.createElement('div');
68
- banner.className = 'an-asr-banner';
69
- banner.setAttribute('role', 'alert');
70
-
71
- const msg = document.createElement('span');
72
- msg.className = 'an-asr-msg';
73
- if (meta.savedAt) {
74
- const d = new Date(meta.savedAt);
75
- const formatted = d.toLocaleString();
76
- msg.textContent = (t.foundAt || 'Draft from {date}. Restore?').replace('{date}', formatted);
77
- } else {
78
- msg.textContent = label;
79
- }
80
-
81
- const restoreBtn = document.createElement('button');
82
- restoreBtn.type = 'button';
83
- restoreBtn.className = 'an-btn an-asr-btn-restore';
84
- restoreBtn.textContent = restoreLabel;
85
- restoreBtn.addEventListener('click', () => this._restore(draftHtml));
86
-
87
- const discardBtn = document.createElement('button');
88
- discardBtn.type = 'button';
89
- discardBtn.className = 'an-btn an-asr-btn-discard';
90
- discardBtn.textContent = discardLabel;
91
- discardBtn.addEventListener('click', () => this._discard());
92
-
93
- banner.appendChild(msg);
94
- banner.appendChild(restoreBtn);
95
- banner.appendChild(discardBtn);
96
-
97
- this._banner = banner;
98
- const container = this.context.layoutInfo.container;
99
- container.insertBefore(banner, container.firstChild);
100
- }
101
-
102
- _restore(draftHtml) {
103
- this.context.setHTML(draftHtml);
104
- this.context.clearHistory();
105
- this._removeBanner();
106
-
107
- if (typeof this.options.onAutoSaveRestore === 'function') {
108
- this.options.onAutoSaveRestore(draftHtml, this.context);
109
- }
110
- }
111
-
112
- _discard() {
113
- const key = this.options.autoSaveKey;
114
- try {
115
- localStorage.removeItem(key);
116
- localStorage.removeItem(key + ':asrmeta');
117
- } catch (_) { void _; }
118
- this._removeBanner();
119
- }
120
-
121
- _removeBanner() {
122
- this._banner?.remove();
123
- this._banner = null;
124
- }
125
- }
@@ -1,133 +0,0 @@
1
- import { createElement, on, trapFocus, makeDraggable } from '../core/dom.js';
2
- import { withSavedRange } from '../core/range.js';
3
-
4
- /**
5
- * Shared lifecycle and shell-building logic for all modal dialogs.
6
- * Subclasses implement _buildDialog() for their specific form fields.
7
- */
8
- export class BaseDialog {
9
- /** @param {import('../Context.js').Context} context */
10
- constructor(context) {
11
- this.context = context;
12
- this.options = context.options;
13
- /** @type {HTMLElement|null} */
14
- this._dialog = null;
15
- this._disposers = [];
16
- this._savedRange = null;
17
- /** @type {HTMLElement|null} First focusable input; set by subclass in _buildDialog(). */
18
- this._firstInput = null;
19
- this._removeTrap = null;
20
- }
21
-
22
- // ---------------------------------------------------------------------------
23
- // Abstract — subclasses must override
24
- // ---------------------------------------------------------------------------
25
-
26
- /** @returns {HTMLElement} */
27
- _buildDialog() { throw new Error('_buildDialog() must be implemented by subclass'); }
28
-
29
- // ---------------------------------------------------------------------------
30
- // Lifecycle (shared)
31
- // ---------------------------------------------------------------------------
32
-
33
- initialize() {
34
- this._dialog = this._buildDialog();
35
- document.body.appendChild(this._dialog);
36
- return this;
37
- }
38
-
39
- destroy() {
40
- this._disposers.forEach((d) => d());
41
- this._disposers = [];
42
- if (this._dialog?.parentNode) {
43
- this._dialog.remove();
44
- }
45
- this._dialog = null;
46
- }
47
-
48
- // ---------------------------------------------------------------------------
49
- // Shared show helpers
50
- // ---------------------------------------------------------------------------
51
-
52
- /** Saves the current selection range before opening the dialog. */
53
- _saveRange() {
54
- withSavedRange((range) => { this._savedRange = range; });
55
- }
56
-
57
- _open() {
58
- if (this._dialog) {
59
- this._dialog.style.display = 'flex';
60
- this._removeTrap = trapFocus(this._dialog, () => this._close());
61
- setTimeout(() => this._firstInput?.focus(), 50);
62
- }
63
- }
64
-
65
- _close() {
66
- if (this._dialog) this._dialog.style.display = 'none';
67
- if (this._removeTrap) { this._removeTrap(); this._removeTrap = null; }
68
- this._savedRange = null;
69
- }
70
-
71
- // ---------------------------------------------------------------------------
72
- // Shell builders (used by subclass _buildDialog())
73
- // ---------------------------------------------------------------------------
74
-
75
- /**
76
- * Builds the overlay + box + header shell common to all dialogs.
77
- * Also wires up draggable and overlay-click-to-close.
78
- * @param {string} ariaLabel
79
- * @param {string} iconHtml Raw SVG string for the dialog icon
80
- * @param {string} titleText
81
- * @returns {{ overlay: HTMLElement, box: HTMLElement }}
82
- */
83
- _buildDialogShell(ariaLabel, iconHtml, titleText) {
84
- const overlay = createElement('div', {
85
- class: 'an-dialog-overlay',
86
- role: 'dialog',
87
- 'aria-modal': 'true',
88
- 'aria-label': ariaLabel,
89
- });
90
- const box = createElement('div', { class: 'an-dialog-box' });
91
-
92
- const header = createElement('div', { class: 'an-dialog-header' });
93
- const iconEl = createElement('span', { class: 'an-dialog-icon' });
94
- iconEl.innerHTML = iconHtml;
95
- const titleEl = createElement('h3', { class: 'an-dialog-title' });
96
- titleEl.textContent = titleText;
97
- header.appendChild(iconEl);
98
- header.appendChild(titleEl);
99
-
100
- box.appendChild(header);
101
- overlay.appendChild(box);
102
- makeDraggable(header, box);
103
-
104
- const d = on(overlay, 'click', (e) => { if (e.target === overlay) this._close(); });
105
- this._disposers.push(d);
106
-
107
- return { overlay, box };
108
- }
109
-
110
- /**
111
- * Builds an action button row with a primary insert button and a cancel button.
112
- * Disposers are registered automatically.
113
- * @param {string} insertLabel
114
- * @param {string} cancelLabel
115
- * @param {() => void} onInsert
116
- * @returns {HTMLElement}
117
- */
118
- _buildButtonRow(insertLabel, cancelLabel, onInsert) {
119
- const btnRow = createElement('div', { class: 'an-dialog-actions' });
120
- const insertBtn = createElement('button', { type: 'button', class: 'an-btn an-btn-primary' });
121
- insertBtn.textContent = insertLabel;
122
- const cancelBtn = createElement('button', { type: 'button', class: 'an-btn' });
123
- cancelBtn.textContent = cancelLabel;
124
- btnRow.appendChild(insertBtn);
125
- btnRow.appendChild(cancelBtn);
126
-
127
- const d1 = on(insertBtn, 'click', onInsert);
128
- const d2 = on(cancelBtn, 'click', () => this._close());
129
- this._disposers.push(d1, d2);
130
-
131
- return btnRow;
132
- }
133
- }
@@ -1,142 +0,0 @@
1
- /**
2
- * BaseMediaTooltip.js — Shared hover-tooltip behaviour for media embeds.
3
- *
4
- * ImageTooltip and VideoTooltip duplicated their button factory, show/hide
5
- * timers and viewport-aware positioning (~22% of both files). Those pieces live
6
- * here; each subclass keeps only what genuinely differs — which element counts
7
- * as the target, which buttons the bar contains, and the actions behind them.
8
- *
9
- * Mirrors the existing BaseDialog / BaseResizer pattern.
10
- */
11
-
12
- import { createElement, on } from '../core/dom.js';
13
-
14
- /** Delay before a hovered target shows its tooltip. */
15
- export const SHOW_DELAY = 100;
16
- /** Grace period before a tooltip hides after the pointer leaves. */
17
- export const HIDE_DELAY = 180;
18
-
19
- export class BaseMediaTooltip {
20
- /** @param {import('../Context.js').Context} context */
21
- constructor(context) {
22
- this.context = context;
23
- this.options = context.options;
24
- /** @type {HTMLElement|null} The tooltip bar */
25
- this._el = null;
26
- /** @type {HTMLElement|null} Currently hovered target */
27
- this._active = null;
28
- this._showTimer = null;
29
- this._hideTimer = null;
30
- this._disposers = [];
31
- }
32
-
33
- // ---------------------------------------------------------------------------
34
- // Subclass hooks
35
- // ---------------------------------------------------------------------------
36
-
37
- /**
38
- * Whether `_scheduleHide` is allowed to start the hide countdown. Subclasses
39
- * override to pin the tooltip open (e.g. while a video preview is playing).
40
- * @returns {boolean}
41
- */
42
- _canHide() { return true; }
43
-
44
- /** Runs just before the tooltip is hidden, for subclass-specific teardown. */
45
- _beforeHide() {}
46
-
47
- // ---------------------------------------------------------------------------
48
- // Buttons
49
- // ---------------------------------------------------------------------------
50
-
51
- /**
52
- * Builds a tooltip button and registers its click disposer.
53
- * @param {string} icon - inline SVG markup
54
- * @param {string} title
55
- * @param {() => void} handler
56
- * @param {boolean} [isDanger]
57
- * @returns {HTMLElement}
58
- */
59
- _makeBtn(icon, title, handler, isDanger = false) {
60
- const btn = createElement('button', {
61
- type: 'button',
62
- class: isDanger ? 'an-link-tooltip-btn an-link-tooltip-btn--danger' : 'an-link-tooltip-btn',
63
- title,
64
- });
65
- btn.innerHTML = icon;
66
- this._disposers.push(on(btn, 'click', (e) => {
67
- e.preventDefault();
68
- e.stopPropagation();
69
- handler();
70
- }));
71
- return btn;
72
- }
73
-
74
- // ---------------------------------------------------------------------------
75
- // Show / Hide
76
- // ---------------------------------------------------------------------------
77
-
78
- _scheduleShow(target) {
79
- if (this._active === target && this._el.style.display !== 'none') return;
80
- clearTimeout(this._hideTimer);
81
- this._hideTimer = null;
82
- clearTimeout(this._showTimer);
83
- this._showTimer = setTimeout(() => {
84
- this._active = target;
85
- this._show(target);
86
- }, SHOW_DELAY);
87
- }
88
-
89
- _scheduleHide() {
90
- if (!this._canHide()) return;
91
- clearTimeout(this._showTimer);
92
- this._showTimer = null;
93
- // Always reset the hide timer so rapid mouseout→mouseover sequences
94
- // don't leave a stale timer that hides the tooltip prematurely.
95
- clearTimeout(this._hideTimer);
96
- this._hideTimer = setTimeout(() => this._hide(), HIDE_DELAY);
97
- }
98
-
99
- _show(_target) {
100
- this._el.style.display = 'flex';
101
- // Defer positioning: offsetWidth on a newly-visible element forces layout
102
- requestAnimationFrame(() => {
103
- if (this._active) this._positionNear(this._active);
104
- });
105
- }
106
-
107
- _hide() {
108
- this._beforeHide();
109
- this._el.style.display = 'none';
110
- this._active = null;
111
- this._clearTimers();
112
- }
113
-
114
- _clearTimers() {
115
- clearTimeout(this._showTimer);
116
- clearTimeout(this._hideTimer);
117
- this._showTimer = null;
118
- this._hideTimer = null;
119
- }
120
-
121
- /**
122
- * Places the tooltip under the target, flipping above and clamping
123
- * horizontally when it would leave the viewport.
124
- * @param {HTMLElement} target
125
- */
126
- _positionNear(target) {
127
- const rect = target.getBoundingClientRect();
128
- const tipW = this._el.offsetWidth || 220;
129
- const tipH = this._el.offsetHeight || 32;
130
- const margin = 6;
131
-
132
- let top = rect.bottom + margin;
133
- let left = rect.left + (rect.width - tipW) / 2;
134
-
135
- if (top + tipH > globalThis.innerHeight - margin) top = rect.top - tipH - margin;
136
- if (left + tipW > globalThis.innerWidth - margin) left = globalThis.innerWidth - tipW - margin;
137
- if (left < margin) left = margin;
138
-
139
- this._el.style.top = `${top}px`;
140
- this._el.style.left = `${left}px`;
141
- }
142
- }