autumnnote 2.7.0 → 3.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 +181 -15
- package/dist/autumnnote.cjs +35 -35
- package/dist/autumnnote.core.es.js +1179 -849
- package/dist/autumnnote.core.es.js.map +1 -1
- package/dist/autumnnote.css +1 -1
- package/dist/autumnnote.es.js +1678 -1318
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.min.js +35 -35
- package/dist/autumnnote.umd.js +35 -35
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +10 -10
- package/src/js/core/func.js +38 -6
- package/src/js/i18n/de.js +10 -0
- package/src/js/i18n/en.js +10 -0
- package/src/js/i18n/es.js +10 -0
- package/src/js/i18n/fr.js +10 -0
- package/src/js/i18n/ja.js +10 -0
- package/src/js/i18n/ko.js +10 -0
- package/src/js/i18n/vi.js +10 -0
- package/src/js/i18n/zh.js +10 -0
- package/types/index.d.ts +188 -5
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autumnnote",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "WYSIWYG rich-text editor built with vanilla JavaScript
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "WYSIWYG rich-text editor built with vanilla JavaScript — zero dependencies, no jQuery. Dark mode, @mention, markdown shortcuts, bubble toolbar. React and Vue 3 wrappers included.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/autumnnote.cjs",
|
|
7
7
|
"module": "dist/autumnnote.es.js",
|
|
@@ -119,18 +119,18 @@
|
|
|
119
119
|
"@vitest/browser-playwright": "^4.1.10",
|
|
120
120
|
"@vitest/coverage-v8": "^4.1.8",
|
|
121
121
|
"cross-env": "^10.1.0",
|
|
122
|
-
"eslint": "^10.
|
|
123
|
-
"jsdom": "^
|
|
124
|
-
"playwright": "^1.
|
|
125
|
-
"rollup-plugin-visualizer": "^7.
|
|
126
|
-
"sass": "^1.
|
|
127
|
-
"typescript": "^
|
|
128
|
-
"vite": "^8.1
|
|
122
|
+
"eslint": "^10.8.1",
|
|
123
|
+
"jsdom": "^30.0.1",
|
|
124
|
+
"playwright": "^1.62.1",
|
|
125
|
+
"rollup-plugin-visualizer": "^7.1.1",
|
|
126
|
+
"sass": "^1.102.0",
|
|
127
|
+
"typescript": "^7.0.2",
|
|
128
|
+
"vite": "^8.2.1",
|
|
129
129
|
"vitest": "^4.1.8"
|
|
130
130
|
},
|
|
131
131
|
"packageManager": "pnpm@11.1.3",
|
|
132
132
|
"engines": {
|
|
133
|
-
"node": ">=
|
|
133
|
+
"node": "^22.22.2 || >=24.15.0"
|
|
134
134
|
},
|
|
135
135
|
"browserslist": [
|
|
136
136
|
"last 2 versions",
|
package/src/js/core/func.js
CHANGED
|
@@ -108,9 +108,14 @@ export function isFunction(val) {
|
|
|
108
108
|
* mutations to the merged result do not bleed back into the source object
|
|
109
109
|
* (e.g. mutating `instance.options.fontFamilies` should not affect
|
|
110
110
|
* `AutumnNote.defaults.fontFamilies`).
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
111
|
+
*
|
|
112
|
+
* The result starts as a copy of `target`, so it carries `target`'s shape —
|
|
113
|
+
* `source` only overwrites values. Typing the return as `T` rather than
|
|
114
|
+
* `object` is what lets callers read properties off the merged result.
|
|
115
|
+
* @template {object} T
|
|
116
|
+
* @param {T} target
|
|
117
|
+
* @param {object} [source]
|
|
118
|
+
* @returns {T}
|
|
114
119
|
*/
|
|
115
120
|
export function mergeDeep(target, source) {
|
|
116
121
|
// Start with a shallow copy of target; clone any arrays to avoid shared refs
|
|
@@ -133,16 +138,43 @@ export function mergeDeep(target, source) {
|
|
|
133
138
|
}
|
|
134
139
|
}
|
|
135
140
|
}
|
|
136
|
-
|
|
141
|
+
// `output` is built key by key from `target`, which no inference can follow.
|
|
142
|
+
return /** @type {T} */ (output);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Structural equality for option values: plain objects and arrays compare by
|
|
147
|
+
* content, everything else (functions, DOM nodes, class instances) by identity.
|
|
148
|
+
* @param {*} a
|
|
149
|
+
* @param {*} b
|
|
150
|
+
* @returns {boolean}
|
|
151
|
+
*/
|
|
152
|
+
export function deepEqual(a, b) {
|
|
153
|
+
if (Object.is(a, b)) return true;
|
|
154
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
155
|
+
return a.length === b.length && a.every((item, i) => deepEqual(item, b[i]));
|
|
156
|
+
}
|
|
157
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
158
|
+
const keys = Object.keys(a);
|
|
159
|
+
return keys.length === Object.keys(b).length
|
|
160
|
+
&& keys.every((key) => Object.hasOwn(b, key) && deepEqual(a[key], b[key]));
|
|
161
|
+
}
|
|
162
|
+
return false;
|
|
137
163
|
}
|
|
138
164
|
|
|
139
165
|
/**
|
|
140
|
-
* Checks if value is a plain object.
|
|
166
|
+
* Checks if value is a plain object (an object literal or Object.create(null)).
|
|
167
|
+
*
|
|
168
|
+
* DOM nodes and class instances are not: mergeDeep() used to recurse into
|
|
169
|
+
* them, which turned a `popupContainer` element into a detached copy and
|
|
170
|
+
* stripped the prototype methods off class-based adapters.
|
|
141
171
|
* @param {*} val
|
|
142
172
|
* @returns {boolean}
|
|
143
173
|
*/
|
|
144
174
|
export function isPlainObject(val) {
|
|
145
|
-
|
|
175
|
+
if (val === null || typeof val !== 'object') return false;
|
|
176
|
+
const proto = Object.getPrototypeOf(val);
|
|
177
|
+
return proto === Object.prototype || proto === null;
|
|
146
178
|
}
|
|
147
179
|
|
|
148
180
|
/**
|
package/src/js/i18n/de.js
CHANGED
|
@@ -159,6 +159,8 @@ export const de = {
|
|
|
159
159
|
replaceBtn: 'Ersetzen',
|
|
160
160
|
noResults: 'Keine Ergebnisse',
|
|
161
161
|
useRegex: 'Regulären Ausdruck verwenden',
|
|
162
|
+
prevMatch: 'Zurück (Umschalt+Eingabe)',
|
|
163
|
+
nextMatch: 'Weiter (Eingabe)',
|
|
162
164
|
replaceAllBtn: 'Alle ersetzen',
|
|
163
165
|
close: '×',
|
|
164
166
|
},
|
|
@@ -167,6 +169,7 @@ export const de = {
|
|
|
167
169
|
title: 'Tastenkürzel',
|
|
168
170
|
ariaLabel: 'Tastenkürzel',
|
|
169
171
|
close: 'Schließen',
|
|
172
|
+
customCategory: 'Benutzerdefiniert',
|
|
170
173
|
shortcuts: [
|
|
171
174
|
{
|
|
172
175
|
category: 'Textformatierung',
|
|
@@ -244,6 +247,13 @@ export const de = {
|
|
|
244
247
|
charsLimit: (n, max) => `Zeichen: ${n}/${max}`,
|
|
245
248
|
},
|
|
246
249
|
|
|
250
|
+
a11y: {
|
|
251
|
+
editor: 'Rich-Text-Editor',
|
|
252
|
+
toolbar: 'Editor-Werkzeugleiste',
|
|
253
|
+
statistics: 'Editor-Statistik',
|
|
254
|
+
tableSize: 'Tabellengröße wählen',
|
|
255
|
+
},
|
|
256
|
+
|
|
247
257
|
tooltips: {
|
|
248
258
|
link: {
|
|
249
259
|
ariaLabel: 'Link-Aktionen',
|
package/src/js/i18n/en.js
CHANGED
|
@@ -162,6 +162,8 @@ export const en = {
|
|
|
162
162
|
replaceAllBtn: 'Replace All',
|
|
163
163
|
noResults: 'No results',
|
|
164
164
|
useRegex: 'Use Regular Expression',
|
|
165
|
+
prevMatch: 'Previous (Shift+Enter)',
|
|
166
|
+
nextMatch: 'Next (Enter)',
|
|
165
167
|
close: '\u00d7',
|
|
166
168
|
},
|
|
167
169
|
|
|
@@ -176,6 +178,7 @@ export const en = {
|
|
|
176
178
|
title: 'Keyboard Shortcuts',
|
|
177
179
|
ariaLabel: 'Keyboard Shortcuts',
|
|
178
180
|
close: 'Close',
|
|
181
|
+
customCategory: 'Custom',
|
|
179
182
|
shortcuts: [
|
|
180
183
|
{
|
|
181
184
|
category: 'Text Formatting',
|
|
@@ -257,6 +260,13 @@ export const en = {
|
|
|
257
260
|
charsLimit: (n, max) => `Chars: ${n}/${max}`,
|
|
258
261
|
},
|
|
259
262
|
|
|
263
|
+
a11y: {
|
|
264
|
+
editor: 'Rich text editor',
|
|
265
|
+
toolbar: 'Editor toolbar',
|
|
266
|
+
statistics: 'Editor statistics',
|
|
267
|
+
tableSize: 'Select table size',
|
|
268
|
+
},
|
|
269
|
+
|
|
260
270
|
tooltips: {
|
|
261
271
|
link: {
|
|
262
272
|
ariaLabel: 'Link actions',
|
package/src/js/i18n/es.js
CHANGED
|
@@ -159,6 +159,8 @@ export const es = {
|
|
|
159
159
|
replaceBtn: 'Reemplazar',
|
|
160
160
|
noResults: 'Sin resultados',
|
|
161
161
|
useRegex: 'Usar expresión regular',
|
|
162
|
+
prevMatch: 'Anterior (Mayús+Intro)',
|
|
163
|
+
nextMatch: 'Siguiente (Intro)',
|
|
162
164
|
replaceAllBtn: 'Reemplazar todo',
|
|
163
165
|
close: '×',
|
|
164
166
|
},
|
|
@@ -167,6 +169,7 @@ export const es = {
|
|
|
167
169
|
title: 'Atajos de teclado',
|
|
168
170
|
ariaLabel: 'Atajos de teclado',
|
|
169
171
|
close: 'Cerrar',
|
|
172
|
+
customCategory: 'Personalizados',
|
|
170
173
|
shortcuts: [
|
|
171
174
|
{
|
|
172
175
|
category: 'Formato de texto',
|
|
@@ -244,6 +247,13 @@ export const es = {
|
|
|
244
247
|
charsLimit: (n, max) => `Caracteres: ${n}/${max}`,
|
|
245
248
|
},
|
|
246
249
|
|
|
250
|
+
a11y: {
|
|
251
|
+
editor: 'Editor de texto enriquecido',
|
|
252
|
+
toolbar: 'Barra de herramientas del editor',
|
|
253
|
+
statistics: 'Estadísticas del editor',
|
|
254
|
+
tableSize: 'Seleccionar tamaño de tabla',
|
|
255
|
+
},
|
|
256
|
+
|
|
247
257
|
tooltips: {
|
|
248
258
|
link: {
|
|
249
259
|
ariaLabel: 'Acciones de enlace',
|
package/src/js/i18n/fr.js
CHANGED
|
@@ -160,6 +160,8 @@ export const fr = {
|
|
|
160
160
|
replaceBtn: 'Remplacer',
|
|
161
161
|
noResults: 'Aucun résultat',
|
|
162
162
|
useRegex: 'Utiliser une expression régulière',
|
|
163
|
+
prevMatch: 'Précédent (Maj+Entrée)',
|
|
164
|
+
nextMatch: 'Suivant (Entrée)',
|
|
163
165
|
replaceAllBtn: 'Tout remplacer',
|
|
164
166
|
close: '\u00d7',
|
|
165
167
|
},
|
|
@@ -168,6 +170,7 @@ export const fr = {
|
|
|
168
170
|
title: 'Raccourcis clavier',
|
|
169
171
|
ariaLabel: 'Raccourcis clavier',
|
|
170
172
|
close: 'Fermer',
|
|
173
|
+
customCategory: 'Personnalisés',
|
|
171
174
|
shortcuts: [
|
|
172
175
|
{
|
|
173
176
|
category: 'Mise en forme du texte',
|
|
@@ -245,6 +248,13 @@ export const fr = {
|
|
|
245
248
|
charsLimit: (n, max) => `Caractères\u00a0: ${n}/${max}`,
|
|
246
249
|
},
|
|
247
250
|
|
|
251
|
+
a11y: {
|
|
252
|
+
editor: 'Éditeur de texte enrichi',
|
|
253
|
+
toolbar: 'Barre d\'outils de l\'éditeur',
|
|
254
|
+
statistics: 'Statistiques de l\'éditeur',
|
|
255
|
+
tableSize: 'Choisir la taille du tableau',
|
|
256
|
+
},
|
|
257
|
+
|
|
248
258
|
tooltips: {
|
|
249
259
|
link: {
|
|
250
260
|
ariaLabel: 'Actions du lien',
|
package/src/js/i18n/ja.js
CHANGED
|
@@ -160,6 +160,8 @@ export const ja = {
|
|
|
160
160
|
replaceBtn: '置換',
|
|
161
161
|
noResults: '結果なし',
|
|
162
162
|
useRegex: '正規表現を使用',
|
|
163
|
+
prevMatch: '前へ (Shift+Enter)',
|
|
164
|
+
nextMatch: '次へ (Enter)',
|
|
163
165
|
replaceAllBtn: 'すべて置換',
|
|
164
166
|
close: '\u00d7',
|
|
165
167
|
},
|
|
@@ -168,6 +170,7 @@ export const ja = {
|
|
|
168
170
|
title: 'キーボードショートカット',
|
|
169
171
|
ariaLabel: 'キーボードショートカット',
|
|
170
172
|
close: '閉じる',
|
|
173
|
+
customCategory: 'カスタム',
|
|
171
174
|
shortcuts: [
|
|
172
175
|
{
|
|
173
176
|
category: 'テキスト書式',
|
|
@@ -245,6 +248,13 @@ export const ja = {
|
|
|
245
248
|
charsLimit: (n, max) => `文字数: ${n}/${max}`,
|
|
246
249
|
},
|
|
247
250
|
|
|
251
|
+
a11y: {
|
|
252
|
+
editor: 'リッチテキストエディター',
|
|
253
|
+
toolbar: 'エディターツールバー',
|
|
254
|
+
statistics: 'エディターの統計',
|
|
255
|
+
tableSize: '表のサイズを選択',
|
|
256
|
+
},
|
|
257
|
+
|
|
248
258
|
tooltips: {
|
|
249
259
|
link: {
|
|
250
260
|
ariaLabel: 'リンク操作',
|
package/src/js/i18n/ko.js
CHANGED
|
@@ -159,6 +159,8 @@ export const ko = {
|
|
|
159
159
|
replaceBtn: '바꾸기',
|
|
160
160
|
noResults: '결과 없음',
|
|
161
161
|
useRegex: '정규식 사용',
|
|
162
|
+
prevMatch: '이전 (Shift+Enter)',
|
|
163
|
+
nextMatch: '다음 (Enter)',
|
|
162
164
|
replaceAllBtn: '모두 바꾸기',
|
|
163
165
|
close: '×',
|
|
164
166
|
},
|
|
@@ -167,6 +169,7 @@ export const ko = {
|
|
|
167
169
|
title: '키보드 단축키',
|
|
168
170
|
ariaLabel: '키보드 단축키',
|
|
169
171
|
close: '닫기',
|
|
172
|
+
customCategory: '사용자 지정',
|
|
170
173
|
shortcuts: [
|
|
171
174
|
{
|
|
172
175
|
category: '텍스트 서식',
|
|
@@ -244,6 +247,13 @@ export const ko = {
|
|
|
244
247
|
charsLimit: (n, max) => `글자: ${n}/${max}`,
|
|
245
248
|
},
|
|
246
249
|
|
|
250
|
+
a11y: {
|
|
251
|
+
editor: '서식 있는 텍스트 편집기',
|
|
252
|
+
toolbar: '편집기 도구 모음',
|
|
253
|
+
statistics: '편집기 통계',
|
|
254
|
+
tableSize: '표 크기 선택',
|
|
255
|
+
},
|
|
256
|
+
|
|
247
257
|
tooltips: {
|
|
248
258
|
link: {
|
|
249
259
|
ariaLabel: '링크 작업',
|
package/src/js/i18n/vi.js
CHANGED
|
@@ -161,6 +161,8 @@ export const vi = {
|
|
|
161
161
|
replaceAllBtn: 'Thay thế tất cả',
|
|
162
162
|
noResults: 'Không có kết quả',
|
|
163
163
|
useRegex: 'Dùng biểu thức chính quy',
|
|
164
|
+
prevMatch: 'Trước (Shift+Enter)',
|
|
165
|
+
nextMatch: 'Tiếp (Enter)',
|
|
164
166
|
close: '\u00d7',
|
|
165
167
|
},
|
|
166
168
|
|
|
@@ -168,6 +170,7 @@ export const vi = {
|
|
|
168
170
|
title: 'Phím tắt bàn phím',
|
|
169
171
|
ariaLabel: 'Phím tắt bàn phím',
|
|
170
172
|
close: 'Đóng',
|
|
173
|
+
customCategory: 'Tùy chỉnh',
|
|
171
174
|
shortcuts: [
|
|
172
175
|
{
|
|
173
176
|
category: 'Định dạng văn bản',
|
|
@@ -245,6 +248,13 @@ export const vi = {
|
|
|
245
248
|
charsLimit: (n, max) => `Ký tự: ${n}/${max}`,
|
|
246
249
|
},
|
|
247
250
|
|
|
251
|
+
a11y: {
|
|
252
|
+
editor: 'Trình soạn thảo văn bản',
|
|
253
|
+
toolbar: 'Thanh công cụ soạn thảo',
|
|
254
|
+
statistics: 'Thống kê văn bản',
|
|
255
|
+
tableSize: 'Chọn kích thước bảng',
|
|
256
|
+
},
|
|
257
|
+
|
|
248
258
|
tooltips: {
|
|
249
259
|
link: {
|
|
250
260
|
ariaLabel: 'Hành động liên kết',
|
package/src/js/i18n/zh.js
CHANGED
|
@@ -160,6 +160,8 @@ export const zh = {
|
|
|
160
160
|
replaceBtn: '替换',
|
|
161
161
|
noResults: '没有结果',
|
|
162
162
|
useRegex: '使用正则表达式',
|
|
163
|
+
prevMatch: '上一个 (Shift+Enter)',
|
|
164
|
+
nextMatch: '下一个 (Enter)',
|
|
163
165
|
replaceAllBtn: '全部替换',
|
|
164
166
|
close: '\u00d7',
|
|
165
167
|
},
|
|
@@ -168,6 +170,7 @@ export const zh = {
|
|
|
168
170
|
title: '键盘快捷键',
|
|
169
171
|
ariaLabel: '键盘快捷键',
|
|
170
172
|
close: '关闭',
|
|
173
|
+
customCategory: '自定义',
|
|
171
174
|
shortcuts: [
|
|
172
175
|
{
|
|
173
176
|
category: '文字格式',
|
|
@@ -245,6 +248,13 @@ export const zh = {
|
|
|
245
248
|
charsLimit: (n, max) => `字符数: ${n}/${max}`,
|
|
246
249
|
},
|
|
247
250
|
|
|
251
|
+
a11y: {
|
|
252
|
+
editor: '富文本编辑器',
|
|
253
|
+
toolbar: '编辑器工具栏',
|
|
254
|
+
statistics: '编辑器统计',
|
|
255
|
+
tableSize: '选择表格大小',
|
|
256
|
+
},
|
|
257
|
+
|
|
248
258
|
tooltips: {
|
|
249
259
|
link: {
|
|
250
260
|
ariaLabel: '链接操作',
|
package/types/index.d.ts
CHANGED
|
@@ -29,6 +29,40 @@ export interface AutoSaveAdapter {
|
|
|
29
29
|
remove?(payload: { key: string; context: Context }): void | Promise<void>;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* One entry in the right-click menu. Most entries are a labelled row with an
|
|
34
|
+
* `action`; the remaining fields each select a different kind of row, and an
|
|
35
|
+
* entry that sets one of them ignores `action`.
|
|
36
|
+
*/
|
|
37
|
+
export interface ContextMenuItem {
|
|
38
|
+
/** Unique identifier. Omitted on separators and other non-interactive rows. */
|
|
39
|
+
name?: string;
|
|
40
|
+
label?: string;
|
|
41
|
+
/** Icon markup (SVG or HTML). */
|
|
42
|
+
icon?: string;
|
|
43
|
+
/** Key into `locale.contextMenu`; preferred over `label` when it resolves. */
|
|
44
|
+
localeKey?: string;
|
|
45
|
+
action?: (context: Context) => void;
|
|
46
|
+
/** Greys the row out and blocks the click. A function is evaluated per open. */
|
|
47
|
+
disabled?: boolean | ((context: Context) => boolean);
|
|
48
|
+
/** Opens a submenu instead of firing `action`. */
|
|
49
|
+
navigate?: ContextMenuItem[] | ((context: Context) => ContextMenuItem[]);
|
|
50
|
+
/** A horizontal rule. `sep` is an accepted alias. */
|
|
51
|
+
separator?: boolean;
|
|
52
|
+
/** @see separator */
|
|
53
|
+
sep?: boolean;
|
|
54
|
+
/** Renders as the submenu's "back" row rather than a command. */
|
|
55
|
+
back?: boolean;
|
|
56
|
+
/** Renders a row of quick colour swatches for `colorType`. */
|
|
57
|
+
colorStrip?: 'foreColor' | 'hiliteColor';
|
|
58
|
+
/** Renders the full palette plus a native colour input, for `colorType`. */
|
|
59
|
+
colorPalette?: boolean;
|
|
60
|
+
/** Which command `colorStrip` / `colorPalette` applies. */
|
|
61
|
+
colorType?: 'foreColor' | 'hiliteColor';
|
|
62
|
+
/** Renders the drag-to-size table picker. */
|
|
63
|
+
tableGrid?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
32
66
|
export interface SlashCommand {
|
|
33
67
|
id: string;
|
|
34
68
|
label?: string;
|
|
@@ -45,6 +79,38 @@ export interface CollaborationAdapter {
|
|
|
45
79
|
onLocalChange?(html: string, context: Context): void | Promise<void>;
|
|
46
80
|
}
|
|
47
81
|
|
|
82
|
+
/** Built-in design tokens accepted by `themeVars` (any `--an-*` key also passes through). */
|
|
83
|
+
export interface AsnThemeVars {
|
|
84
|
+
primary?: string;
|
|
85
|
+
'primary-hover'?: string;
|
|
86
|
+
border?: string;
|
|
87
|
+
bg?: string;
|
|
88
|
+
'bg-toolbar'?: string;
|
|
89
|
+
'bg-btn-hover'?: string;
|
|
90
|
+
'bg-btn-active'?: string;
|
|
91
|
+
text?: string;
|
|
92
|
+
muted?: string;
|
|
93
|
+
'statusbar-bg'?: string;
|
|
94
|
+
radius?: string;
|
|
95
|
+
'radius-sm'?: string;
|
|
96
|
+
'font-family'?: string;
|
|
97
|
+
'font-size'?: string;
|
|
98
|
+
'line-height'?: string;
|
|
99
|
+
[customProperty: `--an-${string}`]: string | number | undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* A keyMap value. Built-in commands: undo, redo, bold, italic, underline,
|
|
104
|
+
* inlineCode, link, find, findReplace, shortcuts, pastePlainText — or any
|
|
105
|
+
* toolbar button name. A handler returning `false` lets the key through.
|
|
106
|
+
*/
|
|
107
|
+
export type AsnKeyBinding =
|
|
108
|
+
| false
|
|
109
|
+
| null
|
|
110
|
+
| string
|
|
111
|
+
| ((context: Context, event: KeyboardEvent) => void | false)
|
|
112
|
+
| { run: (context: Context, event: KeyboardEvent) => void | false; description?: string };
|
|
113
|
+
|
|
48
114
|
export interface AsnOptions {
|
|
49
115
|
/** Placeholder text when the editor is empty. */
|
|
50
116
|
placeholder?: string;
|
|
@@ -58,6 +124,12 @@ export interface AsnOptions {
|
|
|
58
124
|
focus?: boolean;
|
|
59
125
|
/** Show the resize handle in the statusbar. */
|
|
60
126
|
resizable?: boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Show the statusbar (word/char count and resize handle). Default `true`.
|
|
129
|
+
* When `false` the bar is hidden, but `getWordCount()`/`getCharCount()`
|
|
130
|
+
* keep working. Can be toggled at runtime with `updateOptions()`.
|
|
131
|
+
*/
|
|
132
|
+
statusbar?: boolean;
|
|
61
133
|
/** Toolbar button group configuration. */
|
|
62
134
|
toolbar?: Array<Array<ToolbarItemDef | string>>;
|
|
63
135
|
/** Use Bootstrap button classes on toolbar buttons. */
|
|
@@ -98,6 +170,16 @@ export interface AsnOptions {
|
|
|
98
170
|
onInit?: (context: Context) => void;
|
|
99
171
|
/** Callback fired just before the editor instance is destroyed. */
|
|
100
172
|
onDestroy?: (context: Context) => void;
|
|
173
|
+
/**
|
|
174
|
+
* Fired before a command runs from the toolbar, a keyboard shortcut, the
|
|
175
|
+
* context menu or the bubble toolbar. Return `false` to cancel it.
|
|
176
|
+
*/
|
|
177
|
+
onBeforeCommand?: (data: {
|
|
178
|
+
name: string;
|
|
179
|
+
value?: unknown;
|
|
180
|
+
source: 'toolbar' | 'shortcut' | 'contextMenu' | 'bubbleToolbar';
|
|
181
|
+
event?: KeyboardEvent;
|
|
182
|
+
}) => void | false;
|
|
101
183
|
/** Callback fired whenever the selection changes inside the editor. */
|
|
102
184
|
onSelectionChange?: (context: Context) => void;
|
|
103
185
|
/** Callback fired when the character limit is reached. */
|
|
@@ -140,8 +222,29 @@ export interface AsnOptions {
|
|
|
140
222
|
stickyToolbar?: boolean;
|
|
141
223
|
/** Top offset in px for sticky toolbar (e.g. height of a fixed nav bar). */
|
|
142
224
|
stickyToolbarOffset?: number;
|
|
143
|
-
/**
|
|
225
|
+
/**
|
|
226
|
+
* Colour theme: 'light' (default), 'dark', or 'auto' (follows the OS
|
|
227
|
+
* `prefers-color-scheme`). Can be changed at runtime with `updateOptions()`.
|
|
228
|
+
*/
|
|
144
229
|
theme?: 'light' | 'dark' | 'auto';
|
|
230
|
+
/**
|
|
231
|
+
* Design-token overrides applied to this editor and its floating UI, e.g.
|
|
232
|
+
* `{ primary: '#f97316', radius: '10px' }`. Keys are token names (`primary`)
|
|
233
|
+
* or full custom properties (`--an-primary`). See README "Theming".
|
|
234
|
+
*/
|
|
235
|
+
themeVars?: AsnThemeVars | null;
|
|
236
|
+
/**
|
|
237
|
+
* Added to the z-index of every floating layer (tooltips, popovers, dialogs,
|
|
238
|
+
* fullscreen). Use it to lift the editor's UI above a host modal. Default 0.
|
|
239
|
+
*/
|
|
240
|
+
zIndexOffset?: number;
|
|
241
|
+
/**
|
|
242
|
+
* Where the editor mounts its floating UI: a selector, an element or a
|
|
243
|
+
* ShadowRoot. Default `document.body`. Use it inside a modal that traps
|
|
244
|
+
* focus, or a shadow root. The element must not have `transform`, `filter`
|
|
245
|
+
* or `contain` set, because floating UI is positioned against the viewport.
|
|
246
|
+
*/
|
|
247
|
+
popupContainer?: string | Element | ShadowRoot | null;
|
|
145
248
|
/** Auto-load Prism.js for syntax highlighting inside code blocks. */
|
|
146
249
|
codeHighlight?: boolean;
|
|
147
250
|
/** CDN base URL for Prism assets. */
|
|
@@ -165,6 +268,56 @@ export interface AsnOptions {
|
|
|
165
268
|
defaultFontSize?: string;
|
|
166
269
|
/** Font families shown in the font-family toolbar dropdown. */
|
|
167
270
|
fontFamilies?: string[];
|
|
271
|
+
/** Sizes offered by the font-size dropdown (CSS lengths). Default 8px–72px. */
|
|
272
|
+
fontSizes?: string[];
|
|
273
|
+
/** Values offered by the line-height dropdown. Default '1.0'–'3.0'. */
|
|
274
|
+
lineHeights?: string[];
|
|
275
|
+
/** Block formats offered by the paragraph-style dropdown; `value` is a block tag name. */
|
|
276
|
+
paragraphStyles?: Array<{ value: string; label: string }>;
|
|
277
|
+
/** Replaces the built-in colour swatches (toolbar, bubble toolbar, context menu). `colorSwatches` are still prepended. */
|
|
278
|
+
colorPalette?: string[] | null;
|
|
279
|
+
/**
|
|
280
|
+
* Per-editor icon overrides keyed by button name (`bold`) or icon id
|
|
281
|
+
* (`list-ul`). A value starting with `<` is markup (e.g. an SVG); anything
|
|
282
|
+
* else is a CSS class list rendered as `<i class="...">`.
|
|
283
|
+
*/
|
|
284
|
+
icons?: Record<string, string> | null;
|
|
285
|
+
/**
|
|
286
|
+
* Per-editor button definitions, usable by name in `toolbar` without the
|
|
287
|
+
* global registry: `{ save: { icon: 'save', tooltip: 'Save', action } }`.
|
|
288
|
+
*/
|
|
289
|
+
buttons?: Record<string, Omit<ButtonDef, 'name'> | Omit<DropdownDef, 'name'>> | ToolbarItemDef[] | null;
|
|
290
|
+
/**
|
|
291
|
+
* Keyboard shortcuts merged over the defaults. Keys are combos (`Mod+B`,
|
|
292
|
+
* `Ctrl+Alt+1`; `Mod` = Ctrl or Cmd). Values: `false` to disable, a
|
|
293
|
+
* built-in command or toolbar button name, a handler, or `{ run, description }`.
|
|
294
|
+
*/
|
|
295
|
+
keyMap?: Record<string, AsnKeyBinding> | null;
|
|
296
|
+
/** Link dialog defaults. */
|
|
297
|
+
linkDefaults?: {
|
|
298
|
+
/** Pre-tick "open in new tab" for new links. Default false. */
|
|
299
|
+
openInNewTab?: boolean;
|
|
300
|
+
/** `rel` for new-tab links; `noopener` is always added. Default 'noopener noreferrer'. */
|
|
301
|
+
rel?: string;
|
|
302
|
+
/** Prefix for bare domains ('example.com'); '' disables. Relative links are never prefixed. Default 'https://'. */
|
|
303
|
+
defaultProtocol?: string;
|
|
304
|
+
} | null;
|
|
305
|
+
/**
|
|
306
|
+
* Extra video providers for the video dialog, tried before the built-in
|
|
307
|
+
* YouTube/Vimeo rules. The embed URL's host must be built in or listed in
|
|
308
|
+
* `iframeHosts`, otherwise the provider is ignored.
|
|
309
|
+
*/
|
|
310
|
+
videoProviders?: Array<{
|
|
311
|
+
name: string;
|
|
312
|
+
match: RegExp;
|
|
313
|
+
embed: (match: RegExpExecArray, url: string) => string;
|
|
314
|
+
}> | null;
|
|
315
|
+
/**
|
|
316
|
+
* Extra hostnames whose iframes survive sanitisation (exact hostnames,
|
|
317
|
+
* HTTPS only), e.g. `['player.twitch.tv']`. Every listed host can render
|
|
318
|
+
* arbitrary content inside the document — list only hosts you trust.
|
|
319
|
+
*/
|
|
320
|
+
iframeHosts?: string[] | null;
|
|
168
321
|
/** Start the editor in read-only (non-editable) mode. */
|
|
169
322
|
readOnly?: boolean;
|
|
170
323
|
/** Enable browser spellcheck in the editable area (default: true). */
|
|
@@ -188,7 +341,11 @@ export interface AsnOptions {
|
|
|
188
341
|
/** Insert a header row (<thead>) when creating new tables. */
|
|
189
342
|
tableHeaderRow?: boolean;
|
|
190
343
|
/** Callback fired after every paste event. */
|
|
191
|
-
|
|
344
|
+
/**
|
|
345
|
+
* Fired on every paste before anything is inserted. Return `false` to cancel
|
|
346
|
+
* the paste, or an HTML string to insert instead (it is sanitised).
|
|
347
|
+
*/
|
|
348
|
+
onPaste?: (data: { text: string; html: string | null }) => void | false | string;
|
|
192
349
|
/** Callback fired when pasted or dropped content cannot be processed. */
|
|
193
350
|
onPasteError?: (error: PasteErrorData) => void;
|
|
194
351
|
/** Additional color swatches shown at the top of the color picker. */
|
|
@@ -215,7 +372,7 @@ export interface AsnOptions {
|
|
|
215
372
|
autoSaveRestoreTimeout?: number;
|
|
216
373
|
/** Callback fired after the user chooses to restore a draft. */
|
|
217
374
|
onAutoSaveRestore?: (html: string, context: Context) => void;
|
|
218
|
-
/** Maximum paste size in
|
|
375
|
+
/** Maximum paste size in bytes; larger pastes are dropped and `pasteError` fires (0 = unlimited). Default: 5242880 (5 MB). */
|
|
219
376
|
maxPasteSize?: number;
|
|
220
377
|
/** Minimum image dimension in px during resize (width and height). Default: 20. */
|
|
221
378
|
minImageSize?: number;
|
|
@@ -237,6 +394,14 @@ export interface AsnOptions {
|
|
|
237
394
|
/** @mention autocomplete configuration. Activated when mention.onSearch is provided. */
|
|
238
395
|
mention?: MentionOptions | null;
|
|
239
396
|
|
|
397
|
+
// ---- Right-click menu ------------------------------------------------------
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Replaces the built-in right-click menu. Omit it, or omit `items`, to keep
|
|
401
|
+
* the default list.
|
|
402
|
+
*/
|
|
403
|
+
contextMenu?: { items?: ContextMenuItem[] } | null;
|
|
404
|
+
|
|
240
405
|
// ---- Slash command menu ----------------------------------------------------
|
|
241
406
|
|
|
242
407
|
/** Show a "/" command palette for quick block insertion (headings, lists, table, image, ...). Default: true. */
|
|
@@ -247,6 +412,7 @@ export interface AsnOptions {
|
|
|
247
412
|
documentAdapters?: Record<string, DocumentAdapter>;
|
|
248
413
|
/** Optional external image processor, such as a Web Worker bridge. */
|
|
249
414
|
imageProcessor?: (file: File, helpers: { context: Context }) => string | Promise<string>;
|
|
415
|
+
/** Bridge notified with local HTML changes. */
|
|
250
416
|
collaborationAdapter?: CollaborationAdapter | null;
|
|
251
417
|
/** Adds stable IDs to top-level blocks for external collaboration adapters. */
|
|
252
418
|
blockIds?: boolean;
|
|
@@ -404,6 +570,8 @@ export interface AsnLocale {
|
|
|
404
570
|
title: string;
|
|
405
571
|
ariaLabel: string;
|
|
406
572
|
close: string;
|
|
573
|
+
/** Heading of the section listing `keyMap` shortcuts. */
|
|
574
|
+
customCategory: string;
|
|
407
575
|
shortcuts: Array<{ category: string; items: Array<{ keys: string; action: string }> }>;
|
|
408
576
|
};
|
|
409
577
|
contextMenu: Record<string, string>;
|
|
@@ -414,6 +582,13 @@ export interface AsnLocale {
|
|
|
414
582
|
chars: (n: number) => string;
|
|
415
583
|
charsLimit: (n: number, max: number) => string;
|
|
416
584
|
};
|
|
585
|
+
/** Accessible names for landmarks that have no visible label. */
|
|
586
|
+
a11y: {
|
|
587
|
+
editor: string;
|
|
588
|
+
toolbar: string;
|
|
589
|
+
statistics: string;
|
|
590
|
+
tableSize: string;
|
|
591
|
+
};
|
|
417
592
|
tooltips: {
|
|
418
593
|
link: Record<string, string>;
|
|
419
594
|
image: Record<string, string>;
|
|
@@ -507,13 +682,14 @@ export declare class Context {
|
|
|
507
682
|
invoke(path: string, ...args: unknown[]): unknown;
|
|
508
683
|
|
|
509
684
|
/** Subscribes to an editor event. Returns an unsubscribe function. */
|
|
510
|
-
on(eventName: string, handler: (...args:
|
|
685
|
+
on(eventName: string, handler: (...args: any[]) => unknown): () => void;
|
|
511
686
|
|
|
512
687
|
/** Unsubscribes from an editor event. */
|
|
513
688
|
off(eventName: string, handler: (...args: unknown[]) => void): void;
|
|
514
689
|
|
|
515
690
|
/** Triggers an editor event. */
|
|
516
|
-
|
|
691
|
+
/** Fires an event; returns the last value a handler returned (other than undefined). */
|
|
692
|
+
triggerEvent(eventName: string, ...args: unknown[]): unknown;
|
|
517
693
|
|
|
518
694
|
/** Applies runtime-safe option changes without recreating the editor. */
|
|
519
695
|
updateOptions(overrides: Partial<AsnOptions>): this;
|
|
@@ -776,6 +952,13 @@ export interface AutumnNoteStatic {
|
|
|
776
952
|
* referenced by string name in toolbar configuration.
|
|
777
953
|
*/
|
|
778
954
|
registerButton(btnDef: ToolbarItemDef): this;
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Registers an icon for every editor, keyed by button name or icon id.
|
|
958
|
+
* `icon` is SVG/HTML markup, or a CSS class list such as `'bi bi-type-bold'`.
|
|
959
|
+
* The per-editor `icons` option takes precedence.
|
|
960
|
+
*/
|
|
961
|
+
registerIcon(name: string, icon: string): this;
|
|
779
962
|
registerSlashCommand(command: SlashCommand): this;
|
|
780
963
|
|
|
781
964
|
/**
|