autumnnote 2.0.0 → 2.2.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 (64) hide show
  1. package/README.md +72 -5
  2. package/dist/autumnnote.cjs +20 -20
  3. package/dist/autumnnote.css +1 -1
  4. package/dist/autumnnote.es.js +661 -798
  5. package/dist/autumnnote.es.js.map +1 -1
  6. package/dist/autumnnote.min.js +20 -20
  7. package/dist/autumnnote.umd.js +20 -20
  8. package/dist/autumnnote.umd.js.map +1 -1
  9. package/dist/icon-data-V0Xqv-wX.js +255 -0
  10. package/dist/icon-data-V0Xqv-wX.js.map +1 -0
  11. package/package.json +13 -4
  12. package/types/index.d.ts +8 -0
  13. package/src/js/Context.js +0 -854
  14. package/src/js/core/detectLang.js +0 -98
  15. package/src/js/core/dom.js +0 -372
  16. package/src/js/core/env.js +0 -25
  17. package/src/js/core/key.js +0 -66
  18. package/src/js/core/lists.js +0 -121
  19. package/src/js/core/markdown.js +0 -695
  20. package/src/js/core/range.js +0 -194
  21. package/src/js/core/sanitise.js +0 -231
  22. package/src/js/editing/History.js +0 -266
  23. package/src/js/editing/Style.js +0 -812
  24. package/src/js/editing/Table.js +0 -105
  25. package/src/js/editing/Typing.js +0 -397
  26. package/src/js/index.js +0 -193
  27. package/src/js/index.umd.js +0 -17
  28. package/src/js/module/AutoSaveRestore.js +0 -125
  29. package/src/js/module/BaseDialog.js +0 -133
  30. package/src/js/module/BaseMediaTooltip.js +0 -142
  31. package/src/js/module/BaseResizer.js +0 -312
  32. package/src/js/module/BubbleToolbar.js +0 -483
  33. package/src/js/module/Buttons.js +0 -399
  34. package/src/js/module/Clipboard.js +0 -579
  35. package/src/js/module/CodeTooltip.js +0 -493
  36. package/src/js/module/Codeview.js +0 -125
  37. package/src/js/module/ContextMenu.js +0 -621
  38. package/src/js/module/Editor.js +0 -747
  39. package/src/js/module/EmojiDialog.js +0 -254
  40. package/src/js/module/FindReplace.js +0 -512
  41. package/src/js/module/Fullscreen.js +0 -80
  42. package/src/js/module/IconDialog.js +0 -618
  43. package/src/js/module/ImageCropOverlay.js +0 -586
  44. package/src/js/module/ImageDialog.js +0 -193
  45. package/src/js/module/ImageResizer.js +0 -42
  46. package/src/js/module/ImageTooltip.js +0 -285
  47. package/src/js/module/LinkDialog.js +0 -145
  48. package/src/js/module/LinkTooltip.js +0 -250
  49. package/src/js/module/MarkdownShortcuts.js +0 -250
  50. package/src/js/module/Mention.js +0 -365
  51. package/src/js/module/Placeholder.js +0 -51
  52. package/src/js/module/ShortcutsDialog.js +0 -111
  53. package/src/js/module/SlashMenu.js +0 -376
  54. package/src/js/module/Statusbar.js +0 -246
  55. package/src/js/module/TableTooltip.js +0 -1521
  56. package/src/js/module/Toolbar.js +0 -750
  57. package/src/js/module/VideoDialog.js +0 -193
  58. package/src/js/module/VideoResizer.js +0 -66
  59. package/src/js/module/VideoTooltip.js +0 -248
  60. package/src/js/module/emoji-data.js +0 -496
  61. package/src/js/renderer.js +0 -120
  62. package/src/js/settings.js +0 -214
  63. package/src/styles/_variables.scss +0 -48
  64. package/src/styles/autumnnote.scss +0 -2866
@@ -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
- }