autumnnote 2.3.0 → 2.5.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 CHANGED
@@ -27,17 +27,18 @@ A **zero-dependency WYSIWYG rich-text editor** built with vanilla JavaScript (ES
27
27
 
28
28
  1. [Features](#features)
29
29
  2. [Installation](#installation)
30
- 3. [Framework Wrappers](#framework-wrappers)
31
- 4. [Quick Start](#quick-start)
32
- 5. [Plugin API](#plugin-api)
33
- 6. [API](#api)
34
- 7. [Options](#options)
35
- 8. [Toolbar Customisation](#toolbar-customisation)
36
- 9. [Keyboard Shortcuts](#keyboard-shortcuts)
37
- 10. [Mentions](#mentions)
38
- 11. [Project Structure](#project-structure)
39
- 12. [Comparison](#comparison)
40
- 13. [License](#license)
30
+ 3. [Minimal build](#minimal-build)
31
+ 4. [Framework Wrappers](#framework-wrappers)
32
+ 5. [Quick Start](#quick-start)
33
+ 6. [Plugin API](#plugin-api)
34
+ 7. [API](#api)
35
+ 8. [Options](#options)
36
+ 9. [Toolbar Customisation](#toolbar-customisation)
37
+ 10. [Keyboard Shortcuts](#keyboard-shortcuts)
38
+ 11. [Mentions](#mentions)
39
+ 12. [Project Structure](#project-structure)
40
+ 13. [Comparison](#comparison)
41
+ 14. [License](#license)
41
42
 
42
43
  ---
43
44
 
@@ -60,7 +61,23 @@ A **zero-dependency WYSIWYG rich-text editor** built with vanilla JavaScript (ES
60
61
  ### Insert
61
62
  - **Horizontal rule** — inserts an `<hr>` at the current caret position
62
63
  - **Link dialog** — URL, display text (auto-filled from selection), "Open in new tab" checkbox; edits existing links when caret is inside an `<a>`
63
- - **Image dialog** — insert by URL with alt text, or file upload (base64 embed); enforces `maxImageSize`; file input restricted to browser-renderable MIME types; supports custom `onImageUpload` handler for server-side upload
64
+ - **Image dialog** — insert by URL with alt text, or file upload (base64 embed); enforces `maxImageSize`; file input restricted to browser-renderable MIME types
65
+ - **Server-side image upload** — return the uploaded URL from `onImageUpload` (or a promise of it) and the editor drops in a dimmed placeholder previewing the local file straight away, then swaps in the real URL when it lands. Report progress with the supplied `setProgress(file, ratio)`; a rejection marks the image failed and fires `imageError` with a `retry()` for that file. A handler that returns nothing keeps the previous behaviour and inserts the image itself:
66
+
67
+ ```js
68
+ AutumnNote.create('#editor', {
69
+ async onImageUpload(files, { setProgress }) {
70
+ return Promise.all(files.map(async (file) => {
71
+ const body = new FormData();
72
+ body.append('file', file);
73
+ setProgress(file, 0.1);
74
+ const res = await fetch('/api/upload', { method: 'POST', body });
75
+ setProgress(file, 1);
76
+ return (await res.json()).url; // inserted in place of the placeholder
77
+ }));
78
+ },
79
+ });
80
+ ```
64
81
  - **Image crop overlay** — inline interactive crop tool triggered from the image tooltip; corner and edge drag handles; canvas-based crop export; CORS fallback warning
65
82
  - **Video dialog** — paste a YouTube watch/short URL, Vimeo URL, or direct `.mp4 / .webm / .ogg` URL; configurable width; renders as responsive `<iframe>` or `<video>`
66
83
  - **Table** — interactive grid picker (up to 10x10); optional header row (`tableHeaderRow`); floating tooltip for full row/column/cell management
@@ -69,7 +86,7 @@ A **zero-dependency WYSIWYG rich-text editor** built with vanilla JavaScript (ES
69
86
 
70
87
  ### Search
71
88
  - **Find and Replace** — `Ctrl+F` to find, `Ctrl+H` for find-and-replace; compact non-blocking floating panel (top-right); TreeWalker text matching; `<mark>` highlighting; case-sensitive `Aa` toggle; **regex mode** (`.*` toggle); icon-button Prev/Next navigation (↑ ↓); single and replace-all modes
72
- - **Auto language detection** — when selected text is formatted as a code block the editor automatically analyses the content and applies Prism.js syntax highlighting; 20 languages detected: JavaScript, TypeScript, Python, HTML, CSS, SCSS, JSON, SQL, Bash, Java, C#, PHP, Ruby, Go, Rust, C++, C, Kotlin, Swift, XML
89
+ - **Auto language detection** — when selected text is formatted as a code block the editor analyses the content and applies Prism.js syntax highlighting. 22 languages: JavaScript, TypeScript, Python, HTML, CSS, SCSS, JSON, YAML, Markdown, XML, SQL, Bash, Java, C#, PHP, Ruby, Go, Rust, C++, C, Kotlin, Swift. Detection weighs every matching signal and picks the highest-scoring language, requiring a clear margin before it commits — a snippet that could be two things is left unhighlighted rather than guessed at, and prose is never treated as code
73
90
 
74
91
  ### Inline tooltips
75
92
  Floating toolbars appear automatically when the user clicks on an editable element:
@@ -187,6 +204,34 @@ import 'autumnnote/dist/autumnnote.css';
187
204
 
188
205
  ---
189
206
 
207
+ ## Minimal build
208
+
209
+ The default entry installs every module. When you only need basic formatting,
210
+ import `autumnnote/core` instead — it leaves the dialogs, floating tooltips,
211
+ emoji and icon pickers and the crop overlay out of the bundle entirely rather
212
+ than shipping them switched off:
213
+
214
+ ```js
215
+ import AutumnNote from 'autumnnote/core';
216
+ import 'autumnnote/dist/autumnnote.css'; // same stylesheet as the full build
217
+
218
+ AutumnNote.create('#editor', {
219
+ toolbar: [['bold', 'italic', 'underline'], ['ul', 'ol'], ['undo', 'redo']],
220
+ });
221
+ ```
222
+
223
+ | Entry | Modules | ES bundle (gzip) |
224
+ |---|---|---|
225
+ | `autumnnote` | all | 84.1 KiB |
226
+ | `autumnnote/core` | editor, toolbar, statusbar, clipboard, placeholder | **44.2 KiB** |
227
+
228
+ Same API, same types, same stylesheet — the difference is only which modules are
229
+ installed. A toolbar button whose module is absent still renders, but invoking it
230
+ logs a warning and does nothing, so give this preset a toolbar naming only
231
+ buttons the core modules serve.
232
+
233
+ ---
234
+
190
235
  ## Framework Wrappers
191
236
 
192
237
  Official React and Vue 3 wrappers are available as separate packages in this monorepo (managed with pnpm workspaces).
@@ -312,18 +357,44 @@ const editor = AutumnNote.create('#my-editor', {
312
357
 
313
358
  ### Custom image upload
314
359
 
360
+ Return the URL and the editor places the image for you — a placeholder appears
361
+ at the caret immediately and is replaced when the upload resolves:
362
+
363
+ ```js
364
+ AutumnNote.create('#my-editor', {
365
+ async onImageUpload(files, { setProgress }) {
366
+ return Promise.all(files.map(async (file) => {
367
+ const fd = new FormData();
368
+ fd.append('file', file);
369
+ setProgress(file, 0.1);
370
+ const res = await fetch('/api/upload', { method: 'POST', body: fd });
371
+ setProgress(file, 1);
372
+ return (await res.json()).url;
373
+ }));
374
+ },
375
+ onImageError({ file, message, retry }) {
376
+ console.warn(message, file?.name);
377
+ retry?.(); // re-sends just that file
378
+ },
379
+ });
380
+ ```
381
+
382
+ Returning nothing keeps the original behaviour — the handler inserts the image
383
+ itself and no placeholder is shown:
384
+
315
385
  ```js
316
386
  const editor = AutumnNote.create('#my-editor', {
317
387
  onImageUpload(files) {
318
- const fd = new FormData();
319
- fd.append('file', files[0]);
320
- fetch('/api/upload', { method: 'POST', body: fd })
321
- .then(r => r.json())
322
- .then(({ url }) => editor.invoke('editor.insertImage', url, files[0].name));
388
+ upload(files[0]).then(({ url }) =>
389
+ editor.invoke('editor.insertImage', url, files[0].name));
323
390
  },
324
391
  });
325
392
  ```
326
393
 
394
+ > `onImageUpload` **uploads** and resolves to any URL the sanitiser accepts.
395
+ > `imageProcessor` **transforms** a file and must resolve to a data URL — use it
396
+ > for compression or format conversion, not for sending the file somewhere.
397
+
327
398
  ### Bubble toolbar
328
399
 
329
400
  ```js
@@ -474,7 +545,7 @@ See the [full Plugin API docs →](https://autumn.konexforge.com/docs.html#plugi
474
545
  | `blur` | `context` | Editor lost focus. |
475
546
  | `init` | `context` | Fired once after the editor has fully initialised. |
476
547
  | `imageUpload` | `files: FileList` | Fired when images are dropped or pasted (when `onImageUpload` is provided). |
477
- | `imageError` | `{ file, message }` | Fired when an image is rejected (e.g. over `maxImageSize`). |
548
+ | `imageError` | `{ file, message, error?, retry? }` | Fired when an image is rejected (e.g. over `maxImageSize`) or an upload fails. `retry()` is present on upload failures and re-sends that one file. |
478
549
  | `paste` | `{ text, html }` | Fired after every paste event. |
479
550
  | `pasteError` | `{ message, size?, maxBytes? }` | Fired when paste/drop exceeds `maxPasteSize` or a dropped Markdown file cannot be read. |
480
551
  | `selectionChange` | `context` | Fired when the cursor or selection changes. |
@@ -542,7 +613,7 @@ See the [full Plugin API docs →](https://autumn.konexforge.com/docs.html#plugi
542
613
  | `onFocus` | `Function` | `null` | `(context) => void` — called when the editor gains focus. |
543
614
  | `onBlur` | `Function` | `null` | `(context) => void` — called when the editor loses focus. |
544
615
  | `onInit` | `Function` | `null` | `(context) => void` — called once after the editor is initialised. |
545
- | `onImageUpload` | `Function` | `null` | `(files: FileList) => void`custom upload handler. Overrides base64 embed. |
616
+ | `onImageUpload` | `Function` | `null` | `(files, { context, setProgress }) => void \| string \| string[] \| Promise<…>` — upload handler; overrides the base64 embed. Return the uploaded URL(s) to have the editor insert them, or nothing to insert them yourself. |
546
617
  | `onImageError` | `Function` | `null` | `({ file, message }) => void` — called when an image is rejected. |
547
618
  | `onPaste` | `Function` | `null` | `({ text, html }) => void` — called after every paste event. |
548
619
  | `onPasteError` | `Function` | `null` | `({ message, size?, maxBytes? }) => void` — called when pasted or dropped content cannot be processed. |
@@ -721,7 +792,8 @@ src/
721
792
  │ │ └── sanitise.js DOM-based HTML and URL sanitiser
722
793
  │ ├── editing/
723
794
  │ │ ├── History.js Undo/redo stack (configurable depth)
724
- │ │ ├── Style.js Formatting commands (execCommand + DOM list/checklist transitions)
795
+ │ │ ├── insert.js Range-based insertHTML/insertText/insertHorizontalRule
796
+ │ │ ├── Style.js Formatting commands (native insertion, execCommand fallback)
725
797
  │ │ ├── Table.js Table creation and cell manipulation
726
798
  │ │ └── Typing.js Tab/Enter/ArrowKey behaviour and FA icon caret handling
727
799
  │ ├── module/