autumnnote 1.0.7 → 1.0.9
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 +332 -638
- package/dist/autumnnote.css +40 -4
- package/dist/autumnnote.es.js +3375 -262
- package/dist/autumnnote.es.js.map +1 -1
- package/dist/autumnnote.umd.js +3374 -261
- package/dist/autumnnote.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/js/Context.js +4 -0
- package/src/js/editing/Style.js +195 -44
- package/src/js/editing/Typing.js +2 -2
- package/src/js/i18n/de.js +320 -0
- package/src/js/i18n/en.js +328 -0
- package/src/js/i18n/es.js +320 -0
- package/src/js/i18n/fr.js +321 -0
- package/src/js/i18n/index.js +59 -0
- package/src/js/i18n/ja.js +321 -0
- package/src/js/i18n/ko.js +320 -0
- package/src/js/i18n/vi.js +321 -0
- package/src/js/i18n/zh.js +321 -0
- package/src/js/index.js +2 -1
- package/src/js/module/CodeTooltip.js +12 -9
- package/src/js/module/ContextMenu.js +13 -11
- package/src/js/module/Editor.js +14 -3
- package/src/js/module/EmojiDialog.js +19 -7
- package/src/js/module/FindReplace.js +14 -13
- package/src/js/module/IconDialog.js +25 -13
- package/src/js/module/ImageDialog.js +25 -20
- package/src/js/module/ImageTooltip.js +13 -12
- package/src/js/module/LinkDialog.js +10 -9
- package/src/js/module/LinkTooltip.js +6 -5
- package/src/js/module/Placeholder.js +6 -1
- package/src/js/module/ShortcutsDialog.js +5 -4
- package/src/js/module/Statusbar.js +6 -5
- package/src/js/module/TableTooltip.js +412 -102
- package/src/js/module/Toolbar.js +21 -15
- package/src/js/module/VideoDialog.js +10 -9
- package/src/js/module/VideoTooltip.js +12 -11
- package/src/js/settings.js +4 -0
- package/src/styles/autumnnote.scss +50 -5
- package/types/index.d.ts +58 -1
package/src/js/module/Toolbar.js
CHANGED
|
@@ -182,9 +182,9 @@ export class Toolbar {
|
|
|
182
182
|
const btn = createElement('button', {
|
|
183
183
|
type: 'button',
|
|
184
184
|
class: baseClass,
|
|
185
|
-
title: def.tooltip || '',
|
|
185
|
+
title: this.context.locale.toolbar[def.name] || def.tooltip || '',
|
|
186
186
|
'data-btn': def.name,
|
|
187
|
-
'aria-label': def.tooltip || def.name,
|
|
187
|
+
'aria-label': this.context.locale.toolbar[def.name] || def.tooltip || def.name,
|
|
188
188
|
'aria-haspopup': 'true',
|
|
189
189
|
'aria-expanded': 'false',
|
|
190
190
|
});
|
|
@@ -206,7 +206,7 @@ export class Toolbar {
|
|
|
206
206
|
});
|
|
207
207
|
const grid = createElement('div', { class: 'an-table-grid' });
|
|
208
208
|
const label = createElement('div', { class: 'an-table-label' });
|
|
209
|
-
label.textContent = 'Insert Table';
|
|
209
|
+
label.textContent = this.context.locale.toolbar.insertTableLabel || 'Insert Table';
|
|
210
210
|
|
|
211
211
|
const cells = [];
|
|
212
212
|
for (let r = 1; r <= ROWS; r++) {
|
|
@@ -232,7 +232,7 @@ export class Toolbar {
|
|
|
232
232
|
const c = +cell.getAttribute('data-col');
|
|
233
233
|
cell.classList.toggle('active', r <= rows && c <= cols);
|
|
234
234
|
});
|
|
235
|
-
label.textContent = (rows && cols) ? `${rows} × ${cols}` : 'Insert Table';
|
|
235
|
+
label.textContent = (rows && cols) ? `${rows} × ${cols}` : (this.context.locale.toolbar.insertTableLabel || 'Insert Table');
|
|
236
236
|
};
|
|
237
237
|
|
|
238
238
|
const openPopup = () => {
|
|
@@ -307,9 +307,9 @@ export class Toolbar {
|
|
|
307
307
|
const applyBtn = createElement('button', {
|
|
308
308
|
type: 'button',
|
|
309
309
|
class: `${baseClass} an-color-btn`,
|
|
310
|
-
title: def.tooltip || '',
|
|
310
|
+
title: this.context.locale.toolbar[def.name] || def.tooltip || '',
|
|
311
311
|
'data-btn': def.name,
|
|
312
|
-
'aria-label': def.tooltip || def.name,
|
|
312
|
+
'aria-label': this.context.locale.toolbar[def.name] || def.tooltip || def.name,
|
|
313
313
|
});
|
|
314
314
|
|
|
315
315
|
const S = 'stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"';
|
|
@@ -326,7 +326,9 @@ export class Toolbar {
|
|
|
326
326
|
const arrowBtn = createElement('button', {
|
|
327
327
|
type: 'button',
|
|
328
328
|
class: `${baseClass} an-color-arrow`,
|
|
329
|
-
title:
|
|
329
|
+
title: def.name === 'foreColor'
|
|
330
|
+
? (this.context.locale.toolbar.chooseTextColor || 'Choose text color')
|
|
331
|
+
: (this.context.locale.toolbar.chooseHighlightColor || 'Choose highlight color'),
|
|
330
332
|
'aria-haspopup': 'true',
|
|
331
333
|
'aria-expanded': 'false',
|
|
332
334
|
});
|
|
@@ -346,8 +348,8 @@ export class Toolbar {
|
|
|
346
348
|
});
|
|
347
349
|
|
|
348
350
|
const customRow = createElement('div', { class: 'an-color-custom' });
|
|
349
|
-
const colorInput = createElement('input', { type: 'color', value: currentColor, title: 'Custom color' });
|
|
350
|
-
const customLabel = createElement('span', {}, ['Custom color']);
|
|
351
|
+
const colorInput = createElement('input', { type: 'color', value: currentColor, title: this.context.locale.toolbar.customColor || 'Custom color' });
|
|
352
|
+
const customLabel = createElement('span', {}, [this.context.locale.toolbar.customColor || 'Custom color']);
|
|
351
353
|
customRow.appendChild(colorInput);
|
|
352
354
|
customRow.appendChild(customLabel);
|
|
353
355
|
|
|
@@ -491,19 +493,23 @@ export class Toolbar {
|
|
|
491
493
|
const cls = def.selectClass ? `an-select ${def.selectClass}` : 'an-select';
|
|
492
494
|
const select = createElement('select', {
|
|
493
495
|
class: cls,
|
|
494
|
-
title: def.tooltip || '',
|
|
496
|
+
title: this.context.locale.toolbar[def.name] || def.tooltip || '',
|
|
495
497
|
'data-btn': def.name,
|
|
496
|
-
'aria-label': def.tooltip || def.name,
|
|
498
|
+
'aria-label': this.context.locale.toolbar[def.name] || def.tooltip || def.name,
|
|
497
499
|
});
|
|
498
500
|
|
|
499
501
|
// Blank "placeholder" option (non-selectable header)
|
|
500
|
-
const placeholderText = def.placeholder || 'Font';
|
|
502
|
+
const placeholderText = this.context.locale.toolbar[def.name + 'Placeholder'] || def.placeholder || 'Font';
|
|
501
503
|
const placeholder = createElement('option', { value: '', disabled: '', hidden: '' }, [placeholderText]);
|
|
502
504
|
select.appendChild(placeholder);
|
|
503
505
|
|
|
504
506
|
items.forEach((item) => {
|
|
505
507
|
const value = (typeof item === 'object') ? item.value : item;
|
|
506
|
-
const label = (typeof item === 'object')
|
|
508
|
+
const label = (typeof item === 'object')
|
|
509
|
+
? (def.name === 'paragraphStyle'
|
|
510
|
+
? ((this.context.locale.toolbar.paragraphItems || {})[item.value] || item.label)
|
|
511
|
+
: item.label)
|
|
512
|
+
: item;
|
|
507
513
|
const isHeader = (typeof item === 'object') && !!item.disabled;
|
|
508
514
|
const attrs = { value };
|
|
509
515
|
if (isHeader) attrs.disabled = '';
|
|
@@ -558,9 +564,9 @@ export class Toolbar {
|
|
|
558
564
|
const btn = createElement('button', {
|
|
559
565
|
type: 'button',
|
|
560
566
|
class: classAttr,
|
|
561
|
-
title: btnDef.tooltip || '',
|
|
567
|
+
title: this.context.locale.toolbar[btnDef.name] || btnDef.tooltip || '',
|
|
562
568
|
'data-btn': btnDef.name,
|
|
563
|
-
'aria-label': btnDef.tooltip || btnDef.name,
|
|
569
|
+
'aria-label': this.context.locale.toolbar[btnDef.name] || btnDef.tooltip || btnDef.name,
|
|
564
570
|
});
|
|
565
571
|
|
|
566
572
|
// Render icon: prefer FontAwesome if enabled; otherwise fall back to SVG or text.
|
|
@@ -59,24 +59,25 @@ export class VideoDialog {
|
|
|
59
59
|
// ---------------------------------------------------------------------------
|
|
60
60
|
|
|
61
61
|
_buildDialog() {
|
|
62
|
+
const L = this.context.locale.videoDialog;
|
|
62
63
|
const overlay = createElement('div', {
|
|
63
64
|
class: 'an-dialog-overlay',
|
|
64
65
|
role: 'dialog',
|
|
65
66
|
'aria-modal': 'true',
|
|
66
|
-
'aria-label':
|
|
67
|
+
'aria-label': L.ariaLabel,
|
|
67
68
|
});
|
|
68
69
|
const box = createElement('div', { class: 'an-dialog-box' });
|
|
69
70
|
|
|
70
71
|
const title = createElement('h3', { class: 'an-dialog-title' });
|
|
71
|
-
title.textContent =
|
|
72
|
+
title.textContent = L.title;
|
|
72
73
|
|
|
73
74
|
// URL input
|
|
74
75
|
const urlLabel = createElement('label', { class: 'an-label' });
|
|
75
|
-
urlLabel.textContent =
|
|
76
|
+
urlLabel.textContent = L.videoUrl;
|
|
76
77
|
const urlInput = /** @type {HTMLInputElement} */ (createElement('input', {
|
|
77
78
|
type: 'url',
|
|
78
79
|
class: 'an-input',
|
|
79
|
-
placeholder:
|
|
80
|
+
placeholder: L.urlPlaceholder,
|
|
80
81
|
autocomplete: 'off',
|
|
81
82
|
}));
|
|
82
83
|
this._urlInput = urlInput;
|
|
@@ -87,7 +88,7 @@ export class VideoDialog {
|
|
|
87
88
|
|
|
88
89
|
// Width
|
|
89
90
|
const widthLabel = createElement('label', { class: 'an-label' });
|
|
90
|
-
widthLabel.textContent =
|
|
91
|
+
widthLabel.textContent = L.widthLabel;
|
|
91
92
|
const widthInput = /** @type {HTMLInputElement} */ (createElement('input', {
|
|
92
93
|
type: 'number',
|
|
93
94
|
class: 'an-input',
|
|
@@ -101,9 +102,9 @@ export class VideoDialog {
|
|
|
101
102
|
// Buttons
|
|
102
103
|
const btnRow = createElement('div', { class: 'an-dialog-actions' });
|
|
103
104
|
const insertBtn = createElement('button', { type: 'button', class: 'an-btn an-btn-primary' });
|
|
104
|
-
insertBtn.textContent =
|
|
105
|
+
insertBtn.textContent = L.insertBtn;
|
|
105
106
|
const cancelBtn = createElement('button', { type: 'button', class: 'an-btn' });
|
|
106
|
-
cancelBtn.textContent =
|
|
107
|
+
cancelBtn.textContent = L.cancelBtn;
|
|
107
108
|
btnRow.appendChild(insertBtn);
|
|
108
109
|
btnRow.appendChild(cancelBtn);
|
|
109
110
|
|
|
@@ -113,7 +114,7 @@ export class VideoDialog {
|
|
|
113
114
|
// Live URL hint
|
|
114
115
|
const d0 = on(urlInput, 'input', () => {
|
|
115
116
|
const info = this._parseVideoUrl(urlInput.value.trim());
|
|
116
|
-
hintEl.textContent = info ?
|
|
117
|
+
hintEl.textContent = info ? this.context.locale.videoDialog.detected(info.type) : (urlInput.value ? this.context.locale.videoDialog.unknownFormat : '');
|
|
117
118
|
});
|
|
118
119
|
|
|
119
120
|
const d1 = on(insertBtn, 'click', () => this._onInsert());
|
|
@@ -140,7 +141,7 @@ export class VideoDialog {
|
|
|
140
141
|
|
|
141
142
|
const html = this._buildEmbedHtml(rawUrl, width);
|
|
142
143
|
if (!html) {
|
|
143
|
-
this._hintEl.textContent =
|
|
144
|
+
this._hintEl.textContent = this.context.locale.videoDialog.invalidUrl;
|
|
144
145
|
this._urlInput.focus();
|
|
145
146
|
return;
|
|
146
147
|
}
|
|
@@ -78,24 +78,25 @@ export class VideoTooltip {
|
|
|
78
78
|
// ---------------------------------------------------------------------------
|
|
79
79
|
|
|
80
80
|
_buildTooltip() {
|
|
81
|
+
const L = this.context.locale.tooltips.video;
|
|
81
82
|
const el = createElement('div', {
|
|
82
83
|
class: 'an-link-tooltip an-video-tooltip',
|
|
83
84
|
role: 'toolbar',
|
|
84
|
-
'aria-label':
|
|
85
|
+
'aria-label': L.ariaLabel,
|
|
85
86
|
});
|
|
86
87
|
el.style.display = 'none';
|
|
87
88
|
|
|
88
89
|
// Label
|
|
89
90
|
this._label = createElement('span', { class: 'an-link-tooltip-url' });
|
|
90
|
-
this._label.textContent =
|
|
91
|
+
this._label.textContent = L.label;
|
|
91
92
|
el.appendChild(this._label);
|
|
92
93
|
|
|
93
94
|
el.appendChild(createElement('div', { class: 'an-link-tooltip-sep' }));
|
|
94
95
|
|
|
95
|
-
this._floatLeftBtn = this._makeBtn(ICONS.floatLeft,
|
|
96
|
-
this._floatNoneBtn = this._makeBtn(ICONS.floatNone,
|
|
97
|
-
this._alignCenterBtn = this._makeBtn(ICONS.alignCenter,
|
|
98
|
-
this._floatRightBtn = this._makeBtn(ICONS.floatRight,
|
|
96
|
+
this._floatLeftBtn = this._makeBtn(ICONS.floatLeft, L.floatLeft, () => this._setFloat('left'));
|
|
97
|
+
this._floatNoneBtn = this._makeBtn(ICONS.floatNone, L.noFloat, () => this._setFloat(''));
|
|
98
|
+
this._alignCenterBtn = this._makeBtn(ICONS.alignCenter, L.alignCenter, () => this._setCenter());
|
|
99
|
+
this._floatRightBtn = this._makeBtn(ICONS.floatRight, L.floatRight, () => this._setFloat('right'));
|
|
99
100
|
|
|
100
101
|
el.appendChild(this._floatLeftBtn);
|
|
101
102
|
el.appendChild(this._floatNoneBtn);
|
|
@@ -104,18 +105,18 @@ export class VideoTooltip {
|
|
|
104
105
|
|
|
105
106
|
el.appendChild(createElement('div', { class: 'an-link-tooltip-sep' }));
|
|
106
107
|
|
|
107
|
-
this._originalBtn = this._makeBtn(ICONS.originalSize,
|
|
108
|
+
this._originalBtn = this._makeBtn(ICONS.originalSize, L.originalSize, () => this._resetSize());
|
|
108
109
|
|
|
109
110
|
el.appendChild(this._originalBtn);
|
|
110
111
|
|
|
111
112
|
el.appendChild(createElement('div', { class: 'an-link-tooltip-sep' }));
|
|
112
113
|
|
|
113
|
-
this._previewBtn = this._makeBtn(ICONS.preview,
|
|
114
|
+
this._previewBtn = this._makeBtn(ICONS.preview, L.previewVideo, () => this._togglePreview());
|
|
114
115
|
el.appendChild(this._previewBtn);
|
|
115
116
|
|
|
116
117
|
el.appendChild(createElement('div', { class: 'an-link-tooltip-sep' }));
|
|
117
118
|
|
|
118
|
-
this._deleteBtn = this._makeBtn(ICONS.deleteVideo,
|
|
119
|
+
this._deleteBtn = this._makeBtn(ICONS.deleteVideo, L.deleteVideo, () => this._delete(), true);
|
|
119
120
|
|
|
120
121
|
el.appendChild(this._deleteBtn);
|
|
121
122
|
|
|
@@ -292,7 +293,7 @@ export class VideoTooltip {
|
|
|
292
293
|
|
|
293
294
|
// Visual feedback: button turns primary-coloured
|
|
294
295
|
this._previewBtn.classList.add('an-link-tooltip-btn--copied');
|
|
295
|
-
this._previewBtn.title =
|
|
296
|
+
this._previewBtn.title = this.context.locale.tooltips.video.exitPreview;
|
|
296
297
|
|
|
297
298
|
// Exit preview on mousedown outside the wrapper.
|
|
298
299
|
// Using 'mousedown' (not 'click') so clicks inside an iframe
|
|
@@ -319,7 +320,7 @@ export class VideoTooltip {
|
|
|
319
320
|
|
|
320
321
|
// Reset button appearance
|
|
321
322
|
this._previewBtn.classList.remove('an-link-tooltip-btn--copied');
|
|
322
|
-
this._previewBtn.title =
|
|
323
|
+
this._previewBtn.title = this.context.locale.tooltips.video.previewVideo;
|
|
323
324
|
|
|
324
325
|
if (this._previewClickOff) {
|
|
325
326
|
document.removeEventListener('mousedown', this._previewClickOff, true);
|
package/src/js/settings.js
CHANGED
|
@@ -135,4 +135,8 @@ export const defaultOptions = {
|
|
|
135
135
|
// Custom focus ring colour — overrides the default blue when set.
|
|
136
136
|
// Accepts any valid CSS colour string, e.g. '#f97316', 'hsl(25,90%,55%)'.
|
|
137
137
|
focusColor: null,
|
|
138
|
+
// Display language for the editor UI.
|
|
139
|
+
// Built-in values: 'en' (default), 'vi', 'ja', 'zh', 'fr'.
|
|
140
|
+
// Pass a partial or full locale object to override individual strings.
|
|
141
|
+
lang: 'en',
|
|
138
142
|
};
|
|
@@ -48,20 +48,34 @@
|
|
|
48
48
|
.an-editable {
|
|
49
49
|
cursor: text;
|
|
50
50
|
user-select: text;
|
|
51
|
-
//
|
|
52
|
-
|
|
51
|
+
// No background change — keep the same appearance as editable mode
|
|
52
|
+
// so read-only content looks identical to the live editor.
|
|
53
53
|
|
|
54
54
|
// Block checklist checkbox interaction in read-only mode.
|
|
55
|
+
// Keep opacity:1 so disabled checkboxes are still clearly visible.
|
|
55
56
|
ul.an-checklist input[type='checkbox'] {
|
|
56
57
|
pointer-events: none;
|
|
57
58
|
cursor: default;
|
|
59
|
+
opacity: 1;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
// Prevent images
|
|
61
|
-
img
|
|
62
|
+
// Prevent images from being dragged out.
|
|
63
|
+
img {
|
|
64
|
+
-webkit-user-drag: none;
|
|
65
|
+
user-drag: none;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Prevent video wrapper itself from being dragged, but keep pointer-events
|
|
69
|
+
// active so the video shield works and the iframe is visible/interactive.
|
|
62
70
|
.an-video-wrapper {
|
|
63
71
|
-webkit-user-drag: none;
|
|
64
72
|
user-drag: none;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// D-3: In read-only mode, disable the video shield so clicks reach the
|
|
76
|
+
// underlying <iframe> / <video> and users can play videos normally.
|
|
77
|
+
// The shield is only needed in edit mode to prevent accidental interaction.
|
|
78
|
+
.an-video-wrapper .an-video-shield {
|
|
65
79
|
pointer-events: none;
|
|
66
80
|
}
|
|
67
81
|
}
|
|
@@ -435,7 +449,7 @@
|
|
|
435
449
|
// Content styles
|
|
436
450
|
p { margin: 0 0 0.75em; }
|
|
437
451
|
h1, h2, h3, h4, h5, h6 { margin: 0.5em 0; line-height: 1.3; }
|
|
438
|
-
ul, ol { margin: 0 0 0.75em 1.5em;
|
|
452
|
+
ul, ol { margin: 0 0 0.75em 0; padding-left: 1.5em; list-style-position: inside; }
|
|
439
453
|
li { margin-bottom: 0.25em; }
|
|
440
454
|
blockquote {
|
|
441
455
|
margin: 0.5em 0 0.5em 1em;
|
|
@@ -638,6 +652,26 @@
|
|
|
638
652
|
letter-spacing: 0.02em;
|
|
639
653
|
}
|
|
640
654
|
|
|
655
|
+
// Active state for toggle buttons in tooltips (e.g. Select Cells)
|
|
656
|
+
.an-link-tooltip-btn--active {
|
|
657
|
+
background: rgba(#3b82f6, 0.12) !important;
|
|
658
|
+
color: #3b82f6 !important;
|
|
659
|
+
svg { stroke: #3b82f6; }
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// Cells highlighted when select mode is active
|
|
663
|
+
.an-cell-selected {
|
|
664
|
+
background-color: rgba(#3b82f6, 0.18) !important;
|
|
665
|
+
outline: 2px solid #3b82f6;
|
|
666
|
+
outline-offset: -2px;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Cursor hint for all cells when select mode is on
|
|
670
|
+
.an-table-select-mode td,
|
|
671
|
+
.an-table-select-mode th {
|
|
672
|
+
cursor: cell;
|
|
673
|
+
}
|
|
674
|
+
|
|
641
675
|
// Size popover (column width / row height)
|
|
642
676
|
.an-size-popover {
|
|
643
677
|
position: fixed;
|
|
@@ -1759,6 +1793,17 @@ $an-video-accent: #8b5cf6; // violet-500
|
|
|
1759
1793
|
color: #cdd6f4;
|
|
1760
1794
|
}
|
|
1761
1795
|
|
|
1796
|
+
.an-link-tooltip-btn--active {
|
|
1797
|
+
background: rgba(#6366f1, 0.2) !important;
|
|
1798
|
+
color: #818cf8 !important;
|
|
1799
|
+
svg { stroke: #818cf8; }
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
.an-cell-selected {
|
|
1803
|
+
background-color: rgba(#6366f1, 0.25) !important;
|
|
1804
|
+
outline-color: #6366f1;
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1762
1807
|
.an-table-cell {
|
|
1763
1808
|
background: #24273a;
|
|
1764
1809
|
border-color: #3f3f5f;
|
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AutumnNote – TypeScript declarations
|
|
3
|
-
* @version 1.0.
|
|
3
|
+
* @version 1.0.9
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
@@ -104,6 +104,12 @@ export interface AsnOptions {
|
|
|
104
104
|
onPaste?: (data: { text: string; html: string | null }) => void;
|
|
105
105
|
/** Additional color swatches shown at the top of the color picker. */
|
|
106
106
|
colorSwatches?: string[];
|
|
107
|
+
/**
|
|
108
|
+
* Display language for the editor UI.
|
|
109
|
+
* Built-in: 'en' (default) | 'vi' | 'ja' | 'zh' | 'fr'.
|
|
110
|
+
* Pass a partial locale object to override individual strings.
|
|
111
|
+
*/
|
|
112
|
+
lang?: string | Partial<AsnLocale>;
|
|
107
113
|
}
|
|
108
114
|
|
|
109
115
|
// ---------------------------------------------------------------------------
|
|
@@ -179,6 +185,57 @@ export type ToolbarItemDef = ButtonDef | DropdownDef | GridButtonDef | ColorPick
|
|
|
179
185
|
/** Runtime default options object (same export as `src/js/index.js`). */
|
|
180
186
|
export declare const defaultOptions: Required<AsnOptions>;
|
|
181
187
|
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
// Locale / i18n
|
|
190
|
+
// ---------------------------------------------------------------------------
|
|
191
|
+
|
|
192
|
+
/** Full locale object shape used by the editor. All leaf values are strings or template functions. */
|
|
193
|
+
export interface AsnLocale {
|
|
194
|
+
toolbar: Record<string, string | ((n: string | number) => string) | Record<string, string>>;
|
|
195
|
+
linkDialog: Record<string, string>;
|
|
196
|
+
imageDialog: Record<string, string>;
|
|
197
|
+
videoDialog: Record<string, string | ((type: string) => string)>;
|
|
198
|
+
emojiDialog: Record<string, string | Record<string, string>>;
|
|
199
|
+
iconDialog: Record<string, string | Record<string, string>>;
|
|
200
|
+
findReplace: Record<string, string>;
|
|
201
|
+
shortcutsDialog: {
|
|
202
|
+
title: string;
|
|
203
|
+
ariaLabel: string;
|
|
204
|
+
close: string;
|
|
205
|
+
shortcuts: Array<{ category: string; items: Array<{ keys: string; action: string }> }>;
|
|
206
|
+
};
|
|
207
|
+
contextMenu: Record<string, string>;
|
|
208
|
+
statusbar: {
|
|
209
|
+
resizeHandle: string;
|
|
210
|
+
words: (n: number) => string;
|
|
211
|
+
wordsLimit: (n: number, max: number) => string;
|
|
212
|
+
chars: (n: number) => string;
|
|
213
|
+
charsLimit: (n: number, max: number) => string;
|
|
214
|
+
};
|
|
215
|
+
tooltips: {
|
|
216
|
+
link: Record<string, string>;
|
|
217
|
+
image: Record<string, string>;
|
|
218
|
+
code: Record<string, string>;
|
|
219
|
+
table: Record<string, string>;
|
|
220
|
+
video: Record<string, string>;
|
|
221
|
+
};
|
|
222
|
+
errors: {
|
|
223
|
+
imageFormat: (type: string) => string;
|
|
224
|
+
imageSize: (maxMb: number) => string;
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** Registry of all built-in locales (keys: 'en', 'vi', 'ja', 'zh', 'fr'). */
|
|
229
|
+
export declare const locales: Record<string, AsnLocale>;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Resolves a lang value to a full AsnLocale.
|
|
233
|
+
* - string key → looks up locales registry, deep-merges with 'en' fallback.
|
|
234
|
+
* - object → deep-merges with 'en' as base.
|
|
235
|
+
* - falsy / 'en' → returns the canonical English locale.
|
|
236
|
+
*/
|
|
237
|
+
export declare function resolveLocale(lang: string | Partial<AsnLocale> | null | undefined): AsnLocale;
|
|
238
|
+
|
|
182
239
|
// Re-export core utility modules exposed by the package entry-point.
|
|
183
240
|
export * from '../src/js/core/dom.js';
|
|
184
241
|
export * from '../src/js/core/range.js';
|