overtype 1.2.3 → 1.2.4

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.
@@ -0,0 +1,169 @@
1
+ // Type definitions for OverType
2
+ // Project: https://github.com/panphora/overtype
3
+ // Definitions generated from JSDoc comments and implementation
4
+
5
+ export interface Theme {
6
+ name: string;
7
+ colors: {
8
+ bgPrimary?: string;
9
+ bgSecondary?: string;
10
+ text?: string;
11
+ textSecondary?: string;
12
+ h1?: string;
13
+ h2?: string;
14
+ h3?: string;
15
+ strong?: string;
16
+ em?: string;
17
+ link?: string;
18
+ code?: string;
19
+ codeBg?: string;
20
+ blockquote?: string;
21
+ hr?: string;
22
+ syntaxMarker?: string;
23
+ listMarker?: string;
24
+ cursor?: string;
25
+ selection?: string;
26
+ rawLine?: string;
27
+ // Toolbar theme colors
28
+ toolbarBg?: string;
29
+ toolbarIcon?: string;
30
+ toolbarHover?: string;
31
+ toolbarActive?: string;
32
+ border?: string;
33
+ };
34
+ }
35
+
36
+ export interface Stats {
37
+ words: number;
38
+ chars: number;
39
+ lines: number;
40
+ line: number;
41
+ column: number;
42
+ }
43
+
44
+ export interface MobileOptions {
45
+ fontSize?: string;
46
+ padding?: string;
47
+ lineHeight?: string | number;
48
+ }
49
+
50
+ export interface Options {
51
+ // Typography
52
+ fontSize?: string;
53
+ lineHeight?: string | number;
54
+ fontFamily?: string;
55
+ padding?: string;
56
+
57
+ // Mobile responsive
58
+ mobile?: MobileOptions;
59
+
60
+ // Native textarea attributes (v1.1.2+)
61
+ textareaProps?: Record<string, any>;
62
+
63
+ // Behavior
64
+ autofocus?: boolean;
65
+ autoResize?: boolean; // v1.1.2+ Auto-expand height with content
66
+ minHeight?: string; // v1.1.2+ Minimum height for autoResize mode
67
+ maxHeight?: string | null; // v1.1.2+ Maximum height for autoResize mode
68
+ placeholder?: string;
69
+ value?: string;
70
+
71
+ // Features
72
+ showActiveLineRaw?: boolean;
73
+ showStats?: boolean;
74
+ toolbar?: boolean | {
75
+ buttons?: Array<{
76
+ name?: string;
77
+ icon?: string;
78
+ title?: string;
79
+ action?: string;
80
+ separator?: boolean;
81
+ }>;
82
+ };
83
+ smartLists?: boolean; // v1.2.3+ Smart list continuation
84
+ statsFormatter?: (stats: Stats) => string;
85
+
86
+ // Theme (deprecated in favor of global theme)
87
+ theme?: string | Theme;
88
+ colors?: Partial<Theme['colors']>;
89
+
90
+ // Callbacks
91
+ onChange?: (value: string, instance: OverTypeInstance) => void;
92
+ onKeydown?: (event: KeyboardEvent, instance: OverTypeInstance) => void;
93
+ }
94
+
95
+ // Interface for constructor that returns array
96
+ export interface OverTypeConstructor {
97
+ new(target: string | Element | NodeList | Element[], options?: Options): OverTypeInstance[];
98
+ // Static members
99
+ instances: WeakMap<Element, OverTypeInstance>;
100
+ stylesInjected: boolean;
101
+ globalListenersInitialized: boolean;
102
+ instanceCount: number;
103
+ currentTheme: Theme;
104
+ themes: {
105
+ solar: Theme;
106
+ cave: Theme;
107
+ };
108
+ MarkdownParser: any;
109
+ ShortcutsManager: any;
110
+ init(target: string | Element | NodeList | Element[], options?: Options): OverTypeInstance[];
111
+ getInstance(element: Element): OverTypeInstance | null;
112
+ destroyAll(): void;
113
+ injectStyles(force?: boolean): void;
114
+ setTheme(theme: string | Theme, customColors?: Partial<Theme['colors']>): void;
115
+ initGlobalListeners(): void;
116
+ getTheme(name: string): Theme;
117
+ }
118
+
119
+ export interface RenderOptions {
120
+ cleanHTML?: boolean;
121
+ }
122
+
123
+ export interface OverTypeInstance {
124
+ // Public properties
125
+ container: HTMLElement;
126
+ wrapper: HTMLElement;
127
+ textarea: HTMLTextAreaElement;
128
+ preview: HTMLElement;
129
+ statsBar?: HTMLElement;
130
+ toolbar?: any; // Toolbar instance
131
+ shortcuts?: any; // ShortcutsManager instance
132
+ linkTooltip?: any; // LinkTooltip instance
133
+ options: Options;
134
+ initialized: boolean;
135
+ instanceId: number;
136
+ element: Element;
137
+
138
+ // Public methods
139
+ getValue(): string;
140
+ setValue(value: string): void;
141
+ getStats(): Stats;
142
+ getContainer(): HTMLElement;
143
+ focus(): void;
144
+ blur(): void;
145
+ destroy(): void;
146
+ isInitialized(): boolean;
147
+ reinit(options: Options): void;
148
+ showStats(show: boolean): void;
149
+ setTheme(theme: string | Theme): void;
150
+ updatePreview(): void;
151
+
152
+ // HTML output methods
153
+ getRenderedHTML(options?: RenderOptions): string;
154
+ getCleanHTML(): string;
155
+ getPreviewHTML(): string;
156
+
157
+ // View mode methods
158
+ showPlainTextarea(show: boolean): void;
159
+ showPreviewMode(show: boolean): void;
160
+ }
161
+
162
+ // Declare the constructor as a constant with proper typing
163
+ declare const OverType: OverTypeConstructor;
164
+
165
+ // Export the instance type under a different name for clarity
166
+ export type OverType = OverTypeInstance;
167
+
168
+ // Module exports - default export is the constructor
169
+ export default OverType;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * OverType v1.2.2
2
+ * OverType v1.2.4
3
3
  * A lightweight markdown editor library with perfect WYSIWYG alignment
4
4
  * @license MIT
5
5
  * @author Demo User
@@ -131,6 +131,17 @@ var MarkdownParser = class {
131
131
  html = html.replace(new RegExp("(?<!_)_(?!_)(.+?)(?<!_)_(?!_)", "g"), '<em><span class="syntax-marker">_</span>$1<span class="syntax-marker">_</span></em>');
132
132
  return html;
133
133
  }
134
+ /**
135
+ * Parse strikethrough text
136
+ * Supports both single (~) and double (~~) tildes, but rejects 3+ tildes
137
+ * @param {string} html - HTML with potential strikethrough markdown
138
+ * @returns {string} HTML with strikethrough styling
139
+ */
140
+ static parseStrikethrough(html) {
141
+ html = html.replace(new RegExp("(?<!~)~~(?!~)(.+?)(?<!~)~~(?!~)", "g"), '<del><span class="syntax-marker">~~</span>$1<span class="syntax-marker">~~</span></del>');
142
+ html = html.replace(new RegExp("(?<!~)~(?!~)(.+?)(?<!~)~(?!~)", "g"), '<del><span class="syntax-marker">~</span>$1<span class="syntax-marker">~</span></del>');
143
+ return html;
144
+ }
134
145
  /**
135
146
  * Parse inline code
136
147
  * @param {string} html - HTML with potential code markdown
@@ -193,6 +204,7 @@ var MarkdownParser = class {
193
204
  sanctuaries.set(placeholder, match);
194
205
  return placeholder;
195
206
  });
207
+ html = this.parseStrikethrough(html);
196
208
  html = this.parseBold(html);
197
209
  html = this.parseItalic(html);
198
210
  sanctuaries.forEach((content, placeholder) => {
@@ -327,6 +339,17 @@ var MarkdownParser = class {
327
339
  container.insertBefore(currentList, child);
328
340
  listType = newType;
329
341
  }
342
+ const indentationNodes = [];
343
+ for (const node of child.childNodes) {
344
+ if (node.nodeType === 3 && node.textContent.match(/^\u00A0+$/)) {
345
+ indentationNodes.push(node.cloneNode(true));
346
+ } else if (node === listItem) {
347
+ break;
348
+ }
349
+ }
350
+ indentationNodes.forEach((node) => {
351
+ listItem.insertBefore(node, listItem.firstChild);
352
+ });
330
353
  currentList.appendChild(listItem);
331
354
  child.remove();
332
355
  } else {
@@ -344,15 +367,35 @@ var MarkdownParser = class {
344
367
  static postProcessHTMLManual(html) {
345
368
  let processed = html;
346
369
  processed = processed.replace(/((?:<div>(?:&nbsp;)*<li class="bullet-list">.*?<\/li><\/div>\s*)+)/gs, (match) => {
347
- const items = match.match(/<li class="bullet-list">.*?<\/li>/gs) || [];
348
- if (items.length > 0) {
370
+ const divs = match.match(/<div>(?:&nbsp;)*<li class="bullet-list">.*?<\/li><\/div>/gs) || [];
371
+ if (divs.length > 0) {
372
+ const items = divs.map((div) => {
373
+ const indentMatch = div.match(/<div>((?:&nbsp;)*)<li/);
374
+ const listItemMatch = div.match(/<li class="bullet-list">.*?<\/li>/);
375
+ if (indentMatch && listItemMatch) {
376
+ const indentation = indentMatch[1];
377
+ const listItem = listItemMatch[0];
378
+ return listItem.replace(/<li class="bullet-list">/, `<li class="bullet-list">${indentation}`);
379
+ }
380
+ return listItemMatch ? listItemMatch[0] : "";
381
+ }).filter(Boolean);
349
382
  return "<ul>" + items.join("") + "</ul>";
350
383
  }
351
384
  return match;
352
385
  });
353
386
  processed = processed.replace(/((?:<div>(?:&nbsp;)*<li class="ordered-list">.*?<\/li><\/div>\s*)+)/gs, (match) => {
354
- const items = match.match(/<li class="ordered-list">.*?<\/li>/gs) || [];
355
- if (items.length > 0) {
387
+ const divs = match.match(/<div>(?:&nbsp;)*<li class="ordered-list">.*?<\/li><\/div>/gs) || [];
388
+ if (divs.length > 0) {
389
+ const items = divs.map((div) => {
390
+ const indentMatch = div.match(/<div>((?:&nbsp;)*)<li/);
391
+ const listItemMatch = div.match(/<li class="ordered-list">.*?<\/li>/);
392
+ if (indentMatch && listItemMatch) {
393
+ const indentation = indentMatch[1];
394
+ const listItem = listItemMatch[0];
395
+ return listItem.replace(/<li class="ordered-list">/, `<li class="ordered-list">${indentation}`);
396
+ }
397
+ return listItemMatch ? listItemMatch[0] : "";
398
+ }).filter(Boolean);
356
399
  return "<ol>" + items.join("") + "</ol>";
357
400
  }
358
401
  return match;
@@ -1894,6 +1937,14 @@ function generateStyles(options = {}) {
1894
1937
  font-style: italic !important;
1895
1938
  }
1896
1939
 
1940
+ /* Strikethrough text */
1941
+ .overtype-wrapper .overtype-preview del {
1942
+ color: var(--del, #ee964b) !important;
1943
+ text-decoration: line-through !important;
1944
+ text-decoration-color: var(--del, #ee964b) !important;
1945
+ text-decoration-thickness: 1px !important;
1946
+ }
1947
+
1897
1948
  /* Inline code */
1898
1949
  .overtype-wrapper .overtype-preview code {
1899
1950
  background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
@@ -2037,10 +2088,10 @@ function generateStyles(options = {}) {
2037
2088
  height: 8px !important;
2038
2089
  background: #4caf50 !important;
2039
2090
  border-radius: 50% !important;
2040
- animation: pulse 2s infinite !important;
2091
+ animation: overtype-pulse 2s infinite !important;
2041
2092
  }
2042
2093
 
2043
- @keyframes pulse {
2094
+ @keyframes overtype-pulse {
2044
2095
  0%, 100% { opacity: 1; transform: scale(1); }
2045
2096
  50% { opacity: 0.6; transform: scale(1.2); }
2046
2097
  }
@@ -2048,19 +2099,19 @@ function generateStyles(options = {}) {
2048
2099
 
2049
2100
  /* Toolbar Styles */
2050
2101
  .overtype-toolbar {
2051
- display: flex;
2052
- align-items: center;
2053
- gap: 4px;
2102
+ display: flex !important;
2103
+ align-items: center !important;
2104
+ gap: 4px !important;
2054
2105
  padding: 8px !important; /* Override reset */
2055
2106
  background: var(--toolbar-bg, var(--bg-primary, #f8f9fa)) !important; /* Override reset */
2056
2107
  overflow-x: auto !important; /* Allow horizontal scrolling */
2057
2108
  overflow-y: hidden !important; /* Hide vertical overflow */
2058
- -webkit-overflow-scrolling: touch;
2059
- flex-shrink: 0;
2109
+ -webkit-overflow-scrolling: touch !important;
2110
+ flex-shrink: 0 !important;
2060
2111
  height: auto !important;
2061
2112
  grid-row: 1 !important; /* Always first row in grid */
2062
2113
  position: relative !important; /* Override reset */
2063
- z-index: 100; /* Ensure toolbar is above wrapper */
2114
+ z-index: 100 !important; /* Ensure toolbar is above wrapper */
2064
2115
  scrollbar-width: thin; /* Thin scrollbar on Firefox */
2065
2116
  }
2066
2117
 
@@ -2442,20 +2493,67 @@ var eyeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke
2442
2493
 
2443
2494
  // src/toolbar.js
2444
2495
  var Toolbar = class {
2445
- constructor(editor) {
2496
+ constructor(editor, buttonConfig = null) {
2446
2497
  this.editor = editor;
2447
2498
  this.container = null;
2448
2499
  this.buttons = {};
2500
+ this.buttonConfig = buttonConfig;
2501
+ }
2502
+ /**
2503
+ * Check if cursor/selection is inside a markdown link
2504
+ * @param {HTMLTextAreaElement} textarea - The textarea element
2505
+ * @returns {boolean} True if inside a link
2506
+ */
2507
+ isInsideLink(textarea) {
2508
+ const value = textarea.value;
2509
+ const start = textarea.selectionStart;
2510
+ const end = textarea.selectionEnd;
2511
+ let insideLink = false;
2512
+ let openBracket = -1;
2513
+ let closeBracket = -1;
2514
+ for (let i = start - 1; i >= 0; i--) {
2515
+ if (value[i] === "[") {
2516
+ openBracket = i;
2517
+ break;
2518
+ }
2519
+ if (value[i] === "\n") {
2520
+ break;
2521
+ }
2522
+ }
2523
+ if (openBracket >= 0) {
2524
+ for (let i = end; i < value.length - 1; i++) {
2525
+ if (value[i] === "]" && value[i + 1] === "(") {
2526
+ closeBracket = i;
2527
+ break;
2528
+ }
2529
+ if (value[i] === "\n") {
2530
+ break;
2531
+ }
2532
+ }
2533
+ }
2534
+ if (openBracket >= 0 && closeBracket >= 0) {
2535
+ for (let i = closeBracket + 2; i < value.length; i++) {
2536
+ if (value[i] === ")") {
2537
+ insideLink = true;
2538
+ break;
2539
+ }
2540
+ if (value[i] === "\n" || value[i] === " ") {
2541
+ break;
2542
+ }
2543
+ }
2544
+ }
2545
+ return insideLink;
2449
2546
  }
2450
2547
  /**
2451
2548
  * Create and attach toolbar to editor
2452
2549
  */
2453
2550
  create() {
2551
+ var _a;
2454
2552
  this.container = document.createElement("div");
2455
2553
  this.container.className = "overtype-toolbar";
2456
2554
  this.container.setAttribute("role", "toolbar");
2457
2555
  this.container.setAttribute("aria-label", "Text formatting");
2458
- const buttonConfig = [
2556
+ const buttonConfig = (_a = this.buttonConfig) != null ? _a : [
2459
2557
  { name: "bold", icon: boldIcon, title: "Bold (Ctrl+B)", action: "toggleBold" },
2460
2558
  { name: "italic", icon: italicIcon, title: "Italic (Ctrl+I)", action: "toggleItalic" },
2461
2559
  { separator: true },
@@ -2549,6 +2647,9 @@ var Toolbar = class {
2549
2647
  insertLink(textarea);
2550
2648
  break;
2551
2649
  case "toggleCode":
2650
+ if (this.isInsideLink(textarea)) {
2651
+ return;
2652
+ }
2552
2653
  toggleCode(textarea);
2553
2654
  break;
2554
2655
  case "toggleBulletList":
@@ -2764,29 +2865,29 @@ var LinkTooltip = class {
2764
2865
  position: absolute;
2765
2866
  position-anchor: var(--target-anchor, --link-0);
2766
2867
  position-area: block-end center;
2767
- margin-top: 8px;
2868
+ margin-top: 8px !important;
2768
2869
 
2769
- background: #333;
2770
- color: white;
2771
- padding: 6px 10px;
2772
- border-radius: 16px;
2773
- font-size: 12px;
2774
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
2775
- display: none;
2776
- z-index: 10000;
2777
- cursor: pointer;
2778
- box-shadow: 0 2px 8px rgba(0,0,0,0.3);
2779
- max-width: 300px;
2780
- white-space: nowrap;
2781
- overflow: hidden;
2782
- text-overflow: ellipsis;
2870
+ background: #333 !important;
2871
+ color: white !important;
2872
+ padding: 6px 10px !important;
2873
+ border-radius: 16px !important;
2874
+ font-size: 12px !important;
2875
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
2876
+ display: none !important;
2877
+ z-index: 10000 !important;
2878
+ cursor: pointer !important;
2879
+ box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
2880
+ max-width: 300px !important;
2881
+ white-space: nowrap !important;
2882
+ overflow: hidden !important;
2883
+ text-overflow: ellipsis !important;
2783
2884
 
2784
2885
  position-try: most-width block-end inline-end, flip-inline, block-start center;
2785
2886
  position-visibility: anchors-visible;
2786
2887
  }
2787
2888
 
2788
2889
  .overtype-link-tooltip.visible {
2789
- display: flex;
2890
+ display: flex !important;
2790
2891
  }
2791
2892
  }
2792
2893
  `;
@@ -2934,7 +3035,8 @@ var _OverType = class _OverType {
2934
3035
  this.shortcuts = new ShortcutsManager(this);
2935
3036
  this.linkTooltip = new LinkTooltip(this);
2936
3037
  if (this.options.toolbar) {
2937
- this.toolbar = new Toolbar(this);
3038
+ const toolbarButtons = typeof this.options.toolbar === "object" ? this.options.toolbar.buttons : null;
3039
+ this.toolbar = new Toolbar(this, toolbarButtons);
2938
3040
  this.toolbar.create();
2939
3041
  this.textarea.addEventListener("selectionchange", () => {
2940
3042
  this.toolbar.updateButtonStates();
@@ -3416,24 +3518,36 @@ var _OverType = class _OverType {
3416
3518
  }
3417
3519
  /**
3418
3520
  * Get the rendered HTML of the current content
3419
- * @param {boolean} processForPreview - If true, post-processes HTML for preview mode (consolidates lists/code blocks)
3521
+ * @param {Object} options - Rendering options
3522
+ * @param {boolean} options.cleanHTML - If true, removes syntax markers and OverType-specific classes
3420
3523
  * @returns {string} Rendered HTML
3421
3524
  */
3422
- getRenderedHTML(processForPreview = false) {
3525
+ getRenderedHTML(options = {}) {
3423
3526
  const markdown = this.getValue();
3424
3527
  let html = MarkdownParser.parse(markdown);
3425
- if (processForPreview) {
3426
- html = MarkdownParser.postProcessHTML(html);
3528
+ if (options.cleanHTML) {
3529
+ html = html.replace(/<span class="syntax-marker[^"]*">.*?<\/span>/g, "");
3530
+ html = html.replace(/\sclass="(bullet-list|ordered-list|code-fence|hr-marker|blockquote|url-part)"/g, "");
3531
+ html = html.replace(/\sclass=""/g, "");
3427
3532
  }
3428
3533
  return html;
3429
3534
  }
3430
3535
  /**
3431
3536
  * Get the current preview element's HTML
3537
+ * This includes all syntax markers and OverType styling
3432
3538
  * @returns {string} Current preview HTML (as displayed)
3433
3539
  */
3434
3540
  getPreviewHTML() {
3435
3541
  return this.preview.innerHTML;
3436
3542
  }
3543
+ /**
3544
+ * Get clean HTML without any OverType-specific markup
3545
+ * Useful for exporting to other formats or storage
3546
+ * @returns {string} Clean HTML suitable for export
3547
+ */
3548
+ getCleanHTML() {
3549
+ return this.getRenderedHTML({ cleanHTML: true });
3550
+ }
3437
3551
  /**
3438
3552
  * Focus the editor
3439
3553
  */
@@ -3752,9 +3866,6 @@ OverType.ShortcutsManager = ShortcutsManager;
3752
3866
  OverType.themes = { solar, cave: getTheme("cave") };
3753
3867
  OverType.getTheme = getTheme;
3754
3868
  OverType.currentTheme = solar;
3755
- if (typeof window !== "undefined" && typeof window.document !== "undefined") {
3756
- window.OverType = OverType;
3757
- }
3758
3869
  var overtype_default = OverType;
3759
3870
  export {
3760
3871
  OverType,