overtype 2.3.9 → 2.4.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
@@ -1,6 +1,6 @@
1
1
  # OverType
2
2
 
3
- A lightweight markdown editor library with perfect WYSIWYG alignment using an invisible textarea overlay technique. Includes optional toolbar. ~110KB minified with all features.
3
+ A lightweight markdown editor library with perfect WYSIWYG alignment using an invisible textarea overlay technique. Includes optional toolbar. ~117KB minified with all features.
4
4
 
5
5
  ## Live Examples
6
6
 
@@ -19,7 +19,7 @@ A lightweight markdown editor library with perfect WYSIWYG alignment using an in
19
19
  - ⌨️ **Keyboard shortcuts** - Common markdown shortcuts (Cmd/Ctrl+B for bold, etc.)
20
20
  - 📱 **Mobile optimized** - Responsive design with mobile-specific styles
21
21
  - 🔄 **DOM persistence aware** - Recovers from existing DOM (perfect for HyperClay and similar platforms)
22
- - 🚀 **Lightweight** - ~110KB minified
22
+ - 🚀 **Lightweight** - ~117KB minified
23
23
  - 🎯 **Optional toolbar** - Clean, minimal toolbar with all essential formatting
24
24
  - ✨ **Smart shortcuts** - Keyboard shortcuts with selection preservation
25
25
  - 📝 **Smart list continuation** - GitHub-style automatic list continuation on Enter
@@ -35,7 +35,7 @@ We overlap an invisible textarea on top of styled output, giving the illusion of
35
35
 
36
36
  | Feature | OverType | HyperMD | Milkdown | TUI Editor | EasyMDE |
37
37
  |---------|----------|---------|----------|------------|---------|
38
- | **Size** | ~110KB | 364.02 KB | 344.51 KB | 560.99 KB | 323.69 KB |
38
+ | **Size** | ~117KB | 364.02 KB | 344.51 KB | 560.99 KB | 323.69 KB |
39
39
  | **Dependencies** | Bundled | CodeMirror | ProseMirror + plugins | Multiple libs | CodeMirror |
40
40
  | **Setup** | Single file | Complex config | Build step required | Complex config | Moderate |
41
41
  | **Approach** | Invisible textarea | ContentEditable | ContentEditable | ContentEditable | CodeMirror |
@@ -62,14 +62,42 @@ We overlap an invisible textarea on top of styled output, giving the illusion of
62
62
 
63
63
  ## Installation
64
64
 
65
- ### NPM
65
+ ### NPM (bundlers: Vite, webpack, Rollup, etc.)
66
66
  ```bash
67
67
  npm install overtype
68
68
  ```
69
69
 
70
- ### CDN
70
+ ```javascript
71
+ import OverType from 'overtype';
72
+
73
+ const [editor] = new OverType('#editor', { value: '# Hello' });
74
+ ```
75
+
76
+ OverType is ESM-first and also ships a CommonJS build, so both styles work:
77
+
78
+ ```javascript
79
+ // ESM — default or named import
80
+ import OverType from 'overtype';
81
+ import { OverType } from 'overtype';
82
+
83
+ // CommonJS
84
+ const { OverType } = require('overtype');
85
+ ```
86
+
87
+ ### CDN: native ES module (no build step)
88
+ ```html
89
+ <script type="module">
90
+ import OverType from 'https://cdn.jsdelivr.net/npm/overtype@latest/dist/overtype.esm.js';
91
+ const [editor] = new OverType('#editor', { value: '# Hello' });
92
+ </script>
93
+ ```
94
+
95
+ ### CDN: global script tag (IIFE)
71
96
  ```html
72
97
  <script src="https://cdn.jsdelivr.net/npm/overtype@latest/dist/overtype.min.js"></script>
98
+ <script>
99
+ const [editor] = new OverType('#editor', { value: '# Hello' });
100
+ </script>
73
101
  ```
74
102
 
75
103
  ## Quick Start
@@ -145,6 +173,38 @@ const [editor] = new OverType('#editor', {
145
173
  // orderedList, taskList, quote, separator, viewMode
146
174
  ```
147
175
 
176
+ Custom buttons that behave like toggle buttons can provide `isActive`. When it returns `true` or `false`, OverType updates the button’s `active` class and `aria-pressed` state:
177
+
178
+ ```javascript
179
+ {
180
+ name: 'customToggle',
181
+ icon: '<svg>...</svg>',
182
+ title: 'Custom Toggle',
183
+ isActive: ({ editor, activeFormats }) => activeFormats.includes('bold'),
184
+ action: ({ editor }) => {
185
+ // Toggle your custom formatting
186
+ }
187
+ }
188
+ ```
189
+
190
+ **Driving formatting from your own UI:**
191
+
192
+ OverType re-exports the bundled `markdown-actions` library so you can build a fully custom toolbar (or any UI) without installing or bundling `markdown-actions` separately:
193
+
194
+ ```javascript
195
+ import OverType, { markdownActions } from 'overtype';
196
+
197
+ const [editor] = new OverType('#editor');
198
+
199
+ // Apply formatting to the editor's textarea directly
200
+ document.querySelector('#bold-btn').addEventListener('click', () => {
201
+ markdownActions.toggleBold(editor.textarea);
202
+ editor.textarea.focus();
203
+ });
204
+ ```
205
+
206
+ Available actions include `toggleBold`, `toggleItalic`, `toggleCode`, `insertLink`, `toggleBulletList`, `toggleNumberedList`, `toggleQuote`, `toggleTaskList`, `insertHeader`, `toggleH1`/`H2`/`H3`, `getActiveFormats`, `hasFormat`, `expandSelection`, and `applyCustomFormat`. The same namespace is available as `window.markdownActions` and `OverType.markdownActions` in script-tag builds.
207
+
148
208
  See [examples/custom-toolbar.html](examples/custom-toolbar.html) for complete examples.
149
209
 
150
210
  ### View Modes
@@ -198,8 +258,12 @@ The toolbar and keyboard shortcuts work together seamlessly:
198
258
  - **Cmd/Ctrl + K** - Insert link
199
259
  - **Cmd/Ctrl + Shift + 7** - Numbered list
200
260
  - **Cmd/Ctrl + Shift + 8** - Bullet list
261
+ - **Cmd/Ctrl + ]** - Indent current line or selection
262
+ - **Cmd/Ctrl + [** - Outdent current line or selection
263
+ - **Tab / Shift+Tab** - Indent or outdent selected lines
201
264
 
202
- All shortcuts preserve text selection, allowing you to apply multiple formats quickly.
265
+ Collapsed **Tab** and **Shift+Tab** follow normal browser focus navigation so keyboard users can leave the editor.
266
+ Editing shortcuts preserve text selection, allowing you to apply multiple formats quickly.
203
267
 
204
268
  ### Multiple Editors
205
269
 
@@ -236,6 +300,38 @@ document.querySelector('form').addEventListener('submit', (e) => {
236
300
  });
237
301
  ```
238
302
 
303
+ ### File Uploads
304
+
305
+ OverType handles paste and drop of files when `fileUpload` is configured. You upload to your own backend in `onInsertFile` and return the markdown to insert. When that markdown link is later removed from the editor, `onRemoveFile` fires so you can clean up the backend file.
306
+
307
+ ```javascript
308
+ const [editor] = new OverType('#editor', {
309
+ fileUpload: {
310
+ enabled: true,
311
+ maxSize: 10 * 1024 * 1024, // 10MB
312
+ mimeTypes: ['image/png', 'image/jpeg'], // optional whitelist; empty = accept all
313
+ batch: false, // true = one onInsertFile call per drop
314
+
315
+ // Upload to your backend, return the markdown link to insert
316
+ onInsertFile: async (file) => {
317
+ const { url } = await uploadToBackend(file);
318
+ const isImage = file.type.startsWith('image/');
319
+ return isImage ? `![${file.name}](${url})` : `[${file.name}](${url})`;
320
+ },
321
+
322
+ // Optional: fires when an inserted link is removed from the editor.
323
+ // Useful for deleting orphaned files from storage.
324
+ onRemoveFile: ({ url, filename, file }) => {
325
+ fetch(`/api/files/${encodeURIComponent(url)}`, { method: 'DELETE' });
326
+ }
327
+ }
328
+ });
329
+ ```
330
+
331
+ `onRemoveFile` only fires for URLs that OverType originally inserted via `onInsertFile`. URL edits, manual paste of an existing link, or programmatic edits to non-tracked URLs do not trigger it.
332
+
333
+ See [examples/file-upload.html](website/examples/file-upload.html) for a complete working demo.
334
+
239
335
  ### Custom Theme
240
336
 
241
337
  ```javascript
@@ -468,6 +564,9 @@ new OverType(target, options)
468
564
  // Spellcheck
469
565
  spellcheck: false, // Enable browser spellcheck (disabled by default)
470
566
 
567
+ // Link tooltip
568
+ transformLinkUrl: (url) => url, // Rewrite the URL shown/opened in the link tooltip (per instance)
569
+
471
570
  // Stats bar
472
571
  showStats: false, // Enable/disable stats bar
473
572
  statsFormatter: (stats) => { // Custom stats format
@@ -476,7 +575,19 @@ new OverType(target, options)
476
575
 
477
576
  // Callbacks
478
577
  onChange: (value, instance) => {},
479
- onKeydown: (event, instance) => {}
578
+ onKeydown: (event, instance) => {},
579
+ onFocus: (event, instance) => {},
580
+ onBlur: (event, instance) => {},
581
+
582
+ // File upload (paste/drop) — see "File Uploads" section below
583
+ fileUpload: {
584
+ enabled: true,
585
+ maxSize: 10 * 1024 * 1024, // bytes (default 10MB)
586
+ mimeTypes: [], // empty = accept all
587
+ batch: false, // single onInsertFile call per drop
588
+ onInsertFile: async (file) => `[${file.name}](url)`, // required: return inserted markdown
589
+ onRemoveFile: ({ url, filename, file }) => {} // fires when an inserted link is removed
590
+ }
480
591
  }
481
592
  ```
482
593
 
@@ -554,10 +665,12 @@ OverType.init(target, options)
554
665
 
555
666
  // Initialize with per-element config via data-ot-* attributes
556
667
  // Uses kebab-case: data-ot-show-stats="true" → showStats: true
668
+ // Accepts a selector, Element, NodeList, or Array of elements
557
669
  OverType.initFromData('.editor', { /* defaults */ })
558
670
 
559
- // Get instance from element
560
- OverType.getInstance(element)
671
+ // Get instance from a selector, Element, NodeList, or Array
672
+ // Returns the instance for the first matching element
673
+ OverType.getInstance(target)
561
674
 
562
675
  // Destroy all instances
563
676
  OverType.destroyAll()
@@ -573,10 +686,14 @@ OverType.themes.cave
573
686
  |----------|--------|
574
687
  | Cmd/Ctrl + B | Toggle bold |
575
688
  | Cmd/Ctrl + I | Toggle italic |
576
- | Cmd/Ctrl + K | Wrap in code |
577
- | Cmd/Ctrl + Shift + K | Insert link |
689
+ | Cmd/Ctrl + K | Insert link |
578
690
  | Cmd/Ctrl + Shift + 7 | Toggle numbered list |
579
691
  | Cmd/Ctrl + Shift + 8 | Toggle bullet list |
692
+ | Cmd/Ctrl + ] | Indent current line or selection |
693
+ | Cmd/Ctrl + [ | Outdent current line or selection |
694
+ | Tab / Shift+Tab | Indent or outdent selected lines |
695
+
696
+ When no text is selected, Tab and Shift+Tab use normal browser focus navigation.
580
697
 
581
698
  ## Supported Markdown
582
699
 
@@ -697,6 +814,26 @@ Links are clickable with Cmd/Ctrl+Click only. Direct clicking would interfere wi
697
814
 
698
815
  These limitations are what enable OverType's core benefits: perfect native textarea behavior, tiny size, and zero complexity.
699
816
 
817
+ ## Transforming Link URLs
818
+
819
+ When your cursor is inside a `[text](url)`, OverType shows a tooltip to open the link. If you edit a document at a different path or domain than where it's published, relative URLs can point to the wrong place. Pass `transformLinkUrl` to rewrite the URL shown and opened by the tooltip, per instance. Your markdown text and the rendered preview are left untouched.
820
+
821
+ ```javascript
822
+ const urlPreviewRegExp = [[/^\//, '/preview/'], [/www\./, '']];
823
+
824
+ const [editor] = new OverType('#editor', {
825
+ transformLinkUrl: (url) => urlPreviewRegExp.reduce((value, re) => value.replace(...re), url)
826
+ });
827
+ ```
828
+
829
+ The transformed URL is passed through OverType's URL sanitizer before opening, so the tooltip can never open a dangerous scheme (`javascript:`, `data:`, and similar). If your function throws or returns a non-string, the original URL is used.
830
+
831
+ ## Recipes
832
+
833
+ OverType stays small by leaving optional features to the host app and exposing the public API needed to build them (`editor.textarea`, `onChange`, `getValue`/`setValue`).
834
+
835
+ - **[Autocomplete / mention popups](docs/AUTOCOMPLETE.md)** - GitHub-style `@mention` and `#issue` popups built entirely on the public API, no core changes.
836
+
700
837
  ## Development
701
838
 
702
839
  ```bash
@@ -761,9 +898,25 @@ Use `OverType.initFromData()` to configure multiple editors via HTML data attrib
761
898
 
762
899
  Uses kebab-case attributes that convert to camelCase options (e.g., `data-ot-show-stats` → `showStats`).
763
900
 
764
- **Supported:** `toolbar`, `theme`, `value`, `placeholder`, `autofocus`, `auto-resize`, `min-height`, `max-height`, `font-size`, `line-height`, `show-stats`, `smart-lists`, `show-active-line-raw`
901
+ ### Native textarea attributes (`required`, `name`, etc.)
902
+
903
+ Set `textareaProps` from HTML in two ways:
904
+
905
+ ```html
906
+ <!-- One attribute per prop: data-ot-textarea-<attr> -->
907
+ <div class="editor" data-ot-textarea-required data-ot-textarea-name="message"></div>
908
+
909
+ <!-- Or the whole object as JSON -->
910
+ <div class="editor" data-ot-textarea-props='{"required":true,"maxLength":500,"name":"message"}'></div>
911
+ ```
912
+
913
+ Both put a real `required`/`name`/etc. attribute on the underlying `<textarea>`, so the editor participates in native form validation. To make a field optional, omit the attribute (don't set `data-ot-textarea-required="false"`, which still marks it required, the same way the HTML `required` attribute works).
914
+
915
+ Any object-valued option can also be passed as JSON (values starting with `{` or `[` are parsed; malformed JSON falls back to the raw string).
916
+
917
+ **Supported:** `toolbar`, `theme`, `value`, `placeholder`, `autofocus`, `auto-resize`, `min-height`, `max-height`, `font-size`, `line-height`, `show-stats`, `smart-lists`, `show-active-line-raw`, `textarea-props` / `textarea-*`
765
918
 
766
- **Not supported (use JS):** `toolbarButtons`, `textareaProps`, `onChange`, `onKeydown`, `statsFormatter`, `codeHighlighter`, `colors`, `mobile`
919
+ **Not supported (use JS):** `toolbarButtons`, `onChange`, `onKeydown`, `onFocus`, `onBlur`, `statsFormatter`, `codeHighlighter`, `colors`, `mobile`
767
920
 
768
921
  ## Contributors
769
922
 
@@ -776,7 +929,7 @@ Special thanks to:
776
929
  - [Lyric Wai](https://github.com/lyricat) - Fixed double-escaping of links ([#64](https://github.com/panphora/overtype/pull/64)), shared code block alignment fix ([#65](https://github.com/panphora/overtype/issues/65))
777
930
  - [kozi](https://github.com/kozi) - Reported Firefox link tooltip bug ([#68](https://github.com/panphora/overtype/issues/68)), toolbar positioning ([#69](https://github.com/panphora/overtype/issues/69)), theme CSS variable issues ([#70](https://github.com/panphora/overtype/issues/70), [#71](https://github.com/panphora/overtype/issues/71))
778
931
  - [1951FDG](https://github.com/1951FDG) - Reported unordered list rendering bug ([#74](https://github.com/panphora/overtype/issues/74)), suggested showStats() API improvement ([#77](https://github.com/panphora/overtype/issues/77)), reported placeholder CSS regression ([#102](https://github.com/panphora/overtype/issues/102))
779
- - [nodesocket](https://github.com/nodesocket) - Reported toolbarButtons export issues ([#73](https://github.com/panphora/overtype/issues/73), [#78](https://github.com/panphora/overtype/issues/78)), suggested image toolbar button ([#89](https://github.com/panphora/overtype/issues/89)), reported custom theme stats bar styling ([#101](https://github.com/panphora/overtype/issues/101))
932
+ - [nodesocket](https://github.com/nodesocket) - Reported toolbarButtons export issues ([#73](https://github.com/panphora/overtype/issues/73), [#78](https://github.com/panphora/overtype/issues/78)), suggested image toolbar button ([#89](https://github.com/panphora/overtype/issues/89)), reported custom theme stats bar styling ([#101](https://github.com/panphora/overtype/issues/101)), suggested onRemoveFile callback ([#104](https://github.com/panphora/overtype/issues/104))
780
933
  - [Travis Bell](https://github.com/travisbell) - Reported keyboard shortcuts bug in ESM build ([#80](https://github.com/panphora/overtype/issues/80))
781
934
  - [fab2713](https://github.com/fab2713) - Reported italic rendering in lists ([#81](https://github.com/panphora/overtype/issues/81)), reinit maxHeight ([#82](https://github.com/panphora/overtype/issues/82)), placeholder visibility ([#83](https://github.com/panphora/overtype/issues/83)), suggested auto theme ([#84](https://github.com/panphora/overtype/issues/84)), relative URL prefix ([#85](https://github.com/panphora/overtype/issues/85)), minification improvements ([#94](https://github.com/panphora/overtype/issues/94))
782
935
  - [oooo-ps](https://github.com/oooo-ps) - Reported remote script loading issue ([#86](https://github.com/panphora/overtype/issues/86))
@@ -789,6 +942,9 @@ Special thanks to:
789
942
  - [phinnaeus](https://github.com/phinnaeus) - Diagnosed missing fontFamily wiring ([#110](https://github.com/panphora/overtype/issues/110))
790
943
  - [Tan Nhu](https://github.com/tnhu) - Fixed onChange feedback loop with async syntax highlighters ([#111](https://github.com/panphora/overtype/pull/111))
791
944
  - [pscanf](https://github.com/pscanf) - Re-exported markdown-actions for custom toolbar implementations ([#105](https://github.com/panphora/overtype/issues/105), [#106](https://github.com/panphora/overtype/pull/106))
945
+ - [riasvdv](https://github.com/riasvdv) - Contributed keyboard focus-trap fix ([#115](https://github.com/panphora/overtype/pull/115)) and toolbar accessibility following the W3C APG Toolbar pattern ([#114](https://github.com/panphora/overtype/pull/114))
946
+ - [gcamacho079](https://github.com/gcamacho079) - Reported the markdown editor keyboard focus trap ([#113](https://github.com/panphora/overtype/issues/113))
947
+ - [Matt Round](https://mattround.com/) - Reported the Safari stale-glyph caret/wrap desync and supplied the original workaround ([#116](https://github.com/panphora/overtype/issues/116))
792
948
 
793
949
  ### TypeScript & Framework Support
794
950
  - [merlinz01](https://github.com/merlinz01) - Contributed TypeScript declaration file ([#20](https://github.com/panphora/overtype/pull/20))
@@ -800,7 +956,7 @@ Special thanks to:
800
956
  - [Yukai Huang](https://github.com/Yukaii) - Contributed syntax highlighting implementation ([#35](https://github.com/panphora/overtype/pull/35))
801
957
  - [Rognoni](https://github.com/rognoni) - Suggested custom toolbar button API ([#61](https://github.com/panphora/overtype/issues/61))
802
958
  - [Deyan Gigov](https://github.com/dido739) - Reported checkbox rendering bug in preview mode ([#60](https://github.com/panphora/overtype/issues/60)), contributed auto theme implementation ([#100](https://github.com/panphora/overtype/pull/100))
803
- - [GregJohnStewart](https://github.com/GregJohnStewart) - Suggested data attribute configuration ([#76](https://github.com/panphora/overtype/issues/76)), reported initFromData array nesting bug ([#93](https://github.com/panphora/overtype/issues/93)), suggested DOM element init ([#92](https://github.com/panphora/overtype/issues/92))
959
+ - [GregJohnStewart](https://github.com/GregJohnStewart) - Suggested data attribute configuration ([#76](https://github.com/panphora/overtype/issues/76)), reported initFromData array nesting bug ([#93](https://github.com/panphora/overtype/issues/93)), suggested DOM element init ([#92](https://github.com/panphora/overtype/issues/92)), suggested supporting more options via data attributes ([#112](https://github.com/panphora/overtype/issues/112))
804
960
  - [boris-glumpler](https://github.com/boris-glumpler) - Suggested custom syntax highlighting API ([#79](https://github.com/panphora/overtype/issues/79))
805
961
  - [sorokya](https://github.com/sorokya) - Contributed file upload support ([#87](https://github.com/panphora/overtype/pull/87))
806
962
  - [aaronmyatt](https://github.com/aaronmyatt) - Contributed show/hide toolbar methods ([#95](https://github.com/panphora/overtype/pull/95))