overtype 2.0.5 → 2.1.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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * OverType v2.0.5
2
+ * OverType v2.0.6
3
3
  * A lightweight markdown editor library with perfect WYSIWYG alignment
4
4
  * @license MIT
5
5
  * @author David Miranda
@@ -50,6 +50,24 @@ var OverTypeEditor = (() => {
50
50
  static setCodeHighlighter(highlighter) {
51
51
  this.codeHighlighter = highlighter;
52
52
  }
53
+ /**
54
+ * Set custom syntax processor function
55
+ * @param {Function|null} processor - Function that takes (html) and returns modified HTML
56
+ */
57
+ static setCustomSyntax(processor) {
58
+ this.customSyntax = processor;
59
+ }
60
+ /**
61
+ * Apply custom syntax processor to parsed HTML
62
+ * @param {string} html - Parsed HTML line
63
+ * @returns {string} HTML with custom syntax applied
64
+ */
65
+ static applyCustomSyntax(html) {
66
+ if (this.customSyntax) {
67
+ return this.customSyntax(html);
68
+ }
69
+ return html;
70
+ }
53
71
  /**
54
72
  * Escape HTML special characters
55
73
  * @param {string} text - Raw text to escape
@@ -114,7 +132,7 @@ var OverTypeEditor = (() => {
114
132
  * @returns {string} Parsed bullet list item
115
133
  */
116
134
  static parseBulletList(html) {
117
- return html.replace(/^((?: )*)([-*])\s(.+)$/, (match, indent, marker, content) => {
135
+ return html.replace(/^((?: )*)([-*+])\s(.+)$/, (match, indent, marker, content) => {
118
136
  return `${indent}<li class="bullet-list"><span class="syntax-marker">${marker} </span>${content}</li>`;
119
137
  });
120
138
  }
@@ -173,7 +191,7 @@ var OverTypeEditor = (() => {
173
191
  * @returns {string} HTML with italic styling
174
192
  */
175
193
  static parseItalic(html) {
176
- html = html.replace(new RegExp("(?<!\\*)\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)", "g"), '<em><span class="syntax-marker">*</span>$1<span class="syntax-marker">*</span></em>');
194
+ html = html.replace(new RegExp("(?<![\\*>])\\*(?!\\*)(.+?)(?<!\\*)\\*(?!\\*)", "g"), '<em><span class="syntax-marker">*</span>$1<span class="syntax-marker">*</span></em>');
177
195
  html = html.replace(new RegExp("(?<=^|\\s)_(?!_)(.+?)(?<!_)_(?!_)(?=\\s|$)", "g"), '<em><span class="syntax-marker">_</span>$1<span class="syntax-marker">_</span></em>');
178
196
  return html;
179
197
  }
@@ -388,14 +406,14 @@ var OverTypeEditor = (() => {
388
406
  const codeFenceRegex = /^```[^`]*$/;
389
407
  if (codeFenceRegex.test(line)) {
390
408
  inCodeBlock = !inCodeBlock;
391
- return this.parseLine(line, isPreviewMode);
409
+ return this.applyCustomSyntax(this.parseLine(line, isPreviewMode));
392
410
  }
393
411
  if (inCodeBlock) {
394
412
  const escaped = this.escapeHtml(line);
395
413
  const indented = this.preserveIndentation(escaped, line);
396
414
  return `<div>${indented || "&nbsp;"}</div>`;
397
415
  }
398
- return this.parseLine(line, isPreviewMode);
416
+ return this.applyCustomSyntax(this.parseLine(line, isPreviewMode));
399
417
  });
400
418
  const html = parsedLines.join("");
401
419
  return this.postProcessHTML(html, instanceHighlighter);
@@ -727,6 +745,8 @@ var OverTypeEditor = (() => {
727
745
  __publicField(MarkdownParser, "linkIndex", 0);
728
746
  // Global code highlighter function
729
747
  __publicField(MarkdownParser, "codeHighlighter", null);
748
+ // Custom syntax processor function
749
+ __publicField(MarkdownParser, "customSyntax", null);
730
750
  /**
731
751
  * List pattern definitions
732
752
  */
@@ -2785,6 +2805,28 @@ ${blockSuffix}` : suffix;
2785
2805
  button.addEventListener("click", button._clickHandler);
2786
2806
  return button;
2787
2807
  }
2808
+ /**
2809
+ * Handle button action programmatically (used by keyboard shortcuts)
2810
+ * @param {Object} buttonConfig - Button configuration object with action function
2811
+ */
2812
+ async handleAction(buttonConfig) {
2813
+ this.editor.textarea.focus();
2814
+ try {
2815
+ if (buttonConfig.action) {
2816
+ await buttonConfig.action({
2817
+ editor: this.editor,
2818
+ getValue: () => this.editor.getValue(),
2819
+ setValue: (value) => this.editor.setValue(value),
2820
+ event: null
2821
+ });
2822
+ }
2823
+ } catch (error) {
2824
+ console.error(`Action "${buttonConfig.name}" error:`, error);
2825
+ this.editor.wrapper.dispatchEvent(new CustomEvent("button-error", {
2826
+ detail: { buttonName: buttonConfig.name, error }
2827
+ }));
2828
+ }
2829
+ }
2788
2830
  /**
2789
2831
  * Sanitize SVG to prevent XSS
2790
2832
  */
@@ -3723,10 +3765,13 @@ ${blockSuffix}` : suffix;
3723
3765
  */
3724
3766
  handleKeydown(event) {
3725
3767
  if (event.key === "Tab") {
3726
- event.preventDefault();
3727
3768
  const start = this.textarea.selectionStart;
3728
3769
  const end = this.textarea.selectionEnd;
3729
3770
  const value = this.textarea.value;
3771
+ if (event.shiftKey && start === end) {
3772
+ return;
3773
+ }
3774
+ event.preventDefault();
3730
3775
  if (start !== end && event.shiftKey) {
3731
3776
  const before = value.substring(0, start);
3732
3777
  const selection = value.substring(start, end);
@@ -4082,6 +4127,8 @@ ${blockSuffix}` : suffix;
4082
4127
  this.statsBar.className = "overtype-stats";
4083
4128
  this.container.appendChild(this.statsBar);
4084
4129
  this._updateStats();
4130
+ } else if (show && this.statsBar) {
4131
+ this._updateStats();
4085
4132
  } else if (!show && this.statsBar) {
4086
4133
  this.statsBar.remove();
4087
4134
  this.statsBar = null;
@@ -4150,6 +4197,44 @@ ${blockSuffix}` : suffix;
4150
4197
  static init(target, options = {}) {
4151
4198
  return new _OverType(target, options);
4152
4199
  }
4200
+ /**
4201
+ * Initialize editors with options from data-ot-* attributes
4202
+ * @param {string} selector - CSS selector for target elements
4203
+ * @param {Object} defaults - Default options (data attrs override these)
4204
+ * @returns {Array<OverType>} Array of OverType instances
4205
+ * @example
4206
+ * // HTML: <div class="editor" data-ot-toolbar="true" data-ot-theme="cave"></div>
4207
+ * OverType.initFromData('.editor', { fontSize: '14px' });
4208
+ */
4209
+ static initFromData(selector, defaults = {}) {
4210
+ const elements = document.querySelectorAll(selector);
4211
+ return Array.from(elements).map((el) => {
4212
+ const options = { ...defaults };
4213
+ for (const attr of el.attributes) {
4214
+ if (attr.name.startsWith("data-ot-")) {
4215
+ const kebab = attr.name.slice(8);
4216
+ const key = kebab.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
4217
+ options[key] = _OverType._parseDataValue(attr.value);
4218
+ }
4219
+ }
4220
+ return new _OverType(el, options);
4221
+ });
4222
+ }
4223
+ /**
4224
+ * Parse a data attribute value to the appropriate type
4225
+ * @private
4226
+ */
4227
+ static _parseDataValue(value) {
4228
+ if (value === "true")
4229
+ return true;
4230
+ if (value === "false")
4231
+ return false;
4232
+ if (value === "null")
4233
+ return null;
4234
+ if (value !== "" && !isNaN(Number(value)))
4235
+ return Number(value);
4236
+ return value;
4237
+ }
4153
4238
  /**
4154
4239
  * Get instance from element
4155
4240
  * @param {Element} element - DOM element
@@ -4250,6 +4335,32 @@ ${blockSuffix}` : suffix;
4250
4335
  }
4251
4336
  });
4252
4337
  }
4338
+ /**
4339
+ * Set custom syntax processor for extending markdown parsing
4340
+ * @param {Function|null} processor - Function that takes (html) and returns modified HTML
4341
+ * @example
4342
+ * OverType.setCustomSyntax((html) => {
4343
+ * // Highlight footnote references [^1]
4344
+ * return html.replace(/\[\^(\w+)\]/g, '<span class="footnote-ref">$&</span>');
4345
+ * });
4346
+ */
4347
+ static setCustomSyntax(processor) {
4348
+ MarkdownParser.setCustomSyntax(processor);
4349
+ document.querySelectorAll(".overtype-wrapper").forEach((wrapper) => {
4350
+ const instance = wrapper._instance;
4351
+ if (instance && instance.updatePreview) {
4352
+ instance.updatePreview();
4353
+ }
4354
+ });
4355
+ document.querySelectorAll("overtype-editor").forEach((webComponent) => {
4356
+ if (typeof webComponent.getEditor === "function") {
4357
+ const instance = webComponent.getEditor();
4358
+ if (instance && instance.updatePreview) {
4359
+ instance.updatePreview();
4360
+ }
4361
+ }
4362
+ });
4363
+ }
4253
4364
  /**
4254
4365
  * Initialize global event listeners
4255
4366
  */