autumnnote 1.15.0 → 2.0.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 +53 -2
- package/dist/autumnnote.cjs +21 -21
- package/dist/autumnnote.css +1 -1
- package/dist/autumnnote.es.js +1470 -5884
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.min.js +61 -0
- package/dist/autumnnote.umd.js +21 -21
- package/dist/autumnnote.umd.js.map +1 -1
- package/dist/emoji-data-BDQX5kh-.js +2331 -0
- package/dist/emoji-data-BDQX5kh-.js.map +1 -0
- package/package.json +9 -5
- package/src/js/Context.js +216 -17
- package/src/js/editing/History.js +38 -6
- package/src/js/i18n/all.js +27 -0
- package/src/js/i18n/de.js +15 -0
- package/src/js/i18n/en.js +15 -0
- package/src/js/i18n/es.js +15 -0
- package/src/js/i18n/fr.js +15 -0
- package/src/js/i18n/index.js +45 -19
- package/src/js/i18n/ja.js +15 -0
- package/src/js/i18n/ko.js +15 -0
- package/src/js/i18n/vi.js +15 -0
- package/src/js/i18n/zh.js +15 -0
- package/src/js/index.js +24 -2
- package/src/js/index.umd.js +5 -0
- package/src/js/module/BaseMediaTooltip.js +142 -0
- package/src/js/module/BaseResizer.js +312 -0
- package/src/js/module/Clipboard.js +20 -6
- package/src/js/module/Editor.js +15 -1
- package/src/js/module/EmojiDialog.js +41 -494
- package/src/js/module/ImageDialog.js +34 -6
- package/src/js/module/ImageResizer.js +23 -241
- package/src/js/module/ImageTooltip.js +16 -111
- package/src/js/module/MarkdownShortcuts.js +2 -2
- package/src/js/module/SlashMenu.js +376 -0
- package/src/js/module/Statusbar.js +3 -9
- package/src/js/module/VideoResizer.js +38 -239
- package/src/js/module/VideoTooltip.js +27 -114
- package/src/js/module/emoji-data.js +496 -0
- package/src/js/settings.js +27 -0
- package/src/styles/autumnnote.scss +49 -0
- package/types/i18n/all.d.ts +14 -0
- package/types/i18n/de.d.ts +4 -0
- package/types/i18n/en.d.ts +4 -0
- package/types/i18n/es.d.ts +4 -0
- package/types/i18n/fr.d.ts +4 -0
- package/types/i18n/ja.d.ts +4 -0
- package/types/i18n/ko.d.ts +4 -0
- package/types/i18n/vi.d.ts +4 -0
- package/types/i18n/zh.d.ts +4 -0
- package/types/index.d.ts +113 -4
package/src/js/i18n/fr.js
CHANGED
|
@@ -343,4 +343,19 @@ export const fr = {
|
|
|
343
343
|
restore: 'Restaurer',
|
|
344
344
|
discard: 'Ignorer',
|
|
345
345
|
},
|
|
346
|
+
|
|
347
|
+
slashMenu: {
|
|
348
|
+
noResults: 'Aucune commande correspondante',
|
|
349
|
+
heading1: 'Titre 1',
|
|
350
|
+
heading2: 'Titre 2',
|
|
351
|
+
heading3: 'Titre 3',
|
|
352
|
+
bulletList: 'Liste à puces',
|
|
353
|
+
numberedList: 'Liste numérotée',
|
|
354
|
+
checklist: 'Liste de contrôle',
|
|
355
|
+
blockquote: 'Citation',
|
|
356
|
+
codeBlock: 'Bloc de code',
|
|
357
|
+
horizontalRule: 'Ligne horizontale',
|
|
358
|
+
table: 'Tableau',
|
|
359
|
+
image: 'Image',
|
|
360
|
+
},
|
|
346
361
|
};
|
package/src/js/i18n/index.js
CHANGED
|
@@ -1,33 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* i18n/index.js — Locale registry and resolver for autumn-note-ce.
|
|
3
3
|
*
|
|
4
|
+
* Only English ships in the ESM bundle. Bundling all eight locales cost every
|
|
5
|
+
* consumer ~15 KB gzip even when they only ever rendered English, so the other
|
|
6
|
+
* locales are opt-in via subpath imports:
|
|
7
|
+
*
|
|
8
|
+
* import AutumnNote from 'autumnnote';
|
|
9
|
+
* import { vi } from 'autumnnote/i18n/vi';
|
|
10
|
+
*
|
|
11
|
+
* AutumnNote.registerLocale('vi', vi);
|
|
12
|
+
* AutumnNote.create('#editor', { lang: 'vi' });
|
|
13
|
+
*
|
|
14
|
+
* The UMD/CDN build cannot tree-shake, so it pre-registers every locale and
|
|
15
|
+
* `lang: 'vi'` keeps working there with no extra imports.
|
|
16
|
+
*
|
|
4
17
|
* Usage:
|
|
5
|
-
* lang: 'en' → built-in English (
|
|
6
|
-
* lang: '
|
|
7
|
-
* lang: 'ja' → built-in Japanese
|
|
8
|
-
* lang: 'zh' → built-in Simplified Chinese
|
|
9
|
-
* lang: 'fr' → built-in French
|
|
10
|
-
* lang: 'de' → built-in German
|
|
11
|
-
* lang: 'es' → built-in Spanish
|
|
12
|
-
* lang: 'ko' → built-in Korean
|
|
18
|
+
* lang: 'en' → built-in English (always available)
|
|
19
|
+
* lang: '<code>' → a locale previously passed to registerLocale()
|
|
13
20
|
* lang: { ... } → custom locale object, deep-merged over English
|
|
14
21
|
*/
|
|
15
22
|
|
|
16
23
|
import { mergeDeep } from '../core/func.js';
|
|
17
24
|
import { en } from './en.js';
|
|
18
|
-
import { vi } from './vi.js';
|
|
19
|
-
import { ja } from './ja.js';
|
|
20
|
-
import { zh } from './zh.js';
|
|
21
|
-
import { fr } from './fr.js';
|
|
22
|
-
import { de } from './de.js';
|
|
23
|
-
import { es } from './es.js';
|
|
24
|
-
import { ko } from './ko.js';
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Locales available to `lang: '<code>'`. Starts with English only; other codes
|
|
28
|
+
* are added through {@link registerLocale}.
|
|
28
29
|
* @type {Record<string, Partial<AsnLocale>>}
|
|
29
30
|
*/
|
|
30
|
-
export const locales = { en
|
|
31
|
+
export const locales = { en };
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Registers a locale so it can be selected by code.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} code - Language code, e.g. 'vi'.
|
|
37
|
+
* @param {Partial<AsnLocale>} locale - Locale object; missing keys fall back to English.
|
|
38
|
+
* @returns {void}
|
|
39
|
+
*/
|
|
40
|
+
export function registerLocale(code, locale) {
|
|
41
|
+
if (typeof code !== 'string' || !code) {
|
|
42
|
+
throw new TypeError('[AutumnNote] registerLocale: code must be a non-empty string.');
|
|
43
|
+
}
|
|
44
|
+
if (!locale || typeof locale !== 'object') {
|
|
45
|
+
throw new TypeError(`[AutumnNote] registerLocale: locale for "${code}" must be an object.`);
|
|
46
|
+
}
|
|
47
|
+
locales[code] = locale;
|
|
48
|
+
}
|
|
31
49
|
|
|
32
50
|
/**
|
|
33
51
|
* Resolve a locale object from a lang option value.
|
|
@@ -41,8 +59,16 @@ export function resolveLocale(lang) {
|
|
|
41
59
|
|
|
42
60
|
if (typeof lang === 'string') {
|
|
43
61
|
const partial = locales[lang];
|
|
44
|
-
|
|
45
|
-
|
|
62
|
+
if (!partial) {
|
|
63
|
+
// Unregistered code → English, but say why: silently rendering English
|
|
64
|
+
// after asking for another language is confusing to debug.
|
|
65
|
+
console.warn(
|
|
66
|
+
`[AutumnNote] Locale "${lang}" is not registered, falling back to English. ` +
|
|
67
|
+
`Import it first: import { ${lang} } from 'autumnnote/i18n/${lang}'; ` +
|
|
68
|
+
`AutumnNote.registerLocale('${lang}', ${lang});`,
|
|
69
|
+
);
|
|
70
|
+
return en;
|
|
71
|
+
}
|
|
46
72
|
return mergeDeep(mergeDeep({}, en), partial);
|
|
47
73
|
}
|
|
48
74
|
|
package/src/js/i18n/ja.js
CHANGED
|
@@ -343,4 +343,19 @@ export const ja = {
|
|
|
343
343
|
restore: '復元',
|
|
344
344
|
discard: '破棄',
|
|
345
345
|
},
|
|
346
|
+
|
|
347
|
+
slashMenu: {
|
|
348
|
+
noResults: '一致するコマンドがありません',
|
|
349
|
+
heading1: '見出し1',
|
|
350
|
+
heading2: '見出し2',
|
|
351
|
+
heading3: '見出し3',
|
|
352
|
+
bulletList: '箇条書きリスト',
|
|
353
|
+
numberedList: '番号付きリスト',
|
|
354
|
+
checklist: 'チェックリスト',
|
|
355
|
+
blockquote: '引用',
|
|
356
|
+
codeBlock: 'コードブロック',
|
|
357
|
+
horizontalRule: '水平線',
|
|
358
|
+
table: '表',
|
|
359
|
+
image: '画像',
|
|
360
|
+
},
|
|
346
361
|
};
|
package/src/js/i18n/ko.js
CHANGED
|
@@ -342,4 +342,19 @@ export const ko = {
|
|
|
342
342
|
restore: '복원',
|
|
343
343
|
discard: '삭제',
|
|
344
344
|
},
|
|
345
|
+
|
|
346
|
+
slashMenu: {
|
|
347
|
+
noResults: '일치하는 명령이 없습니다',
|
|
348
|
+
heading1: '제목 1',
|
|
349
|
+
heading2: '제목 2',
|
|
350
|
+
heading3: '제목 3',
|
|
351
|
+
bulletList: '글머리 기호 목록',
|
|
352
|
+
numberedList: '번호 매기기 목록',
|
|
353
|
+
checklist: '체크리스트',
|
|
354
|
+
blockquote: '인용문',
|
|
355
|
+
codeBlock: '코드 블록',
|
|
356
|
+
horizontalRule: '가로선',
|
|
357
|
+
table: '표',
|
|
358
|
+
image: '이미지',
|
|
359
|
+
},
|
|
345
360
|
};
|
package/src/js/i18n/vi.js
CHANGED
|
@@ -343,4 +343,19 @@ export const vi = {
|
|
|
343
343
|
restore: 'Khôi phục',
|
|
344
344
|
discard: 'Bỏ qua',
|
|
345
345
|
},
|
|
346
|
+
|
|
347
|
+
slashMenu: {
|
|
348
|
+
noResults: 'Không có lệnh phù hợp',
|
|
349
|
+
heading1: 'Tiêu đề 1',
|
|
350
|
+
heading2: 'Tiêu đề 2',
|
|
351
|
+
heading3: 'Tiêu đề 3',
|
|
352
|
+
bulletList: 'Danh sách không thứ tự',
|
|
353
|
+
numberedList: 'Danh sách có thứ tự',
|
|
354
|
+
checklist: 'Danh sách công việc',
|
|
355
|
+
blockquote: 'Trích dẫn',
|
|
356
|
+
codeBlock: 'Khối mã',
|
|
357
|
+
horizontalRule: 'Đường kẻ ngang',
|
|
358
|
+
table: 'Bảng',
|
|
359
|
+
image: 'Hình ảnh',
|
|
360
|
+
},
|
|
346
361
|
};
|
package/src/js/i18n/zh.js
CHANGED
|
@@ -343,4 +343,19 @@ export const zh = {
|
|
|
343
343
|
restore: '恢复',
|
|
344
344
|
discard: '放弃',
|
|
345
345
|
},
|
|
346
|
+
|
|
347
|
+
slashMenu: {
|
|
348
|
+
noResults: '没有匹配的命令',
|
|
349
|
+
heading1: '标题 1',
|
|
350
|
+
heading2: '标题 2',
|
|
351
|
+
heading3: '标题 3',
|
|
352
|
+
bulletList: '项目符号列表',
|
|
353
|
+
numberedList: '编号列表',
|
|
354
|
+
checklist: '检查清单',
|
|
355
|
+
blockquote: '引用',
|
|
356
|
+
codeBlock: '代码块',
|
|
357
|
+
horizontalRule: '水平线',
|
|
358
|
+
table: '表格',
|
|
359
|
+
image: '图片',
|
|
360
|
+
},
|
|
346
361
|
};
|
package/src/js/index.js
CHANGED
|
@@ -14,6 +14,7 @@ import '../styles/autumnnote.scss';
|
|
|
14
14
|
import { Context, _customModules, _globalPlugins } from './Context.js';
|
|
15
15
|
import { registerButton, buttons } from './module/Buttons.js';
|
|
16
16
|
import { defaultOptions } from './settings.js';
|
|
17
|
+
import { registerLocale } from './i18n/index.js';
|
|
17
18
|
|
|
18
19
|
// Snapshot of factory defaults taken at module-load time (before any setDefaults() calls)
|
|
19
20
|
const _originalDefaults = { ...defaultOptions };
|
|
@@ -29,7 +30,7 @@ export * from './core/lists.js';
|
|
|
29
30
|
export * from './core/env.js';
|
|
30
31
|
export * from './core/sanitise.js';
|
|
31
32
|
export * from './module/Buttons.js';
|
|
32
|
-
export { locales, resolveLocale } from './i18n/index.js';
|
|
33
|
+
export { locales, resolveLocale, registerLocale } from './i18n/index.js';
|
|
33
34
|
|
|
34
35
|
// ---------------------------------------------------------------------------
|
|
35
36
|
// Main factory
|
|
@@ -140,11 +141,32 @@ const AutumnNote = {
|
|
|
140
141
|
*/
|
|
141
142
|
registerButton(btnDef) { registerButton(btnDef); return this; },
|
|
142
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Registers a locale so `lang: '<code>'` can select it.
|
|
146
|
+
* Only English ships in the ESM bundle — import others from
|
|
147
|
+
* `autumnnote/i18n/<code>` and register them here.
|
|
148
|
+
* @param {string} code
|
|
149
|
+
* @param {object} locale
|
|
150
|
+
*/
|
|
151
|
+
registerLocale(code, locale) { registerLocale(code, locale); return this; },
|
|
152
|
+
|
|
153
|
+
/** Registers a slash-menu command for future editor instances. */
|
|
154
|
+
registerSlashCommand(command) {
|
|
155
|
+
if (!command?.id || typeof command.run !== 'function') {
|
|
156
|
+
throw new TypeError('[AutumnNote] Slash command requires an id and run(context) function.');
|
|
157
|
+
}
|
|
158
|
+
const commands = defaultOptions.slashCommands;
|
|
159
|
+
const index = commands.findIndex((item) => item.id === command.id);
|
|
160
|
+
if (index >= 0) commands[index] = command;
|
|
161
|
+
else commands.push(command);
|
|
162
|
+
return this;
|
|
163
|
+
},
|
|
164
|
+
|
|
143
165
|
/** All pre-built button definitions — accessible in every module format including UMD/CJS. */
|
|
144
166
|
buttons,
|
|
145
167
|
|
|
146
168
|
/** Library version */
|
|
147
|
-
version: '
|
|
169
|
+
version: '2.0.0',
|
|
148
170
|
};
|
|
149
171
|
|
|
150
172
|
// ---------------------------------------------------------------------------
|
package/src/js/index.umd.js
CHANGED
|
@@ -9,4 +9,9 @@
|
|
|
9
9
|
* const editor = AutumnNote.create('#my-editor');
|
|
10
10
|
* </script>
|
|
11
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
|
+
|
|
12
17
|
export { default } from './index.js';
|
|
@@ -0,0 +1,142 @@
|
|
|
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
|
+
}
|