@37signals/lexxy 0.9.28 → 0.9.29
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/dist/lexxy.esm.js +151 -33
- package/package.json +1 -1
package/dist/lexxy.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { highlightCode, highlightElement } from './lexxy_helpers.esm.js';
|
|
2
2
|
import DOMPurify from 'dompurify';
|
|
3
3
|
import { getStyleObjectFromCSS, getCSSFromStyleObject, $getSelectionStyleValueForProperty, $ensureForwardRangeSelection, $isAtNodeEnd, $patchStyleText, $setBlocksType, $forEachSelectedTextNode } from '@lexical/selection';
|
|
4
|
-
import { SKIP_DOM_SELECTION_TAG, CAN_UNDO_COMMAND, COMMAND_PRIORITY_LOW, CAN_REDO_COMMAND, $getSelection, $isRangeSelection, DecoratorNode, $createTextNode, defineExtension, $getRoot, $caretFromPoint, $setSelectionFromCaretRange, $getCaretRange, $normalizeCaret, $getChildCaret, $getCaretInDirection, $isParagraphNode, $isLineBreakNode, $createParagraphNode, $isElementNode, $isRootOrShadowRoot, $isRootNode, $createNodeSelection, $isDecoratorNode, $isTextNode, $getSiblingCaret, $rewindSiblingCaret, $splitAtPointCaretNext, $normalizeSelection__EXPERIMENTAL, $isChildCaret, $isTextPointCaret, $isExtendableTextPointCaret, $isSiblingCaret, $getCommonAncestor, $findMatchingParent, TextNode, createCommand, COMMAND_PRIORITY_EDITOR, $getEditor, $getNodeByKey, HISTORY_MERGE_TAG, SKIP_SCROLL_INTO_VIEW_TAG, $cloneWithProperties, $getNearestRootOrShadowRoot, $createRangeSelection, $setSelection, createState, COMMAND_PRIORITY_NORMAL, $getState, $setState, $hasUpdateTag, PASTE_TAG, FORMAT_TEXT_COMMAND, UNDO_COMMAND, REDO_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_TAB_COMMAND, INSERT_LINE_BREAK_COMMAND, COMMAND_PRIORITY_HIGH, INSERT_PARAGRAPH_COMMAND, OUTDENT_CONTENT_COMMAND, INDENT_CONTENT_COMMAND, $isNodeSelection, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ARROW_DOWN_COMMAND, DELETE_CHARACTER_COMMAND, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_CRITICAL, $addUpdateTag, CLICK_COMMAND, isDOMNode, $getNearestNodeFromDOMNode, ElementNode, $splitNode, $getChildCaretAtIndex, $createLineBreakNode, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, PASTE_COMMAND, $onUpdate, ParagraphNode, RootNode, DRAGSTART_COMMAND, DROP_COMMAND, mergeRegister as mergeRegister$1, $createRangeSelectionFromDom, CLEAR_HISTORY_COMMAND, KEY_ENTER_COMMAND,
|
|
4
|
+
import { SKIP_DOM_SELECTION_TAG, CAN_UNDO_COMMAND, COMMAND_PRIORITY_LOW, CAN_REDO_COMMAND, $getSelection, $isRangeSelection, DecoratorNode, $createTextNode, defineExtension, $getRoot, $caretFromPoint, $setSelectionFromCaretRange, $getCaretRange, $normalizeCaret, $getChildCaret, $getCaretInDirection, $isParagraphNode, $isLineBreakNode, $createParagraphNode, $isElementNode, $isRootOrShadowRoot, $isRootNode, $createNodeSelection, $isDecoratorNode, $isTextNode, $getSiblingCaret, $rewindSiblingCaret, $splitAtPointCaretNext, $normalizeSelection__EXPERIMENTAL, $isChildCaret, $isTextPointCaret, $isExtendableTextPointCaret, $isSiblingCaret, $getCommonAncestor, $findMatchingParent, TextNode, createCommand, COMMAND_PRIORITY_EDITOR, $getEditor, $getNodeByKey, HISTORY_MERGE_TAG, SKIP_SCROLL_INTO_VIEW_TAG, $cloneWithProperties, $getNearestRootOrShadowRoot, $createRangeSelection, $setSelection, createState, COMMAND_PRIORITY_NORMAL, $getState, $setState, $hasUpdateTag, PASTE_TAG, FORMAT_TEXT_COMMAND, UNDO_COMMAND, REDO_COMMAND, KEY_ARROW_RIGHT_COMMAND, KEY_TAB_COMMAND, INSERT_LINE_BREAK_COMMAND, COMMAND_PRIORITY_HIGH, INSERT_PARAGRAPH_COMMAND, OUTDENT_CONTENT_COMMAND, INDENT_CONTENT_COMMAND, $isNodeSelection, KEY_ARROW_LEFT_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ARROW_DOWN_COMMAND, DELETE_CHARACTER_COMMAND, SELECTION_CHANGE_COMMAND, COMMAND_PRIORITY_CRITICAL, $addUpdateTag, CLICK_COMMAND, isDOMNode, $getNearestNodeFromDOMNode, ElementNode, $splitNode, $getChildCaretAtIndex, $createLineBreakNode, SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, PASTE_COMMAND, $onUpdate, ParagraphNode, RootNode, DRAGSTART_COMMAND, DROP_COMMAND, mergeRegister as mergeRegister$1, $createRangeSelectionFromDom, CLEAR_HISTORY_COMMAND, KEY_ENTER_COMMAND, KEY_SPACE_COMMAND, INPUT_COMMAND, KEY_BACKSPACE_COMMAND, KEY_DOWN_COMMAND } from 'lexical';
|
|
5
5
|
import * as lexical from 'lexical';
|
|
6
6
|
export { lexical as Lexical };
|
|
7
7
|
import { LinkNode, $createAutoLinkNode, $toggleLink, $createLinkNode, $isLinkNode, AutoLinkNode } from '@lexical/link';
|
|
@@ -1527,7 +1527,7 @@ class CustomActionTextAttachmentNode extends DecoratorNode {
|
|
|
1527
1527
|
return Lexxy.global.get("attachmentTagName")
|
|
1528
1528
|
}
|
|
1529
1529
|
|
|
1530
|
-
constructor({ tagName, sgid, contentType, innerHtml, plainText }, key) {
|
|
1530
|
+
constructor({ tagName, sgid, contentType, innerHtml, plainText } = {}, key) {
|
|
1531
1531
|
super(key);
|
|
1532
1532
|
|
|
1533
1533
|
const contentTypeNamespace = Lexxy.global.get("attachmentContentTypeNamespace");
|
|
@@ -2328,7 +2328,7 @@ class ActionTextAttachmentNode extends DecoratorNode {
|
|
|
2328
2328
|
return Lexxy.global.get("attachmentTagName")
|
|
2329
2329
|
}
|
|
2330
2330
|
|
|
2331
|
-
constructor({ tagName, sgid, src, previewSrc, previewable, previewStatusUrl, pendingPreview, altText, caption, contentType, fileName, fileSize, width, height, uploadError }, key) {
|
|
2331
|
+
constructor({ tagName, sgid, src, previewSrc, previewable, previewStatusUrl, pendingPreview, altText, caption, contentType, fileName, fileSize, width, height, uploadError } = {}, key) {
|
|
2332
2332
|
super(key);
|
|
2333
2333
|
|
|
2334
2334
|
this.tagName = tagName || ActionTextAttachmentNode.TAG_NAME;
|
|
@@ -5472,7 +5472,7 @@ class ActionTextAttachmentUploadNode extends ActionTextAttachmentNode {
|
|
|
5472
5472
|
return null
|
|
5473
5473
|
}
|
|
5474
5474
|
|
|
5475
|
-
constructor(node, key) {
|
|
5475
|
+
constructor(node = {}, key) {
|
|
5476
5476
|
const { file, uploadUrl, blobUrlTemplate, progress, width, height, uploadError, fileName, contentType } = node;
|
|
5477
5477
|
super({ ...node, contentType: file?.type ?? contentType }, key);
|
|
5478
5478
|
this.file = file ?? null;
|
|
@@ -5493,9 +5493,10 @@ class ActionTextAttachmentUploadNode extends ActionTextAttachmentNode {
|
|
|
5493
5493
|
// node is reloaded from saved state such as from history.
|
|
5494
5494
|
this.#startUploadIfNeeded();
|
|
5495
5495
|
|
|
5496
|
-
// Bridge-managed uploads (uploadUrl is null)
|
|
5497
|
-
//
|
|
5498
|
-
|
|
5496
|
+
// Bridge-managed uploads (uploadUrl is null) and restored or remote
|
|
5497
|
+
// instances (no local File) don't have file data to show an image
|
|
5498
|
+
// preview, so always show the file icon during upload.
|
|
5499
|
+
const canPreviewFile = this.isPreviewableAttachment && this.uploadUrl != null && this.file != null;
|
|
5499
5500
|
const figure = this.createAttachmentFigure(canPreviewFile);
|
|
5500
5501
|
|
|
5501
5502
|
if (canPreviewFile) {
|
|
@@ -5566,9 +5567,12 @@ class ActionTextAttachmentUploadNode extends ActionTextAttachmentNode {
|
|
|
5566
5567
|
const figcaption = createElement("figcaption", { className: "attachment__caption" });
|
|
5567
5568
|
|
|
5568
5569
|
const nameSpan = createElement("span", { className: "attachment__name", textContent: this.caption || this.fileName || "" });
|
|
5569
|
-
const sizeSpan = createElement("span", { className: "attachment__size", textContent: bytesToHumanSize(this.file?.size) });
|
|
5570
5570
|
figcaption.appendChild(nameSpan);
|
|
5571
|
-
|
|
5571
|
+
|
|
5572
|
+
if (this.file) {
|
|
5573
|
+
const sizeSpan = createElement("span", { className: "attachment__size", textContent: bytesToHumanSize(this.file.size) });
|
|
5574
|
+
figcaption.appendChild(sizeSpan);
|
|
5575
|
+
}
|
|
5572
5576
|
|
|
5573
5577
|
return figcaption
|
|
5574
5578
|
}
|
|
@@ -5590,6 +5594,7 @@ class ActionTextAttachmentUploadNode extends ActionTextAttachmentNode {
|
|
|
5590
5594
|
async #startUploadIfNeeded() {
|
|
5591
5595
|
if (this.#uploadStarted) return
|
|
5592
5596
|
if (!this.uploadUrl) return // Bridge-managed upload — skip DirectUpload
|
|
5597
|
+
if (!this.file) return // Restored or remote instance — no local File to upload
|
|
5593
5598
|
|
|
5594
5599
|
this.#setUploadStarted();
|
|
5595
5600
|
|
|
@@ -6081,12 +6086,24 @@ class OfficeFormatter {
|
|
|
6081
6086
|
}
|
|
6082
6087
|
}
|
|
6083
6088
|
|
|
6089
|
+
// Properties worth rescuing from a foreign style sheet before #stripStyleElements
|
|
6090
|
+
// drops it, keyed by the elements that carry them. Word and Outlook declare
|
|
6091
|
+
// paragraph spacing in the sheet (p.MsoNormal { margin: 0cm }) and never inline,
|
|
6092
|
+
// so once the sheet goes there is nothing left to say how tightly the author's
|
|
6093
|
+
// paragraphs sat, and hosts that turn pasted paragraph margins into explicit
|
|
6094
|
+
// blank lines read tight Office paragraphs as spaced ones and multiply every
|
|
6095
|
+
// line break.
|
|
6096
|
+
const PRESERVABLE_STYLES = {
|
|
6097
|
+
p: [ "margin-top", "margin-bottom" ]
|
|
6098
|
+
};
|
|
6099
|
+
|
|
6084
6100
|
class PastedContentFormatter {
|
|
6085
6101
|
constructor(doc) {
|
|
6086
6102
|
this.doc = doc;
|
|
6087
6103
|
}
|
|
6088
6104
|
|
|
6089
6105
|
format() {
|
|
6106
|
+
this.#inlinePreservableStyles();
|
|
6090
6107
|
this.#stripStyleElements();
|
|
6091
6108
|
this.#unwrapPlaceholderAnchors();
|
|
6092
6109
|
this.#stripTableCellColorStyles();
|
|
@@ -6094,9 +6111,23 @@ class PastedContentFormatter {
|
|
|
6094
6111
|
this.#unwrapWrappedListChildren();
|
|
6095
6112
|
this.#nestStrayListChildren();
|
|
6096
6113
|
this.#stripStrayListChildren();
|
|
6114
|
+
this.#replaceGmailEmojiImgTags();
|
|
6097
6115
|
return this.doc
|
|
6098
6116
|
}
|
|
6099
6117
|
|
|
6118
|
+
// Runs before #stripStyleElements, to inline anything we still need
|
|
6119
|
+
// from an external style before we remove it
|
|
6120
|
+
#inlinePreservableStyles() {
|
|
6121
|
+
const rules = this.#styleRules();
|
|
6122
|
+
if (rules.length === 0) return
|
|
6123
|
+
|
|
6124
|
+
for (const [ selector, properties ] of Object.entries(PRESERVABLE_STYLES)) {
|
|
6125
|
+
for (const element of this.doc.querySelectorAll(selector)) {
|
|
6126
|
+
this.#inlineDeclaredStyles(element, properties, rules);
|
|
6127
|
+
}
|
|
6128
|
+
}
|
|
6129
|
+
}
|
|
6130
|
+
|
|
6100
6131
|
// Spreadsheets (e.g. Excel) copy a <style> block whose rules (td { color:
|
|
6101
6132
|
// black }, .xlNN { ... }) cascade onto the imported text. That color rides
|
|
6102
6133
|
// in through the cascade rather than an inline style, so it slips past both
|
|
@@ -6191,6 +6222,72 @@ class PastedContentFormatter {
|
|
|
6191
6222
|
}
|
|
6192
6223
|
}
|
|
6193
6224
|
|
|
6225
|
+
// Read the rules from a sheet we build rather than from this.doc.styleSheets: the
|
|
6226
|
+
// document came from DOMParser, so it has no browsing context, and WebKit leaves
|
|
6227
|
+
// its styleSheets empty. Parsing the text ourselves still expands the shorthands
|
|
6228
|
+
// Word writes (margin: 0cm) into the longhands we ask for.
|
|
6229
|
+
#styleRules() {
|
|
6230
|
+
const css = Array.from(this.doc.querySelectorAll("style"), (style) => style.textContent).join("\n");
|
|
6231
|
+
if (css.trim() === "") return []
|
|
6232
|
+
|
|
6233
|
+
const sheet = new CSSStyleSheet();
|
|
6234
|
+
sheet.replaceSync(css);
|
|
6235
|
+
|
|
6236
|
+
const rules = [];
|
|
6237
|
+
for (const rule of sheet.cssRules) {
|
|
6238
|
+
if (rule instanceof CSSStyleRule) {
|
|
6239
|
+
rules.push(rule);
|
|
6240
|
+
}
|
|
6241
|
+
}
|
|
6242
|
+
return rules
|
|
6243
|
+
}
|
|
6244
|
+
|
|
6245
|
+
// A declaration the element already carries inline is the author's own and wins.
|
|
6246
|
+
#inlineDeclaredStyles(element, properties, rules) {
|
|
6247
|
+
for (const property of properties) {
|
|
6248
|
+
if (element.style.getPropertyValue(property) === "") {
|
|
6249
|
+
const value = this.#declaredValue(rules, element, property);
|
|
6250
|
+
if (value) {
|
|
6251
|
+
this.#appendStyleProperty(element, property, value);
|
|
6252
|
+
}
|
|
6253
|
+
}
|
|
6254
|
+
}
|
|
6255
|
+
}
|
|
6256
|
+
|
|
6257
|
+
// Source order alone doesn't decide the cascade, so when the matching rules
|
|
6258
|
+
// disagree we can't say which value wins without resolving specificity. Skip
|
|
6259
|
+
// the property rather than guess: guessing is permanent, since the sheet is
|
|
6260
|
+
// about to go, and skipping only leaves the host on its own default.
|
|
6261
|
+
#declaredValue(rules, element, property) {
|
|
6262
|
+
const declared = new Set();
|
|
6263
|
+
for (const rule of rules) {
|
|
6264
|
+
const value = rule.style.getPropertyValue(property);
|
|
6265
|
+
if (value !== "" && element.matches(rule.selectorText)) {
|
|
6266
|
+
declared.add(value);
|
|
6267
|
+
}
|
|
6268
|
+
}
|
|
6269
|
+
|
|
6270
|
+
if (declared.size === 1) {
|
|
6271
|
+
return declared.values().next().value
|
|
6272
|
+
} else {
|
|
6273
|
+
return null
|
|
6274
|
+
}
|
|
6275
|
+
}
|
|
6276
|
+
|
|
6277
|
+
// Assigning through element.style would reserialize the style attribute and
|
|
6278
|
+
// drop the mso-* declarations Word leaves inline (they aren't valid CSS),
|
|
6279
|
+
// and OfficeFormatter still needs to read mso-list from them. Append to the
|
|
6280
|
+
// attribute instead so the original declarations survive untouched.
|
|
6281
|
+
#appendStyleProperty(element, property, value) {
|
|
6282
|
+
const style = element.getAttribute("style");
|
|
6283
|
+
const declaration = `${property}:${value}`;
|
|
6284
|
+
if (style === null || style.trim() === "") {
|
|
6285
|
+
element.setAttribute("style", declaration);
|
|
6286
|
+
} else {
|
|
6287
|
+
element.setAttribute("style", `${style.replace(/;\s*$/, "")};${declaration}`);
|
|
6288
|
+
}
|
|
6289
|
+
}
|
|
6290
|
+
|
|
6194
6291
|
#firstStrayListChild(list) {
|
|
6195
6292
|
for (const child of list.childNodes) {
|
|
6196
6293
|
if (child.nodeType !== Node.ELEMENT_NODE || child.tagName !== "LI") {
|
|
@@ -6207,6 +6304,16 @@ class PastedContentFormatter {
|
|
|
6207
6304
|
#containsListItems(node) {
|
|
6208
6305
|
return node.nodeType === Node.ELEMENT_NODE && node.querySelector("li") !== null
|
|
6209
6306
|
}
|
|
6307
|
+
|
|
6308
|
+
// Emoji in gmail: <img data-emoji="😂" class="an1" alt="😂" aria-label="😂" draggable="false" src="https://fonts.gstatic.com/s/e/notoemoji/17.0/1f602/32.png" loading="lazy" style="height: 1.2em; width: 1.2em; vertical-align: middle;">
|
|
6309
|
+
#replaceGmailEmojiImgTags() {
|
|
6310
|
+
for (const emojiImg of this.doc.querySelectorAll("img[data-emoji]")) {
|
|
6311
|
+
const emoji = emojiImg.dataset.emoji;
|
|
6312
|
+
if (emoji === emojiImg.alt) {
|
|
6313
|
+
emojiImg.replaceWith(emoji);
|
|
6314
|
+
}
|
|
6315
|
+
}
|
|
6316
|
+
}
|
|
6210
6317
|
}
|
|
6211
6318
|
|
|
6212
6319
|
class Contents {
|
|
@@ -6249,20 +6356,6 @@ class Contents {
|
|
|
6249
6356
|
}, { tag });
|
|
6250
6357
|
}
|
|
6251
6358
|
|
|
6252
|
-
// A literal "\n" stays visible in the editor, which Lexical renders with white-space: pre-wrap,
|
|
6253
|
-
// but collapses to a space once serialized to HTML, so it has to become line break nodes.
|
|
6254
|
-
insertTextWithLineBreaks(text) {
|
|
6255
|
-
const normalizedText = text?.replace(/\r\n?/g, "\n");
|
|
6256
|
-
const selection = $getSelection();
|
|
6257
|
-
|
|
6258
|
-
if (normalizedText?.includes("\n") && $isRangeSelection(selection)) {
|
|
6259
|
-
selection.insertRawText(normalizedText);
|
|
6260
|
-
return true
|
|
6261
|
-
} else {
|
|
6262
|
-
return false
|
|
6263
|
-
}
|
|
6264
|
-
}
|
|
6265
|
-
|
|
6266
6359
|
insertAtCursor(...nodes) {
|
|
6267
6360
|
const selection = this.#insertableSelection();
|
|
6268
6361
|
const inserter = BaseNodeInserter.for(selection);
|
|
@@ -8908,6 +9001,39 @@ class CustomAttachmentDragAndDropExtension extends LexxyExtension {
|
|
|
8908
9001
|
}
|
|
8909
9002
|
}
|
|
8910
9003
|
|
|
9004
|
+
const LINE_SEPARATORS = /\r\n|[\n\r\u2028\u2029]/;
|
|
9005
|
+
|
|
9006
|
+
// A literal line separator inside a text node renders as a break in the editor, or not at all,
|
|
9007
|
+
// but never survives serialization to HTML. macOS text replacements deliver U+2028 LINE SEPARATOR,
|
|
9008
|
+
// and other insertions can carry "\n", so however the text arrives, a transform converts whatever
|
|
9009
|
+
// lands in a text node into line break nodes.
|
|
9010
|
+
class LineSeparatorsExtension extends LexxyExtension {
|
|
9011
|
+
get lexicalExtension() {
|
|
9012
|
+
return this.defineExtension({
|
|
9013
|
+
name: "lexxy/line-separators",
|
|
9014
|
+
register(editor) {
|
|
9015
|
+
return editor.registerNodeTransform(TextNode, $replaceLineSeparatorWithLineBreak)
|
|
9016
|
+
}
|
|
9017
|
+
})
|
|
9018
|
+
}
|
|
9019
|
+
}
|
|
9020
|
+
|
|
9021
|
+
// Replaces the first separator only: the split leaves dirty text nodes behind, so Lexical re-runs
|
|
9022
|
+
// the transform until none remain.
|
|
9023
|
+
function $replaceLineSeparatorWithLineBreak(textNode) {
|
|
9024
|
+
const match = textNode.getTextContent().match(LINE_SEPARATORS);
|
|
9025
|
+
|
|
9026
|
+
if (match) {
|
|
9027
|
+
let separatorNode;
|
|
9028
|
+
if (match.index === 0) {
|
|
9029
|
+
[ separatorNode ] = textNode.splitText(match[0].length);
|
|
9030
|
+
} else {
|
|
9031
|
+
[ , separatorNode ] = textNode.splitText(match.index, match.index + match[0].length);
|
|
9032
|
+
}
|
|
9033
|
+
separatorNode.replace($createLineBreakNode());
|
|
9034
|
+
}
|
|
9035
|
+
}
|
|
9036
|
+
|
|
8911
9037
|
class LexicalEditorElement extends HTMLElement {
|
|
8912
9038
|
static formAssociated = true
|
|
8913
9039
|
static debug = false
|
|
@@ -9066,7 +9192,8 @@ class LexicalEditorElement extends HTMLElement {
|
|
|
9066
9192
|
FormatEscapeExtension,
|
|
9067
9193
|
LinkOpenerExtension,
|
|
9068
9194
|
PreventLexicalTripleClickExtension,
|
|
9069
|
-
CustomAttachmentDragAndDropExtension
|
|
9195
|
+
CustomAttachmentDragAndDropExtension,
|
|
9196
|
+
LineSeparatorsExtension
|
|
9070
9197
|
]
|
|
9071
9198
|
}
|
|
9072
9199
|
|
|
@@ -9254,7 +9381,6 @@ class LexicalEditorElement extends HTMLElement {
|
|
|
9254
9381
|
#initialize() {
|
|
9255
9382
|
this.#registerComponents();
|
|
9256
9383
|
this.#handleEnter();
|
|
9257
|
-
this.#handleReplacementText();
|
|
9258
9384
|
this.#registerFocusEvents();
|
|
9259
9385
|
this.#registerHistoryEvents();
|
|
9260
9386
|
this.#registerFileAcceptFilter();
|
|
@@ -9518,14 +9644,6 @@ class LexicalEditorElement extends HTMLElement {
|
|
|
9518
9644
|
));
|
|
9519
9645
|
}
|
|
9520
9646
|
|
|
9521
|
-
#handleReplacementText() {
|
|
9522
|
-
this.#listeners.track(this.editor.registerCommand(
|
|
9523
|
-
CONTROLLED_TEXT_INSERTION_COMMAND,
|
|
9524
|
-
(event) => event instanceof InputEvent && this.contents.insertTextWithLineBreaks(event.data),
|
|
9525
|
-
COMMAND_PRIORITY_NORMAL
|
|
9526
|
-
));
|
|
9527
|
-
}
|
|
9528
|
-
|
|
9529
9647
|
#registerFocusEvents() {
|
|
9530
9648
|
this.#listeners.track(
|
|
9531
9649
|
registerEventListener(this, "focusin", this.#handleFocusIn),
|