autumnnote 1.4.2 → 1.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
@@ -26,16 +26,17 @@ A modern WYSIWYG rich-text editor built with vanilla JavaScript (ES2022+) — no
26
26
 
27
27
  1. [Features](#features)
28
28
  2. [Installation](#installation)
29
- 3. [Quick Start](#quick-start)
30
- 4. [Plugin API](#plugin-api)
31
- 5. [API](#api)
32
- 6. [Options](#options)
33
- 7. [Toolbar Customisation](#toolbar-customisation)
34
- 8. [Keyboard Shortcuts](#keyboard-shortcuts)
35
- 9. [Mentions](#mentions)
36
- 10. [Project Structure](#project-structure)
37
- 11. [Comparison](#comparison)
38
- 12. [License](#license)
29
+ 3. [Framework Wrappers](#framework-wrappers)
30
+ 4. [Quick Start](#quick-start)
31
+ 5. [Plugin API](#plugin-api)
32
+ 6. [API](#api)
33
+ 7. [Options](#options)
34
+ 8. [Toolbar Customisation](#toolbar-customisation)
35
+ 9. [Keyboard Shortcuts](#keyboard-shortcuts)
36
+ 10. [Mentions](#mentions)
37
+ 11. [Project Structure](#project-structure)
38
+ 12. [Comparison](#comparison)
39
+ 13. [License](#license)
39
40
 
40
41
  ---
41
42
 
@@ -166,6 +167,66 @@ import 'autumnnote/dist/autumnnote.css';
166
167
 
167
168
  ---
168
169
 
170
+ ## Framework Wrappers
171
+
172
+ Official React and Vue 3 wrappers are available as separate packages in this monorepo (managed with pnpm workspaces).
173
+
174
+ ### React
175
+
176
+ ```bash
177
+ npm install autumnnote autumnnote-react
178
+ import 'autumnnote/dist/autumnnote.css';
179
+ ```
180
+
181
+ ```jsx
182
+ import { useRef } from 'react';
183
+ import AutumnNoteEditor from 'autumnnote-react';
184
+
185
+ function MyEditor() {
186
+ const editorRef = useRef(null);
187
+
188
+ return (
189
+ <AutumnNoteEditor
190
+ ref={editorRef}
191
+ options={{ placeholder: 'Start typing…', height: 300, bubbleToolbar: true }}
192
+ />
193
+ );
194
+ }
195
+
196
+ // Access the editor instance:
197
+ editorRef.current.getHTML();
198
+ editorRef.current.invoke('editor.setHTML', '<p>Hello!</p>');
199
+ ```
200
+
201
+ The `ref` is forwarded to the underlying `Context` instance via `useImperativeHandle`. Pass a `key` prop to force remount when options change.
202
+
203
+ ### Vue 3
204
+
205
+ ```bash
206
+ npm install autumnnote autumnnote-vue
207
+ import 'autumnnote/dist/autumnnote.css';
208
+ ```
209
+
210
+ ```vue
211
+ <script setup>
212
+ import { ref } from 'vue';
213
+ import AutumnNoteEditor from 'autumnnote-vue';
214
+
215
+ const editorRef = ref(null);
216
+ </script>
217
+
218
+ <template>
219
+ <AutumnNoteEditor
220
+ ref="editorRef"
221
+ :options="{ placeholder: 'Start typing…', height: 300 }"
222
+ />
223
+ </template>
224
+ ```
225
+
226
+ Access the editor instance via `editorRef.value.editor.value` (the `editor` reactive ref exposed by `defineExpose`).
227
+
228
+ ---
229
+
169
230
  ## Quick Start
170
231
 
171
232
  ### ES Module
@@ -641,16 +702,34 @@ src/
641
702
  └── autumnnote.scss Main stylesheet
642
703
  ```
643
704
 
705
+ ### Monorepo structure
706
+
707
+ This project uses **pnpm workspaces** to manage the core library alongside official framework wrappers:
708
+
709
+ ```
710
+ autumn-note-ce/
711
+ ├── pnpm-workspace.yaml # workspace root
712
+ ├── src/ # core library source
713
+ ├── packages/
714
+ │ ├── react/ # autumnnote-react
715
+ │ │ └── src/index.jsx
716
+ │ └── vue/ # autumnnote-vue
717
+ │ └── src/AutumnNote.vue
718
+ └── test/ # Vitest test suite
719
+ ```
720
+
644
721
  ### Development commands
645
722
 
646
723
  ```bash
647
- npm install # install dependencies
648
- npm run dev # start Vite dev server with HMR
649
- npm run build # build ES + UMD + CSS to dist/
650
- npm test # run Vitest test suite once
651
- npm run test:watch # run tests in watch mode
652
- npm run lint # ESLint
653
- npm run typecheck # TypeScript type check (tsconfig.json)
724
+ pnpm install # install all workspace packages
725
+ npm run dev # start Vite dev server with HMR
726
+ npm run build # build core ES + UMD + CSS to dist/
727
+ pnpm --filter autumnnote-react build # build React wrapper
728
+ pnpm --filter autumnnote-vue build # build Vue wrapper
729
+ npm test # run Vitest test suite once
730
+ npm run test:watch # run tests in watch mode
731
+ npm run lint # ESLint
732
+ npm run typecheck # TypeScript type check (tsconfig.json)
654
733
  ```
655
734
 
656
735
  Build output in `dist/`:
@@ -1590,6 +1590,7 @@ var en = {
1590
1590
  chooseHighlightColor: "Choose highlight color",
1591
1591
  customColor: "Custom color",
1592
1592
  insertTableLabel: "Insert Table",
1593
+ /** Map of paragraph-style value → label (only values needing translation) */
1593
1594
  paragraphItems: {
1594
1595
  p: "Normal",
1595
1596
  blockquote: "Quote",
@@ -1632,6 +1633,7 @@ var en = {
1632
1633
  widthPlaceholder: "560",
1633
1634
  insertBtn: "Insert",
1634
1635
  cancelBtn: "Cancel",
1636
+ /** @param {string} type */
1635
1637
  detected: (type) => `Detected: ${type}`,
1636
1638
  unknownFormat: "Unknown format — will try direct video embed",
1637
1639
  invalidUrl: "Invalid URL — please enter a valid video link."
@@ -1794,9 +1796,13 @@ var en = {
1794
1796
  },
1795
1797
  statusbar: {
1796
1798
  resizeHandle: "Resize editor",
1799
+ /** @param {number} n */
1797
1800
  words: (n) => `Words: ${n}`,
1801
+ /** @param {number} n @param {number} max */
1798
1802
  wordsLimit: (n, max) => `Words: ${n}/${max}`,
1803
+ /** @param {number} n */
1799
1804
  chars: (n) => `Chars: ${n}`,
1805
+ /** @param {number} n @param {number} max */
1800
1806
  charsLimit: (n, max) => `Chars: ${n}/${max}`
1801
1807
  },
1802
1808
  tooltips: {
@@ -1869,7 +1875,9 @@ var en = {
1869
1875
  }
1870
1876
  },
1871
1877
  errors: {
1878
+ /** @param {string} type */
1872
1879
  imageFormat: (type) => `Format "${type}" is not supported for display in web browsers. Please convert to JPEG, PNG, or WebP first.`,
1880
+ /** @param {number} maxSize */
1873
1881
  imageSize: (maxSize) => `Image file is too large. Maximum allowed size is ${maxSize} MB.`
1874
1882
  }
1875
1883
  };
@@ -16359,13 +16367,21 @@ function any(arr, predicate) {
16359
16367
  */
16360
16368
  var userAgent = navigator.userAgent;
16361
16369
  var env = {
16370
+ /** True if browser is Chrome */
16362
16371
  isChrome: /Chrome\//.test(userAgent),
16372
+ /** True if browser is Firefox */
16363
16373
  isFF: /Firefox\//.test(userAgent),
16374
+ /** True if browser is Safari (not Chrome) */
16364
16375
  isSafari: /^((?!chrome|android).)*safari/i.test(userAgent),
16376
+ /** True if browser is Edge (Chromium) */
16365
16377
  isEdge: /Edg\//.test(userAgent),
16378
+ /** True if running on macOS */
16366
16379
  isMac: /Macintosh/.test(userAgent),
16380
+ /** True if running on mobile */
16367
16381
  isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent),
16382
+ /** True if touch is supported */
16368
16383
  isTouch: "ontouchstart" in window || navigator.maxTouchPoints > 0,
16384
+ /** Modifier key name depending on platform */
16369
16385
  modifierKey: /Macintosh/.test(userAgent) ? "metaKey" : "ctrlKey"
16370
16386
  };
16371
16387
  //#endregion
@@ -16374,6 +16390,13 @@ var _originalDefaults = { ...defaultOptions };
16374
16390
  /** @type {WeakMap<Element, Context>} */
16375
16391
  var instances = /* @__PURE__ */ new WeakMap();
16376
16392
  var AutumnNote = {
16393
+ /**
16394
+ * Creates (or returns existing) editor instance on one or more elements.
16395
+ *
16396
+ * @param {string|Element|NodeList|Element[]} selector
16397
+ * @param {import('./settings.js').AsnOptions} [options]
16398
+ * @returns {Context|Context[]} single Context or array of Contexts
16399
+ */
16377
16400
  create(selector, options = {}) {
16378
16401
  const ctxs = resolveElements(selector).map((el) => {
16379
16402
  if (instances.has(el)) return instances.get(el);
@@ -16384,6 +16407,10 @@ var AutumnNote = {
16384
16407
  });
16385
16408
  return ctxs.length === 1 ? ctxs[0] : ctxs;
16386
16409
  },
16410
+ /**
16411
+ * Destroys the editor(s) on the given selector.
16412
+ * @param {string|Element|NodeList|Element[]} selector
16413
+ */
16387
16414
  destroy(selector) {
16388
16415
  resolveElements(selector).forEach((el) => {
16389
16416
  const ctx = instances.get(el);
@@ -16393,23 +16420,45 @@ var AutumnNote = {
16393
16420
  }
16394
16421
  });
16395
16422
  },
16423
+ /**
16424
+ * Returns the Context instance for a given element (or null).
16425
+ * @param {string|Element} selector
16426
+ * @returns {Context|null}
16427
+ */
16396
16428
  getInstance(selector) {
16397
16429
  const el = typeof selector === "string" ? document.querySelector(selector) : selector;
16398
16430
  return el ? instances.get(el) || null : null;
16399
16431
  },
16432
+ /** Returns a shallow copy of the default options (read-only snapshot). */
16400
16433
  get defaults() {
16401
16434
  return { ...defaultOptions };
16402
16435
  },
16436
+ /** Merges properties into the global defaults, applied to all future instances. */
16403
16437
  setDefaults(overrides) {
16404
16438
  Object.assign(defaultOptions, overrides);
16405
16439
  },
16440
+ /** Restores global defaults to their original factory values. */
16406
16441
  resetDefaults() {
16407
16442
  Object.keys(defaultOptions).forEach((k) => delete defaultOptions[k]);
16408
16443
  Object.assign(defaultOptions, _originalDefaults);
16409
16444
  },
16445
+ /**
16446
+ * Registers a custom module to be included in every new editor instance.
16447
+ * @param {string} name - unique module key used for ctx.invoke() calls
16448
+ * @param {Function} ModuleClass - class with initialize() and optional destroy()
16449
+ */
16410
16450
  registerModule(name, ModuleClass) {
16411
16451
  _customModules.set(name, ModuleClass);
16412
16452
  },
16453
+ /**
16454
+ * Installs a plugin globally — applied to every future editor instance.
16455
+ * Plugin `buttons` are registered to the global button registry immediately
16456
+ * so they are available when Toolbar initialises inside create().
16457
+ * Plugin `install()` is called after all built-in modules have initialised.
16458
+ * @param {object} plugin - { name, version?, buttons?, install?, uninstall? }
16459
+ * @param {object} [options] - Forwarded to plugin.install(context, options)
16460
+ * @returns {typeof AutumnNote}
16461
+ */
16413
16462
  use(plugin, options = {}) {
16414
16463
  if (!plugin || typeof plugin.name !== "string") throw new TypeError("[AutumnNote] AutumnNote.use: plugin must have a string `name` property.");
16415
16464
  if (_globalPlugins.has(plugin.name)) {
@@ -16423,14 +16472,26 @@ var AutumnNote = {
16423
16472
  });
16424
16473
  return this;
16425
16474
  },
16475
+ /**
16476
+ * Returns true if a plugin with the given name has been registered globally.
16477
+ * @param {string} name
16478
+ * @returns {boolean}
16479
+ */
16426
16480
  hasPlugin(name) {
16427
16481
  return _globalPlugins.has(name);
16428
16482
  },
16483
+ /**
16484
+ * Registers a single button definition in the global button registry.
16485
+ * After create(), call ctx.invoke('toolbar.rebuild') to render new buttons.
16486
+ * @param {object} btnDef - ButtonDef-compatible object with a `name` string
16487
+ * @returns {typeof AutumnNote}
16488
+ */
16429
16489
  registerButton(btnDef) {
16430
16490
  registerButton(btnDef);
16431
16491
  return this;
16432
16492
  },
16433
- version: "1.4.2"
16493
+ /** Library version */
16494
+ version: "1.5.0"
16434
16495
  };
16435
16496
  /**
16436
16497
  * @param {string|Element|NodeList|Element[]} selector