overtype 1.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/LICENSE +21 -0
- package/README.md +441 -0
- package/dist/overtype.esm.js +2576 -0
- package/dist/overtype.esm.js.map +7 -0
- package/dist/overtype.js +2599 -0
- package/dist/overtype.js.map +7 -0
- package/dist/overtype.min.js +546 -0
- package/package.json +50 -0
- package/src/icons.js +77 -0
- package/src/index.js +4 -0
- package/src/overtype.js +781 -0
- package/src/parser.js +222 -0
- package/src/shortcuts.js +125 -0
- package/src/styles.js +486 -0
- package/src/themes.js +124 -0
- package/src/toolbar.js +221 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Demo User
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
# OverType
|
|
2
|
+
|
|
3
|
+
A lightweight markdown editor library with perfect WYSIWYG alignment using an invisible textarea overlay technique. Includes optional toolbar. ~45KB minified with all features.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 👻 **Invisible textarea overlay** - Transparent input layer overlaid on styled preview for seamless editing
|
|
8
|
+
- 🎨 **Global theming** - Solar (light) and Cave (dark) themes that apply to all instances
|
|
9
|
+
- ⌨️ **Keyboard shortcuts** - Common markdown shortcuts (Cmd/Ctrl+B for bold, etc.)
|
|
10
|
+
- 📱 **Mobile optimized** - Responsive design with mobile-specific styles
|
|
11
|
+
- 🔄 **DOM persistence aware** - Recovers from existing DOM (perfect for HyperClay and similar platforms)
|
|
12
|
+
- 🚀 **Lightweight** - ~45KB minified
|
|
13
|
+
- 🎯 **Optional toolbar** - Clean, minimal toolbar with all essential formatting
|
|
14
|
+
- ✨ **Smart shortcuts** - Keyboard shortcuts with selection preservation
|
|
15
|
+
- 🔧 **Framework agnostic** - Works with React, Vue, vanilla JS, and more
|
|
16
|
+
|
|
17
|
+
## How it works
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
We overlap an invisible textarea on top of styled output, giving the illusion of editing styled text using a plain textarea.
|
|
22
|
+
|
|
23
|
+
## Comparisons
|
|
24
|
+
|
|
25
|
+
| Feature | OverType | HyperMD | Milkdown | TUI Editor | EasyMDE |
|
|
26
|
+
|---------|----------|---------|----------|------------|---------|
|
|
27
|
+
| **Size** | ~45KB | 364.02 KB | 344.51 KB | 560.99 KB | 323.69 KB |
|
|
28
|
+
| **Dependencies** | Bundled | CodeMirror | ProseMirror + plugins | Multiple libs | CodeMirror |
|
|
29
|
+
| **Setup** | Single file | Complex config | Build step required | Complex config | Moderate |
|
|
30
|
+
| **Approach** | Invisible textarea | ContentEditable | ContentEditable | ContentEditable | CodeMirror |
|
|
31
|
+
| **Mobile** | Perfect native | Issues common | Issues common | Issues common | Limited |
|
|
32
|
+
| **Markdown syntax** | Visible | Hidden | Hidden | Toggle | Visible |
|
|
33
|
+
| **Advanced features** | Basic | Full | Full | Full | Moderate |
|
|
34
|
+
| **Best for** | Simple, fast, mobile | Full WYSIWYG | Modern frameworks | Enterprise apps | Classic editing |
|
|
35
|
+
|
|
36
|
+
**Choose OverType when you need:**
|
|
37
|
+
- Tiny bundle size (10x smaller than alternatives)
|
|
38
|
+
- Zero dependencies - single file that works immediately
|
|
39
|
+
- Perfect native browser features (undo/redo, mobile keyboards, spellcheck)
|
|
40
|
+
- Dead-simple integration without build tools
|
|
41
|
+
- Easy to understand, modify, and extend
|
|
42
|
+
- Excellent mobile support with visible markdown syntax
|
|
43
|
+
|
|
44
|
+
**Choose other editors when you need:**
|
|
45
|
+
- Full WYSIWYG with hidden markdown syntax
|
|
46
|
+
- Advanced features like tables, diagrams, or collaborative editing
|
|
47
|
+
- Rich plugin ecosystems
|
|
48
|
+
- Enterprise features and extensive customization
|
|
49
|
+
- Framework-specific integration (React, Vue, etc.)
|
|
50
|
+
- Complex multi-layered architecture for deep customization
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
### NPM
|
|
55
|
+
```
|
|
56
|
+
npm install overtype
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### CDN
|
|
60
|
+
```
|
|
61
|
+
<script src="https://unpkg.com/overtype/dist/overtype.min.js"></script>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Quick Start
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
// Create a single editor
|
|
68
|
+
const [editor] = new OverType('#editor', {
|
|
69
|
+
value: '# Hello World',
|
|
70
|
+
theme: 'solar'
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Get/set content
|
|
74
|
+
editor.getValue();
|
|
75
|
+
editor.setValue('# New Content');
|
|
76
|
+
|
|
77
|
+
// Change theme
|
|
78
|
+
editor.setTheme('cave');
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
### Basic Editor
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
<div id="editor" style="height: 400px;"></div>
|
|
87
|
+
|
|
88
|
+
<script>
|
|
89
|
+
const [editor] = new OverType('#editor', {
|
|
90
|
+
placeholder: 'Start typing markdown...',
|
|
91
|
+
value: '# Welcome\n\nStart writing **markdown** here!',
|
|
92
|
+
onChange: (value, instance) => {
|
|
93
|
+
console.log('Content changed:', value);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
</script>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Toolbar
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
// Enable the toolbar
|
|
103
|
+
const [editor] = new OverType('#editor', {
|
|
104
|
+
toolbar: true, // Enables the toolbar
|
|
105
|
+
value: '# Document\n\nSelect text and use the toolbar buttons!'
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Toolbar provides:
|
|
109
|
+
// - Bold, Italic formatting
|
|
110
|
+
// - Heading levels (H1, H2, H3)
|
|
111
|
+
// - Links, inline code, code blocks
|
|
112
|
+
// - Bullet and numbered lists
|
|
113
|
+
// - All with keyboard shortcuts!
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Keyboard Shortcuts
|
|
117
|
+
|
|
118
|
+
The toolbar and keyboard shortcuts work together seamlessly:
|
|
119
|
+
|
|
120
|
+
- **Cmd/Ctrl + B** - Bold
|
|
121
|
+
- **Cmd/Ctrl + I** - Italic
|
|
122
|
+
- **Cmd/Ctrl + K** - Insert link
|
|
123
|
+
- **Cmd/Ctrl + Shift + 7** - Numbered list
|
|
124
|
+
- **Cmd/Ctrl + Shift + 8** - Bullet list
|
|
125
|
+
|
|
126
|
+
All shortcuts preserve text selection, allowing you to apply multiple formats quickly.
|
|
127
|
+
|
|
128
|
+
### Multiple Editors
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
// Initialize multiple editors at once
|
|
132
|
+
const editors = OverType.init('.markdown-editor', {
|
|
133
|
+
theme: 'cave',
|
|
134
|
+
fontSize: '16px'
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Each editor is independent
|
|
138
|
+
editors.forEach((editor, index) => {
|
|
139
|
+
editor.setValue(`# Editor ${index + 1}`);
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Custom Theme
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
const [editor] = new OverType('#editor', {
|
|
147
|
+
theme: {
|
|
148
|
+
name: 'my-theme',
|
|
149
|
+
colors: {
|
|
150
|
+
bgPrimary: '#faf0ca',
|
|
151
|
+
bgSecondary: '#ffffff',
|
|
152
|
+
text: '#0d3b66',
|
|
153
|
+
h1: '#f95738',
|
|
154
|
+
h2: '#ee964b',
|
|
155
|
+
h3: '#3d8a51',
|
|
156
|
+
strong: '#ee964b',
|
|
157
|
+
em: '#f95738',
|
|
158
|
+
link: '#0d3b66',
|
|
159
|
+
code: '#0d3b66',
|
|
160
|
+
codeBg: 'rgba(244, 211, 94, 0.2)',
|
|
161
|
+
blockquote: '#5a7a9b',
|
|
162
|
+
hr: '#5a7a9b',
|
|
163
|
+
syntaxMarker: 'rgba(13, 59, 102, 0.52)',
|
|
164
|
+
cursor: '#f95738',
|
|
165
|
+
selection: 'rgba(244, 211, 94, 0.4)'
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Stats Bar
|
|
172
|
+
|
|
173
|
+
Enable a built-in stats bar that shows character, word, and line counts:
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
// Enable stats bar on initialization
|
|
177
|
+
const [editor] = new OverType('#editor', {
|
|
178
|
+
showStats: true
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Show or hide stats bar dynamically
|
|
182
|
+
editor.showStats(true); // Show
|
|
183
|
+
editor.showStats(false); // Hide
|
|
184
|
+
|
|
185
|
+
// Custom stats format
|
|
186
|
+
const [editor] = new OverType('#editor', {
|
|
187
|
+
showStats: true,
|
|
188
|
+
statsFormatter: (stats) => {
|
|
189
|
+
// stats object contains: { chars, words, lines, line, column }
|
|
190
|
+
return `<span>${stats.chars} characters</span>
|
|
191
|
+
<span>${stats.words} words</span>
|
|
192
|
+
<span>${stats.lines} lines</span>
|
|
193
|
+
<span>Line ${stats.line}, Col ${stats.column}</span>`;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The stats bar automatically adapts to your theme colors using CSS variables.
|
|
199
|
+
|
|
200
|
+
### React Component
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
function MarkdownEditor({ value, onChange }) {
|
|
204
|
+
const ref = useRef();
|
|
205
|
+
const editorRef = useRef();
|
|
206
|
+
|
|
207
|
+
useEffect(() => {
|
|
208
|
+
const [instance] = OverType.init(ref.current, {
|
|
209
|
+
value,
|
|
210
|
+
onChange
|
|
211
|
+
});
|
|
212
|
+
editorRef.current = instance;
|
|
213
|
+
|
|
214
|
+
return () => editorRef.current?.destroy();
|
|
215
|
+
}, []);
|
|
216
|
+
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
if (editorRef.current && value !== editorRef.current.getValue()) {
|
|
219
|
+
editorRef.current.setValue(value);
|
|
220
|
+
}
|
|
221
|
+
}, [value]);
|
|
222
|
+
|
|
223
|
+
return <div ref={ref} style={{ height: '400px' }} />;
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## API
|
|
228
|
+
|
|
229
|
+
### Constructor
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
new OverType(target, options)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
**Parameters:**
|
|
236
|
+
- `target` - Selector string, Element, NodeList, or Array of elements
|
|
237
|
+
- `options` - Configuration object (see below)
|
|
238
|
+
|
|
239
|
+
**Returns:** Array of OverType instances (always an array, even for single element)
|
|
240
|
+
|
|
241
|
+
### Options
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
{
|
|
245
|
+
// Typography
|
|
246
|
+
fontSize: '14px',
|
|
247
|
+
lineHeight: 1.6,
|
|
248
|
+
fontFamily: 'monospace',
|
|
249
|
+
padding: '16px',
|
|
250
|
+
|
|
251
|
+
// Theme - 'solar', 'cave', or custom theme object
|
|
252
|
+
theme: 'solar',
|
|
253
|
+
|
|
254
|
+
// Custom colors (override theme colors)
|
|
255
|
+
colors: {
|
|
256
|
+
h1: '#e63946',
|
|
257
|
+
h2: '#457b9d',
|
|
258
|
+
// ... any color variable
|
|
259
|
+
},
|
|
260
|
+
|
|
261
|
+
// Mobile styles (applied at <= 640px)
|
|
262
|
+
mobile: {
|
|
263
|
+
fontSize: '16px',
|
|
264
|
+
padding: '12px',
|
|
265
|
+
lineHeight: 1.5
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
// Behavior
|
|
269
|
+
autofocus: false,
|
|
270
|
+
placeholder: 'Start typing...',
|
|
271
|
+
value: '',
|
|
272
|
+
|
|
273
|
+
// Stats bar
|
|
274
|
+
showStats: false, // Enable/disable stats bar
|
|
275
|
+
statsFormatter: (stats) => { // Custom stats format
|
|
276
|
+
return `${stats.chars} chars | ${stats.words} words`;
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
// Callbacks
|
|
280
|
+
onChange: (value, instance) => {},
|
|
281
|
+
onKeydown: (event, instance) => {}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Instance Methods
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
// Get current markdown content
|
|
289
|
+
editor.getValue()
|
|
290
|
+
|
|
291
|
+
// Set markdown content
|
|
292
|
+
editor.setValue(markdown)
|
|
293
|
+
|
|
294
|
+
// Change theme
|
|
295
|
+
editor.setTheme('cave') // Built-in theme name
|
|
296
|
+
editor.setTheme(customThemeObject) // Custom theme
|
|
297
|
+
|
|
298
|
+
// Focus/blur
|
|
299
|
+
editor.focus()
|
|
300
|
+
editor.blur()
|
|
301
|
+
|
|
302
|
+
// Show or hide stats bar
|
|
303
|
+
editor.showStats(true) // Show stats
|
|
304
|
+
editor.showStats(false) // Hide stats
|
|
305
|
+
|
|
306
|
+
// Check if initialized
|
|
307
|
+
editor.isInitialized()
|
|
308
|
+
|
|
309
|
+
// Re-initialize with new options
|
|
310
|
+
editor.reinit(options)
|
|
311
|
+
|
|
312
|
+
// Destroy the editor
|
|
313
|
+
editor.destroy()
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### Static Methods
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
// Set global theme (affects all instances)
|
|
320
|
+
OverType.setTheme('cave') // Built-in theme
|
|
321
|
+
OverType.setTheme(customTheme) // Custom theme object
|
|
322
|
+
OverType.setTheme('solar', { h1: '#custom' }) // Override specific colors
|
|
323
|
+
|
|
324
|
+
// Initialize multiple editors (same as constructor)
|
|
325
|
+
OverType.init(target, options)
|
|
326
|
+
|
|
327
|
+
// Get instance from element
|
|
328
|
+
OverType.getInstance(element)
|
|
329
|
+
|
|
330
|
+
// Destroy all instances
|
|
331
|
+
OverType.destroyAll()
|
|
332
|
+
|
|
333
|
+
// Access themes
|
|
334
|
+
OverType.themes.solar
|
|
335
|
+
OverType.themes.cave
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Keyboard Shortcuts
|
|
339
|
+
|
|
340
|
+
| Shortcut | Action |
|
|
341
|
+
|----------|--------|
|
|
342
|
+
| Cmd/Ctrl + B | Toggle bold |
|
|
343
|
+
| Cmd/Ctrl + I | Toggle italic |
|
|
344
|
+
| Cmd/Ctrl + K | Wrap in code |
|
|
345
|
+
| Cmd/Ctrl + Shift + K | Insert link |
|
|
346
|
+
| Cmd/Ctrl + Shift + 7 | Toggle numbered list |
|
|
347
|
+
| Cmd/Ctrl + Shift + 8 | Toggle bullet list |
|
|
348
|
+
|
|
349
|
+
## Supported Markdown
|
|
350
|
+
|
|
351
|
+
- **Headers** - `# H1`, `## H2`, `### H3`
|
|
352
|
+
- **Bold** - `**text**` or `__text__`
|
|
353
|
+
- **Italic** - `*text*` or `_text_`
|
|
354
|
+
- **Code** - `` `inline code` ``
|
|
355
|
+
- **Links** - `[text](url)`
|
|
356
|
+
- **Lists** - `- item`, `* item`, `1. item`
|
|
357
|
+
- **Blockquotes** - `> quote`
|
|
358
|
+
- **Horizontal rule** - `---`, `***`, or `___`
|
|
359
|
+
|
|
360
|
+
Note: Markdown syntax remains visible but styled (e.g., `**bold**` shows with styled markers).
|
|
361
|
+
|
|
362
|
+
## DOM Persistence & Re-initialization
|
|
363
|
+
|
|
364
|
+
OverType is designed to work with platforms that persist DOM across page loads (like HyperClay):
|
|
365
|
+
|
|
366
|
+
```
|
|
367
|
+
// Safe to call multiple times - will recover existing editors
|
|
368
|
+
OverType.init('.editor');
|
|
369
|
+
|
|
370
|
+
// The library will:
|
|
371
|
+
// 1. Check for existing OverType DOM structure
|
|
372
|
+
// 2. Recover content from existing textarea if found
|
|
373
|
+
// 3. Re-establish event bindings
|
|
374
|
+
// 4. Or create fresh editor if no existing DOM
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Examples
|
|
378
|
+
|
|
379
|
+
Check the `examples` folder for complete examples:
|
|
380
|
+
|
|
381
|
+
- `basic.html` - Simple single editor
|
|
382
|
+
- `multiple.html` - Multiple independent editors
|
|
383
|
+
- `custom-theme.html` - Theme customization
|
|
384
|
+
- `dynamic.html` - Dynamic creation/destruction
|
|
385
|
+
|
|
386
|
+
## Development
|
|
387
|
+
|
|
388
|
+
```
|
|
389
|
+
# Install dependencies
|
|
390
|
+
npm install
|
|
391
|
+
|
|
392
|
+
# Development build with watch
|
|
393
|
+
npm run dev
|
|
394
|
+
|
|
395
|
+
# Production build
|
|
396
|
+
npm run build
|
|
397
|
+
|
|
398
|
+
# Run tests
|
|
399
|
+
npm test
|
|
400
|
+
|
|
401
|
+
# Check bundle size
|
|
402
|
+
npm run size
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Browser Support
|
|
406
|
+
|
|
407
|
+
- Chrome 62+
|
|
408
|
+
- Firefox 78+
|
|
409
|
+
- Safari 16+
|
|
410
|
+
- Edge (Chromium)
|
|
411
|
+
|
|
412
|
+
Requires support for:
|
|
413
|
+
- CSS Custom Properties
|
|
414
|
+
- ES6 features
|
|
415
|
+
- Lookbehind assertions in RegExp (for italic parsing)
|
|
416
|
+
|
|
417
|
+
## Architecture
|
|
418
|
+
|
|
419
|
+
OverType uses a unique invisible textarea overlay approach:
|
|
420
|
+
|
|
421
|
+
1. **Two perfectly aligned layers:**
|
|
422
|
+
- Invisible textarea (top) - handles input and cursor
|
|
423
|
+
- Styled preview div (bottom) - shows formatted markdown
|
|
424
|
+
|
|
425
|
+
2. **Character-perfect alignment:**
|
|
426
|
+
- Monospace font required
|
|
427
|
+
- No size changes in styling
|
|
428
|
+
- Syntax markers remain visible
|
|
429
|
+
|
|
430
|
+
3. **Single source of truth:**
|
|
431
|
+
- Textarea content drives everything
|
|
432
|
+
- One-way data flow: textarea → parser → preview
|
|
433
|
+
|
|
434
|
+
## License
|
|
435
|
+
|
|
436
|
+
MIT
|
|
437
|
+
|
|
438
|
+
## Contributing
|
|
439
|
+
|
|
440
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
441
|
+
|