1(() => { 2 var __create = Object.create; 3 var __defProp = Object.defineProperty; 4 var __getOwnPropDesc = Object.getOwnPropertyDescriptor; 5 var __getOwnPropNames = Object.getOwnPropertyNames; 6 var __getProtoOf = Object.getPrototypeOf; 7 var __hasOwnProp = Object.prototype.hasOwnProperty; 8 var __esm = (fn, res) => function __init() { 9 return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; 10 }; 11 var __commonJS = (cb, mod18) => function __require() { 12 return mod18 || (0, cb[__getOwnPropNames(cb)[0]])((mod18 = { exports: {} }).exports, mod18), mod18.exports; 13 }; 14 var __export = (target, all) => { 15 for (var name in all) 16 __defProp(target, name, { get: all[name], enumerable: true }); 17 }; 18 var __copyProps = (to, from, except, desc) => { 19 if (from && typeof from === "object" || typeof from === "function") { 20 for (let key of __getOwnPropNames(from)) 21 if (!__hasOwnProp.call(to, key) && key !== except) 22 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); 23 } 24 return to; 25 }; 26 var __toESM = (mod18, isNodeMode, target) => (target = mod18 != null ? __create(__getProtoOf(mod18)) : {}, __copyProps( 27 // If the importer is in node compatibility mode or this is not an ESM 28 // file that has been converted to a CommonJS file using a Babel- 29 // compatible transform (i.e. "__esModule" has not been set), then set 30 // "default" to the CommonJS "module.exports" for node compatibility. 31 isNodeMode || !mod18 || !mod18.__esModule ? __defProp(target, "default", { value: mod18, enumerable: true }) : target, 32 mod18 33 )); 34 35
vendor: 61,303 bytes, lines 35-1484
35// node_modules/prismjs/prism.js 36 var require_prism = __commonJS({ 37 "node_modules/prismjs/prism.js"(exports, module) { 38 var _self = typeof window !== "undefined" ? window : typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope ? self : {}; 39 var Prism3 = function(_self2) { 40 var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i; 41 var uniqueId = 0; 42 var plainTextGrammar = {}; 43 var _3 = { 44 /** 45 * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the 46 * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load 47 * additional languages or plugins yourself. 48 * 49 * By setting this value to `true`, Prism will not automatically highlight all code elements on the page. 50 * 51 * You obviously have to change this value before the automatic highlighting started. To do this, you can add an 52 * empty Prism object into the global scope before loading the Prism script like this: 53 * 54 * ```js 55 * window.Prism = window.Prism || {}; 56 * Prism.manual = true; 57 * // add a new <script> to load Prism's script 58 * ``` 59 * 60 * @default false 61 * @type {boolean} 62 * @memberof Prism 63 * @public 64 */ 65 manual: _self2.Prism && _self2.Prism.manual, 66 /** 67 * By default, if Prism is in a web worker, it assumes that it is in a worker it created itself, so it uses 68 * `addEventListener` to communicate with its parent instance. However, if you're using Prism manually in your 69 * own worker, you don't want it to do this. 70 * 71 * By setting this value to `true`, Prism will not add its own listeners to the worker. 72 * 73 * You obviously have to change this value before Prism executes. To do this, you can add an 74 * empty Prism object into the global scope before loading the Prism script like this: 75 * 76 * ```js 77 * window.Prism = window.Prism || {}; 78 * Prism.disableWorkerMessageHandler = true; 79 * // Load Prism's script 80 * ``` 81 * 82 * @default false 83 * @type {boolean} 84 * @memberof Prism 85 * @public 86 */ 87 disableWorkerMessageHandler: _self2.Prism && _self2.Prism.disableWorkerMessageHandler, 88 /** 89 * A namespace for utility methods. 90 * 91 * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may 92 * change or disappear at any time. 93 * 94 * @namespace 95 * @memberof Prism 96 */ 97 util: { 98 encode: function encode(tokens) { 99 if (tokens instanceof Token) { 100 return new Token(tokens.type, encode(tokens.content), tokens.alias); 101 } else if (Array.isArray(tokens)) { 102 return tokens.map(encode); 103 } else { 104 return tokens.replace(/&/g, "&").replace(/</g, "<").replace(/\u00a0/g, " "); 105 } 106 }, 107 /** 108 * Returns the name of the type of the given value. 109 * 110 * @param {any} o 111 * @returns {string} 112 * @example 113 * type(null) === 'Null' 114 * type(undefined) === 'Undefined' 115 * type(123) === 'Number' 116 * type('foo') === 'String' 117 * type(true) === 'Boolean' 118 * type([1, 2]) === 'Array' 119 * type({}) === 'Object' 120 * type(String) === 'Function' 121 * type(/abc+/) === 'RegExp' 122 */ 123 type: function(o2) { 124 return Object.prototype.toString.call(o2).slice(8, -1); 125 }, 126 /** 127 * Returns a unique number for the given object. Later calls will still return the same number. 128 * 129 * @param {Object} obj 130 * @returns {number} 131 */ 132 objId: function(obj) { 133 if (!obj["__id"]) { 134 Object.defineProperty(obj, "__id", { value: ++uniqueId }); 135 } 136 return obj["__id"]; 137 }, 138 /** 139 * Creates a deep clone of the given object. 140 * 141 * The main intended use of this function is to clone language definitions. 142 * 143 * @param {T} o 144 * @param {Record<number, any>} [visited] 145 * @returns {T} 146 * @template T 147 */ 148 clone: function deepClone(o2, visited) { 149 visited = visited || {}; 150 var clone2; 151 var id3; 152 switch (_3.util.type(o2)) { 153 case "Object": 154 id3 = _3.util.objId(o2); 155 if (visited[id3]) { 156 return visited[id3]; 157 } 158 clone2 = /** @type {Record<string, any>} */ 159 {}; 160 visited[id3] = clone2; 161 for (var key in o2) { 162 if (o2.hasOwnProperty(key)) { 163 clone2[key] = deepClone(o2[key], visited); 164 } 165 } 166 return ( 167 /** @type {any} */ 168 clone2 169 ); 170 case "Array": 171 id3 = _3.util.objId(o2); 172 if (visited[id3]) { 173 return visited[id3]; 174 } 175 clone2 = []; 176 visited[id3] = clone2; 177 /** @type {Array} */ 178 /** @type {any} */ 179 o2.forEach(function(v3, i2) { 180 clone2[i2] = deepClone(v3, visited); 181 }); 182 return ( 183 /** @type {any} */ 184 clone2 185 ); 186 default: 187 return o2; 188 } 189 }, 190 /** 191 * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class. 192 * 193 * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned. 194 * 195 * @param {Element} element 196 * @returns {string} 197 */ 198 getLanguage: function(element) { 199 while (element) { 200 var m3 = lang.exec(element.className); 201 if (m3) { 202 return m3[1].toLowerCase(); 203 } 204 element = element.parentElement; 205 } 206 return "none"; 207 }, 208 /** 209 * Sets the Prism `language-xxxx` class of the given element. 210 * 211 * @param {Element} element 212 * @param {string} language 213 * @returns {void} 214 */ 215 setLanguage: function(element, language) { 216 element.className = element.className.replace(RegExp(lang, "gi"), ""); 217 element.classList.add("language-" + language); 218 }, 219 /** 220 * Returns the script element that is currently executing. 221 * 222 * This does __not__ work for line script element. 223 * 224 * @returns {HTMLScriptElement | null} 225 */ 226 currentScript: function() { 227 if (typeof document === "undefined") { 228 return null; 229 } 230 if (document.currentScript && document.currentScript.tagName === "SCRIPT" && 1 < 2) { 231 return ( 232 /** @type {any} */ 233 document.currentScript 234 ); 235 } 236 try { 237 throw new Error(); 238 } catch (err) { 239 var src = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(err.stack) || [])[1]; 240 if (src) { 241 var scripts = document.getElementsByTagName("script"); 242 for (var i2 in scripts) { 243 if (scripts[i2].src == src) { 244 return scripts[i2]; 245 } 246 } 247 } 248 return null; 249 } 250 }, 251 /** 252 * Returns whether a given class is active for `element`. 253 * 254 * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated 255 * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the 256 * given class is just the given class with a `no-` prefix. 257 * 258 * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is 259 * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its 260 * ancestors have the given class or the negated version of it, then the default activation will be returned. 261 * 262 * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated 263 * version of it, the class is considered active. 264 * 265 * @param {Element} element 266 * @param {string} className 267 * @param {boolean} [defaultActivation=false] 268 * @returns {boolean} 269 */ 270 isActive: function(element, className, defaultActivation) { 271 var no = "no-" + className; 272 while (element) { 273 var classList = element.classList; 274 if (classList.contains(className)) { 275 return true; 276 } 277 if (classList.contains(no)) { 278 return false; 279 } 280 element = element.parentElement; 281 } 282 return !!defaultActivation; 283 } 284 }, 285 /** 286 * This namespace contains all currently loaded languages and the some helper functions to create and modify languages. 287 * 288 * @namespace 289 * @memberof Prism 290 * @public 291 */ 292 languages: { 293 /** 294 * The grammar for plain, unformatted text. 295 */ 296 plain: plainTextGrammar, 297 plaintext: plainTextGrammar, 298 text: plainTextGrammar, 299 txt: plainTextGrammar, 300 /** 301 * Creates a deep copy of the language with the given id and appends the given tokens. 302 * 303 * If a token in `redef` also appears in the copied language, then the existing token in the copied language 304 * will be overwritten at its original position. 305 * 306 * ## Best practices 307 * 308 * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language) 309 * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to 310 * understand the language definition because, normally, the order of tokens matters in Prism grammars. 311 * 312 * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens. 313 * Furthermore, all non-overwriting tokens should be placed after the overwriting ones. 314 * 315 * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`. 316 * @param {Grammar} redef The new tokens to append. 317 * @returns {Grammar} The new language created. 318 * @public 319 * @example 320 * Prism.languages['css-with-colors'] = Prism.languages.extend('css', { 321 * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token 322 * // at its original position 323 * 'comment': { ... }, 324 * // CSS doesn't have a 'color' token, so this token will be appended 325 * 'color': /\b(?:red|green|blue)\b/ 326 * }); 327 */ 328 extend: function(id3, redef) { 329 var lang2 = _3.util.clone(_3.languages[id3]); 330 for (var key in redef) { 331 lang2[key] = redef[key]; 332 } 333 return lang2; 334 }, 335 /** 336 * Inserts tokens _before_ another token in a language definition or any other grammar. 337 * 338 * ## Usage 339 * 340 * This helper method makes it easy to modify existing languages. For example, the CSS language definition 341 * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded 342 * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the 343 * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do 344 * this: 345 * 346 * ```js 347 * Prism.languages.markup.style = { 348 * // token 349 * }; 350 * ``` 351 * 352 * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens 353 * before existing tokens. For the CSS example above, you would use it like this: 354 * 355 * ```js 356 * Prism.languages.insertBefore('markup', 'cdata', { 357 * 'style': { 358 * // token 359 * } 360 * }); 361 * ``` 362 * 363 * ## Special cases 364 * 365 * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar 366 * will be ignored. 367 * 368 * This behavior can be used to insert tokens after `before`: 369 * 370 * ```js 371 * Prism.languages.insertBefore('markup', 'comment', { 372 * 'comment': Prism.languages.markup.comment, 373 * // tokens after 'comment' 374 * }); 375 * ``` 376 * 377 * ## Limitations 378 * 379 * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object 380 * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave 381 * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily 382 * deleting properties which is necessary to insert at arbitrary positions. 383 * 384 * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object. 385 * Instead, it will create a new object and replace all references to the target object with the new one. This 386 * can be done without temporarily deleting properties, so the iteration order is well-defined. 387 * 388 * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if 389 * you hold the target object in a variable, then the value of the variable will not change. 390 * 391 * ```js 392 * var oldMarkup = Prism.languages.markup; 393 * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... }); 394 * 395 * assert(oldMarkup !== Prism.languages.markup); 396 * assert(newMarkup === Prism.languages.markup); 397 * ``` 398 * 399 * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the 400 * object to be modified. 401 * @param {string} before The key to insert before. 402 * @param {Grammar} insert An object containing the key-value pairs to be inserted. 403 * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the 404 * object to be modified. 405 * 406 * Defaults to `Prism.languages`. 407 * @returns {Grammar} The new grammar object. 408 * @public 409 */ 410 insertBefore: function(inside, before, insert, root) { 411 root = root || /** @type {any} */ 412 _3.languages; 413 var grammar = root[inside]; 414 var ret = {}; 415 for (var token in grammar) { 416 if (grammar.hasOwnProperty(token)) { 417 if (token == before) { 418 for (var newToken in insert) { 419 if (insert.hasOwnProperty(newToken)) { 420 ret[newToken] = insert[newToken]; 421 } 422 } 423 } 424 if (!insert.hasOwnProperty(token)) { 425 ret[token] = grammar[token]; 426 } 427 } 428 } 429 var old = root[inside]; 430 root[inside] = ret; 431 _3.languages.DFS(_3.languages, function(key, value) { 432 if (value === old && key != inside) { 433 this[key] = ret; 434 } 435 }); 436 return ret; 437 }, 438 // Traverse a language definition with Depth First Search 439 DFS: function DFS(o2, callback, type, visited) { 440 visited = visited || {}; 441 var objId = _3.util.objId; 442 for (var i2 in o2) { 443 if (o2.hasOwnProperty(i2)) { 444 callback.call(o2, i2, o2[i2], type || i2); 445 var property = o2[i2]; 446 var propertyType = _3.util.type(property); 447 if (propertyType === "Object" && !visited[objId(property)]) { 448 visited[objId(property)] = true; 449 DFS(property, callback, null, visited); 450 } else if (propertyType === "Array" && !visited[objId(property)]) { 451 visited[objId(property)] = true; 452 DFS(property, callback, i2, visited); 453 } 454 } 455 } 456 } 457 }, 458 plugins: {}, 459 /** 460 * This is the most high-level function in Prismâs API. 461 * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on 462 * each one of them. 463 * 464 * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`. 465 * 466 * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}. 467 * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}. 468 * @memberof Prism 469 * @public 470 */ 471 highlightAll: function(async, callback) { 472 _3.highlightAllUnder(document, async, callback); 473 }, 474 /** 475 * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls 476 * {@link Prism.highlightElement} on each one of them. 477 * 478 * The following hooks will be run: 479 * 1. `before-highlightall` 480 * 2. `before-all-elements-highlight` 481 * 3. All hooks of {@link Prism.highlightElement} for each element. 482 * 483 * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted. 484 * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers. 485 * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done. 486 * @memberof Prism 487 * @public 488 */ 489 highlightAllUnder: function(container, async, callback) { 490 var env = { 491 callback, 492 container, 493 selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code' 494 }; 495 _3.hooks.run("before-highlightall", env); 496 env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector)); 497 _3.hooks.run("before-all-elements-highlight", env); 498 for (var i2 = 0, element; element = env.elements[i2++]; ) { 499 _3.highlightElement(element, async === true, env.callback); 500 } 501 }, 502 /** 503 * Highlights the code inside a single element. 504 * 505 * The following hooks will be run: 506 * 1. `before-sanity-check` 507 * 2. `before-highlight` 508 * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`. 509 * 4. `before-insert` 510 * 5. `after-highlight` 511 * 6. `complete` 512 * 513 * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for 514 * the element's language. 515 * 516 * @param {Element} element The element containing the code. 517 * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier. 518 * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers 519 * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is 520 * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default). 521 * 522 * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for 523 * asynchronous highlighting to work. You can build your own bundle on the 524 * [Download page](https://prismjs.com/download.html). 525 * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done. 526 * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously. 527 * @memberof Prism 528 * @public 529 */ 530 highlightElement: function(element, async, callback) { 531 var language = _3.util.getLanguage(element); 532 var grammar = _3.languages[language]; 533 _3.util.setLanguage(element, language); 534 var parent = element.parentElement; 535 if (parent && parent.nodeName.toLowerCase() === "pre") { 536 _3.util.setLanguage(parent, language); 537 } 538 var code = element.textContent; 539 var env = { 540 element, 541 language, 542 grammar, 543 code 544 }; 545 function insertHighlightedCode(highlightedCode) { 546 env.highlightedCode = highlightedCode; 547 _3.hooks.run("before-insert", env); 548 env.element.innerHTML = env.highlightedCode; 549 _3.hooks.run("after-highlight", env); 550 _3.hooks.run("complete", env); 551 callback && callback.call(env.element); 552 } 553 _3.hooks.run("before-sanity-check", env); 554 parent = env.element.parentElement; 555 if (parent && parent.nodeName.toLowerCase() === "pre" && !parent.hasAttribute("tabindex")) { 556 parent.setAttribute("tabindex", "0"); 557 } 558 if (!env.code) { 559 _3.hooks.run("complete", env); 560 callback && callback.call(env.element); 561 return; 562 } 563 _3.hooks.run("before-highlight", env); 564 if (!env.grammar) { 565 insertHighlightedCode(_3.util.encode(env.code)); 566 return; 567 } 568 if (async && _self2.Worker) { 569 var worker = new Worker(_3.filename); 570 worker.onmessage = function(evt) { 571 insertHighlightedCode(evt.data); 572 }; 573 worker.postMessage(JSON.stringify({ 574 language: env.language, 575 code: env.code, 576 immediateClose: true 577 })); 578 } else { 579 insertHighlightedCode(_3.highlight(env.code, env.grammar, env.language)); 580 } 581 }, 582 /** 583 * Low-level function, only use if you know what youâre doing. It accepts a string of text as input 584 * and the language definitions to use, and returns a string with the HTML produced. 585 * 586 * The following hooks will be run: 587 * 1. `before-tokenize` 588 * 2. `after-tokenize` 589 * 3. `wrap`: On each {@link Token}. 590 * 591 * @param {string} text A string with the code to be highlighted. 592 * @param {Grammar} grammar An object containing the tokens to use. 593 * 594 * Usually a language definition like `Prism.languages.markup`. 595 * @param {string} language The name of the language definition passed to `grammar`. 596 * @returns {string} The highlighted HTML. 597 * @memberof Prism 598 * @public 599 * @example 600 * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript'); 601 */ 602 highlight: function(text2, grammar, language) { 603 var env = { 604 code: text2, 605 grammar, 606 language 607 }; 608 _3.hooks.run("before-tokenize", env); 609 if (!env.grammar) { 610 throw new Error('The language "' + env.language + '" has no grammar.'); 611 } 612 env.tokens = _3.tokenize(env.code, env.grammar); 613 _3.hooks.run("after-tokenize", env); 614 return Token.stringify(_3.util.encode(env.tokens), env.language); 615 }, 616 /** 617 * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input 618 * and the language definitions to use, and returns an array with the tokenized code. 619 * 620 * When the language definition includes nested tokens, the function is called recursively on each of these tokens. 621 * 622 * This method could be useful in other contexts as well, as a very crude parser. 623 * 624 * @param {string} text A string with the code to be highlighted. 625 * @param {Grammar} grammar An object containing the tokens to use. 626 * 627 * Usually a language definition like `Prism.languages.markup`. 628 * @returns {TokenStream} An array of strings and tokens, a token stream. 629 * @memberof Prism 630 * @public 631 * @example 632 * let code = `var foo = 0;`; 633 * let tokens = Prism.tokenize(code, Prism.languages.javascript); 634 * tokens.forEach(token => { 635 * if (token instanceof Prism.Token && token.type === 'number') { 636 * console.log(`Found numeric literal: ${token.content}`); 637 * } 638 * }); 639 */ 640 tokenize: function(text2, grammar) { 641 var rest = grammar.rest; 642 if (rest) { 643 for (var token in rest) { 644 grammar[token] = rest[token]; 645 } 646 delete grammar.rest; 647 } 648 var tokenList = new LinkedList(); 649 addAfter(tokenList, tokenList.head, text2); 650 matchGrammar(text2, tokenList, grammar, tokenList.head, 0); 651 return toArray3(tokenList); 652 }, 653 /** 654 * @namespace 655 * @memberof Prism 656 * @public 657 */ 658 hooks: { 659 all: {}, 660 /** 661 * Adds the given callback to the list of callbacks for the given hook. 662 * 663 * The callback will be invoked when the hook it is registered for is run. 664 * Hooks are usually directly run by a highlight function but you can also run hooks yourself. 665 * 666 * One callback function can be registered to multiple hooks and the same hook multiple times. 667 * 668 * @param {string} name The name of the hook. 669 * @param {HookCallback} callback The callback function which is given environment variables. 670 * @public 671 */ 672 add: function(name, callback) { 673 var hooks = _3.hooks.all; 674 hooks[name] = hooks[name] || []; 675 hooks[name].push(callback); 676 }, 677 /** 678 * Runs a hook invoking all registered callbacks with the given environment variables. 679 * 680 * Callbacks will be invoked synchronously and in the order in which they were registered. 681 * 682 * @param {string} name The name of the hook. 683 * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered. 684 * @public 685 */ 686 run: function(name, env) { 687 var callbacks = _3.hooks.all[name]; 688 if (!callbacks || !callbacks.length) { 689 return; 690 } 691 for (var i2 = 0, callback; callback = callbacks[i2++]; ) { 692 callback(env); 693 } 694 } 695 }, 696 Token 697 }; 698 _self2.Prism = _3; 699 function Token(type, content, alias, matchedStr) { 700 this.type = type; 701 this.content = content; 702 this.alias = alias; 703 this.length = (matchedStr || "").length | 0; 704 } 705 Token.stringify = function stringify(o2, language) { 706 if (typeof o2 == "string") { 707 return o2; 708 } 709 if (Array.isArray(o2)) { 710 var s2 = ""; 711 o2.forEach(function(e2) { 712 s2 += stringify(e2, language); 713 }); 714 return s2; 715 } 716 var env = { 717 type: o2.type, 718 content: stringify(o2.content, language), 719 tag: "span", 720 classes: ["token", o2.type], 721 attributes: {}, 722 language 723 }; 724 var aliases = o2.alias; 725 if (aliases) { 726 if (Array.isArray(aliases)) { 727 Array.prototype.push.apply(env.classes, aliases); 728 } else { 729 env.classes.push(aliases); 730 } 731 } 732 _3.hooks.run("wrap", env); 733 var attributes = ""; 734 for (var name in env.attributes) { 735 attributes += " " + name + '="' + (env.attributes[name] || "").replace(/"/g, """) + '"'; 736 } 737 return "<" + env.tag + ' class="' + env.classes.join(" ") + '"' + attributes + ">" + env.content + "</" + env.tag + ">"; 738 }; 739 function matchPattern(pattern, pos, text2, lookbehind) { 740 pattern.lastIndex = pos; 741 var match = pattern.exec(text2); 742 if (match && lookbehind && match[1]) { 743 var lookbehindLength = match[1].length; 744 match.index += lookbehindLength; 745 match[0] = match[0].slice(lookbehindLength); 746 } 747 return match; 748 } 749 function matchGrammar(text2, tokenList, grammar, startNode, startPos, rematch) { 750 for (var token in grammar) { 751 if (!grammar.hasOwnProperty(token) || !grammar[token]) { 752 continue; 753 } 754 var patterns = grammar[token]; 755 patterns = Array.isArray(patterns) ? patterns : [patterns]; 756 for (var j3 = 0; j3 < patterns.length; ++j3) { 757 if (rematch && rematch.cause == token + "," + j3) { 758 return; 759 } 760 var patternObj = patterns[j3]; 761 var inside = patternObj.inside; 762 var lookbehind = !!patternObj.lookbehind; 763 var greedy = !!patternObj.greedy; 764 var alias = patternObj.alias; 765 if (greedy && !patternObj.pattern.global) { 766 var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0]; 767 patternObj.pattern = RegExp(patternObj.pattern.source, flags + "g"); 768 } 769 var pattern = patternObj.pattern || patternObj; 770 for (var currentNode = startNode.next, pos = startPos; currentNode !== tokenList.tail; pos += currentNode.value.length, currentNode = currentNode.next) { 771 if (rematch && pos >= rematch.reach) { 772 break; 773 } 774 var str = currentNode.value; 775 if (tokenList.length > text2.length) { 776 return; 777 } 778 if (str instanceof Token) { 779 continue; 780 } 781 var removeCount = 1; 782 var match; 783 if (greedy) { 784 match = matchPattern(pattern, pos, text2, lookbehind); 785 if (!match || match.index >= text2.length) { 786 break; 787 } 788 var from = match.index; 789 var to = match.index + match[0].length; 790 var p2 = pos; 791 p2 += currentNode.value.length; 792 while (from >= p2) { 793 currentNode = currentNode.next; 794 p2 += currentNode.value.length; 795 } 796 p2 -= currentNode.value.length; 797 pos = p2; 798 if (currentNode.value instanceof Token) { 799 continue; 800 } 801 for (var k2 = currentNode; k2 !== tokenList.tail && (p2 < to || typeof k2.value === "string"); k2 = k2.next) { 802 removeCount++; 803 p2 += k2.value.length; 804 } 805 removeCount--; 806 str = text2.slice(pos, p2); 807 match.index -= pos; 808 } else { 809 match = matchPattern(pattern, 0, str, lookbehind); 810 if (!match) { 811 continue; 812 } 813 } 814 var from = match.index; 815 var matchStr = match[0]; 816 var before = str.slice(0, from); 817 var after = str.slice(from + matchStr.length); 818 var reach = pos + str.length; 819 if (rematch && reach > rematch.reach) { 820 rematch.reach = reach; 821 } 822 var removeFrom = currentNode.prev; 823 if (before) { 824 removeFrom = addAfter(tokenList, removeFrom, before); 825 pos += before.length; 826 } 827 removeRange(tokenList, removeFrom, removeCount); 828 var wrapped = new Token(token, inside ? _3.tokenize(matchStr, inside) : matchStr, alias, matchStr); 829 currentNode = addAfter(tokenList, removeFrom, wrapped); 830 if (after) { 831 addAfter(tokenList, currentNode, after); 832 } 833 if (removeCount > 1) { 834 var nestedRematch = { 835 cause: token + "," + j3, 836 reach 837 }; 838 matchGrammar(text2, tokenList, grammar, currentNode.prev, pos, nestedRematch); 839 if (rematch && nestedRematch.reach > rematch.reach) { 840 rematch.reach = nestedRematch.reach; 841 } 842 } 843 } 844 } 845 } 846 } 847 function LinkedList() { 848 var head = { value: null, prev: null, next: null }; 849 var tail = { value: null, prev: head, next: null }; 850 head.next = tail; 851 this.head = head; 852 this.tail = tail; 853 this.length = 0; 854 } 855 function addAfter(list, node, value) { 856 var next = node.next; 857 var newNode = { value, prev: node, next }; 858 node.next = newNode; 859 next.prev = newNode; 860 list.length++; 861 return newNode; 862 } 863 function removeRange(list, node, count) { 864 var next = node.next; 865 for (var i2 = 0; i2 < count && next !== list.tail; i2++) { 866 next = next.next; 867 } 868 node.next = next; 869 next.prev = node; 870 list.length -= i2; 871 } 872 function toArray3(list) { 873 var array = []; 874 var node = list.head.next; 875 while (node !== list.tail) { 876 array.push(node.value); 877 node = node.next; 878 } 879 return array; 880 } 881 if (!_self2.document) { 882 if (!_self2.addEventListener) { 883 return _3; 884 } 885 if (!_3.disableWorkerMessageHandler) { 886 _self2.addEventListener("message", function(evt) { 887 var message = JSON.parse(evt.data); 888 var lang2 = message.language; 889 var code = message.code; 890 var immediateClose = message.immediateClose; 891 _self2.postMessage(_3.highlight(code, _3.languages[lang2], lang2)); 892 if (immediateClose) { 893 _self2.close(); 894 } 895 }, false); 896 } 897 return _3; 898 } 899 var script = _3.util.currentScript(); 900 if (script) { 901 _3.filename = script.src; 902 if (script.hasAttribute("data-manual")) { 903 _3.manual = true; 904 } 905 } 906 function highlightAutomaticallyCallback() { 907 if (!_3.manual) { 908 _3.highlightAll(); 909 } 910 } 911 if (!_3.manual) { 912 var readyState = document.readyState; 913 if (readyState === "loading" || readyState === "interactive" && script && script.defer) { 914 document.addEventListener("DOMContentLoaded", highlightAutomaticallyCallback); 915 } else { 916 if (window.requestAnimationFrame) { 917 window.requestAnimationFrame(highlightAutomaticallyCallback); 918 } else { 919 window.setTimeout(highlightAutomaticallyCallback, 16); 920 } 921 } 922 } 923 return _3; 924 }(_self); 925 if (typeof module !== "undefined" && module.exports) { 926 module.exports = Prism3; 927 } 928 if (typeof global !== "undefined") { 929 global.Prism = Prism3; 930 } 931 Prism3.languages.markup = { 932 "comment": { 933 pattern: /<!--(?:(?!<!--)[\s\S])*?-->/, 934 greedy: true 935 }, 936 "prolog": { 937 pattern: /<\?[\s\S]+?\?>/, 938 greedy: true 939 }, 940 "doctype": { 941 // https://www.w3.org/TR/xml/#NT-doctypedecl 942 pattern: /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i, 943 greedy: true, 944 inside: { 945 "internal-subset": { 946 pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/, 947 lookbehind: true, 948 greedy: true, 949 inside: null 950 // see below 951 }, 952 "string": { 953 pattern: /"[^"]*"|'[^']*'/, 954 greedy: true 955 }, 956 "punctuation": /^<!|>$|[[\]]/, 957 "doctype-tag": /^DOCTYPE/i, 958 "name": /[^\s<>'"]+/ 959 } 960 }, 961 "cdata": { 962 pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, 963 greedy: true 964 }, 965 "tag": { 966 pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/, 967 greedy: true, 968 inside: { 969 "tag": { 970 pattern: /^<\/?[^\s>\/]+/, 971 inside: { 972 "punctuation": /^<\/?/, 973 "namespace": /^[^\s>\/:]+:/ 974 } 975 }, 976 "special-attr": [], 977 "attr-value": { 978 pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, 979 inside: { 980 "punctuation": [ 981 { 982 pattern: /^=/, 983 alias: "attr-equals" 984 }, 985 { 986 pattern: /^(\s*)["']|["']$/, 987 lookbehind: true 988 } 989 ] 990 } 991 }, 992 "punctuation": /\/?>/, 993 "attr-name": { 994 pattern: /[^\s>\/]+/, 995 inside: { 996 "namespace": /^[^\s>\/:]+:/ 997 } 998 } 999 } 1000 }, 1001 "entity": [ 1002 { 1003 pattern: /&[\da-z]{1,8};/i, 1004 alias: "named-entity" 1005 }, 1006 /&#x?[\da-f]{1,8};/i 1007 ] 1008 }; 1009 Prism3.languages.markup["tag"].inside["attr-value"].inside["entity"] = Prism3.languages.markup["entity"]; 1010 Prism3.languages.markup["doctype"].inside["internal-subset"].inside = Prism3.languages.markup; 1011 Prism3.hooks.add("wrap", function(env) { 1012 if (env.type === "entity") { 1013 env.attributes["title"] = env.content.replace(/&/, "&"); 1014 } 1015 }); 1016 Object.defineProperty(Prism3.languages.markup.tag, "addInlined", { 1017 /** 1018 * Adds an inlined language to markup. 1019 * 1020 * An example of an inlined language is CSS with `<style>` tags. 1021 * 1022 * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as 1023 * case insensitive. 1024 * @param {string} lang The language key. 1025 * @example 1026 * addInlined('style', 'css'); 1027 */ 1028 value: function addInlined2(tagName, lang) { 1029 var includedCdataInside = {}; 1030 includedCdataInside["language-" + lang] = { 1031 pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i, 1032 lookbehind: true, 1033 inside: Prism3.languages[lang] 1034 }; 1035 includedCdataInside["cdata"] = /^<!\[CDATA\[|\]\]>$/i; 1036 var inside = { 1037 "included-cdata": { 1038 pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, 1039 inside: includedCdataInside 1040 } 1041 }; 1042 inside["language-" + lang] = { 1043 pattern: /[\s\S]+/, 1044 inside: Prism3.languages[lang] 1045 }; 1046 var def = {}; 1047 def[tagName] = { 1048 pattern: RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function() { 1049 return tagName; 1050 }), "i"), 1051 lookbehind: true, 1052 greedy: true, 1053 inside 1054 }; 1055 Prism3.languages.insertBefore("markup", "cdata", def); 1056 } 1057 }); 1058 Object.defineProperty(Prism3.languages.markup.tag, "addAttribute", { 1059 /** 1060 * Adds an pattern to highlight languages embedded in HTML attributes. 1061 * 1062 * An example of an inlined language is CSS with `style` attributes. 1063 * 1064 * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as 1065 * case insensitive. 1066 * @param {string} lang The language key. 1067 * @example 1068 * addAttribute('style', 'css'); 1069 */ 1070 value: function(attrName, lang) { 1071 Prism3.languages.markup.tag.inside["special-attr"].push({ 1072 pattern: RegExp( 1073 /(^|["'\s])/.source + "(?:" + attrName + ")" + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source, 1074 "i" 1075 ), 1076 lookbehind: true, 1077 inside: { 1078 "attr-name": /^[^\s=]+/, 1079 "attr-value": { 1080 pattern: /=[\s\S]+/, 1081 inside: { 1082 "value": { 1083 pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/, 1084 lookbehind: true, 1085 alias: [lang, "language-" + lang], 1086 inside: Prism3.languages[lang] 1087 }, 1088 "punctuation": [ 1089 { 1090 pattern: /^=/, 1091 alias: "attr-equals" 1092 }, 1093 /"|'/ 1094 ] 1095 } 1096 } 1097 } 1098 }); 1099 } 1100 }); 1101 Prism3.languages.html = Prism3.languages.markup; 1102 Prism3.languages.mathml = Prism3.languages.markup; 1103 Prism3.languages.svg = Prism3.languages.markup; 1104 Prism3.languages.xml = Prism3.languages.extend("markup", {}); 1105 Prism3.languages.ssml = Prism3.languages.xml; 1106 Prism3.languages.atom = Prism3.languages.xml; 1107 Prism3.languages.rss = Prism3.languages.xml; 1108 (function(Prism4) { 1109 var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/; 1110 Prism4.languages.css = { 1111 "comment": /\/\*[\s\S]*?\*\//, 1112 "atrule": { 1113 pattern: RegExp("@[\\w-](?:" + /[^;{\s"']|\s+(?!\s)/.source + "|" + string.source + ")*?" + /(?:;|(?=\s*\{))/.source), 1114 inside: { 1115 "rule": /^@[\w-]+/, 1116 "selector-function-argument": { 1117 pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/, 1118 lookbehind: true, 1119 alias: "selector" 1120 }, 1121 "keyword": { 1122 pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/, 1123 lookbehind: true 1124 } 1125 // See rest below 1126 } 1127 }, 1128 "url": { 1129 // https://drafts.csswg.org/css-values-3/#urls 1130 pattern: RegExp("\\burl\\((?:" + string.source + "|" + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + ")\\)", "i"), 1131 greedy: true, 1132 inside: { 1133 "function": /^url/i, 1134 "punctuation": /^\(|\)$/, 1135 "string": { 1136 pattern: RegExp("^" + string.source + "$"), 1137 alias: "url" 1138 } 1139 } 1140 }, 1141 "selector": { 1142 pattern: RegExp(`(^|[{}\\s])[^{}\\s](?:[^{};"'\\s]|\\s+(?![\\s{])|` + string.source + ")*(?=\\s*\\{)"), 1143 lookbehind: true 1144 }, 1145 "string": { 1146 pattern: string, 1147 greedy: true 1148 }, 1149 "property": { 1150 pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i, 1151 lookbehind: true 1152 }, 1153 "important": /!important\b/i, 1154 "function": { 1155 pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i, 1156 lookbehind: true 1157 }, 1158 "punctuation": /[(){};:,]/ 1159 }; 1160 Prism4.languages.css["atrule"].inside.rest = Prism4.languages.css; 1161 var markup = Prism4.languages.markup; 1162 if (markup) { 1163 markup.tag.addInlined("style", "css"); 1164 markup.tag.addAttribute("style", "css"); 1165 } 1166 })(Prism3); 1167 Prism3.languages.clike = { 1168 "comment": [ 1169 { 1170 pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, 1171 lookbehind: true, 1172 greedy: true 1173 }, 1174 { 1175 pattern: /(^|[^\\:])\/\/.*/, 1176 lookbehind: true, 1177 greedy: true 1178 } 1179 ], 1180 "string": { 1181 pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, 1182 greedy: true 1183 }, 1184 "class-name": { 1185 pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i, 1186 lookbehind: true, 1187 inside: { 1188 "punctuation": /[.\\]/ 1189 } 1190 }, 1191 "keyword": /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/, 1192 "boolean": /\b(?:false|true)\b/, 1193 "function": /\b\w+(?=\()/, 1194 "number": /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i, 1195 "operator": /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/, 1196 "punctuation": /[{}[\];(),.:]/ 1197 }; 1198 Prism3.languages.javascript = Prism3.languages.extend("clike", { 1199 "class-name": [ 1200 Prism3.languages.clike["class-name"], 1201 { 1202 pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/, 1203 lookbehind: true 1204 } 1205 ], 1206 "keyword": [ 1207 { 1208 pattern: /((?:^|\})\s*)catch\b/, 1209 lookbehind: true 1210 }, 1211 { 1212 pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/, 1213 lookbehind: true 1214 } 1215 ], 1216 // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) 1217 "function": /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, 1218 "number": { 1219 pattern: RegExp( 1220 /(^|[^\w$])/.source + "(?:" + // constant 1221 (/NaN|Infinity/.source + "|" + // binary integer 1222 /0[bB][01]+(?:_[01]+)*n?/.source + "|" + // octal integer 1223 /0[oO][0-7]+(?:_[0-7]+)*n?/.source + "|" + // hexadecimal integer 1224 /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source + "|" + // decimal bigint 1225 /\d+(?:_\d+)*n/.source + "|" + // decimal number (integer or float) but no bigint 1226 /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source) + ")" + /(?![\w$])/.source 1227 ), 1228 lookbehind: true 1229 }, 1230 "operator": /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/ 1231 }); 1232 Prism3.languages.javascript["class-name"][0].pattern = /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/; 1233 Prism3.languages.insertBefore("javascript", "keyword", { 1234 "regex": { 1235 pattern: RegExp( 1236 // lookbehind 1237 // eslint-disable-next-line regexp/no-dupe-characters-character-class 1238 /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source + // Regex pattern: 1239 // There are 2 regex patterns here. The RegExp set notation proposal added support for nested character 1240 // classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible 1241 // with the only syntax, so we have to define 2 different regex patterns. 1242 /\//.source + "(?:" + /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source + "|" + // `v` flag syntax. This supports 3 levels of nested character classes. 1243 /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source + ")" + // lookahead 1244 /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source 1245 ), 1246 lookbehind: true, 1247 greedy: true, 1248 inside: { 1249 "regex-source": { 1250 pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/, 1251 lookbehind: true, 1252 alias: "language-regex", 1253 inside: Prism3.languages.regex 1254 }, 1255 "regex-delimiter": /^\/|\/$/, 1256 "regex-flags": /^[a-z]+$/ 1257 } 1258 }, 1259 // This must be declared before keyword because we use "function" inside the look-forward 1260 "function-variable": { 1261 pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/, 1262 alias: "function" 1263 }, 1264 "parameter": [ 1265 { 1266 pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/, 1267 lookbehind: true, 1268 inside: Prism3.languages.javascript 1269 }, 1270 { 1271 pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i, 1272 lookbehind: true, 1273 inside: Prism3.languages.javascript 1274 }, 1275 { 1276 pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/, 1277 lookbehind: true, 1278 inside: Prism3.languages.javascript 1279 }, 1280 { 1281 pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/, 1282 lookbehind: true, 1283 inside: Prism3.languages.javascript 1284 } 1285 ], 1286 "constant": /\b[A-Z](?:[A-Z_]|\dx?)*\b/ 1287 }); 1288 Prism3.languages.insertBefore("javascript", "string", { 1289 "hashbang": { 1290 pattern: /^#!.*/, 1291 greedy: true, 1292 alias: "comment" 1293 }, 1294 "template-string": { 1295 pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/, 1296 greedy: true, 1297 inside: { 1298 "template-punctuation": { 1299 pattern: /^`|`$/, 1300 alias: "string" 1301 }, 1302 "interpolation": { 1303 pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/, 1304 lookbehind: true, 1305 inside: { 1306 "interpolation-punctuation": { 1307 pattern: /^\$\{|\}$/, 1308 alias: "punctuation" 1309 }, 1310 rest: Prism3.languages.javascript 1311 } 1312 }, 1313 "string": /[\s\S]+/ 1314 } 1315 }, 1316 "string-property": { 1317 pattern: /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m, 1318 lookbehind: true, 1319 greedy: true, 1320 alias: "property" 1321 } 1322 }); 1323 Prism3.languages.insertBefore("javascript", "operator", { 1324 "literal-property": { 1325 pattern: /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m, 1326 lookbehind: true, 1327 alias: "property" 1328 } 1329 }); 1330 if (Prism3.languages.markup) { 1331 Prism3.languages.markup.tag.addInlined("script", "javascript"); 1332 Prism3.languages.markup.tag.addAttribute( 1333 /on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source, 1334 "javascript" 1335 ); 1336 } 1337 Prism3.languages.js = Prism3.languages.javascript; 1338 (function() { 1339 if (typeof Prism3 === "undefined" || typeof document === "undefined") { 1340 return; 1341 } 1342 if (!Element.prototype.matches) { 1343 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 1344 } 1345 var LOADING_MESSAGE = "Loading\u2026"; 1346 var FAILURE_MESSAGE = function(status, message) { 1347 return "\u2716 Error " + status + " while fetching file: " + message; 1348 }; 1349 var FAILURE_EMPTY_MESSAGE = "\u2716 Error: File does not exist or is empty"; 1350 var EXTENSIONS = { 1351 "js": "javascript", 1352 "py": "python", 1353 "rb": "ruby", 1354 "ps1": "powershell", 1355 "psm1": "powershell", 1356 "sh": "bash", 1357 "bat": "batch", 1358 "h": "c", 1359 "tex": "latex" 1360 }; 1361 var STATUS_ATTR = "data-src-status"; 1362 var STATUS_LOADING = "loading"; 1363 var STATUS_LOADED = "loaded"; 1364 var STATUS_FAILED = "failed"; 1365 var SELECTOR = "pre[data-src]:not([" + STATUS_ATTR + '="' + STATUS_LOADED + '"]):not([' + STATUS_ATTR + '="' + STATUS_LOADING + '"])'; 1366 function loadFile(src, success, error) { 1367 var xhr = new XMLHttpRequest(); 1368 xhr.open("GET", src, true); 1369 xhr.onreadystatechange = function() { 1370 if (xhr.readyState == 4) { 1371 if (xhr.status < 400 && xhr.responseText) { 1372 success(xhr.responseText); 1373 } else { 1374 if (xhr.status >= 400) { 1375 error(FAILURE_MESSAGE(xhr.status, xhr.statusText)); 1376 } else { 1377 error(FAILURE_EMPTY_MESSAGE); 1378 } 1379 } 1380 } 1381 }; 1382 xhr.send(null); 1383 } 1384 function parseRange(range2) { 1385 var m3 = /^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(range2 || ""); 1386 if (m3) { 1387 var start3 = Number(m3[1]); 1388 var comma = m3[2]; 1389 var end = m3[3]; 1390 if (!comma) { 1391 return [start3, start3]; 1392 } 1393 if (!end) { 1394 return [start3, void 0]; 1395 } 1396 return [start3, Number(end)]; 1397 } 1398 return void 0; 1399 } 1400 Prism3.hooks.add("before-highlightall", function(env) { 1401 env.selector += ", " + SELECTOR; 1402 }); 1403 Prism3.hooks.add("before-sanity-check", function(env) { 1404 var pre = ( 1405 /** @type {HTMLPreElement} */ 1406 env.element 1407 ); 1408 if (pre.matches(SELECTOR)) { 1409 env.code = ""; 1410 pre.setAttribute(STATUS_ATTR, STATUS_LOADING); 1411 var code = pre.appendChild(document.createElement("CODE")); 1412 code.textContent = LOADING_MESSAGE; 1413 var src = pre.getAttribute("data-src"); 1414 var language = env.language; 1415 if (language === "none") { 1416 var extension = (/\.(\w+)$/.exec(src) || [, "none"])[1]; 1417 language = EXTENSIONS[extension] || extension; 1418 } 1419 Prism3.util.setLanguage(code, language); 1420 Prism3.util.setLanguage(pre, language); 1421 var autoloader = Prism3.plugins.autoloader; 1422 if (autoloader) { 1423 autoloader.loadLanguages(language); 1424 } 1425 loadFile( 1426 src, 1427 function(text2) { 1428 pre.setAttribute(STATUS_ATTR, STATUS_LOADED); 1429 var range2 = parseRange(pre.getAttribute("data-range")); 1430 if (range2) { 1431 var lines = text2.split(/\r\n?|\n/g); 1432 var start3 = range2[0]; 1433 var end = range2[1] == null ? lines.length : range2[1]; 1434 if (start3 < 0) { 1435 start3 += lines.length; 1436 } 1437 start3 = Math.max(0, Math.min(start3 - 1, lines.length)); 1438 if (end < 0) { 1439 end += lines.length; 1440 } 1441 end = Math.max(0, Math.min(end, lines.length)); 1442 text2 = lines.slice(start3, end).join("\n"); 1443 if (!pre.hasAttribute("data-start")) { 1444 pre.setAttribute("data-start", String(start3 + 1)); 1445 } 1446 } 1447 code.textContent = text2; 1448 Prism3.highlightElement(code); 1449 }, 1450 function(error) { 1451 pre.setAttribute(STATUS_ATTR, STATUS_FAILED); 1452 code.textContent = error; 1453 } 1454 ); 1455 } 1456 }); 1457 Prism3.plugins.fileHighlight = { 1458 /** 1459 * Executes the File Highlight plugin for all matching `pre` elements under the given container. 1460 * 1461 * Note: Elements which are already loaded or currently loading will not be touched by this method. 1462 * 1463 * @param {ParentNode} [container=document] 1464 */ 1465 highlight: function highlight(container) { 1466 var elements = (container || document).querySelectorAll(SELECTOR); 1467 for (var i2 = 0, element; element = elements[i2++]; ) { 1468 Prism3.highlightElement(element); 1469 } 1470 } 1471 }; 1472 var logged = false; 1473 Prism3.fileHighlight = function() { 1474 if (!logged) { 1475 console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."); 1476 logged = true; 1477 } 1478 Prism3.plugins.fileHighlight.highlight.apply(this, arguments); 1479 }; 1480 })(); 1481 } 1482 }); 1483 1484
vendor: 34,211 bytes, lines 1484-2351
1484// node_modules/@rails/activestorage/app/assets/javascripts/activestorage.esm.js 1485 var activestorage_esm_exports = {}; 1486 __export(activestorage_esm_exports, { 1487 DirectUpload: () => DirectUpload, 1488 DirectUploadController: () => DirectUploadController, 1489 DirectUploadsController: () => DirectUploadsController, 1490 dispatchEvent: () => dispatchEvent, 1491 start: () => start 1492 }); 1493 function getMetaValue(name) { 1494 const element = findElement(document.head, `meta[name="${name}"]`); 1495 if (element) { 1496 return element.getAttribute("content"); 1497 } 1498 } 1499 function findElements(root, selector) { 1500 if (typeof root == "string") { 1501 selector = root; 1502 root = document; 1503 } 1504 const elements = root.querySelectorAll(selector); 1505 return toArray(elements); 1506 } 1507 function findElement(root, selector) { 1508 if (typeof root == "string") { 1509 selector = root; 1510 root = document; 1511 } 1512 return root.querySelector(selector); 1513 } 1514 function dispatchEvent(element, type, eventInit = {}) { 1515 const { disabled } = element; 1516 const { bubbles, cancelable, detail } = eventInit; 1517 const event = document.createEvent("Event"); 1518 event.initEvent(type, bubbles || true, cancelable || true); 1519 event.detail = detail || {}; 1520 try { 1521 element.disabled = false; 1522 element.dispatchEvent(event); 1523 } finally { 1524 element.disabled = disabled; 1525 } 1526 return event; 1527 } 1528 function toArray(value) { 1529 if (Array.isArray(value)) { 1530 return value; 1531 } else if (Array.from) { 1532 return Array.from(value); 1533 } else { 1534 return [].slice.call(value); 1535 } 1536 } 1537 function notify(object, methodName, ...messages) { 1538 if (object && typeof object[methodName] == "function") { 1539 return object[methodName](...messages); 1540 } 1541 } 1542 function start() { 1543 if (!started) { 1544 started = true; 1545 document.addEventListener("click", didClick, true); 1546 document.addEventListener("submit", didSubmitForm, true); 1547 document.addEventListener("ajax:before", didSubmitRemoteElement); 1548 } 1549 } 1550 function didClick(event) { 1551 const button = event.target.closest("button, input"); 1552 if (button && button.type === "submit" && button.form) { 1553 submitButtonsByForm.set(button.form, button); 1554 } 1555 } 1556 function didSubmitForm(event) { 1557 handleFormSubmissionEvent(event); 1558 } 1559 function didSubmitRemoteElement(event) { 1560 if (event.target.tagName == "FORM") { 1561 handleFormSubmissionEvent(event); 1562 } 1563 } 1564 function handleFormSubmissionEvent(event) { 1565 const form = event.target; 1566 if (form.hasAttribute(processingAttribute)) { 1567 event.preventDefault(); 1568 return; 1569 } 1570 const controller = new DirectUploadsController(form); 1571 const { inputs } = controller; 1572 if (inputs.length) { 1573 event.preventDefault(); 1574 form.setAttribute(processingAttribute, ""); 1575 inputs.forEach(disable); 1576 controller.start((error) => { 1577 form.removeAttribute(processingAttribute); 1578 if (error) { 1579 inputs.forEach(enable); 1580 } else { 1581 submitForm(form); 1582 } 1583 }); 1584 } 1585 } 1586 function submitForm(form) { 1587 let button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit], button[type=submit]"); 1588 if (button) { 1589 const { disabled } = button; 1590 button.disabled = false; 1591 button.focus(); 1592 button.click(); 1593 button.disabled = disabled; 1594 } else { 1595 button = document.createElement("input"); 1596 button.type = "submit"; 1597 button.style.display = "none"; 1598 form.appendChild(button); 1599 button.click(); 1600 form.removeChild(button); 1601 } 1602 submitButtonsByForm.delete(form); 1603 } 1604 function disable(input) { 1605 input.disabled = true; 1606 } 1607 function enable(input) { 1608 input.disabled = false; 1609 } 1610 function autostart() { 1611 if (window.ActiveStorage) { 1612 start(); 1613 } 1614 } 1615 var sparkMd5, SparkMD5, fileSlice, FileChecksum, BlobRecord, BlobUpload, id, DirectUpload, DirectUploadController, inputSelector, DirectUploadsController, processingAttribute, submitButtonsByForm, started; 1616 var init_activestorage_esm = __esm({ 1617 "node_modules/@rails/activestorage/app/assets/javascripts/activestorage.esm.js"() { 1618 sparkMd5 = { 1619 exports: {} 1620 }; 1621 (function(module, exports) { 1622 (function(factory) { 1623 { 1624 module.exports = factory(); 1625 } 1626 })(function(undefined$1) { 1627 var hex_chr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]; 1628 function md5cycle(x3, k2) { 1629 var a2 = x3[0], b3 = x3[1], c2 = x3[2], d3 = x3[3]; 1630 a2 += (b3 & c2 | ~b3 & d3) + k2[0] - 680876936 | 0; 1631 a2 = (a2 << 7 | a2 >>> 25) + b3 | 0; 1632 d3 += (a2 & b3 | ~a2 & c2) + k2[1] - 389564586 | 0; 1633 d3 = (d3 << 12 | d3 >>> 20) + a2 | 0; 1634 c2 += (d3 & a2 | ~d3 & b3) + k2[2] + 606105819 | 0; 1635 c2 = (c2 << 17 | c2 >>> 15) + d3 | 0; 1636 b3 += (c2 & d3 | ~c2 & a2) + k2[3] - 1044525330 | 0; 1637 b3 = (b3 << 22 | b3 >>> 10) + c2 | 0; 1638 a2 += (b3 & c2 | ~b3 & d3) + k2[4] - 176418897 | 0; 1639 a2 = (a2 << 7 | a2 >>> 25) + b3 | 0; 1640 d3 += (a2 & b3 | ~a2 & c2) + k2[5] + 1200080426 | 0; 1641 d3 = (d3 << 12 | d3 >>> 20) + a2 | 0; 1642 c2 += (d3 & a2 | ~d3 & b3) + k2[6] - 1473231341 | 0; 1643 c2 = (c2 << 17 | c2 >>> 15) + d3 | 0; 1644 b3 += (c2 & d3 | ~c2 & a2) + k2[7] - 45705983 | 0; 1645 b3 = (b3 << 22 | b3 >>> 10) + c2 | 0; 1646 a2 += (b3 & c2 | ~b3 & d3) + k2[8] + 1770035416 | 0; 1647 a2 = (a2 << 7 | a2 >>> 25) + b3 | 0; 1648 d3 += (a2 & b3 | ~a2 & c2) + k2[9] - 1958414417 | 0; 1649 d3 = (d3 << 12 | d3 >>> 20) + a2 | 0; 1650 c2 += (d3 & a2 | ~d3 & b3) + k2[10] - 42063 | 0; 1651 c2 = (c2 << 17 | c2 >>> 15) + d3 | 0; 1652 b3 += (c2 & d3 | ~c2 & a2) + k2[11] - 1990404162 | 0; 1653 b3 = (b3 << 22 | b3 >>> 10) + c2 | 0; 1654 a2 += (b3 & c2 | ~b3 & d3) + k2[12] + 1804603682 | 0; 1655 a2 = (a2 << 7 | a2 >>> 25) + b3 | 0; 1656 d3 += (a2 & b3 | ~a2 & c2) + k2[13] - 40341101 | 0; 1657 d3 = (d3 << 12 | d3 >>> 20) + a2 | 0; 1658 c2 += (d3 & a2 | ~d3 & b3) + k2[14] - 1502002290 | 0; 1659 c2 = (c2 << 17 | c2 >>> 15) + d3 | 0; 1660 b3 += (c2 & d3 | ~c2 & a2) + k2[15] + 1236535329 | 0; 1661 b3 = (b3 << 22 | b3 >>> 10) + c2 | 0; 1662 a2 += (b3 & d3 | c2 & ~d3) + k2[1] - 165796510 | 0; 1663 a2 = (a2 << 5 | a2 >>> 27) + b3 | 0; 1664 d3 += (a2 & c2 | b3 & ~c2) + k2[6] - 1069501632 | 0; 1665 d3 = (d3 << 9 | d3 >>> 23) + a2 | 0; 1666 c2 += (d3 & b3 | a2 & ~b3) + k2[11] + 643717713 | 0; 1667 c2 = (c2 << 14 | c2 >>> 18) + d3 | 0; 1668 b3 += (c2 & a2 | d3 & ~a2) + k2[0] - 373897302 | 0; 1669 b3 = (b3 << 20 | b3 >>> 12) + c2 | 0; 1670 a2 += (b3 & d3 | c2 & ~d3) + k2[5] - 701558691 | 0; 1671 a2 = (a2 << 5 | a2 >>> 27) + b3 | 0; 1672 d3 += (a2 & c2 | b3 & ~c2) + k2[10] + 38016083 | 0; 1673 d3 = (d3 << 9 | d3 >>> 23) + a2 | 0; 1674 c2 += (d3 & b3 | a2 & ~b3) + k2[15] - 660478335 | 0; 1675 c2 = (c2 << 14 | c2 >>> 18) + d3 | 0; 1676 b3 += (c2 & a2 | d3 & ~a2) + k2[4] - 405537848 | 0; 1677 b3 = (b3 << 20 | b3 >>> 12) + c2 | 0; 1678 a2 += (b3 & d3 | c2 & ~d3) + k2[9] + 568446438 | 0; 1679 a2 = (a2 << 5 | a2 >>> 27) + b3 | 0; 1680 d3 += (a2 & c2 | b3 & ~c2) + k2[14] - 1019803690 | 0; 1681 d3 = (d3 << 9 | d3 >>> 23) + a2 | 0; 1682 c2 += (d3 & b3 | a2 & ~b3) + k2[3] - 187363961 | 0; 1683 c2 = (c2 << 14 | c2 >>> 18) + d3 | 0; 1684 b3 += (c2 & a2 | d3 & ~a2) + k2[8] + 1163531501 | 0; 1685 b3 = (b3 << 20 | b3 >>> 12) + c2 | 0; 1686 a2 += (b3 & d3 | c2 & ~d3) + k2[13] - 1444681467 | 0; 1687 a2 = (a2 << 5 | a2 >>> 27) + b3 | 0; 1688 d3 += (a2 & c2 | b3 & ~c2) + k2[2] - 51403784 | 0; 1689 d3 = (d3 << 9 | d3 >>> 23) + a2 | 0; 1690 c2 += (d3 & b3 | a2 & ~b3) + k2[7] + 1735328473 | 0; 1691 c2 = (c2 << 14 | c2 >>> 18) + d3 | 0; 1692 b3 += (c2 & a2 | d3 & ~a2) + k2[12] - 1926607734 | 0; 1693 b3 = (b3 << 20 | b3 >>> 12) + c2 | 0; 1694 a2 += (b3 ^ c2 ^ d3) + k2[5] - 378558 | 0; 1695 a2 = (a2 << 4 | a2 >>> 28) + b3 | 0; 1696 d3 += (a2 ^ b3 ^ c2) + k2[8] - 2022574463 | 0; 1697 d3 = (d3 << 11 | d3 >>> 21) + a2 | 0; 1698 c2 += (d3 ^ a2 ^ b3) + k2[11] + 1839030562 | 0; 1699 c2 = (c2 << 16 | c2 >>> 16) + d3 | 0; 1700 b3 += (c2 ^ d3 ^ a2) + k2[14] - 35309556 | 0; 1701 b3 = (b3 << 23 | b3 >>> 9) + c2 | 0; 1702 a2 += (b3 ^ c2 ^ d3) + k2[1] - 1530992060 | 0; 1703 a2 = (a2 << 4 | a2 >>> 28) + b3 | 0; 1704 d3 += (a2 ^ b3 ^ c2) + k2[4] + 1272893353 | 0; 1705 d3 = (d3 << 11 | d3 >>> 21) + a2 | 0; 1706 c2 += (d3 ^ a2 ^ b3) + k2[7] - 155497632 | 0; 1707 c2 = (c2 << 16 | c2 >>> 16) + d3 | 0; 1708 b3 += (c2 ^ d3 ^ a2) + k2[10] - 1094730640 | 0; 1709 b3 = (b3 << 23 | b3 >>> 9) + c2 | 0; 1710 a2 += (b3 ^ c2 ^ d3) + k2[13] + 681279174 | 0; 1711 a2 = (a2 << 4 | a2 >>> 28) + b3 | 0; 1712 d3 += (a2 ^ b3 ^ c2) + k2[0] - 358537222 | 0; 1713 d3 = (d3 << 11 | d3 >>> 21) + a2 | 0; 1714 c2 += (d3 ^ a2 ^ b3) + k2[3] - 722521979 | 0; 1715 c2 = (c2 << 16 | c2 >>> 16) + d3 | 0; 1716 b3 += (c2 ^ d3 ^ a2) + k2[6] + 76029189 | 0; 1717 b3 = (b3 << 23 | b3 >>> 9) + c2 | 0; 1718 a2 += (b3 ^ c2 ^ d3) + k2[9] - 640364487 | 0; 1719 a2 = (a2 << 4 | a2 >>> 28) + b3 | 0; 1720 d3 += (a2 ^ b3 ^ c2) + k2[12] - 421815835 | 0; 1721 d3 = (d3 << 11 | d3 >>> 21) + a2 | 0; 1722 c2 += (d3 ^ a2 ^ b3) + k2[15] + 530742520 | 0; 1723 c2 = (c2 << 16 | c2 >>> 16) + d3 | 0; 1724 b3 += (c2 ^ d3 ^ a2) + k2[2] - 995338651 | 0; 1725 b3 = (b3 << 23 | b3 >>> 9) + c2 | 0; 1726 a2 += (c2 ^ (b3 | ~d3)) + k2[0] - 198630844 | 0; 1727 a2 = (a2 << 6 | a2 >>> 26) + b3 | 0; 1728 d3 += (b3 ^ (a2 | ~c2)) + k2[7] + 1126891415 | 0; 1729 d3 = (d3 << 10 | d3 >>> 22) + a2 | 0; 1730 c2 += (a2 ^ (d3 | ~b3)) + k2[14] - 1416354905 | 0; 1731 c2 = (c2 << 15 | c2 >>> 17) + d3 | 0; 1732 b3 += (d3 ^ (c2 | ~a2)) + k2[5] - 57434055 | 0; 1733 b3 = (b3 << 21 | b3 >>> 11) + c2 | 0; 1734 a2 += (c2 ^ (b3 | ~d3)) + k2[12] + 1700485571 | 0; 1735 a2 = (a2 << 6 | a2 >>> 26) + b3 | 0; 1736 d3 += (b3 ^ (a2 | ~c2)) + k2[3] - 1894986606 | 0; 1737 d3 = (d3 << 10 | d3 >>> 22) + a2 | 0; 1738 c2 += (a2 ^ (d3 | ~b3)) + k2[10] - 1051523 | 0; 1739 c2 = (c2 << 15 | c2 >>> 17) + d3 | 0; 1740 b3 += (d3 ^ (c2 | ~a2)) + k2[1] - 2054922799 | 0; 1741 b3 = (b3 << 21 | b3 >>> 11) + c2 | 0; 1742 a2 += (c2 ^ (b3 | ~d3)) + k2[8] + 1873313359 | 0; 1743 a2 = (a2 << 6 | a2 >>> 26) + b3 | 0; 1744 d3 += (b3 ^ (a2 | ~c2)) + k2[15] - 30611744 | 0; 1745 d3 = (d3 << 10 | d3 >>> 22) + a2 | 0; 1746 c2 += (a2 ^ (d3 | ~b3)) + k2[6] - 1560198380 | 0; 1747 c2 = (c2 << 15 | c2 >>> 17) + d3 | 0; 1748 b3 += (d3 ^ (c2 | ~a2)) + k2[13] + 1309151649 | 0; 1749 b3 = (b3 << 21 | b3 >>> 11) + c2 | 0; 1750 a2 += (c2 ^ (b3 | ~d3)) + k2[4] - 145523070 | 0; 1751 a2 = (a2 << 6 | a2 >>> 26) + b3 | 0; 1752 d3 += (b3 ^ (a2 | ~c2)) + k2[11] - 1120210379 | 0; 1753 d3 = (d3 << 10 | d3 >>> 22) + a2 | 0; 1754 c2 += (a2 ^ (d3 | ~b3)) + k2[2] + 718787259 | 0; 1755 c2 = (c2 << 15 | c2 >>> 17) + d3 | 0; 1756 b3 += (d3 ^ (c2 | ~a2)) + k2[9] - 343485551 | 0; 1757 b3 = (b3 << 21 | b3 >>> 11) + c2 | 0; 1758 x3[0] = a2 + x3[0] | 0; 1759 x3[1] = b3 + x3[1] | 0; 1760 x3[2] = c2 + x3[2] | 0; 1761 x3[3] = d3 + x3[3] | 0; 1762 } 1763 function md5blk(s2) { 1764 var md5blks = [], i2; 1765 for (i2 = 0; i2 < 64; i2 += 4) { 1766 md5blks[i2 >> 2] = s2.charCodeAt(i2) + (s2.charCodeAt(i2 + 1) << 8) + (s2.charCodeAt(i2 + 2) << 16) + (s2.charCodeAt(i2 + 3) << 24); 1767 } 1768 return md5blks; 1769 } 1770 function md5blk_array(a2) { 1771 var md5blks = [], i2; 1772 for (i2 = 0; i2 < 64; i2 += 4) { 1773 md5blks[i2 >> 2] = a2[i2] + (a2[i2 + 1] << 8) + (a2[i2 + 2] << 16) + (a2[i2 + 3] << 24); 1774 } 1775 return md5blks; 1776 } 1777 function md51(s2) { 1778 var n2 = s2.length, state = [1732584193, -271733879, -1732584194, 271733878], i2, length, tail, tmp, lo, hi; 1779 for (i2 = 64; i2 <= n2; i2 += 64) { 1780 md5cycle(state, md5blk(s2.substring(i2 - 64, i2))); 1781 } 1782 s2 = s2.substring(i2 - 64); 1783 length = s2.length; 1784 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 1785 for (i2 = 0; i2 < length; i2 += 1) { 1786 tail[i2 >> 2] |= s2.charCodeAt(i2) << (i2 % 4 << 3); 1787 } 1788 tail[i2 >> 2] |= 128 << (i2 % 4 << 3); 1789 if (i2 > 55) { 1790 md5cycle(state, tail); 1791 for (i2 = 0; i2 < 16; i2 += 1) { 1792 tail[i2] = 0; 1793 } 1794 } 1795 tmp = n2 * 8; 1796 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); 1797 lo = parseInt(tmp[2], 16); 1798 hi = parseInt(tmp[1], 16) || 0; 1799 tail[14] = lo; 1800 tail[15] = hi; 1801 md5cycle(state, tail); 1802 return state; 1803 } 1804 function md51_array(a2) { 1805 var n2 = a2.length, state = [1732584193, -271733879, -1732584194, 271733878], i2, length, tail, tmp, lo, hi; 1806 for (i2 = 64; i2 <= n2; i2 += 64) { 1807 md5cycle(state, md5blk_array(a2.subarray(i2 - 64, i2))); 1808 } 1809 a2 = i2 - 64 < n2 ? a2.subarray(i2 - 64) : new Uint8Array(0); 1810 length = a2.length; 1811 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 1812 for (i2 = 0; i2 < length; i2 += 1) { 1813 tail[i2 >> 2] |= a2[i2] << (i2 % 4 << 3); 1814 } 1815 tail[i2 >> 2] |= 128 << (i2 % 4 << 3); 1816 if (i2 > 55) { 1817 md5cycle(state, tail); 1818 for (i2 = 0; i2 < 16; i2 += 1) { 1819 tail[i2] = 0; 1820 } 1821 } 1822 tmp = n2 * 8; 1823 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); 1824 lo = parseInt(tmp[2], 16); 1825 hi = parseInt(tmp[1], 16) || 0; 1826 tail[14] = lo; 1827 tail[15] = hi; 1828 md5cycle(state, tail); 1829 return state; 1830 } 1831 function rhex(n2) { 1832 var s2 = "", j3; 1833 for (j3 = 0; j3 < 4; j3 += 1) { 1834 s2 += hex_chr[n2 >> j3 * 8 + 4 & 15] + hex_chr[n2 >> j3 * 8 & 15]; 1835 } 1836 return s2; 1837 } 1838 function hex(x3) { 1839 var i2; 1840 for (i2 = 0; i2 < x3.length; i2 += 1) { 1841 x3[i2] = rhex(x3[i2]); 1842 } 1843 return x3.join(""); 1844 } 1845 if (hex(md51("hello")) !== "5d41402abc4b2a76b9719d911017c592") ; 1846 if (typeof ArrayBuffer !== "undefined" && !ArrayBuffer.prototype.slice) { 1847 (function() { 1848 function clamp2(val, length) { 1849 val = val | 0 || 0; 1850 if (val < 0) { 1851 return Math.max(val + length, 0); 1852 } 1853 return Math.min(val, length); 1854 } 1855 ArrayBuffer.prototype.slice = function(from, to) { 1856 var length = this.byteLength, begin = clamp2(from, length), end = length, num, target, targetArray, sourceArray; 1857 if (to !== undefined$1) { 1858 end = clamp2(to, length); 1859 } 1860 if (begin > end) { 1861 return new ArrayBuffer(0); 1862 } 1863 num = end - begin; 1864 target = new ArrayBuffer(num); 1865 targetArray = new Uint8Array(target); 1866 sourceArray = new Uint8Array(this, begin, num); 1867 targetArray.set(sourceArray); 1868 return target; 1869 }; 1870 })(); 1871 } 1872 function toUtf8(str) { 1873 if (/[\u0080-\uFFFF]/.test(str)) { 1874 str = unescape(encodeURIComponent(str)); 1875 } 1876 return str; 1877 } 1878 function utf8Str2ArrayBuffer(str, returnUInt8Array) { 1879 var length = str.length, buff = new ArrayBuffer(length), arr = new Uint8Array(buff), i2; 1880 for (i2 = 0; i2 < length; i2 += 1) { 1881 arr[i2] = str.charCodeAt(i2); 1882 } 1883 return returnUInt8Array ? arr : buff; 1884 } 1885 function arrayBuffer2Utf8Str(buff) { 1886 return String.fromCharCode.apply(null, new Uint8Array(buff)); 1887 } 1888 function concatenateArrayBuffers(first, second, returnUInt8Array) { 1889 var result = new Uint8Array(first.byteLength + second.byteLength); 1890 result.set(new Uint8Array(first)); 1891 result.set(new Uint8Array(second), first.byteLength); 1892 return returnUInt8Array ? result : result.buffer; 1893 } 1894 function hexToBinaryString(hex2) { 1895 var bytes = [], length = hex2.length, x3; 1896 for (x3 = 0; x3 < length - 1; x3 += 2) { 1897 bytes.push(parseInt(hex2.substr(x3, 2), 16)); 1898 } 1899 return String.fromCharCode.apply(String, bytes); 1900 } 1901 function SparkMD53() { 1902 this.reset(); 1903 } 1904 SparkMD53.prototype.append = function(str) { 1905 this.appendBinary(toUtf8(str)); 1906 return this; 1907 }; 1908 SparkMD53.prototype.appendBinary = function(contents) { 1909 this._buff += contents; 1910 this._length += contents.length; 1911 var length = this._buff.length, i2; 1912 for (i2 = 64; i2 <= length; i2 += 64) { 1913 md5cycle(this._hash, md5blk(this._buff.substring(i2 - 64, i2))); 1914 } 1915 this._buff = this._buff.substring(i2 - 64); 1916 return this; 1917 }; 1918 SparkMD53.prototype.end = function(raw) { 1919 var buff = this._buff, length = buff.length, i2, tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ret; 1920 for (i2 = 0; i2 < length; i2 += 1) { 1921 tail[i2 >> 2] |= buff.charCodeAt(i2) << (i2 % 4 << 3); 1922 } 1923 this._finish(tail, length); 1924 ret = hex(this._hash); 1925 if (raw) { 1926 ret = hexToBinaryString(ret); 1927 } 1928 this.reset(); 1929 return ret; 1930 }; 1931 SparkMD53.prototype.reset = function() { 1932 this._buff = ""; 1933 this._length = 0; 1934 this._hash = [1732584193, -271733879, -1732584194, 271733878]; 1935 return this; 1936 }; 1937 SparkMD53.prototype.getState = function() { 1938 return { 1939 buff: this._buff, 1940 length: this._length, 1941 hash: this._hash.slice() 1942 }; 1943 }; 1944 SparkMD53.prototype.setState = function(state) { 1945 this._buff = state.buff; 1946 this._length = state.length; 1947 this._hash = state.hash; 1948 return this; 1949 }; 1950 SparkMD53.prototype.destroy = function() { 1951 delete this._hash; 1952 delete this._buff; 1953 delete this._length; 1954 }; 1955 SparkMD53.prototype._finish = function(tail, length) { 1956 var i2 = length, tmp, lo, hi; 1957 tail[i2 >> 2] |= 128 << (i2 % 4 << 3); 1958 if (i2 > 55) { 1959 md5cycle(this._hash, tail); 1960 for (i2 = 0; i2 < 16; i2 += 1) { 1961 tail[i2] = 0; 1962 } 1963 } 1964 tmp = this._length * 8; 1965 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); 1966 lo = parseInt(tmp[2], 16); 1967 hi = parseInt(tmp[1], 16) || 0; 1968 tail[14] = lo; 1969 tail[15] = hi; 1970 md5cycle(this._hash, tail); 1971 }; 1972 SparkMD53.hash = function(str, raw) { 1973 return SparkMD53.hashBinary(toUtf8(str), raw); 1974 }; 1975 SparkMD53.hashBinary = function(content, raw) { 1976 var hash = md51(content), ret = hex(hash); 1977 return raw ? hexToBinaryString(ret) : ret; 1978 }; 1979 SparkMD53.ArrayBuffer = function() { 1980 this.reset(); 1981 }; 1982 SparkMD53.ArrayBuffer.prototype.append = function(arr) { 1983 var buff = concatenateArrayBuffers(this._buff.buffer, arr, true), length = buff.length, i2; 1984 this._length += arr.byteLength; 1985 for (i2 = 64; i2 <= length; i2 += 64) { 1986 md5cycle(this._hash, md5blk_array(buff.subarray(i2 - 64, i2))); 1987 } 1988 this._buff = i2 - 64 < length ? new Uint8Array(buff.buffer.slice(i2 - 64)) : new Uint8Array(0); 1989 return this; 1990 }; 1991 SparkMD53.ArrayBuffer.prototype.end = function(raw) { 1992 var buff = this._buff, length = buff.length, tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], i2, ret; 1993 for (i2 = 0; i2 < length; i2 += 1) { 1994 tail[i2 >> 2] |= buff[i2] << (i2 % 4 << 3); 1995 } 1996 this._finish(tail, length); 1997 ret = hex(this._hash); 1998 if (raw) { 1999 ret = hexToBinaryString(ret); 2000 } 2001 this.reset(); 2002 return ret; 2003 }; 2004 SparkMD53.ArrayBuffer.prototype.reset = function() { 2005 this._buff = new Uint8Array(0); 2006 this._length = 0; 2007 this._hash = [1732584193, -271733879, -1732584194, 271733878]; 2008 return this; 2009 }; 2010 SparkMD53.ArrayBuffer.prototype.getState = function() { 2011 var state = SparkMD53.prototype.getState.call(this); 2012 state.buff = arrayBuffer2Utf8Str(state.buff); 2013 return state; 2014 }; 2015 SparkMD53.ArrayBuffer.prototype.setState = function(state) { 2016 state.buff = utf8Str2ArrayBuffer(state.buff, true); 2017 return SparkMD53.prototype.setState.call(this, state); 2018 }; 2019 SparkMD53.ArrayBuffer.prototype.destroy = SparkMD53.prototype.destroy; 2020 SparkMD53.ArrayBuffer.prototype._finish = SparkMD53.prototype._finish; 2021 SparkMD53.ArrayBuffer.hash = function(arr, raw) { 2022 var hash = md51_array(new Uint8Array(arr)), ret = hex(hash); 2023 return raw ? hexToBinaryString(ret) : ret; 2024 }; 2025 return SparkMD53; 2026 }); 2027 })(sparkMd5); 2028 SparkMD5 = sparkMd5.exports; 2029 fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; 2030 FileChecksum = class _FileChecksum { 2031 static create(file, callback) { 2032 const instance = new _FileChecksum(file); 2033 instance.create(callback); 2034 } 2035 constructor(file) { 2036 this.file = file; 2037 this.chunkSize = 2097152; 2038 this.chunkCount = Math.ceil(this.file.size / this.chunkSize); 2039 this.chunkIndex = 0; 2040 } 2041 create(callback) { 2042 this.callback = callback; 2043 this.md5Buffer = new SparkMD5.ArrayBuffer(); 2044 this.fileReader = new FileReader(); 2045 this.fileReader.addEventListener("load", (event) => this.fileReaderDidLoad(event)); 2046 this.fileReader.addEventListener("error", (event) => this.fileReaderDidError(event)); 2047 this.readNextChunk(); 2048 } 2049 fileReaderDidLoad(event) { 2050 this.md5Buffer.append(event.target.result); 2051 if (!this.readNextChunk()) { 2052 const binaryDigest = this.md5Buffer.end(true); 2053 const base64digest = btoa(binaryDigest); 2054 this.callback(null, base64digest); 2055 } 2056 } 2057 fileReaderDidError(event) { 2058 this.callback(`Error reading ${this.file.name}`); 2059 } 2060 readNextChunk() { 2061 if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) { 2062 const start3 = this.chunkIndex * this.chunkSize; 2063 const end = Math.min(start3 + this.chunkSize, this.file.size); 2064 const bytes = fileSlice.call(this.file, start3, end); 2065 this.fileReader.readAsArrayBuffer(bytes); 2066 this.chunkIndex++; 2067 return true; 2068 } else { 2069 return false; 2070 } 2071 } 2072 }; 2073 BlobRecord = class { 2074 constructor(file, checksum, url, customHeaders = {}) { 2075 this.file = file; 2076 this.attributes = { 2077 filename: file.name, 2078 content_type: file.type || "application/octet-stream", 2079 byte_size: file.size, 2080 checksum 2081 }; 2082 this.xhr = new XMLHttpRequest(); 2083 this.xhr.open("POST", url, true); 2084 this.xhr.responseType = "json"; 2085 this.xhr.setRequestHeader("Content-Type", "application/json"); 2086 this.xhr.setRequestHeader("Accept", "application/json"); 2087 this.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 2088 Object.keys(customHeaders).forEach((headerKey) => { 2089 this.xhr.setRequestHeader(headerKey, customHeaders[headerKey]); 2090 }); 2091 const csrfToken = getMetaValue("csrf-token"); 2092 if (csrfToken != void 0) { 2093 this.xhr.setRequestHeader("X-CSRF-Token", csrfToken); 2094 } 2095 this.xhr.addEventListener("load", (event) => this.requestDidLoad(event)); 2096 this.xhr.addEventListener("error", (event) => this.requestDidError(event)); 2097 } 2098 get status() { 2099 return this.xhr.status; 2100 } 2101 get response() { 2102 const { responseType, response } = this.xhr; 2103 if (responseType == "json") { 2104 return response; 2105 } else { 2106 return JSON.parse(response); 2107 } 2108 } 2109 create(callback) { 2110 this.callback = callback; 2111 this.xhr.send(JSON.stringify({ 2112 blob: this.attributes 2113 })); 2114 } 2115 requestDidLoad(event) { 2116 if (this.status >= 200 && this.status < 300) { 2117 const { response } = this; 2118 const { direct_upload } = response; 2119 delete response.direct_upload; 2120 this.attributes = response; 2121 this.directUploadData = direct_upload; 2122 this.callback(null, this.toJSON()); 2123 } else { 2124 this.requestDidError(event); 2125 } 2126 } 2127 requestDidError(event) { 2128 this.callback(`Error creating Blob for "${this.file.name}". Status: ${this.status}`); 2129 } 2130 toJSON() { 2131 const result = {}; 2132 for (const key in this.attributes) { 2133 result[key] = this.attributes[key]; 2134 } 2135 return result; 2136 } 2137 }; 2138 BlobUpload = class { 2139 constructor(blob) { 2140 this.blob = blob; 2141 this.file = blob.file; 2142 const { url, headers } = blob.directUploadData; 2143 this.xhr = new XMLHttpRequest(); 2144 this.xhr.open("PUT", url, true); 2145 this.xhr.responseType = "text"; 2146 for (const key in headers) { 2147 this.xhr.setRequestHeader(key, headers[key]); 2148 } 2149 this.xhr.addEventListener("load", (event) => this.requestDidLoad(event)); 2150 this.xhr.addEventListener("error", (event) => this.requestDidError(event)); 2151 } 2152 create(callback) { 2153 this.callback = callback; 2154 this.xhr.send(this.file.slice()); 2155 } 2156 requestDidLoad(event) { 2157 const { status, response } = this.xhr; 2158 if (status >= 200 && status < 300) { 2159 this.callback(null, response); 2160 } else { 2161 this.requestDidError(event); 2162 } 2163 } 2164 requestDidError(event) { 2165 this.callback(`Error storing "${this.file.name}". Status: ${this.xhr.status}`); 2166 } 2167 }; 2168 id = 0; 2169 DirectUpload = class { 2170 constructor(file, url, delegate, customHeaders = {}) { 2171 this.id = ++id; 2172 this.file = file; 2173 this.url = url; 2174 this.delegate = delegate; 2175 this.customHeaders = customHeaders; 2176 } 2177 create(callback) { 2178 FileChecksum.create(this.file, (error, checksum) => { 2179 if (error) { 2180 callback(error); 2181 return; 2182 } 2183 const blob = new BlobRecord(this.file, checksum, this.url, this.customHeaders); 2184 notify(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr); 2185 blob.create((error2) => { 2186 if (error2) { 2187 callback(error2); 2188 } else { 2189 const upload = new BlobUpload(blob); 2190 notify(this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr); 2191 upload.create((error3) => { 2192 if (error3) { 2193 callback(error3); 2194 } else { 2195 callback(null, blob.toJSON()); 2196 } 2197 }); 2198 } 2199 }); 2200 }); 2201 } 2202 }; 2203 DirectUploadController = class { 2204 constructor(input, file) { 2205 this.input = input; 2206 this.file = file; 2207 this.directUpload = new DirectUpload(this.file, this.url, this); 2208 this.dispatch("initialize"); 2209 } 2210 start(callback) { 2211 const hiddenInput = document.createElement("input"); 2212 hiddenInput.type = "hidden"; 2213 hiddenInput.name = this.input.name; 2214 this.input.insertAdjacentElement("beforebegin", hiddenInput); 2215 this.dispatch("start"); 2216 this.directUpload.create((error, attributes) => { 2217 if (error) { 2218 hiddenInput.parentNode.removeChild(hiddenInput); 2219 this.dispatchError(error); 2220 } else { 2221 hiddenInput.value = attributes.signed_id; 2222 } 2223 this.dispatch("end"); 2224 callback(error); 2225 }); 2226 } 2227 uploadRequestDidProgress(event) { 2228 const progress = event.loaded / event.total * 90; 2229 if (progress) { 2230 this.dispatch("progress", { 2231 progress 2232 }); 2233 } 2234 } 2235 get url() { 2236 return this.input.getAttribute("data-direct-upload-url"); 2237 } 2238 dispatch(name, detail = {}) { 2239 detail.file = this.file; 2240 detail.id = this.directUpload.id; 2241 return dispatchEvent(this.input, `direct-upload:${name}`, { 2242 detail 2243 }); 2244 } 2245 dispatchError(error) { 2246 const event = this.dispatch("error", { 2247 error 2248 }); 2249 if (!event.defaultPrevented) { 2250 alert(error); 2251 } 2252 } 2253 directUploadWillCreateBlobWithXHR(xhr) { 2254 this.dispatch("before-blob-request", { 2255 xhr 2256 }); 2257 } 2258 directUploadWillStoreFileWithXHR(xhr) { 2259 this.dispatch("before-storage-request", { 2260 xhr 2261 }); 2262 xhr.upload.addEventListener("progress", (event) => this.uploadRequestDidProgress(event)); 2263 xhr.upload.addEventListener("loadend", () => { 2264 this.simulateResponseProgress(xhr); 2265 }); 2266 } 2267 simulateResponseProgress(xhr) { 2268 let progress = 90; 2269 const startTime = Date.now(); 2270 const updateProgress = () => { 2271 const elapsed = Date.now() - startTime; 2272 const estimatedResponseTime = this.estimateResponseTime(); 2273 const responseProgress = Math.min(elapsed / estimatedResponseTime, 1); 2274 progress = 90 + responseProgress * 9; 2275 this.dispatch("progress", { 2276 progress 2277 }); 2278 if (xhr.readyState !== XMLHttpRequest.DONE && progress < 99) { 2279 requestAnimationFrame(updateProgress); 2280 } 2281 }; 2282 xhr.addEventListener("loadend", () => { 2283 this.dispatch("progress", { 2284 progress: 100 2285 }); 2286 }); 2287 requestAnimationFrame(updateProgress); 2288 } 2289 estimateResponseTime() { 2290 const fileSize = this.file.size; 2291 const MB = 1024 * 1024; 2292 if (fileSize < MB) { 2293 return 1e3; 2294 } else if (fileSize < 10 * MB) { 2295 return 2e3; 2296 } else { 2297 return 3e3 + fileSize / MB * 50; 2298 } 2299 } 2300 }; 2301 inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])"; 2302 DirectUploadsController = class { 2303 constructor(form) { 2304 this.form = form; 2305 this.inputs = findElements(form, inputSelector).filter((input) => input.files.length); 2306 } 2307 start(callback) { 2308 const controllers = this.createDirectUploadControllers(); 2309 const startNextController = () => { 2310 const controller = controllers.shift(); 2311 if (controller) { 2312 controller.start((error) => { 2313 if (error) { 2314 callback(error); 2315 this.dispatch("end"); 2316 } else { 2317 startNextController(); 2318 } 2319 }); 2320 } else { 2321 callback(); 2322 this.dispatch("end"); 2323 } 2324 }; 2325 this.dispatch("start"); 2326 startNextController(); 2327 } 2328 createDirectUploadControllers() { 2329 const controllers = []; 2330 this.inputs.forEach((input) => { 2331 toArray(input.files).forEach((file) => { 2332 const controller = new DirectUploadController(input, file); 2333 controllers.push(controller); 2334 }); 2335 }); 2336 return controllers; 2337 } 2338 dispatch(name, detail = {}) { 2339 return dispatchEvent(this.form, `direct-uploads:${name}`, { 2340 detail 2341 }); 2342 } 2343 }; 2344 processingAttribute = "data-direct-uploads-processing"; 2345 submitButtonsByForm = /* @__PURE__ */ new WeakMap(); 2346 started = false; 2347 setTimeout(autostart, 1); 2348 } 2349 }); 2350 2351
vendor: 38,053 bytes, lines 2351-3317
2351// node_modules/@rails/actiontext/app/assets/javascripts/actiontext.esm.js 2352 var actiontext_esm_exports = {}; 2353 __export(actiontext_esm_exports, { 2354 AttachmentUpload: () => AttachmentUpload 2355 }); 2356 function getMetaValue2(name) { 2357 const element = findElement2(document.head, `meta[name="${name}"]`); 2358 if (element) { 2359 return element.getAttribute("content"); 2360 } 2361 } 2362 function findElements2(root, selector) { 2363 if (typeof root == "string") { 2364 selector = root; 2365 root = document; 2366 } 2367 const elements = root.querySelectorAll(selector); 2368 return toArray2(elements); 2369 } 2370 function findElement2(root, selector) { 2371 if (typeof root == "string") { 2372 selector = root; 2373 root = document; 2374 } 2375 return root.querySelector(selector); 2376 } 2377 function dispatchEvent2(element, type, eventInit = {}) { 2378 const { disabled } = element; 2379 const { bubbles, cancelable, detail } = eventInit; 2380 const event = document.createEvent("Event"); 2381 event.initEvent(type, bubbles || true, cancelable || true); 2382 event.detail = detail || {}; 2383 try { 2384 element.disabled = false; 2385 element.dispatchEvent(event); 2386 } finally { 2387 element.disabled = disabled; 2388 } 2389 return event; 2390 } 2391 function toArray2(value) { 2392 if (Array.isArray(value)) { 2393 return value; 2394 } else if (Array.from) { 2395 return Array.from(value); 2396 } else { 2397 return [].slice.call(value); 2398 } 2399 } 2400 function notify2(object, methodName, ...messages) { 2401 if (object && typeof object[methodName] == "function") { 2402 return object[methodName](...messages); 2403 } 2404 } 2405 function start2() { 2406 if (!started2) { 2407 started2 = true; 2408 document.addEventListener("click", didClick2, true); 2409 document.addEventListener("submit", didSubmitForm2, true); 2410 document.addEventListener("ajax:before", didSubmitRemoteElement2); 2411 } 2412 } 2413 function didClick2(event) { 2414 const button = event.target.closest("button, input"); 2415 if (button && button.type === "submit" && button.form) { 2416 submitButtonsByForm2.set(button.form, button); 2417 } 2418 } 2419 function didSubmitForm2(event) { 2420 handleFormSubmissionEvent2(event); 2421 } 2422 function didSubmitRemoteElement2(event) { 2423 if (event.target.tagName == "FORM") { 2424 handleFormSubmissionEvent2(event); 2425 } 2426 } 2427 function handleFormSubmissionEvent2(event) { 2428 const form = event.target; 2429 if (form.hasAttribute(processingAttribute2)) { 2430 event.preventDefault(); 2431 return; 2432 } 2433 const controller = new DirectUploadsController2(form); 2434 const { inputs } = controller; 2435 if (inputs.length) { 2436 event.preventDefault(); 2437 form.setAttribute(processingAttribute2, ""); 2438 inputs.forEach(disable2); 2439 controller.start((error) => { 2440 form.removeAttribute(processingAttribute2); 2441 if (error) { 2442 inputs.forEach(enable2); 2443 } else { 2444 submitForm2(form); 2445 } 2446 }); 2447 } 2448 } 2449 function submitForm2(form) { 2450 let button = submitButtonsByForm2.get(form) || findElement2(form, "input[type=submit], button[type=submit]"); 2451 if (button) { 2452 const { disabled } = button; 2453 button.disabled = false; 2454 button.focus(); 2455 button.click(); 2456 button.disabled = disabled; 2457 } else { 2458 button = document.createElement("input"); 2459 button.type = "submit"; 2460 button.style.display = "none"; 2461 form.appendChild(button); 2462 button.click(); 2463 form.removeChild(button); 2464 } 2465 submitButtonsByForm2.delete(form); 2466 } 2467 function disable2(input) { 2468 input.disabled = true; 2469 } 2470 function enable2(input) { 2471 input.disabled = false; 2472 } 2473 function autostart2() { 2474 if (window.ActiveStorage) { 2475 start2(); 2476 } 2477 } 2478 var sparkMd52, SparkMD52, fileSlice2, FileChecksum2, BlobRecord2, BlobUpload2, id2, DirectUpload2, DirectUploadController2, inputSelector2, DirectUploadsController2, processingAttribute2, submitButtonsByForm2, started2, AttachmentUpload; 2479 var init_actiontext_esm = __esm({ 2480 "node_modules/@rails/actiontext/app/assets/javascripts/actiontext.esm.js"() { 2481 sparkMd52 = { 2482 exports: {} 2483 }; 2484 (function(module, exports) { 2485 (function(factory) { 2486 { 2487 module.exports = factory(); 2488 } 2489 })(function(undefined$1) { 2490 var hex_chr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"]; 2491 function md5cycle(x3, k2) { 2492 var a2 = x3[0], b3 = x3[1], c2 = x3[2], d3 = x3[3]; 2493 a2 += (b3 & c2 | ~b3 & d3) + k2[0] - 680876936 | 0; 2494 a2 = (a2 << 7 | a2 >>> 25) + b3 | 0; 2495 d3 += (a2 & b3 | ~a2 & c2) + k2[1] - 389564586 | 0; 2496 d3 = (d3 << 12 | d3 >>> 20) + a2 | 0; 2497 c2 += (d3 & a2 | ~d3 & b3) + k2[2] + 606105819 | 0; 2498 c2 = (c2 << 17 | c2 >>> 15) + d3 | 0; 2499 b3 += (c2 & d3 | ~c2 & a2) + k2[3] - 1044525330 | 0; 2500 b3 = (b3 << 22 | b3 >>> 10) + c2 | 0; 2501 a2 += (b3 & c2 | ~b3 & d3) + k2[4] - 176418897 | 0; 2502 a2 = (a2 << 7 | a2 >>> 25) + b3 | 0; 2503 d3 += (a2 & b3 | ~a2 & c2) + k2[5] + 1200080426 | 0; 2504 d3 = (d3 << 12 | d3 >>> 20) + a2 | 0; 2505 c2 += (d3 & a2 | ~d3 & b3) + k2[6] - 1473231341 | 0; 2506 c2 = (c2 << 17 | c2 >>> 15) + d3 | 0; 2507 b3 += (c2 & d3 | ~c2 & a2) + k2[7] - 45705983 | 0; 2508 b3 = (b3 << 22 | b3 >>> 10) + c2 | 0; 2509 a2 += (b3 & c2 | ~b3 & d3) + k2[8] + 1770035416 | 0; 2510 a2 = (a2 << 7 | a2 >>> 25) + b3 | 0; 2511 d3 += (a2 & b3 | ~a2 & c2) + k2[9] - 1958414417 | 0; 2512 d3 = (d3 << 12 | d3 >>> 20) + a2 | 0; 2513 c2 += (d3 & a2 | ~d3 & b3) + k2[10] - 42063 | 0; 2514 c2 = (c2 << 17 | c2 >>> 15) + d3 | 0; 2515 b3 += (c2 & d3 | ~c2 & a2) + k2[11] - 1990404162 | 0; 2516 b3 = (b3 << 22 | b3 >>> 10) + c2 | 0; 2517 a2 += (b3 & c2 | ~b3 & d3) + k2[12] + 1804603682 | 0; 2518 a2 = (a2 << 7 | a2 >>> 25) + b3 | 0; 2519 d3 += (a2 & b3 | ~a2 & c2) + k2[13] - 40341101 | 0; 2520 d3 = (d3 << 12 | d3 >>> 20) + a2 | 0; 2521 c2 += (d3 & a2 | ~d3 & b3) + k2[14] - 1502002290 | 0; 2522 c2 = (c2 << 17 | c2 >>> 15) + d3 | 0; 2523 b3 += (c2 & d3 | ~c2 & a2) + k2[15] + 1236535329 | 0; 2524 b3 = (b3 << 22 | b3 >>> 10) + c2 | 0; 2525 a2 += (b3 & d3 | c2 & ~d3) + k2[1] - 165796510 | 0; 2526 a2 = (a2 << 5 | a2 >>> 27) + b3 | 0; 2527 d3 += (a2 & c2 | b3 & ~c2) + k2[6] - 1069501632 | 0; 2528 d3 = (d3 << 9 | d3 >>> 23) + a2 | 0; 2529 c2 += (d3 & b3 | a2 & ~b3) + k2[11] + 643717713 | 0; 2530 c2 = (c2 << 14 | c2 >>> 18) + d3 | 0; 2531 b3 += (c2 & a2 | d3 & ~a2) + k2[0] - 373897302 | 0; 2532 b3 = (b3 << 20 | b3 >>> 12) + c2 | 0; 2533 a2 += (b3 & d3 | c2 & ~d3) + k2[5] - 701558691 | 0; 2534 a2 = (a2 << 5 | a2 >>> 27) + b3 | 0; 2535 d3 += (a2 & c2 | b3 & ~c2) + k2[10] + 38016083 | 0; 2536 d3 = (d3 << 9 | d3 >>> 23) + a2 | 0; 2537 c2 += (d3 & b3 | a2 & ~b3) + k2[15] - 660478335 | 0; 2538 c2 = (c2 << 14 | c2 >>> 18) + d3 | 0; 2539 b3 += (c2 & a2 | d3 & ~a2) + k2[4] - 405537848 | 0; 2540 b3 = (b3 << 20 | b3 >>> 12) + c2 | 0; 2541 a2 += (b3 & d3 | c2 & ~d3) + k2[9] + 568446438 | 0; 2542 a2 = (a2 << 5 | a2 >>> 27) + b3 | 0; 2543 d3 += (a2 & c2 | b3 & ~c2) + k2[14] - 1019803690 | 0; 2544 d3 = (d3 << 9 | d3 >>> 23) + a2 | 0; 2545 c2 += (d3 & b3 | a2 & ~b3) + k2[3] - 187363961 | 0; 2546 c2 = (c2 << 14 | c2 >>> 18) + d3 | 0; 2547 b3 += (c2 & a2 | d3 & ~a2) + k2[8] + 1163531501 | 0; 2548 b3 = (b3 << 20 | b3 >>> 12) + c2 | 0; 2549 a2 += (b3 & d3 | c2 & ~d3) + k2[13] - 1444681467 | 0; 2550 a2 = (a2 << 5 | a2 >>> 27) + b3 | 0; 2551 d3 += (a2 & c2 | b3 & ~c2) + k2[2] - 51403784 | 0; 2552 d3 = (d3 << 9 | d3 >>> 23) + a2 | 0; 2553 c2 += (d3 & b3 | a2 & ~b3) + k2[7] + 1735328473 | 0; 2554 c2 = (c2 << 14 | c2 >>> 18) + d3 | 0; 2555 b3 += (c2 & a2 | d3 & ~a2) + k2[12] - 1926607734 | 0; 2556 b3 = (b3 << 20 | b3 >>> 12) + c2 | 0; 2557 a2 += (b3 ^ c2 ^ d3) + k2[5] - 378558 | 0; 2558 a2 = (a2 << 4 | a2 >>> 28) + b3 | 0; 2559 d3 += (a2 ^ b3 ^ c2) + k2[8] - 2022574463 | 0; 2560 d3 = (d3 << 11 | d3 >>> 21) + a2 | 0; 2561 c2 += (d3 ^ a2 ^ b3) + k2[11] + 1839030562 | 0; 2562 c2 = (c2 << 16 | c2 >>> 16) + d3 | 0; 2563 b3 += (c2 ^ d3 ^ a2) + k2[14] - 35309556 | 0; 2564 b3 = (b3 << 23 | b3 >>> 9) + c2 | 0; 2565 a2 += (b3 ^ c2 ^ d3) + k2[1] - 1530992060 | 0; 2566 a2 = (a2 << 4 | a2 >>> 28) + b3 | 0; 2567 d3 += (a2 ^ b3 ^ c2) + k2[4] + 1272893353 | 0; 2568 d3 = (d3 << 11 | d3 >>> 21) + a2 | 0; 2569 c2 += (d3 ^ a2 ^ b3) + k2[7] - 155497632 | 0; 2570 c2 = (c2 << 16 | c2 >>> 16) + d3 | 0; 2571 b3 += (c2 ^ d3 ^ a2) + k2[10] - 1094730640 | 0; 2572 b3 = (b3 << 23 | b3 >>> 9) + c2 | 0; 2573 a2 += (b3 ^ c2 ^ d3) + k2[13] + 681279174 | 0; 2574 a2 = (a2 << 4 | a2 >>> 28) + b3 | 0; 2575 d3 += (a2 ^ b3 ^ c2) + k2[0] - 358537222 | 0; 2576 d3 = (d3 << 11 | d3 >>> 21) + a2 | 0; 2577 c2 += (d3 ^ a2 ^ b3) + k2[3] - 722521979 | 0; 2578 c2 = (c2 << 16 | c2 >>> 16) + d3 | 0; 2579 b3 += (c2 ^ d3 ^ a2) + k2[6] + 76029189 | 0; 2580 b3 = (b3 << 23 | b3 >>> 9) + c2 | 0; 2581 a2 += (b3 ^ c2 ^ d3) + k2[9] - 640364487 | 0; 2582 a2 = (a2 << 4 | a2 >>> 28) + b3 | 0; 2583 d3 += (a2 ^ b3 ^ c2) + k2[12] - 421815835 | 0; 2584 d3 = (d3 << 11 | d3 >>> 21) + a2 | 0; 2585 c2 += (d3 ^ a2 ^ b3) + k2[15] + 530742520 | 0; 2586 c2 = (c2 << 16 | c2 >>> 16) + d3 | 0; 2587 b3 += (c2 ^ d3 ^ a2) + k2[2] - 995338651 | 0; 2588 b3 = (b3 << 23 | b3 >>> 9) + c2 | 0; 2589 a2 += (c2 ^ (b3 | ~d3)) + k2[0] - 198630844 | 0; 2590 a2 = (a2 << 6 | a2 >>> 26) + b3 | 0; 2591 d3 += (b3 ^ (a2 | ~c2)) + k2[7] + 1126891415 | 0; 2592 d3 = (d3 << 10 | d3 >>> 22) + a2 | 0; 2593 c2 += (a2 ^ (d3 | ~b3)) + k2[14] - 1416354905 | 0; 2594 c2 = (c2 << 15 | c2 >>> 17) + d3 | 0; 2595 b3 += (d3 ^ (c2 | ~a2)) + k2[5] - 57434055 | 0; 2596 b3 = (b3 << 21 | b3 >>> 11) + c2 | 0; 2597 a2 += (c2 ^ (b3 | ~d3)) + k2[12] + 1700485571 | 0; 2598 a2 = (a2 << 6 | a2 >>> 26) + b3 | 0; 2599 d3 += (b3 ^ (a2 | ~c2)) + k2[3] - 1894986606 | 0; 2600 d3 = (d3 << 10 | d3 >>> 22) + a2 | 0; 2601 c2 += (a2 ^ (d3 | ~b3)) + k2[10] - 1051523 | 0; 2602 c2 = (c2 << 15 | c2 >>> 17) + d3 | 0; 2603 b3 += (d3 ^ (c2 | ~a2)) + k2[1] - 2054922799 | 0; 2604 b3 = (b3 << 21 | b3 >>> 11) + c2 | 0; 2605 a2 += (c2 ^ (b3 | ~d3)) + k2[8] + 1873313359 | 0; 2606 a2 = (a2 << 6 | a2 >>> 26) + b3 | 0; 2607 d3 += (b3 ^ (a2 | ~c2)) + k2[15] - 30611744 | 0; 2608 d3 = (d3 << 10 | d3 >>> 22) + a2 | 0; 2609 c2 += (a2 ^ (d3 | ~b3)) + k2[6] - 1560198380 | 0; 2610 c2 = (c2 << 15 | c2 >>> 17) + d3 | 0; 2611 b3 += (d3 ^ (c2 | ~a2)) + k2[13] + 1309151649 | 0; 2612 b3 = (b3 << 21 | b3 >>> 11) + c2 | 0; 2613 a2 += (c2 ^ (b3 | ~d3)) + k2[4] - 145523070 | 0; 2614 a2 = (a2 << 6 | a2 >>> 26) + b3 | 0; 2615 d3 += (b3 ^ (a2 | ~c2)) + k2[11] - 1120210379 | 0; 2616 d3 = (d3 << 10 | d3 >>> 22) + a2 | 0; 2617 c2 += (a2 ^ (d3 | ~b3)) + k2[2] + 718787259 | 0; 2618 c2 = (c2 << 15 | c2 >>> 17) + d3 | 0; 2619 b3 += (d3 ^ (c2 | ~a2)) + k2[9] - 343485551 | 0; 2620 b3 = (b3 << 21 | b3 >>> 11) + c2 | 0; 2621 x3[0] = a2 + x3[0] | 0; 2622 x3[1] = b3 + x3[1] | 0; 2623 x3[2] = c2 + x3[2] | 0; 2624 x3[3] = d3 + x3[3] | 0; 2625 } 2626 function md5blk(s2) { 2627 var md5blks = [], i2; 2628 for (i2 = 0; i2 < 64; i2 += 4) { 2629 md5blks[i2 >> 2] = s2.charCodeAt(i2) + (s2.charCodeAt(i2 + 1) << 8) + (s2.charCodeAt(i2 + 2) << 16) + (s2.charCodeAt(i2 + 3) << 24); 2630 } 2631 return md5blks; 2632 } 2633 function md5blk_array(a2) { 2634 var md5blks = [], i2; 2635 for (i2 = 0; i2 < 64; i2 += 4) { 2636 md5blks[i2 >> 2] = a2[i2] + (a2[i2 + 1] << 8) + (a2[i2 + 2] << 16) + (a2[i2 + 3] << 24); 2637 } 2638 return md5blks; 2639 } 2640 function md51(s2) { 2641 var n2 = s2.length, state = [1732584193, -271733879, -1732584194, 271733878], i2, length, tail, tmp, lo, hi; 2642 for (i2 = 64; i2 <= n2; i2 += 64) { 2643 md5cycle(state, md5blk(s2.substring(i2 - 64, i2))); 2644 } 2645 s2 = s2.substring(i2 - 64); 2646 length = s2.length; 2647 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 2648 for (i2 = 0; i2 < length; i2 += 1) { 2649 tail[i2 >> 2] |= s2.charCodeAt(i2) << (i2 % 4 << 3); 2650 } 2651 tail[i2 >> 2] |= 128 << (i2 % 4 << 3); 2652 if (i2 > 55) { 2653 md5cycle(state, tail); 2654 for (i2 = 0; i2 < 16; i2 += 1) { 2655 tail[i2] = 0; 2656 } 2657 } 2658 tmp = n2 * 8; 2659 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); 2660 lo = parseInt(tmp[2], 16); 2661 hi = parseInt(tmp[1], 16) || 0; 2662 tail[14] = lo; 2663 tail[15] = hi; 2664 md5cycle(state, tail); 2665 return state; 2666 } 2667 function md51_array(a2) { 2668 var n2 = a2.length, state = [1732584193, -271733879, -1732584194, 271733878], i2, length, tail, tmp, lo, hi; 2669 for (i2 = 64; i2 <= n2; i2 += 64) { 2670 md5cycle(state, md5blk_array(a2.subarray(i2 - 64, i2))); 2671 } 2672 a2 = i2 - 64 < n2 ? a2.subarray(i2 - 64) : new Uint8Array(0); 2673 length = a2.length; 2674 tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 2675 for (i2 = 0; i2 < length; i2 += 1) { 2676 tail[i2 >> 2] |= a2[i2] << (i2 % 4 << 3); 2677 } 2678 tail[i2 >> 2] |= 128 << (i2 % 4 << 3); 2679 if (i2 > 55) { 2680 md5cycle(state, tail); 2681 for (i2 = 0; i2 < 16; i2 += 1) { 2682 tail[i2] = 0; 2683 } 2684 } 2685 tmp = n2 * 8; 2686 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); 2687 lo = parseInt(tmp[2], 16); 2688 hi = parseInt(tmp[1], 16) || 0; 2689 tail[14] = lo; 2690 tail[15] = hi; 2691 md5cycle(state, tail); 2692 return state; 2693 } 2694 function rhex(n2) { 2695 var s2 = "", j3; 2696 for (j3 = 0; j3 < 4; j3 += 1) { 2697 s2 += hex_chr[n2 >> j3 * 8 + 4 & 15] + hex_chr[n2 >> j3 * 8 & 15]; 2698 } 2699 return s2; 2700 } 2701 function hex(x3) { 2702 var i2; 2703 for (i2 = 0; i2 < x3.length; i2 += 1) { 2704 x3[i2] = rhex(x3[i2]); 2705 } 2706 return x3.join(""); 2707 } 2708 if (hex(md51("hello")) !== "5d41402abc4b2a76b9719d911017c592") ; 2709 if (typeof ArrayBuffer !== "undefined" && !ArrayBuffer.prototype.slice) { 2710 (function() { 2711 function clamp2(val, length) { 2712 val = val | 0 || 0; 2713 if (val < 0) { 2714 return Math.max(val + length, 0); 2715 } 2716 return Math.min(val, length); 2717 } 2718 ArrayBuffer.prototype.slice = function(from, to) { 2719 var length = this.byteLength, begin = clamp2(from, length), end = length, num, target, targetArray, sourceArray; 2720 if (to !== undefined$1) { 2721 end = clamp2(to, length); 2722 } 2723 if (begin > end) { 2724 return new ArrayBuffer(0); 2725 } 2726 num = end - begin; 2727 target = new ArrayBuffer(num); 2728 targetArray = new Uint8Array(target); 2729 sourceArray = new Uint8Array(this, begin, num); 2730 targetArray.set(sourceArray); 2731 return target; 2732 }; 2733 })(); 2734 } 2735 function toUtf8(str) { 2736 if (/[\u0080-\uFFFF]/.test(str)) { 2737 str = unescape(encodeURIComponent(str)); 2738 } 2739 return str; 2740 } 2741 function utf8Str2ArrayBuffer(str, returnUInt8Array) { 2742 var length = str.length, buff = new ArrayBuffer(length), arr = new Uint8Array(buff), i2; 2743 for (i2 = 0; i2 < length; i2 += 1) { 2744 arr[i2] = str.charCodeAt(i2); 2745 } 2746 return returnUInt8Array ? arr : buff; 2747 } 2748 function arrayBuffer2Utf8Str(buff) { 2749 return String.fromCharCode.apply(null, new Uint8Array(buff)); 2750 } 2751 function concatenateArrayBuffers(first, second, returnUInt8Array) { 2752 var result = new Uint8Array(first.byteLength + second.byteLength); 2753 result.set(new Uint8Array(first)); 2754 result.set(new Uint8Array(second), first.byteLength); 2755 return returnUInt8Array ? result : result.buffer; 2756 } 2757 function hexToBinaryString(hex2) { 2758 var bytes = [], length = hex2.length, x3; 2759 for (x3 = 0; x3 < length - 1; x3 += 2) { 2760 bytes.push(parseInt(hex2.substr(x3, 2), 16)); 2761 } 2762 return String.fromCharCode.apply(String, bytes); 2763 } 2764 function SparkMD53() { 2765 this.reset(); 2766 } 2767 SparkMD53.prototype.append = function(str) { 2768 this.appendBinary(toUtf8(str)); 2769 return this; 2770 }; 2771 SparkMD53.prototype.appendBinary = function(contents) { 2772 this._buff += contents; 2773 this._length += contents.length; 2774 var length = this._buff.length, i2; 2775 for (i2 = 64; i2 <= length; i2 += 64) { 2776 md5cycle(this._hash, md5blk(this._buff.substring(i2 - 64, i2))); 2777 } 2778 this._buff = this._buff.substring(i2 - 64); 2779 return this; 2780 }; 2781 SparkMD53.prototype.end = function(raw) { 2782 var buff = this._buff, length = buff.length, i2, tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ret; 2783 for (i2 = 0; i2 < length; i2 += 1) { 2784 tail[i2 >> 2] |= buff.charCodeAt(i2) << (i2 % 4 << 3); 2785 } 2786 this._finish(tail, length); 2787 ret = hex(this._hash); 2788 if (raw) { 2789 ret = hexToBinaryString(ret); 2790 } 2791 this.reset(); 2792 return ret; 2793 }; 2794 SparkMD53.prototype.reset = function() { 2795 this._buff = ""; 2796 this._length = 0; 2797 this._hash = [1732584193, -271733879, -1732584194, 271733878]; 2798 return this; 2799 }; 2800 SparkMD53.prototype.getState = function() { 2801 return { 2802 buff: this._buff, 2803 length: this._length, 2804 hash: this._hash.slice() 2805 }; 2806 }; 2807 SparkMD53.prototype.setState = function(state) { 2808 this._buff = state.buff; 2809 this._length = state.length; 2810 this._hash = state.hash; 2811 return this; 2812 }; 2813 SparkMD53.prototype.destroy = function() { 2814 delete this._hash; 2815 delete this._buff; 2816 delete this._length; 2817 }; 2818 SparkMD53.prototype._finish = function(tail, length) { 2819 var i2 = length, tmp, lo, hi; 2820 tail[i2 >> 2] |= 128 << (i2 % 4 << 3); 2821 if (i2 > 55) { 2822 md5cycle(this._hash, tail); 2823 for (i2 = 0; i2 < 16; i2 += 1) { 2824 tail[i2] = 0; 2825 } 2826 } 2827 tmp = this._length * 8; 2828 tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/); 2829 lo = parseInt(tmp[2], 16); 2830 hi = parseInt(tmp[1], 16) || 0; 2831 tail[14] = lo; 2832 tail[15] = hi; 2833 md5cycle(this._hash, tail); 2834 }; 2835 SparkMD53.hash = function(str, raw) { 2836 return SparkMD53.hashBinary(toUtf8(str), raw); 2837 }; 2838 SparkMD53.hashBinary = function(content, raw) { 2839 var hash = md51(content), ret = hex(hash); 2840 return raw ? hexToBinaryString(ret) : ret; 2841 }; 2842 SparkMD53.ArrayBuffer = function() { 2843 this.reset(); 2844 }; 2845 SparkMD53.ArrayBuffer.prototype.append = function(arr) { 2846 var buff = concatenateArrayBuffers(this._buff.buffer, arr, true), length = buff.length, i2; 2847 this._length += arr.byteLength; 2848 for (i2 = 64; i2 <= length; i2 += 64) { 2849 md5cycle(this._hash, md5blk_array(buff.subarray(i2 - 64, i2))); 2850 } 2851 this._buff = i2 - 64 < length ? new Uint8Array(buff.buffer.slice(i2 - 64)) : new Uint8Array(0); 2852 return this; 2853 }; 2854 SparkMD53.ArrayBuffer.prototype.end = function(raw) { 2855 var buff = this._buff, length = buff.length, tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], i2, ret; 2856 for (i2 = 0; i2 < length; i2 += 1) { 2857 tail[i2 >> 2] |= buff[i2] << (i2 % 4 << 3); 2858 } 2859 this._finish(tail, length); 2860 ret = hex(this._hash); 2861 if (raw) { 2862 ret = hexToBinaryString(ret); 2863 } 2864 this.reset(); 2865 return ret; 2866 }; 2867 SparkMD53.ArrayBuffer.prototype.reset = function() { 2868 this._buff = new Uint8Array(0); 2869 this._length = 0; 2870 this._hash = [1732584193, -271733879, -1732584194, 271733878]; 2871 return this; 2872 }; 2873 SparkMD53.ArrayBuffer.prototype.getState = function() { 2874 var state = SparkMD53.prototype.getState.call(this); 2875 state.buff = arrayBuffer2Utf8Str(state.buff); 2876 return state; 2877 }; 2878 SparkMD53.ArrayBuffer.prototype.setState = function(state) { 2879 state.buff = utf8Str2ArrayBuffer(state.buff, true); 2880 return SparkMD53.prototype.setState.call(this, state); 2881 }; 2882 SparkMD53.ArrayBuffer.prototype.destroy = SparkMD53.prototype.destroy; 2883 SparkMD53.ArrayBuffer.prototype._finish = SparkMD53.prototype._finish; 2884 SparkMD53.ArrayBuffer.hash = function(arr, raw) { 2885 var hash = md51_array(new Uint8Array(arr)), ret = hex(hash); 2886 return raw ? hexToBinaryString(ret) : ret; 2887 }; 2888 return SparkMD53; 2889 }); 2890 })(sparkMd52); 2891 SparkMD52 = sparkMd52.exports; 2892 fileSlice2 = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice; 2893 FileChecksum2 = class _FileChecksum { 2894 static create(file, callback) { 2895 const instance = new _FileChecksum(file); 2896 instance.create(callback); 2897 } 2898 constructor(file) { 2899 this.file = file; 2900 this.chunkSize = 2097152; 2901 this.chunkCount = Math.ceil(this.file.size / this.chunkSize); 2902 this.chunkIndex = 0; 2903 } 2904 create(callback) { 2905 this.callback = callback; 2906 this.md5Buffer = new SparkMD52.ArrayBuffer(); 2907 this.fileReader = new FileReader(); 2908 this.fileReader.addEventListener("load", (event) => this.fileReaderDidLoad(event)); 2909 this.fileReader.addEventListener("error", (event) => this.fileReaderDidError(event)); 2910 this.readNextChunk(); 2911 } 2912 fileReaderDidLoad(event) { 2913 this.md5Buffer.append(event.target.result); 2914 if (!this.readNextChunk()) { 2915 const binaryDigest = this.md5Buffer.end(true); 2916 const base64digest = btoa(binaryDigest); 2917 this.callback(null, base64digest); 2918 } 2919 } 2920 fileReaderDidError(event) { 2921 this.callback(`Error reading ${this.file.name}`); 2922 } 2923 readNextChunk() { 2924 if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) { 2925 const start3 = this.chunkIndex * this.chunkSize; 2926 const end = Math.min(start3 + this.chunkSize, this.file.size); 2927 const bytes = fileSlice2.call(this.file, start3, end); 2928 this.fileReader.readAsArrayBuffer(bytes); 2929 this.chunkIndex++; 2930 return true; 2931 } else { 2932 return false; 2933 } 2934 } 2935 }; 2936 BlobRecord2 = class { 2937 constructor(file, checksum, url, customHeaders = {}) { 2938 this.file = file; 2939 this.attributes = { 2940 filename: file.name, 2941 content_type: file.type || "application/octet-stream", 2942 byte_size: file.size, 2943 checksum 2944 }; 2945 this.xhr = new XMLHttpRequest(); 2946 this.xhr.open("POST", url, true); 2947 this.xhr.responseType = "json"; 2948 this.xhr.setRequestHeader("Content-Type", "application/json"); 2949 this.xhr.setRequestHeader("Accept", "application/json"); 2950 this.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 2951 Object.keys(customHeaders).forEach((headerKey) => { 2952 this.xhr.setRequestHeader(headerKey, customHeaders[headerKey]); 2953 }); 2954 const csrfToken = getMetaValue2("csrf-token"); 2955 if (csrfToken != void 0) { 2956 this.xhr.setRequestHeader("X-CSRF-Token", csrfToken); 2957 } 2958 this.xhr.addEventListener("load", (event) => this.requestDidLoad(event)); 2959 this.xhr.addEventListener("error", (event) => this.requestDidError(event)); 2960 } 2961 get status() { 2962 return this.xhr.status; 2963 } 2964 get response() { 2965 const { responseType, response } = this.xhr; 2966 if (responseType == "json") { 2967 return response; 2968 } else { 2969 return JSON.parse(response); 2970 } 2971 } 2972 create(callback) { 2973 this.callback = callback; 2974 this.xhr.send(JSON.stringify({ 2975 blob: this.attributes 2976 })); 2977 } 2978 requestDidLoad(event) { 2979 if (this.status >= 200 && this.status < 300) { 2980 const { response } = this; 2981 const { direct_upload } = response; 2982 delete response.direct_upload; 2983 this.attributes = response; 2984 this.directUploadData = direct_upload; 2985 this.callback(null, this.toJSON()); 2986 } else { 2987 this.requestDidError(event); 2988 } 2989 } 2990 requestDidError(event) { 2991 this.callback(`Error creating Blob for "${this.file.name}". Status: ${this.status}`); 2992 } 2993 toJSON() { 2994 const result = {}; 2995 for (const key in this.attributes) { 2996 result[key] = this.attributes[key]; 2997 } 2998 return result; 2999 } 3000 }; 3001 BlobUpload2 = class { 3002 constructor(blob) { 3003 this.blob = blob; 3004 this.file = blob.file; 3005 const { url, headers } = blob.directUploadData; 3006 this.xhr = new XMLHttpRequest(); 3007 this.xhr.open("PUT", url, true); 3008 this.xhr.responseType = "text"; 3009 for (const key in headers) { 3010 this.xhr.setRequestHeader(key, headers[key]); 3011 } 3012 this.xhr.addEventListener("load", (event) => this.requestDidLoad(event)); 3013 this.xhr.addEventListener("error", (event) => this.requestDidError(event)); 3014 } 3015 create(callback) { 3016 this.callback = callback; 3017 this.xhr.send(this.file.slice()); 3018 } 3019 requestDidLoad(event) { 3020 const { status, response } = this.xhr; 3021 if (status >= 200 && status < 300) { 3022 this.callback(null, response); 3023 } else { 3024 this.requestDidError(event); 3025 } 3026 } 3027 requestDidError(event) { 3028 this.callback(`Error storing "${this.file.name}". Status: ${this.xhr.status}`); 3029 } 3030 }; 3031 id2 = 0; 3032 DirectUpload2 = class { 3033 constructor(file, url, delegate, customHeaders = {}) { 3034 this.id = ++id2; 3035 this.file = file; 3036 this.url = url; 3037 this.delegate = delegate; 3038 this.customHeaders = customHeaders; 3039 } 3040 create(callback) { 3041 FileChecksum2.create(this.file, (error, checksum) => { 3042 if (error) { 3043 callback(error); 3044 return; 3045 } 3046 const blob = new BlobRecord2(this.file, checksum, this.url, this.customHeaders); 3047 notify2(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr); 3048 blob.create((error2) => { 3049 if (error2) { 3050 callback(error2); 3051 } else { 3052 const upload = new BlobUpload2(blob); 3053 notify2(this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr); 3054 upload.create((error3) => { 3055 if (error3) { 3056 callback(error3); 3057 } else { 3058 callback(null, blob.toJSON()); 3059 } 3060 }); 3061 } 3062 }); 3063 }); 3064 } 3065 }; 3066 DirectUploadController2 = class { 3067 constructor(input, file) { 3068 this.input = input; 3069 this.file = file; 3070 this.directUpload = new DirectUpload2(this.file, this.url, this); 3071 this.dispatch("initialize"); 3072 } 3073 start(callback) { 3074 const hiddenInput = document.createElement("input"); 3075 hiddenInput.type = "hidden"; 3076 hiddenInput.name = this.input.name; 3077 this.input.insertAdjacentElement("beforebegin", hiddenInput); 3078 this.dispatch("start"); 3079 this.directUpload.create((error, attributes) => { 3080 if (error) { 3081 hiddenInput.parentNode.removeChild(hiddenInput); 3082 this.dispatchError(error); 3083 } else { 3084 hiddenInput.value = attributes.signed_id; 3085 } 3086 this.dispatch("end"); 3087 callback(error); 3088 }); 3089 } 3090 uploadRequestDidProgress(event) { 3091 const progress = event.loaded / event.total * 90; 3092 if (progress) { 3093 this.dispatch("progress", { 3094 progress 3095 }); 3096 } 3097 } 3098 get url() { 3099 return this.input.getAttribute("data-direct-upload-url"); 3100 } 3101 dispatch(name, detail = {}) { 3102 detail.file = this.file; 3103 detail.id = this.directUpload.id; 3104 return dispatchEvent2(this.input, `direct-upload:${name}`, { 3105 detail 3106 }); 3107 } 3108 dispatchError(error) { 3109 const event = this.dispatch("error", { 3110 error 3111 }); 3112 if (!event.defaultPrevented) { 3113 alert(error); 3114 } 3115 } 3116 directUploadWillCreateBlobWithXHR(xhr) { 3117 this.dispatch("before-blob-request", { 3118 xhr 3119 }); 3120 } 3121 directUploadWillStoreFileWithXHR(xhr) { 3122 this.dispatch("before-storage-request", { 3123 xhr 3124 }); 3125 xhr.upload.addEventListener("progress", (event) => this.uploadRequestDidProgress(event)); 3126 xhr.upload.addEventListener("loadend", () => { 3127 this.simulateResponseProgress(xhr); 3128 }); 3129 } 3130 simulateResponseProgress(xhr) { 3131 let progress = 90; 3132 const startTime = Date.now(); 3133 const updateProgress = () => { 3134 const elapsed = Date.now() - startTime; 3135 const estimatedResponseTime = this.estimateResponseTime(); 3136 const responseProgress = Math.min(elapsed / estimatedResponseTime, 1); 3137 progress = 90 + responseProgress * 9; 3138 this.dispatch("progress", { 3139 progress 3140 }); 3141 if (xhr.readyState !== XMLHttpRequest.DONE && progress < 99) { 3142 requestAnimationFrame(updateProgress); 3143 } 3144 }; 3145 xhr.addEventListener("loadend", () => { 3146 this.dispatch("progress", { 3147 progress: 100 3148 }); 3149 }); 3150 requestAnimationFrame(updateProgress); 3151 } 3152 estimateResponseTime() { 3153 const fileSize = this.file.size; 3154 const MB = 1024 * 1024; 3155 if (fileSize < MB) { 3156 return 1e3; 3157 } else if (fileSize < 10 * MB) { 3158 return 2e3; 3159 } else { 3160 return 3e3 + fileSize / MB * 50; 3161 } 3162 } 3163 }; 3164 inputSelector2 = "input[type=file][data-direct-upload-url]:not([disabled])"; 3165 DirectUploadsController2 = class { 3166 constructor(form) { 3167 this.form = form; 3168 this.inputs = findElements2(form, inputSelector2).filter((input) => input.files.length); 3169 } 3170 start(callback) { 3171 const controllers = this.createDirectUploadControllers(); 3172 const startNextController = () => { 3173 const controller = controllers.shift(); 3174 if (controller) { 3175 controller.start((error) => { 3176 if (error) { 3177 callback(error); 3178 this.dispatch("end"); 3179 } else { 3180 startNextController(); 3181 } 3182 }); 3183 } else { 3184 callback(); 3185 this.dispatch("end"); 3186 } 3187 }; 3188 this.dispatch("start"); 3189 startNextController(); 3190 } 3191 createDirectUploadControllers() { 3192 const controllers = []; 3193 this.inputs.forEach((input) => { 3194 toArray2(input.files).forEach((file) => { 3195 const controller = new DirectUploadController2(input, file); 3196 controllers.push(controller); 3197 }); 3198 }); 3199 return controllers; 3200 } 3201 dispatch(name, detail = {}) { 3202 return dispatchEvent2(this.form, `direct-uploads:${name}`, { 3203 detail 3204 }); 3205 } 3206 }; 3207 processingAttribute2 = "data-direct-uploads-processing"; 3208 submitButtonsByForm2 = /* @__PURE__ */ new WeakMap(); 3209 started2 = false; 3210 setTimeout(autostart2, 1); 3211 AttachmentUpload = class { 3212 constructor(attachment, element, file = attachment.file) { 3213 this.attachment = attachment; 3214 this.element = element; 3215 this.directUpload = new DirectUpload2(file, this.directUploadUrl, this); 3216 this.file = file; 3217 } 3218 start() { 3219 return new Promise((resolve, reject) => { 3220 this.directUpload.create((error, attributes) => this.directUploadDidComplete(error, attributes, resolve, reject)); 3221 this.dispatch("start"); 3222 }); 3223 } 3224 directUploadWillStoreFileWithXHR(xhr) { 3225 xhr.upload.addEventListener("progress", (event) => { 3226 const progress = event.loaded / event.total * 90; 3227 if (progress) { 3228 this.dispatch("progress", { 3229 progress 3230 }); 3231 } 3232 }); 3233 xhr.upload.addEventListener("loadend", () => { 3234 this.simulateResponseProgress(xhr); 3235 }); 3236 } 3237 simulateResponseProgress(xhr) { 3238 let progress = 90; 3239 const startTime = Date.now(); 3240 const updateProgress = () => { 3241 const elapsed = Date.now() - startTime; 3242 const estimatedResponseTime = this.estimateResponseTime(); 3243 const responseProgress = Math.min(elapsed / estimatedResponseTime, 1); 3244 progress = 90 + responseProgress * 9; 3245 this.dispatch("progress", { 3246 progress 3247 }); 3248 if (xhr.readyState !== XMLHttpRequest.DONE && progress < 99) { 3249 requestAnimationFrame(updateProgress); 3250 } 3251 }; 3252 xhr.addEventListener("loadend", () => { 3253 this.dispatch("progress", { 3254 progress: 100 3255 }); 3256 }); 3257 requestAnimationFrame(updateProgress); 3258 } 3259 estimateResponseTime() { 3260 const fileSize = this.file.size; 3261 const MB = 1024 * 1024; 3262 if (fileSize < MB) { 3263 return 1e3; 3264 } else if (fileSize < 10 * MB) { 3265 return 2e3; 3266 } else { 3267 return 3e3 + fileSize / MB * 50; 3268 } 3269 } 3270 directUploadDidComplete(error, attributes, resolve, reject) { 3271 if (error) { 3272 this.dispatchError(error, reject); 3273 } else { 3274 resolve({ 3275 sgid: attributes.attachable_sgid, 3276 url: this.createBlobUrl(attributes.signed_id, attributes.filename) 3277 }); 3278 this.dispatch("end"); 3279 } 3280 } 3281 createBlobUrl(signedId, filename) { 3282 return this.blobUrlTemplate.replace(":signed_id", signedId).replace(":filename", encodeURIComponent(filename)); 3283 } 3284 dispatch(name, detail = {}) { 3285 detail.attachment = this.attachment; 3286 return dispatchEvent2(this.element, `direct-upload:${name}`, { 3287 detail 3288 }); 3289 } 3290 dispatchError(error, reject) { 3291 const event = this.dispatch("error", { 3292 error 3293 }); 3294 if (!event.defaultPrevented) { 3295 reject(error); 3296 } 3297 } 3298 get directUploadUrl() { 3299 return this.element.dataset.directUploadUrl; 3300 } 3301 get blobUrlTemplate() { 3302 return this.element.dataset.blobUrlTemplate; 3303 } 3304 }; 3305 addEventListener("trix-attachment-add", (event) => { 3306 const { attachment, target } = event; 3307 if (attachment.file) { 3308 const upload = new AttachmentUpload(attachment, target, attachment.file); 3309 const onProgress = (event2) => attachment.setUploadProgress(event2.detail.progress); 3310 target.addEventListener("direct-upload:progress", onProgress); 3311 upload.start().then((attributes) => attachment.setAttributes(attributes)).catch((error) => alert(error)).finally(() => target.removeEventListener("direct-upload:progress", onProgress)); 3312 } 3313 }); 3314 } 3315 }); 3316 3317
vendor: 114 bytes, lines 3317-3320
3317// node_modules/@37signals/lexxy/dist/lexxy_helpers.esm.js 3318 var import_prismjs = __toESM(require_prism(), 1); 3319 3320
vendor: 1,013 bytes, lines 3320-3353
3320// node_modules/prismjs/components/prism-clike.js 3321 Prism.languages.clike = { 3322 "comment": [ 3323 { 3324 pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, 3325 lookbehind: true, 3326 greedy: true 3327 }, 3328 { 3329 pattern: /(^|[^\\:])\/\/.*/, 3330 lookbehind: true, 3331 greedy: true 3332 } 3333 ], 3334 "string": { 3335 pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, 3336 greedy: true 3337 }, 3338 "class-name": { 3339 pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i, 3340 lookbehind: true, 3341 inside: { 3342 "punctuation": /[.\\]/ 3343 } 3344 }, 3345 "keyword": /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/, 3346 "boolean": /\b(?:false|true)\b/, 3347 "function": /\b\w+(?=\()/, 3348 "number": /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i, 3349 "operator": /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/, 3350 "punctuation": /[{}[\];(),.:]/ 3351 }; 3352 3353
vendor: 1,404 bytes, lines 3353-3403
3353// node_modules/prismjs/components/prism-diff.js 3354 (function(Prism3) { 3355 Prism3.languages.diff = { 3356 "coord": [ 3357 // Match all kinds of coord lines (prefixed by "+++", "---" or "***"). 3358 /^(?:\*{3}|-{3}|\+{3}).*$/m, 3359 // Match "@@ ... @@" coord lines in unified diff. 3360 /^@@.*@@$/m, 3361 // Match coord lines in normal diff (starts with a number). 3362 /^\d.*$/m 3363 ] 3364 // deleted, inserted, unchanged, diff 3365 }; 3366 var PREFIXES = { 3367 "deleted-sign": "-", 3368 "deleted-arrow": "<", 3369 "inserted-sign": "+", 3370 "inserted-arrow": ">", 3371 "unchanged": " ", 3372 "diff": "!" 3373 }; 3374 Object.keys(PREFIXES).forEach(function(name) { 3375 var prefix = PREFIXES[name]; 3376 var alias = []; 3377 if (!/^\w+$/.test(name)) { 3378 alias.push(/\w+/.exec(name)[0]); 3379 } 3380 if (name === "diff") { 3381 alias.push("bold"); 3382 } 3383 Prism3.languages.diff[name] = { 3384 pattern: RegExp("^(?:[" + prefix + "].*(?:\r\n?|\n|(?![\\s\\S])))+", "m"), 3385 alias, 3386 inside: { 3387 "line": { 3388 pattern: /(.)(?=[\s\S]).*(?:\r\n?|\n)?/, 3389 lookbehind: true 3390 }, 3391 "prefix": { 3392 pattern: /[\s\S]/, 3393 alias: /\w+/.exec(name)[0] 3394 } 3395 } 3396 }; 3397 }); 3398 Object.defineProperty(Prism3.languages.diff, "PREFIXES", { 3399 value: PREFIXES 3400 }); 3401 })(Prism); 3402 3403
vendor: 6,755 bytes, lines 3403-3545
3403// node_modules/prismjs/components/prism-javascript.js 3404 Prism.languages.javascript = Prism.languages.extend("clike", { 3405 "class-name": [ 3406 Prism.languages.clike["class-name"], 3407 { 3408 pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/, 3409 lookbehind: true 3410 } 3411 ], 3412 "keyword": [ 3413 { 3414 pattern: /((?:^|\})\s*)catch\b/, 3415 lookbehind: true 3416 }, 3417 { 3418 pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/, 3419 lookbehind: true 3420 } 3421 ], 3422 // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444) 3423 "function": /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/, 3424 "number": { 3425 pattern: RegExp( 3426 /(^|[^\w$])/.source + "(?:" + // constant 3427 (/NaN|Infinity/.source + "|" + // binary integer 3428 /0[bB][01]+(?:_[01]+)*n?/.source + "|" + // octal integer 3429 /0[oO][0-7]+(?:_[0-7]+)*n?/.source + "|" + // hexadecimal integer 3430 /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source + "|" + // decimal bigint 3431 /\d+(?:_\d+)*n/.source + "|" + // decimal number (integer or float) but no bigint 3432 /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source) + ")" + /(?![\w$])/.source 3433 ), 3434 lookbehind: true 3435 }, 3436 "operator": /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/ 3437 }); 3438 Prism.languages.javascript["class-name"][0].pattern = /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/; 3439 Prism.languages.insertBefore("javascript", "keyword", { 3440 "regex": { 3441 pattern: RegExp( 3442 // lookbehind 3443 // eslint-disable-next-line regexp/no-dupe-characters-character-class 3444 /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source + // Regex pattern: 3445 // There are 2 regex patterns here. The RegExp set notation proposal added support for nested character 3446 // classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible 3447 // with the only syntax, so we have to define 2 different regex patterns. 3448 /\//.source + "(?:" + /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source + "|" + // `v` flag syntax. This supports 3 levels of nested character classes. 3449 /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source + ")" + // lookahead 3450 /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source 3451 ), 3452 lookbehind: true, 3453 greedy: true, 3454 inside: { 3455 "regex-source": { 3456 pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/, 3457 lookbehind: true, 3458 alias: "language-regex", 3459 inside: Prism.languages.regex 3460 }, 3461 "regex-delimiter": /^\/|\/$/, 3462 "regex-flags": /^[a-z]+$/ 3463 } 3464 }, 3465 // This must be declared before keyword because we use "function" inside the look-forward 3466 "function-variable": { 3467 pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/, 3468 alias: "function" 3469 }, 3470 "parameter": [ 3471 { 3472 pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/, 3473 lookbehind: true, 3474 inside: Prism.languages.javascript 3475 }, 3476 { 3477 pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i, 3478 lookbehind: true, 3479 inside: Prism.languages.javascript 3480 }, 3481 { 3482 pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/, 3483 lookbehind: true, 3484 inside: Prism.languages.javascript 3485 }, 3486 { 3487 pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/, 3488 lookbehind: true, 3489 inside: Prism.languages.javascript 3490 } 3491 ], 3492 "constant": /\b[A-Z](?:[A-Z_]|\dx?)*\b/ 3493 }); 3494 Prism.languages.insertBefore("javascript", "string", { 3495 "hashbang": { 3496 pattern: /^#!.*/, 3497 greedy: true, 3498 alias: "comment" 3499 }, 3500 "template-string": { 3501 pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/, 3502 greedy: true, 3503 inside: { 3504 "template-punctuation": { 3505 pattern: /^`|`$/, 3506 alias: "string" 3507 }, 3508 "interpolation": { 3509 pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/, 3510 lookbehind: true, 3511 inside: { 3512 "interpolation-punctuation": { 3513 pattern: /^\$\{|\}$/, 3514 alias: "punctuation" 3515 }, 3516 rest: Prism.languages.javascript 3517 } 3518 }, 3519 "string": /[\s\S]+/ 3520 } 3521 }, 3522 "string-property": { 3523 pattern: /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m, 3524 lookbehind: true, 3525 greedy: true, 3526 alias: "property" 3527 } 3528 }); 3529 Prism.languages.insertBefore("javascript", "operator", { 3530 "literal-property": { 3531 pattern: /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m, 3532 lookbehind: true, 3533 alias: "property" 3534 } 3535 }); 3536 if (Prism.languages.markup) { 3537 Prism.languages.markup.tag.addInlined("script", "javascript"); 3538 Prism.languages.markup.tag.addAttribute( 3539 /on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source, 3540 "javascript" 3541 ); 3542 } 3543 Prism.languages.js = Prism.languages.javascript; 3544 3545
vendor: 5,558 bytes, lines 3545-3724
3545// node_modules/prismjs/components/prism-markup.js 3546 Prism.languages.markup = { 3547 "comment": { 3548 pattern: /<!--(?:(?!<!--)[\s\S])*?-->/, 3549 greedy: true 3550 }, 3551 "prolog": { 3552 pattern: /<\?[\s\S]+?\?>/, 3553 greedy: true 3554 }, 3555 "doctype": { 3556 // https://www.w3.org/TR/xml/#NT-doctypedecl 3557 pattern: /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i, 3558 greedy: true, 3559 inside: { 3560 "internal-subset": { 3561 pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/, 3562 lookbehind: true, 3563 greedy: true, 3564 inside: null 3565 // see below 3566 }, 3567 "string": { 3568 pattern: /"[^"]*"|'[^']*'/, 3569 greedy: true 3570 }, 3571 "punctuation": /^<!|>$|[[\]]/, 3572 "doctype-tag": /^DOCTYPE/i, 3573 "name": /[^\s<>'"]+/ 3574 } 3575 }, 3576 "cdata": { 3577 pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, 3578 greedy: true 3579 }, 3580 "tag": { 3581 pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/, 3582 greedy: true, 3583 inside: { 3584 "tag": { 3585 pattern: /^<\/?[^\s>\/]+/, 3586 inside: { 3587 "punctuation": /^<\/?/, 3588 "namespace": /^[^\s>\/:]+:/ 3589 } 3590 }, 3591 "special-attr": [], 3592 "attr-value": { 3593 pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/, 3594 inside: { 3595 "punctuation": [ 3596 { 3597 pattern: /^=/, 3598 alias: "attr-equals" 3599 }, 3600 { 3601 pattern: /^(\s*)["']|["']$/, 3602 lookbehind: true 3603 } 3604 ] 3605 } 3606 }, 3607 "punctuation": /\/?>/, 3608 "attr-name": { 3609 pattern: /[^\s>\/]+/, 3610 inside: { 3611 "namespace": /^[^\s>\/:]+:/ 3612 } 3613 } 3614 } 3615 }, 3616 "entity": [ 3617 { 3618 pattern: /&[\da-z]{1,8};/i, 3619 alias: "named-entity" 3620 }, 3621 /&#x?[\da-f]{1,8};/i 3622 ] 3623 }; 3624 Prism.languages.markup["tag"].inside["attr-value"].inside["entity"] = Prism.languages.markup["entity"]; 3625 Prism.languages.markup["doctype"].inside["internal-subset"].inside = Prism.languages.markup; 3626 Prism.hooks.add("wrap", function(env) { 3627 if (env.type === "entity") { 3628 env.attributes["title"] = env.content.replace(/&/, "&"); 3629 } 3630 }); 3631 Object.defineProperty(Prism.languages.markup.tag, "addInlined", { 3632 /** 3633 * Adds an inlined language to markup. 3634 * 3635 * An example of an inlined language is CSS with `<style>` tags. 3636 * 3637 * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as 3638 * case insensitive. 3639 * @param {string} lang The language key. 3640 * @example 3641 * addInlined('style', 'css'); 3642 */ 3643 value: function addInlined(tagName, lang) { 3644 var includedCdataInside = {}; 3645 includedCdataInside["language-" + lang] = { 3646 pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i, 3647 lookbehind: true, 3648 inside: Prism.languages[lang] 3649 }; 3650 includedCdataInside["cdata"] = /^<!\[CDATA\[|\]\]>$/i; 3651 var inside = { 3652 "included-cdata": { 3653 pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, 3654 inside: includedCdataInside 3655 } 3656 }; 3657 inside["language-" + lang] = { 3658 pattern: /[\s\S]+/, 3659 inside: Prism.languages[lang] 3660 }; 3661 var def = {}; 3662 def[tagName] = { 3663 pattern: RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function() { 3664 return tagName; 3665 }), "i"), 3666 lookbehind: true, 3667 greedy: true, 3668 inside 3669 }; 3670 Prism.languages.insertBefore("markup", "cdata", def); 3671 } 3672 }); 3673 Object.defineProperty(Prism.languages.markup.tag, "addAttribute", { 3674 /** 3675 * Adds an pattern to highlight languages embedded in HTML attributes. 3676 * 3677 * An example of an inlined language is CSS with `style` attributes. 3678 * 3679 * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as 3680 * case insensitive. 3681 * @param {string} lang The language key. 3682 * @example 3683 * addAttribute('style', 'css'); 3684 */ 3685 value: function(attrName, lang) { 3686 Prism.languages.markup.tag.inside["special-attr"].push({ 3687 pattern: RegExp( 3688 /(^|["'\s])/.source + "(?:" + attrName + ")" + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source, 3689 "i" 3690 ), 3691 lookbehind: true, 3692 inside: { 3693 "attr-name": /^[^\s=]+/, 3694 "attr-value": { 3695 pattern: /=[\s\S]+/, 3696 inside: { 3697 "value": { 3698 pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/, 3699 lookbehind: true, 3700 alias: [lang, "language-" + lang], 3701 inside: Prism.languages[lang] 3702 }, 3703 "punctuation": [ 3704 { 3705 pattern: /^=/, 3706 alias: "attr-equals" 3707 }, 3708 /"|'/ 3709 ] 3710 } 3711 } 3712 } 3713 }); 3714 } 3715 }); 3716 Prism.languages.html = Prism.languages.markup; 3717 Prism.languages.mathml = Prism.languages.markup; 3718 Prism.languages.svg = Prism.languages.markup; 3719 Prism.languages.xml = Prism.languages.extend("markup", {}); 3720 Prism.languages.ssml = Prism.languages.xml; 3721 Prism.languages.atom = Prism.languages.xml; 3722 Prism.languages.rss = Prism.languages.xml; 3723 3724
vendor: 11,010 bytes, lines 3724-4065
3724// node_modules/prismjs/components/prism-markdown.js 3725 (function(Prism3) { 3726 var inner = /(?:\\.|[^\\\n\r]|(?:\n|\r\n?)(?![\r\n]))/.source; 3727 function createInline(pattern) { 3728 pattern = pattern.replace(/<inner>/g, function() { 3729 return inner; 3730 }); 3731 return RegExp(/((?:^|[^\\])(?:\\{2})*)/.source + "(?:" + pattern + ")"); 3732 } 3733 var tableCell = /(?:\\.|``(?:[^`\r\n]|`(?!`))+``|`[^`\r\n]+`|[^\\|\r\n`])+/.source; 3734 var tableRow = /\|?__(?:\|__)+\|?(?:(?:\n|\r\n?)|(?![\s\S]))/.source.replace(/__/g, function() { 3735 return tableCell; 3736 }); 3737 var tableLine = /\|?[ \t]*:?-{3,}:?[ \t]*(?:\|[ \t]*:?-{3,}:?[ \t]*)+\|?(?:\n|\r\n?)/.source; 3738 Prism3.languages.markdown = Prism3.languages.extend("markup", {}); 3739 Prism3.languages.insertBefore("markdown", "prolog", { 3740 "front-matter-block": { 3741 pattern: /(^(?:\s*[\r\n])?)---(?!.)[\s\S]*?[\r\n]---(?!.)/, 3742 lookbehind: true, 3743 greedy: true, 3744 inside: { 3745 "punctuation": /^---|---$/, 3746 "front-matter": { 3747 pattern: /\S+(?:\s+\S+)*/, 3748 alias: ["yaml", "language-yaml"], 3749 inside: Prism3.languages.yaml 3750 } 3751 } 3752 }, 3753 "blockquote": { 3754 // > ... 3755 pattern: /^>(?:[\t ]*>)*/m, 3756 alias: "punctuation" 3757 }, 3758 "table": { 3759 pattern: RegExp("^" + tableRow + tableLine + "(?:" + tableRow + ")*", "m"), 3760 inside: { 3761 "table-data-rows": { 3762 pattern: RegExp("^(" + tableRow + tableLine + ")(?:" + tableRow + ")*$"), 3763 lookbehind: true, 3764 inside: { 3765 "table-data": { 3766 pattern: RegExp(tableCell), 3767 inside: Prism3.languages.markdown 3768 }, 3769 "punctuation": /\|/ 3770 } 3771 }, 3772 "table-line": { 3773 pattern: RegExp("^(" + tableRow + ")" + tableLine + "$"), 3774 lookbehind: true, 3775 inside: { 3776 "punctuation": /\||:?-{3,}:?/ 3777 } 3778 }, 3779 "table-header-row": { 3780 pattern: RegExp("^" + tableRow + "$"), 3781 inside: { 3782 "table-header": { 3783 pattern: RegExp(tableCell), 3784 alias: "important", 3785 inside: Prism3.languages.markdown 3786 }, 3787 "punctuation": /\|/ 3788 } 3789 } 3790 } 3791 }, 3792 "code": [ 3793 { 3794 // Prefixed by 4 spaces or 1 tab and preceded by an empty line 3795 pattern: /((?:^|\n)[ \t]*\n|(?:^|\r\n?)[ \t]*\r\n?)(?: {4}|\t).+(?:(?:\n|\r\n?)(?: {4}|\t).+)*/, 3796 lookbehind: true, 3797 alias: "keyword" 3798 }, 3799 { 3800 // ```optional language 3801 // code block 3802 // ``` 3803 pattern: /^```[\s\S]*?^```$/m, 3804 greedy: true, 3805 inside: { 3806 "code-block": { 3807 pattern: /^(```.*(?:\n|\r\n?))[\s\S]+?(?=(?:\n|\r\n?)^```$)/m, 3808 lookbehind: true 3809 }, 3810 "code-language": { 3811 pattern: /^(```).+/, 3812 lookbehind: true 3813 }, 3814 "punctuation": /```/ 3815 } 3816 } 3817 ], 3818 "title": [ 3819 { 3820 // title 1 3821 // ======= 3822 // title 2 3823 // ------- 3824 pattern: /\S.*(?:\n|\r\n?)(?:==+|--+)(?=[ \t]*$)/m, 3825 alias: "important", 3826 inside: { 3827 punctuation: /==+$|--+$/ 3828 } 3829 }, 3830 { 3831 // # title 1 3832 // ###### title 6 3833 pattern: /(^\s*)#.+/m, 3834 lookbehind: true, 3835 alias: "important", 3836 inside: { 3837 punctuation: /^#+|#+$/ 3838 } 3839 } 3840 ], 3841 "hr": { 3842 // *** 3843 // --- 3844 // * * * 3845 // ----------- 3846 pattern: /(^\s*)([*-])(?:[\t ]*\2){2,}(?=\s*$)/m, 3847 lookbehind: true, 3848 alias: "punctuation" 3849 }, 3850 "list": { 3851 // * item 3852 // + item 3853 // - item 3854 // 1. item 3855 pattern: /(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m, 3856 lookbehind: true, 3857 alias: "punctuation" 3858 }, 3859 "url-reference": { 3860 // [id]: http://example.com "Optional title" 3861 // [id]: http://example.com 'Optional title' 3862 // [id]: http://example.com (Optional title) 3863 // [id]: <http://example.com> "Optional title" 3864 pattern: /!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/, 3865 inside: { 3866 "variable": { 3867 pattern: /^(!?\[)[^\]]+/, 3868 lookbehind: true 3869 }, 3870 "string": /(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/, 3871 "punctuation": /^[\[\]!:]|[<>]/ 3872 }, 3873 alias: "url" 3874 }, 3875 "bold": { 3876 // **strong** 3877 // __strong__ 3878 // allow one nested instance of italic text using the same delimiter 3879 pattern: createInline(/\b__(?:(?!_)<inner>|_(?:(?!_)<inner>)+_)+__\b|\*\*(?:(?!\*)<inner>|\*(?:(?!\*)<inner>)+\*)+\*\*/.source), 3880 lookbehind: true, 3881 greedy: true, 3882 inside: { 3883 "content": { 3884 pattern: /(^..)[\s\S]+(?=..$)/, 3885 lookbehind: true, 3886 inside: {} 3887 // see below 3888 }, 3889 "punctuation": /\*\*|__/ 3890 } 3891 }, 3892 "italic": { 3893 // *em* 3894 // _em_ 3895 // allow one nested instance of bold text using the same delimiter 3896 pattern: createInline(/\b_(?:(?!_)<inner>|__(?:(?!_)<inner>)+__)+_\b|\*(?:(?!\*)<inner>|\*\*(?:(?!\*)<inner>)+\*\*)+\*/.source), 3897 lookbehind: true, 3898 greedy: true, 3899 inside: { 3900 "content": { 3901 pattern: /(^.)[\s\S]+(?=.$)/, 3902 lookbehind: true, 3903 inside: {} 3904 // see below 3905 }, 3906 "punctuation": /[*_]/ 3907 } 3908 }, 3909 "strike": { 3910 // ~~strike through~~ 3911 // ~strike~ 3912 // eslint-disable-next-line regexp/strict 3913 pattern: createInline(/(~~?)(?:(?!~)<inner>)+\2/.source), 3914 lookbehind: true, 3915 greedy: true, 3916 inside: { 3917 "content": { 3918 pattern: /(^~~?)[\s\S]+(?=\1$)/, 3919 lookbehind: true, 3920 inside: {} 3921 // see below 3922 }, 3923 "punctuation": /~~?/ 3924 } 3925 }, 3926 "code-snippet": { 3927 // `code` 3928 // ``code`` 3929 pattern: /(^|[^\\`])(?:``[^`\r\n]+(?:`[^`\r\n]+)*``(?!`)|`[^`\r\n]+`(?!`))/, 3930 lookbehind: true, 3931 greedy: true, 3932 alias: ["code", "keyword"] 3933 }, 3934 "url": { 3935 // [example](http://example.com "Optional title") 3936 // [example][id] 3937 // [example] [id] 3938 pattern: createInline(/!?\[(?:(?!\])<inner>)+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)|[ \t]?\[(?:(?!\])<inner>)+\])/.source), 3939 lookbehind: true, 3940 greedy: true, 3941 inside: { 3942 "operator": /^!/, 3943 "content": { 3944 pattern: /(^\[)[^\]]+(?=\])/, 3945 lookbehind: true, 3946 inside: {} 3947 // see below 3948 }, 3949 "variable": { 3950 pattern: /(^\][ \t]?\[)[^\]]+(?=\]$)/, 3951 lookbehind: true 3952 }, 3953 "url": { 3954 pattern: /(^\]\()[^\s)]+/, 3955 lookbehind: true 3956 }, 3957 "string": { 3958 pattern: /(^[ \t]+)"(?:\\.|[^"\\])*"(?=\)$)/, 3959 lookbehind: true 3960 } 3961 } 3962 } 3963 }); 3964 ["url", "bold", "italic", "strike"].forEach(function(token) { 3965 ["url", "bold", "italic", "strike", "code-snippet"].forEach(function(inside) { 3966 if (token !== inside) { 3967 Prism3.languages.markdown[token].inside.content.inside[inside] = Prism3.languages.markdown[inside]; 3968 } 3969 }); 3970 }); 3971 Prism3.hooks.add("after-tokenize", function(env) { 3972 if (env.language !== "markdown" && env.language !== "md") { 3973 return; 3974 } 3975 function walkTokens(tokens) { 3976 if (!tokens || typeof tokens === "string") { 3977 return; 3978 } 3979 for (var i2 = 0, l4 = tokens.length; i2 < l4; i2++) { 3980 var token = tokens[i2]; 3981 if (token.type !== "code") { 3982 walkTokens(token.content); 3983 continue; 3984 } 3985 var codeLang = token.content[1]; 3986 var codeBlock = token.content[3]; 3987 if (codeLang && codeBlock && codeLang.type === "code-language" && codeBlock.type === "code-block" && typeof codeLang.content === "string") { 3988 var lang = codeLang.content.replace(/\b#/g, "sharp").replace(/\b\+\+/g, "pp"); 3989 lang = (/[a-z][\w-]*/i.exec(lang) || [""])[0].toLowerCase(); 3990 var alias = "language-" + lang; 3991 if (!codeBlock.alias) { 3992 codeBlock.alias = [alias]; 3993 } else if (typeof codeBlock.alias === "string") { 3994 codeBlock.alias = [codeBlock.alias, alias]; 3995 } else { 3996 codeBlock.alias.push(alias); 3997 } 3998 } 3999 } 4000 } 4001 walkTokens(env.tokens); 4002 }); 4003 Prism3.hooks.add("wrap", function(env) { 4004 if (env.type !== "code-block") { 4005 return; 4006 } 4007 var codeLang = ""; 4008 for (var i2 = 0, l4 = env.classes.length; i2 < l4; i2++) { 4009 var cls = env.classes[i2]; 4010 var match = /language-(.+)/.exec(cls); 4011 if (match) { 4012 codeLang = match[1]; 4013 break; 4014 } 4015 } 4016 var grammar = Prism3.languages[codeLang]; 4017 if (!grammar) { 4018 if (codeLang && codeLang !== "none" && Prism3.plugins.autoloader) { 4019 var id3 = "md-" + (/* @__PURE__ */ new Date()).valueOf() + "-" + Math.floor(Math.random() * 1e16); 4020 env.attributes["id"] = id3; 4021 Prism3.plugins.autoloader.loadLanguages(codeLang, function() { 4022 var ele = document.getElementById(id3); 4023 if (ele) { 4024 ele.innerHTML = Prism3.highlight(ele.textContent, Prism3.languages[codeLang], codeLang); 4025 } 4026 }); 4027 } 4028 } else { 4029 env.content = Prism3.highlight(textContent(env.content), grammar, codeLang); 4030 } 4031 }); 4032 var tagPattern = RegExp(Prism3.languages.markup.tag.pattern.source, "gi"); 4033 var KNOWN_ENTITY_NAMES = { 4034 "amp": "&", 4035 "lt": "<", 4036 "gt": ">", 4037 "quot": '"' 4038 }; 4039 var fromCodePoint = String.fromCodePoint || String.fromCharCode; 4040 function textContent(html2) { 4041 var text2 = html2.replace(tagPattern, ""); 4042 text2 = text2.replace(/&(\w{1,8}|#x?[\da-f]{1,8});/gi, function(m3, code) { 4043 code = code.toLowerCase(); 4044 if (code[0] === "#") { 4045 var value; 4046 if (code[1] === "x") { 4047 value = parseInt(code.slice(2), 16); 4048 } else { 4049 value = Number(code.slice(1)); 4050 } 4051 return fromCodePoint(value); 4052 } else { 4053 var known = KNOWN_ENTITY_NAMES[code]; 4054 if (known) { 4055 return known; 4056 } 4057 return m3; 4058 } 4059 }); 4060 return text2; 4061 } 4062 Prism3.languages.md = Prism3.languages.markdown; 4063 })(Prism); 4064 4065
vendor: 2,997 bytes, lines 4065-4143
4065// node_modules/prismjs/components/prism-c.js 4066 Prism.languages.c = Prism.languages.extend("clike", { 4067 "comment": { 4068 pattern: /\/\/(?:[^\r\n\\]|\\(?:\r\n?|\n|(?![\r\n])))*|\/\*[\s\S]*?(?:\*\/|$)/, 4069 greedy: true 4070 }, 4071 "string": { 4072 // https://en.cppreference.com/w/c/language/string_literal 4073 pattern: /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/, 4074 greedy: true 4075 }, 4076 "class-name": { 4077 pattern: /(\b(?:enum|struct)\s+(?:__attribute__\s*\(\([\s\S]*?\)\)\s*)?)\w+|\b[a-z]\w*_t\b/, 4078 lookbehind: true 4079 }, 4080 "keyword": /\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\b/, 4081 "function": /\b[a-z_]\w*(?=\s*\()/i, 4082 "number": /(?:\b0x(?:[\da-f]+(?:\.[\da-f]*)?|\.[\da-f]+)(?:p[+-]?\d+)?|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?)[ful]{0,4}/i, 4083 "operator": />>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*/%&|^!=<>]=?/ 4084 }); 4085 Prism.languages.insertBefore("c", "string", { 4086 "char": { 4087 // https://en.cppreference.com/w/c/language/character_constant 4088 pattern: /'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n]){0,32}'/, 4089 greedy: true 4090 } 4091 }); 4092 Prism.languages.insertBefore("c", "string", { 4093 "macro": { 4094 // allow for multiline macro definitions 4095 // spaces after the # character compile fine with gcc 4096 pattern: /(^[\t ]*)#\s*[a-z](?:[^\r\n\\/]|\/(?!\*)|\/\*(?:[^*]|\*(?!\/))*\*\/|\\(?:\r\n|[\s\S]))*/im, 4097 lookbehind: true, 4098 greedy: true, 4099 alias: "property", 4100 inside: { 4101 "string": [ 4102 { 4103 // highlight the path of the include statement as a string 4104 pattern: /^(#\s*include\s*)<[^>]+>/, 4105 lookbehind: true 4106 }, 4107 Prism.languages.c["string"] 4108 ], 4109 "char": Prism.languages.c["char"], 4110 "comment": Prism.languages.c["comment"], 4111 "macro-name": [ 4112 { 4113 pattern: /(^#\s*define\s+)\w+\b(?!\()/i, 4114 lookbehind: true 4115 }, 4116 { 4117 pattern: /(^#\s*define\s+)\w+\b(?=\()/i, 4118 lookbehind: true, 4119 alias: "function" 4120 } 4121 ], 4122 // highlight macro directives as keywords 4123 "directive": { 4124 pattern: /^(#\s*)[a-z]+/, 4125 lookbehind: true, 4126 alias: "keyword" 4127 }, 4128 "directive-hash": /^#/, 4129 "punctuation": /##|\\(?=[\r\n])/, 4130 "expression": { 4131 pattern: /\S[\s\S]*/, 4132 inside: Prism.languages.c 4133 } 4134 } 4135 } 4136 }); 4137 Prism.languages.insertBefore("c", "function", { 4138 // highlight predefined macros as constants 4139 "constant": /\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\b/ 4140 }); 4141 delete Prism.languages.c["boolean"]; 4142 4143
vendor: 2,077 bytes, lines 4143-4204
4143// node_modules/prismjs/components/prism-css.js 4144 (function(Prism3) { 4145 var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/; 4146 Prism3.languages.css = { 4147 "comment": /\/\*[\s\S]*?\*\//, 4148 "atrule": { 4149 pattern: RegExp("@[\\w-](?:" + /[^;{\s"']|\s+(?!\s)/.source + "|" + string.source + ")*?" + /(?:;|(?=\s*\{))/.source), 4150 inside: { 4151 "rule": /^@[\w-]+/, 4152 "selector-function-argument": { 4153 pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/, 4154 lookbehind: true, 4155 alias: "selector" 4156 }, 4157 "keyword": { 4158 pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/, 4159 lookbehind: true 4160 } 4161 // See rest below 4162 } 4163 }, 4164 "url": { 4165 // https://drafts.csswg.org/css-values-3/#urls 4166 pattern: RegExp("\\burl\\((?:" + string.source + "|" + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + ")\\)", "i"), 4167 greedy: true, 4168 inside: { 4169 "function": /^url/i, 4170 "punctuation": /^\(|\)$/, 4171 "string": { 4172 pattern: RegExp("^" + string.source + "$"), 4173 alias: "url" 4174 } 4175 } 4176 }, 4177 "selector": { 4178 pattern: RegExp(`(^|[{}\\s])[^{}\\s](?:[^{};"'\\s]|\\s+(?![\\s{])|` + string.source + ")*(?=\\s*\\{)"), 4179 lookbehind: true 4180 }, 4181 "string": { 4182 pattern: string, 4183 greedy: true 4184 }, 4185 "property": { 4186 pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i, 4187 lookbehind: true 4188 }, 4189 "important": /!important\b/i, 4190 "function": { 4191 pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i, 4192 lookbehind: true 4193 }, 4194 "punctuation": /[(){};:,]/ 4195 }; 4196 Prism3.languages.css["atrule"].inside.rest = Prism3.languages.css; 4197 var markup = Prism3.languages.markup; 4198 if (markup) { 4199 markup.tag.addInlined("style", "css"); 4200 markup.tag.addAttribute("style", "css"); 4201 } 4202 })(Prism); 4203 4204
vendor: 807 bytes, lines 4204-4216
4204// node_modules/prismjs/components/prism-objectivec.js 4205 Prism.languages.objectivec = Prism.languages.extend("c", { 4206 "string": { 4207 pattern: /@?"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"/, 4208 greedy: true 4209 }, 4210 "keyword": /\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\b/, 4211 "operator": /-[->]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|\|?|[~^%?*\/@]/ 4212 }); 4213 delete Prism.languages.objectivec["class-name"]; 4214 Prism.languages.objc = Prism.languages.objectivec; 4215 4216
vendor: 3,619 bytes, lines 4216-4251
4216// node_modules/prismjs/components/prism-sql.js 4217 Prism.languages.sql = { 4218 "comment": { 4219 pattern: /(^|[^\\])(?:\/\*[\s\S]*?\*\/|(?:--|\/\/|#).*)/, 4220 lookbehind: true 4221 }, 4222 "variable": [ 4223 { 4224 pattern: /@(["'`])(?:\\[\s\S]|(?!\1)[^\\])+\1/, 4225 greedy: true 4226 }, 4227 /@[\w.$]+/ 4228 ], 4229 "string": { 4230 pattern: /(^|[^@\\])("|')(?:\\[\s\S]|(?!\2)[^\\]|\2\2)*\2/, 4231 greedy: true, 4232 lookbehind: true 4233 }, 4234 "identifier": { 4235 pattern: /(^|[^@\\])`(?:\\[\s\S]|[^`\\]|``)*`/, 4236 greedy: true, 4237 lookbehind: true, 4238 inside: { 4239 "punctuation": /^`|`$/ 4240 } 4241 }, 4242 "function": /\b(?:AVG|COUNT|FIRST|FORMAT|LAST|LCASE|LEN|MAX|MID|MIN|MOD|NOW|ROUND|SUM|UCASE)(?=\s*\()/i, 4243 // Should we highlight user defined functions too? 4244 "keyword": /\b(?:ACTION|ADD|AFTER|ALGORITHM|ALL|ALTER|ANALYZE|ANY|APPLY|AS|ASC|AUTHORIZATION|AUTO_INCREMENT|BACKUP|BDB|BEGIN|BERKELEYDB|BIGINT|BINARY|BIT|BLOB|BOOL|BOOLEAN|BREAK|BROWSE|BTREE|BULK|BY|CALL|CASCADED?|CASE|CHAIN|CHAR(?:ACTER|SET)?|CHECK(?:POINT)?|CLOSE|CLUSTERED|COALESCE|COLLATE|COLUMNS?|COMMENT|COMMIT(?:TED)?|COMPUTE|CONNECT|CONSISTENT|CONSTRAINT|CONTAINS(?:TABLE)?|CONTINUE|CONVERT|CREATE|CROSS|CURRENT(?:_DATE|_TIME|_TIMESTAMP|_USER)?|CURSOR|CYCLE|DATA(?:BASES?)?|DATE(?:TIME)?|DAY|DBCC|DEALLOCATE|DEC|DECIMAL|DECLARE|DEFAULT|DEFINER|DELAYED|DELETE|DELIMITERS?|DENY|DESC|DESCRIBE|DETERMINISTIC|DISABLE|DISCARD|DISK|DISTINCT|DISTINCTROW|DISTRIBUTED|DO|DOUBLE|DROP|DUMMY|DUMP(?:FILE)?|DUPLICATE|ELSE(?:IF)?|ENABLE|ENCLOSED|END|ENGINE|ENUM|ERRLVL|ERRORS|ESCAPED?|EXCEPT|EXEC(?:UTE)?|EXISTS|EXIT|EXPLAIN|EXTENDED|FETCH|FIELDS|FILE|FILLFACTOR|FIRST|FIXED|FLOAT|FOLLOWING|FOR(?: EACH ROW)?|FORCE|FOREIGN|FREETEXT(?:TABLE)?|FROM|FULL|FUNCTION|GEOMETRY(?:COLLECTION)?|GLOBAL|GOTO|GRANT|GROUP|HANDLER|HASH|HAVING|HOLDLOCK|HOUR|IDENTITY(?:COL|_INSERT)?|IF|IGNORE|IMPORT|INDEX|INFILE|INNER|INNODB|INOUT|INSERT|INT|INTEGER|INTERSECT|INTERVAL|INTO|INVOKER|ISOLATION|ITERATE|JOIN|KEYS?|KILL|LANGUAGE|LAST|LEAVE|LEFT|LEVEL|LIMIT|LINENO|LINES|LINESTRING|LOAD|LOCAL|LOCK|LONG(?:BLOB|TEXT)|LOOP|MATCH(?:ED)?|MEDIUM(?:BLOB|INT|TEXT)|MERGE|MIDDLEINT|MINUTE|MODE|MODIFIES|MODIFY|MONTH|MULTI(?:LINESTRING|POINT|POLYGON)|NATIONAL|NATURAL|NCHAR|NEXT|NO|NONCLUSTERED|NULLIF|NUMERIC|OFF?|OFFSETS?|ON|OPEN(?:DATASOURCE|QUERY|ROWSET)?|OPTIMIZE|OPTION(?:ALLY)?|ORDER|OUT(?:ER|FILE)?|OVER|PARTIAL|PARTITION|PERCENT|PIVOT|PLAN|POINT|POLYGON|PRECEDING|PRECISION|PREPARE|PREV|PRIMARY|PRINT|PRIVILEGES|PROC(?:EDURE)?|PUBLIC|PURGE|QUICK|RAISERROR|READS?|REAL|RECONFIGURE|REFERENCES|RELEASE|RENAME|REPEAT(?:ABLE)?|REPLACE|REPLICATION|REQUIRE|RESIGNAL|RESTORE|RESTRICT|RETURN(?:ING|S)?|REVOKE|RIGHT|ROLLBACK|ROUTINE|ROW(?:COUNT|GUIDCOL|S)?|RTREE|RULE|SAVE(?:POINT)?|SCHEMA|SECOND|SELECT|SERIAL(?:IZABLE)?|SESSION(?:_USER)?|SET(?:USER)?|SHARE|SHOW|SHUTDOWN|SIMPLE|SMALLINT|SNAPSHOT|SOME|SONAME|SQL|START(?:ING)?|STATISTICS|STATUS|STRIPED|SYSTEM_USER|TABLES?|TABLESPACE|TEMP(?:ORARY|TABLE)?|TERMINATED|TEXT(?:SIZE)?|THEN|TIME(?:STAMP)?|TINY(?:BLOB|INT|TEXT)|TOP?|TRAN(?:SACTIONS?)?|TRIGGER|TRUNCATE|TSEQUAL|TYPES?|UNBOUNDED|UNCOMMITTED|UNDEFINED|UNION|UNIQUE|UNLOCK|UNPIVOT|UNSIGNED|UPDATE(?:TEXT)?|USAGE|USE|USER|USING|VALUES?|VAR(?:BINARY|CHAR|CHARACTER|YING)|VIEW|WAITFOR|WARNINGS|WHEN|WHERE|WHILE|WITH(?: ROLLUP|IN)?|WORK|WRITE(?:TEXT)?|YEAR)\b/i, 4245 "boolean": /\b(?:FALSE|NULL|TRUE)\b/i, 4246 "number": /\b0x[\da-f]+\b|\b\d+(?:\.\d*)?|\B\.\d+\b/i, 4247 "operator": /[-+*\/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?|\b(?:AND|BETWEEN|DIV|ILIKE|IN|IS|LIKE|NOT|OR|REGEXP|RLIKE|SOUNDS LIKE|XOR)\b/i, 4248 "punctuation": /[;[\]()`,.]/ 4249 }; 4250 4251
vendor: 3,404 bytes, lines 4251-4308
4251// node_modules/prismjs/components/prism-powershell.js 4252 (function(Prism3) { 4253 var powershell = Prism3.languages.powershell = { 4254 "comment": [ 4255 { 4256 pattern: /(^|[^`])<#[\s\S]*?#>/, 4257 lookbehind: true 4258 }, 4259 { 4260 pattern: /(^|[^`])#.*/, 4261 lookbehind: true 4262 } 4263 ], 4264 "string": [ 4265 { 4266 pattern: /"(?:`[\s\S]|[^`"])*"/, 4267 greedy: true, 4268 inside: null 4269 // see below 4270 }, 4271 { 4272 pattern: /'(?:[^']|'')*'/, 4273 greedy: true 4274 } 4275 ], 4276 // Matches name spaces as well as casts, attribute decorators. Force starting with letter to avoid matching array indices 4277 // Supports two levels of nested brackets (e.g. `[OutputType([System.Collections.Generic.List[int]])]`) 4278 "namespace": /\[[a-z](?:\[(?:\[[^\]]*\]|[^\[\]])*\]|[^\[\]])*\]/i, 4279 "boolean": /\$(?:false|true)\b/i, 4280 "variable": /\$\w+\b/, 4281 // Cmdlets and aliases. Aliases should come last, otherwise "write" gets preferred over "write-host" for example 4282 // Get-Command | ?{ $_.ModuleName -match "Microsoft.PowerShell.(Util|Core|Management)" } 4283 // Get-Alias | ?{ $_.ReferencedCommand.Module.Name -match "Microsoft.PowerShell.(Util|Core|Management)" } 4284 "function": [ 4285 /\b(?:Add|Approve|Assert|Backup|Block|Checkpoint|Clear|Close|Compare|Complete|Compress|Confirm|Connect|Convert|ConvertFrom|ConvertTo|Copy|Debug|Deny|Disable|Disconnect|Dismount|Edit|Enable|Enter|Exit|Expand|Export|Find|ForEach|Format|Get|Grant|Group|Hide|Import|Initialize|Install|Invoke|Join|Limit|Lock|Measure|Merge|Move|New|Open|Optimize|Out|Ping|Pop|Protect|Publish|Push|Read|Receive|Redo|Register|Remove|Rename|Repair|Request|Reset|Resize|Resolve|Restart|Restore|Resume|Revoke|Save|Search|Select|Send|Set|Show|Skip|Sort|Split|Start|Step|Stop|Submit|Suspend|Switch|Sync|Tee|Test|Trace|Unblock|Undo|Uninstall|Unlock|Unprotect|Unpublish|Unregister|Update|Use|Wait|Watch|Where|Write)-[a-z]+\b/i, 4286 /\b(?:ac|cat|chdir|clc|cli|clp|clv|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|ebp|echo|epal|epcsv|epsn|erase|fc|fl|ft|fw|gal|gbp|gc|gci|gcs|gdr|gi|gl|gm|gp|gps|group|gsv|gu|gv|gwmi|iex|ii|ipal|ipcsv|ipsn|irm|iwmi|iwr|kill|lp|ls|measure|mi|mount|move|mp|mv|nal|ndr|ni|nv|ogv|popd|ps|pushd|pwd|rbp|rd|rdr|ren|ri|rm|rmdir|rni|rnp|rp|rv|rvpa|rwmi|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls|sort|sp|spps|spsv|start|sv|swmi|tee|trcm|type|write)\b/i 4287 ], 4288 // per http://technet.microsoft.com/en-us/library/hh847744.aspx 4289 "keyword": /\b(?:Begin|Break|Catch|Class|Continue|Data|Define|Do|DynamicParam|Else|ElseIf|End|Exit|Filter|Finally|For|ForEach|From|Function|If|InlineScript|Parallel|Param|Process|Return|Sequence|Switch|Throw|Trap|Try|Until|Using|Var|While|Workflow)\b/i, 4290 "operator": { 4291 pattern: /(^|\W)(?:!|-(?:b?(?:and|x?or)|as|(?:Not)?(?:Contains|In|Like|Match)|eq|ge|gt|is(?:Not)?|Join|le|lt|ne|not|Replace|sh[lr])\b|-[-=]?|\+[+=]?|[*\/%]=?)/i, 4292 lookbehind: true 4293 }, 4294 "punctuation": /[|{}[\];(),.]/ 4295 }; 4296 powershell.string[0].inside = { 4297 "function": { 4298 // Allow for one level of nesting 4299 pattern: /(^|[^`])\$\((?:\$\([^\r\n()]*\)|(?!\$\()[^\r\n)])*\)/, 4300 lookbehind: true, 4301 inside: powershell 4302 }, 4303 "boolean": powershell.boolean, 4304 "variable": powershell.variable 4305 }; 4306 })(Prism); 4307 4308
vendor: 2,829 bytes, lines 4308-4373
4308// node_modules/prismjs/components/prism-python.js 4309 Prism.languages.python = { 4310 "comment": { 4311 pattern: /(^|[^\\])#.*/, 4312 lookbehind: true, 4313 greedy: true 4314 }, 4315 "string-interpolation": { 4316 pattern: /(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i, 4317 greedy: true, 4318 inside: { 4319 "interpolation": { 4320 // "{" <expression> <optional "!s", "!r", or "!a"> <optional ":" format specifier> "}" 4321 pattern: /((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/, 4322 lookbehind: true, 4323 inside: { 4324 "format-spec": { 4325 pattern: /(:)[^:(){}]+(?=\}$)/, 4326 lookbehind: true 4327 }, 4328 "conversion-option": { 4329 pattern: //, 4330 alias: "punctuation" 4331 }, 4332 rest: null 4333 } 4334 }, 4335 "string": /[\s\S]+/ 4336 } 4337 }, 4338 "triple-quoted-string": { 4339 pattern: /(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i, 4340 greedy: true, 4341 alias: "string" 4342 }, 4343 "string": { 4344 pattern: /(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i, 4345 greedy: true 4346 }, 4347 "function": { 4348 pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g, 4349 lookbehind: true 4350 }, 4351 "class-name": { 4352 pattern: /(\bclass\s+)\w+/i, 4353 lookbehind: true 4354 }, 4355 "decorator": { 4356 pattern: /(^[\t ]*)@\w+(?:\.\w+)*/m, 4357 lookbehind: true, 4358 alias: ["annotation", "punctuation"], 4359 inside: { 4360 "punctuation": /\./ 4361 } 4362 }, 4363 "keyword": /\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/, 4364 "builtin": /\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/, 4365 "boolean": /\b(?:False|None|True)\b/, 4366 "number": /\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i, 4367 "operator": /[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/, 4368 "punctuation": /[{}[\];(),.:]/ 4369 }; 4370 Prism.languages.python["string-interpolation"].inside["interpolation"].inside.rest = Prism.languages.python; 4371 Prism.languages.py = Prism.languages.python; 4372 4373
vendor: 4,406 bytes, lines 4373-4496
4373// node_modules/prismjs/components/prism-rust.js 4374 (function(Prism3) { 4375 var multilineComment = /\/\*(?:[^*/]|\*(?!\/)|\/(?!\*)|<self>)*\*\//.source; 4376 for (var i2 = 0; i2 < 2; i2++) { 4377 multilineComment = multilineComment.replace(/<self>/g, function() { 4378 return multilineComment; 4379 }); 4380 } 4381 multilineComment = multilineComment.replace(/<self>/g, function() { 4382 return /[^\s\S]/.source; 4383 }); 4384 Prism3.languages.rust = { 4385 "comment": [ 4386 { 4387 pattern: RegExp(/(^|[^\\])/.source + multilineComment), 4388 lookbehind: true, 4389 greedy: true 4390 }, 4391 { 4392 pattern: /(^|[^\\:])\/\/.*/, 4393 lookbehind: true, 4394 greedy: true 4395 } 4396 ], 4397 "string": { 4398 pattern: /b?"(?:\\[\s\S]|[^\\"])*"|b?r(#*)"(?:[^"]|"(?!\1))*"\1/, 4399 greedy: true 4400 }, 4401 "char": { 4402 pattern: /b?'(?:\\(?:x[0-7][\da-fA-F]|u\{(?:[\da-fA-F]_*){1,6}\}|.)|[^\\\r\n\t'])'/, 4403 greedy: true 4404 }, 4405 "attribute": { 4406 pattern: /#!?\[(?:[^\[\]"]|"(?:\\[\s\S]|[^\\"])*")*\]/, 4407 greedy: true, 4408 alias: "attr-name", 4409 inside: { 4410 "string": null 4411 // see below 4412 } 4413 }, 4414 // Closure params should not be confused with bitwise OR | 4415 "closure-params": { 4416 pattern: /([=(,:]\s*|\bmove\s*)\|[^|]*\||\|[^|]*\|(?=\s*(?:\{|->))/, 4417 lookbehind: true, 4418 greedy: true, 4419 inside: { 4420 "closure-punctuation": { 4421 pattern: /^\||\|$/, 4422 alias: "punctuation" 4423 }, 4424 rest: null 4425 // see below 4426 } 4427 }, 4428 "lifetime-annotation": { 4429 pattern: /'\w+/, 4430 alias: "symbol" 4431 }, 4432 "fragment-specifier": { 4433 pattern: /(\$\w+:)[a-z]+/, 4434 lookbehind: true, 4435 alias: "punctuation" 4436 }, 4437 "variable": /\$\w+/, 4438 "function-definition": { 4439 pattern: /(\bfn\s+)\w+/, 4440 lookbehind: true, 4441 alias: "function" 4442 }, 4443 "type-definition": { 4444 pattern: /(\b(?:enum|struct|trait|type|union)\s+)\w+/, 4445 lookbehind: true, 4446 alias: "class-name" 4447 }, 4448 "module-declaration": [ 4449 { 4450 pattern: /(\b(?:crate|mod)\s+)[a-z][a-z_\d]*/, 4451 lookbehind: true, 4452 alias: "namespace" 4453 }, 4454 { 4455 pattern: /(\b(?:crate|self|super)\s*)::\s*[a-z][a-z_\d]*\b(?:\s*::(?:\s*[a-z][a-z_\d]*\s*::)*)?/, 4456 lookbehind: true, 4457 alias: "namespace", 4458 inside: { 4459 "punctuation": /::/ 4460 } 4461 } 4462 ], 4463 "keyword": [ 4464 // https://github.com/rust-lang/reference/blob/master/src/keywords.md 4465 /\b(?:Self|abstract|as|async|await|become|box|break|const|continue|crate|do|dyn|else|enum|extern|final|fn|for|if|impl|in|let|loop|macro|match|mod|move|mut|override|priv|pub|ref|return|self|static|struct|super|trait|try|type|typeof|union|unsafe|unsized|use|virtual|where|while|yield)\b/, 4466 // primitives and str 4467 // https://doc.rust-lang.org/stable/rust-by-example/primitives.html 4468 /\b(?:bool|char|f(?:32|64)|[ui](?:8|16|32|64|128|size)|str)\b/ 4469 ], 4470 // functions can technically start with an upper-case letter, but this will introduce a lot of false positives 4471 // and Rust's naming conventions recommend snake_case anyway. 4472 // https://doc.rust-lang.org/1.0.0/style/style/naming/README.html 4473 "function": /\b[a-z_]\w*(?=\s*(?:::\s*<|\())/, 4474 "macro": { 4475 pattern: /\b\w+!/, 4476 alias: "property" 4477 }, 4478 "constant": /\b[A-Z_][A-Z_\d]+\b/, 4479 "class-name": /\b[A-Z]\w*\b/, 4480 "namespace": { 4481 pattern: /(?:\b[a-z][a-z_\d]*\s*::\s*)*\b[a-z][a-z_\d]*\s*::(?!\s*<)/, 4482 inside: { 4483 "punctuation": /::/ 4484 } 4485 }, 4486 // Hex, oct, bin, dec numbers with visual separators and type suffix 4487 "number": /\b(?:0x[\dA-Fa-f](?:_?[\dA-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:(?:\d(?:_?\d)*)?\.)?\d(?:_?\d)*(?:[Ee][+-]?\d+)?)(?:_?(?:f32|f64|[iu](?:8|16|32|64|size)?))?\b/, 4488 "boolean": /\b(?:false|true)\b/, 4489 "punctuation": /->|\.\.=|\.{1,3}|::|[{}[\];(),:]/, 4490 "operator": /[-+*\/%!^]=?|=[=>]?|&[&=]?|\|[|=]?|<<?=?|>>?=?|[@?]/ 4491 }; 4492 Prism3.languages.rust["closure-params"].inside.rest = Prism3.languages.rust; 4493 Prism3.languages.rust["attribute"].inside["string"] = Prism3.languages.rust["string"]; 4494 })(Prism); 4495 4496
vendor: 4,712 bytes, lines 4496-4611
4496// node_modules/prismjs/components/prism-swift.js 4497 Prism.languages.swift = { 4498 "comment": { 4499 // Nested comments are supported up to 2 levels 4500 pattern: /(^|[^\\:])(?:\/\/.*|\/\*(?:[^/*]|\/(?!\*)|\*(?!\/)|\/\*(?:[^*]|\*(?!\/))*\*\/)*\*\/)/, 4501 lookbehind: true, 4502 greedy: true 4503 }, 4504 "string-literal": [ 4505 // https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html 4506 { 4507 pattern: RegExp( 4508 /(^|[^"#])/.source + "(?:" + /"(?:\\(?:\((?:[^()]|\([^()]*\))*\)|\r\n|[^(])|[^\\\r\n"])*"/.source + "|" + /"""(?:\\(?:\((?:[^()]|\([^()]*\))*\)|[^(])|[^\\"]|"(?!""))*"""/.source + ")" + /(?!["#])/.source 4509 ), 4510 lookbehind: true, 4511 greedy: true, 4512 inside: { 4513 "interpolation": { 4514 pattern: /(\\\()(?:[^()]|\([^()]*\))*(?=\))/, 4515 lookbehind: true, 4516 inside: null 4517 // see below 4518 }, 4519 "interpolation-punctuation": { 4520 pattern: /^\)|\\\($/, 4521 alias: "punctuation" 4522 }, 4523 "punctuation": /\\(?=[\r\n])/, 4524 "string": /[\s\S]+/ 4525 } 4526 }, 4527 { 4528 pattern: RegExp( 4529 /(^|[^"#])(#+)/.source + "(?:" + /"(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|\r\n|[^#])|[^\\\r\n])*?"/.source + "|" + /"""(?:\\(?:#+\((?:[^()]|\([^()]*\))*\)|[^#])|[^\\])*?"""/.source + ")\\2" 4530 ), 4531 lookbehind: true, 4532 greedy: true, 4533 inside: { 4534 "interpolation": { 4535 pattern: /(\\#+\()(?:[^()]|\([^()]*\))*(?=\))/, 4536 lookbehind: true, 4537 inside: null 4538 // see below 4539 }, 4540 "interpolation-punctuation": { 4541 pattern: /^\)|\\#+\($/, 4542 alias: "punctuation" 4543 }, 4544 "string": /[\s\S]+/ 4545 } 4546 } 4547 ], 4548 "directive": { 4549 // directives with conditions 4550 pattern: RegExp( 4551 /#/.source + "(?:" + (/(?:elseif|if)\b/.source + "(?:[ ]*" + /(?:![ \t]*)?(?:\b\w+\b(?:[ \t]*\((?:[^()]|\([^()]*\))*\))?|\((?:[^()]|\([^()]*\))*\))(?:[ \t]*(?:&&|\|\|))?/.source + ")+") + "|" + /(?:else|endif)\b/.source + ")" 4552 ), 4553 alias: "property", 4554 inside: { 4555 "directive-name": /^#\w+/, 4556 "boolean": /\b(?:false|true)\b/, 4557 "number": /\b\d+(?:\.\d+)*\b/, 4558 "operator": /!|&&|\|\||[<>]=?/, 4559 "punctuation": /[(),]/ 4560 } 4561 }, 4562 "literal": { 4563 pattern: /#(?:colorLiteral|column|dsohandle|file(?:ID|Literal|Path)?|function|imageLiteral|line)\b/, 4564 alias: "constant" 4565 }, 4566 "other-directive": { 4567 pattern: /#\w+\b/, 4568 alias: "property" 4569 }, 4570 "attribute": { 4571 pattern: /@\w+/, 4572 alias: "atrule" 4573 }, 4574 "function-definition": { 4575 pattern: /(\bfunc\s+)\w+/, 4576 lookbehind: true, 4577 alias: "function" 4578 }, 4579 "label": { 4580 // https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html#ID141 4581 pattern: /\b(break|continue)\s+\w+|\b[a-zA-Z_]\w*(?=\s*:\s*(?:for|repeat|while)\b)/, 4582 lookbehind: true, 4583 alias: "important" 4584 }, 4585 "keyword": /\b(?:Any|Protocol|Self|Type|actor|as|assignment|associatedtype|associativity|async|await|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic|else|enum|extension|fallthrough|fileprivate|final|for|func|get|guard|higherThan|if|import|in|indirect|infix|init|inout|internal|is|isolated|lazy|left|let|lowerThan|mutating|none|nonisolated|nonmutating|open|operator|optional|override|postfix|precedencegroup|prefix|private|protocol|public|repeat|required|rethrows|return|right|safe|self|set|some|static|struct|subscript|super|switch|throw|throws|try|typealias|unowned|unsafe|var|weak|where|while|willSet)\b/, 4586 "boolean": /\b(?:false|true)\b/, 4587 "nil": { 4588 pattern: /\bnil\b/, 4589 alias: "constant" 4590 }, 4591 "short-argument": /\$\d+\b/, 4592 "omit": { 4593 pattern: /\b_\b/, 4594 alias: "keyword" 4595 }, 4596 "number": /\b(?:[\d_]+(?:\.[\de_]+)?|0x[a-f0-9_]+(?:\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\b/i, 4597 // A class name must start with an upper-case letter and be either 1 letter long or contain a lower-case letter. 4598 "class-name": /\b[A-Z](?:[A-Z_\d]*[a-z]\w*)?\b/, 4599 "function": /\b[a-z_]\w*(?=\s*\()/i, 4600 "constant": /\b(?:[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\b/, 4601 // Operators are generic in Swift. Developers can even create new operators (e.g. +++). 4602 // https://docs.swift.org/swift-book/ReferenceManual/zzSummaryOfTheGrammar.html#ID481 4603 // This regex only supports ASCII operators. 4604 "operator": /[-+*/%=!<>&|^~?]+|\.[.\-+*/%=!<>&|^~?]+/, 4605 "punctuation": /[{}[\]();,.:\\]/ 4606 }; 4607 Prism.languages.swift["string-literal"].forEach(function(rule) { 4608 rule.inside["interpolation"].inside = Prism.languages.swift; 4609 }); 4610 4611
vendor: 2,083 bytes, lines 4611-4664
4611// node_modules/prismjs/components/prism-typescript.js 4612 (function(Prism3) { 4613 Prism3.languages.typescript = Prism3.languages.extend("javascript", { 4614 "class-name": { 4615 pattern: /(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/, 4616 lookbehind: true, 4617 greedy: true, 4618 inside: null 4619 // see below 4620 }, 4621 "builtin": /\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/ 4622 }); 4623 Prism3.languages.typescript.keyword.push( 4624 /\b(?:abstract|declare|is|keyof|readonly|require)\b/, 4625 // keywords that have to be followed by an identifier 4626 /\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/, 4627 // This is for `import type *, {}` 4628 /\btype\b(?=\s*(?:[\{*]|$))/ 4629 ); 4630 delete Prism3.languages.typescript["parameter"]; 4631 delete Prism3.languages.typescript["literal-property"]; 4632 var typeInside = Prism3.languages.extend("typescript", {}); 4633 delete typeInside["class-name"]; 4634 Prism3.languages.typescript["class-name"].inside = typeInside; 4635 Prism3.languages.insertBefore("typescript", "function", { 4636 "decorator": { 4637 pattern: /@[$\w\xA0-\uFFFF]+/, 4638 inside: { 4639 "at": { 4640 pattern: /^@/, 4641 alias: "operator" 4642 }, 4643 "function": /^[\s\S]+/ 4644 } 4645 }, 4646 "generic-function": { 4647 // e.g. foo<T extends "bar" | "baz">( ... 4648 pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/, 4649 greedy: true, 4650 inside: { 4651 "function": /^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/, 4652 "generic": { 4653 pattern: /<[\s\S]+/, 4654 // everything after the first < 4655 alias: "class-name", 4656 inside: typeInside 4657 } 4658 } 4659 } 4660 }); 4661 Prism3.languages.ts = Prism3.languages.typescript; 4662 })(Prism); 4663 4664
vendor: 4,679 bytes, lines 4664-4784
4664// node_modules/prismjs/components/prism-java.js 4665 (function(Prism3) { 4666 var keywords = /\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\s*[(){}[\]<>=%~.:,;?+\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\b/; 4667 var classNamePrefix = /(?:[a-z]\w*\s*\.\s*)*(?:[A-Z]\w*\s*\.\s*)*/.source; 4668 var className = { 4669 pattern: RegExp(/(^|[^\w.])/.source + classNamePrefix + /[A-Z](?:[\d_A-Z]*[a-z]\w*)?\b/.source), 4670 lookbehind: true, 4671 inside: { 4672 "namespace": { 4673 pattern: /^[a-z]\w*(?:\s*\.\s*[a-z]\w*)*(?:\s*\.)?/, 4674 inside: { 4675 "punctuation": /\./ 4676 } 4677 }, 4678 "punctuation": /\./ 4679 } 4680 }; 4681 Prism3.languages.java = Prism3.languages.extend("clike", { 4682 "string": { 4683 pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"/, 4684 lookbehind: true, 4685 greedy: true 4686 }, 4687 "class-name": [ 4688 className, 4689 { 4690 // variables, parameters, and constructor references 4691 // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods) 4692 pattern: RegExp(/(^|[^\w.])/.source + classNamePrefix + /[A-Z]\w*(?=\s+\w+\s*[;,=()]|\s*(?:\[[\s,]*\]\s*)?::\s*new\b)/.source), 4693 lookbehind: true, 4694 inside: className.inside 4695 }, 4696 { 4697 // class names based on keyword 4698 // this to support class names (or generic parameters) which do not contain a lower case letter (also works for methods) 4699 pattern: RegExp(/(\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\s+)/.source + classNamePrefix + /[A-Z]\w*\b/.source), 4700 lookbehind: true, 4701 inside: className.inside 4702 } 4703 ], 4704 "keyword": keywords, 4705 "function": [ 4706 Prism3.languages.clike.function, 4707 { 4708 pattern: /(::\s*)[a-z_]\w*/, 4709 lookbehind: true 4710 } 4711 ], 4712 "number": /\b0b[01][01_]*L?\b|\b0x(?:\.[\da-f_p+-]+|[\da-f_]+(?:\.[\da-f_p+-]+)?)\b|(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?\d[\d_]*)?[dfl]?/i, 4713 "operator": { 4714 pattern: /(^|[^.])(?:<<=?|>>>?=?|->|--|\+\+|&&|\|\||::|[?:~]|[-+*/%&|^!=<>]=?)/m, 4715 lookbehind: true 4716 }, 4717 "constant": /\b[A-Z][A-Z_\d]+\b/ 4718 }); 4719 Prism3.languages.insertBefore("java", "string", { 4720 "triple-quoted-string": { 4721 // http://openjdk.java.net/jeps/355#Description 4722 pattern: /"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/, 4723 greedy: true, 4724 alias: "string" 4725 }, 4726 "char": { 4727 pattern: /'(?:\\.|[^'\\\r\n]){1,6}'/, 4728 greedy: true 4729 } 4730 }); 4731 Prism3.languages.insertBefore("java", "class-name", { 4732 "annotation": { 4733 pattern: /(^|[^.])@\w+(?:\s*\.\s*\w+)*/, 4734 lookbehind: true, 4735 alias: "punctuation" 4736 }, 4737 "generics": { 4738 pattern: /<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&)|<(?:[\w\s,.?]|&(?!&))*>)*>)*>)*>/, 4739 inside: { 4740 "class-name": className, 4741 "keyword": keywords, 4742 "punctuation": /[<>(),.:]/, 4743 "operator": /[?&|]/ 4744 } 4745 }, 4746 "import": [ 4747 { 4748 pattern: RegExp(/(\bimport\s+)/.source + classNamePrefix + /(?:[A-Z]\w*|\*)(?=\s*;)/.source), 4749 lookbehind: true, 4750 inside: { 4751 "namespace": className.inside.namespace, 4752 "punctuation": /\./, 4753 "operator": /\*/, 4754 "class-name": /\w+/ 4755 } 4756 }, 4757 { 4758 pattern: RegExp(/(\bimport\s+static\s+)/.source + classNamePrefix + /(?:\w+|\*)(?=\s*;)/.source), 4759 lookbehind: true, 4760 alias: "static", 4761 inside: { 4762 "namespace": className.inside.namespace, 4763 "static": /\b\w+$/, 4764 "punctuation": /\./, 4765 "operator": /\*/, 4766 "class-name": /\w+/ 4767 } 4768 } 4769 ], 4770 "namespace": { 4771 pattern: RegExp( 4772 /(\b(?:exports|import(?:\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\s+)(?!<keyword>)[a-z]\w*(?:\.[a-z]\w*)*\.?/.source.replace(/<keyword>/g, function() { 4773 return keywords.source; 4774 }) 4775 ), 4776 lookbehind: true, 4777 inside: { 4778 "punctuation": /\./ 4779 } 4780 } 4781 }); 4782 })(Prism); 4783 4784
vendor: 4,463 bytes, lines 4784-4877
4784// node_modules/prismjs/components/prism-cpp.js 4785 (function(Prism3) { 4786 var keyword = /\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/; 4787 var modName = /\b(?!<keyword>)\w+(?:\s*\.\s*\w+)*\b/.source.replace(/<keyword>/g, function() { 4788 return keyword.source; 4789 }); 4790 Prism3.languages.cpp = Prism3.languages.extend("c", { 4791 "class-name": [ 4792 { 4793 pattern: RegExp(/(\b(?:class|concept|enum|struct|typename)\s+)(?!<keyword>)\w+/.source.replace(/<keyword>/g, function() { 4794 return keyword.source; 4795 })), 4796 lookbehind: true 4797 }, 4798 // This is intended to capture the class name of method implementations like: 4799 // void foo::bar() const {} 4800 // However! The `foo` in the above example could also be a namespace, so we only capture the class name if 4801 // it starts with an uppercase letter. This approximation should give decent results. 4802 /\b[A-Z]\w*(?=\s*::\s*\w+\s*\()/, 4803 // This will capture the class name before destructors like: 4804 // Foo::~Foo() {} 4805 /\b[A-Z_]\w*(?=\s*::\s*~\w+\s*\()/i, 4806 // This also intends to capture the class name of method implementations but here the class has template 4807 // parameters, so it can't be a namespace (until C++ adds generic namespaces). 4808 /\b\w+(?=\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\s*::\s*\w+\s*\()/ 4809 ], 4810 "keyword": keyword, 4811 "number": { 4812 pattern: /(?:\b0b[01']+|\b0x(?:[\da-f']+(?:\.[\da-f']*)?|\.[\da-f']+)(?:p[+-]?[\d']+)?|(?:\b[\d']+(?:\.[\d']*)?|\B\.[\d']+)(?:e[+-]?[\d']+)?)[ful]{0,4}/i, 4813 greedy: true 4814 }, 4815 "operator": />>=?|<<=?|->|--|\+\+|&&|\|\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/, 4816 "boolean": /\b(?:false|true)\b/ 4817 }); 4818 Prism3.languages.insertBefore("cpp", "string", { 4819 "module": { 4820 // https://en.cppreference.com/w/cpp/language/modules 4821 pattern: RegExp( 4822 /(\b(?:import|module)\s+)/.source + "(?:" + // header-name 4823 /"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|<[^<>\r\n]*>/.source + "|" + // module name or partition or both 4824 /<mod-name>(?:\s*:\s*<mod-name>)?|:\s*<mod-name>/.source.replace(/<mod-name>/g, function() { 4825 return modName; 4826 }) + ")" 4827 ), 4828 lookbehind: true, 4829 greedy: true, 4830 inside: { 4831 "string": /^[<"][\s\S]+/, 4832 "operator": /:/, 4833 "punctuation": /\./ 4834 } 4835 }, 4836 "raw-string": { 4837 pattern: /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/, 4838 alias: "string", 4839 greedy: true 4840 } 4841 }); 4842 Prism3.languages.insertBefore("cpp", "keyword", { 4843 "generic-function": { 4844 pattern: /\b(?!operator\b)[a-z_]\w*\s*<(?:[^<>]|<[^<>]*>)*>(?=\s*\()/i, 4845 inside: { 4846 "function": /^\w+/, 4847 "generic": { 4848 pattern: /<[\s\S]+/, 4849 alias: "class-name", 4850 inside: Prism3.languages.cpp 4851 } 4852 } 4853 } 4854 }); 4855 Prism3.languages.insertBefore("cpp", "operator", { 4856 "double-colon": { 4857 pattern: /::/, 4858 alias: "punctuation" 4859 } 4860 }); 4861 Prism3.languages.insertBefore("cpp", "class-name", { 4862 // the base clause is an optional list of parent classes 4863 // https://en.cppreference.com/w/cpp/language/class 4864 "base-clause": { 4865 pattern: /(\b(?:class|struct)\s+\w+\s*:\s*)[^;{}"'\s]+(?:\s+[^;{}"'\s]+)*(?=\s*[;{])/, 4866 lookbehind: true, 4867 greedy: true, 4868 inside: Prism3.languages.extend("cpp", {}) 4869 } 4870 }); 4871 Prism3.languages.insertBefore("inside", "double-colon", { 4872 // All untokenized words that are not namespaces should be class names 4873 "class-name": /\b[a-z_]\w*\b(?!\s*::)/i 4874 }, Prism3.languages.cpp["base-clause"]); 4875 })(Prism); 4876 4877
vendor: 3,855 bytes, lines 4877-4972
4877// node_modules/prismjs/components/prism-markup-templating.js 4878 (function(Prism3) { 4879 function getPlaceholder(language, index) { 4880 return "___" + language.toUpperCase() + index + "___"; 4881 } 4882 Object.defineProperties(Prism3.languages["markup-templating"] = {}, { 4883 buildPlaceholders: { 4884 /** 4885 * Tokenize all inline templating expressions matching `placeholderPattern`. 4886 * 4887 * If `replaceFilter` is provided, only matches of `placeholderPattern` for which `replaceFilter` returns 4888 * `true` will be replaced. 4889 * 4890 * @param {object} env The environment of the `before-tokenize` hook. 4891 * @param {string} language The language id. 4892 * @param {RegExp} placeholderPattern The matches of this pattern will be replaced by placeholders. 4893 * @param {(match: string) => boolean} [replaceFilter] 4894 */ 4895 value: function(env, language, placeholderPattern, replaceFilter) { 4896 if (env.language !== language) { 4897 return; 4898 } 4899 var tokenStack = env.tokenStack = []; 4900 env.code = env.code.replace(placeholderPattern, function(match) { 4901 if (typeof replaceFilter === "function" && !replaceFilter(match)) { 4902 return match; 4903 } 4904 var i2 = tokenStack.length; 4905 var placeholder; 4906 while (env.code.indexOf(placeholder = getPlaceholder(language, i2)) !== -1) { 4907 ++i2; 4908 } 4909 tokenStack[i2] = match; 4910 return placeholder; 4911 }); 4912 env.grammar = Prism3.languages.markup; 4913 } 4914 }, 4915 tokenizePlaceholders: { 4916 /** 4917 * Replace placeholders with proper tokens after tokenizing. 4918 * 4919 * @param {object} env The environment of the `after-tokenize` hook. 4920 * @param {string} language The language id. 4921 */ 4922 value: function(env, language) { 4923 if (env.language !== language || !env.tokenStack) { 4924 return; 4925 } 4926 env.grammar = Prism3.languages[language]; 4927 var j3 = 0; 4928 var keys = Object.keys(env.tokenStack); 4929 function walkTokens(tokens) { 4930 for (var i2 = 0; i2 < tokens.length; i2++) { 4931 if (j3 >= keys.length) { 4932 break; 4933 } 4934 var token = tokens[i2]; 4935 if (typeof token === "string" || token.content && typeof token.content === "string") { 4936 var k2 = keys[j3]; 4937 var t2 = env.tokenStack[k2]; 4938 var s2 = typeof token === "string" ? token : token.content; 4939 var placeholder = getPlaceholder(language, k2); 4940 var index = s2.indexOf(placeholder); 4941 if (index > -1) { 4942 ++j3; 4943 var before = s2.substring(0, index); 4944 var middle = new Prism3.Token(language, Prism3.tokenize(t2, env.grammar), "language-" + language, t2); 4945 var after = s2.substring(index + placeholder.length); 4946 var replacement = []; 4947 if (before) { 4948 replacement.push.apply(replacement, walkTokens([before])); 4949 } 4950 replacement.push(middle); 4951 if (after) { 4952 replacement.push.apply(replacement, walkTokens([after])); 4953 } 4954 if (typeof token === "string") { 4955 tokens.splice.apply(tokens, [i2, 1].concat(replacement)); 4956 } else { 4957 token.content = replacement; 4958 } 4959 } 4960 } else if (token.content) { 4961 walkTokens(token.content); 4962 } 4963 } 4964 return tokens; 4965 } 4966 walkTokens(env.tokens); 4967 } 4968 } 4969 }); 4970 })(Prism); 4971 4972
vendor: 5,803 bytes, lines 4972-5147
4972// node_modules/prismjs/components/prism-ruby.js 4973 (function(Prism3) { 4974 Prism3.languages.ruby = Prism3.languages.extend("clike", { 4975 "comment": { 4976 pattern: /#.*|^=begin\s[\s\S]*?^=end/m, 4977 greedy: true 4978 }, 4979 "class-name": { 4980 pattern: /(\b(?:class|module)\s+|\bcatch\s+\()[\w.\\]+|\b[A-Z_]\w*(?=\s*\.\s*new\b)/, 4981 lookbehind: true, 4982 inside: { 4983 "punctuation": /[.\\]/ 4984 } 4985 }, 4986 "keyword": /\b(?:BEGIN|END|alias|and|begin|break|case|class|def|define_method|defined|do|each|else|elsif|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|private|protected|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/, 4987 "operator": /\.{2,3}|&\.|===|<?=>|[!=]?~|(?:&&|\|\||<<|>>|\*\*|[+\-*/%<>!^&|=])=?|[?:]/, 4988 "punctuation": /[(){}[\].,;]/ 4989 }); 4990 Prism3.languages.insertBefore("ruby", "operator", { 4991 "double-colon": { 4992 pattern: /::/, 4993 alias: "punctuation" 4994 } 4995 }); 4996 var interpolation = { 4997 pattern: /((?:^|[^\\])(?:\\{2})*)#\{(?:[^{}]|\{[^{}]*\})*\}/, 4998 lookbehind: true, 4999 inside: { 5000 "content": { 5001 pattern: /^(#\{)[\s\S]+(?=\}$)/, 5002 lookbehind: true, 5003 inside: Prism3.languages.ruby 5004 }, 5005 "delimiter": { 5006 pattern: /^#\{|\}$/, 5007 alias: "punctuation" 5008 } 5009 } 5010 }; 5011 delete Prism3.languages.ruby.function; 5012 var percentExpression = "(?:" + [ 5013 /([^a-zA-Z0-9\s{(\[<=])(?:(?!\1)[^\\]|\\[\s\S])*\1/.source, 5014 /\((?:[^()\\]|\\[\s\S]|\((?:[^()\\]|\\[\s\S])*\))*\)/.source, 5015 /\{(?:[^{}\\]|\\[\s\S]|\{(?:[^{}\\]|\\[\s\S])*\})*\}/.source, 5016 /\[(?:[^\[\]\\]|\\[\s\S]|\[(?:[^\[\]\\]|\\[\s\S])*\])*\]/.source, 5017 /<(?:[^<>\\]|\\[\s\S]|<(?:[^<>\\]|\\[\s\S])*>)*>/.source 5018 ].join("|") + ")"; 5019 var symbolName = /(?:"(?:\\.|[^"\\\r\n])*"|(?:\b[a-zA-Z_]\w*|[^\s\0-\x7F]+)[?!]?|\$.)/.source; 5020 Prism3.languages.insertBefore("ruby", "keyword", { 5021 "regex-literal": [ 5022 { 5023 pattern: RegExp(/%r/.source + percentExpression + /[egimnosux]{0,6}/.source), 5024 greedy: true, 5025 inside: { 5026 "interpolation": interpolation, 5027 "regex": /[\s\S]+/ 5028 } 5029 }, 5030 { 5031 pattern: /(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/, 5032 lookbehind: true, 5033 greedy: true, 5034 inside: { 5035 "interpolation": interpolation, 5036 "regex": /[\s\S]+/ 5037 } 5038 } 5039 ], 5040 "variable": /[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/, 5041 "symbol": [ 5042 { 5043 pattern: RegExp(/(^|[^:]):/.source + symbolName), 5044 lookbehind: true, 5045 greedy: true 5046 }, 5047 { 5048 pattern: RegExp(/([\r\n{(,][ \t]*)/.source + symbolName + /(?=:(?!:))/.source), 5049 lookbehind: true, 5050 greedy: true 5051 } 5052 ], 5053 "method-definition": { 5054 pattern: /(\bdef\s+)\w+(?:\s*\.\s*\w+)?/, 5055 lookbehind: true, 5056 inside: { 5057 "function": /\b\w+$/, 5058 "keyword": /^self\b/, 5059 "class-name": /^\w+/, 5060 "punctuation": /\./ 5061 } 5062 } 5063 }); 5064 Prism3.languages.insertBefore("ruby", "string", { 5065 "string-literal": [ 5066 { 5067 pattern: RegExp(/%[qQiIwWs]?/.source + percentExpression), 5068 greedy: true, 5069 inside: { 5070 "interpolation": interpolation, 5071 "string": /[\s\S]+/ 5072 } 5073 }, 5074 { 5075 pattern: /("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/, 5076 greedy: true, 5077 inside: { 5078 "interpolation": interpolation, 5079 "string": /[\s\S]+/ 5080 } 5081 }, 5082 { 5083 pattern: /<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i, 5084 alias: "heredoc-string", 5085 greedy: true, 5086 inside: { 5087 "delimiter": { 5088 pattern: /^<<[-~]?[a-z_]\w*|\b[a-z_]\w*$/i, 5089 inside: { 5090 "symbol": /\b\w+/, 5091 "punctuation": /^<<[-~]?/ 5092 } 5093 }, 5094 "interpolation": interpolation, 5095 "string": /[\s\S]+/ 5096 } 5097 }, 5098 { 5099 pattern: /<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i, 5100 alias: "heredoc-string", 5101 greedy: true, 5102 inside: { 5103 "delimiter": { 5104 pattern: /^<<[-~]?'[a-z_]\w*'|\b[a-z_]\w*$/i, 5105 inside: { 5106 "symbol": /\b\w+/, 5107 "punctuation": /^<<[-~]?'|'$/ 5108 } 5109 }, 5110 "string": /[\s\S]+/ 5111 } 5112 } 5113 ], 5114 "command-literal": [ 5115 { 5116 pattern: RegExp(/%x/.source + percentExpression), 5117 greedy: true, 5118 inside: { 5119 "interpolation": interpolation, 5120 "command": { 5121 pattern: /[\s\S]+/, 5122 alias: "string" 5123 } 5124 } 5125 }, 5126 { 5127 pattern: /`(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|[^\\`#\r\n])*`/, 5128 greedy: true, 5129 inside: { 5130 "interpolation": interpolation, 5131 "command": { 5132 pattern: /[\s\S]+/, 5133 alias: "string" 5134 } 5135 } 5136 } 5137 ] 5138 }); 5139 delete Prism3.languages.ruby.string; 5140 Prism3.languages.insertBefore("ruby", "number", { 5141 "builtin": /\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Fixnum|Float|Hash|IO|Integer|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|Stat|String|Struct|Symbol|TMS|Thread|ThreadGroup|Time|TrueClass)\b/, 5142 "constant": /\b[A-Z][A-Z0-9_]*(?:[?!]|\b)/ 5143 }); 5144 Prism3.languages.rb = Prism3.languages.ruby; 5145 })(Prism); 5146 5147
vendor: 10,604 bytes, lines 5147-5476
5147// node_modules/prismjs/components/prism-php.js 5148 (function(Prism3) { 5149 var comment = /\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/; 5150 var constant = [ 5151 { 5152 pattern: /\b(?:false|true)\b/i, 5153 alias: "boolean" 5154 }, 5155 { 5156 pattern: /(::\s*)\b[a-z_]\w*\b(?!\s*\()/i, 5157 greedy: true, 5158 lookbehind: true 5159 }, 5160 { 5161 pattern: /(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i, 5162 greedy: true, 5163 lookbehind: true 5164 }, 5165 /\b(?:null)\b/i, 5166 /\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/ 5167 ]; 5168 var number = /\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i; 5169 var operator = /<?=>|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/; 5170 var punctuation = /[{}\[\](),:;]/; 5171 Prism3.languages.php = { 5172 "delimiter": { 5173 pattern: /\?>$|^<\?(?:php(?=\s)|=)?/i, 5174 alias: "important" 5175 }, 5176 "comment": comment, 5177 "variable": /\$+(?:\w+\b|(?=\{))/, 5178 "package": { 5179 pattern: /(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i, 5180 lookbehind: true, 5181 inside: { 5182 "punctuation": /\\/ 5183 } 5184 }, 5185 "class-name-definition": { 5186 pattern: /(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i, 5187 lookbehind: true, 5188 alias: "class-name" 5189 }, 5190 "function-definition": { 5191 pattern: /(\bfunction\s+)[a-z_]\w*(?=\s*\()/i, 5192 lookbehind: true, 5193 alias: "function" 5194 }, 5195 "keyword": [ 5196 { 5197 pattern: /(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i, 5198 alias: "type-casting", 5199 greedy: true, 5200 lookbehind: true 5201 }, 5202 { 5203 pattern: /([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i, 5204 alias: "type-hint", 5205 greedy: true, 5206 lookbehind: true 5207 }, 5208 { 5209 pattern: /(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i, 5210 alias: "return-type", 5211 greedy: true, 5212 lookbehind: true 5213 }, 5214 { 5215 pattern: /\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i, 5216 alias: "type-declaration", 5217 greedy: true 5218 }, 5219 { 5220 pattern: /(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i, 5221 alias: "type-declaration", 5222 greedy: true, 5223 lookbehind: true 5224 }, 5225 { 5226 pattern: /\b(?:parent|self|static)(?=\s*::)/i, 5227 alias: "static-context", 5228 greedy: true 5229 }, 5230 { 5231 // yield from 5232 pattern: /(\byield\s+)from\b/i, 5233 lookbehind: true 5234 }, 5235 // `class` is always a keyword unlike other keywords 5236 /\bclass\b/i, 5237 { 5238 // https://www.php.net/manual/en/reserved.keywords.php 5239 // 5240 // keywords cannot be preceded by "->" 5241 // the complex lookbehind means `(?<!(?:->|::)\s*)` 5242 pattern: /((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i, 5243 lookbehind: true 5244 } 5245 ], 5246 "argument-name": { 5247 pattern: /([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i, 5248 lookbehind: true 5249 }, 5250 "class-name": [ 5251 { 5252 pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i, 5253 greedy: true, 5254 lookbehind: true 5255 }, 5256 { 5257 pattern: /(\|\s*)\b[a-z_]\w*(?!\\)\b/i, 5258 greedy: true, 5259 lookbehind: true 5260 }, 5261 { 5262 pattern: /\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i, 5263 greedy: true 5264 }, 5265 { 5266 pattern: /(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i, 5267 alias: "class-name-fully-qualified", 5268 greedy: true, 5269 lookbehind: true, 5270 inside: { 5271 "punctuation": /\\/ 5272 } 5273 }, 5274 { 5275 pattern: /(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i, 5276 alias: "class-name-fully-qualified", 5277 greedy: true, 5278 inside: { 5279 "punctuation": /\\/ 5280 } 5281 }, 5282 { 5283 pattern: /(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i, 5284 alias: "class-name-fully-qualified", 5285 greedy: true, 5286 lookbehind: true, 5287 inside: { 5288 "punctuation": /\\/ 5289 } 5290 }, 5291 { 5292 pattern: /\b[a-z_]\w*(?=\s*\$)/i, 5293 alias: "type-declaration", 5294 greedy: true 5295 }, 5296 { 5297 pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i, 5298 alias: ["class-name-fully-qualified", "type-declaration"], 5299 greedy: true, 5300 inside: { 5301 "punctuation": /\\/ 5302 } 5303 }, 5304 { 5305 pattern: /\b[a-z_]\w*(?=\s*::)/i, 5306 alias: "static-context", 5307 greedy: true 5308 }, 5309 { 5310 pattern: /(?:\\?\b[a-z_]\w*)+(?=\s*::)/i, 5311 alias: ["class-name-fully-qualified", "static-context"], 5312 greedy: true, 5313 inside: { 5314 "punctuation": /\\/ 5315 } 5316 }, 5317 { 5318 pattern: /([(,?]\s*)[a-z_]\w*(?=\s*\$)/i, 5319 alias: "type-hint", 5320 greedy: true, 5321 lookbehind: true 5322 }, 5323 { 5324 pattern: /([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i, 5325 alias: ["class-name-fully-qualified", "type-hint"], 5326 greedy: true, 5327 lookbehind: true, 5328 inside: { 5329 "punctuation": /\\/ 5330 } 5331 }, 5332 { 5333 pattern: /(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i, 5334 alias: "return-type", 5335 greedy: true, 5336 lookbehind: true 5337 }, 5338 { 5339 pattern: /(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i, 5340 alias: ["class-name-fully-qualified", "return-type"], 5341 greedy: true, 5342 lookbehind: true, 5343 inside: { 5344 "punctuation": /\\/ 5345 } 5346 } 5347 ], 5348 "constant": constant, 5349 "function": { 5350 pattern: /(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i, 5351 lookbehind: true, 5352 inside: { 5353 "punctuation": /\\/ 5354 } 5355 }, 5356 "property": { 5357 pattern: /(->\s*)\w+/, 5358 lookbehind: true 5359 }, 5360 "number": number, 5361 "operator": operator, 5362 "punctuation": punctuation 5363 }; 5364 var string_interpolation = { 5365 pattern: /\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/, 5366 lookbehind: true, 5367 inside: Prism3.languages.php 5368 }; 5369 var string = [ 5370 { 5371 pattern: /<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/, 5372 alias: "nowdoc-string", 5373 greedy: true, 5374 inside: { 5375 "delimiter": { 5376 pattern: /^<<<'[^']+'|[a-z_]\w*;$/i, 5377 alias: "symbol", 5378 inside: { 5379 "punctuation": /^<<<'?|[';]$/ 5380 } 5381 } 5382 } 5383 }, 5384 { 5385 pattern: /<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i, 5386 alias: "heredoc-string", 5387 greedy: true, 5388 inside: { 5389 "delimiter": { 5390 pattern: /^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i, 5391 alias: "symbol", 5392 inside: { 5393 "punctuation": /^<<<"?|[";]$/ 5394 } 5395 }, 5396 "interpolation": string_interpolation 5397 } 5398 }, 5399 { 5400 pattern: /`(?:\\[\s\S]|[^\\`])*`/, 5401 alias: "backtick-quoted-string", 5402 greedy: true 5403 }, 5404 { 5405 pattern: /'(?:\\[\s\S]|[^\\'])*'/, 5406 alias: "single-quoted-string", 5407 greedy: true 5408 }, 5409 { 5410 pattern: /"(?:\\[\s\S]|[^\\"])*"/, 5411 alias: "double-quoted-string", 5412 greedy: true, 5413 inside: { 5414 "interpolation": string_interpolation 5415 } 5416 } 5417 ]; 5418 Prism3.languages.insertBefore("php", "variable", { 5419 "string": string, 5420 "attribute": { 5421 pattern: /#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im, 5422 greedy: true, 5423 inside: { 5424 "attribute-content": { 5425 pattern: /^(#\[)[\s\S]+(?=\]$)/, 5426 lookbehind: true, 5427 // inside can appear subset of php 5428 inside: { 5429 "comment": comment, 5430 "string": string, 5431 "attribute-class-name": [ 5432 { 5433 pattern: /([^:]|^)\b[a-z_]\w*(?!\\)\b/i, 5434 alias: "class-name", 5435 greedy: true, 5436 lookbehind: true 5437 }, 5438 { 5439 pattern: /([^:]|^)(?:\\?\b[a-z_]\w*)+/i, 5440 alias: [ 5441 "class-name", 5442 "class-name-fully-qualified" 5443 ], 5444 greedy: true, 5445 lookbehind: true, 5446 inside: { 5447 "punctuation": /\\/ 5448 } 5449 } 5450 ], 5451 "constant": constant, 5452 "number": number, 5453 "operator": operator, 5454 "punctuation": punctuation 5455 } 5456 }, 5457 "delimiter": { 5458 pattern: /^#\[|\]$/, 5459 alias: "punctuation" 5460 } 5461 } 5462 } 5463 }); 5464 Prism3.hooks.add("before-tokenize", function(env) { 5465 if (!/<\?/.test(env.code)) { 5466 return; 5467 } 5468 var phpPattern = /<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g; 5469 Prism3.languages["markup-templating"].buildPlaceholders(env, "php", phpPattern); 5470 }); 5471 Prism3.hooks.add("after-tokenize", function(env) { 5472 Prism3.languages["markup-templating"].tokenizePlaceholders(env, "php"); 5473 }); 5474 })(Prism); 5475 5476
vendor: 1,291 bytes, lines 5476-5504
5476// node_modules/prismjs/components/prism-go.js 5477 Prism.languages.go = Prism.languages.extend("clike", { 5478 "string": { 5479 pattern: /(^|[^\\])"(?:\\.|[^"\\\r\n])*"|`[^`]*`/, 5480 lookbehind: true, 5481 greedy: true 5482 }, 5483 "keyword": /\b(?:break|case|chan|const|continue|default|defer|else|fallthrough|for|func|go(?:to)?|if|import|interface|map|package|range|return|select|struct|switch|type|var)\b/, 5484 "boolean": /\b(?:_|false|iota|nil|true)\b/, 5485 "number": [ 5486 // binary and octal integers 5487 /\b0(?:b[01_]+|o[0-7_]+)i?\b/i, 5488 // hexadecimal integers and floats 5489 /\b0x(?:[a-f\d_]+(?:\.[a-f\d_]*)?|\.[a-f\d_]+)(?:p[+-]?\d+(?:_\d+)*)?i?(?!\w)/i, 5490 // decimal integers and floats 5491 /(?:\b\d[\d_]*(?:\.[\d_]*)?|\B\.\d[\d_]*)(?:e[+-]?[\d_]+)?i?(?!\w)/i 5492 ], 5493 "operator": /[*\/%^!=]=?|\+[=+]?|-[=-]?|\|[=|]?|&(?:=|&|\^=?)?|>(?:>=?|=)?|<(?:<=?|=|-)?|:=|\.\.\./, 5494 "builtin": /\b(?:append|bool|byte|cap|close|complex|complex(?:64|128)|copy|delete|error|float(?:32|64)|u?int(?:8|16|32|64)?|imag|len|make|new|panic|print(?:ln)?|real|recover|rune|string|uintptr)\b/ 5495 }); 5496 Prism.languages.insertBefore("go", "string", { 5497 "char": { 5498 pattern: /'(?:\\.|[^'\\\r\n]){0,10}'/, 5499 greedy: true 5500 } 5501 }); 5502 delete Prism.languages.go["class-name"]; 5503 5504
vendor: 10,138 bytes, lines 5504-5732
5504// node_modules/prismjs/components/prism-bash.js 5505 (function(Prism3) { 5506 var envVars = "\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b"; 5507 var commandAfterHeredoc = { 5508 pattern: /(^(["']?)\w+\2)[ \t]+\S.*/, 5509 lookbehind: true, 5510 alias: "punctuation", 5511 // this looks reasonably well in all themes 5512 inside: null 5513 // see below 5514 }; 5515 var insideString = { 5516 "bash": commandAfterHeredoc, 5517 "environment": { 5518 pattern: RegExp("\\$" + envVars), 5519 alias: "constant" 5520 }, 5521 "variable": [ 5522 // [0]: Arithmetic Environment 5523 { 5524 pattern: /\$?\(\([\s\S]+?\)\)/, 5525 greedy: true, 5526 inside: { 5527 // If there is a $ sign at the beginning highlight $(( and )) as variable 5528 "variable": [ 5529 { 5530 pattern: /(^\$\(\([\s\S]+)\)\)/, 5531 lookbehind: true 5532 }, 5533 /^\$\(\(/ 5534 ], 5535 "number": /\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/, 5536 // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic 5537 "operator": /--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/, 5538 // If there is no $ sign at the beginning highlight (( and )) as punctuation 5539 "punctuation": /\(\(?|\)\)?|,|;/ 5540 } 5541 }, 5542 // [1]: Command Substitution 5543 { 5544 pattern: /\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/, 5545 greedy: true, 5546 inside: { 5547 "variable": /^\$\(|^`|\)$|`$/ 5548 } 5549 }, 5550 // [2]: Brace expansion 5551 { 5552 pattern: /\$\{[^}]+\}/, 5553 greedy: true, 5554 inside: { 5555 "operator": /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/, 5556 "punctuation": /[\[\]]/, 5557 "environment": { 5558 pattern: RegExp("(\\{)" + envVars), 5559 lookbehind: true, 5560 alias: "constant" 5561 } 5562 } 5563 }, 5564 /\$(?:\w+|[#?*!@$])/ 5565 ], 5566 // Escape sequences from echo and printf's manuals, and escaped quotes. 5567 "entity": /\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/ 5568 }; 5569 Prism3.languages.bash = { 5570 "shebang": { 5571 pattern: /^#!\s*\/.*/, 5572 alias: "important" 5573 }, 5574 "comment": { 5575 pattern: /(^|[^"{\\$])#.*/, 5576 lookbehind: true 5577 }, 5578 "function-name": [ 5579 // a) function foo { 5580 // b) foo() { 5581 // c) function foo() { 5582 // but not âfoo {â 5583 { 5584 // a) and c) 5585 pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/, 5586 lookbehind: true, 5587 alias: "function" 5588 }, 5589 { 5590 // b) 5591 pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/, 5592 alias: "function" 5593 } 5594 ], 5595 // Highlight variable names as variables in for and select beginnings. 5596 "for-or-select": { 5597 pattern: /(\b(?:for|select)\s+)\w+(?=\s+in\s)/, 5598 alias: "variable", 5599 lookbehind: true 5600 }, 5601 // Highlight variable names as variables in the left-hand part 5602 // of assignments (â=â and â+=â). 5603 "assign-left": { 5604 pattern: /(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/, 5605 inside: { 5606 "environment": { 5607 pattern: RegExp("(^|[\\s;|&]|[<>]\\()" + envVars), 5608 lookbehind: true, 5609 alias: "constant" 5610 } 5611 }, 5612 alias: "variable", 5613 lookbehind: true 5614 }, 5615 // Highlight parameter names as variables 5616 "parameter": { 5617 pattern: /(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/, 5618 alias: "variable", 5619 lookbehind: true 5620 }, 5621 "string": [ 5622 // Support for Here-documents https://en.wikipedia.org/wiki/Here_document 5623 { 5624 pattern: /((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/, 5625 lookbehind: true, 5626 greedy: true, 5627 inside: insideString 5628 }, 5629 // Here-document with quotes around the tag 5630 // â No expansion (so no âinsideâ). 5631 { 5632 pattern: /((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/, 5633 lookbehind: true, 5634 greedy: true, 5635 inside: { 5636 "bash": commandAfterHeredoc 5637 } 5638 }, 5639 // âNormalâ string 5640 { 5641 // https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html 5642 pattern: /(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/, 5643 lookbehind: true, 5644 greedy: true, 5645 inside: insideString 5646 }, 5647 { 5648 // https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html 5649 pattern: /(^|[^$\\])'[^']*'/, 5650 lookbehind: true, 5651 greedy: true 5652 }, 5653 { 5654 // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html 5655 pattern: /\$'(?:[^'\\]|\\[\s\S])*'/, 5656 greedy: true, 5657 inside: { 5658 "entity": insideString.entity 5659 } 5660 } 5661 ], 5662 "environment": { 5663 pattern: RegExp("\\$?" + envVars), 5664 alias: "constant" 5665 }, 5666 "variable": insideString.variable, 5667 "function": { 5668 pattern: /(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/, 5669 lookbehind: true 5670 }, 5671 "keyword": { 5672 pattern: /(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/, 5673 lookbehind: true 5674 }, 5675 // https://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html 5676 "builtin": { 5677 pattern: /(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/, 5678 lookbehind: true, 5679 // Alias added to make those easier to distinguish from strings. 5680 alias: "class-name" 5681 }, 5682 "boolean": { 5683 pattern: /(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/, 5684 lookbehind: true 5685 }, 5686 "file-descriptor": { 5687 pattern: /\B&\d\b/, 5688 alias: "important" 5689 }, 5690 "operator": { 5691 // Lots of redirections here, but not just that. 5692 pattern: /\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/, 5693 inside: { 5694 "file-descriptor": { 5695 pattern: /^\d/, 5696 alias: "important" 5697 } 5698 } 5699 }, 5700 "punctuation": /\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/, 5701 "number": { 5702 pattern: /(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/, 5703 lookbehind: true 5704 } 5705 }; 5706 commandAfterHeredoc.inside = Prism3.languages.bash; 5707 var toBeCopied = [ 5708 "comment", 5709 "function-name", 5710 "for-or-select", 5711 "assign-left", 5712 "parameter", 5713 "string", 5714 "environment", 5715 "function", 5716 "keyword", 5717 "builtin", 5718 "boolean", 5719 "file-descriptor", 5720 "operator", 5721 "punctuation", 5722 "number" 5723 ]; 5724 var inside = insideString.variable[1].inside; 5725 for (var i2 = 0; i2 < toBeCopied.length; i2++) { 5726 inside[toBeCopied[i2]] = Prism3.languages.bash[toBeCopied[i2]]; 5727 } 5728 Prism3.languages.sh = Prism3.languages.bash; 5729 Prism3.languages.shell = Prism3.languages.bash; 5730 })(Prism); 5731 5732
vendor: 688 bytes, lines 5732-5759
5732// node_modules/prismjs/components/prism-json.js 5733 Prism.languages.json = { 5734 "property": { 5735 pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/, 5736 lookbehind: true, 5737 greedy: true 5738 }, 5739 "string": { 5740 pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/, 5741 lookbehind: true, 5742 greedy: true 5743 }, 5744 "comment": { 5745 pattern: /\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/, 5746 greedy: true 5747 }, 5748 "number": /-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i, 5749 "punctuation": /[{}[\],]/, 5750 "operator": /:/, 5751 "boolean": /\b(?:false|true)\b/, 5752 "null": { 5753 pattern: /\bnull\b/, 5754 alias: "keyword" 5755 } 5756 }; 5757 Prism.languages.webmanifest = Prism.languages.json; 5758 5759
vendor: 3,117 bytes, lines 5759-5842
5759// node_modules/prismjs/components/prism-kotlin.js 5760 (function(Prism3) { 5761 Prism3.languages.kotlin = Prism3.languages.extend("clike", { 5762 "keyword": { 5763 // The lookbehind prevents wrong highlighting of e.g. kotlin.properties.get 5764 pattern: /(^|[^.])\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\b/, 5765 lookbehind: true 5766 }, 5767 "function": [ 5768 { 5769 pattern: /(?:`[^\r\n`]+`|\b\w+)(?=\s*\()/, 5770 greedy: true 5771 }, 5772 { 5773 pattern: /(\.)(?:`[^\r\n`]+`|\w+)(?=\s*\{)/, 5774 lookbehind: true, 5775 greedy: true 5776 } 5777 ], 5778 "number": /\b(?:0[xX][\da-fA-F]+(?:_[\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\d+(?:_\d+)*(?:\.\d+(?:_\d+)*)?(?:[eE][+-]?\d+(?:_\d+)*)?[fFL]?)\b/, 5779 "operator": /\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\/*%<>]=?|[?:]:?|\.\.|&&|\|\||\b(?:and|inv|or|shl|shr|ushr|xor)\b/ 5780 }); 5781 delete Prism3.languages.kotlin["class-name"]; 5782 var interpolationInside = { 5783 "interpolation-punctuation": { 5784 pattern: /^\$\{?|\}$/, 5785 alias: "punctuation" 5786 }, 5787 "expression": { 5788 pattern: /[\s\S]+/, 5789 inside: Prism3.languages.kotlin 5790 } 5791 }; 5792 Prism3.languages.insertBefore("kotlin", "string", { 5793 // https://kotlinlang.org/spec/expressions.html#string-interpolation-expressions 5794 "string-literal": [ 5795 { 5796 pattern: /"""(?:[^$]|\$(?:(?!\{)|\{[^{}]*\}))*?"""/, 5797 alias: "multiline", 5798 inside: { 5799 "interpolation": { 5800 pattern: /\$(?:[a-z_]\w*|\{[^{}]*\})/i, 5801 inside: interpolationInside 5802 }, 5803 "string": /[\s\S]+/ 5804 } 5805 }, 5806 { 5807 pattern: /"(?:[^"\\\r\n$]|\\.|\$(?:(?!\{)|\{[^{}]*\}))*"/, 5808 alias: "singleline", 5809 inside: { 5810 "interpolation": { 5811 pattern: /((?:^|[^\\])(?:\\{2})*)\$(?:[a-z_]\w*|\{[^{}]*\})/i, 5812 lookbehind: true, 5813 inside: interpolationInside 5814 }, 5815 "string": /[\s\S]+/ 5816 } 5817 } 5818 ], 5819 "char": { 5820 // https://kotlinlang.org/spec/expressions.html#character-literals 5821 pattern: /'(?:[^'\\\r\n]|\\(?:.|u[a-fA-F0-9]{0,4}))'/, 5822 greedy: true 5823 } 5824 }); 5825 delete Prism3.languages.kotlin["string"]; 5826 Prism3.languages.insertBefore("kotlin", "keyword", { 5827 "annotation": { 5828 pattern: /\B@(?:\w+:)?(?:[A-Z]\w*|\[[^\]]+\])/, 5829 alias: "builtin" 5830 } 5831 }); 5832 Prism3.languages.insertBefore("kotlin", "function", { 5833 "label": { 5834 pattern: /\b\w+@|@\w+\b/, 5835 alias: "symbol" 5836 } 5837 }); 5838 Prism3.languages.kt = Prism3.languages.kotlin; 5839 Prism3.languages.kts = Prism3.languages.kotlin; 5840 })(Prism); 5841 5842
vendor: 3,801 bytes, lines 5842-5948
5842// node_modules/@37signals/lexxy/dist/lexxy_helpers.esm.js 5843 window.Prism ||= {}; 5844 window.Prism.manual = true; 5845 function highlightCode(root = document) { 5846 const elements = root.querySelectorAll("pre[data-language]:not([data-highlighted])"); 5847 elements.forEach((preElement) => { 5848 highlightElement(preElement); 5849 }); 5850 } 5851 function highlightElement(preElement) { 5852 if (preElement.dataset.highlighted === "true") return; 5853 const language = preElement.getAttribute("data-language"); 5854 const grammar = import_prismjs.default.languages?.[language]; 5855 if (!grammar) return; 5856 const { code, highlights } = extractCodeAndHighlights(preElement); 5857 const highlightedHtml = import_prismjs.default.highlight(code, grammar, language); 5858 preElement.innerHTML = highlightedHtml; 5859 if (highlights.length > 0) { 5860 applyHighlightRanges(preElement, highlights); 5861 } 5862 preElement.dataset.highlighted = "true"; 5863 } 5864 function extractCodeAndHighlights(preElement) { 5865 const root = preElement.querySelector("code") || preElement; 5866 const highlights = []; 5867 let code = ""; 5868 function walk(node) { 5869 if (node.nodeType === Node.TEXT_NODE) { 5870 code += node.textContent; 5871 } else if (node.nodeType === Node.ELEMENT_NODE) { 5872 if (node.tagName === "BR") { 5873 code += "\n"; 5874 } else if (node.tagName === "MARK") { 5875 const start3 = code.length; 5876 for (const child of node.childNodes) { 5877 walk(child); 5878 } 5879 const style = extractStyle(node); 5880 if (style) { 5881 highlights.push({ start: start3, end: code.length, style }); 5882 } 5883 } else { 5884 for (const child of node.childNodes) { 5885 walk(child); 5886 } 5887 } 5888 } 5889 } 5890 for (const child of root.childNodes) { 5891 walk(child); 5892 } 5893 return { code, highlights }; 5894 } 5895 function extractStyle(element) { 5896 const parts = []; 5897 if (element.style?.color) parts.push(`color: ${element.style.color};`); 5898 if (element.style?.backgroundColor) parts.push(`background-color: ${element.style.backgroundColor};`); 5899 return parts.length > 0 ? parts.join(" ") : null; 5900 } 5901 function applyHighlightRanges(element, highlights) { 5902 for (const { start: start3, end, style } of highlights) { 5903 wrapRange(element, start3, end, style); 5904 } 5905 } 5906 function wrapRange(container, rangeStart, rangeEnd, style) { 5907 const textNodes = collectTextNodes(container); 5908 for (let i2 = textNodes.length - 1; i2 >= 0; i2--) { 5909 const { node, start: nodeStart, end: nodeEnd } = textNodes[i2]; 5910 const overlapStart = Math.max(rangeStart, nodeStart); 5911 const overlapEnd = Math.min(rangeEnd, nodeEnd); 5912 if (overlapStart >= overlapEnd) continue; 5913 const relStart = overlapStart - nodeStart; 5914 const relEnd = overlapEnd - nodeStart; 5915 const text2 = node.textContent; 5916 const parent = node.parentNode; 5917 const mark = document.createElement("mark"); 5918 mark.setAttribute("style", style); 5919 mark.textContent = text2.slice(relStart, relEnd); 5920 if (relEnd < text2.length) { 5921 parent.insertBefore(document.createTextNode(text2.slice(relEnd)), node.nextSibling); 5922 } 5923 parent.insertBefore(mark, node.nextSibling); 5924 if (relStart > 0) { 5925 node.textContent = text2.slice(0, relStart); 5926 } else { 5927 parent.removeChild(node); 5928 } 5929 } 5930 } 5931 function collectTextNodes(root) { 5932 const nodes = []; 5933 let offset3 = 0; 5934 const walker = document.createTreeWalker( 5935 root, 5936 4 5937 /* NodeFilter.SHOW_TEXT */ 5938 ); 5939 let node; 5940 while (node = walker.nextNode()) { 5941 const length = node.textContent.length; 5942 nodes.push({ node, start: offset3, end: offset3 + length }); 5943 offset3 += length; 5944 } 5945 return nodes; 5946 } 5947 5948
vendor: 66,780 bytes, lines 5948-7395
5948// node_modules/dompurify/dist/purify.es.mjs 5949 function _arrayLikeToArray(r2, a2) { 5950 (null == a2 || a2 > r2.length) && (a2 = r2.length); 5951 for (var e2 = 0, n2 = Array(a2); e2 < a2; e2++) n2[e2] = r2[e2]; 5952 return n2; 5953 } 5954 function _arrayWithHoles(r2) { 5955 if (Array.isArray(r2)) return r2; 5956 } 5957 function _iterableToArrayLimit(r2, l4) { 5958 var t2 = null == r2 ? null : "undefined" != typeof Symbol && r2[Symbol.iterator] || r2["@@iterator"]; 5959 if (null != t2) { 5960 var e2, n2, i2, u2, a2 = [], f = true, o2 = false; 5961 try { 5962 if (i2 = (t2 = t2.call(r2)).next, 0 === l4) ; 5963 else for (; !(f = (e2 = i2.call(t2)).done) && (a2.push(e2.value), a2.length !== l4); f = true) ; 5964 } catch (r3) { 5965 o2 = true, n2 = r3; 5966 } finally { 5967 try { 5968 if (!f && null != t2.return && (u2 = t2.return(), Object(u2) !== u2)) return; 5969 } finally { 5970 if (o2) throw n2; 5971 } 5972 } 5973 return a2; 5974 } 5975 } 5976 function _nonIterableRest() { 5977 throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); 5978 } 5979 function _slicedToArray(r2, e2) { 5980 return _arrayWithHoles(r2) || _iterableToArrayLimit(r2, e2) || _unsupportedIterableToArray(r2, e2) || _nonIterableRest(); 5981 } 5982 function _unsupportedIterableToArray(r2, a2) { 5983 if (r2) { 5984 if ("string" == typeof r2) return _arrayLikeToArray(r2, a2); 5985 var t2 = {}.toString.call(r2).slice(8, -1); 5986 return "Object" === t2 && r2.constructor && (t2 = r2.constructor.name), "Map" === t2 || "Set" === t2 ? Array.from(r2) : "Arguments" === t2 || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t2) ? _arrayLikeToArray(r2, a2) : void 0; 5987 } 5988 } 5989 var entries = Object.entries; 5990 var setPrototypeOf = Object.setPrototypeOf; 5991 var isFrozen = Object.isFrozen; 5992 var getPrototypeOf = Object.getPrototypeOf; 5993 var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; 5994 var freeze = Object.freeze; 5995 var seal = Object.seal; 5996 var create = Object.create; 5997 var _ref = typeof Reflect !== "undefined" && Reflect; 5998 var apply = _ref.apply; 5999 var construct = _ref.construct; 6000 if (!freeze) { 6001 freeze = function freeze2(x3) { 6002 return x3; 6003 }; 6004 } 6005 if (!seal) { 6006 seal = function seal2(x3) { 6007 return x3; 6008 }; 6009 } 6010 if (!apply) { 6011 apply = function apply2(func, thisArg) { 6012 for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { 6013 args[_key - 2] = arguments[_key]; 6014 } 6015 return func.apply(thisArg, args); 6016 }; 6017 } 6018 if (!construct) { 6019 construct = function construct2(Func) { 6020 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 6021 args[_key2 - 1] = arguments[_key2]; 6022 } 6023 return new Func(...args); 6024 }; 6025 } 6026 var arrayForEach = unapply(Array.prototype.forEach); 6027 var arrayLastIndexOf = unapply(Array.prototype.lastIndexOf); 6028 var arrayPop = unapply(Array.prototype.pop); 6029 var arrayPush = unapply(Array.prototype.push); 6030 var arraySplice = unapply(Array.prototype.splice); 6031 var arrayIsArray = Array.isArray; 6032 var stringToLowerCase = unapply(String.prototype.toLowerCase); 6033 var stringToString = unapply(String.prototype.toString); 6034 var stringMatch = unapply(String.prototype.match); 6035 var stringReplace = unapply(String.prototype.replace); 6036 var stringIndexOf = unapply(String.prototype.indexOf); 6037 var stringTrim = unapply(String.prototype.trim); 6038 var numberToString = unapply(Number.prototype.toString); 6039 var booleanToString = unapply(Boolean.prototype.toString); 6040 var bigintToString = typeof BigInt === "undefined" ? null : unapply(BigInt.prototype.toString); 6041 var symbolToString = typeof Symbol === "undefined" ? null : unapply(Symbol.prototype.toString); 6042 var objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty); 6043 var objectToString = unapply(Object.prototype.toString); 6044 var regExpTest = unapply(RegExp.prototype.test); 6045 var typeErrorCreate = unconstruct(TypeError); 6046 function unapply(func) { 6047 return function(thisArg) { 6048 if (thisArg instanceof RegExp) { 6049 thisArg.lastIndex = 0; 6050 } 6051 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { 6052 args[_key3 - 1] = arguments[_key3]; 6053 } 6054 return apply(func, thisArg, args); 6055 }; 6056 } 6057 function unconstruct(Func) { 6058 return function() { 6059 for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { 6060 args[_key4] = arguments[_key4]; 6061 } 6062 return construct(Func, args); 6063 }; 6064 } 6065 function addToSet(set, array) { 6066 let transformCaseFunc = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : stringToLowerCase; 6067 if (setPrototypeOf) { 6068 setPrototypeOf(set, null); 6069 } 6070 if (!arrayIsArray(array)) { 6071 return set; 6072 } 6073 let l4 = array.length; 6074 while (l4--) { 6075 let element = array[l4]; 6076 if (typeof element === "string") { 6077 const lcElement = transformCaseFunc(element); 6078 if (lcElement !== element) { 6079 if (!isFrozen(array)) { 6080 array[l4] = lcElement; 6081 } 6082 element = lcElement; 6083 } 6084 } 6085 set[element] = true; 6086 } 6087 return set; 6088 } 6089 function cleanArray(array) { 6090 for (let index = 0; index < array.length; index++) { 6091 const isPropertyExist = objectHasOwnProperty(array, index); 6092 if (!isPropertyExist) { 6093 array[index] = null; 6094 } 6095 } 6096 return array; 6097 } 6098 function clone(object) { 6099 const newObject = create(null); 6100 for (const _ref2 of entries(object)) { 6101 var _ref3 = _slicedToArray(_ref2, 2); 6102 const property = _ref3[0]; 6103 const value = _ref3[1]; 6104 const isPropertyExist = objectHasOwnProperty(object, property); 6105 if (isPropertyExist) { 6106 if (arrayIsArray(value)) { 6107 newObject[property] = cleanArray(value); 6108 } else if (value && typeof value === "object" && value.constructor === Object) { 6109 newObject[property] = clone(value); 6110 } else { 6111 newObject[property] = value; 6112 } 6113 } 6114 } 6115 return newObject; 6116 } 6117 function stringifyValue(value) { 6118 switch (typeof value) { 6119 case "string": { 6120 return value; 6121 } 6122 case "number": { 6123 return numberToString(value); 6124 } 6125 case "boolean": { 6126 return booleanToString(value); 6127 } 6128 case "bigint": { 6129 return bigintToString ? bigintToString(value) : "0"; 6130 } 6131 case "symbol": { 6132 return symbolToString ? symbolToString(value) : "Symbol()"; 6133 } 6134 case "undefined": { 6135 return objectToString(value); 6136 } 6137 case "function": 6138 case "object": { 6139 if (value === null) { 6140 return objectToString(value); 6141 } 6142 const valueAsRecord = value; 6143 const valueToString = lookupGetter(valueAsRecord, "toString"); 6144 if (typeof valueToString === "function") { 6145 const stringified = valueToString(valueAsRecord); 6146 return typeof stringified === "string" ? stringified : objectToString(stringified); 6147 } 6148 return objectToString(value); 6149 } 6150 default: { 6151 return objectToString(value); 6152 } 6153 } 6154 } 6155 function lookupGetter(object, prop) { 6156 while (object !== null) { 6157 const desc = getOwnPropertyDescriptor(object, prop); 6158 if (desc) { 6159 if (desc.get) { 6160 return unapply(desc.get); 6161 } 6162 if (typeof desc.value === "function") { 6163 return unapply(desc.value); 6164 } 6165 } 6166 object = getPrototypeOf(object); 6167 } 6168 function fallbackValue() { 6169 return null; 6170 } 6171 return fallbackValue; 6172 } 6173 function isRegex(value) { 6174 try { 6175 regExpTest(value, ""); 6176 return true; 6177 } catch (_unused) { 6178 return false; 6179 } 6180 } 6181 var html$1 = freeze(["a", "abbr", "acronym", "address", "area", "article", "aside", "audio", "b", "bdi", "bdo", "big", "blink", "blockquote", "body", "br", "button", "canvas", "caption", "center", "cite", "code", "col", "colgroup", "content", "data", "datalist", "dd", "decorator", "del", "details", "dfn", "dialog", "dir", "div", "dl", "dt", "element", "em", "fieldset", "figcaption", "figure", "font", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", "i", "img", "input", "ins", "kbd", "label", "legend", "li", "main", "map", "mark", "marquee", "menu", "menuitem", "meter", "nav", "nobr", "ol", "optgroup", "option", "output", "p", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "search", "section", "select", "shadow", "slot", "small", "source", "spacer", "span", "strike", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td", "template", "textarea", "tfoot", "th", "thead", "time", "tr", "track", "tt", "u", "ul", "var", "video", "wbr"]); 6182 var svg$1 = freeze(["svg", "a", "altglyph", "altglyphdef", "altglyphitem", "animatecolor", "animatemotion", "animatetransform", "circle", "clippath", "defs", "desc", "ellipse", "enterkeyhint", "exportparts", "filter", "font", "g", "glyph", "glyphref", "hkern", "image", "inputmode", "line", "lineargradient", "marker", "mask", "metadata", "mpath", "part", "path", "pattern", "polygon", "polyline", "radialgradient", "rect", "stop", "style", "switch", "symbol", "text", "textpath", "title", "tref", "tspan", "view", "vkern"]); 6183 var svgFilters = freeze(["feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feDropShadow", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence"]); 6184 var svgDisallowed = freeze(["animate", "color-profile", "cursor", "discard", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "foreignobject", "hatch", "hatchpath", "mesh", "meshgradient", "meshpatch", "meshrow", "missing-glyph", "script", "set", "solidcolor", "unknown", "use"]); 6185 var mathMl$1 = freeze(["math", "menclose", "merror", "mfenced", "mfrac", "mglyph", "mi", "mlabeledtr", "mmultiscripts", "mn", "mo", "mover", "mpadded", "mphantom", "mroot", "mrow", "ms", "mspace", "msqrt", "mstyle", "msub", "msup", "msubsup", "mtable", "mtd", "mtext", "mtr", "munder", "munderover", "mprescripts"]); 6186 var mathMlDisallowed = freeze(["maction", "maligngroup", "malignmark", "mlongdiv", "mscarries", "mscarry", "msgroup", "mstack", "msline", "msrow", "semantics", "annotation", "annotation-xml", "mprescripts", "none"]); 6187 var text = freeze(["#text"]); 6188 var html = freeze(["accept", "action", "align", "alt", "autocapitalize", "autocomplete", "autopictureinpicture", "autoplay", "background", "bgcolor", "border", "capture", "cellpadding", "cellspacing", "checked", "cite", "class", "clear", "color", "cols", "colspan", "command", "commandfor", "controls", "controlslist", "coords", "crossorigin", "datetime", "decoding", "default", "dir", "disabled", "disablepictureinpicture", "disableremoteplayback", "download", "draggable", "enctype", "enterkeyhint", "exportparts", "face", "for", "headers", "height", "hidden", "high", "href", "hreflang", "id", "inert", "inputmode", "integrity", "ismap", "kind", "label", "lang", "list", "loading", "loop", "low", "max", "maxlength", "media", "method", "min", "minlength", "multiple", "muted", "name", "nonce", "noshade", "novalidate", "nowrap", "open", "optimum", "part", "pattern", "placeholder", "playsinline", "popover", "popovertarget", "popovertargetaction", "poster", "preload", "pubdate", "radiogroup", "readonly", "rel", "required", "rev", "reversed", "role", "rows", "rowspan", "spellcheck", "scope", "selected", "shape", "size", "sizes", "slot", "span", "srclang", "start", "src", "srcset", "step", "style", "summary", "tabindex", "title", "translate", "type", "usemap", "valign", "value", "width", "wrap", "xmlns"]); 6189 var svg = freeze(["accent-height", "accumulate", "additive", "alignment-baseline", "amplitude", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dur", "edgemode", "elevation", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "mask-type", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "slope", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "tablevalues", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"]); 6190 var mathMl = freeze(["accent", "accentunder", "align", "bevelled", "close", "columnalign", "columnlines", "columnspacing", "columnspan", "denomalign", "depth", "dir", "display", "displaystyle", "encoding", "fence", "frame", "height", "href", "id", "largeop", "length", "linethickness", "lquote", "lspace", "mathbackground", "mathcolor", "mathsize", "mathvariant", "maxsize", "minsize", "movablelimits", "notation", "numalign", "open", "rowalign", "rowlines", "rowspacing", "rowspan", "rspace", "rquote", "scriptlevel", "scriptminsize", "scriptsizemultiplier", "selection", "separator", "separators", "stretchy", "subscriptshift", "supscriptshift", "symmetric", "voffset", "width", "xmlns"]); 6191 var xml = freeze(["xlink:href", "xml:id", "xlink:title", "xml:space", "xmlns:xlink"]); 6192 var MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g); 6193 var ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g); 6194 var TMPLIT_EXPR = seal(/\${[\w\W]*/g); 6195 var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); 6196 var ARIA_ATTR = seal(/^aria-[\-\w]+$/); 6197 var IS_ALLOWED_URI = seal( 6198 /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i 6199 // eslint-disable-line no-useless-escape 6200 ); 6201 var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i); 6202 var ATTR_WHITESPACE = seal( 6203 /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g 6204 // eslint-disable-line no-control-regex 6205 ); 6206 var DOCTYPE_NAME = seal(/^html$/i); 6207 var CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i); 6208 var ELEMENT_MARKUP_PROBE = seal(/<[/\w!]/g); 6209 var COMMENT_MARKUP_PROBE = seal(/<[/\w]/g); 6210 var FALLBACK_TAG_CLOSE = seal(/<\/no(script|embed|frames)/i); 6211 var SELF_CLOSING_TAG = seal(/\/>/i); 6212 var NODE_TYPE = { 6213 element: 1, 6214 attribute: 2, 6215 text: 3, 6216 cdataSection: 4, 6217 entityReference: 5, 6218 // Deprecated 6219 entityNode: 6, 6220 // Deprecated 6221 processingInstruction: 7, 6222 comment: 8, 6223 document: 9, 6224 documentType: 10, 6225 documentFragment: 11, 6226 notation: 12 6227 // Deprecated 6228 }; 6229 var getGlobal = function getGlobal2() { 6230 return typeof window === "undefined" ? null : window; 6231 }; 6232 var _createTrustedTypesPolicy = function _createTrustedTypesPolicy2(trustedTypes, purifyHostElement) { 6233 if (typeof trustedTypes !== "object" || typeof trustedTypes.createPolicy !== "function") { 6234 return null; 6235 } 6236 let suffix = null; 6237 const ATTR_NAME = "data-tt-policy-suffix"; 6238 if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) { 6239 suffix = purifyHostElement.getAttribute(ATTR_NAME); 6240 } 6241 const policyName = "dompurify" + (suffix ? "#" + suffix : ""); 6242 try { 6243 return trustedTypes.createPolicy(policyName, { 6244 createHTML(html2) { 6245 return html2; 6246 }, 6247 createScriptURL(scriptUrl) { 6248 return scriptUrl; 6249 } 6250 }); 6251 } catch (_3) { 6252 console.warn("TrustedTypes policy " + policyName + " could not be created."); 6253 return null; 6254 } 6255 }; 6256 var _createHooksMap = function _createHooksMap2() { 6257 return { 6258 afterSanitizeAttributes: [], 6259 afterSanitizeElements: [], 6260 afterSanitizeShadowDOM: [], 6261 beforeSanitizeAttributes: [], 6262 beforeSanitizeElements: [], 6263 beforeSanitizeShadowDOM: [], 6264 uponSanitizeAttribute: [], 6265 uponSanitizeElement: [], 6266 uponSanitizeShadowNode: [] 6267 }; 6268 }; 6269 var _resolveSetOption = function _resolveSetOption2(cfg, key, fallback, options) { 6270 return objectHasOwnProperty(cfg, key) && arrayIsArray(cfg[key]) ? addToSet(options.base ? clone(options.base) : {}, cfg[key], options.transform) : fallback; 6271 }; 6272 function createDOMPurify() { 6273 let window2 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : getGlobal(); 6274 const DOMPurify = (root) => createDOMPurify(root); 6275 DOMPurify.version = "3.4.11"; 6276 DOMPurify.removed = []; 6277 if (!window2 || !window2.document || window2.document.nodeType !== NODE_TYPE.document || !window2.Element) { 6278 DOMPurify.isSupported = false; 6279 return DOMPurify; 6280 } 6281 let document2 = window2.document; 6282 const originalDocument = document2; 6283 const currentScript = originalDocument.currentScript; 6284 window2.DocumentFragment; 6285 const HTMLTemplateElement = window2.HTMLTemplateElement, Node2 = window2.Node, Element2 = window2.Element, NodeFilter2 = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap; 6286 _window$NamedNodeMap === void 0 ? window2.NamedNodeMap || window2.MozNamedAttrMap : _window$NamedNodeMap; 6287 window2.HTMLFormElement; 6288 const DOMParser2 = window2.DOMParser, trustedTypes = window2.trustedTypes; 6289 const ElementPrototype = Element2.prototype; 6290 const cloneNode = lookupGetter(ElementPrototype, "cloneNode"); 6291 const remove = lookupGetter(ElementPrototype, "remove"); 6292 const getNextSibling2 = lookupGetter(ElementPrototype, "nextSibling"); 6293 const getChildNodes = lookupGetter(ElementPrototype, "childNodes"); 6294 const getParentNode2 = lookupGetter(ElementPrototype, "parentNode"); 6295 const getShadowRoot = lookupGetter(ElementPrototype, "shadowRoot"); 6296 const getAttributes = lookupGetter(ElementPrototype, "attributes"); 6297 const getNodeType = Node2 && Node2.prototype ? lookupGetter(Node2.prototype, "nodeType") : null; 6298 const getNodeName2 = Node2 && Node2.prototype ? lookupGetter(Node2.prototype, "nodeName") : null; 6299 if (typeof HTMLTemplateElement === "function") { 6300 const template = document2.createElement("template"); 6301 if (template.content && template.content.ownerDocument) { 6302 document2 = template.content.ownerDocument; 6303 } 6304 } 6305 let trustedTypesPolicy; 6306 let emptyHTML = ""; 6307 let defaultTrustedTypesPolicy; 6308 let defaultTrustedTypesPolicyResolved = false; 6309 let IN_TRUSTED_TYPES_POLICY = 0; 6310 const _assertNotInTrustedTypesPolicy = function _assertNotInTrustedTypesPolicy2() { 6311 if (IN_TRUSTED_TYPES_POLICY > 0) { 6312 throw typeErrorCreate('A configured TRUSTED_TYPES_POLICY callback (createHTML or createScriptURL) must not call DOMPurify.sanitize, as that causes infinite recursion. Do not pass a policy whose callbacks wrap DOMPurify as TRUSTED_TYPES_POLICY; see the "DOMPurify and Trusted Types" section of the README.'); 6313 } 6314 }; 6315 const _createTrustedHTML = function _createTrustedHTML2(html2) { 6316 _assertNotInTrustedTypesPolicy(); 6317 IN_TRUSTED_TYPES_POLICY++; 6318 try { 6319 return trustedTypesPolicy.createHTML(html2); 6320 } finally { 6321 IN_TRUSTED_TYPES_POLICY--; 6322 } 6323 }; 6324 const _createTrustedScriptURL = function _createTrustedScriptURL2(scriptUrl) { 6325 _assertNotInTrustedTypesPolicy(); 6326 IN_TRUSTED_TYPES_POLICY++; 6327 try { 6328 return trustedTypesPolicy.createScriptURL(scriptUrl); 6329 } finally { 6330 IN_TRUSTED_TYPES_POLICY--; 6331 } 6332 }; 6333 const _getDefaultTrustedTypesPolicy = function _getDefaultTrustedTypesPolicy2() { 6334 if (!defaultTrustedTypesPolicyResolved) { 6335 defaultTrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript); 6336 defaultTrustedTypesPolicyResolved = true; 6337 } 6338 return defaultTrustedTypesPolicy; 6339 }; 6340 const _document = document2, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName; 6341 const importNode = originalDocument.importNode; 6342 let hooks = _createHooksMap(); 6343 DOMPurify.isSupported = typeof entries === "function" && typeof getParentNode2 === "function" && implementation && implementation.createHTMLDocument !== void 0; 6344 const MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, TMPLIT_EXPR$1 = TMPLIT_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE, CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT; 6345 let IS_ALLOWED_URI$1 = IS_ALLOWED_URI; 6346 let ALLOWED_TAGS = null; 6347 const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]); 6348 let ALLOWED_ATTR = null; 6349 const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]); 6350 let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, { 6351 tagNameCheck: { 6352 writable: true, 6353 configurable: false, 6354 enumerable: true, 6355 value: null 6356 }, 6357 attributeNameCheck: { 6358 writable: true, 6359 configurable: false, 6360 enumerable: true, 6361 value: null 6362 }, 6363 allowCustomizedBuiltInElements: { 6364 writable: true, 6365 configurable: false, 6366 enumerable: true, 6367 value: false 6368 } 6369 })); 6370 let FORBID_TAGS = null; 6371 let FORBID_ATTR = null; 6372 const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, { 6373 tagCheck: { 6374 writable: true, 6375 configurable: false, 6376 enumerable: true, 6377 value: null 6378 }, 6379 attributeCheck: { 6380 writable: true, 6381 configurable: false, 6382 enumerable: true, 6383 value: null 6384 } 6385 })); 6386 let ALLOW_ARIA_ATTR = true; 6387 let ALLOW_DATA_ATTR = true; 6388 let ALLOW_UNKNOWN_PROTOCOLS = false; 6389 let ALLOW_SELF_CLOSE_IN_ATTR = true; 6390 let SAFE_FOR_TEMPLATES = false; 6391 let SAFE_FOR_XML = true; 6392 let WHOLE_DOCUMENT = false; 6393 let SET_CONFIG = false; 6394 let SET_CONFIG_ALLOWED_TAGS = null; 6395 let SET_CONFIG_ALLOWED_ATTR = null; 6396 let FORCE_BODY = false; 6397 let RETURN_DOM = false; 6398 let RETURN_DOM_FRAGMENT = false; 6399 let RETURN_TRUSTED_TYPE = false; 6400 let SANITIZE_DOM = true; 6401 let SANITIZE_NAMED_PROPS = false; 6402 const SANITIZE_NAMED_PROPS_PREFIX = "user-content-"; 6403 let KEEP_CONTENT = true; 6404 let IN_PLACE = false; 6405 let USE_PROFILES = {}; 6406 let FORBID_CONTENTS = null; 6407 const DEFAULT_FORBID_CONTENTS = addToSet({}, [ 6408 "annotation-xml", 6409 "audio", 6410 "colgroup", 6411 "desc", 6412 "foreignobject", 6413 "head", 6414 "iframe", 6415 "math", 6416 "mi", 6417 "mn", 6418 "mo", 6419 "ms", 6420 "mtext", 6421 "noembed", 6422 "noframes", 6423 "noscript", 6424 "plaintext", 6425 "script", 6426 // <selectedcontent> mirrors the selected <option>'s subtree, cloned by 6427 // the UA (customizable <select>) â including any on* handlers â and the 6428 // engine re-mirrors synchronously whenever a removal changes which 6429 // option/selectedcontent is current, even inside DOMPurify's inert 6430 // DOMParser document. Hoisting its children on removal re-inserts a fresh 6431 // mirror target ahead of the walk, which the engine refills, looping 6432 // forever (DoS) and amplifying output. Dropping its content on removal 6433 // (rather than hoisting) breaks that cascade; the content is a duplicate 6434 // of the option, which is sanitized on its own. See campaign-3 F1/F6. 6435 "selectedcontent", 6436 "style", 6437 "svg", 6438 "template", 6439 "thead", 6440 "title", 6441 "video", 6442 "xmp" 6443 ]); 6444 let DATA_URI_TAGS = null; 6445 const DEFAULT_DATA_URI_TAGS = addToSet({}, ["audio", "video", "img", "source", "image", "track"]); 6446 let URI_SAFE_ATTRIBUTES = null; 6447 const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ["alt", "class", "for", "id", "label", "name", "pattern", "placeholder", "role", "summary", "title", "value", "style", "xmlns"]); 6448 const MATHML_NAMESPACE = "http://www.w3.org/1998/Math/MathML"; 6449 const SVG_NAMESPACE = "http://www.w3.org/2000/svg"; 6450 const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; 6451 let NAMESPACE = HTML_NAMESPACE; 6452 let IS_EMPTY_INPUT = false; 6453 let ALLOWED_NAMESPACES = null; 6454 const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString); 6455 const DEFAULT_MATHML_TEXT_INTEGRATION_POINTS = freeze(["mi", "mo", "mn", "ms", "mtext"]); 6456 let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS); 6457 const DEFAULT_HTML_INTEGRATION_POINTS = freeze(["annotation-xml"]); 6458 let HTML_INTEGRATION_POINTS = addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS); 6459 const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ["title", "style", "font", "a", "script"]); 6460 let PARSER_MEDIA_TYPE = null; 6461 const SUPPORTED_PARSER_MEDIA_TYPES = ["application/xhtml+xml", "text/html"]; 6462 const DEFAULT_PARSER_MEDIA_TYPE = "text/html"; 6463 let transformCaseFunc = null; 6464 let CONFIG = null; 6465 const formElement = document2.createElement("form"); 6466 const isRegexOrFunction = function isRegexOrFunction2(testValue) { 6467 return testValue instanceof RegExp || testValue instanceof Function; 6468 }; 6469 const _parseConfig = function _parseConfig2() { 6470 let cfg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; 6471 if (CONFIG && CONFIG === cfg) { 6472 return; 6473 } 6474 if (!cfg || typeof cfg !== "object") { 6475 cfg = {}; 6476 } 6477 cfg = clone(cfg); 6478 PARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes 6479 SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE; 6480 transformCaseFunc = PARSER_MEDIA_TYPE === "application/xhtml+xml" ? stringToString : stringToLowerCase; 6481 ALLOWED_TAGS = _resolveSetOption(cfg, "ALLOWED_TAGS", DEFAULT_ALLOWED_TAGS, { 6482 transform: transformCaseFunc 6483 }); 6484 ALLOWED_ATTR = _resolveSetOption(cfg, "ALLOWED_ATTR", DEFAULT_ALLOWED_ATTR, { 6485 transform: transformCaseFunc 6486 }); 6487 ALLOWED_NAMESPACES = _resolveSetOption(cfg, "ALLOWED_NAMESPACES", DEFAULT_ALLOWED_NAMESPACES, { 6488 transform: stringToString 6489 }); 6490 URI_SAFE_ATTRIBUTES = _resolveSetOption(cfg, "ADD_URI_SAFE_ATTR", DEFAULT_URI_SAFE_ATTRIBUTES, { 6491 transform: transformCaseFunc, 6492 base: DEFAULT_URI_SAFE_ATTRIBUTES 6493 }); 6494 DATA_URI_TAGS = _resolveSetOption(cfg, "ADD_DATA_URI_TAGS", DEFAULT_DATA_URI_TAGS, { 6495 transform: transformCaseFunc, 6496 base: DEFAULT_DATA_URI_TAGS 6497 }); 6498 FORBID_CONTENTS = _resolveSetOption(cfg, "FORBID_CONTENTS", DEFAULT_FORBID_CONTENTS, { 6499 transform: transformCaseFunc 6500 }); 6501 FORBID_TAGS = _resolveSetOption(cfg, "FORBID_TAGS", clone({}), { 6502 transform: transformCaseFunc 6503 }); 6504 FORBID_ATTR = _resolveSetOption(cfg, "FORBID_ATTR", clone({}), { 6505 transform: transformCaseFunc 6506 }); 6507 USE_PROFILES = objectHasOwnProperty(cfg, "USE_PROFILES") ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === "object" ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false; 6508 ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; 6509 ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; 6510 ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; 6511 ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; 6512 SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; 6513 SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; 6514 WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; 6515 RETURN_DOM = cfg.RETURN_DOM || false; 6516 RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; 6517 RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; 6518 FORCE_BODY = cfg.FORCE_BODY || false; 6519 SANITIZE_DOM = cfg.SANITIZE_DOM !== false; 6520 SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; 6521 KEEP_CONTENT = cfg.KEEP_CONTENT !== false; 6522 IN_PLACE = cfg.IN_PLACE || false; 6523 IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI; 6524 NAMESPACE = typeof cfg.NAMESPACE === "string" ? cfg.NAMESPACE : HTML_NAMESPACE; 6525 MATHML_TEXT_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "MATHML_TEXT_INTEGRATION_POINTS") && cfg.MATHML_TEXT_INTEGRATION_POINTS && typeof cfg.MATHML_TEXT_INTEGRATION_POINTS === "object" ? clone(cfg.MATHML_TEXT_INTEGRATION_POINTS) : addToSet({}, DEFAULT_MATHML_TEXT_INTEGRATION_POINTS); 6526 HTML_INTEGRATION_POINTS = objectHasOwnProperty(cfg, "HTML_INTEGRATION_POINTS") && cfg.HTML_INTEGRATION_POINTS && typeof cfg.HTML_INTEGRATION_POINTS === "object" ? clone(cfg.HTML_INTEGRATION_POINTS) : addToSet({}, DEFAULT_HTML_INTEGRATION_POINTS); 6527 const customElementHandling = objectHasOwnProperty(cfg, "CUSTOM_ELEMENT_HANDLING") && cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING === "object" ? clone(cfg.CUSTOM_ELEMENT_HANDLING) : create(null); 6528 CUSTOM_ELEMENT_HANDLING = create(null); 6529 if (objectHasOwnProperty(customElementHandling, "tagNameCheck") && isRegexOrFunction(customElementHandling.tagNameCheck)) { 6530 CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck; 6531 } 6532 if (objectHasOwnProperty(customElementHandling, "attributeNameCheck") && isRegexOrFunction(customElementHandling.attributeNameCheck)) { 6533 CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck; 6534 } 6535 if (objectHasOwnProperty(customElementHandling, "allowCustomizedBuiltInElements") && typeof customElementHandling.allowCustomizedBuiltInElements === "boolean") { 6536 CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements; 6537 } 6538 seal(CUSTOM_ELEMENT_HANDLING); 6539 if (SAFE_FOR_TEMPLATES) { 6540 ALLOW_DATA_ATTR = false; 6541 } 6542 if (RETURN_DOM_FRAGMENT) { 6543 RETURN_DOM = true; 6544 } 6545 if (USE_PROFILES) { 6546 ALLOWED_TAGS = addToSet({}, text); 6547 ALLOWED_ATTR = create(null); 6548 if (USE_PROFILES.html === true) { 6549 addToSet(ALLOWED_TAGS, html$1); 6550 addToSet(ALLOWED_ATTR, html); 6551 } 6552 if (USE_PROFILES.svg === true) { 6553 addToSet(ALLOWED_TAGS, svg$1); 6554 addToSet(ALLOWED_ATTR, svg); 6555 addToSet(ALLOWED_ATTR, xml); 6556 } 6557 if (USE_PROFILES.svgFilters === true) { 6558 addToSet(ALLOWED_TAGS, svgFilters); 6559 addToSet(ALLOWED_ATTR, svg); 6560 addToSet(ALLOWED_ATTR, xml); 6561 } 6562 if (USE_PROFILES.mathMl === true) { 6563 addToSet(ALLOWED_TAGS, mathMl$1); 6564 addToSet(ALLOWED_ATTR, mathMl); 6565 addToSet(ALLOWED_ATTR, xml); 6566 } 6567 } 6568 EXTRA_ELEMENT_HANDLING.tagCheck = null; 6569 EXTRA_ELEMENT_HANDLING.attributeCheck = null; 6570 if (objectHasOwnProperty(cfg, "ADD_TAGS")) { 6571 if (typeof cfg.ADD_TAGS === "function") { 6572 EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS; 6573 } else if (arrayIsArray(cfg.ADD_TAGS)) { 6574 if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) { 6575 ALLOWED_TAGS = clone(ALLOWED_TAGS); 6576 } 6577 addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc); 6578 } 6579 } 6580 if (objectHasOwnProperty(cfg, "ADD_ATTR")) { 6581 if (typeof cfg.ADD_ATTR === "function") { 6582 EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR; 6583 } else if (arrayIsArray(cfg.ADD_ATTR)) { 6584 if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) { 6585 ALLOWED_ATTR = clone(ALLOWED_ATTR); 6586 } 6587 addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc); 6588 } 6589 } 6590 if (objectHasOwnProperty(cfg, "ADD_URI_SAFE_ATTR") && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) { 6591 addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc); 6592 } 6593 if (objectHasOwnProperty(cfg, "FORBID_CONTENTS") && arrayIsArray(cfg.FORBID_CONTENTS)) { 6594 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) { 6595 FORBID_CONTENTS = clone(FORBID_CONTENTS); 6596 } 6597 addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc); 6598 } 6599 if (objectHasOwnProperty(cfg, "ADD_FORBID_CONTENTS") && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) { 6600 if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) { 6601 FORBID_CONTENTS = clone(FORBID_CONTENTS); 6602 } 6603 addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc); 6604 } 6605 if (KEEP_CONTENT) { 6606 ALLOWED_TAGS["#text"] = true; 6607 } 6608 if (WHOLE_DOCUMENT) { 6609 addToSet(ALLOWED_TAGS, ["html", "head", "body"]); 6610 } 6611 if (ALLOWED_TAGS.table) { 6612 addToSet(ALLOWED_TAGS, ["tbody"]); 6613 delete FORBID_TAGS.tbody; 6614 } 6615 if (cfg.TRUSTED_TYPES_POLICY) { 6616 if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== "function") { 6617 throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.'); 6618 } 6619 if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== "function") { 6620 throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.'); 6621 } 6622 const previousTrustedTypesPolicy = trustedTypesPolicy; 6623 trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY; 6624 try { 6625 emptyHTML = _createTrustedHTML(""); 6626 } catch (error) { 6627 trustedTypesPolicy = previousTrustedTypesPolicy; 6628 throw error; 6629 } 6630 } else if (cfg.TRUSTED_TYPES_POLICY === null) { 6631 trustedTypesPolicy = void 0; 6632 emptyHTML = ""; 6633 } else { 6634 if (trustedTypesPolicy === void 0) { 6635 trustedTypesPolicy = _getDefaultTrustedTypesPolicy(); 6636 } 6637 if (trustedTypesPolicy && typeof emptyHTML === "string") { 6638 emptyHTML = _createTrustedHTML(""); 6639 } 6640 } 6641 if (freeze) { 6642 freeze(cfg); 6643 } 6644 CONFIG = cfg; 6645 }; 6646 const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]); 6647 const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]); 6648 const _checkSvgNamespace = function _checkSvgNamespace2(tagName, parent, parentTagName) { 6649 if (parent.namespaceURI === HTML_NAMESPACE) { 6650 return tagName === "svg"; 6651 } 6652 if (parent.namespaceURI === MATHML_NAMESPACE) { 6653 return tagName === "svg" && (parentTagName === "annotation-xml" || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]); 6654 } 6655 return Boolean(ALL_SVG_TAGS[tagName]); 6656 }; 6657 const _checkMathMlNamespace = function _checkMathMlNamespace2(tagName, parent, parentTagName) { 6658 if (parent.namespaceURI === HTML_NAMESPACE) { 6659 return tagName === "math"; 6660 } 6661 if (parent.namespaceURI === SVG_NAMESPACE) { 6662 return tagName === "math" && HTML_INTEGRATION_POINTS[parentTagName]; 6663 } 6664 return Boolean(ALL_MATHML_TAGS[tagName]); 6665 }; 6666 const _checkHtmlNamespace = function _checkHtmlNamespace2(tagName, parent, parentTagName) { 6667 if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) { 6668 return false; 6669 } 6670 if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) { 6671 return false; 6672 } 6673 return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]); 6674 }; 6675 const _checkValidNamespace = function _checkValidNamespace2(element) { 6676 let parent = getParentNode2(element); 6677 if (!parent || !parent.tagName) { 6678 parent = { 6679 namespaceURI: NAMESPACE, 6680 tagName: "template" 6681 }; 6682 } 6683 const tagName = stringToLowerCase(element.tagName); 6684 const parentTagName = stringToLowerCase(parent.tagName); 6685 if (!ALLOWED_NAMESPACES[element.namespaceURI]) { 6686 return false; 6687 } 6688 if (element.namespaceURI === SVG_NAMESPACE) { 6689 return _checkSvgNamespace(tagName, parent, parentTagName); 6690 } 6691 if (element.namespaceURI === MATHML_NAMESPACE) { 6692 return _checkMathMlNamespace(tagName, parent, parentTagName); 6693 } 6694 if (element.namespaceURI === HTML_NAMESPACE) { 6695 return _checkHtmlNamespace(tagName, parent, parentTagName); 6696 } 6697 if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && ALLOWED_NAMESPACES[element.namespaceURI]) { 6698 return true; 6699 } 6700 return false; 6701 }; 6702 const _forceRemove = function _forceRemove2(node) { 6703 arrayPush(DOMPurify.removed, { 6704 element: node 6705 }); 6706 try { 6707 getParentNode2(node).removeChild(node); 6708 } catch (_3) { 6709 remove(node); 6710 if (!getParentNode2(node)) { 6711 throw typeErrorCreate("a node selected for removal could not be detached from its tree and cannot be safely returned; refusing to sanitize in place"); 6712 } 6713 } 6714 }; 6715 const _neutralizeRoot = function _neutralizeRoot2(root) { 6716 const childNodes = getChildNodes(root); 6717 if (childNodes) { 6718 const snapshot = []; 6719 arrayForEach(childNodes, (child) => { 6720 arrayPush(snapshot, child); 6721 }); 6722 arrayForEach(snapshot, (child) => { 6723 try { 6724 remove(child); 6725 } catch (_3) { 6726 } 6727 }); 6728 } 6729 const attributes = getAttributes(root); 6730 if (attributes) { 6731 for (let i2 = attributes.length - 1; i2 >= 0; --i2) { 6732 const attribute = attributes[i2]; 6733 const name = attribute && attribute.name; 6734 if (typeof name === "string") { 6735 try { 6736 root.removeAttribute(name); 6737 } catch (_3) { 6738 } 6739 } 6740 } 6741 } 6742 }; 6743 const _removeAttribute = function _removeAttribute2(name, element) { 6744 try { 6745 arrayPush(DOMPurify.removed, { 6746 attribute: element.getAttributeNode(name), 6747 from: element 6748 }); 6749 } catch (_3) { 6750 arrayPush(DOMPurify.removed, { 6751 attribute: null, 6752 from: element 6753 }); 6754 } 6755 element.removeAttribute(name); 6756 if (name === "is") { 6757 if (RETURN_DOM || RETURN_DOM_FRAGMENT) { 6758 try { 6759 _forceRemove(element); 6760 } catch (_3) { 6761 } 6762 } else { 6763 try { 6764 element.setAttribute(name, ""); 6765 } catch (_3) { 6766 } 6767 } 6768 } 6769 }; 6770 const _stripDisallowedAttributes = function _stripDisallowedAttributes2(element) { 6771 const attributes = getAttributes(element); 6772 if (!attributes) { 6773 return; 6774 } 6775 for (let i2 = attributes.length - 1; i2 >= 0; --i2) { 6776 const attribute = attributes[i2]; 6777 const name = attribute && attribute.name; 6778 if (typeof name !== "string" || ALLOWED_ATTR[transformCaseFunc(name)]) { 6779 continue; 6780 } 6781 try { 6782 element.removeAttribute(name); 6783 } catch (_3) { 6784 } 6785 } 6786 }; 6787 const _neutralizeSubtree = function _neutralizeSubtree2(root) { 6788 const stack = [root]; 6789 while (stack.length > 0) { 6790 const node = stack.pop(); 6791 const nodeType = getNodeType ? getNodeType(node) : node.nodeType; 6792 if (nodeType === NODE_TYPE.element) { 6793 _stripDisallowedAttributes(node); 6794 } 6795 const childNodes = getChildNodes(node); 6796 if (childNodes) { 6797 for (let i2 = childNodes.length - 1; i2 >= 0; --i2) { 6798 stack.push(childNodes[i2]); 6799 } 6800 } 6801 } 6802 }; 6803 const _initDocument = function _initDocument2(dirty) { 6804 let doc = null; 6805 let leadingWhitespace = null; 6806 if (FORCE_BODY) { 6807 dirty = "<remove></remove>" + dirty; 6808 } else { 6809 const matches = stringMatch(dirty, /^[\r\n\t ]+/); 6810 leadingWhitespace = matches && matches[0]; 6811 } 6812 if (PARSER_MEDIA_TYPE === "application/xhtml+xml" && NAMESPACE === HTML_NAMESPACE) { 6813 dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + "</body></html>"; 6814 } 6815 const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty; 6816 if (NAMESPACE === HTML_NAMESPACE) { 6817 try { 6818 doc = new DOMParser2().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE); 6819 } catch (_3) { 6820 } 6821 } 6822 if (!doc || !doc.documentElement) { 6823 doc = implementation.createDocument(NAMESPACE, "template", null); 6824 try { 6825 doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload; 6826 } catch (_3) { 6827 } 6828 } 6829 const body = doc.body || doc.documentElement; 6830 if (dirty && leadingWhitespace) { 6831 body.insertBefore(document2.createTextNode(leadingWhitespace), body.childNodes[0] || null); 6832 } 6833 if (NAMESPACE === HTML_NAMESPACE) { 6834 return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? "html" : "body")[0]; 6835 } 6836 return WHOLE_DOCUMENT ? doc.documentElement : body; 6837 }; 6838 const _createNodeIterator = function _createNodeIterator2(root) { 6839 return createNodeIterator.call( 6840 root.ownerDocument || root, 6841 root, 6842 // eslint-disable-next-line no-bitwise 6843 NodeFilter2.SHOW_ELEMENT | NodeFilter2.SHOW_COMMENT | NodeFilter2.SHOW_TEXT | NodeFilter2.SHOW_PROCESSING_INSTRUCTION | NodeFilter2.SHOW_CDATA_SECTION, 6844 null 6845 ); 6846 }; 6847 const _stripTemplateExpressions = function _stripTemplateExpressions2(value) { 6848 value = stringReplace(value, MUSTACHE_EXPR$1, " "); 6849 value = stringReplace(value, ERB_EXPR$1, " "); 6850 value = stringReplace(value, TMPLIT_EXPR$1, " "); 6851 return value; 6852 }; 6853 const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) { 6854 var _node$querySelectorAl; 6855 node.normalize(); 6856 const walker = createNodeIterator.call( 6857 node.ownerDocument || node, 6858 node, 6859 // eslint-disable-next-line no-bitwise 6860 NodeFilter2.SHOW_TEXT | NodeFilter2.SHOW_COMMENT | NodeFilter2.SHOW_CDATA_SECTION | NodeFilter2.SHOW_PROCESSING_INSTRUCTION, 6861 null 6862 ); 6863 let currentNode = walker.nextNode(); 6864 while (currentNode) { 6865 currentNode.data = _stripTemplateExpressions(currentNode.data); 6866 currentNode = walker.nextNode(); 6867 } 6868 const templates = (_node$querySelectorAl = node.querySelectorAll) === null || _node$querySelectorAl === void 0 ? void 0 : _node$querySelectorAl.call(node, "template"); 6869 if (templates) { 6870 arrayForEach(templates, (tmpl) => { 6871 if (_isDocumentFragment(tmpl.content)) { 6872 _scrubTemplateExpressions2(tmpl.content); 6873 } 6874 }); 6875 } 6876 }; 6877 const _isClobbered = function _isClobbered2(element) { 6878 const realTagName = getNodeName2 ? getNodeName2(element) : null; 6879 if (typeof realTagName !== "string") { 6880 return false; 6881 } 6882 if (transformCaseFunc(realTagName) !== "form") { 6883 return false; 6884 } 6885 return typeof element.nodeName !== "string" || typeof element.textContent !== "string" || typeof element.removeChild !== "function" || // Realm-safe NamedNodeMap detection: equality against the cached 6886 // prototype getter. Clobbered .attributes (e.g. <input name="attributes">) 6887 // makes the direct read diverge from the cached read; a clean form 6888 // (same-realm OR foreign-realm) has both reads pointing at the same 6889 // canonical NamedNodeMap. 6890 element.attributes !== getAttributes(element) || typeof element.removeAttribute !== "function" || typeof element.setAttribute !== "function" || typeof element.namespaceURI !== "string" || typeof element.insertBefore !== "function" || typeof element.hasChildNodes !== "function" || // NodeType clobbering probe. Cached Node.prototype.nodeType getter 6891 // returns the integer 1 for any Element regardless of realm; direct 6892 // read on a clobbered form (e.g. <input name="nodeType">) returns 6893 // the named child element. Cheap addition â nodeType is read from 6894 // an internal slot, no serialization cost â and removes a residual 6895 // clobbering surface used by several mXSS / PI / comment branches 6896 // in _sanitizeElements that compare currentNode.nodeType directly. 6897 element.nodeType !== getNodeType(element) || // HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named 6898 // "childNodes" shadows the prototype getter. Direct reads of 6899 // form.childNodes from a clobbered form return the named child 6900 // instead of the real NodeList, so any walk that reads it directly 6901 // skips the form's real children. Compare the direct read to the 6902 // cached Node.prototype getter â when the form's named-property 6903 // getter intercepts the read, the two values differ and we flag 6904 // the form. This catches every clobbering child type (input, 6905 // select, etc.) regardless of whether the named child happens to 6906 // carry a numeric .length, which a typeof-based probe would miss 6907 // (e.g. HTMLSelectElement.length is a defined unsigned-long). 6908 element.childNodes !== getChildNodes(element); 6909 }; 6910 const _isDocumentFragment = function _isDocumentFragment2(value) { 6911 if (!getNodeType || typeof value !== "object" || value === null) { 6912 return false; 6913 } 6914 try { 6915 return getNodeType(value) === NODE_TYPE.documentFragment; 6916 } catch (_3) { 6917 return false; 6918 } 6919 }; 6920 const _isNode = function _isNode2(value) { 6921 if (!getNodeType || typeof value !== "object" || value === null) { 6922 return false; 6923 } 6924 try { 6925 return typeof getNodeType(value) === "number"; 6926 } catch (_3) { 6927 return false; 6928 } 6929 }; 6930 function _executeHooks(hooks2, currentNode, data) { 6931 if (hooks2.length === 0) { 6932 return; 6933 } 6934 arrayForEach(hooks2, (hook) => { 6935 hook.call(DOMPurify, currentNode, data, CONFIG); 6936 }); 6937 } 6938 const _isUnsafeNode = function _isUnsafeNode2(currentNode, tagName) { 6939 if (SAFE_FOR_XML && currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.textContent) && regExpTest(ELEMENT_MARKUP_PROBE, currentNode.innerHTML)) { 6940 return true; 6941 } 6942 if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === "style" && _isNode(currentNode.firstElementChild)) { 6943 return true; 6944 } 6945 if (currentNode.nodeType === NODE_TYPE.processingInstruction) { 6946 return true; 6947 } 6948 if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, currentNode.data)) { 6949 return true; 6950 } 6951 return false; 6952 }; 6953 const _sanitizeDisallowedNode = function _sanitizeDisallowedNode2(currentNode, tagName) { 6954 if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) { 6955 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) { 6956 return false; 6957 } 6958 if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) { 6959 return false; 6960 } 6961 } 6962 if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) { 6963 const parentNode = getParentNode2(currentNode); 6964 const childNodes = getChildNodes(currentNode); 6965 if (childNodes && parentNode) { 6966 const childCount = childNodes.length; 6967 for (let i2 = childCount - 1; i2 >= 0; --i2) { 6968 const hoisted = IN_PLACE ? childNodes[i2] : cloneNode(childNodes[i2], true); 6969 parentNode.insertBefore(hoisted, getNextSibling2(currentNode)); 6970 } 6971 } 6972 } 6973 _forceRemove(currentNode); 6974 return true; 6975 }; 6976 const _sanitizeElements = function _sanitizeElements2(currentNode) { 6977 _executeHooks(hooks.beforeSanitizeElements, currentNode, null); 6978 if (_isClobbered(currentNode)) { 6979 _forceRemove(currentNode); 6980 return true; 6981 } 6982 const tagName = transformCaseFunc(getNodeName2 ? getNodeName2(currentNode) : currentNode.nodeName); 6983 _executeHooks(hooks.uponSanitizeElement, currentNode, { 6984 tagName, 6985 allowedTags: ALLOWED_TAGS 6986 }); 6987 if (_isUnsafeNode(currentNode, tagName)) { 6988 _forceRemove(currentNode); 6989 return true; 6990 } 6991 if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) { 6992 return _sanitizeDisallowedNode(currentNode, tagName); 6993 } 6994 const nt = getNodeType ? getNodeType(currentNode) : currentNode.nodeType; 6995 if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) { 6996 _forceRemove(currentNode); 6997 return true; 6998 } 6999 if ((tagName === "noscript" || tagName === "noembed" || tagName === "noframes") && regExpTest(FALLBACK_TAG_CLOSE, currentNode.innerHTML)) { 7000 _forceRemove(currentNode); 7001 return true; 7002 } 7003 if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) { 7004 const content = _stripTemplateExpressions(currentNode.textContent); 7005 if (currentNode.textContent !== content) { 7006 arrayPush(DOMPurify.removed, { 7007 element: currentNode.cloneNode() 7008 }); 7009 currentNode.textContent = content; 7010 } 7011 } 7012 _executeHooks(hooks.afterSanitizeElements, currentNode, null); 7013 return false; 7014 }; 7015 const _isValidAttribute = function _isValidAttribute2(lcTag, lcName, value) { 7016 if (FORBID_ATTR[lcName]) { 7017 return false; 7018 } 7019 if (SANITIZE_DOM && (lcName === "id" || lcName === "name") && (value in document2 || value in formElement)) { 7020 return false; 7021 } 7022 const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag); 7023 if (ALLOW_DATA_ATTR && regExpTest(DATA_ATTR$1, lcName)) ; 7024 else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) ; 7025 else if (!nameIsPermitted) { 7026 if ( 7027 // First condition does a very basic check if a) it's basically a valid custom element tagname AND 7028 // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck 7029 // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck 7030 _isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName, lcTag)) || // Alternative, second condition checks if it's an `is`-attribute, AND 7031 // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck 7032 lcName === "is" && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value)) 7033 ) ; 7034 else { 7035 return false; 7036 } 7037 } else if (URI_SAFE_ATTRIBUTES[lcName]) ; 7038 else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) ; 7039 else if ((lcName === "src" || lcName === "xlink:href" || lcName === "href") && lcTag !== "script" && stringIndexOf(value, "data:") === 0 && DATA_URI_TAGS[lcTag]) ; 7040 else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ""))) ; 7041 else if (value) { 7042 return false; 7043 } else ; 7044 return true; 7045 }; 7046 const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, ["annotation-xml", "color-profile", "font-face", "font-face-format", "font-face-name", "font-face-src", "font-face-uri", "missing-glyph"]); 7047 const _isBasicCustomElement = function _isBasicCustomElement2(tagName) { 7048 return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName); 7049 }; 7050 const _applyTrustedTypesToAttribute = function _applyTrustedTypesToAttribute2(lcTag, lcName, namespaceURI, value) { 7051 if (trustedTypesPolicy && typeof trustedTypes === "object" && typeof trustedTypes.getAttributeType === "function" && !namespaceURI) { 7052 switch (trustedTypes.getAttributeType(lcTag, lcName)) { 7053 case "TrustedHTML": { 7054 return _createTrustedHTML(value); 7055 } 7056 case "TrustedScriptURL": { 7057 return _createTrustedScriptURL(value); 7058 } 7059 } 7060 } 7061 return value; 7062 }; 7063 const _setAttributeValue = function _setAttributeValue2(currentNode, name, namespaceURI, value) { 7064 try { 7065 if (namespaceURI) { 7066 currentNode.setAttributeNS(namespaceURI, name, value); 7067 } else { 7068 currentNode.setAttribute(name, value); 7069 } 7070 if (_isClobbered(currentNode)) { 7071 _forceRemove(currentNode); 7072 } else { 7073 arrayPop(DOMPurify.removed); 7074 } 7075 } catch (_3) { 7076 _removeAttribute(name, currentNode); 7077 } 7078 }; 7079 const _sanitizeAttributes = function _sanitizeAttributes2(currentNode) { 7080 _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null); 7081 const attributes = currentNode.attributes; 7082 if (!attributes || _isClobbered(currentNode)) { 7083 return; 7084 } 7085 const hookEvent = { 7086 attrName: "", 7087 attrValue: "", 7088 keepAttr: true, 7089 allowedAttributes: ALLOWED_ATTR, 7090 forceKeepAttr: void 0 7091 }; 7092 let l4 = attributes.length; 7093 const lcTag = transformCaseFunc(currentNode.nodeName); 7094 while (l4--) { 7095 const attr = attributes[l4]; 7096 const name = attr.name, namespaceURI = attr.namespaceURI, attrValue = attr.value; 7097 const lcName = transformCaseFunc(name); 7098 const initValue = attrValue; 7099 let value = name === "value" ? initValue : stringTrim(initValue); 7100 hookEvent.attrName = lcName; 7101 hookEvent.attrValue = value; 7102 hookEvent.keepAttr = true; 7103 hookEvent.forceKeepAttr = void 0; 7104 _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent); 7105 value = hookEvent.attrValue; 7106 if (SANITIZE_NAMED_PROPS && (lcName === "id" || lcName === "name") && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) { 7107 _removeAttribute(name, currentNode); 7108 value = SANITIZE_NAMED_PROPS_PREFIX + value; 7109 } 7110 if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) { 7111 _removeAttribute(name, currentNode); 7112 continue; 7113 } 7114 if (lcName === "attributename" && stringMatch(value, "href")) { 7115 _removeAttribute(name, currentNode); 7116 continue; 7117 } 7118 if (hookEvent.forceKeepAttr) { 7119 continue; 7120 } 7121 if (!hookEvent.keepAttr) { 7122 _removeAttribute(name, currentNode); 7123 continue; 7124 } 7125 if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(SELF_CLOSING_TAG, value)) { 7126 _removeAttribute(name, currentNode); 7127 continue; 7128 } 7129 if (SAFE_FOR_TEMPLATES) { 7130 value = _stripTemplateExpressions(value); 7131 } 7132 if (!_isValidAttribute(lcTag, lcName, value)) { 7133 _removeAttribute(name, currentNode); 7134 continue; 7135 } 7136 value = _applyTrustedTypesToAttribute(lcTag, lcName, namespaceURI, value); 7137 if (value !== initValue) { 7138 _setAttributeValue(currentNode, name, namespaceURI, value); 7139 } 7140 } 7141 _executeHooks(hooks.afterSanitizeAttributes, currentNode, null); 7142 }; 7143 const _sanitizeShadowDOM2 = function _sanitizeShadowDOM(fragment) { 7144 let shadowNode = null; 7145 const shadowIterator = _createNodeIterator(fragment); 7146 _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null); 7147 while (shadowNode = shadowIterator.nextNode()) { 7148 _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null); 7149 _sanitizeElements(shadowNode); 7150 _sanitizeAttributes(shadowNode); 7151 if (_isDocumentFragment(shadowNode.content)) { 7152 _sanitizeShadowDOM2(shadowNode.content); 7153 } 7154 const shadowNodeType = getNodeType ? getNodeType(shadowNode) : shadowNode.nodeType; 7155 if (shadowNodeType === NODE_TYPE.element) { 7156 const innerSr = getShadowRoot(shadowNode); 7157 if (_isDocumentFragment(innerSr)) { 7158 _sanitizeAttachedShadowRoots(innerSr); 7159 _sanitizeShadowDOM2(innerSr); 7160 } 7161 } 7162 } 7163 _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null); 7164 }; 7165 const _sanitizeAttachedShadowRoots = function _sanitizeAttachedShadowRoots2(root) { 7166 const stack = [{ 7167 node: root, 7168 shadow: null 7169 }]; 7170 while (stack.length > 0) { 7171 const item = stack.pop(); 7172 if (item.shadow) { 7173 _sanitizeShadowDOM2(item.shadow); 7174 continue; 7175 } 7176 const node = item.node; 7177 const nodeType = getNodeType ? getNodeType(node) : node.nodeType; 7178 const isElement2 = nodeType === NODE_TYPE.element; 7179 const childNodes = getChildNodes(node); 7180 if (childNodes) { 7181 for (let i2 = childNodes.length - 1; i2 >= 0; --i2) { 7182 stack.push({ 7183 node: childNodes[i2], 7184 shadow: null 7185 }); 7186 } 7187 } 7188 if (isElement2) { 7189 const rootName = getNodeName2 ? getNodeName2(node) : null; 7190 if (typeof rootName === "string" && transformCaseFunc(rootName) === "template") { 7191 const content = node.content; 7192 if (_isDocumentFragment(content)) { 7193 stack.push({ 7194 node: content, 7195 shadow: null 7196 }); 7197 } 7198 } 7199 } 7200 if (isElement2) { 7201 const sr = getShadowRoot(node); 7202 if (_isDocumentFragment(sr)) { 7203 stack.push({ 7204 node: null, 7205 shadow: sr 7206 }, { 7207 node: sr, 7208 shadow: null 7209 }); 7210 } 7211 } 7212 } 7213 }; 7214 DOMPurify.sanitize = function(dirty) { 7215 let cfg = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}; 7216 let body = null; 7217 let importedNode = null; 7218 let currentNode = null; 7219 let returnNode = null; 7220 IS_EMPTY_INPUT = !dirty; 7221 if (IS_EMPTY_INPUT) { 7222 dirty = "<!-->"; 7223 } 7224 if (typeof dirty !== "string" && !_isNode(dirty)) { 7225 dirty = stringifyValue(dirty); 7226 if (typeof dirty !== "string") { 7227 throw typeErrorCreate("dirty is not a string, aborting"); 7228 } 7229 } 7230 if (!DOMPurify.isSupported) { 7231 return dirty; 7232 } 7233 if (SET_CONFIG) { 7234 ALLOWED_TAGS = SET_CONFIG_ALLOWED_TAGS; 7235 ALLOWED_ATTR = SET_CONFIG_ALLOWED_ATTR; 7236 } else { 7237 _parseConfig(cfg); 7238 } 7239 if (hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) { 7240 ALLOWED_TAGS = clone(ALLOWED_TAGS); 7241 } 7242 if (hooks.uponSanitizeAttribute.length > 0) { 7243 ALLOWED_ATTR = clone(ALLOWED_ATTR); 7244 } 7245 DOMPurify.removed = []; 7246 const inPlace = IN_PLACE && typeof dirty !== "string" && _isNode(dirty); 7247 if (inPlace) { 7248 const nn = getNodeName2 ? getNodeName2(dirty) : dirty.nodeName; 7249 if (typeof nn === "string") { 7250 const tagName = transformCaseFunc(nn); 7251 if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) { 7252 throw typeErrorCreate("root node is forbidden and cannot be sanitized in-place"); 7253 } 7254 } 7255 if (_isClobbered(dirty)) { 7256 throw typeErrorCreate("root node is clobbered and cannot be sanitized in-place"); 7257 } 7258 try { 7259 _sanitizeAttachedShadowRoots(dirty); 7260 } catch (error) { 7261 _neutralizeRoot(dirty); 7262 throw error; 7263 } 7264 } else if (_isNode(dirty)) { 7265 body = _initDocument("<!---->"); 7266 importedNode = body.ownerDocument.importNode(dirty, true); 7267 if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === "BODY") { 7268 body = importedNode; 7269 } else if (importedNode.nodeName === "HTML") { 7270 body = importedNode; 7271 } else { 7272 body.appendChild(importedNode); 7273 } 7274 _sanitizeAttachedShadowRoots(importedNode); 7275 } else { 7276 if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && // eslint-disable-next-line unicorn/prefer-includes 7277 dirty.indexOf("<") === -1) { 7278 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty; 7279 } 7280 body = _initDocument(dirty); 7281 if (!body) { 7282 return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : ""; 7283 } 7284 } 7285 if (body && FORCE_BODY) { 7286 _forceRemove(body.firstChild); 7287 } 7288 const nodeIterator = _createNodeIterator(inPlace ? dirty : body); 7289 try { 7290 while (currentNode = nodeIterator.nextNode()) { 7291 _sanitizeElements(currentNode); 7292 _sanitizeAttributes(currentNode); 7293 if (_isDocumentFragment(currentNode.content)) { 7294 _sanitizeShadowDOM2(currentNode.content); 7295 } 7296 } 7297 } catch (error) { 7298 if (inPlace) { 7299 _neutralizeRoot(dirty); 7300 } 7301 throw error; 7302 } 7303 if (inPlace) { 7304 arrayForEach(DOMPurify.removed, (entry) => { 7305 if (entry.element) { 7306 _neutralizeSubtree(entry.element); 7307 } 7308 }); 7309 if (SAFE_FOR_TEMPLATES) { 7310 _scrubTemplateExpressions2(dirty); 7311 } 7312 return dirty; 7313 } 7314 if (RETURN_DOM) { 7315 if (SAFE_FOR_TEMPLATES) { 7316 _scrubTemplateExpressions2(body); 7317 } 7318 if (RETURN_DOM_FRAGMENT) { 7319 returnNode = createDocumentFragment.call(body.ownerDocument); 7320 while (body.firstChild) { 7321 returnNode.appendChild(body.firstChild); 7322 } 7323 } else { 7324 returnNode = body; 7325 } 7326 if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) { 7327 returnNode = importNode.call(originalDocument, returnNode, true); 7328 } 7329 return returnNode; 7330 } 7331 let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML; 7332 if (WHOLE_DOCUMENT && ALLOWED_TAGS["!doctype"] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) { 7333 serializedHTML = "<!DOCTYPE " + body.ownerDocument.doctype.name + ">\n" + serializedHTML; 7334 } 7335 if (SAFE_FOR_TEMPLATES) { 7336 serializedHTML = _stripTemplateExpressions(serializedHTML); 7337 } 7338 return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML; 7339 }; 7340 DOMPurify.setConfig = function() { 7341 let cfg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; 7342 _parseConfig(cfg); 7343 SET_CONFIG = true; 7344 SET_CONFIG_ALLOWED_TAGS = ALLOWED_TAGS; 7345 SET_CONFIG_ALLOWED_ATTR = ALLOWED_ATTR; 7346 }; 7347 DOMPurify.clearConfig = function() { 7348 CONFIG = null; 7349 SET_CONFIG = false; 7350 SET_CONFIG_ALLOWED_TAGS = null; 7351 SET_CONFIG_ALLOWED_ATTR = null; 7352 trustedTypesPolicy = defaultTrustedTypesPolicy; 7353 emptyHTML = ""; 7354 }; 7355 DOMPurify.isValidAttribute = function(tag, attr, value) { 7356 if (!CONFIG) { 7357 _parseConfig({}); 7358 } 7359 const lcTag = transformCaseFunc(tag); 7360 const lcName = transformCaseFunc(attr); 7361 return _isValidAttribute(lcTag, lcName, value); 7362 }; 7363 DOMPurify.addHook = function(entryPoint, hookFunction) { 7364 if (typeof hookFunction !== "function") { 7365 return; 7366 } 7367 if (!objectHasOwnProperty(hooks, entryPoint)) { 7368 return; 7369 } 7370 arrayPush(hooks[entryPoint], hookFunction); 7371 }; 7372 DOMPurify.removeHook = function(entryPoint, hookFunction) { 7373 if (!objectHasOwnProperty(hooks, entryPoint)) { 7374 return void 0; 7375 } 7376 if (hookFunction !== void 0) { 7377 const index = arrayLastIndexOf(hooks[entryPoint], hookFunction); 7378 return index === -1 ? void 0 : arraySplice(hooks[entryPoint], index, 1)[0]; 7379 } 7380 return arrayPop(hooks[entryPoint]); 7381 }; 7382 DOMPurify.removeHooks = function(entryPoint) { 7383 if (!objectHasOwnProperty(hooks, entryPoint)) { 7384 return; 7385 } 7386 hooks[entryPoint] = []; 7387 }; 7388 DOMPurify.removeAllHooks = function() { 7389 hooks = _createHooksMap(); 7390 }; 7391 return DOMPurify; 7392 } 7393 var purify = createDOMPurify(); 7394 7395
vendor: 1,541 bytes, lines 7395-7425
7395// node_modules/@lexical/selection/LexicalSelection.dev.mjs 7396 var LexicalSelection_dev_exports = {}; 7397 __export(LexicalSelection_dev_exports, { 7398 $addNodeStyle: () => $addNodeStyle, 7399 $cloneWithProperties: () => $cloneWithProperties2, 7400 $copyBlockFormatIndent: () => $copyBlockFormatIndent, 7401 $ensureForwardRangeSelection: () => $ensureForwardRangeSelection, 7402 $forEachSelectedTextNode: () => $forEachSelectedTextNode, 7403 $getComputedStyleForElement: () => $getComputedStyleForElement, 7404 $getComputedStyleForParent: () => $getComputedStyleForParent, 7405 $getSelectionStyleValueForProperty: () => $getSelectionStyleValueForProperty, 7406 $isAtNodeEnd: () => $isAtNodeEnd, 7407 $isParentElementRTL: () => $isParentElementRTL, 7408 $isParentRTL: () => $isParentRTL, 7409 $moveCaretSelection: () => $moveCaretSelection, 7410 $moveCharacter: () => $moveCharacter, 7411 $patchStyleText: () => $patchStyleText, 7412 $selectAll: () => $selectAll2, 7413 $setBlocksType: () => $setBlocksType, 7414 $shouldOverrideDefaultCharacterSelection: () => $shouldOverrideDefaultCharacterSelection, 7415 $sliceSelectedTextNodeContent: () => $sliceSelectedTextNodeContent, 7416 $trimTextContentFromAnchor: () => $trimTextContentFromAnchor, 7417 $wrapNodes: () => $wrapNodes, 7418 createDOMRange: () => createDOMRange, 7419 createRectsFromDOMRange: () => createRectsFromDOMRange, 7420 getCSSFromStyleObject: () => getCSSFromStyleObject, 7421 getStyleObjectFromCSS: () => getStyleObjectFromCSS3, 7422 trimTextContentFromAnchor: () => trimTextContentFromAnchor 7423 }); 7424 7425
vendor: 12,053 bytes, lines 7425-7664
7425// node_modules/lexical/Lexical.mjs 7426 var Lexical_exports = {}; 7427 __export(Lexical_exports, { 7428 $addUpdateTag: () => $addUpdateTag2, 7429 $applyNodeReplacement: () => $applyNodeReplacement2, 7430 $caretFromPoint: () => $caretFromPoint2, 7431 $caretRangeFromSelection: () => $caretRangeFromSelection2, 7432 $cloneWithProperties: () => $cloneWithProperties2, 7433 $cloneWithPropertiesEphemeral: () => $cloneWithPropertiesEphemeral2, 7434 $comparePointCaretNext: () => $comparePointCaretNext2, 7435 $copyNode: () => $copyNode2, 7436 $create: () => $create2, 7437 $createChildrenArray: () => $createChildrenArray2, 7438 $createLineBreakNode: () => $createLineBreakNode2, 7439 $createNodeSelection: () => $createNodeSelection2, 7440 $createParagraphNode: () => $createParagraphNode2, 7441 $createPoint: () => $createPoint2, 7442 $createRangeSelection: () => $createRangeSelection2, 7443 $createRangeSelectionFromDom: () => $createRangeSelectionFromDom2, 7444 $createTabNode: () => $createTabNode2, 7445 $createTextNode: () => $createTextNode2, 7446 $extendCaretToRange: () => $extendCaretToRange2, 7447 $findMatchingParent: () => $findMatchingParent2, 7448 $getAdjacentChildCaret: () => $getAdjacentChildCaret2, 7449 $getAdjacentNode: () => $getAdjacentNode2, 7450 $getAdjacentSiblingOrParentSiblingCaret: () => $getAdjacentSiblingOrParentSiblingCaret2, 7451 $getCaretInDirection: () => $getCaretInDirection2, 7452 $getCaretRange: () => $getCaretRange2, 7453 $getCaretRangeInDirection: () => $getCaretRangeInDirection2, 7454 $getCharacterOffsets: () => $getCharacterOffsets2, 7455 $getChildCaret: () => $getChildCaret2, 7456 $getChildCaretAtIndex: () => $getChildCaretAtIndex2, 7457 $getChildCaretOrSelf: () => $getChildCaretOrSelf2, 7458 $getCollapsedCaretRange: () => $getCollapsedCaretRange2, 7459 $getCommonAncestor: () => $getCommonAncestor2, 7460 $getCommonAncestorResultBranchOrder: () => $getCommonAncestorResultBranchOrder2, 7461 $getEditor: () => $getEditor2, 7462 $getEditorDOMRenderConfig: () => $getEditorDOMRenderConfig2, 7463 $getNearestNodeFromDOMNode: () => $getNearestNodeFromDOMNode2, 7464 $getNearestRootOrShadowRoot: () => $getNearestRootOrShadowRoot2, 7465 $getNodeByKey: () => $getNodeByKey2, 7466 $getNodeByKeyOrThrow: () => $getNodeByKeyOrThrow2, 7467 $getNodeFromDOMNode: () => $getNodeFromDOMNode2, 7468 $getPreviousSelection: () => $getPreviousSelection2, 7469 $getRoot: () => $getRoot2, 7470 $getSelection: () => $getSelection2, 7471 $getSiblingCaret: () => $getSiblingCaret2, 7472 $getState: () => $getState2, 7473 $getStateChange: () => $getStateChange2, 7474 $getTextContent: () => $getTextContent2, 7475 $getTextNodeOffset: () => $getTextNodeOffset2, 7476 $getTextPointCaret: () => $getTextPointCaret2, 7477 $getTextPointCaretSlice: () => $getTextPointCaretSlice2, 7478 $getWritableNodeState: () => $getWritableNodeState2, 7479 $hasAncestor: () => $hasAncestor2, 7480 $hasUpdateTag: () => $hasUpdateTag2, 7481 $insertNodes: () => $insertNodes2, 7482 $isBlockElementNode: () => $isBlockElementNode2, 7483 $isChildCaret: () => $isChildCaret2, 7484 $isDecoratorNode: () => $isDecoratorNode2, 7485 $isEditorState: () => $isEditorState2, 7486 $isElementNode: () => $isElementNode2, 7487 $isExtendableTextPointCaret: () => $isExtendableTextPointCaret2, 7488 $isInlineElementOrDecoratorNode: () => $isInlineElementOrDecoratorNode2, 7489 $isLeafNode: () => $isLeafNode2, 7490 $isLexicalNode: () => $isLexicalNode2, 7491 $isLineBreakNode: () => $isLineBreakNode2, 7492 $isNodeCaret: () => $isNodeCaret2, 7493 $isNodeSelection: () => $isNodeSelection2, 7494 $isParagraphNode: () => $isParagraphNode2, 7495 $isRangeSelection: () => $isRangeSelection2, 7496 $isRootNode: () => $isRootNode2, 7497 $isRootOrShadowRoot: () => $isRootOrShadowRoot2, 7498 $isSiblingCaret: () => $isSiblingCaret2, 7499 $isTabNode: () => $isTabNode2, 7500 $isTextNode: () => $isTextNode2, 7501 $isTextPointCaret: () => $isTextPointCaret2, 7502 $isTextPointCaretSlice: () => $isTextPointCaretSlice2, 7503 $isTokenOrSegmented: () => $isTokenOrSegmented2, 7504 $isTokenOrTab: () => $isTokenOrTab2, 7505 $nodesOfType: () => $nodesOfType2, 7506 $normalizeCaret: () => $normalizeCaret2, 7507 $normalizeSelection__EXPERIMENTAL: () => $normalizeSelection__EXPERIMENTAL, 7508 $onUpdate: () => $onUpdate2, 7509 $parseSerializedNode: () => $parseSerializedNode2, 7510 $removeTextFromCaretRange: () => $removeTextFromCaretRange2, 7511 $rewindSiblingCaret: () => $rewindSiblingCaret2, 7512 $selectAll: () => $selectAll2, 7513 $setCompositionKey: () => $setCompositionKey2, 7514 $setPointFromCaret: () => $setPointFromCaret2, 7515 $setSelection: () => $setSelection2, 7516 $setSelectionFromCaretRange: () => $setSelectionFromCaretRange2, 7517 $setState: () => $setState2, 7518 $splitAtPointCaretNext: () => $splitAtPointCaretNext2, 7519 $splitNode: () => $splitNode2, 7520 $updateRangeSelectionFromCaretRange: () => $updateRangeSelectionFromCaretRange2, 7521 ArtificialNode__DO_NOT_USE: () => ArtificialNode__DO_NOT_USE2, 7522 BEFORE_INPUT_COMMAND: () => BEFORE_INPUT_COMMAND2, 7523 BLUR_COMMAND: () => BLUR_COMMAND2, 7524 CAN_REDO_COMMAND: () => CAN_REDO_COMMAND2, 7525 CAN_UNDO_COMMAND: () => CAN_UNDO_COMMAND2, 7526 CLEAR_EDITOR_COMMAND: () => CLEAR_EDITOR_COMMAND2, 7527 CLEAR_HISTORY_COMMAND: () => CLEAR_HISTORY_COMMAND2, 7528 CLICK_COMMAND: () => CLICK_COMMAND2, 7529 COLLABORATION_TAG: () => COLLABORATION_TAG2, 7530 COMMAND_PRIORITY_BEFORE_CRITICAL: () => COMMAND_PRIORITY_BEFORE_CRITICAL2, 7531 COMMAND_PRIORITY_BEFORE_EDITOR: () => COMMAND_PRIORITY_BEFORE_EDITOR2, 7532 COMMAND_PRIORITY_BEFORE_HIGH: () => COMMAND_PRIORITY_BEFORE_HIGH2, 7533 COMMAND_PRIORITY_BEFORE_LOW: () => COMMAND_PRIORITY_BEFORE_LOW2, 7534 COMMAND_PRIORITY_BEFORE_NORMAL: () => COMMAND_PRIORITY_BEFORE_NORMAL2, 7535 COMMAND_PRIORITY_CRITICAL: () => COMMAND_PRIORITY_CRITICAL2, 7536 COMMAND_PRIORITY_EDITOR: () => COMMAND_PRIORITY_EDITOR2, 7537 COMMAND_PRIORITY_HIGH: () => COMMAND_PRIORITY_HIGH2, 7538 COMMAND_PRIORITY_LOW: () => COMMAND_PRIORITY_LOW2, 7539 COMMAND_PRIORITY_NORMAL: () => COMMAND_PRIORITY_NORMAL2, 7540 COMPOSITION_END_COMMAND: () => COMPOSITION_END_COMMAND2, 7541 COMPOSITION_END_TAG: () => COMPOSITION_END_TAG2, 7542 COMPOSITION_START_COMMAND: () => COMPOSITION_START_COMMAND2, 7543 COMPOSITION_START_TAG: () => COMPOSITION_START_TAG2, 7544 CONTROLLED_TEXT_INSERTION_COMMAND: () => CONTROLLED_TEXT_INSERTION_COMMAND2, 7545 COPY_COMMAND: () => COPY_COMMAND2, 7546 CUT_COMMAND: () => CUT_COMMAND2, 7547 DEFAULT_EDITOR_DOM_CONFIG: () => DEFAULT_EDITOR_DOM_CONFIG2, 7548 DELETE_CHARACTER_COMMAND: () => DELETE_CHARACTER_COMMAND2, 7549 DELETE_LINE_COMMAND: () => DELETE_LINE_COMMAND2, 7550 DELETE_WORD_COMMAND: () => DELETE_WORD_COMMAND2, 7551 DRAGEND_COMMAND: () => DRAGEND_COMMAND2, 7552 DRAGOVER_COMMAND: () => DRAGOVER_COMMAND2, 7553 DRAGSTART_COMMAND: () => DRAGSTART_COMMAND2, 7554 DROP_COMMAND: () => DROP_COMMAND2, 7555 DecoratorNode: () => DecoratorNode2, 7556 ElementNode: () => ElementNode2, 7557 FOCUS_COMMAND: () => FOCUS_COMMAND2, 7558 FORMAT_ELEMENT_COMMAND: () => FORMAT_ELEMENT_COMMAND2, 7559 FORMAT_TEXT_COMMAND: () => FORMAT_TEXT_COMMAND2, 7560 HISTORIC_TAG: () => HISTORIC_TAG2, 7561 HISTORY_MERGE_TAG: () => HISTORY_MERGE_TAG2, 7562 HISTORY_PUSH_TAG: () => HISTORY_PUSH_TAG2, 7563 INDENT_CONTENT_COMMAND: () => INDENT_CONTENT_COMMAND2, 7564 INPUT_COMMAND: () => INPUT_COMMAND2, 7565 INSERT_LINE_BREAK_COMMAND: () => INSERT_LINE_BREAK_COMMAND2, 7566 INSERT_PARAGRAPH_COMMAND: () => INSERT_PARAGRAPH_COMMAND2, 7567 INSERT_TAB_COMMAND: () => INSERT_TAB_COMMAND2, 7568 INTERNAL_$isBlock: () => INTERNAL_$isBlock2, 7569 IS_ALL_FORMATTING: () => IS_ALL_FORMATTING2, 7570 IS_BOLD: () => IS_BOLD2, 7571 IS_CODE: () => IS_CODE2, 7572 IS_HIGHLIGHT: () => IS_HIGHLIGHT2, 7573 IS_ITALIC: () => IS_ITALIC2, 7574 IS_STRIKETHROUGH: () => IS_STRIKETHROUGH2, 7575 IS_SUBSCRIPT: () => IS_SUBSCRIPT2, 7576 IS_SUPERSCRIPT: () => IS_SUPERSCRIPT2, 7577 IS_UNDERLINE: () => IS_UNDERLINE2, 7578 KEY_ARROW_DOWN_COMMAND: () => KEY_ARROW_DOWN_COMMAND2, 7579 KEY_ARROW_LEFT_COMMAND: () => KEY_ARROW_LEFT_COMMAND2, 7580 KEY_ARROW_RIGHT_COMMAND: () => KEY_ARROW_RIGHT_COMMAND2, 7581 KEY_ARROW_UP_COMMAND: () => KEY_ARROW_UP_COMMAND2, 7582 KEY_BACKSPACE_COMMAND: () => KEY_BACKSPACE_COMMAND2, 7583 KEY_DELETE_COMMAND: () => KEY_DELETE_COMMAND2, 7584 KEY_DOWN_COMMAND: () => KEY_DOWN_COMMAND2, 7585 KEY_ENTER_COMMAND: () => KEY_ENTER_COMMAND2, 7586 KEY_ESCAPE_COMMAND: () => KEY_ESCAPE_COMMAND2, 7587 KEY_MODIFIER_COMMAND: () => KEY_MODIFIER_COMMAND2, 7588 KEY_SPACE_COMMAND: () => KEY_SPACE_COMMAND2, 7589 KEY_TAB_COMMAND: () => KEY_TAB_COMMAND2, 7590 LineBreakNode: () => LineBreakNode2, 7591 MOVE_TO_END: () => MOVE_TO_END2, 7592 MOVE_TO_START: () => MOVE_TO_START2, 7593 NODE_STATE_KEY: () => NODE_STATE_KEY2, 7594 OUTDENT_CONTENT_COMMAND: () => OUTDENT_CONTENT_COMMAND2, 7595 PASTE_COMMAND: () => PASTE_COMMAND2, 7596 PASTE_TAG: () => PASTE_TAG2, 7597 ParagraphNode: () => ParagraphNode2, 7598 REDO_COMMAND: () => REDO_COMMAND2, 7599 REMOVE_TEXT_COMMAND: () => REMOVE_TEXT_COMMAND2, 7600 RootNode: () => RootNode2, 7601 SELECTION_CHANGE_COMMAND: () => SELECTION_CHANGE_COMMAND2, 7602 SELECTION_INSERT_CLIPBOARD_NODES_COMMAND: () => SELECTION_INSERT_CLIPBOARD_NODES_COMMAND2, 7603 SELECT_ALL_COMMAND: () => SELECT_ALL_COMMAND2, 7604 SKIP_COLLAB_TAG: () => SKIP_COLLAB_TAG2, 7605 SKIP_DOM_SELECTION_TAG: () => SKIP_DOM_SELECTION_TAG2, 7606 SKIP_SCROLL_INTO_VIEW_TAG: () => SKIP_SCROLL_INTO_VIEW_TAG2, 7607 SKIP_SELECTION_FOCUS_TAG: () => SKIP_SELECTION_FOCUS_TAG2, 7608 TEXT_TYPE_TO_FORMAT: () => TEXT_TYPE_TO_FORMAT2, 7609 TabNode: () => TabNode2, 7610 TextNode: () => TextNode2, 7611 UNDO_COMMAND: () => UNDO_COMMAND2, 7612 addClassNamesToElement: () => addClassNamesToElement2, 7613 buildImportMap: () => buildImportMap2, 7614 configExtension: () => configExtension2, 7615 createCommand: () => createCommand2, 7616 createEditor: () => createEditor2, 7617 createSharedNodeState: () => createSharedNodeState2, 7618 createState: () => createState2, 7619 declarePeerDependency: () => declarePeerDependency2, 7620 defineExtension: () => defineExtension2, 7621 flipDirection: () => flipDirection2, 7622 getDOMOwnerDocument: () => getDOMOwnerDocument2, 7623 getDOMSelection: () => getDOMSelection2, 7624 getDOMSelectionFromTarget: () => getDOMSelectionFromTarget2, 7625 getDOMTextNode: () => getDOMTextNode2, 7626 getEditorPropertyFromDOMNode: () => getEditorPropertyFromDOMNode2, 7627 getNearestEditorFromDOMNode: () => getNearestEditorFromDOMNode2, 7628 getRegisteredNode: () => getRegisteredNode2, 7629 getRegisteredNodeOrThrow: () => getRegisteredNodeOrThrow2, 7630 getStaticNodeConfig: () => getStaticNodeConfig2, 7631 getStyleObjectFromCSS: () => getStyleObjectFromCSS2, 7632 getTextDirection: () => getTextDirection2, 7633 getTransformSetFromKlass: () => getTransformSetFromKlass2, 7634 isBlockDomNode: () => isBlockDomNode2, 7635 isCurrentlyReadOnlyMode: () => isCurrentlyReadOnlyMode2, 7636 isDOMDocumentNode: () => isDOMDocumentNode2, 7637 isDOMNode: () => isDOMNode2, 7638 isDOMTextNode: () => isDOMTextNode2, 7639 isDOMUnmanaged: () => isDOMUnmanaged2, 7640 isDocumentFragment: () => isDocumentFragment2, 7641 isExactShortcutMatch: () => isExactShortcutMatch2, 7642 isHTMLAnchorElement: () => isHTMLAnchorElement2, 7643 isHTMLElement: () => isHTMLElement2, 7644 isInlineDomNode: () => isInlineDomNode2, 7645 isLexicalEditor: () => isLexicalEditor2, 7646 isModifierMatch: () => isModifierMatch2, 7647 isSelectionCapturedInDecoratorInput: () => isSelectionCapturedInDecoratorInput2, 7648 isSelectionWithinEditor: () => isSelectionWithinEditor2, 7649 makeStepwiseIterator: () => makeStepwiseIterator2, 7650 mergeRegister: () => mergeRegister2, 7651 normalizeClassNames: () => normalizeClassNames2, 7652 removeClassNamesFromElement: () => removeClassNamesFromElement2, 7653 removeFromParent: () => removeFromParent2, 7654 resetRandomKey: () => resetRandomKey2, 7655 safeCast: () => safeCast2, 7656 setDOMStyleFromCSS: () => setDOMStyleFromCSS2, 7657 setDOMStyleObject: () => setDOMStyleObject2, 7658 setDOMUnmanaged: () => setDOMUnmanaged2, 7659 setNodeIndentFromDOM: () => setNodeIndentFromDOM2, 7660 shallowMergeConfig: () => shallowMergeConfig2, 7661 toggleTextFormatType: () => toggleTextFormatType2 7662 }); 7663 7664
vendor: 446,113 bytes, lines 7664-19555
7664// node_modules/lexical/Lexical.dev.mjs 7665 var Lexical_dev_exports = {}; 7666 __export(Lexical_dev_exports, { 7667 $addUpdateTag: () => $addUpdateTag, 7668 $applyNodeReplacement: () => $applyNodeReplacement, 7669 $caretFromPoint: () => $caretFromPoint, 7670 $caretRangeFromSelection: () => $caretRangeFromSelection, 7671 $cloneWithProperties: () => $cloneWithProperties, 7672 $cloneWithPropertiesEphemeral: () => $cloneWithPropertiesEphemeral, 7673 $comparePointCaretNext: () => $comparePointCaretNext, 7674 $copyNode: () => $copyNode, 7675 $create: () => $create, 7676 $createChildrenArray: () => $createChildrenArray, 7677 $createLineBreakNode: () => $createLineBreakNode, 7678 $createNodeSelection: () => $createNodeSelection, 7679 $createParagraphNode: () => $createParagraphNode, 7680 $createPoint: () => $createPoint, 7681 $createRangeSelection: () => $createRangeSelection, 7682 $createRangeSelectionFromDom: () => $createRangeSelectionFromDom, 7683 $createTabNode: () => $createTabNode, 7684 $createTextNode: () => $createTextNode, 7685 $extendCaretToRange: () => $extendCaretToRange, 7686 $findMatchingParent: () => $findMatchingParent, 7687 $getAdjacentChildCaret: () => $getAdjacentChildCaret, 7688 $getAdjacentNode: () => $getAdjacentNode, 7689 $getAdjacentSiblingOrParentSiblingCaret: () => $getAdjacentSiblingOrParentSiblingCaret, 7690 $getCaretInDirection: () => $getCaretInDirection, 7691 $getCaretRange: () => $getCaretRange, 7692 $getCaretRangeInDirection: () => $getCaretRangeInDirection, 7693 $getCharacterOffsets: () => $getCharacterOffsets, 7694 $getChildCaret: () => $getChildCaret, 7695 $getChildCaretAtIndex: () => $getChildCaretAtIndex, 7696 $getChildCaretOrSelf: () => $getChildCaretOrSelf, 7697 $getCollapsedCaretRange: () => $getCollapsedCaretRange, 7698 $getCommonAncestor: () => $getCommonAncestor, 7699 $getCommonAncestorResultBranchOrder: () => $getCommonAncestorResultBranchOrder, 7700 $getEditor: () => $getEditor, 7701 $getEditorDOMRenderConfig: () => $getEditorDOMRenderConfig, 7702 $getNearestNodeFromDOMNode: () => $getNearestNodeFromDOMNode, 7703 $getNearestRootOrShadowRoot: () => $getNearestRootOrShadowRoot, 7704 $getNodeByKey: () => $getNodeByKey, 7705 $getNodeByKeyOrThrow: () => $getNodeByKeyOrThrow, 7706 $getNodeFromDOMNode: () => $getNodeFromDOMNode, 7707 $getPreviousSelection: () => $getPreviousSelection, 7708 $getRoot: () => $getRoot, 7709 $getSelection: () => $getSelection, 7710 $getSiblingCaret: () => $getSiblingCaret, 7711 $getState: () => $getState, 7712 $getStateChange: () => $getStateChange, 7713 $getTextContent: () => $getTextContent, 7714 $getTextNodeOffset: () => $getTextNodeOffset, 7715 $getTextPointCaret: () => $getTextPointCaret, 7716 $getTextPointCaretSlice: () => $getTextPointCaretSlice, 7717 $getWritableNodeState: () => $getWritableNodeState, 7718 $hasAncestor: () => $hasAncestor, 7719 $hasUpdateTag: () => $hasUpdateTag, 7720 $insertNodes: () => $insertNodes, 7721 $isBlockElementNode: () => $isBlockElementNode, 7722 $isChildCaret: () => $isChildCaret, 7723 $isDecoratorNode: () => $isDecoratorNode, 7724 $isEditorState: () => $isEditorState, 7725 $isElementNode: () => $isElementNode, 7726 $isExtendableTextPointCaret: () => $isExtendableTextPointCaret, 7727 $isInlineElementOrDecoratorNode: () => $isInlineElementOrDecoratorNode, 7728 $isLeafNode: () => $isLeafNode, 7729 $isLexicalNode: () => $isLexicalNode, 7730 $isLineBreakNode: () => $isLineBreakNode, 7731 $isNodeCaret: () => $isNodeCaret, 7732 $isNodeSelection: () => $isNodeSelection, 7733 $isParagraphNode: () => $isParagraphNode, 7734 $isRangeSelection: () => $isRangeSelection, 7735 $isRootNode: () => $isRootNode, 7736 $isRootOrShadowRoot: () => $isRootOrShadowRoot, 7737 $isSiblingCaret: () => $isSiblingCaret, 7738 $isTabNode: () => $isTabNode, 7739 $isTextNode: () => $isTextNode, 7740 $isTextPointCaret: () => $isTextPointCaret, 7741 $isTextPointCaretSlice: () => $isTextPointCaretSlice, 7742 $isTokenOrSegmented: () => $isTokenOrSegmented, 7743 $isTokenOrTab: () => $isTokenOrTab, 7744 $nodesOfType: () => $nodesOfType, 7745 $normalizeCaret: () => $normalizeCaret, 7746 $normalizeSelection__EXPERIMENTAL: () => $normalizeSelection, 7747 $onUpdate: () => $onUpdate, 7748 $parseSerializedNode: () => $parseSerializedNode, 7749 $removeTextFromCaretRange: () => $removeTextFromCaretRange, 7750 $rewindSiblingCaret: () => $rewindSiblingCaret, 7751 $selectAll: () => $selectAll, 7752 $setCompositionKey: () => $setCompositionKey, 7753 $setPointFromCaret: () => $setPointFromCaret, 7754 $setSelection: () => $setSelection, 7755 $setSelectionFromCaretRange: () => $setSelectionFromCaretRange, 7756 $setState: () => $setState, 7757 $splitAtPointCaretNext: () => $splitAtPointCaretNext, 7758 $splitNode: () => $splitNode, 7759 $updateRangeSelectionFromCaretRange: () => $updateRangeSelectionFromCaretRange, 7760 ArtificialNode__DO_NOT_USE: () => ArtificialNode__DO_NOT_USE, 7761 BEFORE_INPUT_COMMAND: () => BEFORE_INPUT_COMMAND, 7762 BLUR_COMMAND: () => BLUR_COMMAND, 7763 CAN_REDO_COMMAND: () => CAN_REDO_COMMAND, 7764 CAN_UNDO_COMMAND: () => CAN_UNDO_COMMAND, 7765 CLEAR_EDITOR_COMMAND: () => CLEAR_EDITOR_COMMAND, 7766 CLEAR_HISTORY_COMMAND: () => CLEAR_HISTORY_COMMAND, 7767 CLICK_COMMAND: () => CLICK_COMMAND, 7768 COLLABORATION_TAG: () => COLLABORATION_TAG, 7769 COMMAND_PRIORITY_BEFORE_CRITICAL: () => COMMAND_PRIORITY_BEFORE_CRITICAL, 7770 COMMAND_PRIORITY_BEFORE_EDITOR: () => COMMAND_PRIORITY_BEFORE_EDITOR, 7771 COMMAND_PRIORITY_BEFORE_HIGH: () => COMMAND_PRIORITY_BEFORE_HIGH, 7772 COMMAND_PRIORITY_BEFORE_LOW: () => COMMAND_PRIORITY_BEFORE_LOW, 7773 COMMAND_PRIORITY_BEFORE_NORMAL: () => COMMAND_PRIORITY_BEFORE_NORMAL, 7774 COMMAND_PRIORITY_CRITICAL: () => COMMAND_PRIORITY_CRITICAL, 7775 COMMAND_PRIORITY_EDITOR: () => COMMAND_PRIORITY_EDITOR, 7776 COMMAND_PRIORITY_HIGH: () => COMMAND_PRIORITY_HIGH, 7777 COMMAND_PRIORITY_LOW: () => COMMAND_PRIORITY_LOW, 7778 COMMAND_PRIORITY_NORMAL: () => COMMAND_PRIORITY_NORMAL, 7779 COMPOSITION_END_COMMAND: () => COMPOSITION_END_COMMAND, 7780 COMPOSITION_END_TAG: () => COMPOSITION_END_TAG, 7781 COMPOSITION_START_COMMAND: () => COMPOSITION_START_COMMAND, 7782 COMPOSITION_START_TAG: () => COMPOSITION_START_TAG, 7783 CONTROLLED_TEXT_INSERTION_COMMAND: () => CONTROLLED_TEXT_INSERTION_COMMAND, 7784 COPY_COMMAND: () => COPY_COMMAND, 7785 CUT_COMMAND: () => CUT_COMMAND, 7786 DEFAULT_EDITOR_DOM_CONFIG: () => DEFAULT_EDITOR_DOM_CONFIG, 7787 DELETE_CHARACTER_COMMAND: () => DELETE_CHARACTER_COMMAND, 7788 DELETE_LINE_COMMAND: () => DELETE_LINE_COMMAND, 7789 DELETE_WORD_COMMAND: () => DELETE_WORD_COMMAND, 7790 DRAGEND_COMMAND: () => DRAGEND_COMMAND, 7791 DRAGOVER_COMMAND: () => DRAGOVER_COMMAND, 7792 DRAGSTART_COMMAND: () => DRAGSTART_COMMAND, 7793 DROP_COMMAND: () => DROP_COMMAND, 7794 DecoratorNode: () => DecoratorNode, 7795 ElementNode: () => ElementNode, 7796 FOCUS_COMMAND: () => FOCUS_COMMAND, 7797 FORMAT_ELEMENT_COMMAND: () => FORMAT_ELEMENT_COMMAND, 7798 FORMAT_TEXT_COMMAND: () => FORMAT_TEXT_COMMAND, 7799 HISTORIC_TAG: () => HISTORIC_TAG, 7800 HISTORY_MERGE_TAG: () => HISTORY_MERGE_TAG, 7801 HISTORY_PUSH_TAG: () => HISTORY_PUSH_TAG, 7802 INDENT_CONTENT_COMMAND: () => INDENT_CONTENT_COMMAND, 7803 INPUT_COMMAND: () => INPUT_COMMAND, 7804 INSERT_LINE_BREAK_COMMAND: () => INSERT_LINE_BREAK_COMMAND, 7805 INSERT_PARAGRAPH_COMMAND: () => INSERT_PARAGRAPH_COMMAND, 7806 INSERT_TAB_COMMAND: () => INSERT_TAB_COMMAND, 7807 INTERNAL_$isBlock: () => INTERNAL_$isBlock, 7808 IS_ALL_FORMATTING: () => IS_ALL_FORMATTING, 7809 IS_BOLD: () => IS_BOLD, 7810 IS_CODE: () => IS_CODE, 7811 IS_HIGHLIGHT: () => IS_HIGHLIGHT, 7812 IS_ITALIC: () => IS_ITALIC, 7813 IS_STRIKETHROUGH: () => IS_STRIKETHROUGH, 7814 IS_SUBSCRIPT: () => IS_SUBSCRIPT, 7815 IS_SUPERSCRIPT: () => IS_SUPERSCRIPT, 7816 IS_UNDERLINE: () => IS_UNDERLINE, 7817 KEY_ARROW_DOWN_COMMAND: () => KEY_ARROW_DOWN_COMMAND, 7818 KEY_ARROW_LEFT_COMMAND: () => KEY_ARROW_LEFT_COMMAND, 7819 KEY_ARROW_RIGHT_COMMAND: () => KEY_ARROW_RIGHT_COMMAND, 7820 KEY_ARROW_UP_COMMAND: () => KEY_ARROW_UP_COMMAND, 7821 KEY_BACKSPACE_COMMAND: () => KEY_BACKSPACE_COMMAND, 7822 KEY_DELETE_COMMAND: () => KEY_DELETE_COMMAND, 7823 KEY_DOWN_COMMAND: () => KEY_DOWN_COMMAND, 7824 KEY_ENTER_COMMAND: () => KEY_ENTER_COMMAND, 7825 KEY_ESCAPE_COMMAND: () => KEY_ESCAPE_COMMAND, 7826 KEY_MODIFIER_COMMAND: () => KEY_MODIFIER_COMMAND, 7827 KEY_SPACE_COMMAND: () => KEY_SPACE_COMMAND, 7828 KEY_TAB_COMMAND: () => KEY_TAB_COMMAND, 7829 LineBreakNode: () => LineBreakNode, 7830 MOVE_TO_END: () => MOVE_TO_END, 7831 MOVE_TO_START: () => MOVE_TO_START, 7832 NODE_STATE_KEY: () => NODE_STATE_KEY, 7833 OUTDENT_CONTENT_COMMAND: () => OUTDENT_CONTENT_COMMAND, 7834 PASTE_COMMAND: () => PASTE_COMMAND, 7835 PASTE_TAG: () => PASTE_TAG, 7836 ParagraphNode: () => ParagraphNode, 7837 REDO_COMMAND: () => REDO_COMMAND, 7838 REMOVE_TEXT_COMMAND: () => REMOVE_TEXT_COMMAND, 7839 RootNode: () => RootNode, 7840 SELECTION_CHANGE_COMMAND: () => SELECTION_CHANGE_COMMAND, 7841 SELECTION_INSERT_CLIPBOARD_NODES_COMMAND: () => SELECTION_INSERT_CLIPBOARD_NODES_COMMAND, 7842 SELECT_ALL_COMMAND: () => SELECT_ALL_COMMAND, 7843 SKIP_COLLAB_TAG: () => SKIP_COLLAB_TAG, 7844 SKIP_DOM_SELECTION_TAG: () => SKIP_DOM_SELECTION_TAG, 7845 SKIP_SCROLL_INTO_VIEW_TAG: () => SKIP_SCROLL_INTO_VIEW_TAG, 7846 SKIP_SELECTION_FOCUS_TAG: () => SKIP_SELECTION_FOCUS_TAG, 7847 TEXT_TYPE_TO_FORMAT: () => TEXT_TYPE_TO_FORMAT, 7848 TabNode: () => TabNode, 7849 TextNode: () => TextNode, 7850 UNDO_COMMAND: () => UNDO_COMMAND, 7851 addClassNamesToElement: () => addClassNamesToElement, 7852 buildImportMap: () => buildImportMap, 7853 configExtension: () => configExtension, 7854 createCommand: () => createCommand, 7855 createEditor: () => createEditor, 7856 createSharedNodeState: () => createSharedNodeState, 7857 createState: () => createState, 7858 declarePeerDependency: () => declarePeerDependency, 7859 defineExtension: () => defineExtension, 7860 flipDirection: () => flipDirection, 7861 getDOMOwnerDocument: () => getDOMOwnerDocument, 7862 getDOMSelection: () => getDOMSelection, 7863 getDOMSelectionFromTarget: () => getDOMSelectionFromTarget, 7864 getDOMTextNode: () => getDOMTextNode, 7865 getEditorPropertyFromDOMNode: () => getEditorPropertyFromDOMNode, 7866 getNearestEditorFromDOMNode: () => getNearestEditorFromDOMNode, 7867 getRegisteredNode: () => getRegisteredNode, 7868 getRegisteredNodeOrThrow: () => getRegisteredNodeOrThrow, 7869 getStaticNodeConfig: () => getStaticNodeConfig, 7870 getStyleObjectFromCSS: () => getStyleObjectFromCSS, 7871 getTextDirection: () => getTextDirection, 7872 getTransformSetFromKlass: () => getTransformSetFromKlass, 7873 isBlockDomNode: () => isBlockDomNode, 7874 isCurrentlyReadOnlyMode: () => isCurrentlyReadOnlyMode, 7875 isDOMDocumentNode: () => isDOMDocumentNode, 7876 isDOMNode: () => isDOMNode, 7877 isDOMTextNode: () => isDOMTextNode, 7878 isDOMUnmanaged: () => isDOMUnmanaged, 7879 isDocumentFragment: () => isDocumentFragment, 7880 isExactShortcutMatch: () => isExactShortcutMatch, 7881 isHTMLAnchorElement: () => isHTMLAnchorElement, 7882 isHTMLElement: () => isHTMLElement, 7883 isInlineDomNode: () => isInlineDomNode, 7884 isLexicalEditor: () => isLexicalEditor, 7885 isModifierMatch: () => isModifierMatch, 7886 isSelectionCapturedInDecoratorInput: () => isSelectionCapturedInDecoratorInput, 7887 isSelectionWithinEditor: () => isSelectionWithinEditor, 7888 makeStepwiseIterator: () => makeStepwiseIterator, 7889 mergeRegister: () => mergeRegister, 7890 normalizeClassNames: () => normalizeClassNames, 7891 removeClassNamesFromElement: () => removeClassNamesFromElement, 7892 removeFromParent: () => removeFromParent, 7893 resetRandomKey: () => resetRandomKey, 7894 safeCast: () => safeCast, 7895 setDOMStyleFromCSS: () => setDOMStyleFromCSS, 7896 setDOMStyleObject: () => setDOMStyleObject, 7897 setDOMUnmanaged: () => setDOMUnmanaged, 7898 setNodeIndentFromDOM: () => setNodeIndentFromDOM, 7899 shallowMergeConfig: () => shallowMergeConfig, 7900 toggleTextFormatType: () => toggleTextFormatType 7901 }); 7902 function formatDevErrorMessage(message) { 7903 throw new Error(message); 7904 } 7905 var CAN_USE_DOM = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined"; 7906 var documentMode = CAN_USE_DOM && "documentMode" in document ? document.documentMode : null; 7907 var IS_APPLE = CAN_USE_DOM && /Mac|iPod|iPhone|iPad/.test(navigator.platform); 7908 var IS_FIREFOX = CAN_USE_DOM && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent); 7909 var CAN_USE_BEFORE_INPUT = CAN_USE_DOM && "InputEvent" in window && !documentMode ? "getTargetRanges" in new window.InputEvent("input") : false; 7910 var IS_IOS = CAN_USE_DOM && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; 7911 var IS_ANDROID = CAN_USE_DOM && /Android/.test(navigator.userAgent); 7912 var IS_SAFARI = CAN_USE_DOM && /Version\/[\d.]+.*Safari/.test(navigator.userAgent) && !IS_ANDROID; 7913 var IS_CHROME = CAN_USE_DOM && /^(?=.*Chrome).*/i.test(navigator.userAgent); 7914 var IS_ANDROID_CHROME = CAN_USE_DOM && IS_ANDROID && IS_CHROME; 7915 var IS_APPLE_WEBKIT = CAN_USE_DOM && /AppleWebKit\/[\d.]+/.test(navigator.userAgent) && IS_APPLE && !IS_CHROME; 7916 var DOM_ELEMENT_TYPE = 1; 7917 var DOM_TEXT_TYPE = 3; 7918 var DOM_DOCUMENT_TYPE = 9; 7919 var DOM_DOCUMENT_FRAGMENT_TYPE = 11; 7920 var NO_DIRTY_NODES = 0; 7921 var HAS_DIRTY_NODES = 1; 7922 var FULL_RECONCILE = 2; 7923 var IS_NORMAL = 0; 7924 var IS_TOKEN = 1; 7925 var IS_SEGMENTED = 2; 7926 var IS_BOLD = 1; 7927 var IS_ITALIC = 1 << 1; 7928 var IS_STRIKETHROUGH = 1 << 2; 7929 var IS_UNDERLINE = 1 << 3; 7930 var IS_CODE = 1 << 4; 7931 var IS_SUBSCRIPT = 1 << 5; 7932 var IS_SUPERSCRIPT = 1 << 6; 7933 var IS_HIGHLIGHT = 1 << 7; 7934 var IS_LOWERCASE = 1 << 8; 7935 var IS_UPPERCASE = 1 << 9; 7936 var IS_CAPITALIZE = 1 << 10; 7937 var IS_ALL_FORMATTING = IS_BOLD | IS_ITALIC | IS_STRIKETHROUGH | IS_UNDERLINE | IS_CODE | IS_SUBSCRIPT | IS_SUPERSCRIPT | IS_HIGHLIGHT | IS_LOWERCASE | IS_UPPERCASE | IS_CAPITALIZE; 7938 var IS_DIRECTIONLESS = 1; 7939 var IS_UNMERGEABLE = 1 << 1; 7940 var IS_ALIGN_LEFT = 1; 7941 var IS_ALIGN_CENTER = 2; 7942 var IS_ALIGN_RIGHT = 3; 7943 var IS_ALIGN_JUSTIFY = 4; 7944 var IS_ALIGN_START = 5; 7945 var IS_ALIGN_END = 6; 7946 var NON_BREAKING_SPACE = "\xA0"; 7947 var ZERO_WIDTH_SPACE = "\u200B"; 7948 var COMPOSITION_SUFFIX = IS_SAFARI || IS_IOS || IS_APPLE_WEBKIT ? NON_BREAKING_SPACE : ZERO_WIDTH_SPACE; 7949 var DOUBLE_LINE_BREAK = "\n\n"; 7950 var COMPOSITION_START_CHAR = IS_FIREFOX ? NON_BREAKING_SPACE : COMPOSITION_SUFFIX; 7951 var RTL = "\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC"; 7952 var LTR = "A-Za-z\xC0-\xD6\xD8-\xF6\xF8-\u02B8\u0300-\u0590\u0800-\u1FFF\u200E\u2C00-\uFB1C\uFE00-\uFE6F\uFEFD-\uFFFF"; 7953 var RTL_REGEX = new RegExp("^[^" + LTR + "]*[" + RTL + "]"); 7954 var LTR_REGEX = new RegExp("^[^" + RTL + "]*[" + LTR + "]"); 7955 var TEXT_TYPE_TO_FORMAT = { 7956 bold: IS_BOLD, 7957 capitalize: IS_CAPITALIZE, 7958 code: IS_CODE, 7959 highlight: IS_HIGHLIGHT, 7960 italic: IS_ITALIC, 7961 lowercase: IS_LOWERCASE, 7962 strikethrough: IS_STRIKETHROUGH, 7963 subscript: IS_SUBSCRIPT, 7964 superscript: IS_SUPERSCRIPT, 7965 underline: IS_UNDERLINE, 7966 uppercase: IS_UPPERCASE 7967 }; 7968 var DETAIL_TYPE_TO_DETAIL = { 7969 directionless: IS_DIRECTIONLESS, 7970 unmergeable: IS_UNMERGEABLE 7971 }; 7972 var ELEMENT_TYPE_TO_FORMAT = { 7973 center: IS_ALIGN_CENTER, 7974 end: IS_ALIGN_END, 7975 justify: IS_ALIGN_JUSTIFY, 7976 left: IS_ALIGN_LEFT, 7977 right: IS_ALIGN_RIGHT, 7978 start: IS_ALIGN_START 7979 }; 7980 var ELEMENT_FORMAT_TO_TYPE = { 7981 [IS_ALIGN_CENTER]: "center", 7982 [IS_ALIGN_END]: "end", 7983 [IS_ALIGN_JUSTIFY]: "justify", 7984 [IS_ALIGN_LEFT]: "left", 7985 [IS_ALIGN_RIGHT]: "right", 7986 [IS_ALIGN_START]: "start" 7987 }; 7988 var TEXT_MODE_TO_TYPE = { 7989 normal: IS_NORMAL, 7990 segmented: IS_SEGMENTED, 7991 token: IS_TOKEN 7992 }; 7993 var TEXT_TYPE_TO_MODE = { 7994 [IS_NORMAL]: "normal", 7995 [IS_SEGMENTED]: "segmented", 7996 [IS_TOKEN]: "token" 7997 }; 7998 var NODE_STATE_KEY = "$"; 7999 var PROTOTYPE_CONFIG_METHOD = "$config"; 8000 var DequeSet = class { 8001 _front = /* @__PURE__ */ new Set(); 8002 _back = /* @__PURE__ */ new Set(); 8003 _cache; 8004 get size() { 8005 return this._front.size + this._back.size; 8006 } 8007 addBack(v3) { 8008 delete this._cache; 8009 if (!this._front.has(v3)) { 8010 this._back.add(v3); 8011 } 8012 return this; 8013 } 8014 addFront(v3) { 8015 delete this._cache; 8016 if (!this._back.has(v3)) { 8017 this._front.add(v3); 8018 } 8019 return this; 8020 } 8021 delete(v3) { 8022 delete this._cache; 8023 return this._front.delete(v3) || this._back.delete(v3); 8024 } 8025 toArray() { 8026 const arr = Array.from(this._front).reverse(); 8027 for (const v3 of this._back) { 8028 arr.push(v3); 8029 } 8030 return arr; 8031 } 8032 toReadonlyArray() { 8033 this._cache = this._cache || this.toArray(); 8034 return this._cache; 8035 } 8036 [Symbol.iterator]() { 8037 return this.toReadonlyArray()[Symbol.iterator](); 8038 } 8039 }; 8040 function $garbageCollectDetachedDecorators(editor, pendingEditorState) { 8041 const currentDecorators = editor._decorators; 8042 const pendingDecorators = editor._pendingDecorators; 8043 let decorators = pendingDecorators || currentDecorators; 8044 const nodeMap = pendingEditorState._nodeMap; 8045 let key; 8046 for (key in decorators) { 8047 if (!nodeMap.has(key)) { 8048 if (decorators === currentDecorators) { 8049 decorators = cloneDecorators(editor); 8050 } 8051 delete decorators[key]; 8052 } 8053 } 8054 } 8055 function $garbageCollectDetachedDeepChildNodes(node, parentKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyNodes) { 8056 let child = node.getFirstChild(); 8057 while (child !== null) { 8058 const childKey = child.__key; 8059 if (child.__parent === parentKey) { 8060 if ($isElementNode(child)) { 8061 $garbageCollectDetachedDeepChildNodes(child, childKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyNodes); 8062 } 8063 if (!prevNodeMap.has(childKey)) { 8064 dirtyNodes.delete(childKey); 8065 } 8066 nodeMapDelete.push(childKey); 8067 } 8068 child = child.getNextSibling(); 8069 } 8070 } 8071 function $garbageCollectDetachedNodes(prevEditorState, editorState, dirtyLeaves, dirtyElements) { 8072 const prevNodeMap = prevEditorState._nodeMap; 8073 const nodeMap = editorState._nodeMap; 8074 const nodeMapDelete = []; 8075 for (const [nodeKey] of dirtyElements) { 8076 const node = nodeMap.get(nodeKey); 8077 if (node !== void 0) { 8078 if (!node.isAttached()) { 8079 if ($isElementNode(node)) { 8080 $garbageCollectDetachedDeepChildNodes(node, nodeKey, prevNodeMap, nodeMap, nodeMapDelete, dirtyElements); 8081 } 8082 if (!prevNodeMap.has(nodeKey)) { 8083 dirtyElements.delete(nodeKey); 8084 } 8085 nodeMapDelete.push(nodeKey); 8086 } 8087 } 8088 } 8089 for (const nodeKey of nodeMapDelete) { 8090 nodeMap.delete(nodeKey); 8091 } 8092 for (const nodeKey of dirtyLeaves) { 8093 const node = nodeMap.get(nodeKey); 8094 if (node !== void 0 && !node.isAttached()) { 8095 if (!prevNodeMap.has(nodeKey)) { 8096 dirtyLeaves.delete(nodeKey); 8097 } 8098 nodeMap.delete(nodeKey); 8099 } 8100 } 8101 } 8102 var TEXT_MUTATION_VARIANCE = 100; 8103 var isProcessingMutations = false; 8104 var lastTextEntryTimeStamp = 0; 8105 function getIsProcessingMutations() { 8106 return isProcessingMutations; 8107 } 8108 function updateTimeStamp(event) { 8109 lastTextEntryTimeStamp = event.timeStamp; 8110 } 8111 function initTextEntryListener(editor) { 8112 if (lastTextEntryTimeStamp === 0) { 8113 getWindow(editor).addEventListener("textInput", updateTimeStamp, true); 8114 } 8115 } 8116 function isManagedLineBreak(dom, target, editor) { 8117 const isBR = dom.nodeName === "BR"; 8118 const lexicalLineBreak = target.__lexicalLineBreak; 8119 return lexicalLineBreak && (dom === lexicalLineBreak || isBR && dom.previousSibling === lexicalLineBreak) || isBR && getNodeKeyFromDOMNode(dom, editor) !== void 0; 8120 } 8121 function getLastSelection(editor) { 8122 return editor.getEditorState().read(() => { 8123 const selection = $getSelection(); 8124 return selection !== null ? selection.clone() : null; 8125 }); 8126 } 8127 function $handleTextMutation(target, node, editor) { 8128 const domSelection = getDOMSelection(getWindow(editor)); 8129 let anchorOffset = null; 8130 let focusOffset = null; 8131 if (domSelection !== null && domSelection.anchorNode === target) { 8132 anchorOffset = domSelection.anchorOffset; 8133 focusOffset = domSelection.focusOffset; 8134 } 8135 const text2 = target.nodeValue; 8136 if (text2 !== null) { 8137 $updateTextNodeFromDOMContent(node, text2, anchorOffset, focusOffset, false); 8138 } 8139 } 8140 function shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode) { 8141 if ($isRangeSelection(selection)) { 8142 const anchorNode = selection.anchor.getNode(); 8143 if (anchorNode.is(targetNode) && selection.format !== anchorNode.getFormat()) { 8144 return false; 8145 } 8146 } 8147 return isDOMTextNode(targetDOM) && targetNode.isAttached(); 8148 } 8149 function $getNearestManagedNodePairFromDOMNode(startingDOM, editor, editorState, rootElement) { 8150 for (let dom = startingDOM; dom && !isDOMUnmanaged(dom); dom = getParentElement(dom)) { 8151 const key = getNodeKeyFromDOMNode(dom, editor); 8152 if (key !== void 0) { 8153 const node = $getNodeByKey(key, editorState); 8154 if (node) { 8155 return $isDecoratorNode(node) || !isHTMLElement(dom) ? void 0 : [dom, node]; 8156 } 8157 } else if (dom === rootElement) { 8158 return [rootElement, internalGetRoot(editorState)]; 8159 } 8160 } 8161 } 8162 function flushMutations(editor, mutations, observer) { 8163 isProcessingMutations = true; 8164 const shouldFlushTextMutations = performance.now() - lastTextEntryTimeStamp > TEXT_MUTATION_VARIANCE; 8165 try { 8166 updateEditorSync(editor, () => { 8167 const selection = $getSelection() || getLastSelection(editor); 8168 const badDOMTargets = /* @__PURE__ */ new Map(); 8169 const rootElement = editor.getRootElement(); 8170 const currentEditorState = editor._editorState; 8171 const blockCursorElement = editor._blockCursorElement; 8172 let shouldRevertSelection = false; 8173 let possibleTextForFirefoxPaste = ""; 8174 for (let i2 = 0; i2 < mutations.length; i2++) { 8175 const mutation = mutations[i2]; 8176 const type = mutation.type; 8177 const targetDOM = mutation.target; 8178 const pair = $getNearestManagedNodePairFromDOMNode(targetDOM, editor, currentEditorState, rootElement); 8179 if (!pair) { 8180 continue; 8181 } 8182 const [nodeDOM, targetNode] = pair; 8183 if (type === "characterData") { 8184 if ( 8185 // TODO there is an edge case here if a mutation happens too quickly 8186 // after text input, it may never be handled since we do not 8187 // track the ignored mutations in any way 8188 shouldFlushTextMutations && $isTextNode(targetNode) && isDOMTextNode(targetDOM) && shouldUpdateTextNodeFromMutation(selection, targetDOM, targetNode) 8189 ) { 8190 $handleTextMutation(targetDOM, targetNode, editor); 8191 } 8192 } else if (type === "childList") { 8193 shouldRevertSelection = true; 8194 const addedDOMs = mutation.addedNodes; 8195 for (let s2 = 0; s2 < addedDOMs.length; s2++) { 8196 const addedDOM = addedDOMs[s2]; 8197 const node = $getNodeFromDOMNode(addedDOM); 8198 const parentDOM = addedDOM.parentNode; 8199 if (parentDOM != null && addedDOM !== blockCursorElement && node === null && !isManagedLineBreak(addedDOM, parentDOM, editor)) { 8200 if (IS_FIREFOX) { 8201 const possibleText = (isHTMLElement(addedDOM) ? addedDOM.innerText : null) || addedDOM.nodeValue; 8202 if (possibleText) { 8203 possibleTextForFirefoxPaste += possibleText; 8204 } 8205 } 8206 parentDOM.removeChild(addedDOM); 8207 } 8208 } 8209 const removedDOMs = mutation.removedNodes; 8210 const removedDOMsLength = removedDOMs.length; 8211 if (removedDOMsLength > 0) { 8212 let unremovedBRs = 0; 8213 for (let s2 = 0; s2 < removedDOMsLength; s2++) { 8214 const removedDOM = removedDOMs[s2]; 8215 if (isManagedLineBreak(removedDOM, targetDOM, editor) || blockCursorElement === removedDOM) { 8216 targetDOM.appendChild(removedDOM); 8217 unremovedBRs++; 8218 } 8219 } 8220 if (removedDOMsLength !== unremovedBRs) { 8221 badDOMTargets.set(nodeDOM, targetNode); 8222 } 8223 } 8224 } 8225 } 8226 if (badDOMTargets.size > 0) { 8227 for (const [nodeDOM, targetNode] of badDOMTargets) { 8228 targetNode.reconcileObservedMutation(nodeDOM, editor); 8229 } 8230 } 8231 const records = observer.takeRecords(); 8232 if (records.length > 0) { 8233 for (let i2 = 0; i2 < records.length; i2++) { 8234 const record = records[i2]; 8235 const addedNodes = record.addedNodes; 8236 const target = record.target; 8237 for (let s2 = 0; s2 < addedNodes.length; s2++) { 8238 const addedDOM = addedNodes[s2]; 8239 const parentDOM = addedDOM.parentNode; 8240 if (parentDOM != null && addedDOM.nodeName === "BR" && !isManagedLineBreak(addedDOM, target, editor)) { 8241 parentDOM.removeChild(addedDOM); 8242 } 8243 } 8244 } 8245 observer.takeRecords(); 8246 } 8247 if (selection !== null) { 8248 if (shouldRevertSelection) { 8249 $setSelection(selection); 8250 } 8251 if (IS_FIREFOX && isFirefoxClipboardEvents(editor)) { 8252 selection.insertRawText(possibleTextForFirefoxPaste); 8253 } 8254 } 8255 }); 8256 } finally { 8257 isProcessingMutations = false; 8258 } 8259 } 8260 function flushRootMutations(editor) { 8261 const observer = editor._observer; 8262 if (observer !== null) { 8263 const mutations = observer.takeRecords(); 8264 flushMutations(editor, mutations, observer); 8265 } 8266 } 8267 function initMutationObserver(editor) { 8268 initTextEntryListener(editor); 8269 editor._observer = new MutationObserver((mutations, observer) => { 8270 flushMutations(editor, mutations, observer); 8271 }); 8272 } 8273 var StateConfig = class { 8274 /** The string key used when serializing this state to JSON */ 8275 key; 8276 /** The parse function from the StateValueConfig passed to createState */ 8277 parse; 8278 /** 8279 * The unparse function from the StateValueConfig passed to createState, 8280 * with a default that is simply a pass-through that assumes the value is 8281 * JSON serializable. 8282 */ 8283 unparse; 8284 /** 8285 * An equality function from the StateValueConfig, with a default of 8286 * Object.is. 8287 */ 8288 isEqual; 8289 /** 8290 * The result of `stateValueConfig.parse(undefined)`, which is computed only 8291 * once and used as the default value. When the current value `isEqual` to 8292 * the `defaultValue`, it will not be serialized to JSON. 8293 */ 8294 defaultValue; 8295 resetOnCopyNode; 8296 constructor(key, stateValueConfig) { 8297 this.key = key; 8298 this.parse = stateValueConfig.parse.bind(stateValueConfig); 8299 this.unparse = (stateValueConfig.unparse || coerceToJSON).bind(stateValueConfig); 8300 this.isEqual = (stateValueConfig.isEqual || Object.is).bind(stateValueConfig); 8301 this.defaultValue = this.parse(void 0); 8302 this.resetOnCopyNode = stateValueConfig.resetOnCopyNode || false; 8303 } 8304 }; 8305 // @__NO_SIDE_EFFECTS__ 8306 function createState(key, valueConfig) { 8307 return new StateConfig(key, valueConfig); 8308 } 8309 function $getState(node, stateConfig, version = "latest") { 8310 const latestOrDirectNode = version === "latest" ? node.getLatest() : node; 8311 const state = latestOrDirectNode.__state; 8312 if (state) { 8313 $checkCollision(node, stateConfig, state); 8314 return state.getValue(stateConfig); 8315 } 8316 return stateConfig.defaultValue; 8317 } 8318 function $getStateChange(node, prevNode, stateConfig) { 8319 const value = $getState(node, stateConfig, "direct"); 8320 const prevValue = $getState(prevNode, stateConfig, "direct"); 8321 return stateConfig.isEqual(value, prevValue) ? null : [value, prevValue]; 8322 } 8323 function $setState(node, stateConfig, valueOrUpdater) { 8324 errorOnReadOnly(); 8325 let value; 8326 if (typeof valueOrUpdater === "function") { 8327 const latest = node.getLatest(); 8328 const prevValue = $getState(latest, stateConfig); 8329 value = valueOrUpdater(prevValue); 8330 if (stateConfig.isEqual(prevValue, value)) { 8331 return latest; 8332 } 8333 } else { 8334 value = valueOrUpdater; 8335 } 8336 const writable = node.getWritable(); 8337 const state = $getWritableNodeState(writable); 8338 $checkCollision(node, stateConfig, state); 8339 state.updateFromKnown(stateConfig, value); 8340 return writable; 8341 } 8342 function $checkCollision(node, stateConfig, state) { 8343 { 8344 const collision = state.sharedNodeState.sharedConfigMap.get(stateConfig.key); 8345 if (collision !== void 0 && collision !== stateConfig) { 8346 { 8347 formatDevErrorMessage(`$setState: State key collision ${JSON.stringify(stateConfig.key)} detected in ${node.constructor.name} node with type ${node.getType()} and key ${node.getKey()}. Only one StateConfig with a given key should be used on a node.`); 8348 } 8349 } 8350 } 8351 } 8352 function createSharedNodeState(nodeConfig) { 8353 const sharedConfigMap = /* @__PURE__ */ new Map(); 8354 const flatKeys = /* @__PURE__ */ new Set(); 8355 for (let klass = typeof nodeConfig === "function" ? nodeConfig : nodeConfig.replace; klass.prototype && klass.prototype.getType !== void 0; klass = Object.getPrototypeOf(klass)) { 8356 const { 8357 ownNodeConfig 8358 } = getStaticNodeConfig(klass); 8359 if (ownNodeConfig && ownNodeConfig.stateConfigs) { 8360 for (const requiredStateConfig of ownNodeConfig.stateConfigs) { 8361 let stateConfig; 8362 if ("stateConfig" in requiredStateConfig) { 8363 stateConfig = requiredStateConfig.stateConfig; 8364 if (requiredStateConfig.flat) { 8365 flatKeys.add(stateConfig.key); 8366 } 8367 } else { 8368 stateConfig = requiredStateConfig; 8369 } 8370 sharedConfigMap.set(stateConfig.key, stateConfig); 8371 } 8372 } 8373 } 8374 return { 8375 flatKeys, 8376 sharedConfigMap 8377 }; 8378 } 8379 var NodeState = class _NodeState { 8380 /** 8381 * @internal 8382 * 8383 * Track the (versioned) node that this NodeState was created for, to 8384 * facilitate copy-on-write for NodeState. When a LexicalNode is cloned, 8385 * it will *reference* the NodeState from its prevNode. From the nextNode 8386 * you can continue to read state without copying, but the first $setState 8387 * will trigger a copy of the prevNode's NodeState with the node property 8388 * updated. 8389 */ 8390 node; 8391 /** 8392 * @internal 8393 * 8394 * State that has already been parsed in a get state, so it is safe. (can be returned with 8395 * just a cast since the proof was given before). 8396 * 8397 * Note that it uses StateConfig, so in addition to (1) the CURRENT VALUE, it has access to 8398 * (2) the State key (3) the DEFAULT VALUE and (4) the PARSE FUNCTION 8399 */ 8400 knownState; 8401 /** 8402 * @internal 8403 * 8404 * A copy of serializedNode[NODE_STATE_KEY] that is made when JSON is 8405 * imported but has not been parsed yet. 8406 * 8407 * It stays here until a get state requires us to parse it, and since we 8408 * then know the value is safe we move it to knownState. 8409 * 8410 * Note that since only string keys are used here, we can only allow this 8411 * state to pass-through on export or on the next version since there is 8412 * no known value configuration. This pass-through is to support scenarios 8413 * where multiple versions of the editor code are working in parallel so 8414 * an old version of your code doesnt erase metadata that was 8415 * set by a newer version of your code. 8416 */ 8417 unknownState; 8418 /** 8419 * @internal 8420 * 8421 * This sharedNodeState is preserved across all instances of a given 8422 * node type in an editor and remains writable. It is how keys are resolved 8423 * to configuration. 8424 */ 8425 sharedNodeState; 8426 /** 8427 * @internal 8428 * 8429 * The count of known or unknown keys in this state, ignoring the 8430 * intersection between the two sets. 8431 */ 8432 size; 8433 /** 8434 * @internal 8435 */ 8436 constructor(node, sharedNodeState, unknownState = void 0, knownState = /* @__PURE__ */ new Map(), size2 = void 0) { 8437 this.node = node; 8438 this.sharedNodeState = sharedNodeState; 8439 this.unknownState = unknownState; 8440 this.knownState = knownState; 8441 const { 8442 sharedConfigMap 8443 } = this.sharedNodeState; 8444 const computedSize = size2 !== void 0 ? size2 : computeSize(sharedConfigMap, unknownState, knownState); 8445 { 8446 if (!(size2 === void 0 || computedSize === size2)) { 8447 formatDevErrorMessage(`NodeState: size != computedSize (${String(size2)} != ${String(computedSize)})`); 8448 } 8449 for (const stateConfig of knownState.keys()) { 8450 if (!sharedConfigMap.has(stateConfig.key)) { 8451 formatDevErrorMessage(`NodeState: sharedConfigMap missing knownState key ${stateConfig.key}`); 8452 } 8453 } 8454 } 8455 this.size = computedSize; 8456 } 8457 /** 8458 * @internal 8459 * 8460 * Get the value from knownState, or parse it from unknownState 8461 * if it contains the given key. 8462 * 8463 * Updates the sharedConfigMap when no known state is found. 8464 * Updates unknownState and knownState when an unknownState is parsed. 8465 */ 8466 getValue(stateConfig) { 8467 const known = this.knownState.get(stateConfig); 8468 if (known !== void 0) { 8469 return known; 8470 } 8471 this.sharedNodeState.sharedConfigMap.set(stateConfig.key, stateConfig); 8472 let parsed = stateConfig.defaultValue; 8473 if (this.unknownState && stateConfig.key in this.unknownState) { 8474 const jsonValue = this.unknownState[stateConfig.key]; 8475 if (jsonValue !== void 0) { 8476 parsed = stateConfig.parse(jsonValue); 8477 } 8478 this.updateFromKnown(stateConfig, parsed); 8479 } 8480 return parsed; 8481 } 8482 /** 8483 * @internal 8484 * 8485 * Used only for advanced use cases, such as collab. The intent here is to 8486 * allow you to diff states with a more stable interface than the properties 8487 * of this class. 8488 */ 8489 getInternalState() { 8490 return [this.unknownState, this.knownState]; 8491 } 8492 /** 8493 * Encode this NodeState to JSON in the format that its node expects. 8494 * This returns `{[NODE_STATE_KEY]?: UnknownStateRecord}` rather than 8495 * `UnknownStateRecord | undefined` so that we can support flattening 8496 * specific entries in the future when nodes can declare what 8497 * their required StateConfigs are. 8498 */ 8499 toJSON() { 8500 const state = { 8501 ...this.unknownState 8502 }; 8503 const flatState = {}; 8504 for (const [stateConfig, v3] of this.knownState) { 8505 if (stateConfig.isEqual(v3, stateConfig.defaultValue)) { 8506 delete state[stateConfig.key]; 8507 } else { 8508 state[stateConfig.key] = stateConfig.unparse(v3); 8509 } 8510 } 8511 for (const key of this.sharedNodeState.flatKeys) { 8512 if (key in state) { 8513 flatState[key] = state[key]; 8514 delete state[key]; 8515 } 8516 } 8517 if (undefinedIfEmpty(state)) { 8518 flatState[NODE_STATE_KEY] = state; 8519 } 8520 return flatState; 8521 } 8522 /** 8523 * @internal 8524 * 8525 * A NodeState is writable when the node to update matches 8526 * the node associated with the NodeState. This basically 8527 * mirrors how the EditorState NodeMap works, but in a 8528 * bottom-up organization rather than a top-down organization. 8529 * 8530 * This allows us to implement the same "copy on write" 8531 * pattern for state, without having the state version 8532 * update every time the node version changes (e.g. when 8533 * its parent or siblings change). 8534 * 8535 * @param node The node to associate with the state 8536 * @returns The next writable state 8537 */ 8538 getWritable(node) { 8539 if (this.node === node) { 8540 return this; 8541 } 8542 const { 8543 sharedNodeState, 8544 unknownState 8545 } = this; 8546 const nextKnownState = new Map(this.knownState); 8547 return new _NodeState(node, sharedNodeState, parseAndPruneNextUnknownState(sharedNodeState.sharedConfigMap, nextKnownState, unknownState), nextKnownState, this.size); 8548 } 8549 /** @internal */ 8550 resetOnCopyNode() { 8551 for (const stateConfig of this.knownState.keys()) { 8552 if (stateConfig.resetOnCopyNode) { 8553 this.knownState.set(stateConfig, stateConfig.defaultValue); 8554 } 8555 } 8556 return this; 8557 } 8558 /** @internal */ 8559 updateFromKnown(stateConfig, value) { 8560 const key = stateConfig.key; 8561 this.sharedNodeState.sharedConfigMap.set(key, stateConfig); 8562 const { 8563 knownState, 8564 unknownState 8565 } = this; 8566 if (!(knownState.has(stateConfig) || unknownState && key in unknownState)) { 8567 if (unknownState) { 8568 delete unknownState[key]; 8569 this.unknownState = undefinedIfEmpty(unknownState); 8570 } 8571 this.size++; 8572 } 8573 knownState.set(stateConfig, value); 8574 } 8575 /** 8576 * @internal 8577 * 8578 * This is intended for advanced use cases only, such 8579 * as collab or dev tools. 8580 * 8581 * Update a single key value pair from unknown state, 8582 * parsing it if the key is known to this node. This is 8583 * basically like updateFromJSON, but the effect is 8584 * isolated to a single entry. 8585 * 8586 * @param k The string key from an UnknownStateRecord 8587 * @param v The unknown value from an UnknownStateRecord 8588 */ 8589 updateFromUnknown(k2, v3) { 8590 const stateConfig = this.sharedNodeState.sharedConfigMap.get(k2); 8591 if (stateConfig) { 8592 this.updateFromKnown(stateConfig, stateConfig.parse(v3)); 8593 } else { 8594 this.unknownState = this.unknownState || {}; 8595 if (!(k2 in this.unknownState)) { 8596 this.size++; 8597 } 8598 this.unknownState[k2] = v3; 8599 } 8600 } 8601 /** 8602 * @internal 8603 * 8604 * Reset all existing state to default or empty values, 8605 * and perform any updates from the given unknownState. 8606 * 8607 * This is used when initializing a node's state from JSON, 8608 * or when resetting a node's state from JSON. 8609 * 8610 * @param unknownState The new state in serialized form 8611 */ 8612 updateFromJSON(unknownState) { 8613 const { 8614 knownState 8615 } = this; 8616 for (const stateConfig of knownState.keys()) { 8617 knownState.set(stateConfig, stateConfig.defaultValue); 8618 } 8619 this.size = knownState.size; 8620 this.unknownState = void 0; 8621 if (unknownState) { 8622 for (const [k2, v3] of Object.entries(unknownState)) { 8623 this.updateFromUnknown(k2, v3); 8624 } 8625 } 8626 } 8627 }; 8628 function $getWritableNodeState(node) { 8629 const writable = node.getWritable(); 8630 const state = writable.__state ? writable.__state.getWritable(writable) : new NodeState(writable, $getSharedNodeState(writable)); 8631 writable.__state = state; 8632 return state; 8633 } 8634 function $getSharedNodeState(node) { 8635 return node.__state ? node.__state.sharedNodeState : getRegisteredNodeOrThrow($getEditor(), node.getType()).sharedNodeState; 8636 } 8637 function $updateStateFromJSON(node, serialized) { 8638 const writable = node.getWritable(); 8639 const unknownState = serialized[NODE_STATE_KEY]; 8640 let parseState = unknownState; 8641 for (const k2 of $getSharedNodeState(writable).flatKeys) { 8642 if (k2 in serialized) { 8643 if (parseState === void 0 || parseState === unknownState) { 8644 parseState = { 8645 ...unknownState 8646 }; 8647 } 8648 parseState[k2] = serialized[k2]; 8649 } 8650 } 8651 if (writable.__state || parseState) { 8652 $getWritableNodeState(node).updateFromJSON(parseState); 8653 } 8654 return writable; 8655 } 8656 function nodeStatesAreEquivalent(a2, b3) { 8657 if (a2 === b3) { 8658 return true; 8659 } 8660 const keys = /* @__PURE__ */ new Set(); 8661 return !(a2 && hasUnequalMapEntry(keys, a2, b3) || b3 && hasUnequalMapEntry(keys, b3, a2) || a2 && hasUnequalRecordEntry(keys, a2, b3) || b3 && hasUnequalRecordEntry(keys, b3, a2)); 8662 } 8663 function computeSize(sharedConfigMap, unknownState, knownState) { 8664 let size2 = knownState.size; 8665 if (unknownState) { 8666 for (const k2 in unknownState) { 8667 const sharedConfig = sharedConfigMap.get(k2); 8668 if (!sharedConfig || !knownState.has(sharedConfig)) { 8669 size2++; 8670 } 8671 } 8672 } 8673 return size2; 8674 } 8675 function undefinedIfEmpty(obj) { 8676 if (obj) { 8677 for (const key in obj) { 8678 return obj; 8679 } 8680 } 8681 return void 0; 8682 } 8683 function coerceToJSON(v3) { 8684 return v3; 8685 } 8686 function parseAndPruneNextUnknownState(sharedConfigMap, nextKnownState, unknownState) { 8687 let nextUnknownState = void 0; 8688 if (unknownState) { 8689 for (const [k2, v3] of Object.entries(unknownState)) { 8690 const stateConfig = sharedConfigMap.get(k2); 8691 if (stateConfig) { 8692 if (!nextKnownState.has(stateConfig)) { 8693 nextKnownState.set(stateConfig, stateConfig.parse(v3)); 8694 } 8695 } else { 8696 nextUnknownState = nextUnknownState || {}; 8697 nextUnknownState[k2] = v3; 8698 } 8699 } 8700 } 8701 return nextUnknownState; 8702 } 8703 function hasUnequalMapEntry(keys, sourceState, otherState) { 8704 for (const [stateConfig, value] of sourceState.knownState) { 8705 if (keys.has(stateConfig.key)) { 8706 continue; 8707 } 8708 keys.add(stateConfig.key); 8709 const otherValue = otherState ? otherState.getValue(stateConfig) : stateConfig.defaultValue; 8710 if (otherValue !== value && !stateConfig.isEqual(otherValue, value)) { 8711 return true; 8712 } 8713 } 8714 return false; 8715 } 8716 function hasUnequalRecordEntry(keys, sourceState, otherState) { 8717 const { 8718 unknownState 8719 } = sourceState; 8720 const otherUnknownState = otherState ? otherState.unknownState : void 0; 8721 if (unknownState) { 8722 for (const [key, value] of Object.entries(unknownState)) { 8723 if (keys.has(key)) { 8724 continue; 8725 } 8726 keys.add(key); 8727 const otherValue = otherUnknownState ? otherUnknownState[key] : void 0; 8728 if (value !== otherValue) { 8729 return true; 8730 } 8731 } 8732 } 8733 return false; 8734 } 8735 function $cloneNodeState(from, to) { 8736 const state = from.__state; 8737 return state && state.node === from ? state.getWritable(to) : state; 8738 } 8739 function $canSimpleTextNodesBeMerged(node1, node2) { 8740 const node1Mode = node1.__mode; 8741 const node1Format = node1.__format; 8742 const node1Style = node1.__style; 8743 const node2Mode = node2.__mode; 8744 const node2Format = node2.__format; 8745 const node2Style = node2.__style; 8746 const node1State = node1.__state; 8747 const node2State = node2.__state; 8748 return (node1Mode === null || node1Mode === node2Mode) && (node1Format === null || node1Format === node2Format) && (node1Style === null || node1Style === node2Style) && (node1.__state === null || node1State === node2State || nodeStatesAreEquivalent(node1State, node2State)); 8749 } 8750 function $mergeTextNodes(node1, node2) { 8751 const writableNode1 = node1.mergeWithSibling(node2); 8752 const normalizedNodes = getActiveEditor()._normalizedNodes; 8753 normalizedNodes.add(node1.__key); 8754 normalizedNodes.add(node2.__key); 8755 return writableNode1; 8756 } 8757 function $normalizeTextNode(textNode) { 8758 let node = textNode; 8759 if (node.__text === "" && node.isSimpleText() && !node.isUnmergeable()) { 8760 node.remove(); 8761 return; 8762 } 8763 let previousNode; 8764 while ((previousNode = node.getPreviousSibling()) !== null && $isTextNode(previousNode) && previousNode.isSimpleText() && !previousNode.isUnmergeable()) { 8765 if (previousNode.__text === "") { 8766 previousNode.remove(); 8767 } else if ($canSimpleTextNodesBeMerged(previousNode, node)) { 8768 node = $mergeTextNodes(previousNode, node); 8769 break; 8770 } else { 8771 break; 8772 } 8773 } 8774 let nextNode; 8775 while ((nextNode = node.getNextSibling()) !== null && $isTextNode(nextNode) && nextNode.isSimpleText() && !nextNode.isUnmergeable()) { 8776 if (nextNode.__text === "") { 8777 nextNode.remove(); 8778 } else if ($canSimpleTextNodesBeMerged(node, nextNode)) { 8779 node = $mergeTextNodes(node, nextNode); 8780 break; 8781 } else { 8782 break; 8783 } 8784 } 8785 } 8786 function $normalizeSelection(selection) { 8787 $normalizePoint(selection.anchor); 8788 $normalizePoint(selection.focus); 8789 return selection; 8790 } 8791 function $normalizePoint(point) { 8792 while (point.type === "element") { 8793 const node = point.getNode(); 8794 const offset3 = point.offset; 8795 let nextNode; 8796 let nextOffsetAtEnd; 8797 if (offset3 === node.getChildrenSize()) { 8798 nextNode = node.getChildAtIndex(offset3 - 1); 8799 nextOffsetAtEnd = true; 8800 } else { 8801 nextNode = node.getChildAtIndex(offset3); 8802 nextOffsetAtEnd = false; 8803 } 8804 if ($isTextNode(nextNode)) { 8805 point.set(nextNode.__key, nextOffsetAtEnd ? nextNode.getTextContentSize() : 0, "text", true); 8806 break; 8807 } else if (!$isElementNode(nextNode)) { 8808 break; 8809 } 8810 point.set(nextNode.__key, nextOffsetAtEnd ? nextNode.getChildrenSize() : 0, "element", true); 8811 } 8812 } 8813 var subTreeTextContent = ""; 8814 var subTreeTextFormat = null; 8815 var subTreeTextStyle = null; 8816 var activeEditorConfig; 8817 var activeEditor$1; 8818 var activeEditorNodes; 8819 var treatAllNodesAsDirty = false; 8820 var activeEditorStateReadOnly = false; 8821 var activeMutationListeners; 8822 var activeDirtyElements; 8823 var activeDirtyLeaves; 8824 var activePrevNodeMap; 8825 var activeNextNodeMap; 8826 var activePrevKeyToDOMMap; 8827 var mutatedNodes; 8828 var activeEditorDOMRenderConfig; 8829 function $destroyNode(key, parentDOM) { 8830 const node = activePrevNodeMap.get(key); 8831 if (parentDOM !== null) { 8832 const dom = getPrevElementByKeyOrThrow(key); 8833 if (dom.parentNode === parentDOM) { 8834 parentDOM.removeChild(dom); 8835 } 8836 } 8837 if (!activeNextNodeMap.has(key)) { 8838 activeEditor$1._keyToDOMMap.delete(key); 8839 } 8840 if ($isElementNode(node)) { 8841 const children = $createChildrenArray(node, activePrevNodeMap); 8842 $destroyChildren(children, 0, children.length - 1, null); 8843 } 8844 if (node !== void 0) { 8845 setMutatedNode(mutatedNodes, activeEditorNodes, activeMutationListeners, node, "destroyed"); 8846 } 8847 } 8848 function $destroyChildren(children, _startIndex, endIndex, dom) { 8849 for (let startIndex = _startIndex; startIndex <= endIndex; ++startIndex) { 8850 const child = children[startIndex]; 8851 if (child !== void 0) { 8852 $destroyNode(child, dom); 8853 } 8854 } 8855 } 8856 function setTextAlign(domStyle, value) { 8857 domStyle.setProperty("text-align", value); 8858 } 8859 var DEFAULT_INDENT_VALUE = "40px"; 8860 function setElementIndent(dom, indent) { 8861 const indentClassName = activeEditorConfig.theme.indent; 8862 if (typeof indentClassName === "string") { 8863 const elementHasClassName = dom.classList.contains(indentClassName); 8864 if (indent > 0 && !elementHasClassName) { 8865 dom.classList.add(indentClassName); 8866 } else if (indent < 1 && elementHasClassName) { 8867 dom.classList.remove(indentClassName); 8868 } 8869 } 8870 if (indent === 0) { 8871 dom.style.setProperty("padding-inline-start", ""); 8872 return; 8873 } 8874 const indentationBaseValue = getComputedStyle(activeEditor$1._rootElement || dom).getPropertyValue("--lexical-indent-base-value") || DEFAULT_INDENT_VALUE; 8875 dom.style.setProperty("padding-inline-start", `calc(${indent} * ${indentationBaseValue})`); 8876 } 8877 function setElementFormat(dom, format) { 8878 const domStyle = dom.style; 8879 if (format === 0) { 8880 setTextAlign(domStyle, ""); 8881 } else if (format === IS_ALIGN_LEFT) { 8882 setTextAlign(domStyle, "left"); 8883 } else if (format === IS_ALIGN_CENTER) { 8884 setTextAlign(domStyle, "center"); 8885 } else if (format === IS_ALIGN_RIGHT) { 8886 setTextAlign(domStyle, "right"); 8887 } else if (format === IS_ALIGN_JUSTIFY) { 8888 setTextAlign(domStyle, "justify"); 8889 } else if (format === IS_ALIGN_START) { 8890 setTextAlign(domStyle, "start"); 8891 } else if (format === IS_ALIGN_END) { 8892 setTextAlign(domStyle, "end"); 8893 } 8894 } 8895 function $getReconciledDirection(node) { 8896 const direction = node.__dir; 8897 if (direction !== null) { 8898 return direction; 8899 } 8900 if ($isRootNode(node)) { 8901 return null; 8902 } 8903 const parent = node.getParentOrThrow(); 8904 if (!$isRootNode(parent) || parent.__dir !== null) { 8905 return null; 8906 } 8907 return "auto"; 8908 } 8909 function $setElementDirection(dom, node) { 8910 const direction = $getReconciledDirection(node); 8911 if (direction !== null) { 8912 dom.dir = direction; 8913 } else { 8914 dom.removeAttribute("dir"); 8915 } 8916 } 8917 function $createNode(key, slot) { 8918 const node = activeNextNodeMap.get(key); 8919 if (node === void 0) { 8920 { 8921 formatDevErrorMessage(`createNode: node does not exist in nodeMap`); 8922 } 8923 } 8924 const dom = activeEditorDOMRenderConfig.$createDOM(node, activeEditor$1); 8925 storeDOMWithKey(key, dom, activeEditor$1); 8926 if ($isTextNode(node)) { 8927 dom.setAttribute("data-lexical-text", "true"); 8928 } else if ($isDecoratorNode(node)) { 8929 dom.setAttribute("data-lexical-decorator", "true"); 8930 } 8931 if ($isElementNode(node)) { 8932 const indent = node.__indent; 8933 const childrenSize = node.__size; 8934 $setElementDirection(dom, node); 8935 if (indent !== 0) { 8936 setElementIndent(dom, indent); 8937 } 8938 if (childrenSize !== 0) { 8939 const endIndex = childrenSize - 1; 8940 const children = $createChildrenArray(node, activeNextNodeMap); 8941 $createChildren(children, node, 0, endIndex, activeEditorDOMRenderConfig.$getDOMSlot(node, dom, activeEditor$1)); 8942 } 8943 const format = node.__format; 8944 if (format !== 0) { 8945 setElementFormat(dom, format); 8946 } 8947 if (!node.isInline()) { 8948 $reconcileElementTerminatingLineBreak(null, node, dom); 8949 } 8950 } else { 8951 const text2 = node.getTextContent(); 8952 if ($isDecoratorNode(node)) { 8953 const decorator = node.decorate(activeEditor$1, activeEditorConfig); 8954 if (decorator !== null) { 8955 reconcileDecorator(key, decorator); 8956 } 8957 dom.contentEditable = "false"; 8958 } 8959 subTreeTextContent += text2; 8960 } 8961 if (slot !== null) { 8962 slot.insertChild(dom); 8963 } 8964 activeEditorDOMRenderConfig.$decorateDOM(node, null, dom, activeEditor$1); 8965 { 8966 Object.freeze(node); 8967 } 8968 setMutatedNode(mutatedNodes, activeEditorNodes, activeMutationListeners, node, "created"); 8969 return dom; 8970 } 8971 function $createChildren(children, element, _startIndex, endIndex, slot) { 8972 const previousSubTreeTextContent = subTreeTextContent; 8973 subTreeTextContent = ""; 8974 let startIndex = _startIndex; 8975 for (; startIndex <= endIndex; ++startIndex) { 8976 $createNode(children[startIndex], slot); 8977 const node = activeNextNodeMap.get(children[startIndex]); 8978 if (node !== null && $isTextNode(node)) { 8979 if (subTreeTextFormat === null) { 8980 subTreeTextFormat = node.getFormat(); 8981 subTreeTextStyle = node.getStyle(); 8982 } 8983 } else if ( 8984 // inline $textContentRequiresDoubleLinebreakAtEnd 8985 $isElementNode(node) && startIndex < endIndex && !node.isInline() 8986 ) { 8987 subTreeTextContent += DOUBLE_LINE_BREAK; 8988 } 8989 } 8990 const dom = slot.element; 8991 dom.__lexicalTextContent = subTreeTextContent; 8992 subTreeTextContent = previousSubTreeTextContent + subTreeTextContent; 8993 } 8994 function isLastChildLineBreakOrDecorator(element, nodeMap) { 8995 if (element) { 8996 const lastKey = element.__last; 8997 if (lastKey) { 8998 const node = nodeMap.get(lastKey); 8999 if (node) { 9000 return $isLineBreakNode(node) ? "line-break" : $isDecoratorNode(node) && node.isInline() ? "decorator" : null; 9001 } 9002 } 9003 return "empty"; 9004 } 9005 return null; 9006 } 9007 function $reconcileElementTerminatingLineBreak(prevElement, nextElement, dom) { 9008 const prevLineBreak = isLastChildLineBreakOrDecorator(prevElement, activePrevNodeMap); 9009 const nextLineBreak = isLastChildLineBreakOrDecorator(nextElement, activeNextNodeMap); 9010 if (prevLineBreak !== nextLineBreak) { 9011 activeEditorDOMRenderConfig.$getDOMSlot(nextElement, dom, activeEditor$1).setManagedLineBreak(nextLineBreak); 9012 } 9013 } 9014 function reconcileTextFormat(element) { 9015 if (subTreeTextFormat != null && subTreeTextFormat !== element.__textFormat && !activeEditorStateReadOnly) { 9016 element.setTextFormat(subTreeTextFormat); 9017 } 9018 } 9019 function reconcileTextStyle(element) { 9020 if (subTreeTextStyle != null && subTreeTextStyle !== element.__textStyle && !activeEditorStateReadOnly) { 9021 element.setTextStyle(subTreeTextStyle); 9022 } 9023 } 9024 function $reconcileChildrenWithDirection(prevElement, nextElement, dom) { 9025 subTreeTextFormat = null; 9026 subTreeTextStyle = null; 9027 $reconcileChildren(prevElement, nextElement, activeEditorDOMRenderConfig.$getDOMSlot(nextElement, dom, activeEditor$1)); 9028 reconcileTextFormat(nextElement); 9029 reconcileTextStyle(nextElement); 9030 } 9031 function $reconcileChildren(prevElement, nextElement, slot) { 9032 const previousSubTreeTextContent = subTreeTextContent; 9033 const prevChildrenSize = prevElement.__size; 9034 const nextChildrenSize = nextElement.__size; 9035 subTreeTextContent = ""; 9036 const dom = slot.element; 9037 if (prevChildrenSize === 1 && nextChildrenSize === 1) { 9038 const prevFirstChildKey = prevElement.__first; 9039 const nextFirstChildKey = nextElement.__first; 9040 if (prevFirstChildKey === nextFirstChildKey) { 9041 $reconcileNode(prevFirstChildKey, dom); 9042 } else { 9043 const lastDOM = getPrevElementByKeyOrThrow(prevFirstChildKey); 9044 const replacementDOM = $createNode(nextFirstChildKey, null); 9045 try { 9046 dom.replaceChild(replacementDOM, lastDOM); 9047 } catch (error) { 9048 if (typeof error === "object" && error != null) { 9049 const msg = `${error.toString()} Parent: ${dom.tagName}, new child: {tag: ${replacementDOM.tagName} key: ${nextFirstChildKey}}, old child: {tag: ${lastDOM.tagName}, key: ${prevFirstChildKey}}.`; 9050 throw new Error(msg); 9051 } else { 9052 throw error; 9053 } 9054 } 9055 $destroyNode(prevFirstChildKey, null); 9056 } 9057 const nextChildNode = activeNextNodeMap.get(nextFirstChildKey); 9058 if ($isTextNode(nextChildNode)) { 9059 if (subTreeTextFormat === null) { 9060 subTreeTextFormat = nextChildNode.getFormat(); 9061 subTreeTextStyle = nextChildNode.getStyle(); 9062 } 9063 } 9064 } else { 9065 const prevChildren = $createChildrenArray(prevElement, activePrevNodeMap); 9066 const nextChildren = $createChildrenArray(nextElement, activeNextNodeMap); 9067 if (!(prevChildren.length === prevChildrenSize)) { 9068 formatDevErrorMessage(`$reconcileChildren: prevChildren.length !== prevChildrenSize`); 9069 } 9070 if (!(nextChildren.length === nextChildrenSize)) { 9071 formatDevErrorMessage(`$reconcileChildren: nextChildren.length !== nextChildrenSize`); 9072 } 9073 if (prevChildrenSize === 0) { 9074 if (nextChildrenSize !== 0) { 9075 $createChildren(nextChildren, nextElement, 0, nextChildrenSize - 1, slot); 9076 } 9077 } else if (nextChildrenSize === 0) { 9078 if (prevChildrenSize !== 0) { 9079 const canUseFastPath = slot.after == null && slot.before == null && slot.element.__lexicalLineBreak == null; 9080 $destroyChildren(prevChildren, 0, prevChildrenSize - 1, canUseFastPath ? null : dom); 9081 if (canUseFastPath) { 9082 dom.textContent = ""; 9083 } 9084 } 9085 } else { 9086 $reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChildrenSize, nextChildrenSize, slot); 9087 } 9088 } 9089 dom.__lexicalTextContent = subTreeTextContent; 9090 subTreeTextContent = previousSubTreeTextContent + subTreeTextContent; 9091 } 9092 function $reconcileNode(key, parentDOM) { 9093 const prevNode = activePrevNodeMap.get(key); 9094 let nextNode = activeNextNodeMap.get(key); 9095 if (prevNode === void 0 || nextNode === void 0) { 9096 { 9097 formatDevErrorMessage(`reconcileNode: prevNode or nextNode does not exist in nodeMap`); 9098 } 9099 } 9100 const isDirty = treatAllNodesAsDirty || activeDirtyLeaves.has(key) || activeDirtyElements.has(key); 9101 const dom = getElementByKeyOrThrow(activeEditor$1, key); 9102 if (prevNode === nextNode && !isDirty) { 9103 let text2; 9104 if ($isElementNode(prevNode)) { 9105 const previousSubTreeTextContent = dom.__lexicalTextContent; 9106 if (typeof previousSubTreeTextContent === "string") { 9107 text2 = previousSubTreeTextContent; 9108 } else { 9109 text2 = prevNode.getTextContent(); 9110 dom.__lexicalTextContent = text2; 9111 } 9112 } else { 9113 text2 = prevNode.getTextContent(); 9114 } 9115 subTreeTextContent += text2; 9116 return dom; 9117 } 9118 if (prevNode !== nextNode && isDirty) { 9119 setMutatedNode(mutatedNodes, activeEditorNodes, activeMutationListeners, nextNode, "updated"); 9120 } 9121 if (activeEditorDOMRenderConfig.$updateDOM(nextNode, prevNode, dom, activeEditor$1)) { 9122 const replacementDOM = $createNode(key, null); 9123 if (parentDOM === null) { 9124 { 9125 formatDevErrorMessage(`reconcileNode: parentDOM is null`); 9126 } 9127 } 9128 parentDOM.replaceChild(replacementDOM, dom); 9129 $destroyNode(key, null); 9130 return replacementDOM; 9131 } 9132 if ($isElementNode(prevNode)) { 9133 if (!$isElementNode(nextNode)) { 9134 formatDevErrorMessage(`Node with key ${key} changed from ElementNode to !ElementNode`); 9135 } 9136 const nextIndent = nextNode.__indent; 9137 if (treatAllNodesAsDirty || nextIndent !== prevNode.__indent) { 9138 setElementIndent(dom, nextIndent); 9139 } 9140 const nextFormat = nextNode.__format; 9141 if (treatAllNodesAsDirty || nextFormat !== prevNode.__format) { 9142 setElementFormat(dom, nextFormat); 9143 } 9144 if (isDirty) { 9145 $reconcileChildrenWithDirection(prevNode, nextNode, dom); 9146 if (!$isRootNode(nextNode) && !nextNode.isInline()) { 9147 $reconcileElementTerminatingLineBreak(prevNode, nextNode, dom); 9148 } 9149 } else { 9150 const previousSubTreeTextContent = dom.__lexicalTextContent; 9151 let text2; 9152 if (typeof previousSubTreeTextContent === "string") { 9153 text2 = previousSubTreeTextContent; 9154 } else { 9155 text2 = prevNode.getTextContent(); 9156 dom.__lexicalTextContent = text2; 9157 } 9158 subTreeTextContent += text2; 9159 } 9160 if (treatAllNodesAsDirty || nextNode.__dir !== prevNode.__dir) { 9161 $setElementDirection(dom, nextNode); 9162 if ( 9163 // Root node direction changing from set to unset (or vice versa) 9164 // changes how children's direction is calculated. 9165 $isRootNode(nextNode) && // Can skip if all children already reconciled. 9166 !treatAllNodesAsDirty 9167 ) { 9168 for (const child of nextNode.getChildren()) { 9169 if ($isElementNode(child)) { 9170 const childDom = getElementByKeyOrThrow(activeEditor$1, child.getKey()); 9171 $setElementDirection(childDom, child); 9172 } 9173 } 9174 } 9175 } 9176 } else { 9177 const text2 = nextNode.getTextContent(); 9178 if ($isDecoratorNode(nextNode)) { 9179 const decorator = nextNode.decorate(activeEditor$1, activeEditorConfig); 9180 if (decorator !== null) { 9181 reconcileDecorator(key, decorator); 9182 } 9183 } 9184 subTreeTextContent += text2; 9185 } 9186 if (!activeEditorStateReadOnly && $isRootNode(nextNode) && nextNode.__cachedText !== subTreeTextContent) { 9187 const nextRootNode = nextNode.getWritable(); 9188 nextRootNode.__cachedText = subTreeTextContent; 9189 nextNode = nextRootNode; 9190 } 9191 activeEditorDOMRenderConfig.$decorateDOM(nextNode, prevNode, dom, activeEditor$1); 9192 { 9193 Object.freeze(nextNode); 9194 } 9195 return dom; 9196 } 9197 function reconcileDecorator(key, decorator) { 9198 let pendingDecorators = activeEditor$1._pendingDecorators; 9199 const currentDecorators = activeEditor$1._decorators; 9200 if (pendingDecorators === null) { 9201 if (currentDecorators[key] === decorator) { 9202 return; 9203 } 9204 pendingDecorators = cloneDecorators(activeEditor$1); 9205 } 9206 pendingDecorators[key] = decorator; 9207 } 9208 function getNextSibling(element) { 9209 let nextSibling = element.nextSibling; 9210 if (nextSibling !== null && nextSibling === activeEditor$1._blockCursorElement) { 9211 nextSibling = nextSibling.nextSibling; 9212 } 9213 return nextSibling; 9214 } 9215 function childrenSet(children, start3) { 9216 const s2 = /* @__PURE__ */ new Set(); 9217 for (let i2 = start3; i2 < children.length; i2++) { 9218 s2.add(children[i2]); 9219 } 9220 return s2; 9221 } 9222 function $reconcileNodeChildren(nextElement, prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, slot) { 9223 const prevEndIndex = prevChildrenLength - 1; 9224 const nextEndIndex = nextChildrenLength - 1; 9225 let prevChildrenSet; 9226 let nextChildrenSet; 9227 let siblingDOM = slot.getFirstChild(); 9228 let prevIndex = 0; 9229 let nextIndex = 0; 9230 while (prevIndex <= prevEndIndex && nextIndex <= nextEndIndex) { 9231 const prevKey = prevChildren[prevIndex]; 9232 const nextKey = nextChildren[nextIndex]; 9233 if (prevKey === nextKey) { 9234 siblingDOM = getNextSibling($reconcileNode(nextKey, slot.element)); 9235 prevIndex++; 9236 nextIndex++; 9237 } else { 9238 if (nextChildrenSet === void 0) { 9239 nextChildrenSet = childrenSet(nextChildren, nextIndex); 9240 } 9241 if (prevChildrenSet === void 0) { 9242 prevChildrenSet = childrenSet(prevChildren, prevIndex); 9243 } else if (!prevChildrenSet.has(prevKey)) { 9244 prevIndex++; 9245 continue; 9246 } 9247 if (!nextChildrenSet.has(prevKey)) { 9248 siblingDOM = getNextSibling(getPrevElementByKeyOrThrow(prevKey)); 9249 $destroyNode(prevKey, slot.element); 9250 prevIndex++; 9251 prevChildrenSet.delete(prevKey); 9252 continue; 9253 } 9254 if (!prevChildrenSet.has(nextKey)) { 9255 $createNode(nextKey, slot.withBefore(siblingDOM)); 9256 nextIndex++; 9257 } else { 9258 const childDOM = getElementByKeyOrThrow(activeEditor$1, nextKey); 9259 if (childDOM !== siblingDOM) { 9260 slot.withBefore(siblingDOM).insertChild(childDOM); 9261 } 9262 siblingDOM = getNextSibling($reconcileNode(nextKey, slot.element)); 9263 prevIndex++; 9264 nextIndex++; 9265 } 9266 } 9267 const node = activeNextNodeMap.get(nextKey); 9268 if (node !== null && $isTextNode(node)) { 9269 if (subTreeTextFormat === null) { 9270 subTreeTextFormat = node.getFormat(); 9271 subTreeTextStyle = node.getStyle(); 9272 } 9273 } else if ( 9274 // inline $textContentRequiresDoubleLinebreakAtEnd 9275 $isElementNode(node) && nextIndex <= nextEndIndex && !node.isInline() 9276 ) { 9277 subTreeTextContent += DOUBLE_LINE_BREAK; 9278 } 9279 } 9280 const appendNewChildren = prevIndex > prevEndIndex; 9281 const removeOldChildren = nextIndex > nextEndIndex; 9282 if (appendNewChildren && !removeOldChildren) { 9283 const previousNode = nextChildren[nextEndIndex + 1]; 9284 const insertDOM = previousNode === void 0 ? null : activeEditor$1.getElementByKey(previousNode); 9285 $createChildren(nextChildren, nextElement, nextIndex, nextEndIndex, slot.withBefore(insertDOM)); 9286 } else if (removeOldChildren && !appendNewChildren) { 9287 $destroyChildren(prevChildren, prevIndex, prevEndIndex, slot.element); 9288 } 9289 } 9290 function $reconcileRoot(prevEditorState, nextEditorState, editor, dirtyType, dirtyElements, dirtyLeaves) { 9291 subTreeTextContent = ""; 9292 treatAllNodesAsDirty = dirtyType === FULL_RECONCILE; 9293 activeEditor$1 = editor; 9294 activeEditorConfig = editor._config; 9295 activeEditorDOMRenderConfig = editor._config.dom || DEFAULT_EDITOR_DOM_CONFIG; 9296 activeEditorNodes = editor._nodes; 9297 activeMutationListeners = activeEditor$1._listeners.mutation; 9298 activeDirtyElements = dirtyElements; 9299 activeDirtyLeaves = dirtyLeaves; 9300 activePrevNodeMap = prevEditorState._nodeMap; 9301 activeNextNodeMap = nextEditorState._nodeMap; 9302 activeEditorStateReadOnly = nextEditorState._readOnly; 9303 activePrevKeyToDOMMap = new Map(editor._keyToDOMMap); 9304 const currentMutatedNodes = /* @__PURE__ */ new Map(); 9305 mutatedNodes = currentMutatedNodes; 9306 $reconcileNode("root", null); 9307 activeEditor$1 = void 0; 9308 activeEditorNodes = void 0; 9309 activeDirtyElements = void 0; 9310 activeDirtyLeaves = void 0; 9311 activePrevNodeMap = void 0; 9312 activeNextNodeMap = void 0; 9313 activeEditorConfig = void 0; 9314 activePrevKeyToDOMMap = void 0; 9315 mutatedNodes = void 0; 9316 activeEditorDOMRenderConfig = DEFAULT_EDITOR_DOM_CONFIG; 9317 return currentMutatedNodes; 9318 } 9319 function storeDOMWithKey(key, dom, editor) { 9320 const keyToDOMMap = editor._keyToDOMMap; 9321 setNodeKeyOnDOMNode(dom, editor, key); 9322 keyToDOMMap.set(key, dom); 9323 } 9324 function getPrevElementByKeyOrThrow(key) { 9325 const element = activePrevKeyToDOMMap.get(key); 9326 if (element === void 0) { 9327 { 9328 formatDevErrorMessage(`Reconciliation: could not find DOM element for node key ${key}`); 9329 } 9330 } 9331 return element; 9332 } 9333 function warnOnlyOnce(message) { 9334 { 9335 let run = false; 9336 return () => { 9337 if (!run) { 9338 console.warn(message); 9339 } 9340 run = true; 9341 }; 9342 } 9343 } 9344 // @__NO_SIDE_EFFECTS__ 9345 function createCommand(type) { 9346 return { 9347 type 9348 }; 9349 } 9350 var SELECTION_CHANGE_COMMAND = /* @__PURE__ */ createCommand("SELECTION_CHANGE_COMMAND"); 9351 var SELECTION_INSERT_CLIPBOARD_NODES_COMMAND = /* @__PURE__ */ createCommand("SELECTION_INSERT_CLIPBOARD_NODES_COMMAND"); 9352 var CLICK_COMMAND = /* @__PURE__ */ createCommand("CLICK_COMMAND"); 9353 var BEFORE_INPUT_COMMAND = /* @__PURE__ */ createCommand("BEFORE_INPUT_COMMAND"); 9354 var INPUT_COMMAND = /* @__PURE__ */ createCommand("INPUT_COMMAND"); 9355 var COMPOSITION_START_COMMAND = /* @__PURE__ */ createCommand("COMPOSITION_START_COMMAND"); 9356 var COMPOSITION_END_COMMAND = /* @__PURE__ */ createCommand("COMPOSITION_END_COMMAND"); 9357 var DELETE_CHARACTER_COMMAND = /* @__PURE__ */ createCommand("DELETE_CHARACTER_COMMAND"); 9358 var INSERT_LINE_BREAK_COMMAND = /* @__PURE__ */ createCommand("INSERT_LINE_BREAK_COMMAND"); 9359 var INSERT_PARAGRAPH_COMMAND = /* @__PURE__ */ createCommand("INSERT_PARAGRAPH_COMMAND"); 9360 var CONTROLLED_TEXT_INSERTION_COMMAND = /* @__PURE__ */ createCommand("CONTROLLED_TEXT_INSERTION_COMMAND"); 9361 var PASTE_COMMAND = /* @__PURE__ */ createCommand("PASTE_COMMAND"); 9362 var REMOVE_TEXT_COMMAND = /* @__PURE__ */ createCommand("REMOVE_TEXT_COMMAND"); 9363 var DELETE_WORD_COMMAND = /* @__PURE__ */ createCommand("DELETE_WORD_COMMAND"); 9364 var DELETE_LINE_COMMAND = /* @__PURE__ */ createCommand("DELETE_LINE_COMMAND"); 9365 var FORMAT_TEXT_COMMAND = /* @__PURE__ */ createCommand("FORMAT_TEXT_COMMAND"); 9366 var UNDO_COMMAND = /* @__PURE__ */ createCommand("UNDO_COMMAND"); 9367 var REDO_COMMAND = /* @__PURE__ */ createCommand("REDO_COMMAND"); 9368 var KEY_DOWN_COMMAND = /* @__PURE__ */ createCommand("KEYDOWN_COMMAND"); 9369 var KEY_ARROW_RIGHT_COMMAND = /* @__PURE__ */ createCommand("KEY_ARROW_RIGHT_COMMAND"); 9370 var MOVE_TO_END = /* @__PURE__ */ createCommand("MOVE_TO_END"); 9371 var KEY_ARROW_LEFT_COMMAND = /* @__PURE__ */ createCommand("KEY_ARROW_LEFT_COMMAND"); 9372 var MOVE_TO_START = /* @__PURE__ */ createCommand("MOVE_TO_START"); 9373 var KEY_ARROW_UP_COMMAND = /* @__PURE__ */ createCommand("KEY_ARROW_UP_COMMAND"); 9374 var KEY_ARROW_DOWN_COMMAND = /* @__PURE__ */ createCommand("KEY_ARROW_DOWN_COMMAND"); 9375 var KEY_ENTER_COMMAND = /* @__PURE__ */ createCommand("KEY_ENTER_COMMAND"); 9376 var KEY_SPACE_COMMAND = /* @__PURE__ */ createCommand("KEY_SPACE_COMMAND"); 9377 var KEY_BACKSPACE_COMMAND = /* @__PURE__ */ createCommand("KEY_BACKSPACE_COMMAND"); 9378 var KEY_ESCAPE_COMMAND = /* @__PURE__ */ createCommand("KEY_ESCAPE_COMMAND"); 9379 var KEY_DELETE_COMMAND = /* @__PURE__ */ createCommand("KEY_DELETE_COMMAND"); 9380 var KEY_TAB_COMMAND = /* @__PURE__ */ createCommand("KEY_TAB_COMMAND"); 9381 var INSERT_TAB_COMMAND = /* @__PURE__ */ createCommand("INSERT_TAB_COMMAND"); 9382 var INDENT_CONTENT_COMMAND = /* @__PURE__ */ createCommand("INDENT_CONTENT_COMMAND"); 9383 var OUTDENT_CONTENT_COMMAND = /* @__PURE__ */ createCommand("OUTDENT_CONTENT_COMMAND"); 9384 var DROP_COMMAND = /* @__PURE__ */ createCommand("DROP_COMMAND"); 9385 var FORMAT_ELEMENT_COMMAND = /* @__PURE__ */ createCommand("FORMAT_ELEMENT_COMMAND"); 9386 var DRAGSTART_COMMAND = /* @__PURE__ */ createCommand("DRAGSTART_COMMAND"); 9387 var DRAGOVER_COMMAND = /* @__PURE__ */ createCommand("DRAGOVER_COMMAND"); 9388 var DRAGEND_COMMAND = /* @__PURE__ */ createCommand("DRAGEND_COMMAND"); 9389 var COPY_COMMAND = /* @__PURE__ */ createCommand("COPY_COMMAND"); 9390 var CUT_COMMAND = /* @__PURE__ */ createCommand("CUT_COMMAND"); 9391 var SELECT_ALL_COMMAND = /* @__PURE__ */ createCommand("SELECT_ALL_COMMAND"); 9392 var CLEAR_EDITOR_COMMAND = /* @__PURE__ */ createCommand("CLEAR_EDITOR_COMMAND"); 9393 var CLEAR_HISTORY_COMMAND = /* @__PURE__ */ createCommand("CLEAR_HISTORY_COMMAND"); 9394 var CAN_REDO_COMMAND = /* @__PURE__ */ createCommand("CAN_REDO_COMMAND"); 9395 var CAN_UNDO_COMMAND = /* @__PURE__ */ createCommand("CAN_UNDO_COMMAND"); 9396 var FOCUS_COMMAND = /* @__PURE__ */ createCommand("FOCUS_COMMAND"); 9397 var BLUR_COMMAND = /* @__PURE__ */ createCommand("BLUR_COMMAND"); 9398 var KEY_MODIFIER_COMMAND = /* @__PURE__ */ createCommand("KEY_MODIFIER_COMMAND"); 9399 var PASS_THROUGH_COMMAND = Object.freeze({}); 9400 var ANDROID_COMPOSITION_LATENCY = 30; 9401 var rootElementEvents = [["keydown", onKeyDown], ["pointerdown", onPointerDown], ["compositionstart", onCompositionStart], ["compositionend", onCompositionEnd], ["input", onInput], ["click", onClick], ["cut", PASS_THROUGH_COMMAND], ["copy", PASS_THROUGH_COMMAND], ["dragstart", PASS_THROUGH_COMMAND], ["dragover", PASS_THROUGH_COMMAND], ["dragend", PASS_THROUGH_COMMAND], ["paste", PASS_THROUGH_COMMAND], ["focus", PASS_THROUGH_COMMAND], ["blur", PASS_THROUGH_COMMAND], ["drop", PASS_THROUGH_COMMAND]]; 9402 if (CAN_USE_BEFORE_INPUT) { 9403 rootElementEvents.push(["beforeinput", (event, editor) => onBeforeInput(event, editor)]); 9404 } 9405 var lastKeyDownTimeStamp = 0; 9406 var lastKeyCode = null; 9407 var lastBeforeInputInsertTextTimeStamp = 0; 9408 var unprocessedBeforeInputData = null; 9409 var rootElementToDocument = /* @__PURE__ */ new WeakMap(); 9410 var rootElementsRegistered = /* @__PURE__ */ new WeakMap(); 9411 var isSelectionChangeFromDOMUpdate = false; 9412 var isSelectionChangeFromMouseDown = false; 9413 var isInsertLineBreak = false; 9414 var isFirefoxEndingComposition = false; 9415 var isSafariEndingComposition = false; 9416 var safariEndCompositionEventData = ""; 9417 var postDeleteSelectionToRestore = null; 9418 var collapsedSelectionFormat = [0, "", 0, "root", 0]; 9419 function $shouldPreventDefaultAndInsertText(selection, domTargetRange, text2, timeStamp, isBeforeInput) { 9420 const anchor = selection.anchor; 9421 const focus = selection.focus; 9422 const anchorNode = anchor.getNode(); 9423 const editor = getActiveEditor(); 9424 const domSelection = getDOMSelection(getWindow(editor)); 9425 const domAnchorNode = domSelection !== null ? domSelection.anchorNode : null; 9426 const anchorKey = anchor.key; 9427 const backingAnchorElement = editor.getElementByKey(anchorKey); 9428 const textLength = text2.length; 9429 return anchorKey !== focus.key || // If we're working with a non-text node. 9430 !$isTextNode(anchorNode) || // If we are replacing a range with a single character or grapheme, and not composing. 9431 (!isBeforeInput && (!CAN_USE_BEFORE_INPUT || // We check to see if there has been 9432 // a recent beforeinput event for "textInput". If there has been one in the last 9433 // 50ms then we proceed as normal. However, if there is not, then this is likely 9434 // a dangling `input` event caused by execCommand('insertText'). 9435 lastBeforeInputInsertTextTimeStamp < timeStamp + 50) || anchorNode.isDirty() && textLength < 2 || // TODO consider if there are other scenarios when multiple code units 9436 // should be addressed here 9437 doesContainSurrogatePair(text2)) && anchor.offset !== focus.offset && !anchorNode.isComposing() || // Any non standard text node. 9438 $isTokenOrSegmented(anchorNode) || // If the text length is more than a single character and we're either 9439 // dealing with this in "beforeinput" or where the node has already recently 9440 // been changed (thus is dirty). 9441 anchorNode.isDirty() && textLength > 1 || // If the DOM selection element is not the same as the backing node during beforeinput. 9442 (isBeforeInput || !CAN_USE_BEFORE_INPUT) && backingAnchorElement !== null && !anchorNode.isComposing() && domAnchorNode !== getDOMTextNode(backingAnchorElement) || // If TargetRange is not the same as the DOM selection; browser trying to edit random parts 9443 // of the editor. 9444 domSelection !== null && domTargetRange !== null && (!domTargetRange.collapsed || domTargetRange.startContainer !== domSelection.anchorNode || domTargetRange.startOffset !== domSelection.anchorOffset) || // Check if we're changing from bold to italics, or some other format. 9445 !anchorNode.isComposing() && (anchorNode.getFormat() !== selection.format || anchorNode.getStyle() !== selection.style) || // One last set of heuristics to check against. 9446 $shouldInsertTextAfterOrBeforeTextNode(selection, anchorNode); 9447 } 9448 function shouldSkipSelectionChange(domNode, offset3) { 9449 return isDOMTextNode(domNode) && domNode.nodeValue !== null && offset3 !== 0 && offset3 !== domNode.nodeValue.length; 9450 } 9451 function onSelectionChange(domSelection, editor, isActive) { 9452 const { 9453 anchorNode: anchorDOM, 9454 anchorOffset, 9455 focusNode: focusDOM, 9456 focusOffset 9457 } = domSelection; 9458 if (isSelectionChangeFromDOMUpdate) { 9459 isSelectionChangeFromDOMUpdate = false; 9460 if (shouldSkipSelectionChange(anchorDOM, anchorOffset) && shouldSkipSelectionChange(focusDOM, focusOffset) && !postDeleteSelectionToRestore) { 9461 return; 9462 } 9463 } 9464 updateEditorSync(editor, () => { 9465 if (!isActive) { 9466 $setSelection(null); 9467 return; 9468 } 9469 if (!isSelectionWithinEditor(editor, anchorDOM, focusDOM)) { 9470 return; 9471 } 9472 let selection = $getSelection(); 9473 if (postDeleteSelectionToRestore && $isRangeSelection(selection) && selection.isCollapsed()) { 9474 const curAnchor = selection.anchor; 9475 const prevAnchor = postDeleteSelectionToRestore.anchor; 9476 if ( 9477 // Rightward shift in same node 9478 curAnchor.key === prevAnchor.key && curAnchor.offset === prevAnchor.offset + 1 || // Or rightward shift into sibling node 9479 curAnchor.offset === 1 && prevAnchor.getNode().is(curAnchor.getNode().getPreviousSibling()) 9480 ) { 9481 selection = postDeleteSelectionToRestore.clone(); 9482 $setSelection(selection); 9483 } 9484 } 9485 postDeleteSelectionToRestore = null; 9486 if ($isRangeSelection(selection)) { 9487 const anchor = selection.anchor; 9488 const anchorNode = anchor.getNode(); 9489 if (selection.isCollapsed()) { 9490 if (domSelection.type === "Range" && domSelection.anchorNode === domSelection.focusNode) { 9491 selection.dirty = true; 9492 } 9493 const windowEvent = getWindow(editor).event; 9494 const currentTimeStamp = windowEvent ? windowEvent.timeStamp : performance.now(); 9495 const [lastFormat, lastStyle, lastOffset, lastKey, timeStamp] = collapsedSelectionFormat; 9496 const root = $getRoot(); 9497 const isRootTextContentEmpty = editor.isComposing() === false && root.getTextContent() === ""; 9498 if (currentTimeStamp < timeStamp + 200 && anchor.offset === lastOffset && anchor.key === lastKey) { 9499 $updateSelectionFormatStyle(selection, lastFormat, lastStyle); 9500 } else { 9501 if (anchor.type === "text") { 9502 if (!$isTextNode(anchorNode)) { 9503 formatDevErrorMessage(`Point.getNode() must return TextNode when type is text`); 9504 } 9505 $updateSelectionFormatStyleFromTextNode(selection, anchorNode); 9506 } else if (anchor.type === "element" && !isRootTextContentEmpty) { 9507 if (!$isElementNode(anchorNode)) { 9508 formatDevErrorMessage(`Point.getNode() must return ElementNode when type is element`); 9509 } 9510 const lastNode = anchor.getNode(); 9511 if ( 9512 // This previously applied to all ParagraphNode 9513 lastNode.isEmpty() 9514 ) { 9515 $updateSelectionFormatStyleFromElementNode(selection, lastNode); 9516 } else { 9517 $updateSelectionFormatStyle(selection, selection.format, ""); 9518 } 9519 } 9520 } 9521 } else { 9522 const anchorKey = anchor.key; 9523 const focus = selection.focus; 9524 const focusKey = focus.key; 9525 const nodes = selection.getNodes(); 9526 const nodesLength = nodes.length; 9527 const isBackward = selection.isBackward(); 9528 const startOffset = isBackward ? focusOffset : anchorOffset; 9529 const endOffset = isBackward ? anchorOffset : focusOffset; 9530 const startKey = isBackward ? focusKey : anchorKey; 9531 const endKey = isBackward ? anchorKey : focusKey; 9532 let combinedFormat = IS_ALL_FORMATTING; 9533 let hasTextNodes = false; 9534 for (let i2 = 0; i2 < nodesLength; i2++) { 9535 const node = nodes[i2]; 9536 const textContentSize = node.getTextContentSize(); 9537 if ($isTextNode(node) && textContentSize !== 0 && // Exclude empty text nodes at boundaries resulting from user's selection 9538 !(i2 === 0 && node.__key === startKey && startOffset === textContentSize || i2 === nodesLength - 1 && node.__key === endKey && endOffset === 0)) { 9539 hasTextNodes = true; 9540 combinedFormat &= node.getFormat(); 9541 if (combinedFormat === 0) { 9542 break; 9543 } 9544 } 9545 } 9546 selection.format = hasTextNodes ? combinedFormat : 0; 9547 } 9548 } 9549 dispatchCommand(editor, SELECTION_CHANGE_COMMAND, void 0); 9550 }); 9551 } 9552 function $updateSelectionFormatStyle(selection, format, style) { 9553 if (selection.format !== format || selection.style !== style) { 9554 selection.format = format; 9555 selection.style = style; 9556 selection.dirty = true; 9557 } 9558 } 9559 function $updateSelectionFormatStyleFromTextNode(selection, node) { 9560 const format = node.getFormat(); 9561 const style = node.getStyle(); 9562 $updateSelectionFormatStyle(selection, format, style); 9563 } 9564 function $updateSelectionFormatStyleFromElementNode(selection, node) { 9565 const format = node.getTextFormat(); 9566 const style = node.getTextStyle(); 9567 $updateSelectionFormatStyle(selection, format, style); 9568 } 9569 function onClick(event, editor) { 9570 updateEditorSync(editor, () => { 9571 const selection = $getSelection(); 9572 const domSelection = getDOMSelection(getWindow(editor)); 9573 const lastSelection = $getPreviousSelection(); 9574 if (domSelection) { 9575 if ($isRangeSelection(selection)) { 9576 const anchor = selection.anchor; 9577 const anchorNode = anchor.getNode(); 9578 if (anchor.type === "element" && anchor.offset === 0 && selection.isCollapsed() && !$isRootNode(anchorNode) && $getRoot().getChildrenSize() === 1 && anchorNode.getTopLevelElementOrThrow().isEmpty() && lastSelection !== null && selection.is(lastSelection)) { 9579 domSelection.removeAllRanges(); 9580 selection.dirty = true; 9581 } else if (event.detail === 3 && !selection.isCollapsed()) { 9582 const focus = selection.focus; 9583 const focusNode = focus.getNode(); 9584 if (anchorNode !== focusNode) { 9585 const parentNode = $findMatchingParent(anchorNode, (node) => $isElementNode(node) && !node.isInline()); 9586 if ($isElementNode(parentNode)) { 9587 parentNode.select(0); 9588 } 9589 } 9590 } 9591 } else if (event.pointerType === "touch" || event.pointerType === "pen") { 9592 const domAnchorNode = domSelection.anchorNode; 9593 if (isHTMLElement(domAnchorNode) || isDOMTextNode(domAnchorNode)) { 9594 const newSelection = $internalCreateRangeSelection(lastSelection, domSelection, editor, event); 9595 $setSelection(newSelection); 9596 } 9597 } 9598 } 9599 dispatchCommand(editor, CLICK_COMMAND, event); 9600 }); 9601 } 9602 function onPointerDown(event, editor) { 9603 const target = event.target; 9604 const pointerType = event.pointerType; 9605 if (isDOMNode(target) && pointerType !== "touch" && pointerType !== "pen" && event.button === 0) { 9606 updateEditorSync(editor, () => { 9607 if (!$isSelectionCapturedInDecorator(target)) { 9608 isSelectionChangeFromMouseDown = true; 9609 } 9610 }); 9611 } 9612 } 9613 function getTargetRange(event) { 9614 if (!event.getTargetRanges) { 9615 return null; 9616 } 9617 const targetRanges = event.getTargetRanges(); 9618 if (targetRanges.length === 0) { 9619 return null; 9620 } 9621 return targetRanges[0]; 9622 } 9623 function $canRemoveText(anchorNode, focusNode) { 9624 return anchorNode !== focusNode || $isElementNode(anchorNode) || $isElementNode(focusNode) || !$isTokenOrTab(anchorNode) || !$isTokenOrTab(focusNode); 9625 } 9626 function isPossiblyAndroidKeyPress(timeStamp) { 9627 return lastKeyCode === "MediaLast" && timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY; 9628 } 9629 function registerDefaultCommandHandlers(editor) { 9630 editor.registerCommand(BEFORE_INPUT_COMMAND, $handleBeforeInput, COMMAND_PRIORITY_EDITOR); 9631 editor.registerCommand(INPUT_COMMAND, $handleInput, COMMAND_PRIORITY_EDITOR); 9632 editor.registerCommand(COMPOSITION_START_COMMAND, $handleCompositionStart, COMMAND_PRIORITY_EDITOR); 9633 editor.registerCommand(COMPOSITION_END_COMMAND, $handleCompositionEnd, COMMAND_PRIORITY_EDITOR); 9634 editor.registerCommand(KEY_DOWN_COMMAND, $handleKeyDown, COMMAND_PRIORITY_EDITOR); 9635 } 9636 function onBeforeInput(event, editor) { 9637 const inputType = event.inputType; 9638 if (inputType === "deleteCompositionText" || // If we're pasting in FF, we shouldn't get this event 9639 // as the `paste` event should have triggered, unless the 9640 // user has dom.event.clipboardevents.enabled disabled in 9641 // about:config. In that case, we need to process the 9642 // pasted content in the DOM mutation phase. 9643 IS_FIREFOX && isFirefoxClipboardEvents(editor)) { 9644 return; 9645 } else if (inputType === "insertCompositionText") { 9646 return; 9647 } 9648 dispatchCommand(editor, BEFORE_INPUT_COMMAND, event); 9649 } 9650 function $handleBeforeInput(event) { 9651 const inputType = event.inputType; 9652 const targetRange = getTargetRange(event); 9653 const editor = getActiveEditor(); 9654 const selection = $getSelection(); 9655 if (inputType === "deleteContentBackward") { 9656 if (selection === null) { 9657 const prevSelection = $getPreviousSelection(); 9658 if (!$isRangeSelection(prevSelection)) { 9659 return true; 9660 } 9661 $setSelection(prevSelection.clone()); 9662 } 9663 if ($isRangeSelection(selection)) { 9664 const isSelectionAnchorSameAsFocus = selection.anchor.key === selection.focus.key; 9665 if (isPossiblyAndroidKeyPress(event.timeStamp) && editor.isComposing() && isSelectionAnchorSameAsFocus) { 9666 $setCompositionKey(null); 9667 lastKeyDownTimeStamp = 0; 9668 setTimeout(() => { 9669 updateEditorSync(editor, () => { 9670 $setCompositionKey(null); 9671 }); 9672 }, ANDROID_COMPOSITION_LATENCY); 9673 if ($isRangeSelection(selection)) { 9674 const anchorNode2 = selection.anchor.getNode(); 9675 anchorNode2.markDirty(); 9676 if (!$isTextNode(anchorNode2)) { 9677 formatDevErrorMessage(`Anchor node must be a TextNode`); 9678 } 9679 $updateSelectionFormatStyleFromTextNode(selection, anchorNode2); 9680 } 9681 } else { 9682 $setCompositionKey(null); 9683 event.preventDefault(); 9684 const selectedNode = selection.anchor.getNode(); 9685 const selectedNodeText = selectedNode.getTextContent(); 9686 const selectedNodeCanInsertTextAfter = selectedNode.canInsertTextAfter(); 9687 const hasSelectedAllTextInNode = selection.anchor.offset === 0 && selection.focus.offset === selectedNodeText.length; 9688 let shouldLetBrowserHandleDelete = IS_ANDROID_CHROME && isSelectionAnchorSameAsFocus && !hasSelectedAllTextInNode && selectedNodeCanInsertTextAfter; 9689 if (shouldLetBrowserHandleDelete && selection.isCollapsed()) { 9690 shouldLetBrowserHandleDelete = !$isDecoratorNode($getAdjacentNode(selection.anchor, true)); 9691 } 9692 if (!shouldLetBrowserHandleDelete) { 9693 dispatchCommand(editor, DELETE_CHARACTER_COMMAND, true); 9694 const selectionAfterDelete = $getSelection(); 9695 if (IS_ANDROID_CHROME && $isRangeSelection(selectionAfterDelete) && selectionAfterDelete.isCollapsed()) { 9696 postDeleteSelectionToRestore = selectionAfterDelete; 9697 setTimeout(() => postDeleteSelectionToRestore = null); 9698 } 9699 } 9700 } 9701 return true; 9702 } 9703 } 9704 if (!$isRangeSelection(selection)) { 9705 return true; 9706 } 9707 const data = event.data; 9708 if (unprocessedBeforeInputData !== null) { 9709 $updateSelectedTextFromDOM(false, editor, unprocessedBeforeInputData); 9710 } 9711 if ((!selection.dirty || unprocessedBeforeInputData !== null) && selection.isCollapsed() && !$isRootNode(selection.anchor.getNode()) && targetRange !== null) { 9712 selection.applyDOMRange(targetRange); 9713 } 9714 unprocessedBeforeInputData = null; 9715 const anchor = selection.anchor; 9716 const focus = selection.focus; 9717 const anchorNode = anchor.getNode(); 9718 const focusNode = focus.getNode(); 9719 if (inputType === "insertText" || inputType === "insertTranspose") { 9720 if (data === "\n") { 9721 event.preventDefault(); 9722 dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, false); 9723 } else if (data === DOUBLE_LINE_BREAK) { 9724 event.preventDefault(); 9725 dispatchCommand(editor, INSERT_PARAGRAPH_COMMAND, void 0); 9726 } else if (data == null && event.dataTransfer) { 9727 const text2 = event.dataTransfer.getData("text/plain"); 9728 event.preventDefault(); 9729 selection.insertRawText(text2); 9730 } else if (data != null && $shouldPreventDefaultAndInsertText(selection, targetRange, data, event.timeStamp, true)) { 9731 event.preventDefault(); 9732 dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data); 9733 } else { 9734 unprocessedBeforeInputData = data; 9735 } 9736 lastBeforeInputInsertTextTimeStamp = event.timeStamp; 9737 return true; 9738 } 9739 event.preventDefault(); 9740 switch (inputType) { 9741 case "insertFromYank": 9742 case "insertFromDrop": 9743 case "insertReplacementText": { 9744 dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, event); 9745 break; 9746 } 9747 case "insertFromComposition": { 9748 $setCompositionKey(null); 9749 dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, event); 9750 break; 9751 } 9752 case "insertLineBreak": { 9753 $setCompositionKey(null); 9754 dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, false); 9755 break; 9756 } 9757 case "insertParagraph": { 9758 $setCompositionKey(null); 9759 if (isInsertLineBreak && !IS_IOS) { 9760 isInsertLineBreak = false; 9761 dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, false); 9762 } else { 9763 dispatchCommand(editor, INSERT_PARAGRAPH_COMMAND, void 0); 9764 } 9765 break; 9766 } 9767 case "insertFromPaste": 9768 case "insertFromPasteAsQuotation": { 9769 dispatchCommand(editor, PASTE_COMMAND, event); 9770 break; 9771 } 9772 case "deleteByComposition": { 9773 if ($canRemoveText(anchorNode, focusNode)) { 9774 dispatchCommand(editor, REMOVE_TEXT_COMMAND, event); 9775 } 9776 break; 9777 } 9778 case "deleteByDrag": { 9779 $addUpdateTag(SKIP_SELECTION_FOCUS_TAG); 9780 dispatchCommand(editor, REMOVE_TEXT_COMMAND, event); 9781 break; 9782 } 9783 case "deleteByCut": { 9784 dispatchCommand(editor, REMOVE_TEXT_COMMAND, event); 9785 break; 9786 } 9787 case "deleteContent": { 9788 dispatchCommand(editor, DELETE_CHARACTER_COMMAND, false); 9789 break; 9790 } 9791 case "deleteWordBackward": { 9792 dispatchCommand(editor, DELETE_WORD_COMMAND, true); 9793 break; 9794 } 9795 case "deleteWordForward": { 9796 dispatchCommand(editor, DELETE_WORD_COMMAND, false); 9797 break; 9798 } 9799 case "deleteHardLineBackward": 9800 case "deleteSoftLineBackward": { 9801 dispatchCommand(editor, DELETE_LINE_COMMAND, true); 9802 break; 9803 } 9804 case "deleteContentForward": 9805 case "deleteHardLineForward": 9806 case "deleteSoftLineForward": { 9807 dispatchCommand(editor, DELETE_LINE_COMMAND, false); 9808 break; 9809 } 9810 case "formatStrikeThrough": { 9811 dispatchCommand(editor, FORMAT_TEXT_COMMAND, "strikethrough"); 9812 break; 9813 } 9814 case "formatBold": { 9815 dispatchCommand(editor, FORMAT_TEXT_COMMAND, "bold"); 9816 break; 9817 } 9818 case "formatItalic": { 9819 dispatchCommand(editor, FORMAT_TEXT_COMMAND, "italic"); 9820 break; 9821 } 9822 case "formatUnderline": { 9823 dispatchCommand(editor, FORMAT_TEXT_COMMAND, "underline"); 9824 break; 9825 } 9826 case "historyUndo": { 9827 dispatchCommand(editor, UNDO_COMMAND, void 0); 9828 break; 9829 } 9830 case "historyRedo": { 9831 dispatchCommand(editor, REDO_COMMAND, void 0); 9832 break; 9833 } 9834 } 9835 return true; 9836 } 9837 function onInput(event, editor) { 9838 event.stopPropagation(); 9839 updateEditorSync(editor, () => { 9840 editor.dispatchCommand(INPUT_COMMAND, event); 9841 }, { 9842 event 9843 }); 9844 unprocessedBeforeInputData = null; 9845 } 9846 function $handleInput(event) { 9847 if (isHTMLElement(event.target) && $isSelectionCapturedInDecorator(event.target)) { 9848 return true; 9849 } 9850 const editor = getActiveEditor(); 9851 const selection = $getSelection(); 9852 const data = event.data; 9853 const targetRange = getTargetRange(event); 9854 if (data != null && $isRangeSelection(selection) && $shouldPreventDefaultAndInsertText(selection, targetRange, data, event.timeStamp, false)) { 9855 if (isFirefoxEndingComposition) { 9856 $onCompositionEndImpl(editor, data); 9857 isFirefoxEndingComposition = false; 9858 } 9859 const anchor = selection.anchor; 9860 const anchorNode = anchor.getNode(); 9861 const domSelection = getDOMSelection(getWindow(editor)); 9862 if (domSelection === null) { 9863 return true; 9864 } 9865 const isBackward = selection.isBackward(); 9866 const startOffset = isBackward ? selection.anchor.offset : selection.focus.offset; 9867 const endOffset = isBackward ? selection.focus.offset : selection.anchor.offset; 9868 if (!CAN_USE_BEFORE_INPUT || selection.isCollapsed() || !$isTextNode(anchorNode) || domSelection.anchorNode === null || anchorNode.getTextContent().slice(0, startOffset) + data + anchorNode.getTextContent().slice(startOffset + endOffset) !== getAnchorTextFromDOM(domSelection.anchorNode)) { 9869 dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data); 9870 } 9871 const textLength = data.length; 9872 if (IS_FIREFOX && textLength > 1 && event.inputType === "insertCompositionText" && !editor.isComposing()) { 9873 selection.anchor.offset -= textLength; 9874 } 9875 if (IS_ANDROID_CHROME && editor.isComposing()) { 9876 lastKeyDownTimeStamp = 0; 9877 $setCompositionKey(null); 9878 } 9879 } else { 9880 const characterData = data !== null ? data : void 0; 9881 $updateSelectedTextFromDOM(false, editor, characterData); 9882 if (isFirefoxEndingComposition) { 9883 $onCompositionEndImpl(editor, data || void 0); 9884 isFirefoxEndingComposition = false; 9885 } 9886 } 9887 $flushMutations(); 9888 return true; 9889 } 9890 function onCompositionStart(event, editor) { 9891 dispatchCommand(editor, COMPOSITION_START_COMMAND, event); 9892 } 9893 function $handleCompositionStart(event) { 9894 const editor = getActiveEditor(); 9895 const selection = $getSelection(); 9896 if ($isRangeSelection(selection) && !editor.isComposing()) { 9897 const anchor = selection.anchor; 9898 const node = selection.anchor.getNode(); 9899 $setCompositionKey(anchor.key); 9900 $addUpdateTag(COMPOSITION_START_TAG); 9901 if ( 9902 // If it has been 30ms since the last keydown, then we should 9903 // apply the empty space heuristic. We can't do this for Safari, 9904 // as the keydown fires after composition start. 9905 event.timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY || // FF has issues around composing multibyte characters, so we also 9906 // need to invoke the empty space heuristic below. 9907 anchor.type === "element" || !selection.isCollapsed() || node.getFormat() !== selection.format || $isTextNode(node) && node.getStyle() !== selection.style 9908 ) { 9909 dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, COMPOSITION_START_CHAR); 9910 } 9911 } 9912 return true; 9913 } 9914 function $handleCompositionEnd(event) { 9915 const editor = getActiveEditor(); 9916 $onCompositionEndImpl(editor, event.data); 9917 $addUpdateTag(COMPOSITION_END_TAG); 9918 return true; 9919 } 9920 function $onCompositionEndImpl(editor, data) { 9921 const compositionKey = editor._compositionKey; 9922 $setCompositionKey(null); 9923 if (compositionKey !== null && data != null) { 9924 if (data === "") { 9925 const node = $getNodeByKey(compositionKey); 9926 const domElement = editor.getElementByKey(compositionKey); 9927 const textNode = getDOMTextNode(domElement); 9928 if (textNode !== null && textNode.nodeValue !== null && $isTextNode(node)) { 9929 const domSelection = getDOMSelection(getWindow(editor)); 9930 let anchorOffset = null; 9931 let focusOffset = null; 9932 if (domSelection !== null && domSelection.anchorNode === textNode) { 9933 anchorOffset = domSelection.anchorOffset; 9934 focusOffset = domSelection.focusOffset; 9935 } 9936 $updateTextNodeFromDOMContent(node, textNode.nodeValue, anchorOffset, focusOffset, true); 9937 } 9938 return; 9939 } else if (data[data.length - 1] === "\n") { 9940 const selection = $getSelection(); 9941 if ($isRangeSelection(selection) || $isNodeSelection(selection)) { 9942 if ($isRangeSelection(selection)) { 9943 const focus = selection.focus; 9944 selection.anchor.set(focus.key, focus.offset, focus.type); 9945 } 9946 dispatchCommand(editor, KEY_ENTER_COMMAND, null); 9947 return; 9948 } 9949 } 9950 } 9951 $updateSelectedTextFromDOM(true, editor, data); 9952 } 9953 function onCompositionEnd(event, editor) { 9954 if (IS_FIREFOX) { 9955 isFirefoxEndingComposition = true; 9956 } else if (!IS_IOS && (IS_SAFARI || IS_APPLE_WEBKIT)) { 9957 isSafariEndingComposition = true; 9958 safariEndCompositionEventData = event.data; 9959 } else { 9960 dispatchCommand(editor, COMPOSITION_END_COMMAND, event); 9961 } 9962 } 9963 function onKeyDown(event, editor) { 9964 lastKeyDownTimeStamp = event.timeStamp; 9965 lastKeyCode = event.key; 9966 if (editor.isComposing()) { 9967 return; 9968 } 9969 dispatchCommand(editor, KEY_DOWN_COMMAND, event); 9970 } 9971 function $handleKeyDown(event) { 9972 const editor = getActiveEditor(); 9973 if (event.key == null) { 9974 return true; 9975 } 9976 if (isSafariEndingComposition) { 9977 if (isBackspace(event)) { 9978 updateEditorSync(editor, () => { 9979 $onCompositionEndImpl(editor, safariEndCompositionEventData); 9980 }); 9981 isSafariEndingComposition = false; 9982 safariEndCompositionEventData = ""; 9983 return true; 9984 } 9985 isSafariEndingComposition = false; 9986 safariEndCompositionEventData = ""; 9987 } 9988 if (isMoveForward(event)) { 9989 dispatchCommand(editor, KEY_ARROW_RIGHT_COMMAND, event); 9990 } else if (isMoveToEnd(event)) { 9991 dispatchCommand(editor, MOVE_TO_END, event); 9992 } else if (isMoveBackward(event)) { 9993 dispatchCommand(editor, KEY_ARROW_LEFT_COMMAND, event); 9994 } else if (isMoveToStart(event)) { 9995 dispatchCommand(editor, MOVE_TO_START, event); 9996 } else if (isMoveUp(event)) { 9997 dispatchCommand(editor, KEY_ARROW_UP_COMMAND, event); 9998 } else if (isMoveDown(event)) { 9999 dispatchCommand(editor, KEY_ARROW_DOWN_COMMAND, event); 10000 } else if (isLineBreak(event)) { 10001 isInsertLineBreak = true; 10002 dispatchCommand(editor, KEY_ENTER_COMMAND, event); 10003 } else if (isSpace(event)) { 10004 dispatchCommand(editor, KEY_SPACE_COMMAND, event); 10005 } else if (isOpenLineBreak(event)) { 10006 event.preventDefault(); 10007 isInsertLineBreak = true; 10008 dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, true); 10009 } else if (isParagraph(event)) { 10010 isInsertLineBreak = false; 10011 dispatchCommand(editor, KEY_ENTER_COMMAND, event); 10012 } else if (isDeleteBackward(event)) { 10013 if (isBackspace(event)) { 10014 dispatchCommand(editor, KEY_BACKSPACE_COMMAND, event); 10015 } else { 10016 event.preventDefault(); 10017 dispatchCommand(editor, DELETE_CHARACTER_COMMAND, true); 10018 } 10019 } else if (isEscape(event)) { 10020 dispatchCommand(editor, KEY_ESCAPE_COMMAND, event); 10021 } else if (isDeleteForward(event)) { 10022 if (isDelete(event)) { 10023 dispatchCommand(editor, KEY_DELETE_COMMAND, event); 10024 } else { 10025 event.preventDefault(); 10026 dispatchCommand(editor, DELETE_CHARACTER_COMMAND, false); 10027 } 10028 } else if (isDeleteWordBackward(event)) { 10029 event.preventDefault(); 10030 dispatchCommand(editor, DELETE_WORD_COMMAND, true); 10031 } else if (isDeleteWordForward(event)) { 10032 event.preventDefault(); 10033 dispatchCommand(editor, DELETE_WORD_COMMAND, false); 10034 } else if (isDeleteLineBackward(event)) { 10035 event.preventDefault(); 10036 dispatchCommand(editor, DELETE_LINE_COMMAND, true); 10037 } else if (isDeleteLineForward(event)) { 10038 event.preventDefault(); 10039 dispatchCommand(editor, DELETE_LINE_COMMAND, false); 10040 } else if (isBold(event)) { 10041 event.preventDefault(); 10042 dispatchCommand(editor, FORMAT_TEXT_COMMAND, "bold"); 10043 } else if (isUnderline(event)) { 10044 event.preventDefault(); 10045 dispatchCommand(editor, FORMAT_TEXT_COMMAND, "underline"); 10046 } else if (isItalic(event)) { 10047 event.preventDefault(); 10048 dispatchCommand(editor, FORMAT_TEXT_COMMAND, "italic"); 10049 } else if (isTab(event)) { 10050 dispatchCommand(editor, KEY_TAB_COMMAND, event); 10051 } else if (isUndo(event)) { 10052 event.preventDefault(); 10053 dispatchCommand(editor, UNDO_COMMAND, void 0); 10054 } else if (isRedo(event)) { 10055 event.preventDefault(); 10056 dispatchCommand(editor, REDO_COMMAND, void 0); 10057 } else { 10058 const prevSelection = editor._editorState._selection; 10059 if (prevSelection !== null && !$isRangeSelection(prevSelection)) { 10060 if (isCopy(event)) { 10061 event.preventDefault(); 10062 dispatchCommand(editor, COPY_COMMAND, event); 10063 } else if (isCut(event)) { 10064 event.preventDefault(); 10065 dispatchCommand(editor, CUT_COMMAND, event); 10066 } else if (isSelectAll(event)) { 10067 event.preventDefault(); 10068 dispatchCommand(editor, SELECT_ALL_COMMAND, event); 10069 } 10070 } else if (isSelectAll(event)) { 10071 event.preventDefault(); 10072 dispatchCommand(editor, SELECT_ALL_COMMAND, event); 10073 } 10074 } 10075 if (isModifier(event)) { 10076 editor.dispatchCommand(KEY_MODIFIER_COMMAND, event); 10077 } 10078 return true; 10079 } 10080 function getRootElementRemoveHandles(rootElement) { 10081 let eventHandles = rootElement.__lexicalEventHandles; 10082 if (eventHandles === void 0) { 10083 eventHandles = []; 10084 rootElement.__lexicalEventHandles = eventHandles; 10085 } 10086 return eventHandles; 10087 } 10088 var activeNestedEditorsMap = /* @__PURE__ */ new Map(); 10089 function onDocumentSelectionChange(event) { 10090 const domSelection = getDOMSelectionFromTarget(event.target); 10091 if (domSelection === null) { 10092 return; 10093 } 10094 const nextActiveEditor = getNearestEditorFromDOMNode(domSelection.anchorNode); 10095 if (nextActiveEditor === null) { 10096 return; 10097 } 10098 if (isSelectionChangeFromMouseDown) { 10099 isSelectionChangeFromMouseDown = false; 10100 updateEditorSync(nextActiveEditor, () => { 10101 const lastSelection = $getPreviousSelection(); 10102 const domAnchorNode = domSelection.anchorNode; 10103 if (isHTMLElement(domAnchorNode) || isDOMTextNode(domAnchorNode)) { 10104 const newSelection = $internalCreateRangeSelection(lastSelection, domSelection, nextActiveEditor, event); 10105 $setSelection(newSelection); 10106 } 10107 }); 10108 } 10109 const editors = getEditorsToPropagate(nextActiveEditor); 10110 const rootEditor = editors[editors.length - 1]; 10111 const rootEditorKey = rootEditor._key; 10112 const activeNestedEditor = activeNestedEditorsMap.get(rootEditorKey); 10113 const prevActiveEditor = activeNestedEditor || rootEditor; 10114 if (prevActiveEditor !== nextActiveEditor) { 10115 onSelectionChange(domSelection, prevActiveEditor, false); 10116 } 10117 onSelectionChange(domSelection, nextActiveEditor, true); 10118 if (nextActiveEditor !== rootEditor) { 10119 activeNestedEditorsMap.set(rootEditorKey, nextActiveEditor); 10120 } else if (activeNestedEditor) { 10121 activeNestedEditorsMap.delete(rootEditorKey); 10122 } 10123 } 10124 function stopLexicalPropagation(event) { 10125 event._lexicalHandled = true; 10126 } 10127 function hasStoppedLexicalPropagation(event) { 10128 const stopped = event._lexicalHandled === true; 10129 return stopped; 10130 } 10131 function addRootElementEvents(rootElement, editor) { 10132 const doc = rootElement.ownerDocument; 10133 rootElementToDocument.set(rootElement, doc); 10134 const documentRootElementsCount = rootElementsRegistered.get(doc) ?? 0; 10135 if (documentRootElementsCount < 1) { 10136 doc.addEventListener("selectionchange", onDocumentSelectionChange); 10137 } 10138 rootElementsRegistered.set(doc, documentRootElementsCount + 1); 10139 rootElement.__lexicalEditor = editor; 10140 const removeHandles = getRootElementRemoveHandles(rootElement); 10141 for (let i2 = 0; i2 < rootElementEvents.length; i2++) { 10142 const [eventName, onEvent] = rootElementEvents[i2]; 10143 const eventHandler = typeof onEvent === "function" ? (event) => { 10144 if (hasStoppedLexicalPropagation(event)) { 10145 return; 10146 } 10147 stopLexicalPropagation(event); 10148 if (editor.isEditable() || eventName === "click") { 10149 onEvent(event, editor); 10150 } 10151 } : (event) => { 10152 if (hasStoppedLexicalPropagation(event)) { 10153 return; 10154 } 10155 stopLexicalPropagation(event); 10156 const isEditable = editor.isEditable(); 10157 switch (eventName) { 10158 case "cut": 10159 return isEditable && dispatchCommand(editor, CUT_COMMAND, event); 10160 case "copy": 10161 return dispatchCommand(editor, COPY_COMMAND, event); 10162 case "paste": 10163 return isEditable && dispatchCommand(editor, PASTE_COMMAND, event); 10164 case "dragstart": 10165 return isEditable && dispatchCommand(editor, DRAGSTART_COMMAND, event); 10166 case "dragover": 10167 return isEditable && dispatchCommand(editor, DRAGOVER_COMMAND, event); 10168 case "dragend": 10169 return isEditable && dispatchCommand(editor, DRAGEND_COMMAND, event); 10170 case "focus": 10171 return isEditable && dispatchCommand(editor, FOCUS_COMMAND, event); 10172 case "blur": { 10173 return isEditable && dispatchCommand(editor, BLUR_COMMAND, event); 10174 } 10175 case "drop": 10176 return isEditable && dispatchCommand(editor, DROP_COMMAND, event); 10177 } 10178 }; 10179 rootElement.addEventListener(eventName, eventHandler); 10180 removeHandles.push(() => { 10181 rootElement.removeEventListener(eventName, eventHandler); 10182 }); 10183 } 10184 } 10185 var rootElementNotRegisteredWarning = warnOnlyOnce("Root element not registered"); 10186 function removeRootElementEvents(rootElement) { 10187 const doc = rootElementToDocument.get(rootElement); 10188 if (doc === void 0) { 10189 rootElementNotRegisteredWarning(); 10190 return; 10191 } 10192 const documentRootElementsCount = rootElementsRegistered.get(doc); 10193 if (documentRootElementsCount === void 0) { 10194 rootElementNotRegisteredWarning(); 10195 return; 10196 } 10197 const newCount = documentRootElementsCount - 1; 10198 if (!(newCount >= 0)) { 10199 formatDevErrorMessage(`Root element count less than 0`); 10200 } 10201 rootElementToDocument.delete(rootElement); 10202 rootElementsRegistered.set(doc, newCount); 10203 if (newCount === 0) { 10204 doc.removeEventListener("selectionchange", onDocumentSelectionChange); 10205 } 10206 const editor = getEditorPropertyFromDOMNode(rootElement); 10207 if (isLexicalEditor(editor)) { 10208 cleanActiveNestedEditorsMap(editor); 10209 rootElement.__lexicalEditor = null; 10210 } else if (editor) { 10211 { 10212 formatDevErrorMessage(`Attempted to remove event handlers from a node that does not belong to this build of Lexical`); 10213 } 10214 } 10215 const removeHandles = getRootElementRemoveHandles(rootElement); 10216 for (let i2 = 0; i2 < removeHandles.length; i2++) { 10217 removeHandles[i2](); 10218 } 10219 rootElement.__lexicalEventHandles = []; 10220 } 10221 function cleanActiveNestedEditorsMap(editor) { 10222 if (editor._parentEditor !== null) { 10223 const editors = getEditorsToPropagate(editor); 10224 const rootEditor = editors[editors.length - 1]; 10225 const rootEditorKey = rootEditor._key; 10226 if (activeNestedEditorsMap.get(rootEditorKey) === editor) { 10227 activeNestedEditorsMap.delete(rootEditorKey); 10228 } 10229 } else { 10230 activeNestedEditorsMap.delete(editor._key); 10231 } 10232 } 10233 function markSelectionChangeFromDOMUpdate() { 10234 isSelectionChangeFromDOMUpdate = true; 10235 } 10236 function markCollapsedSelectionFormat(format, style, offset3, key, timeStamp) { 10237 collapsedSelectionFormat = [format, style, offset3, key, timeStamp]; 10238 } 10239 function $removeNode(nodeToRemove, restoreSelection, preserveEmptyParent) { 10240 errorOnReadOnly(); 10241 const key = nodeToRemove.__key; 10242 const parent = nodeToRemove.getParent(); 10243 if (parent === null) { 10244 return; 10245 } 10246 const selection = $maybeMoveChildrenSelectionToParent(nodeToRemove); 10247 let selectionMoved = false; 10248 if ($isRangeSelection(selection) && restoreSelection) { 10249 const anchor = selection.anchor; 10250 const focus = selection.focus; 10251 if (anchor.key === key) { 10252 moveSelectionPointToSibling(anchor, nodeToRemove, parent, nodeToRemove.getPreviousSibling(), nodeToRemove.getNextSibling()); 10253 selectionMoved = true; 10254 } 10255 if (focus.key === key) { 10256 moveSelectionPointToSibling(focus, nodeToRemove, parent, nodeToRemove.getPreviousSibling(), nodeToRemove.getNextSibling()); 10257 selectionMoved = true; 10258 } 10259 } else if ($isNodeSelection(selection) && restoreSelection && nodeToRemove.isSelected()) { 10260 nodeToRemove.selectPrevious(); 10261 } 10262 if ($isRangeSelection(selection) && restoreSelection && !selectionMoved) { 10263 const index = nodeToRemove.getIndexWithinParent(); 10264 removeFromParent(nodeToRemove); 10265 $updateElementSelectionOnCreateDeleteNode(selection, parent, index, -1); 10266 } else { 10267 removeFromParent(nodeToRemove); 10268 } 10269 if (!preserveEmptyParent && !$isRootOrShadowRoot(parent) && !parent.canBeEmpty() && parent.isEmpty()) { 10270 $removeNode(parent, restoreSelection); 10271 } 10272 if (restoreSelection && selection && $isRootNode(parent) && parent.isEmpty()) { 10273 parent.selectEnd(); 10274 } 10275 } 10276 function buildImportMap(importMap) { 10277 return importMap; 10278 } 10279 var EPHEMERAL = Symbol.for("ephemeral"); 10280 function $isEphemeral(node) { 10281 return node[EPHEMERAL] || false; 10282 } 10283 function $markEphemeral(node) { 10284 node[EPHEMERAL] = true; 10285 return node; 10286 } 10287 var LexicalNode = class { 10288 /** @internal Allow us to look up the type including static props */ 10289 /** @internal */ 10290 __type; 10291 /** @internal */ 10292 //@ts-ignore We set the key in the constructor. 10293 __key; 10294 /** @internal */ 10295 __parent; 10296 /** @internal */ 10297 __prev; 10298 /** @internal */ 10299 __next; 10300 /** @internal */ 10301 __state; 10302 // Flow doesn't support abstract classes unfortunately, so we can't _force_ 10303 // subclasses of Node to implement statics. All subclasses of Node should have 10304 // a static getType and clone method though. We define getType and clone here so we can call it 10305 // on any Node, and we throw this error by default since the subclass should provide 10306 // their own implementation. 10307 /** 10308 * Returns the string type of this node. Every node must 10309 * implement this and it MUST BE UNIQUE amongst nodes registered 10310 * on the editor. 10311 * 10312 */ 10313 static getType() { 10314 const { 10315 ownNodeType 10316 } = getStaticNodeConfig(this); 10317 if (!(ownNodeType !== void 0)) { 10318 formatDevErrorMessage(`LexicalNode: Node ${this.name} does not implement .getType().`); 10319 } 10320 return ownNodeType; 10321 } 10322 /** 10323 * Clones this node, creating a new node with a different key 10324 * and adding it to the EditorState (but not attaching it anywhere!). All nodes must 10325 * implement this method. 10326 * 10327 */ 10328 static clone(_data) { 10329 { 10330 formatDevErrorMessage(`LexicalNode: Node ${this.name} does not implement .clone().`); 10331 } 10332 } 10333 /** 10334 * Override this to implement the new static node configuration protocol, 10335 * this method is called directly on the prototype and must not depend 10336 * on anything initialized in the constructor. Generally it should be 10337 * a trivial implementation. 10338 * 10339 * @example 10340 * ```ts 10341 * class MyNode extends TextNode { 10342 * $config() { 10343 * return this.config('my-node', {extends: TextNode}); 10344 * } 10345 * } 10346 * ``` 10347 */ 10348 $config() { 10349 return {}; 10350 } 10351 /** 10352 * This is a convenience method for $config that 10353 * aids in type inference. See {@link LexicalNode.$config} 10354 * for example usage. 10355 */ 10356 config(type, config) { 10357 const parentKlass = config.extends || Object.getPrototypeOf(this.constructor); 10358 Object.assign(config, { 10359 extends: parentKlass, 10360 type 10361 }); 10362 return { 10363 [type]: config 10364 }; 10365 } 10366 /** 10367 * Perform any state updates on the clone of prevNode that are not already 10368 * handled by the constructor call in the static clone method. If you have 10369 * state to update in your clone that is not handled directly by the 10370 * constructor, it is advisable to override this method but it is required 10371 * to include a call to `super.afterCloneFrom(prevNode)` in your 10372 * implementation. This is only intended to be called by 10373 * {@link $cloneWithProperties} function or via a super call. 10374 * 10375 * @example 10376 * ```ts 10377 * class ClassesTextNode extends TextNode { 10378 * // Not shown: static getType, static importJSON, exportJSON, createDOM, updateDOM 10379 * __classes = new Set<string>(); 10380 * static clone(node: ClassesTextNode): ClassesTextNode { 10381 * // The inherited TextNode constructor is used here, so 10382 * // classes is not set by this method. 10383 * return new ClassesTextNode(node.__text, node.__key); 10384 * } 10385 * afterCloneFrom(node: this): void { 10386 * // This calls TextNode.afterCloneFrom and LexicalNode.afterCloneFrom 10387 * // for necessary state updates 10388 * super.afterCloneFrom(node); 10389 * this.__addClasses(node.__classes); 10390 * } 10391 * // This method is a private implementation detail, it is not 10392 * // suitable for the public API because it does not call getWritable 10393 * __addClasses(classNames: Iterable<string>): this { 10394 * for (const className of classNames) { 10395 * this.__classes.add(className); 10396 * } 10397 * return this; 10398 * } 10399 * addClass(...classNames: string[]): this { 10400 * return this.getWritable().__addClasses(classNames); 10401 * } 10402 * removeClass(...classNames: string[]): this { 10403 * const node = this.getWritable(); 10404 * for (const className of classNames) { 10405 * this.__classes.delete(className); 10406 * } 10407 * return this; 10408 * } 10409 * getClasses(): Set<string> { 10410 * return this.getLatest().__classes; 10411 * } 10412 * } 10413 * ``` 10414 * 10415 */ 10416 afterCloneFrom(prevNode) { 10417 if (this.__key === prevNode.__key) { 10418 this.__parent = prevNode.__parent; 10419 this.__next = prevNode.__next; 10420 this.__prev = prevNode.__prev; 10421 this.__state = prevNode.__state; 10422 } else if (prevNode.__state) { 10423 this.__state = prevNode.__state.getWritable(this); 10424 } 10425 } 10426 /** 10427 * Reset state in this copy of originalNode, if necessary 10428 * 10429 * @param originalNode 10430 */ 10431 resetOnCopyNodeFrom(originalNode) { 10432 if (this.__state) { 10433 this.__state = this.__state.getWritable(this).resetOnCopyNode(); 10434 } 10435 } 10436 // eslint-disable-next-line @typescript-eslint/no-explicit-any 10437 static importDOM; 10438 constructor(key) { 10439 this.__type = this.constructor.getType(); 10440 this.__parent = null; 10441 this.__prev = null; 10442 this.__next = null; 10443 Object.defineProperty(this, "__state", { 10444 configurable: true, 10445 enumerable: false, 10446 value: void 0, 10447 writable: true 10448 }); 10449 $setNodeKey(this, key); 10450 { 10451 if (this.__type !== "root") { 10452 errorOnTypeKlassMismatch(this.__type, this.constructor); 10453 } 10454 } 10455 } 10456 // Getters and Traversers 10457 /** 10458 * Returns the string type of this node. 10459 */ 10460 getType() { 10461 return this.__type; 10462 } 10463 isInline() { 10464 { 10465 formatDevErrorMessage(`LexicalNode: Node ${this.constructor.name} does not implement .isInline().`); 10466 } 10467 } 10468 /** 10469 * Returns true if there is a path between this node and the RootNode, false otherwise. 10470 * This is a way of determining if the node is "attached" EditorState. Unattached nodes 10471 * won't be reconciled and will ultimately be cleaned up by the Lexical GC. 10472 */ 10473 isAttached() { 10474 let nodeKey = this.__key; 10475 while (nodeKey !== null) { 10476 if (nodeKey === "root") { 10477 return true; 10478 } 10479 const node = $getNodeByKey(nodeKey); 10480 if (node === null) { 10481 break; 10482 } 10483 nodeKey = node.__parent; 10484 } 10485 return false; 10486 } 10487 /** 10488 * Returns true if this node is contained within the provided Selection., false otherwise. 10489 * Relies on the algorithms implemented in {@link BaseSelection.getNodes} to determine 10490 * what's included. 10491 * 10492 * @param selection - The selection that we want to determine if the node is in. 10493 */ 10494 isSelected(selection) { 10495 const targetSelection = selection || $getSelection(); 10496 if (targetSelection == null) { 10497 return false; 10498 } 10499 const isSelected = targetSelection.getNodes().some((n2) => n2.__key === this.__key); 10500 if ($isTextNode(this)) { 10501 return isSelected; 10502 } 10503 const isElementRangeSelection = $isRangeSelection(targetSelection) && targetSelection.anchor.type === "element" && targetSelection.focus.type === "element"; 10504 if (isElementRangeSelection) { 10505 if (targetSelection.isCollapsed()) { 10506 return false; 10507 } 10508 const parentNode = this.getParent(); 10509 if ($isDecoratorNode(this) && this.isInline() && parentNode) { 10510 const firstPoint = targetSelection.isBackward() ? targetSelection.focus : targetSelection.anchor; 10511 if (parentNode.is(firstPoint.getNode()) && firstPoint.offset === parentNode.getChildrenSize() && this.is(parentNode.getLastChild())) { 10512 return false; 10513 } 10514 } 10515 } 10516 return isSelected; 10517 } 10518 /** 10519 * Returns this nodes key. 10520 */ 10521 getKey() { 10522 return this.__key; 10523 } 10524 /** 10525 * Returns the zero-based index of this node within the parent. 10526 */ 10527 getIndexWithinParent() { 10528 const parent = this.getParent(); 10529 if (parent === null) { 10530 return -1; 10531 } 10532 let node = parent.getFirstChild(); 10533 let index = 0; 10534 while (node !== null) { 10535 if (this.is(node)) { 10536 return index; 10537 } 10538 index++; 10539 node = node.getNextSibling(); 10540 } 10541 return -1; 10542 } 10543 /** 10544 * Returns the parent of this node, or null if none is found. 10545 */ 10546 getParent() { 10547 const parent = this.getLatest().__parent; 10548 if (parent === null) { 10549 return null; 10550 } 10551 return $getNodeByKey(parent); 10552 } 10553 /** 10554 * Returns the parent of this node, or throws if none is found. 10555 */ 10556 getParentOrThrow() { 10557 const parent = this.getParent(); 10558 if (parent === null) { 10559 { 10560 formatDevErrorMessage(`Expected node ${this.__key} to have a parent.`); 10561 } 10562 } 10563 return parent; 10564 } 10565 /** 10566 * Returns the highest (in the EditorState tree) 10567 * non-root ancestor of this node, or null if none is found. See {@link lexical!$isRootOrShadowRoot} 10568 * for more information on which Elements comprise "roots". 10569 */ 10570 getTopLevelElement() { 10571 let node = this; 10572 while (node !== null) { 10573 const parent = node.getParent(); 10574 if ($isRootOrShadowRoot(parent)) { 10575 if (!($isElementNode(node) || node === this && $isDecoratorNode(node))) { 10576 formatDevErrorMessage(`Children of root nodes must be elements or decorators`); 10577 } 10578 return node; 10579 } 10580 node = parent; 10581 } 10582 return null; 10583 } 10584 /** 10585 * Returns the highest (in the EditorState tree) 10586 * non-root ancestor of this node, or throws if none is found. See {@link lexical!$isRootOrShadowRoot} 10587 * for more information on which Elements comprise "roots". 10588 */ 10589 getTopLevelElementOrThrow() { 10590 const parent = this.getTopLevelElement(); 10591 if (parent === null) { 10592 { 10593 formatDevErrorMessage(`Expected node ${this.__key} to have a top parent element.`); 10594 } 10595 } 10596 return parent; 10597 } 10598 /** 10599 * Returns a list of the every ancestor of this node, 10600 * all the way up to the RootNode. 10601 * 10602 */ 10603 getParents() { 10604 const parents = []; 10605 let node = this.getParent(); 10606 while (node !== null) { 10607 parents.push(node); 10608 node = node.getParent(); 10609 } 10610 return parents; 10611 } 10612 /** 10613 * Returns a list of the keys of every ancestor of this node, 10614 * all the way up to the RootNode. 10615 * 10616 */ 10617 getParentKeys() { 10618 const parents = []; 10619 let node = this.getParent(); 10620 while (node !== null) { 10621 parents.push(node.__key); 10622 node = node.getParent(); 10623 } 10624 return parents; 10625 } 10626 /** 10627 * Returns the "previous" siblings - that is, the node that comes 10628 * before this one in the same parent. 10629 * 10630 */ 10631 getPreviousSibling() { 10632 const self2 = this.getLatest(); 10633 const prevKey = self2.__prev; 10634 return prevKey === null ? null : $getNodeByKey(prevKey); 10635 } 10636 /** 10637 * Returns the "previous" siblings - that is, the nodes that come between 10638 * this one and the first child of it's parent, inclusive. 10639 * 10640 */ 10641 getPreviousSiblings() { 10642 const siblings = []; 10643 const parent = this.getParent(); 10644 if (parent === null) { 10645 return siblings; 10646 } 10647 let node = parent.getFirstChild(); 10648 while (node !== null) { 10649 if (node.is(this)) { 10650 break; 10651 } 10652 siblings.push(node); 10653 node = node.getNextSibling(); 10654 } 10655 return siblings; 10656 } 10657 /** 10658 * Returns the "next" siblings - that is, the node that comes 10659 * after this one in the same parent 10660 * 10661 */ 10662 getNextSibling() { 10663 const self2 = this.getLatest(); 10664 const nextKey = self2.__next; 10665 return nextKey === null ? null : $getNodeByKey(nextKey); 10666 } 10667 /** 10668 * Returns all "next" siblings - that is, the nodes that come between this 10669 * one and the last child of it's parent, inclusive. 10670 * 10671 */ 10672 getNextSiblings() { 10673 const siblings = []; 10674 let node = this.getNextSibling(); 10675 while (node !== null) { 10676 siblings.push(node); 10677 node = node.getNextSibling(); 10678 } 10679 return siblings; 10680 } 10681 /** 10682 * @deprecated use {@link $getCommonAncestor} 10683 * 10684 * Returns the closest common ancestor of this node and the provided one or null 10685 * if one cannot be found. 10686 * 10687 * @param node - the other node to find the common ancestor of. 10688 */ 10689 getCommonAncestor(node) { 10690 const a2 = $isElementNode(this) ? this : this.getParent(); 10691 const b3 = $isElementNode(node) ? node : node.getParent(); 10692 const result = a2 && b3 ? $getCommonAncestor(a2, b3) : null; 10693 return result ? result.commonAncestor : null; 10694 } 10695 /** 10696 * Returns true if the provided node is the exact same one as this node, from Lexical's perspective. 10697 * Always use this instead of referential equality. 10698 * 10699 * @param object - the node to perform the equality comparison on. 10700 */ 10701 is(object) { 10702 if (object == null) { 10703 return false; 10704 } 10705 return this.__key === object.__key; 10706 } 10707 /** 10708 * Returns true if this node logically precedes the target node in the 10709 * editor state, false otherwise (including if there is no common ancestor). 10710 * 10711 * Note that this notion of isBefore is based on post-order; a descendant 10712 * node is always before its ancestors. See also 10713 * {@link $getCommonAncestor} and {@link $comparePointCaretNext} for 10714 * more flexible ways to determine the relative positions of nodes. 10715 * 10716 * @param targetNode - the node we're testing to see if it's after this one. 10717 */ 10718 isBefore(targetNode) { 10719 const compare = $getCommonAncestor(this, targetNode); 10720 if (compare === null) { 10721 return false; 10722 } 10723 if (compare.type === "descendant") { 10724 return true; 10725 } 10726 if (compare.type === "branch") { 10727 return $getCommonAncestorResultBranchOrder(compare) === -1; 10728 } 10729 if (!(compare.type === "same" || compare.type === "ancestor")) { 10730 formatDevErrorMessage(`LexicalNode.isBefore: exhaustiveness check`); 10731 } 10732 return false; 10733 } 10734 /** 10735 * Returns true if this node is an ancestor of and distinct from the target node, false otherwise. 10736 * 10737 * @param targetNode - the would-be child node. 10738 */ 10739 isParentOf(targetNode) { 10740 const result = $getCommonAncestor(this, targetNode); 10741 return result !== null && result.type === "ancestor"; 10742 } 10743 // TO-DO: this function can be simplified a lot 10744 /** 10745 * Returns a list of nodes that are between this node and 10746 * the target node in the EditorState. 10747 * 10748 * @param targetNode - the node that marks the other end of the range of nodes to be returned. 10749 */ 10750 getNodesBetween(targetNode) { 10751 const isBefore = this.isBefore(targetNode); 10752 const nodes = []; 10753 const visited = /* @__PURE__ */ new Set(); 10754 let node = this; 10755 while (true) { 10756 if (node === null) { 10757 break; 10758 } 10759 const key = node.__key; 10760 if (!visited.has(key)) { 10761 visited.add(key); 10762 nodes.push(node); 10763 } 10764 if (node === targetNode) { 10765 break; 10766 } 10767 const child = $isElementNode(node) ? isBefore ? node.getFirstChild() : node.getLastChild() : null; 10768 if (child !== null) { 10769 node = child; 10770 continue; 10771 } 10772 const nextSibling = isBefore ? node.getNextSibling() : node.getPreviousSibling(); 10773 if (nextSibling !== null) { 10774 node = nextSibling; 10775 continue; 10776 } 10777 const parent = node.getParentOrThrow(); 10778 if (!visited.has(parent.__key)) { 10779 nodes.push(parent); 10780 } 10781 if (parent === targetNode) { 10782 break; 10783 } 10784 let parentSibling = null; 10785 let ancestor = parent; 10786 do { 10787 if (ancestor === null) { 10788 { 10789 formatDevErrorMessage(`getNodesBetween: ancestor is null`); 10790 } 10791 } 10792 parentSibling = isBefore ? ancestor.getNextSibling() : ancestor.getPreviousSibling(); 10793 ancestor = ancestor.getParent(); 10794 if (ancestor !== null) { 10795 if (parentSibling === null && !visited.has(ancestor.__key)) { 10796 nodes.push(ancestor); 10797 } 10798 } else { 10799 break; 10800 } 10801 } while (parentSibling === null); 10802 node = parentSibling; 10803 } 10804 if (!isBefore) { 10805 nodes.reverse(); 10806 } 10807 return nodes; 10808 } 10809 /** 10810 * Returns true if this node has been marked dirty during this update cycle. 10811 * 10812 */ 10813 isDirty() { 10814 const editor = getActiveEditor(); 10815 const dirtyLeaves = editor._dirtyLeaves; 10816 return dirtyLeaves !== null && dirtyLeaves.has(this.__key); 10817 } 10818 /** 10819 * Returns the latest version of the node from the active EditorState. 10820 * This is used to avoid getting values from stale node references. 10821 * 10822 */ 10823 getLatest() { 10824 if ($isEphemeral(this)) { 10825 return this; 10826 } 10827 const latest = $getNodeByKey(this.__key); 10828 if (latest === null) { 10829 { 10830 formatDevErrorMessage(`Lexical node does not exist in active editor state. Avoid using the same node references between nested closures from editorState.read/editor.update.`); 10831 } 10832 } 10833 return latest; 10834 } 10835 /** 10836 * Returns a mutable version of the node using {@link $cloneWithProperties} 10837 * if necessary. Will throw an error if called outside of a Lexical Editor 10838 * {@link LexicalEditor.update} callback. 10839 * 10840 */ 10841 getWritable() { 10842 if ($isEphemeral(this)) { 10843 return this; 10844 } 10845 errorOnReadOnly(); 10846 const editorState = getActiveEditorState(); 10847 const editor = getActiveEditor(); 10848 const nodeMap = editorState._nodeMap; 10849 const key = this.__key; 10850 const latestNode = this.getLatest(); 10851 const cloneNotNeeded = editor._cloneNotNeeded; 10852 const selection = $getSelection(); 10853 if (selection !== null) { 10854 selection.setCachedNodes(null); 10855 } 10856 if (cloneNotNeeded.has(key)) { 10857 internalMarkNodeAsDirty(latestNode); 10858 return latestNode; 10859 } 10860 const mutableNode = $cloneWithProperties(latestNode); 10861 cloneNotNeeded.add(key); 10862 internalMarkNodeAsDirty(mutableNode); 10863 nodeMap.set(key, mutableNode); 10864 return mutableNode; 10865 } 10866 /** 10867 * Returns the text content of the node. Override this for 10868 * custom nodes that should have a representation in plain text 10869 * format (for copy + paste, for example) 10870 * 10871 */ 10872 getTextContent() { 10873 return ""; 10874 } 10875 /** 10876 * Returns the length of the string produced by calling getTextContent on this node. 10877 * 10878 */ 10879 getTextContentSize() { 10880 return this.getTextContent().length; 10881 } 10882 // View 10883 /** 10884 * Called during the reconciliation process to determine which nodes 10885 * to insert into the DOM for this Lexical Node. 10886 * 10887 * This method must return exactly one HTMLElement. Nested elements are not supported. 10888 * 10889 * Do not attempt to update the Lexical EditorState during this phase of the update lifecycle. 10890 * 10891 * @param _config - allows access to things like the EditorTheme (to apply classes) during reconciliation. 10892 * @param _editor - allows access to the editor for context during reconciliation. 10893 * 10894 * */ 10895 createDOM(_config, _editor) { 10896 { 10897 formatDevErrorMessage(`createDOM: base method not extended`); 10898 } 10899 } 10900 /** 10901 * Called when a node changes and should update the DOM 10902 * in whatever way is necessary to make it align with any changes that might 10903 * have happened during the update. 10904 * 10905 * Returning "true" here will cause lexical to unmount and recreate the DOM node 10906 * (by calling createDOM). You would need to do this if the element tag changes, 10907 * for instance. 10908 * 10909 * */ 10910 updateDOM(_prevNode, _dom, _config) { 10911 { 10912 formatDevErrorMessage(`updateDOM: base method not extended`); 10913 } 10914 } 10915 /** 10916 * Controls how the this node is serialized to HTML. This is important for 10917 * copy and paste between Lexical and non-Lexical editors, or Lexical editors with different namespaces, 10918 * in which case the primary transfer format is HTML. It's also important if you're serializing 10919 * to HTML for any other reason via {@link @lexical/html!$generateHtmlFromNodes}. You could 10920 * also use this method to build your own HTML renderer. 10921 * 10922 * */ 10923 exportDOM(editor) { 10924 const element = this.createDOM(editor._config, editor); 10925 return { 10926 element 10927 }; 10928 } 10929 /** 10930 * Controls how the this node is serialized to JSON. This is important for 10931 * copy and paste between Lexical editors sharing the same namespace. It's also important 10932 * if you're serializing to JSON for persistent storage somewhere. 10933 * See [Serialization & Deserialization](https://lexical.dev/docs/concepts/serialization#lexical---html). 10934 * 10935 * */ 10936 exportJSON() { 10937 const state = this.__state ? this.__state.toJSON() : void 0; 10938 return { 10939 type: this.__type, 10940 version: 1, 10941 ...state 10942 }; 10943 } 10944 /** 10945 * Controls how the this node is deserialized from JSON. This is usually boilerplate, 10946 * but provides an abstraction between the node implementation and serialized interface that can 10947 * be important if you ever make breaking changes to a node schema (by adding or removing properties). 10948 * See [Serialization & Deserialization](https://lexical.dev/docs/concepts/serialization#lexical---html). 10949 * 10950 * */ 10951 static importJSON(_serializedNode) { 10952 { 10953 formatDevErrorMessage(`LexicalNode: Node ${this.name} does not implement .importJSON().`); 10954 } 10955 } 10956 /** 10957 * Update this LexicalNode instance from serialized JSON. It's recommended 10958 * to implement as much logic as possible in this method instead of the 10959 * static importJSON method, so that the functionality can be inherited in subclasses. 10960 * 10961 * The LexicalUpdateJSON utility type should be used to ignore any type, version, 10962 * or children properties in the JSON so that the extended JSON from subclasses 10963 * are acceptable parameters for the super call. 10964 * 10965 * If overridden, this method must call super. 10966 * 10967 * @example 10968 * ```ts 10969 * class MyTextNode extends TextNode { 10970 * // ... 10971 * static importJSON(serializedNode: SerializedMyTextNode): MyTextNode { 10972 * return $createMyTextNode() 10973 * .updateFromJSON(serializedNode); 10974 * } 10975 * updateFromJSON( 10976 * serializedNode: LexicalUpdateJSON<SerializedMyTextNode>, 10977 * ): this { 10978 * return super.updateFromJSON(serializedNode) 10979 * .setMyProperty(serializedNode.myProperty); 10980 * } 10981 * } 10982 * ``` 10983 **/ 10984 updateFromJSON(serializedNode) { 10985 return $updateStateFromJSON(this, serializedNode); 10986 } 10987 /** 10988 * @experimental 10989 * 10990 * Registers the returned function as a transform on the node during 10991 * Editor initialization. Most such use cases should be addressed via 10992 * the {@link LexicalEditor.registerNodeTransform} API. 10993 * 10994 * Experimental - use at your own risk. 10995 */ 10996 static transform() { 10997 return null; 10998 } 10999 // Setters and mutators 11000 /** 11001 * Removes this LexicalNode from the EditorState. If the node isn't re-inserted 11002 * somewhere, the Lexical garbage collector will eventually clean it up. 11003 * 11004 * @param preserveEmptyParent - If falsy, the node's parent will be removed if 11005 * it's empty after the removal operation. This is the default behavior, subject to 11006 * other node heuristics such as {@link ElementNode#canBeEmpty} 11007 * */ 11008 remove(preserveEmptyParent) { 11009 $removeNode(this, true, preserveEmptyParent); 11010 } 11011 /** 11012 * Replaces this LexicalNode with the provided node, optionally transferring the children 11013 * of the replaced node to the replacing node. 11014 * 11015 * @param replaceWith - The node to replace this one with. 11016 * @param includeChildren - Whether or not to transfer the children of this node to the replacing node. 11017 * */ 11018 replace(replaceWith, includeChildren) { 11019 errorOnReadOnly(); 11020 let selection = $getSelection(); 11021 if (selection !== null) { 11022 selection = selection.clone(); 11023 } 11024 errorOnInsertTextNodeOnRoot(this, replaceWith); 11025 const self2 = this.getLatest(); 11026 const toReplaceKey = this.__key; 11027 const key = replaceWith.__key; 11028 const writableReplaceWith = replaceWith.getWritable(); 11029 const writableParent = this.getParentOrThrow().getWritable(); 11030 const size2 = writableParent.__size; 11031 removeFromParent(writableReplaceWith); 11032 const prevSibling = self2.getPreviousSibling(); 11033 const nextSibling = self2.getNextSibling(); 11034 const prevKey = self2.__prev; 11035 const nextKey = self2.__next; 11036 const parentKey = self2.__parent; 11037 $removeNode(self2, false, true); 11038 if (prevSibling === null) { 11039 writableParent.__first = key; 11040 } else { 11041 const writablePrevSibling = prevSibling.getWritable(); 11042 writablePrevSibling.__next = key; 11043 } 11044 writableReplaceWith.__prev = prevKey; 11045 if (nextSibling === null) { 11046 writableParent.__last = key; 11047 } else { 11048 const writableNextSibling = nextSibling.getWritable(); 11049 writableNextSibling.__prev = key; 11050 } 11051 writableReplaceWith.__next = nextKey; 11052 writableReplaceWith.__parent = parentKey; 11053 writableParent.__size = size2; 11054 if (includeChildren) { 11055 if (!($isElementNode(this) && $isElementNode(writableReplaceWith))) { 11056 formatDevErrorMessage(`includeChildren should only be true for ElementNodes`); 11057 } 11058 this.getChildren().forEach((child) => { 11059 writableReplaceWith.append(child); 11060 }); 11061 } 11062 if ($isRangeSelection(selection)) { 11063 $setSelection(selection); 11064 const anchor = selection.anchor; 11065 const focus = selection.focus; 11066 if (anchor.key === toReplaceKey) { 11067 $moveSelectionPointToEnd(anchor, writableReplaceWith); 11068 } 11069 if (focus.key === toReplaceKey) { 11070 $moveSelectionPointToEnd(focus, writableReplaceWith); 11071 } 11072 } 11073 if ($getCompositionKey() === toReplaceKey) { 11074 $setCompositionKey(key); 11075 } 11076 return writableReplaceWith; 11077 } 11078 /** 11079 * Inserts a node after this LexicalNode (as the next sibling). 11080 * 11081 * @param nodeToInsert - The node to insert after this one. 11082 * @param restoreSelection - Whether or not to attempt to resolve the 11083 * selection to the appropriate place after the operation is complete. 11084 * */ 11085 insertAfter(nodeToInsert, restoreSelection = true) { 11086 errorOnReadOnly(); 11087 errorOnInsertTextNodeOnRoot(this, nodeToInsert); 11088 const writableSelf = this.getWritable(); 11089 const writableNodeToInsert = nodeToInsert.getWritable(); 11090 const oldParent = writableNodeToInsert.getParent(); 11091 const selection = $getSelection(); 11092 let elementAnchorSelectionOnNode = false; 11093 let elementFocusSelectionOnNode = false; 11094 if (oldParent !== null) { 11095 const oldIndex = nodeToInsert.getIndexWithinParent(); 11096 removeFromParent(writableNodeToInsert); 11097 if ($isRangeSelection(selection)) { 11098 const oldParentKey = oldParent.__key; 11099 const anchor = selection.anchor; 11100 const focus = selection.focus; 11101 elementAnchorSelectionOnNode = anchor.type === "element" && anchor.key === oldParentKey && anchor.offset === oldIndex + 1; 11102 elementFocusSelectionOnNode = focus.type === "element" && focus.key === oldParentKey && focus.offset === oldIndex + 1; 11103 } 11104 } 11105 const nextSibling = this.getNextSibling(); 11106 const writableParent = this.getParentOrThrow().getWritable(); 11107 const insertKey = writableNodeToInsert.__key; 11108 const nextKey = writableSelf.__next; 11109 if (nextSibling === null) { 11110 writableParent.__last = insertKey; 11111 } else { 11112 const writableNextSibling = nextSibling.getWritable(); 11113 writableNextSibling.__prev = insertKey; 11114 } 11115 writableParent.__size++; 11116 writableSelf.__next = insertKey; 11117 writableNodeToInsert.__next = nextKey; 11118 writableNodeToInsert.__prev = writableSelf.__key; 11119 writableNodeToInsert.__parent = writableSelf.__parent; 11120 if (restoreSelection && $isRangeSelection(selection)) { 11121 const index = this.getIndexWithinParent(); 11122 $updateElementSelectionOnCreateDeleteNode(selection, writableParent, index + 1); 11123 const writableParentKey = writableParent.__key; 11124 if (elementAnchorSelectionOnNode) { 11125 selection.anchor.set(writableParentKey, index + 2, "element"); 11126 } 11127 if (elementFocusSelectionOnNode) { 11128 selection.focus.set(writableParentKey, index + 2, "element"); 11129 } 11130 } 11131 return nodeToInsert; 11132 } 11133 /** 11134 * Inserts a node before this LexicalNode (as the previous sibling). 11135 * 11136 * @param nodeToInsert - The node to insert before this one. 11137 * @param restoreSelection - Whether or not to attempt to resolve the 11138 * selection to the appropriate place after the operation is complete. 11139 * */ 11140 insertBefore(nodeToInsert, restoreSelection = true) { 11141 errorOnReadOnly(); 11142 errorOnInsertTextNodeOnRoot(this, nodeToInsert); 11143 const writableSelf = this.getWritable(); 11144 const writableNodeToInsert = nodeToInsert.getWritable(); 11145 const insertKey = writableNodeToInsert.__key; 11146 removeFromParent(writableNodeToInsert); 11147 const prevSibling = this.getPreviousSibling(); 11148 const writableParent = this.getParentOrThrow().getWritable(); 11149 const prevKey = writableSelf.__prev; 11150 const index = this.getIndexWithinParent(); 11151 if (prevSibling === null) { 11152 writableParent.__first = insertKey; 11153 } else { 11154 const writablePrevSibling = prevSibling.getWritable(); 11155 writablePrevSibling.__next = insertKey; 11156 } 11157 writableParent.__size++; 11158 writableSelf.__prev = insertKey; 11159 writableNodeToInsert.__prev = prevKey; 11160 writableNodeToInsert.__next = writableSelf.__key; 11161 writableNodeToInsert.__parent = writableSelf.__parent; 11162 const selection = $getSelection(); 11163 if (restoreSelection && $isRangeSelection(selection)) { 11164 const parent = this.getParentOrThrow(); 11165 $updateElementSelectionOnCreateDeleteNode(selection, parent, index); 11166 } 11167 return nodeToInsert; 11168 } 11169 /** 11170 * Whether or not this node has a required parent. Used during copy + paste operations 11171 * to normalize nodes that would otherwise be orphaned. For example, ListItemNodes without 11172 * a ListNode parent or TextNodes with a ParagraphNode parent. 11173 * 11174 * */ 11175 isParentRequired() { 11176 return false; 11177 } 11178 /** 11179 * The creation logic for any required parent. Should be implemented if {@link isParentRequired} returns true. 11180 * 11181 * */ 11182 createParentElementNode() { 11183 return $createParagraphNode(); 11184 } 11185 selectStart() { 11186 return this.selectPrevious(); 11187 } 11188 selectEnd() { 11189 return this.selectNext(0, 0); 11190 } 11191 /** 11192 * Moves selection to the previous sibling of this node, at the specified offsets. 11193 * 11194 * @param anchorOffset - The anchor offset for selection. 11195 * @param focusOffset - The focus offset for selection 11196 * */ 11197 selectPrevious(anchorOffset, focusOffset) { 11198 errorOnReadOnly(); 11199 const prevSibling = this.getPreviousSibling(); 11200 const parent = this.getParentOrThrow(); 11201 if (prevSibling === null) { 11202 return parent.select(0, 0); 11203 } 11204 if ($isElementNode(prevSibling)) { 11205 return prevSibling.select(); 11206 } else if (!$isTextNode(prevSibling)) { 11207 const index = prevSibling.getIndexWithinParent() + 1; 11208 return parent.select(index, index); 11209 } 11210 return prevSibling.select(anchorOffset, focusOffset); 11211 } 11212 /** 11213 * Moves selection to the next sibling of this node, at the specified offsets. 11214 * 11215 * @param anchorOffset - The anchor offset for selection. 11216 * @param focusOffset - The focus offset for selection 11217 * */ 11218 selectNext(anchorOffset, focusOffset) { 11219 errorOnReadOnly(); 11220 const nextSibling = this.getNextSibling(); 11221 const parent = this.getParentOrThrow(); 11222 if (nextSibling === null) { 11223 return parent.select(); 11224 } 11225 if ($isElementNode(nextSibling)) { 11226 return nextSibling.select(0, 0); 11227 } else if (!$isTextNode(nextSibling)) { 11228 const index = nextSibling.getIndexWithinParent(); 11229 return parent.select(index, index); 11230 } 11231 return nextSibling.select(anchorOffset, focusOffset); 11232 } 11233 /** 11234 * Marks a node dirty, triggering transforms and 11235 * forcing it to be reconciled during the update cycle. 11236 * 11237 * */ 11238 markDirty() { 11239 this.getWritable(); 11240 } 11241 /** 11242 * @internal 11243 * 11244 * When the reconciler detects that a node was mutated, this method 11245 * may be called to restore the node to a known good state. 11246 */ 11247 reconcileObservedMutation(dom, editor) { 11248 this.markDirty(); 11249 } 11250 }; 11251 function errorOnTypeKlassMismatch(type, klass) { 11252 const registeredNode = getRegisteredNode(getActiveEditor(), type); 11253 if (registeredNode === void 0) { 11254 { 11255 formatDevErrorMessage(`Create node: Attempted to create node ${klass.name} that was not configured to be used on the editor.`); 11256 } 11257 } 11258 const editorKlass = registeredNode.klass; 11259 if (editorKlass !== klass) { 11260 { 11261 formatDevErrorMessage(`Create node: Type ${type} in node ${klass.name} does not match registered node ${editorKlass.name} with the same type`); 11262 } 11263 } 11264 } 11265 function insertRangeAfter(node, firstToInsert, lastToInsert) { 11266 const lastToInsert2 = firstToInsert.getParentOrThrow().getLastChild(); 11267 let current = firstToInsert; 11268 const nodesToInsert = [firstToInsert]; 11269 while (current !== lastToInsert2) { 11270 if (!current.getNextSibling()) { 11271 { 11272 formatDevErrorMessage(`insertRangeAfter: lastToInsert must be a later sibling of firstToInsert`); 11273 } 11274 } 11275 current = current.getNextSibling(); 11276 nodesToInsert.push(current); 11277 } 11278 let currentNode = node; 11279 for (const nodeToInsert of nodesToInsert) { 11280 currentNode = currentNode.insertAfter(nodeToInsert); 11281 } 11282 } 11283 function $isLexicalNode(node) { 11284 return node instanceof LexicalNode; 11285 } 11286 var HISTORIC_TAG = "historic"; 11287 var HISTORY_PUSH_TAG = "history-push"; 11288 var HISTORY_MERGE_TAG = "history-merge"; 11289 var PASTE_TAG = "paste"; 11290 var COLLABORATION_TAG = "collaboration"; 11291 var SKIP_COLLAB_TAG = "skip-collab"; 11292 var SKIP_SCROLL_INTO_VIEW_TAG = "skip-scroll-into-view"; 11293 var SKIP_DOM_SELECTION_TAG = "skip-dom-selection"; 11294 var SKIP_SELECTION_FOCUS_TAG = "skip-selection-focus"; 11295 var FOCUS_TAG = "focus"; 11296 var COMPOSITION_START_TAG = "composition-start"; 11297 var COMPOSITION_END_TAG = "composition-end"; 11298 var IMPORTANT_REG_EXP = /\s*!important\s*$/i; 11299 function getStyleObjectFromCSS(css) { 11300 const styles = {}; 11301 if (!css) { 11302 return styles; 11303 } 11304 let currentProperty = ""; 11305 let currentValue = ""; 11306 let currentQuote = null; 11307 let inComment = false; 11308 let isEscaped = false; 11309 let isParsingValue = false; 11310 let parenthesisDepth = 0; 11311 for (let i2 = 0; i2 < css.length; i2++) { 11312 const char = css[i2]; 11313 if (inComment) { 11314 if (char === "*" && css[i2 + 1] === "/") { 11315 inComment = false; 11316 i2++; 11317 } 11318 continue; 11319 } 11320 if (isEscaped) { 11321 if (isParsingValue) { 11322 currentValue += char; 11323 } else { 11324 currentProperty += char; 11325 } 11326 isEscaped = false; 11327 continue; 11328 } 11329 if (currentQuote !== null) { 11330 if (isParsingValue) { 11331 currentValue += char; 11332 } else { 11333 currentProperty += char; 11334 } 11335 if (char === "\\") { 11336 isEscaped = true; 11337 } else if (char === currentQuote) { 11338 currentQuote = null; 11339 } 11340 continue; 11341 } 11342 if (char === "/" && css[i2 + 1] === "*") { 11343 inComment = true; 11344 i2++; 11345 continue; 11346 } 11347 if (char === '"' || char === "'") { 11348 currentQuote = char; 11349 if (isParsingValue) { 11350 currentValue += char; 11351 } else { 11352 currentProperty += char; 11353 } 11354 continue; 11355 } 11356 if (char === "(") { 11357 parenthesisDepth++; 11358 if (isParsingValue) { 11359 currentValue += char; 11360 } else { 11361 currentProperty += char; 11362 } 11363 continue; 11364 } 11365 if (char === ")") { 11366 parenthesisDepth = Math.max(0, parenthesisDepth - 1); 11367 if (isParsingValue) { 11368 currentValue += char; 11369 } else { 11370 currentProperty += char; 11371 } 11372 continue; 11373 } 11374 if (!isParsingValue && char === ":" && parenthesisDepth === 0) { 11375 isParsingValue = true; 11376 continue; 11377 } 11378 if (char === ";" && parenthesisDepth === 0) { 11379 const property2 = currentProperty.trim(); 11380 const value2 = currentValue.trim(); 11381 if (property2 !== "" && value2 !== "") { 11382 styles[property2] = value2; 11383 } 11384 currentProperty = ""; 11385 currentValue = ""; 11386 isParsingValue = false; 11387 continue; 11388 } 11389 if (isParsingValue) { 11390 currentValue += char; 11391 } else { 11392 currentProperty += char; 11393 } 11394 } 11395 const property = currentProperty.trim(); 11396 const value = currentValue.trim(); 11397 if (property !== "" && value !== "") { 11398 styles[property] = value; 11399 } 11400 return styles; 11401 } 11402 function setDOMStyleProperty(domStyle, property, value) { 11403 const priority = IMPORTANT_REG_EXP.test(value) ? "important" : ""; 11404 const nextValue = priority === "" ? value : value.replace(IMPORTANT_REG_EXP, "").trim(); 11405 domStyle.setProperty(property, nextValue, priority); 11406 } 11407 function setDOMStyleObject(domStyle, styleObject) { 11408 for (const property in styleObject) { 11409 const value = styleObject[property]; 11410 if (value == null) { 11411 domStyle.removeProperty(property); 11412 } else { 11413 setDOMStyleProperty(domStyle, property, value); 11414 } 11415 } 11416 } 11417 function setDOMStyleFromCSS(domStyle, cssText, prevCSSText = "") { 11418 if (cssText === prevCSSText) { 11419 return; 11420 } 11421 const prevCSS = getStyleObjectFromCSS(prevCSSText); 11422 const nextCSS = getStyleObjectFromCSS(cssText); 11423 for (const property in nextCSS) { 11424 delete prevCSS[property]; 11425 setDOMStyleProperty(domStyle, property, nextCSS[property]); 11426 } 11427 for (const property in prevCSS) { 11428 domStyle.removeProperty(property); 11429 } 11430 } 11431 var LineBreakNode = class _LineBreakNode extends LexicalNode { 11432 /** @internal */ 11433 static getType() { 11434 return "linebreak"; 11435 } 11436 static clone(node) { 11437 return new _LineBreakNode(node.__key); 11438 } 11439 constructor(key) { 11440 super(key); 11441 } 11442 getTextContent() { 11443 return "\n"; 11444 } 11445 createDOM() { 11446 return document.createElement("br"); 11447 } 11448 updateDOM() { 11449 return false; 11450 } 11451 isInline() { 11452 return true; 11453 } 11454 static importDOM() { 11455 return { 11456 br: (node) => { 11457 if (isOnlyChildInBlockNode(node) || isLastChildInBlockNode(node)) { 11458 return null; 11459 } 11460 return { 11461 conversion: $convertLineBreakElement, 11462 priority: 0 11463 }; 11464 } 11465 }; 11466 } 11467 static importJSON(serializedLineBreakNode) { 11468 return $createLineBreakNode().updateFromJSON(serializedLineBreakNode); 11469 } 11470 }; 11471 function $convertLineBreakElement(node) { 11472 return { 11473 node: $createLineBreakNode() 11474 }; 11475 } 11476 function $createLineBreakNode() { 11477 return $applyNodeReplacement(new LineBreakNode()); 11478 } 11479 function $isLineBreakNode(node) { 11480 return node instanceof LineBreakNode; 11481 } 11482 function isOnlyChildInBlockNode(node) { 11483 const parentElement = node.parentElement; 11484 if (parentElement !== null && isBlockDomNode(parentElement)) { 11485 const firstChild = parentElement.firstChild; 11486 if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) { 11487 const lastChild = parentElement.lastChild; 11488 if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) { 11489 return true; 11490 } 11491 } 11492 } 11493 return false; 11494 } 11495 function isLastChildInBlockNode(node) { 11496 const parentElement = node.parentElement; 11497 if (parentElement !== null && isBlockDomNode(parentElement)) { 11498 const firstChild = parentElement.firstChild; 11499 if (firstChild === node || firstChild.nextSibling === node && isWhitespaceDomTextNode(firstChild)) { 11500 return false; 11501 } 11502 const lastChild = parentElement.lastChild; 11503 if (lastChild === node || lastChild.previousSibling === node && isWhitespaceDomTextNode(lastChild)) { 11504 return true; 11505 } 11506 } 11507 return false; 11508 } 11509 function isWhitespaceDomTextNode(node) { 11510 return isDOMTextNode(node) && /^( |\t|\r?\n)+$/.test(node.textContent || ""); 11511 } 11512 function getElementOuterTag(node, format) { 11513 if (format & IS_CODE) { 11514 return "code"; 11515 } 11516 if (format & IS_HIGHLIGHT) { 11517 return "mark"; 11518 } 11519 if (format & IS_SUBSCRIPT) { 11520 return "sub"; 11521 } 11522 if (format & IS_SUPERSCRIPT) { 11523 return "sup"; 11524 } 11525 return null; 11526 } 11527 function getElementInnerTag(node, format) { 11528 if (format & IS_BOLD) { 11529 return "strong"; 11530 } 11531 if (format & IS_ITALIC) { 11532 return "em"; 11533 } 11534 return "span"; 11535 } 11536 function setTextThemeClassNames(tag, prevFormat, nextFormat, dom, textClassNames) { 11537 const domClassList = dom.classList; 11538 let classNames = getCachedClassNameArray(textClassNames, "base"); 11539 if (classNames !== void 0) { 11540 domClassList.add(...classNames); 11541 } 11542 classNames = getCachedClassNameArray(textClassNames, "underlineStrikethrough"); 11543 let hasUnderlineStrikethrough = false; 11544 const prevUnderlineStrikethrough = prevFormat & IS_UNDERLINE && prevFormat & IS_STRIKETHROUGH; 11545 const nextUnderlineStrikethrough = nextFormat & IS_UNDERLINE && nextFormat & IS_STRIKETHROUGH; 11546 if (classNames !== void 0) { 11547 if (nextUnderlineStrikethrough) { 11548 hasUnderlineStrikethrough = true; 11549 if (!prevUnderlineStrikethrough) { 11550 domClassList.add(...classNames); 11551 } 11552 } else if (prevUnderlineStrikethrough) { 11553 domClassList.remove(...classNames); 11554 } 11555 } 11556 for (const key in TEXT_TYPE_TO_FORMAT) { 11557 const format = key; 11558 const flag = TEXT_TYPE_TO_FORMAT[format]; 11559 classNames = getCachedClassNameArray(textClassNames, key); 11560 if (classNames !== void 0) { 11561 if (nextFormat & flag) { 11562 if (hasUnderlineStrikethrough && (key === "underline" || key === "strikethrough")) { 11563 if (prevFormat & flag) { 11564 domClassList.remove(...classNames); 11565 } 11566 continue; 11567 } 11568 if ((prevFormat & flag) === 0 || prevUnderlineStrikethrough && key === "underline" || key === "strikethrough") { 11569 domClassList.add(...classNames); 11570 } 11571 } else if (prevFormat & flag) { 11572 domClassList.remove(...classNames); 11573 } 11574 } 11575 } 11576 } 11577 function diffComposedText(a2, b3) { 11578 const aLength = a2.length; 11579 const bLength = b3.length; 11580 let left = 0; 11581 let right = 0; 11582 while (left < aLength && left < bLength && a2[left] === b3[left]) { 11583 left++; 11584 } 11585 while (right + left < aLength && right + left < bLength && a2[aLength - right - 1] === b3[bLength - right - 1]) { 11586 right++; 11587 } 11588 return [left, aLength - left - right, b3.slice(left, bLength - right)]; 11589 } 11590 function setTextContent(nextText, dom, node) { 11591 const firstChild = dom.firstChild; 11592 const isComposing = node.isComposing(); 11593 const suffix = isComposing ? COMPOSITION_SUFFIX : ""; 11594 const text2 = nextText + suffix; 11595 if (firstChild == null) { 11596 dom.textContent = text2; 11597 } else { 11598 const nodeValue = firstChild.nodeValue; 11599 if (nodeValue !== text2) { 11600 if (isComposing || IS_FIREFOX) { 11601 const [index, remove, insert] = diffComposedText(nodeValue, text2); 11602 if (remove !== 0) { 11603 firstChild.deleteData(index, remove); 11604 } 11605 firstChild.insertData(index, insert); 11606 } else { 11607 firstChild.nodeValue = text2; 11608 } 11609 } 11610 } 11611 } 11612 function createTextInnerDOM(innerDOM, node, innerTag, format, text2, config) { 11613 setTextContent(text2, innerDOM, node); 11614 const theme2 = config.theme; 11615 const textClassNames = theme2.text; 11616 if (textClassNames !== void 0) { 11617 setTextThemeClassNames(innerTag, 0, format, innerDOM, textClassNames); 11618 } 11619 } 11620 function wrapElementWith(element, tag) { 11621 const el = document.createElement(tag); 11622 el.appendChild(element); 11623 return el; 11624 } 11625 var TextNode = class _TextNode extends LexicalNode { 11626 /** @internal */ 11627 __text; 11628 /** @internal */ 11629 __format; 11630 /** @internal */ 11631 __style; 11632 /** @internal */ 11633 __mode; 11634 /** @internal */ 11635 __detail; 11636 static getType() { 11637 return "text"; 11638 } 11639 static clone(node) { 11640 return new _TextNode(node.__text, node.__key); 11641 } 11642 afterCloneFrom(prevNode) { 11643 super.afterCloneFrom(prevNode); 11644 this.__text = prevNode.__text; 11645 this.__format = prevNode.__format; 11646 this.__style = prevNode.__style; 11647 this.__mode = prevNode.__mode; 11648 this.__detail = prevNode.__detail; 11649 } 11650 constructor(text2 = "", key) { 11651 super(key); 11652 this.__text = text2; 11653 this.__format = 0; 11654 this.__style = ""; 11655 this.__mode = 0; 11656 this.__detail = 0; 11657 } 11658 /** 11659 * Returns a 32-bit integer that represents the TextFormatTypes currently applied to the 11660 * TextNode. You probably don't want to use this method directly - consider using TextNode.hasFormat instead. 11661 * 11662 * @returns a number representing the format of the text node. 11663 */ 11664 getFormat() { 11665 const self2 = this.getLatest(); 11666 return self2.__format; 11667 } 11668 /** 11669 * Returns a 32-bit integer that represents the TextDetailTypes currently applied to the 11670 * TextNode. You probably don't want to use this method directly - consider using TextNode.isDirectionless 11671 * or TextNode.isUnmergeable instead. 11672 * 11673 * @returns a number representing the detail of the text node. 11674 */ 11675 getDetail() { 11676 const self2 = this.getLatest(); 11677 return self2.__detail; 11678 } 11679 /** 11680 * Returns the mode (TextModeType) of the TextNode, which may be "normal", "token", or "segmented" 11681 * 11682 * @returns TextModeType. 11683 */ 11684 getMode() { 11685 const self2 = this.getLatest(); 11686 return TEXT_TYPE_TO_MODE[self2.__mode]; 11687 } 11688 /** 11689 * Returns the styles currently applied to the node. This is analogous to CSSText in the DOM. 11690 * 11691 * @returns CSSText-like string of styles applied to the underlying DOM node. 11692 */ 11693 getStyle() { 11694 const self2 = this.getLatest(); 11695 return self2.__style; 11696 } 11697 /** 11698 * Returns whether or not the node is in "token" mode. TextNodes in token mode can be navigated through character-by-character 11699 * with a RangeSelection, but are deleted as a single entity (not individually by character). 11700 * 11701 * @returns true if the node is in token mode, false otherwise. 11702 */ 11703 isToken() { 11704 const self2 = this.getLatest(); 11705 return self2.__mode === IS_TOKEN; 11706 } 11707 /** 11708 * 11709 * @returns true if Lexical detects that an IME or other 3rd-party script is attempting to 11710 * mutate the TextNode, false otherwise. 11711 */ 11712 isComposing() { 11713 return this.__key === $getCompositionKey(); 11714 } 11715 /** 11716 * Returns whether or not the node is in "segmented" mode. TextNodes in segmented mode can be navigated through character-by-character 11717 * with a RangeSelection, but are deleted in space-delimited "segments". 11718 * 11719 * @returns true if the node is in segmented mode, false otherwise. 11720 */ 11721 isSegmented() { 11722 const self2 = this.getLatest(); 11723 return self2.__mode === IS_SEGMENTED; 11724 } 11725 /** 11726 * Returns whether or not the node is "directionless". Directionless nodes don't respect changes between RTL and LTR modes. 11727 * 11728 * @returns true if the node is directionless, false otherwise. 11729 */ 11730 isDirectionless() { 11731 const self2 = this.getLatest(); 11732 return (self2.__detail & IS_DIRECTIONLESS) !== 0; 11733 } 11734 /** 11735 * Returns whether or not the node is unmergeable. In some scenarios, Lexical tries to merge 11736 * adjacent TextNodes into a single TextNode. If a TextNode is unmergeable, this won't happen. 11737 * 11738 * @returns true if the node is unmergeable, false otherwise. 11739 */ 11740 isUnmergeable() { 11741 const self2 = this.getLatest(); 11742 return (self2.__detail & IS_UNMERGEABLE) !== 0; 11743 } 11744 /** 11745 * Returns whether or not the node has the provided format applied. Use this with the human-readable TextFormatType 11746 * string values to get the format of a TextNode. 11747 * 11748 * @param type - the TextFormatType to check for. 11749 * 11750 * @returns true if the node has the provided format, false otherwise. 11751 */ 11752 hasFormat(type) { 11753 const formatFlag = TEXT_TYPE_TO_FORMAT[type]; 11754 return (this.getFormat() & formatFlag) !== 0; 11755 } 11756 /** 11757 * Returns whether or not the node is simple text. Simple text is defined as a TextNode that has the string type "text" 11758 * (i.e., not a subclass) and has no mode applied to it (i.e., not segmented or token). 11759 * 11760 * @returns true if the node is simple text, false otherwise. 11761 */ 11762 isSimpleText() { 11763 return this.__type === "text" && this.__mode === 0; 11764 } 11765 /** 11766 * Returns the text content of the node as a string. 11767 * 11768 * @returns a string representing the text content of the node. 11769 */ 11770 getTextContent() { 11771 const self2 = this.getLatest(); 11772 return self2.__text; 11773 } 11774 /** 11775 * Returns the format flags applied to the node as a 32-bit integer. 11776 * 11777 * @returns a number representing the TextFormatTypes applied to the node. 11778 */ 11779 getFormatFlags(type, alignWithFormat) { 11780 const self2 = this.getLatest(); 11781 const format = self2.__format; 11782 return toggleTextFormatType(format, type, alignWithFormat); 11783 } 11784 /** 11785 * 11786 * @returns true if the text node supports font styling, false otherwise. 11787 */ 11788 canHaveFormat() { 11789 return true; 11790 } 11791 /** 11792 * @returns true if the text node is inline, false otherwise. 11793 */ 11794 isInline() { 11795 return true; 11796 } 11797 // View 11798 createDOM(config, editor) { 11799 const format = this.__format; 11800 const outerTag = getElementOuterTag(this, format); 11801 const innerTag = getElementInnerTag(this, format); 11802 const tag = outerTag === null ? innerTag : outerTag; 11803 const dom = document.createElement(tag); 11804 let innerDOM = dom; 11805 if (this.hasFormat("code")) { 11806 dom.setAttribute("spellcheck", "false"); 11807 } 11808 if (outerTag !== null) { 11809 innerDOM = document.createElement(innerTag); 11810 dom.appendChild(innerDOM); 11811 } 11812 const text2 = this.__text; 11813 createTextInnerDOM(innerDOM, this, innerTag, format, text2, config); 11814 const style = this.__style; 11815 if (style !== "") { 11816 setDOMStyleFromCSS(dom.style, style); 11817 } 11818 return dom; 11819 } 11820 updateDOM(prevNode, dom, config) { 11821 const nextText = this.__text; 11822 const prevFormat = prevNode.__format; 11823 const nextFormat = this.__format; 11824 const prevOuterTag = getElementOuterTag(this, prevFormat); 11825 const nextOuterTag = getElementOuterTag(this, nextFormat); 11826 const prevInnerTag = getElementInnerTag(this, prevFormat); 11827 const nextInnerTag = getElementInnerTag(this, nextFormat); 11828 const prevTag = prevOuterTag === null ? prevInnerTag : prevOuterTag; 11829 const nextTag = nextOuterTag === null ? nextInnerTag : nextOuterTag; 11830 if (prevTag !== nextTag) { 11831 return true; 11832 } 11833 if (prevOuterTag === nextOuterTag && prevInnerTag !== nextInnerTag) { 11834 const prevInnerDOM = dom.firstChild; 11835 if (prevInnerDOM == null) { 11836 { 11837 formatDevErrorMessage(`updateDOM: prevInnerDOM is null or undefined`); 11838 } 11839 } 11840 const nextInnerDOM = document.createElement(nextInnerTag); 11841 createTextInnerDOM(nextInnerDOM, this, nextInnerTag, nextFormat, nextText, config); 11842 dom.replaceChild(nextInnerDOM, prevInnerDOM); 11843 return false; 11844 } 11845 let innerDOM = dom; 11846 if (nextOuterTag !== null) { 11847 if (prevOuterTag !== null) { 11848 innerDOM = dom.firstChild; 11849 if (innerDOM == null) { 11850 { 11851 formatDevErrorMessage(`updateDOM: innerDOM is null or undefined`); 11852 } 11853 } 11854 } 11855 } 11856 setTextContent(nextText, innerDOM, this); 11857 const theme2 = config.theme; 11858 const textClassNames = theme2.text; 11859 if (textClassNames !== void 0 && prevFormat !== nextFormat) { 11860 setTextThemeClassNames(nextInnerTag, prevFormat, nextFormat, innerDOM, textClassNames); 11861 } 11862 const prevStyle = prevNode.__style; 11863 const nextStyle = this.__style; 11864 if (prevStyle !== nextStyle) { 11865 setDOMStyleFromCSS(dom.style, nextStyle, prevStyle); 11866 } 11867 return false; 11868 } 11869 static importDOM() { 11870 return { 11871 "#text": () => ({ 11872 conversion: $convertTextDOMNode, 11873 priority: 0 11874 }), 11875 b: () => ({ 11876 conversion: convertBringAttentionToElement, 11877 priority: 0 11878 }), 11879 code: () => ({ 11880 conversion: convertTextFormatElement, 11881 priority: 0 11882 }), 11883 em: () => ({ 11884 conversion: convertTextFormatElement, 11885 priority: 0 11886 }), 11887 i: () => ({ 11888 conversion: convertTextFormatElement, 11889 priority: 0 11890 }), 11891 mark: () => ({ 11892 conversion: convertTextFormatElement, 11893 priority: 0 11894 }), 11895 s: () => ({ 11896 conversion: convertTextFormatElement, 11897 priority: 0 11898 }), 11899 span: () => ({ 11900 conversion: convertSpanElement, 11901 priority: 0 11902 }), 11903 strong: () => ({ 11904 conversion: convertTextFormatElement, 11905 priority: 0 11906 }), 11907 sub: () => ({ 11908 conversion: convertTextFormatElement, 11909 priority: 0 11910 }), 11911 sup: () => ({ 11912 conversion: convertTextFormatElement, 11913 priority: 0 11914 }), 11915 u: () => ({ 11916 conversion: convertTextFormatElement, 11917 priority: 0 11918 }) 11919 }; 11920 } 11921 static importJSON(serializedNode) { 11922 return $createTextNode().updateFromJSON(serializedNode); 11923 } 11924 updateFromJSON(serializedNode) { 11925 return super.updateFromJSON(serializedNode).setTextContent(serializedNode.text).setFormat(serializedNode.format).setDetail(serializedNode.detail).setMode(serializedNode.mode).setStyle(serializedNode.style); 11926 } 11927 // This improves Lexical's basic text output in copy+paste plus 11928 // for headless mode where people might use Lexical to generate 11929 // HTML content and not have the ability to use CSS classes. 11930 exportDOM(editor) { 11931 let { 11932 element 11933 } = super.exportDOM(editor); 11934 if (!isHTMLElement(element)) { 11935 formatDevErrorMessage(`Expected TextNode createDOM to always return a HTMLElement`); 11936 } 11937 element.style.whiteSpace = "pre-wrap"; 11938 if (this.hasFormat("lowercase")) { 11939 element.style.textTransform = "lowercase"; 11940 } else if (this.hasFormat("uppercase")) { 11941 element.style.textTransform = "uppercase"; 11942 } else if (this.hasFormat("capitalize")) { 11943 element.style.textTransform = "capitalize"; 11944 } 11945 if (this.hasFormat("bold")) { 11946 element = wrapElementWith(element, "b"); 11947 } 11948 if (this.hasFormat("italic")) { 11949 element = wrapElementWith(element, "i"); 11950 } 11951 if (this.hasFormat("strikethrough")) { 11952 element = wrapElementWith(element, "s"); 11953 } 11954 if (this.hasFormat("underline")) { 11955 element = wrapElementWith(element, "u"); 11956 } 11957 return { 11958 element 11959 }; 11960 } 11961 exportJSON() { 11962 return { 11963 detail: this.getDetail(), 11964 format: this.getFormat(), 11965 mode: this.getMode(), 11966 style: this.getStyle(), 11967 text: this.getTextContent(), 11968 // As an exception here we invoke super at the end for historical reasons. 11969 // Namely, to preserve the order of the properties and not to break the tests 11970 // that use the serialized string representation. 11971 ...super.exportJSON() 11972 }; 11973 } 11974 // Mutators 11975 selectionTransform(prevSelection, nextSelection) { 11976 return; 11977 } 11978 /** 11979 * Sets the node format to the provided TextFormatType or 32-bit integer. Note that the TextFormatType 11980 * version of the argument can only specify one format and doing so will remove all other formats that 11981 * may be applied to the node. For toggling behavior, consider using {@link TextNode.toggleFormat} 11982 * 11983 * @param format - TextFormatType or 32-bit integer representing the node format. 11984 * 11985 * @returns this TextNode. 11986 * // TODO 0.12 This should just be a `string`. 11987 */ 11988 setFormat(format) { 11989 const self2 = this.getWritable(); 11990 self2.__format = typeof format === "string" ? TEXT_TYPE_TO_FORMAT[format] : format; 11991 return self2; 11992 } 11993 /** 11994 * Sets the node detail to the provided TextDetailType or 32-bit integer. Note that the TextDetailType 11995 * version of the argument can only specify one detail value and doing so will remove all other detail values that 11996 * may be applied to the node. For toggling behavior, consider using {@link TextNode.toggleDirectionless} 11997 * or {@link TextNode.toggleUnmergeable} 11998 * 11999 * @param detail - TextDetailType or 32-bit integer representing the node detail. 12000 * 12001 * @returns this TextNode. 12002 * // TODO 0.12 This should just be a `string`. 12003 */ 12004 setDetail(detail) { 12005 const self2 = this.getWritable(); 12006 self2.__detail = typeof detail === "string" ? DETAIL_TYPE_TO_DETAIL[detail] : detail; 12007 return self2; 12008 } 12009 /** 12010 * Sets the node style to the provided CSSText-like string. Set this property as you 12011 * would an HTMLElement style attribute to apply inline styles to the underlying DOM Element. 12012 * 12013 * @param style - CSSText to be applied to the underlying HTMLElement. 12014 * 12015 * @returns this TextNode. 12016 */ 12017 setStyle(style) { 12018 const self2 = this.getWritable(); 12019 self2.__style = style; 12020 return self2; 12021 } 12022 /** 12023 * Applies the provided format to this TextNode if it's not present. Removes it if it's present. 12024 * The subscript and superscript formats are mutually exclusive. 12025 * Prefer using this method to turn specific formats on and off. 12026 * 12027 * @param type - TextFormatType to toggle. 12028 * 12029 * @returns this TextNode. 12030 */ 12031 toggleFormat(type) { 12032 const format = this.getFormat(); 12033 const newFormat = toggleTextFormatType(format, type, null); 12034 return this.setFormat(newFormat); 12035 } 12036 /** 12037 * Toggles the directionless detail value of the node. Prefer using this method over setDetail. 12038 * 12039 * @returns this TextNode. 12040 */ 12041 toggleDirectionless() { 12042 const self2 = this.getWritable(); 12043 self2.__detail ^= IS_DIRECTIONLESS; 12044 return self2; 12045 } 12046 /** 12047 * Toggles the unmergeable detail value of the node. Prefer using this method over setDetail. 12048 * 12049 * @returns this TextNode. 12050 */ 12051 toggleUnmergeable() { 12052 const self2 = this.getWritable(); 12053 self2.__detail ^= IS_UNMERGEABLE; 12054 return self2; 12055 } 12056 /** 12057 * Sets the mode of the node. 12058 * 12059 * @returns this TextNode. 12060 */ 12061 setMode(type) { 12062 const mode = TEXT_MODE_TO_TYPE[type]; 12063 if (this.__mode === mode) { 12064 return this; 12065 } 12066 const self2 = this.getWritable(); 12067 self2.__mode = mode; 12068 return self2; 12069 } 12070 /** 12071 * Sets the text content of the node. 12072 * 12073 * @param text - the string to set as the text value of the node. 12074 * 12075 * @returns this TextNode. 12076 */ 12077 setTextContent(text2) { 12078 if (this.__text === text2) { 12079 return this; 12080 } 12081 const self2 = this.getWritable(); 12082 self2.__text = text2; 12083 return self2; 12084 } 12085 /** 12086 * Sets the current Lexical selection to be a RangeSelection with anchor and focus on this TextNode at the provided offsets. 12087 * 12088 * @param _anchorOffset - the offset at which the Selection anchor will be placed. 12089 * @param _focusOffset - the offset at which the Selection focus will be placed. 12090 * 12091 * @returns the new RangeSelection. 12092 */ 12093 select(_anchorOffset, _focusOffset) { 12094 errorOnReadOnly(); 12095 let anchorOffset = _anchorOffset; 12096 let focusOffset = _focusOffset; 12097 const selection = $getSelection(); 12098 const text2 = this.getTextContent(); 12099 const key = this.__key; 12100 if (typeof text2 === "string") { 12101 const lastOffset = text2.length; 12102 if (anchorOffset === void 0) { 12103 anchorOffset = lastOffset; 12104 } 12105 if (focusOffset === void 0) { 12106 focusOffset = lastOffset; 12107 } 12108 } else { 12109 anchorOffset = 0; 12110 focusOffset = 0; 12111 } 12112 if (!$isRangeSelection(selection)) { 12113 return $internalMakeRangeSelection(key, anchorOffset, key, focusOffset, "text", "text"); 12114 } else { 12115 const compositionKey = $getCompositionKey(); 12116 if (compositionKey === selection.anchor.key || compositionKey === selection.focus.key) { 12117 $setCompositionKey(key); 12118 } 12119 selection.setTextNodeRange(this, anchorOffset, this, focusOffset); 12120 } 12121 return selection; 12122 } 12123 selectStart() { 12124 return this.select(0, 0); 12125 } 12126 selectEnd() { 12127 const size2 = this.getTextContentSize(); 12128 return this.select(size2, size2); 12129 } 12130 /** 12131 * Inserts the provided text into this TextNode at the provided offset, deleting the number of characters 12132 * specified. Can optionally calculate a new selection after the operation is complete. 12133 * 12134 * @param offset - the offset at which the splice operation should begin. 12135 * @param delCount - the number of characters to delete, starting from the offset. 12136 * @param newText - the text to insert into the TextNode at the offset. 12137 * @param moveSelection - optional, whether or not to move selection to the end of the inserted substring. 12138 * 12139 * @returns this TextNode. 12140 */ 12141 spliceText(offset3, delCount, newText, moveSelection) { 12142 const writableSelf = this.getWritable(); 12143 const text2 = writableSelf.__text; 12144 const handledTextLength = newText.length; 12145 let index = offset3; 12146 if (index < 0) { 12147 index = handledTextLength + index; 12148 if (index < 0) { 12149 index = 0; 12150 } 12151 } 12152 const selection = $getSelection(); 12153 if (moveSelection && $isRangeSelection(selection)) { 12154 const newOffset = offset3 + handledTextLength; 12155 selection.setTextNodeRange(writableSelf, newOffset, writableSelf, newOffset); 12156 } 12157 const updatedText = text2.slice(0, index) + newText + text2.slice(index + delCount); 12158 writableSelf.__text = updatedText; 12159 return writableSelf; 12160 } 12161 /** 12162 * This method is meant to be overridden by TextNode subclasses to control the behavior of those nodes 12163 * when a user event would cause text to be inserted before them in the editor. If true, Lexical will attempt 12164 * to insert text into this node. If false, it will insert the text in a new sibling node. 12165 * 12166 * @returns true if text can be inserted before the node, false otherwise. 12167 */ 12168 canInsertTextBefore() { 12169 return true; 12170 } 12171 /** 12172 * This method is meant to be overridden by TextNode subclasses to control the behavior of those nodes 12173 * when a user event would cause text to be inserted after them in the editor. If true, Lexical will attempt 12174 * to insert text into this node. If false, it will insert the text in a new sibling node. 12175 * 12176 * @returns true if text can be inserted after the node, false otherwise. 12177 */ 12178 canInsertTextAfter() { 12179 return true; 12180 } 12181 /** 12182 * Splits this TextNode at the provided character offsets, forming new TextNodes from the substrings 12183 * formed by the split, and inserting those new TextNodes into the editor, replacing the one that was split. 12184 * 12185 * @param splitOffsets - rest param of the text content character offsets at which this node should be split. 12186 * 12187 * @returns an Array containing the newly-created TextNodes. 12188 */ 12189 splitText(...splitOffsets) { 12190 errorOnReadOnly(); 12191 const self2 = this.getLatest(); 12192 const textContent = self2.getTextContent(); 12193 if (textContent === "") { 12194 return []; 12195 } 12196 const key = self2.__key; 12197 const compositionKey = $getCompositionKey(); 12198 const textLength = textContent.length; 12199 splitOffsets.sort((a2, b3) => a2 - b3); 12200 splitOffsets.push(textLength); 12201 const parts = []; 12202 const splitOffsetsLength = splitOffsets.length; 12203 for (let start3 = 0, offsetIndex = 0; start3 < textLength && offsetIndex <= splitOffsetsLength; offsetIndex++) { 12204 const end = splitOffsets[offsetIndex]; 12205 if (end > start3) { 12206 parts.push(textContent.slice(start3, end)); 12207 start3 = end; 12208 } 12209 } 12210 const partsLength = parts.length; 12211 if (partsLength === 1) { 12212 return [self2]; 12213 } 12214 const firstPart = parts[0]; 12215 const parent = self2.getParent(); 12216 let writableNode; 12217 const format = self2.getFormat(); 12218 const style = self2.getStyle(); 12219 const detail = self2.__detail; 12220 let hasReplacedSelf = false; 12221 let startTextPoint = null; 12222 let endTextPoint = null; 12223 const selection = $getSelection(); 12224 if ($isRangeSelection(selection)) { 12225 const [startPoint, endPoint] = selection.isBackward() ? [selection.focus, selection.anchor] : [selection.anchor, selection.focus]; 12226 if (startPoint.type === "text" && startPoint.key === key) { 12227 startTextPoint = startPoint; 12228 } 12229 if (endPoint.type === "text" && endPoint.key === key) { 12230 endTextPoint = endPoint; 12231 } 12232 } 12233 if (self2.isSegmented()) { 12234 writableNode = $createTextNode(firstPart); 12235 writableNode.__format = format; 12236 writableNode.__style = style; 12237 writableNode.__detail = detail; 12238 writableNode.__state = $cloneNodeState(self2, writableNode); 12239 hasReplacedSelf = true; 12240 } else { 12241 writableNode = self2.setTextContent(firstPart); 12242 } 12243 const splitNodes = [writableNode]; 12244 for (let i2 = 1; i2 < partsLength; i2++) { 12245 const part = parts[i2]; 12246 const sibling = $createTextNode(part); 12247 sibling.__format = format; 12248 sibling.__style = style; 12249 sibling.__detail = detail; 12250 sibling.__state = $cloneNodeState(self2, sibling); 12251 const siblingKey = sibling.__key; 12252 if (compositionKey === key) { 12253 $setCompositionKey(siblingKey); 12254 } 12255 splitNodes.push(sibling); 12256 } 12257 const originalStartOffset = startTextPoint ? startTextPoint.offset : null; 12258 const originalEndOffset = endTextPoint ? endTextPoint.offset : null; 12259 let startOffset = 0; 12260 for (const node of splitNodes) { 12261 if (!(startTextPoint || endTextPoint)) { 12262 break; 12263 } 12264 const endOffset = startOffset + node.getTextContentSize(); 12265 if (startTextPoint !== null && originalStartOffset !== null && originalStartOffset <= endOffset && originalStartOffset >= startOffset) { 12266 startTextPoint.set(node.getKey(), originalStartOffset - startOffset, "text"); 12267 if (originalStartOffset < endOffset) { 12268 startTextPoint = null; 12269 } 12270 } 12271 if (endTextPoint !== null && originalEndOffset !== null && originalEndOffset <= endOffset && originalEndOffset >= startOffset) { 12272 endTextPoint.set(node.getKey(), originalEndOffset - startOffset, "text"); 12273 break; 12274 } 12275 startOffset = endOffset; 12276 } 12277 if (parent !== null) { 12278 internalMarkSiblingsAsDirty(this); 12279 const writableParent = parent.getWritable(); 12280 const insertionIndex = this.getIndexWithinParent(); 12281 if (hasReplacedSelf) { 12282 writableParent.splice(insertionIndex, 0, splitNodes); 12283 this.remove(); 12284 } else { 12285 writableParent.splice(insertionIndex, 1, splitNodes); 12286 } 12287 if ($isRangeSelection(selection)) { 12288 $updateElementSelectionOnCreateDeleteNode(selection, parent, insertionIndex, partsLength - 1); 12289 } 12290 } 12291 return splitNodes; 12292 } 12293 /** 12294 * Merges the target TextNode into this TextNode, removing the target node. 12295 * 12296 * @param target - the TextNode to merge into this one. 12297 * 12298 * @returns this TextNode. 12299 */ 12300 mergeWithSibling(target) { 12301 const isBefore = target === this.getPreviousSibling(); 12302 if (!isBefore && target !== this.getNextSibling()) { 12303 { 12304 formatDevErrorMessage(`mergeWithSibling: sibling must be a previous or next sibling`); 12305 } 12306 } 12307 const key = this.__key; 12308 const targetKey = target.__key; 12309 const text2 = this.__text; 12310 const textLength = text2.length; 12311 const compositionKey = $getCompositionKey(); 12312 if (compositionKey === targetKey) { 12313 $setCompositionKey(key); 12314 } 12315 const selection = $getSelection(); 12316 if ($isRangeSelection(selection)) { 12317 const anchor = selection.anchor; 12318 const focus = selection.focus; 12319 if (anchor !== null && anchor.key === targetKey) { 12320 adjustPointOffsetForMergedSibling(anchor, isBefore, key, target, textLength); 12321 } 12322 if (focus !== null && focus.key === targetKey) { 12323 adjustPointOffsetForMergedSibling(focus, isBefore, key, target, textLength); 12324 } 12325 } 12326 const targetText = target.__text; 12327 const newText = isBefore ? targetText + text2 : text2 + targetText; 12328 this.setTextContent(newText); 12329 const writableSelf = this.getWritable(); 12330 target.remove(); 12331 return writableSelf; 12332 } 12333 /** 12334 * This method is meant to be overridden by TextNode subclasses to control the behavior of those nodes 12335 * when used with the registerLexicalTextEntity function. If you're using registerLexicalTextEntity, the 12336 * node class that you create and replace matched text with should return true from this method. 12337 * 12338 * @returns true if the node is to be treated as a "text entity", false otherwise. 12339 */ 12340 isTextEntity() { 12341 return false; 12342 } 12343 }; 12344 function convertSpanElement(domNode) { 12345 const span = domNode; 12346 const style = span.style; 12347 return { 12348 forChild: applyTextFormatFromStyle(style), 12349 node: null 12350 }; 12351 } 12352 function convertBringAttentionToElement(domNode) { 12353 const b3 = domNode; 12354 const hasNormalFontWeight = b3.style.fontWeight === "normal"; 12355 return { 12356 forChild: applyTextFormatFromStyle(b3.style, hasNormalFontWeight ? void 0 : "bold"), 12357 node: null 12358 }; 12359 } 12360 var preParentCache = /* @__PURE__ */ new WeakMap(); 12361 function isNodePre(node) { 12362 if (!isHTMLElement(node)) { 12363 return false; 12364 } else if (node.nodeName === "PRE") { 12365 return true; 12366 } 12367 const whiteSpace = node.style.whiteSpace; 12368 return typeof whiteSpace === "string" && whiteSpace.startsWith("pre"); 12369 } 12370 function findParentPreDOMNode(node) { 12371 let cached; 12372 let parent = node.parentNode; 12373 const visited = [node]; 12374 while (parent !== null && (cached = preParentCache.get(parent)) === void 0 && !isNodePre(parent)) { 12375 visited.push(parent); 12376 parent = parent.parentNode; 12377 } 12378 const resultNode = cached === void 0 ? parent : cached; 12379 for (let i2 = 0; i2 < visited.length; i2++) { 12380 preParentCache.set(visited[i2], resultNode); 12381 } 12382 return resultNode; 12383 } 12384 function $convertTextDOMNode(domNode) { 12385 const domNode_ = domNode; 12386 const parentDom = domNode.parentElement; 12387 if (!(parentDom !== null)) { 12388 formatDevErrorMessage(`Expected parentElement of Text not to be null`); 12389 } 12390 let textContent = domNode_.textContent || ""; 12391 if (findParentPreDOMNode(domNode_) !== null) { 12392 const parts = textContent.split(/(\r?\n|\t)/); 12393 const nodes = []; 12394 const length = parts.length; 12395 for (let i2 = 0; i2 < length; i2++) { 12396 const part = parts[i2]; 12397 if (part === "\n" || part === "\r\n") { 12398 nodes.push($createLineBreakNode()); 12399 } else if (part === " ") { 12400 nodes.push($createTabNode()); 12401 } else if (part !== "") { 12402 nodes.push($createTextNode(part)); 12403 } 12404 } 12405 return { 12406 node: nodes 12407 }; 12408 } 12409 textContent = textContent.replace(/\r/g, "").replace(/[ \t\n]+/g, " "); 12410 if (textContent === "") { 12411 return { 12412 node: null 12413 }; 12414 } 12415 if (textContent[0] === " ") { 12416 let previousText = domNode_; 12417 let isStartOfLine = true; 12418 while (previousText !== null && (previousText = findTextInLine(previousText, false)) !== null) { 12419 const previousTextContent = previousText.textContent || ""; 12420 if (previousTextContent.length > 0) { 12421 if (/[ \t\n]$/.test(previousTextContent)) { 12422 textContent = textContent.slice(1); 12423 } 12424 isStartOfLine = false; 12425 break; 12426 } 12427 } 12428 if (isStartOfLine) { 12429 textContent = textContent.slice(1); 12430 } 12431 } 12432 if (textContent[textContent.length - 1] === " ") { 12433 let nextText = domNode_; 12434 let isEndOfLine = true; 12435 while (nextText !== null && (nextText = findTextInLine(nextText, true)) !== null) { 12436 const nextTextContent = (nextText.textContent || "").replace(/^( |\t|\r?\n)+/, ""); 12437 if (nextTextContent.length > 0) { 12438 isEndOfLine = false; 12439 break; 12440 } 12441 } 12442 if (isEndOfLine) { 12443 textContent = textContent.slice(0, textContent.length - 1); 12444 } 12445 } 12446 if (textContent === "") { 12447 return { 12448 node: null 12449 }; 12450 } 12451 return { 12452 node: $createTextNode(textContent) 12453 }; 12454 } 12455 function findTextInLine(text2, forward) { 12456 let node = text2; 12457 while (true) { 12458 let sibling; 12459 while ((sibling = forward ? node.nextSibling : node.previousSibling) === null) { 12460 const parentElement = node.parentElement; 12461 if (parentElement === null) { 12462 return null; 12463 } 12464 node = parentElement; 12465 } 12466 node = sibling; 12467 if (isHTMLElement(node)) { 12468 const display = node.style.display; 12469 if (display === "" && !isInlineDomNode(node) || display !== "" && !display.startsWith("inline")) { 12470 return null; 12471 } 12472 } 12473 let descendant = node; 12474 while ((descendant = forward ? node.firstChild : node.lastChild) !== null) { 12475 node = descendant; 12476 } 12477 if (isDOMTextNode(node)) { 12478 return node; 12479 } else if (node.nodeName === "BR") { 12480 return null; 12481 } 12482 } 12483 } 12484 var nodeNameToTextFormat = { 12485 code: "code", 12486 em: "italic", 12487 i: "italic", 12488 mark: "highlight", 12489 s: "strikethrough", 12490 strong: "bold", 12491 sub: "subscript", 12492 sup: "superscript", 12493 u: "underline" 12494 }; 12495 function convertTextFormatElement(domNode) { 12496 const format = nodeNameToTextFormat[domNode.nodeName.toLowerCase()]; 12497 if (format === void 0) { 12498 return { 12499 node: null 12500 }; 12501 } 12502 return { 12503 forChild: applyTextFormatFromStyle(domNode.style, format), 12504 node: null 12505 }; 12506 } 12507 function $createTextNode(text2 = "") { 12508 return $applyNodeReplacement(new TextNode(text2)); 12509 } 12510 function $isTextNode(node) { 12511 return node instanceof TextNode; 12512 } 12513 function applyTextFormatFromStyle(style, shouldApply) { 12514 const fontWeight = style.fontWeight; 12515 const textDecoration = style.textDecoration.split(" "); 12516 const hasBoldFontWeight = fontWeight === "700" || fontWeight === "bold"; 12517 const hasLinethroughTextDecoration = textDecoration.includes("line-through"); 12518 const hasItalicFontStyle = style.fontStyle === "italic"; 12519 const hasUnderlineTextDecoration = textDecoration.includes("underline"); 12520 const verticalAlign = style.verticalAlign; 12521 return (lexicalNode) => { 12522 if (!$isTextNode(lexicalNode)) { 12523 return lexicalNode; 12524 } 12525 if (hasBoldFontWeight && !lexicalNode.hasFormat("bold")) { 12526 lexicalNode.toggleFormat("bold"); 12527 } 12528 if (hasLinethroughTextDecoration && !lexicalNode.hasFormat("strikethrough")) { 12529 lexicalNode.toggleFormat("strikethrough"); 12530 } 12531 if (hasItalicFontStyle && !lexicalNode.hasFormat("italic")) { 12532 lexicalNode.toggleFormat("italic"); 12533 } 12534 if (hasUnderlineTextDecoration && !lexicalNode.hasFormat("underline")) { 12535 lexicalNode.toggleFormat("underline"); 12536 } 12537 if (verticalAlign === "sub" && !lexicalNode.hasFormat("subscript")) { 12538 lexicalNode.toggleFormat("subscript"); 12539 } 12540 if (verticalAlign === "super" && !lexicalNode.hasFormat("superscript")) { 12541 lexicalNode.toggleFormat("superscript"); 12542 } 12543 if (shouldApply && !lexicalNode.hasFormat(shouldApply)) { 12544 lexicalNode.toggleFormat(shouldApply); 12545 } 12546 return lexicalNode; 12547 }; 12548 } 12549 var TabNode = class _TabNode extends TextNode { 12550 static getType() { 12551 return "tab"; 12552 } 12553 static clone(node) { 12554 return new _TabNode(node.__key); 12555 } 12556 constructor(key) { 12557 super(" ", key); 12558 this.__detail = IS_UNMERGEABLE; 12559 } 12560 static importDOM() { 12561 return null; 12562 } 12563 createDOM(config) { 12564 const dom = super.createDOM(config); 12565 const classNames = getCachedClassNameArray(config.theme, "tab"); 12566 if (classNames !== void 0) { 12567 const domClassList = dom.classList; 12568 domClassList.add(...classNames); 12569 } 12570 return dom; 12571 } 12572 static importJSON(serializedTabNode) { 12573 return $createTabNode().updateFromJSON(serializedTabNode); 12574 } 12575 setTextContent(text2) { 12576 if (!(text2 === " " || text2 === "")) { 12577 formatDevErrorMessage(`TabNode does not support setTextContent`); 12578 } 12579 return super.setTextContent(" "); 12580 } 12581 spliceText(offset3, delCount, newText, moveSelection) { 12582 if (!(newText === "" && delCount === 0 || newText === " " && delCount === 1)) { 12583 formatDevErrorMessage(`TabNode does not support spliceText`); 12584 } 12585 return this; 12586 } 12587 setDetail(detail) { 12588 if (!(detail === IS_UNMERGEABLE)) { 12589 formatDevErrorMessage(`TabNode does not support setDetail`); 12590 } 12591 return this; 12592 } 12593 setMode(type) { 12594 if (!(type === "normal")) { 12595 formatDevErrorMessage(`TabNode does not support setMode`); 12596 } 12597 return this; 12598 } 12599 canInsertTextBefore() { 12600 return false; 12601 } 12602 canInsertTextAfter() { 12603 return false; 12604 } 12605 }; 12606 function $createTabNode() { 12607 return $applyNodeReplacement(new TabNode()); 12608 } 12609 function $isTabNode(node) { 12610 return node instanceof TabNode; 12611 } 12612 var Point = class { 12613 key; 12614 offset; 12615 type; 12616 _selection; 12617 constructor(key, offset3, type) { 12618 { 12619 Object.defineProperty(this, "_selection", { 12620 enumerable: false, 12621 writable: true 12622 }); 12623 } 12624 this._selection = null; 12625 this.key = key; 12626 this.offset = offset3; 12627 this.type = type; 12628 } 12629 is(point) { 12630 return this.key === point.key && this.offset === point.offset && this.type === point.type; 12631 } 12632 isBefore(b3) { 12633 if (this.key === b3.key) { 12634 return this.offset < b3.offset; 12635 } 12636 const aCaret = $normalizeCaret($caretFromPoint(this, "next")); 12637 const bCaret = $normalizeCaret($caretFromPoint(b3, "next")); 12638 return $comparePointCaretNext(aCaret, bCaret) < 0; 12639 } 12640 getNode() { 12641 const key = this.key; 12642 const node = $getNodeByKey(key); 12643 if (node === null) { 12644 { 12645 formatDevErrorMessage(`Point.getNode: node not found`); 12646 } 12647 } 12648 return node; 12649 } 12650 set(key, offset3, type, onlyIfChanged) { 12651 const selection = this._selection; 12652 const oldKey = this.key; 12653 if (onlyIfChanged && this.key === key && this.offset === offset3 && this.type === type) { 12654 return; 12655 } 12656 this.key = key; 12657 this.offset = offset3; 12658 this.type = type; 12659 { 12660 const node = $getNodeByKey(key); 12661 if (!(type === "text" ? $isTextNode(node) : $isElementNode(node))) { 12662 formatDevErrorMessage(`PointType.set: node with key ${key} is ${node ? node.__type : "[not found]"} and can not be used for a ${type} point`); 12663 } 12664 } 12665 if (!isCurrentlyReadOnlyMode()) { 12666 if ($getCompositionKey() === oldKey) { 12667 $setCompositionKey(key); 12668 } 12669 if (selection !== null) { 12670 selection.setCachedNodes(null); 12671 selection.dirty = true; 12672 } 12673 } 12674 } 12675 }; 12676 function $createPoint(key, offset3, type) { 12677 return new Point(key, offset3, type); 12678 } 12679 function selectPointOnNode(point, node) { 12680 let key = node.__key; 12681 let offset3 = point.offset; 12682 let type = "element"; 12683 if ($isTextNode(node)) { 12684 type = "text"; 12685 const textContentLength = node.getTextContentSize(); 12686 if (offset3 > textContentLength) { 12687 offset3 = textContentLength; 12688 } 12689 } else if (!$isElementNode(node)) { 12690 const nextSibling = node.getNextSibling(); 12691 if ($isTextNode(nextSibling)) { 12692 key = nextSibling.__key; 12693 offset3 = 0; 12694 type = "text"; 12695 } else { 12696 const parentNode = node.getParent(); 12697 if (parentNode) { 12698 key = parentNode.__key; 12699 offset3 = node.getIndexWithinParent() + 1; 12700 } 12701 } 12702 } 12703 point.set(key, offset3, type); 12704 } 12705 function $moveSelectionPointToEnd(point, node) { 12706 if ($isElementNode(node)) { 12707 const lastNode = node.getLastDescendant(); 12708 if ($isElementNode(lastNode) || $isTextNode(lastNode)) { 12709 selectPointOnNode(point, lastNode); 12710 } else { 12711 selectPointOnNode(point, node); 12712 } 12713 } else { 12714 selectPointOnNode(point, node); 12715 } 12716 } 12717 function $transferStartingElementPointToTextPoint(start3, end, format, style) { 12718 const element = start3.getNode(); 12719 const placementNode = element.getChildAtIndex(start3.offset); 12720 const textNode = $createTextNode(); 12721 textNode.setFormat(format); 12722 textNode.setStyle(style); 12723 if ($isParagraphNode(placementNode)) { 12724 placementNode.splice(0, 0, [textNode]); 12725 } else { 12726 const target = $isRootNode(element) ? $createParagraphNode().append(textNode) : textNode; 12727 if (placementNode === null) { 12728 element.append(target); 12729 } else { 12730 placementNode.insertBefore(target); 12731 } 12732 } 12733 if (start3.is(end)) { 12734 end.set(textNode.__key, 0, "text"); 12735 } 12736 start3.set(textNode.__key, 0, "text"); 12737 } 12738 var NodeSelection = class _NodeSelection { 12739 _nodes; 12740 _cachedNodes; 12741 dirty; 12742 constructor(objects) { 12743 this._cachedNodes = null; 12744 this._nodes = objects; 12745 this.dirty = false; 12746 } 12747 getCachedNodes() { 12748 return this._cachedNodes; 12749 } 12750 setCachedNodes(nodes) { 12751 this._cachedNodes = nodes; 12752 } 12753 is(selection) { 12754 if (!$isNodeSelection(selection)) { 12755 return false; 12756 } 12757 const a2 = this._nodes; 12758 const b3 = selection._nodes; 12759 return a2.size === b3.size && Array.from(a2).every((key) => b3.has(key)); 12760 } 12761 isCollapsed() { 12762 return false; 12763 } 12764 isBackward() { 12765 return false; 12766 } 12767 getStartEndPoints() { 12768 return null; 12769 } 12770 add(key) { 12771 this.dirty = true; 12772 this._nodes.add(key); 12773 this._cachedNodes = null; 12774 } 12775 delete(key) { 12776 this.dirty = true; 12777 this._nodes.delete(key); 12778 this._cachedNodes = null; 12779 } 12780 clear() { 12781 this.dirty = true; 12782 this._nodes.clear(); 12783 this._cachedNodes = null; 12784 } 12785 has(key) { 12786 return this._nodes.has(key); 12787 } 12788 clone() { 12789 return new _NodeSelection(new Set(this._nodes)); 12790 } 12791 extract() { 12792 return this.getNodes(); 12793 } 12794 insertRawText(text2) { 12795 } 12796 insertText() { 12797 } 12798 insertNodes(nodes) { 12799 const selectedNodes = this.getNodes(); 12800 const selectedNodesLength = selectedNodes.length; 12801 const lastSelectedNode = selectedNodes[selectedNodesLength - 1]; 12802 let selectionAtEnd; 12803 if ($isTextNode(lastSelectedNode)) { 12804 selectionAtEnd = lastSelectedNode.select(); 12805 } else { 12806 const index = lastSelectedNode.getIndexWithinParent() + 1; 12807 selectionAtEnd = lastSelectedNode.getParentOrThrow().select(index, index); 12808 } 12809 selectionAtEnd.insertNodes(nodes); 12810 for (let i2 = 0; i2 < selectedNodesLength; i2++) { 12811 selectedNodes[i2].remove(); 12812 } 12813 } 12814 getNodes() { 12815 const cachedNodes = this._cachedNodes; 12816 if (cachedNodes !== null) { 12817 return cachedNodes; 12818 } 12819 const objects = this._nodes; 12820 const nodes = []; 12821 for (const object of objects) { 12822 const node = $getNodeByKey(object); 12823 if (node !== null) { 12824 nodes.push(node); 12825 } 12826 } 12827 if (!isCurrentlyReadOnlyMode()) { 12828 this._cachedNodes = nodes; 12829 } 12830 return nodes; 12831 } 12832 getTextContent() { 12833 const nodes = this.getNodes(); 12834 let textContent = ""; 12835 for (let i2 = 0; i2 < nodes.length; i2++) { 12836 textContent += nodes[i2].getTextContent(); 12837 } 12838 return textContent; 12839 } 12840 /** 12841 * Remove all nodes in the NodeSelection. If there were any nodes, 12842 * replace the selection with a new RangeSelection at the previous 12843 * location of the first node. 12844 */ 12845 deleteNodes() { 12846 const nodes = this.getNodes(); 12847 if (($getSelection() || $getPreviousSelection()) === this && nodes[0]) { 12848 const firstCaret = $getSiblingCaret(nodes[0], "next"); 12849 $setSelectionFromCaretRange($getCaretRange(firstCaret, firstCaret)); 12850 } 12851 for (const node of nodes) { 12852 node.remove(); 12853 } 12854 } 12855 }; 12856 function $isRangeSelection(x3) { 12857 return x3 instanceof RangeSelection; 12858 } 12859 var RangeSelection = class _RangeSelection { 12860 format; 12861 style; 12862 anchor; 12863 focus; 12864 _cachedNodes; 12865 dirty; 12866 constructor(anchor, focus, format, style) { 12867 this.anchor = anchor; 12868 this.focus = focus; 12869 anchor._selection = this; 12870 focus._selection = this; 12871 this._cachedNodes = null; 12872 this.format = format; 12873 this.style = style; 12874 this.dirty = false; 12875 } 12876 getCachedNodes() { 12877 return this._cachedNodes; 12878 } 12879 setCachedNodes(nodes) { 12880 this._cachedNodes = nodes; 12881 } 12882 /** 12883 * Used to check if the provided selections is equal to this one by value, 12884 * including anchor, focus, format, and style properties. 12885 * @param selection - the Selection to compare this one to. 12886 * @returns true if the Selections are equal, false otherwise. 12887 */ 12888 is(selection) { 12889 if (!$isRangeSelection(selection)) { 12890 return false; 12891 } 12892 return this.anchor.is(selection.anchor) && this.focus.is(selection.focus) && this.format === selection.format && this.style === selection.style; 12893 } 12894 /** 12895 * Returns whether the Selection is "collapsed", meaning the anchor and focus are 12896 * the same node and have the same offset. 12897 * 12898 * @returns true if the Selection is collapsed, false otherwise. 12899 */ 12900 isCollapsed() { 12901 return this.anchor.is(this.focus); 12902 } 12903 /** 12904 * Gets all the nodes in the Selection. Uses caching to make it generally suitable 12905 * for use in hot paths. 12906 * 12907 * See also the {@link CaretRange} APIs (starting with 12908 * {@link $caretRangeFromSelection}), which are likely to provide a better 12909 * foundation for any operation where partial selection is relevant 12910 * (e.g. the anchor or focus are inside an ElementNode and TextNode) 12911 * 12912 * @returns an Array containing all the nodes in the Selection 12913 */ 12914 getNodes() { 12915 const cachedNodes = this._cachedNodes; 12916 if (cachedNodes !== null) { 12917 return cachedNodes; 12918 } 12919 const range2 = $getCaretRangeInDirection($caretRangeFromSelection(this), "next"); 12920 const nodes = $getNodesFromCaretRangeCompat(range2); 12921 { 12922 if (this.isCollapsed() && nodes.length > 1) { 12923 { 12924 formatDevErrorMessage(`RangeSelection.getNodes() returned ${String(nodes.length)} > 1 nodes in a collapsed selection`); 12925 } 12926 } 12927 } 12928 if (!isCurrentlyReadOnlyMode()) { 12929 this._cachedNodes = nodes; 12930 } 12931 return nodes; 12932 } 12933 /** 12934 * Sets this Selection to be of type "text" at the provided anchor and focus values. 12935 * 12936 * @param anchorNode - the anchor node to set on the Selection 12937 * @param anchorOffset - the offset to set on the Selection 12938 * @param focusNode - the focus node to set on the Selection 12939 * @param focusOffset - the focus offset to set on the Selection 12940 */ 12941 setTextNodeRange(anchorNode, anchorOffset, focusNode, focusOffset) { 12942 this.anchor.set(anchorNode.__key, anchorOffset, "text"); 12943 this.focus.set(focusNode.__key, focusOffset, "text"); 12944 } 12945 /** 12946 * Gets the (plain) text content of all the nodes in the selection. 12947 * 12948 * @returns a string representing the text content of all the nodes in the Selection 12949 */ 12950 getTextContent() { 12951 const nodes = this.getNodes(); 12952 if (nodes.length === 0) { 12953 return ""; 12954 } 12955 const firstNode = nodes[0]; 12956 const lastNode = nodes[nodes.length - 1]; 12957 const anchor = this.anchor; 12958 const focus = this.focus; 12959 const isBefore = anchor.isBefore(focus); 12960 const [anchorOffset, focusOffset] = $getCharacterOffsets(this); 12961 let textContent = ""; 12962 let prevWasElement = true; 12963 for (let i2 = 0; i2 < nodes.length; i2++) { 12964 const node = nodes[i2]; 12965 if ($isElementNode(node) && !node.isInline()) { 12966 if (!prevWasElement) { 12967 textContent += "\n"; 12968 } 12969 if (node.isEmpty()) { 12970 prevWasElement = false; 12971 } else { 12972 prevWasElement = true; 12973 } 12974 } else { 12975 prevWasElement = false; 12976 if ($isTextNode(node)) { 12977 let text2 = node.getTextContent(); 12978 if (node === firstNode) { 12979 if (node === lastNode) { 12980 if (anchor.type !== "element" || focus.type !== "element" || focus.offset === anchor.offset) { 12981 text2 = anchorOffset < focusOffset ? text2.slice(anchorOffset, focusOffset) : text2.slice(focusOffset, anchorOffset); 12982 } 12983 } else { 12984 text2 = isBefore ? text2.slice(anchorOffset) : text2.slice(focusOffset); 12985 } 12986 } else if (node === lastNode) { 12987 text2 = isBefore ? text2.slice(0, focusOffset) : text2.slice(0, anchorOffset); 12988 } 12989 textContent += text2; 12990 } else if (($isDecoratorNode(node) || $isLineBreakNode(node)) && (node !== lastNode || !this.isCollapsed())) { 12991 textContent += node.getTextContent(); 12992 } 12993 } 12994 } 12995 return textContent; 12996 } 12997 /** 12998 * Attempts to map a DOM selection range onto this Lexical Selection, 12999 * setting the anchor, focus, and type accordingly 13000 * 13001 * @param range a DOM Selection range conforming to the StaticRange interface. 13002 */ 13003 applyDOMRange(range2) { 13004 const editor = getActiveEditor(); 13005 const currentEditorState = editor.getEditorState(); 13006 const lastSelection = currentEditorState._selection; 13007 const resolvedSelectionPoints = $internalResolveSelectionPoints(range2.startContainer, range2.startOffset, range2.endContainer, range2.endOffset, editor, lastSelection); 13008 if (resolvedSelectionPoints === null) { 13009 return; 13010 } 13011 const [anchorPoint, focusPoint] = resolvedSelectionPoints; 13012 this.anchor.set(anchorPoint.key, anchorPoint.offset, anchorPoint.type, true); 13013 this.focus.set(focusPoint.key, focusPoint.offset, focusPoint.type, true); 13014 $normalizeSelection(this); 13015 } 13016 /** 13017 * Creates a new RangeSelection, copying over all the property values from this one. 13018 * 13019 * @returns a new RangeSelection with the same property values as this one. 13020 */ 13021 clone() { 13022 const anchor = this.anchor; 13023 const focus = this.focus; 13024 const selection = new _RangeSelection($createPoint(anchor.key, anchor.offset, anchor.type), $createPoint(focus.key, focus.offset, focus.type), this.format, this.style); 13025 return selection; 13026 } 13027 /** 13028 * Toggles the provided format on all the TextNodes in the Selection. 13029 * 13030 * @param format a string TextFormatType to toggle on the TextNodes in the selection 13031 */ 13032 toggleFormat(format) { 13033 this.format = toggleTextFormatType(this.format, format, null); 13034 this.dirty = true; 13035 } 13036 /** 13037 * Sets the value of the format property on the Selection 13038 * 13039 * @param format - the format to set at the value of the format property. 13040 */ 13041 setFormat(format) { 13042 this.format = format; 13043 this.dirty = true; 13044 } 13045 /** 13046 * Sets the value of the style property on the Selection 13047 * 13048 * @param style - the style to set at the value of the style property. 13049 */ 13050 setStyle(style) { 13051 this.style = style; 13052 this.dirty = true; 13053 } 13054 /** 13055 * Returns whether the provided TextFormatType is present on the Selection. This will be true if any node in the Selection 13056 * has the specified format. 13057 * 13058 * @param type the TextFormatType to check for. 13059 * @returns true if the provided format is currently toggled on on the Selection, false otherwise. 13060 */ 13061 hasFormat(type) { 13062 const formatFlag = TEXT_TYPE_TO_FORMAT[type]; 13063 return (this.format & formatFlag) !== 0; 13064 } 13065 /** 13066 * Attempts to insert the provided text into the EditorState at the current Selection. 13067 * converts tabs, newlines, and carriage returns into LexicalNodes. 13068 * 13069 * @param text the text to insert into the Selection 13070 */ 13071 insertRawText(text2) { 13072 const parts = text2.split(/(\r?\n|\t)/); 13073 const nodes = []; 13074 const length = parts.length; 13075 for (let i2 = 0; i2 < length; i2++) { 13076 const part = parts[i2]; 13077 if (part === "\n" || part === "\r\n") { 13078 nodes.push($createLineBreakNode()); 13079 } else if (part === " ") { 13080 nodes.push($createTabNode()); 13081 } else { 13082 nodes.push($createTextNode(part)); 13083 } 13084 } 13085 this.insertNodes(nodes); 13086 } 13087 /** 13088 * Insert the provided text into the EditorState at the current Selection. 13089 * 13090 * @param text the text to insert into the Selection 13091 */ 13092 insertText(text2) { 13093 const anchor = this.anchor; 13094 const focus = this.focus; 13095 const format = this.format; 13096 const style = this.style; 13097 let firstPoint = anchor; 13098 let endPoint = focus; 13099 if (!this.isCollapsed() && focus.isBefore(anchor)) { 13100 firstPoint = focus; 13101 endPoint = anchor; 13102 } 13103 if (firstPoint.type === "element") { 13104 $transferStartingElementPointToTextPoint(firstPoint, endPoint, format, style); 13105 } 13106 if (endPoint.type === "element") { 13107 $setPointFromCaret(endPoint, $normalizeCaret($caretFromPoint(endPoint, "next"))); 13108 } 13109 const startOffset = firstPoint.offset; 13110 let endOffset = endPoint.offset; 13111 const selectedNodes = this.getNodes(); 13112 const selectedNodesLength = selectedNodes.length; 13113 let firstNode = selectedNodes[0]; 13114 if (!$isTextNode(firstNode)) { 13115 { 13116 formatDevErrorMessage(`insertText: first node is not a text node`); 13117 } 13118 } 13119 const firstNodeText = firstNode.getTextContent(); 13120 const firstNodeTextLength = firstNodeText.length; 13121 const firstNodeParent = firstNode.getParentOrThrow(); 13122 const lastIndex = selectedNodesLength - 1; 13123 let lastNode = selectedNodes[lastIndex]; 13124 if (selectedNodesLength === 1 && endPoint.type === "element") { 13125 endOffset = firstNodeTextLength; 13126 endPoint.set(firstPoint.key, endOffset, "text"); 13127 } 13128 if (this.isCollapsed() && startOffset === firstNodeTextLength && ($isTokenOrSegmented(firstNode) || !firstNode.canInsertTextAfter() || !firstNodeParent.canInsertTextAfter() && firstNode.getNextSibling() === null)) { 13129 let nextSibling = firstNode.getNextSibling(); 13130 if (!$isTextNode(nextSibling) || !nextSibling.canInsertTextBefore() || $isTokenOrSegmented(nextSibling)) { 13131 nextSibling = $createTextNode(); 13132 nextSibling.setFormat(format); 13133 nextSibling.setStyle(style); 13134 if (!firstNodeParent.canInsertTextAfter()) { 13135 firstNodeParent.insertAfter(nextSibling); 13136 } else { 13137 firstNode.insertAfter(nextSibling); 13138 } 13139 } 13140 nextSibling.select(0, 0); 13141 firstNode = nextSibling; 13142 if (text2 !== "") { 13143 this.insertText(text2); 13144 return; 13145 } 13146 } else if (this.isCollapsed() && startOffset === 0 && ($isTokenOrSegmented(firstNode) || !firstNode.canInsertTextBefore() || !firstNodeParent.canInsertTextBefore() && firstNode.getPreviousSibling() === null)) { 13147 let prevSibling = firstNode.getPreviousSibling(); 13148 if (!$isTextNode(prevSibling) || $isTokenOrSegmented(prevSibling)) { 13149 prevSibling = $createTextNode(); 13150 prevSibling.setFormat(format); 13151 if (!firstNodeParent.canInsertTextBefore()) { 13152 firstNodeParent.insertBefore(prevSibling); 13153 } else { 13154 firstNode.insertBefore(prevSibling); 13155 } 13156 } 13157 prevSibling.select(); 13158 firstNode = prevSibling; 13159 if (text2 !== "") { 13160 this.insertText(text2); 13161 return; 13162 } 13163 } else if (firstNode.isSegmented() && startOffset !== firstNodeTextLength) { 13164 const textNode = $createTextNode(firstNode.getTextContent()); 13165 textNode.setFormat(format); 13166 firstNode.replace(textNode); 13167 firstNode = textNode; 13168 } else if (!this.isCollapsed() && text2 !== "") { 13169 const lastNodeParent = lastNode.getParent(); 13170 if (!firstNodeParent.canInsertTextBefore() || !firstNodeParent.canInsertTextAfter() || $isElementNode(lastNodeParent) && (!lastNodeParent.canInsertTextBefore() || !lastNodeParent.canInsertTextAfter())) { 13171 this.insertText(""); 13172 $normalizeSelectionPointsForBoundaries(this.anchor, this.focus); 13173 this.insertText(text2); 13174 return; 13175 } 13176 } 13177 if (selectedNodesLength === 1) { 13178 if ($isTokenOrTab(firstNode)) { 13179 const textNode = $createTextNode(text2); 13180 textNode.select(); 13181 firstNode.replace(textNode); 13182 return; 13183 } 13184 const firstNodeFormat = firstNode.getFormat(); 13185 const firstNodeStyle = firstNode.getStyle(); 13186 if (startOffset === endOffset && (firstNodeFormat !== format || firstNodeStyle !== style)) { 13187 if (firstNode.getTextContent() === "") { 13188 firstNode.setFormat(format); 13189 firstNode.setStyle(style); 13190 } else { 13191 const textNode = $createTextNode(text2); 13192 textNode.setFormat(format); 13193 textNode.setStyle(style); 13194 textNode.select(); 13195 if (startOffset === 0) { 13196 firstNode.insertBefore(textNode, false); 13197 } else { 13198 const [targetNode] = firstNode.splitText(startOffset); 13199 targetNode.insertAfter(textNode, false); 13200 } 13201 if (textNode.isComposing() && this.anchor.type === "text") { 13202 this.anchor.offset -= text2.length; 13203 } 13204 return; 13205 } 13206 } else if ($isTabNode(firstNode)) { 13207 const textNode = $createTextNode(text2); 13208 textNode.setFormat(format); 13209 textNode.setStyle(style); 13210 textNode.select(); 13211 firstNode.replace(textNode); 13212 return; 13213 } 13214 const delCount = endOffset - startOffset; 13215 firstNode = firstNode.spliceText(startOffset, delCount, text2, true); 13216 if (firstNode.getTextContent() === "") { 13217 firstNode.remove(); 13218 } else if (this.anchor.type === "text") { 13219 this.format = firstNodeFormat; 13220 this.style = firstNodeStyle; 13221 if (firstNode.isComposing()) { 13222 this.anchor.offset -= text2.length; 13223 } 13224 } 13225 } else { 13226 const markedNodeKeysForKeep = /* @__PURE__ */ new Set([...firstNode.getParentKeys(), ...lastNode.getParentKeys()]); 13227 const firstElement = $isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow(); 13228 let lastElement = $isElementNode(lastNode) ? lastNode : lastNode.getParentOrThrow(); 13229 let lastElementChild = lastNode; 13230 if (!firstElement.is(lastElement) && lastElement.isInline()) { 13231 do { 13232 lastElementChild = lastElement; 13233 lastElement = lastElement.getParentOrThrow(); 13234 } while (lastElement.isInline()); 13235 } 13236 if (endPoint.type === "text" && (endOffset !== 0 || lastNode.getTextContent() === "") || endPoint.type === "element" && lastNode.getIndexWithinParent() < endOffset) { 13237 if ($isTextNode(lastNode) && !$isTokenOrTab(lastNode) && endOffset !== lastNode.getTextContentSize()) { 13238 if (lastNode.isSegmented()) { 13239 const textNode = $createTextNode(lastNode.getTextContent()); 13240 lastNode.replace(textNode); 13241 lastNode = textNode; 13242 } 13243 if (!$isRootNode(endPoint.getNode()) && endPoint.type === "text") { 13244 lastNode = lastNode.spliceText(0, endOffset, ""); 13245 } 13246 markedNodeKeysForKeep.add(lastNode.__key); 13247 } else { 13248 const lastNodeParent = lastNode.getParentOrThrow(); 13249 if (!lastNodeParent.canBeEmpty() && lastNodeParent.getChildrenSize() === 1) { 13250 lastNodeParent.remove(); 13251 } else { 13252 lastNode.remove(); 13253 } 13254 } 13255 } else { 13256 markedNodeKeysForKeep.add(lastNode.__key); 13257 } 13258 const lastNodeChildren = lastElement.getChildren(); 13259 const selectedNodesSet = new Set(selectedNodes); 13260 const firstAndLastElementsAreEqual = firstElement.is(lastElement); 13261 const insertionTarget = firstElement.isInline() && firstNode.getNextSibling() === null ? firstElement : firstNode; 13262 for (let i2 = lastNodeChildren.length - 1; i2 >= 0; i2--) { 13263 const lastNodeChild = lastNodeChildren[i2]; 13264 if (lastNodeChild.is(firstNode) || $isElementNode(lastNodeChild) && lastNodeChild.isParentOf(firstNode)) { 13265 break; 13266 } 13267 if (lastNodeChild.isAttached()) { 13268 if (!selectedNodesSet.has(lastNodeChild) || lastNodeChild.is(lastElementChild)) { 13269 if (!firstAndLastElementsAreEqual) { 13270 insertionTarget.insertAfter(lastNodeChild, false); 13271 } 13272 } else { 13273 lastNodeChild.remove(); 13274 } 13275 } 13276 } 13277 if (!firstAndLastElementsAreEqual) { 13278 let parent = lastElement; 13279 let lastRemovedParent = null; 13280 while (parent !== null) { 13281 const children = parent.getChildren(); 13282 const childrenLength = children.length; 13283 if (childrenLength === 0 || children[childrenLength - 1].is(lastRemovedParent)) { 13284 markedNodeKeysForKeep.delete(parent.__key); 13285 lastRemovedParent = parent; 13286 } 13287 parent = parent.getParent(); 13288 } 13289 } 13290 if (!$isTokenOrTab(firstNode)) { 13291 firstNode = firstNode.spliceText(startOffset, firstNodeTextLength - startOffset, text2, true); 13292 if (firstNode.getTextContent() === "") { 13293 firstNode.remove(); 13294 } else if (this.anchor.type === "text") { 13295 this.format = firstNode.getFormat(); 13296 this.style = firstNode.getStyle(); 13297 if (firstNode.isComposing()) { 13298 this.anchor.offset -= text2.length; 13299 } 13300 } 13301 } else if (startOffset === firstNodeTextLength) { 13302 firstNode.select(); 13303 } else { 13304 const textNode = $createTextNode(text2); 13305 textNode.select(); 13306 firstNode.replace(textNode); 13307 } 13308 for (let i2 = 1; i2 < selectedNodesLength; i2++) { 13309 const selectedNode = selectedNodes[i2]; 13310 const key = selectedNode.__key; 13311 if (!markedNodeKeysForKeep.has(key)) { 13312 selectedNode.remove(); 13313 } 13314 } 13315 } 13316 } 13317 /** 13318 * Removes the text in the Selection, adjusting the EditorState accordingly. 13319 */ 13320 removeText() { 13321 const isCurrentSelection = $getSelection() === this; 13322 const newRange = $removeTextFromCaretRange($caretRangeFromSelection(this)); 13323 $updateRangeSelectionFromCaretRange(this, newRange); 13324 if (isCurrentSelection && $getSelection() !== this) { 13325 $setSelection(this); 13326 } 13327 } 13328 // TO-DO: Migrate this method to the new utility function $forEachSelectedTextNode (share similar logic) 13329 /** 13330 * Applies the provided format to the TextNodes in the Selection, splitting or 13331 * merging nodes as necessary. 13332 * 13333 * @param formatType the format type to apply to the nodes in the Selection. 13334 * @param alignWithFormat a 32-bit integer representing formatting flags to align with. 13335 */ 13336 formatText(formatType, alignWithFormat = null) { 13337 if (this.isCollapsed()) { 13338 this.toggleFormat(formatType); 13339 $setCompositionKey(null); 13340 return; 13341 } 13342 const selectedNodes = this.getNodes(); 13343 const selectedTextNodes = []; 13344 for (const selectedNode of selectedNodes) { 13345 if ($isTextNode(selectedNode)) { 13346 selectedTextNodes.push(selectedNode); 13347 } 13348 } 13349 const applyFormatToElements = (alignWith) => { 13350 selectedNodes.forEach((node) => { 13351 if ($isElementNode(node)) { 13352 const newFormat = node.getFormatFlags(formatType, alignWith); 13353 node.setTextFormat(newFormat); 13354 } 13355 }); 13356 }; 13357 const selectedTextNodesLength = selectedTextNodes.length; 13358 if (selectedTextNodesLength === 0) { 13359 this.toggleFormat(formatType); 13360 $setCompositionKey(null); 13361 applyFormatToElements(alignWithFormat); 13362 return; 13363 } 13364 const anchor = this.anchor; 13365 const focus = this.focus; 13366 const isBackward = this.isBackward(); 13367 const startPoint = isBackward ? focus : anchor; 13368 const endPoint = isBackward ? anchor : focus; 13369 let firstIndex = 0; 13370 let firstNode = selectedTextNodes[0]; 13371 let startOffset = startPoint.type === "element" ? 0 : startPoint.offset; 13372 if (startPoint.type === "text" && startOffset === firstNode.getTextContentSize()) { 13373 firstIndex = 1; 13374 firstNode = selectedTextNodes[1]; 13375 startOffset = 0; 13376 } 13377 if (firstNode == null) { 13378 return; 13379 } 13380 const firstNextFormat = firstNode.getFormatFlags(formatType, alignWithFormat); 13381 applyFormatToElements(firstNextFormat); 13382 const lastIndex = selectedTextNodesLength - 1; 13383 let lastNode = selectedTextNodes[lastIndex]; 13384 const endOffset = endPoint.type === "text" ? endPoint.offset : lastNode.getTextContentSize(); 13385 if (firstNode.is(lastNode)) { 13386 if (startOffset === endOffset) { 13387 return; 13388 } 13389 if ($isTokenOrSegmented(firstNode) || startOffset === 0 && endOffset === firstNode.getTextContentSize()) { 13390 firstNode.setFormat(firstNextFormat); 13391 } else { 13392 const splitNodes = firstNode.splitText(startOffset, endOffset); 13393 const replacement = startOffset === 0 ? splitNodes[0] : splitNodes[1]; 13394 replacement.setFormat(firstNextFormat); 13395 if (startPoint.type === "text") { 13396 startPoint.set(replacement.__key, 0, "text"); 13397 } 13398 if (endPoint.type === "text") { 13399 endPoint.set(replacement.__key, endOffset - startOffset, "text"); 13400 } 13401 } 13402 this.format = firstNextFormat; 13403 return; 13404 } 13405 if (startOffset !== 0 && !$isTokenOrSegmented(firstNode)) { 13406 [, firstNode] = firstNode.splitText(startOffset); 13407 startOffset = 0; 13408 } 13409 firstNode.setFormat(firstNextFormat); 13410 const lastNextFormat = lastNode.getFormatFlags(formatType, firstNextFormat); 13411 if (endOffset > 0) { 13412 if (endOffset !== lastNode.getTextContentSize() && !$isTokenOrSegmented(lastNode)) { 13413 [lastNode] = lastNode.splitText(endOffset); 13414 } 13415 lastNode.setFormat(lastNextFormat); 13416 } 13417 for (let i2 = firstIndex + 1; i2 < lastIndex; i2++) { 13418 const textNode = selectedTextNodes[i2]; 13419 const nextFormat = textNode.getFormatFlags(formatType, lastNextFormat); 13420 textNode.setFormat(nextFormat); 13421 } 13422 if (startPoint.type === "text") { 13423 startPoint.set(firstNode.__key, startOffset, "text"); 13424 } 13425 if (endPoint.type === "text") { 13426 endPoint.set(lastNode.__key, endOffset, "text"); 13427 } 13428 this.format = firstNextFormat | lastNextFormat; 13429 } 13430 /** 13431 * Attempts to "intelligently" insert an arbitrary list of Lexical nodes into the EditorState at the 13432 * current Selection according to a set of heuristics that determine how surrounding nodes 13433 * should be changed, replaced, or moved to accommodate the incoming ones. 13434 * 13435 * @param nodes - the nodes to insert 13436 */ 13437 insertNodes(nodes) { 13438 if (nodes.length === 0) { 13439 return; 13440 } 13441 if (!this.isCollapsed()) { 13442 this.removeText(); 13443 } 13444 if (this.anchor.key === "root") { 13445 this.insertParagraph(); 13446 const selection = $getSelection(); 13447 if (!$isRangeSelection(selection)) { 13448 formatDevErrorMessage(`Expected RangeSelection after insertParagraph`); 13449 } 13450 return selection.insertNodes(nodes); 13451 } 13452 const firstPoint = this.isBackward() ? this.focus : this.anchor; 13453 const firstNode = firstPoint.getNode(); 13454 const firstBlock = $findMatchingParent(firstNode, INTERNAL_$isBlock); 13455 const last = nodes[nodes.length - 1]; 13456 if ($isElementNode(firstBlock) && "__language" in firstBlock) { 13457 if ("__language" in nodes[0]) { 13458 this.insertText(nodes[0].getTextContent()); 13459 } else { 13460 const index = $removeTextAndSplitBlock(this); 13461 firstBlock.splice(index, 0, nodes); 13462 last.selectEnd(); 13463 } 13464 return; 13465 } 13466 const notInline = (node) => ($isElementNode(node) || $isDecoratorNode(node)) && !node.isInline(); 13467 if (!nodes.some(notInline)) { 13468 if (!$isElementNode(firstBlock)) { 13469 formatDevErrorMessage(`Expected node ${firstNode.constructor.name} of type ${firstNode.getType()} to have a block ElementNode ancestor`); 13470 } 13471 const index = $removeTextAndSplitBlock(this); 13472 firstBlock.splice(index, 0, nodes); 13473 last.selectEnd(); 13474 return; 13475 } 13476 const blocksParent = $wrapInlineNodes(nodes); 13477 const nodeToSelect = blocksParent.getLastDescendant(); 13478 const blocks = blocksParent.getChildren(); 13479 const isMergeable = (node) => $isElementNode(node) && INTERNAL_$isBlock(node) && !node.isEmpty() && $isElementNode(firstBlock) && (!firstBlock.isEmpty() || firstBlock.canMergeWhenEmpty()); 13480 const shouldInsert = !$isElementNode(firstBlock) || !firstBlock.isEmpty(); 13481 const insertedParagraph = shouldInsert ? this.insertParagraph() : null; 13482 const lastToInsert = blocks[blocks.length - 1]; 13483 let firstToInsert = blocks[0]; 13484 if (isMergeable(firstToInsert)) { 13485 if (!$isElementNode(firstBlock)) { 13486 formatDevErrorMessage(`Expected node ${firstNode.constructor.name} of type ${firstNode.getType()} to have a block ElementNode ancestor`); 13487 } 13488 firstBlock.append(...firstToInsert.getChildren()); 13489 firstToInsert = blocks[1]; 13490 } 13491 if (firstToInsert) { 13492 if (!(firstBlock !== null)) { 13493 formatDevErrorMessage(`Expected node ${firstNode.constructor.name} of type ${firstNode.getType()} to have a block ancestor`); 13494 } 13495 insertRangeAfter(firstBlock, firstToInsert); 13496 } 13497 const lastInsertedBlock = $findMatchingParent(nodeToSelect, INTERNAL_$isBlock); 13498 if (insertedParagraph && $isElementNode(lastInsertedBlock) && (insertedParagraph.canMergeWhenEmpty() || INTERNAL_$isBlock(lastToInsert))) { 13499 lastInsertedBlock.append(...insertedParagraph.getChildren()); 13500 insertedParagraph.remove(); 13501 } 13502 if ($isElementNode(firstBlock) && firstBlock.isEmpty()) { 13503 firstBlock.remove(); 13504 } 13505 nodeToSelect.selectEnd(); 13506 const lastChild = $isElementNode(firstBlock) ? firstBlock.getLastChild() : null; 13507 if ($isLineBreakNode(lastChild) && lastInsertedBlock !== firstBlock) { 13508 lastChild.remove(); 13509 } 13510 } 13511 /** 13512 * Inserts a new ParagraphNode into the EditorState at the current Selection 13513 * 13514 * @returns the newly inserted node. 13515 */ 13516 insertParagraph() { 13517 if (this.anchor.key === "root") { 13518 const paragraph = $createParagraphNode(); 13519 $getRoot().splice(this.anchor.offset, 0, [paragraph]); 13520 paragraph.select(); 13521 return paragraph; 13522 } 13523 const index = $removeTextAndSplitBlock(this); 13524 const block = $findMatchingParent(this.anchor.getNode(), INTERNAL_$isBlock); 13525 if (!$isElementNode(block)) { 13526 formatDevErrorMessage(`Expected ancestor to be a block ElementNode`); 13527 } 13528 const firstToAppend = block.getChildAtIndex(index); 13529 const nodesToInsert = firstToAppend ? [firstToAppend, ...firstToAppend.getNextSiblings()] : []; 13530 const newBlock = block.insertNewAfter(this, false); 13531 if (newBlock) { 13532 newBlock.append(...nodesToInsert); 13533 newBlock.selectStart(); 13534 return newBlock; 13535 } 13536 return null; 13537 } 13538 /** 13539 * Inserts a logical linebreak, which may be a new LineBreakNode or a new ParagraphNode, into the EditorState at the 13540 * current Selection. 13541 */ 13542 insertLineBreak(selectStart) { 13543 const lineBreak = $createLineBreakNode(); 13544 this.insertNodes([lineBreak]); 13545 if (selectStart) { 13546 const parent = lineBreak.getParentOrThrow(); 13547 const index = lineBreak.getIndexWithinParent(); 13548 parent.select(index, index); 13549 } 13550 } 13551 /** 13552 * Extracts the nodes in the Selection, splitting nodes where necessary 13553 * to get offset-level precision. 13554 * 13555 * @returns The nodes in the Selection 13556 */ 13557 extract() { 13558 const selectedNodes = [...this.getNodes()]; 13559 const selectedNodesLength = selectedNodes.length; 13560 let firstNode = selectedNodes[0]; 13561 let lastNode = selectedNodes[selectedNodesLength - 1]; 13562 const [anchorOffset, focusOffset] = $getCharacterOffsets(this); 13563 const isBackward = this.isBackward(); 13564 const [startPoint, endPoint] = isBackward ? [this.focus, this.anchor] : [this.anchor, this.focus]; 13565 const [startOffset, endOffset] = isBackward ? [focusOffset, anchorOffset] : [anchorOffset, focusOffset]; 13566 if (selectedNodesLength === 0) { 13567 return []; 13568 } else if (selectedNodesLength === 1) { 13569 if ($isTextNode(firstNode) && !this.isCollapsed()) { 13570 const splitNodes = firstNode.splitText(startOffset, endOffset); 13571 const node = startOffset === 0 ? splitNodes[0] : splitNodes[1]; 13572 if (node) { 13573 startPoint.set(node.getKey(), 0, "text"); 13574 endPoint.set(node.getKey(), node.getTextContentSize(), "text"); 13575 return [node]; 13576 } 13577 return []; 13578 } 13579 return [firstNode]; 13580 } 13581 if ($isTextNode(firstNode)) { 13582 if (startOffset === firstNode.getTextContentSize()) { 13583 selectedNodes.shift(); 13584 } else if (startOffset !== 0) { 13585 [, firstNode] = firstNode.splitText(startOffset); 13586 selectedNodes[0] = firstNode; 13587 startPoint.set(firstNode.getKey(), 0, "text"); 13588 } 13589 } 13590 if ($isTextNode(lastNode)) { 13591 const lastNodeText = lastNode.getTextContent(); 13592 const lastNodeTextLength = lastNodeText.length; 13593 if (endOffset === 0) { 13594 selectedNodes.pop(); 13595 } else if (endOffset !== lastNodeTextLength) { 13596 [lastNode] = lastNode.splitText(endOffset); 13597 selectedNodes[selectedNodes.length - 1] = lastNode; 13598 endPoint.set(lastNode.getKey(), lastNode.getTextContentSize(), "text"); 13599 } 13600 } 13601 return selectedNodes; 13602 } 13603 /** 13604 * Modifies the Selection according to the parameters and a set of heuristics that account for 13605 * various node types. Can be used to safely move or extend selection by one logical "unit" without 13606 * dealing explicitly with all the possible node types. 13607 * 13608 * @param alter the type of modification to perform 13609 * @param isBackward whether or not selection is backwards 13610 * @param granularity the granularity at which to apply the modification 13611 */ 13612 modify(alter, isBackward, granularity) { 13613 if ($modifySelectionAroundDecoratorsAndBlocks(this, alter, isBackward, granularity)) { 13614 return; 13615 } 13616 const collapse = alter === "move"; 13617 const editor = getActiveEditor(); 13618 const domSelection = getDOMSelection(getWindow(editor)); 13619 if (!domSelection) { 13620 return; 13621 } 13622 const blockCursorElement = editor._blockCursorElement; 13623 const rootElement = editor._rootElement; 13624 const focusNode = this.focus.getNode(); 13625 if (rootElement !== null && blockCursorElement !== null && $isElementNode(focusNode) && !focusNode.isInline() && !focusNode.canBeEmpty()) { 13626 removeDOMBlockCursorElement(blockCursorElement, editor, rootElement); 13627 } 13628 if (this.dirty) { 13629 let nextAnchorDOM = getElementByKeyOrThrow(editor, this.anchor.key); 13630 let nextFocusDOM = getElementByKeyOrThrow(editor, this.focus.key); 13631 if (this.anchor.type === "text") { 13632 nextAnchorDOM = getDOMTextNode(nextAnchorDOM); 13633 } 13634 if (this.focus.type === "text") { 13635 nextFocusDOM = getDOMTextNode(nextFocusDOM); 13636 } 13637 if (nextAnchorDOM && nextFocusDOM) { 13638 setDOMSelectionBaseAndExtent(domSelection, nextAnchorDOM, this.anchor.offset, nextFocusDOM, this.focus.offset); 13639 } 13640 } 13641 moveNativeSelection(domSelection, alter, isBackward ? "backward" : "forward", granularity); 13642 if (domSelection.rangeCount > 0) { 13643 const range2 = domSelection.getRangeAt(0); 13644 const anchorNode = this.anchor.getNode(); 13645 const root = $isRootNode(anchorNode) ? anchorNode : $getNearestRootOrShadowRoot(anchorNode); 13646 this.applyDOMRange(range2); 13647 this.dirty = true; 13648 if (!collapse) { 13649 const nodes = this.getNodes(); 13650 const validNodes = []; 13651 let shrinkSelection = false; 13652 for (let i2 = 0; i2 < nodes.length; i2++) { 13653 const nextNode = nodes[i2]; 13654 if ($hasAncestor(nextNode, root)) { 13655 validNodes.push(nextNode); 13656 } else { 13657 shrinkSelection = true; 13658 } 13659 } 13660 if (shrinkSelection && validNodes.length > 0) { 13661 if (isBackward) { 13662 const firstValidNode = validNodes[0]; 13663 if ($isElementNode(firstValidNode)) { 13664 firstValidNode.selectStart(); 13665 } else { 13666 firstValidNode.getParentOrThrow().selectStart(); 13667 } 13668 } else { 13669 const lastValidNode = validNodes[validNodes.length - 1]; 13670 if ($isElementNode(lastValidNode)) { 13671 lastValidNode.selectEnd(); 13672 } else { 13673 lastValidNode.getParentOrThrow().selectEnd(); 13674 } 13675 } 13676 } 13677 if (domSelection.anchorNode !== range2.startContainer || domSelection.anchorOffset !== range2.startOffset) { 13678 $swapPoints(this); 13679 } 13680 } 13681 } 13682 if (granularity === "lineboundary") { 13683 $modifySelectionAroundDecoratorsAndBlocks(this, alter, isBackward, granularity, "decorators"); 13684 } 13685 } 13686 /** 13687 * Helper for handling forward character and word deletion that prevents element nodes 13688 * like a table, columns layout being destroyed 13689 * 13690 * @param anchor the anchor 13691 * @param anchorNode the anchor node in the selection 13692 * @param isBackward whether or not selection is backwards 13693 */ 13694 forwardDeletion(anchor, anchorNode, isBackward) { 13695 if (!isBackward && // Delete forward handle case 13696 (anchor.type === "element" && $isElementNode(anchorNode) && anchor.offset === anchorNode.getChildrenSize() || anchor.type === "text" && anchor.offset === anchorNode.getTextContentSize())) { 13697 const parent = anchorNode.getParent(); 13698 const nextSibling = anchorNode.getNextSibling() || (parent === null ? null : parent.getNextSibling()); 13699 if ($isElementNode(nextSibling) && nextSibling.isShadowRoot()) { 13700 return true; 13701 } 13702 } 13703 return false; 13704 } 13705 /** 13706 * Performs one logical character deletion operation on the EditorState based on the current Selection. 13707 * Handles different node types. 13708 * 13709 * @param isBackward whether or not the selection is backwards. 13710 */ 13711 deleteCharacter(isBackward) { 13712 const wasCollapsed = this.isCollapsed(); 13713 if (this.isCollapsed()) { 13714 const anchor = this.anchor; 13715 let anchorNode = anchor.getNode(); 13716 if (this.forwardDeletion(anchor, anchorNode, isBackward)) { 13717 return; 13718 } 13719 const direction = isBackward ? "previous" : "next"; 13720 const initialCaret = $caretFromPoint(anchor, direction); 13721 const initialRange = $extendCaretToRange(initialCaret); 13722 if (initialRange.getTextSlices().every((slice) => slice === null || slice.distance === 0)) { 13723 let state = { 13724 type: "initial" 13725 }; 13726 for (const caret of initialRange.iterNodeCarets("shadowRoot")) { 13727 if ($isChildCaret(caret)) { 13728 if (caret.origin.isInline()) ; 13729 else if (caret.origin.isShadowRoot()) { 13730 if (state.type === "merge-block") { 13731 break; 13732 } 13733 if ($isElementNode(initialRange.anchor.origin) && initialRange.anchor.origin.isEmpty()) { 13734 const normCaret = $normalizeCaret(caret); 13735 $updateRangeSelectionFromCaretRange(this, $getCaretRange(normCaret, normCaret)); 13736 initialRange.anchor.origin.remove(); 13737 } 13738 return; 13739 } else if (state.type === "merge-next-block" || state.type === "merge-block") { 13740 state = { 13741 block: state.block, 13742 caret, 13743 type: "merge-block" 13744 }; 13745 } 13746 } else if (state.type === "merge-block") { 13747 break; 13748 } else if ($isSiblingCaret(caret)) { 13749 if ($isElementNode(caret.origin)) { 13750 if (!caret.origin.isInline()) { 13751 state = { 13752 block: caret.origin, 13753 type: "merge-next-block" 13754 }; 13755 } else if (!caret.origin.isParentOf(initialRange.anchor.origin)) { 13756 break; 13757 } 13758 continue; 13759 } else if ($isDecoratorNode(caret.origin)) { 13760 if (caret.origin.isIsolated()) ; 13761 else if (state.type === "merge-next-block" && (caret.origin.isKeyboardSelectable() || !caret.origin.isInline()) && $isElementNode(initialRange.anchor.origin) && initialRange.anchor.origin.isEmpty()) { 13762 initialRange.anchor.origin.remove(); 13763 const nodeSelection = $createNodeSelection(); 13764 nodeSelection.add(caret.origin.getKey()); 13765 $setSelection(nodeSelection); 13766 } else { 13767 caret.origin.remove(); 13768 } 13769 return; 13770 } 13771 break; 13772 } 13773 } 13774 if (state.type === "merge-block") { 13775 const { 13776 caret, 13777 block 13778 } = state; 13779 $updateRangeSelectionFromCaretRange(this, $getCaretRange(!caret.origin.isEmpty() && block.isEmpty() ? $rewindSiblingCaret($getSiblingCaret(block, caret.direction)) : initialRange.anchor, caret)); 13780 return this.removeText(); 13781 } 13782 } 13783 const focus = this.focus; 13784 this.modify("extend", isBackward, "character"); 13785 if (!this.isCollapsed()) { 13786 const focusNode = focus.type === "text" ? focus.getNode() : null; 13787 anchorNode = anchor.type === "text" ? anchor.getNode() : null; 13788 if (focusNode !== null && focusNode.isSegmented()) { 13789 const offset3 = focus.offset; 13790 const textContentSize = focusNode.getTextContentSize(); 13791 if (focusNode.is(anchorNode) || isBackward && offset3 !== textContentSize || !isBackward && offset3 !== 0) { 13792 $removeSegment(focusNode, isBackward, offset3); 13793 return; 13794 } 13795 } else if (anchorNode !== null && anchorNode.isSegmented()) { 13796 const offset3 = anchor.offset; 13797 const textContentSize = anchorNode.getTextContentSize(); 13798 if (anchorNode.is(focusNode) || isBackward && offset3 !== 0 || !isBackward && offset3 !== textContentSize) { 13799 $removeSegment(anchorNode, isBackward, offset3); 13800 return; 13801 } 13802 } 13803 $updateCaretSelectionForUnicodeCharacter(this, isBackward); 13804 } else if (isBackward && anchor.offset === 0) { 13805 if ($collapseAtStart(this, anchor.getNode())) { 13806 return; 13807 } 13808 } 13809 } 13810 this.removeText(); 13811 if (isBackward && !wasCollapsed && this.isCollapsed() && this.anchor.type === "element" && this.anchor.offset === 0) { 13812 const anchorNode = this.anchor.getNode(); 13813 if (anchorNode.isEmpty() && $isRootNode(anchorNode.getParent()) && anchorNode.getPreviousSibling() === null) { 13814 $collapseAtStart(this, anchorNode); 13815 } 13816 } 13817 } 13818 /** 13819 * Performs one logical line deletion operation on the EditorState based on the current Selection. 13820 * Handles different node types. 13821 * 13822 * @param isBackward whether or not the selection is backwards. 13823 */ 13824 deleteLine(isBackward) { 13825 if (this.isCollapsed()) { 13826 this.modify("extend", isBackward, "lineboundary"); 13827 } 13828 if (this.isCollapsed()) { 13829 this.deleteCharacter(isBackward); 13830 } else { 13831 this.removeText(); 13832 } 13833 } 13834 /** 13835 * Performs one logical word deletion operation on the EditorState based on the current Selection. 13836 * Handles different node types. 13837 * 13838 * @param isBackward whether or not the selection is backwards. 13839 */ 13840 deleteWord(isBackward) { 13841 if (this.isCollapsed()) { 13842 const anchor = this.anchor; 13843 const anchorNode = anchor.getNode(); 13844 if (this.forwardDeletion(anchor, anchorNode, isBackward)) { 13845 return; 13846 } 13847 this.modify("extend", isBackward, "word"); 13848 } 13849 if (this.isCollapsed()) { 13850 this.deleteCharacter(isBackward); 13851 } else { 13852 this.removeText(); 13853 } 13854 } 13855 /** 13856 * Returns whether the Selection is "backwards", meaning the focus 13857 * logically precedes the anchor in the EditorState. 13858 * @returns true if the Selection is backwards, false otherwise. 13859 */ 13860 isBackward() { 13861 return this.focus.isBefore(this.anchor); 13862 } 13863 getStartEndPoints() { 13864 return [this.anchor, this.focus]; 13865 } 13866 }; 13867 function $isNodeSelection(x3) { 13868 return x3 instanceof NodeSelection; 13869 } 13870 function getCharacterOffset(point) { 13871 const offset3 = point.offset; 13872 if (point.type === "text") { 13873 return offset3; 13874 } 13875 const parent = point.getNode(); 13876 return offset3 === parent.getChildrenSize() ? parent.getTextContent().length : 0; 13877 } 13878 function $getCharacterOffsets(selection) { 13879 const anchorAndFocus = selection.getStartEndPoints(); 13880 if (anchorAndFocus === null) { 13881 return [0, 0]; 13882 } 13883 const [anchor, focus] = anchorAndFocus; 13884 if (anchor.type === "element" && focus.type === "element" && anchor.key === focus.key && anchor.offset === focus.offset) { 13885 return [0, 0]; 13886 } 13887 return [getCharacterOffset(anchor), getCharacterOffset(focus)]; 13888 } 13889 function $collapseAtStart(selection, startNode) { 13890 for (let node = startNode; node; node = node.getParent()) { 13891 if ($isElementNode(node)) { 13892 if (node.collapseAtStart(selection)) { 13893 return true; 13894 } 13895 if ($isRootOrShadowRoot(node)) { 13896 break; 13897 } 13898 } 13899 if (node.getPreviousSibling()) { 13900 break; 13901 } 13902 } 13903 return false; 13904 } 13905 function $swapPoints(selection) { 13906 const focus = selection.focus; 13907 const anchor = selection.anchor; 13908 const anchorKey = anchor.key; 13909 const anchorOffset = anchor.offset; 13910 const anchorType = anchor.type; 13911 anchor.set(focus.key, focus.offset, focus.type, true); 13912 focus.set(anchorKey, anchorOffset, anchorType, true); 13913 } 13914 function moveNativeSelection(domSelection, alter, direction, granularity) { 13915 domSelection.modify(alter, direction, granularity); 13916 } 13917 function $updateCaretSelectionForUnicodeCharacter(selection, isBackward) { 13918 const anchor = selection.anchor; 13919 const focus = selection.focus; 13920 const anchorNode = anchor.getNode(); 13921 const focusNode = focus.getNode(); 13922 if (anchorNode === focusNode && anchor.type === "text" && focus.type === "text") { 13923 const anchorOffset = anchor.offset; 13924 const focusOffset = focus.offset; 13925 const isBefore = anchorOffset < focusOffset; 13926 const startOffset = isBefore ? anchorOffset : focusOffset; 13927 const endOffset = isBefore ? focusOffset : anchorOffset; 13928 const characterOffset = endOffset - 1; 13929 if (startOffset !== characterOffset) { 13930 const text2 = anchorNode.getTextContent().slice(startOffset, endOffset); 13931 if (shouldDeleteExactlyOneCodeUnit(text2)) { 13932 if (isBackward) { 13933 focus.set(focus.key, characterOffset, focus.type); 13934 } else { 13935 anchor.set(anchor.key, characterOffset, anchor.type); 13936 } 13937 } 13938 } 13939 } 13940 } 13941 function shouldDeleteExactlyOneCodeUnit(text2) { 13942 { 13943 if (!(text2.length > 1)) { 13944 formatDevErrorMessage(`shouldDeleteExactlyOneCodeUnit: expecting to be called only with sequences of two or more code units`); 13945 } 13946 } 13947 return !(doesContainSurrogatePair(text2) || doesContainEmoji(text2)); 13948 } 13949 var doesContainEmoji = (() => { 13950 try { 13951 const re3 = new RegExp("\\p{Emoji}", "u"); 13952 const test = re3.test.bind(re3); 13953 if ( 13954 // Emoji in the BMP (heart) with variation selector 13955 test("\u2764\uFE0F") && // Emoji in the BMP (#) with variation selector 13956 test("#\uFE0F\u20E3") && // Emoji outside the BMP (thumbs up) that is encoded with a surrogate pair 13957 test("\u{1F44D}") 13958 ) { 13959 return test; 13960 } 13961 } catch (_e2) { 13962 } 13963 return () => false; 13964 })(); 13965 function $removeSegment(node, isBackward, offset3) { 13966 const textNode = node; 13967 const textContent = textNode.getTextContent(); 13968 const split = textContent.split(/(?=\s)/g); 13969 const splitLength = split.length; 13970 let segmentOffset = 0; 13971 let restoreOffset = 0; 13972 for (let i2 = 0; i2 < splitLength; i2++) { 13973 const text2 = split[i2]; 13974 const isLast = i2 === splitLength - 1; 13975 restoreOffset = segmentOffset; 13976 segmentOffset += text2.length; 13977 if (isBackward && segmentOffset === offset3 || segmentOffset > offset3 || isLast) { 13978 split.splice(i2, 1); 13979 if (isLast) { 13980 restoreOffset = void 0; 13981 } 13982 break; 13983 } 13984 } 13985 const nextTextContent = split.join("").trim(); 13986 if (nextTextContent === "") { 13987 textNode.remove(); 13988 } else { 13989 textNode.setTextContent(nextTextContent); 13990 textNode.select(restoreOffset, restoreOffset); 13991 } 13992 } 13993 function shouldResolveAncestor(resolvedElement, resolvedOffset, lastPoint) { 13994 const parent = resolvedElement.getParent(); 13995 return lastPoint === null || parent === null || !parent.canBeEmpty() || parent !== lastPoint.getNode(); 13996 } 13997 function $internalResolveSelectionPoint(dom, offset3, lastPoint, editor) { 13998 let resolvedOffset = offset3; 13999 let resolvedNode; 14000 if (isHTMLElement(dom)) { 14001 let moveSelectionToEnd = false; 14002 const childNodes = dom.childNodes; 14003 const childNodesLength = childNodes.length; 14004 const blockCursorElement = editor._blockCursorElement; 14005 if (resolvedOffset === childNodesLength) { 14006 moveSelectionToEnd = true; 14007 resolvedOffset = childNodesLength - 1; 14008 } 14009 let childDOM = childNodes[resolvedOffset]; 14010 let hasBlockCursor = false; 14011 if (childDOM === blockCursorElement) { 14012 childDOM = childNodes[resolvedOffset + 1]; 14013 hasBlockCursor = true; 14014 } else if (blockCursorElement !== null) { 14015 const blockCursorElementParent = blockCursorElement.parentNode; 14016 if (dom === blockCursorElementParent) { 14017 const blockCursorOffset = Array.prototype.indexOf.call(blockCursorElementParent.children, blockCursorElement); 14018 if (offset3 > blockCursorOffset) { 14019 resolvedOffset--; 14020 } 14021 } 14022 } 14023 resolvedNode = $getNodeFromDOM(childDOM); 14024 if ($isTextNode(resolvedNode)) { 14025 resolvedOffset = $getTextNodeOffset(resolvedNode, moveSelectionToEnd ? "next" : "previous"); 14026 } else { 14027 let resolvedElement = $getNodeFromDOM(dom); 14028 if (resolvedElement === null) { 14029 return null; 14030 } 14031 if ($isElementNode(resolvedElement)) { 14032 const elementDOM = editor.getElementByKey(resolvedElement.getKey()); 14033 if (!(elementDOM !== null)) { 14034 formatDevErrorMessage(`$internalResolveSelectionPoint: node in DOM but not keyToDOMMap`); 14035 } 14036 const slot = $getEditorDOMRenderConfig(editor).$getDOMSlot(resolvedElement, elementDOM, editor); 14037 [resolvedElement, resolvedOffset] = slot.resolveChildIndex(resolvedElement, elementDOM, dom, offset3); 14038 if (!$isElementNode(resolvedElement)) { 14039 formatDevErrorMessage(`$internalResolveSelectionPoint: resolvedElement is not an ElementNode`); 14040 } 14041 if (moveSelectionToEnd && resolvedOffset >= resolvedElement.getChildrenSize()) { 14042 resolvedOffset = Math.max(0, resolvedElement.getChildrenSize() - 1); 14043 } 14044 let child = resolvedElement.getChildAtIndex(resolvedOffset); 14045 if ($isElementNode(child) && shouldResolveAncestor(child, resolvedOffset, lastPoint)) { 14046 const descendant = moveSelectionToEnd ? child.getLastDescendant() : child.getFirstDescendant(); 14047 if (descendant === null) { 14048 resolvedElement = child; 14049 } else { 14050 child = descendant; 14051 resolvedElement = $isElementNode(child) ? child : child.getParentOrThrow(); 14052 } 14053 resolvedOffset = 0; 14054 } 14055 if ($isTextNode(child)) { 14056 resolvedNode = child; 14057 resolvedElement = null; 14058 resolvedOffset = $getTextNodeOffset(child, moveSelectionToEnd ? "next" : "previous"); 14059 } else if (child !== resolvedElement && moveSelectionToEnd && !hasBlockCursor) { 14060 if (!$isElementNode(resolvedElement)) { 14061 formatDevErrorMessage(`invariant`); 14062 } 14063 resolvedOffset = Math.min(resolvedElement.getChildrenSize(), resolvedOffset + 1); 14064 } 14065 } else { 14066 const index = resolvedElement.getIndexWithinParent(); 14067 if (offset3 === 0 && $isDecoratorNode(resolvedElement) && $getNodeFromDOM(dom) === resolvedElement) { 14068 resolvedOffset = index; 14069 } else { 14070 resolvedOffset = index + 1; 14071 } 14072 resolvedElement = resolvedElement.getParentOrThrow(); 14073 } 14074 if ($isElementNode(resolvedElement)) { 14075 return $createPoint(resolvedElement.__key, resolvedOffset, "element"); 14076 } 14077 } 14078 } else { 14079 resolvedNode = $getNodeFromDOM(dom); 14080 } 14081 if (!$isTextNode(resolvedNode)) { 14082 return null; 14083 } 14084 return $createPoint(resolvedNode.__key, $getTextNodeOffset(resolvedNode, resolvedOffset, "clamp"), "text"); 14085 } 14086 function resolveSelectionPointOnBoundary(point, isBackward, isCollapsed) { 14087 const offset3 = point.offset; 14088 const node = point.getNode(); 14089 if (offset3 === 0) { 14090 const prevSibling = node.getPreviousSibling(); 14091 const parent = node.getParent(); 14092 if (!isBackward) { 14093 if ($isElementNode(prevSibling) && !isCollapsed && prevSibling.isInline()) { 14094 point.set(prevSibling.__key, prevSibling.getChildrenSize(), "element"); 14095 } else if ($isTextNode(prevSibling)) { 14096 point.set(prevSibling.__key, prevSibling.getTextContent().length, "text"); 14097 } 14098 } else if ((isCollapsed || !isBackward) && prevSibling === null && $isElementNode(parent) && parent.isInline()) { 14099 const parentSibling = parent.getPreviousSibling(); 14100 if ($isTextNode(parentSibling)) { 14101 point.set(parentSibling.__key, parentSibling.getTextContent().length, "text"); 14102 } 14103 } 14104 } else if (offset3 === node.getTextContent().length) { 14105 const nextSibling = node.getNextSibling(); 14106 const parent = node.getParent(); 14107 if (isBackward && $isElementNode(nextSibling) && nextSibling.isInline()) { 14108 point.set(nextSibling.__key, 0, "element"); 14109 } else if ((isCollapsed || isBackward) && nextSibling === null && $isElementNode(parent) && parent.isInline() && !parent.canInsertTextAfter()) { 14110 const parentSibling = parent.getNextSibling(); 14111 if ($isTextNode(parentSibling)) { 14112 point.set(parentSibling.__key, 0, "text"); 14113 } 14114 } 14115 } 14116 } 14117 function $normalizeSelectionPointsForBoundaries(anchor, focus, lastSelection) { 14118 if (anchor.type === "text" && focus.type === "text") { 14119 const isBackward = anchor.isBefore(focus); 14120 const isCollapsed = anchor.is(focus); 14121 resolveSelectionPointOnBoundary(anchor, isBackward, isCollapsed); 14122 resolveSelectionPointOnBoundary(focus, !isBackward, isCollapsed); 14123 if (isCollapsed) { 14124 focus.set(anchor.key, anchor.offset, anchor.type); 14125 } 14126 } 14127 } 14128 function $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection) { 14129 if (anchorDOM === null || focusDOM === null || !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) { 14130 return null; 14131 } 14132 const resolvedAnchorPoint = $internalResolveSelectionPoint(anchorDOM, anchorOffset, $isRangeSelection(lastSelection) ? lastSelection.anchor : null, editor); 14133 if (resolvedAnchorPoint === null) { 14134 return null; 14135 } 14136 const resolvedFocusPoint = $internalResolveSelectionPoint(focusDOM, focusOffset, $isRangeSelection(lastSelection) ? lastSelection.focus : null, editor); 14137 if (resolvedFocusPoint === null) { 14138 return null; 14139 } 14140 { 14141 $validatePoint("anchor", resolvedAnchorPoint); 14142 $validatePoint("focus", resolvedFocusPoint); 14143 } 14144 if (resolvedAnchorPoint.type === "element" && resolvedFocusPoint.type === "element") { 14145 const anchorNode = $getNodeFromDOM(anchorDOM); 14146 const focusNode = $getNodeFromDOM(focusDOM); 14147 if ($isDecoratorNode(anchorNode) && $isDecoratorNode(focusNode)) { 14148 return null; 14149 } 14150 } 14151 $normalizeSelectionPointsForBoundaries(resolvedAnchorPoint, resolvedFocusPoint); 14152 return [resolvedAnchorPoint, resolvedFocusPoint]; 14153 } 14154 function $isBlockElementNode(node) { 14155 return $isElementNode(node) && !node.isInline(); 14156 } 14157 function $internalMakeRangeSelection(anchorKey, anchorOffset, focusKey, focusOffset, anchorType, focusType) { 14158 const editorState = getActiveEditorState(); 14159 const selection = new RangeSelection($createPoint(anchorKey, anchorOffset, anchorType), $createPoint(focusKey, focusOffset, focusType), 0, ""); 14160 selection.dirty = true; 14161 editorState._selection = selection; 14162 return selection; 14163 } 14164 function $createRangeSelection() { 14165 const anchor = $createPoint("root", 0, "element"); 14166 const focus = $createPoint("root", 0, "element"); 14167 return new RangeSelection(anchor, focus, 0, ""); 14168 } 14169 function $createNodeSelection() { 14170 return new NodeSelection(/* @__PURE__ */ new Set()); 14171 } 14172 function $internalCreateSelection(editor, event) { 14173 const currentEditorState = editor.getEditorState(); 14174 const lastSelection = currentEditorState._selection; 14175 const domSelection = getDOMSelection(getWindow(editor)); 14176 if ($isRangeSelection(lastSelection) || lastSelection == null) { 14177 return $internalCreateRangeSelection(lastSelection, domSelection, editor, event); 14178 } 14179 return lastSelection.clone(); 14180 } 14181 function $createRangeSelectionFromDom(domSelection, editor) { 14182 return $internalCreateRangeSelection(null, domSelection, editor, null); 14183 } 14184 function $internalCreateRangeSelection(lastSelection, domSelection, editor, event) { 14185 const windowObj = editor._window; 14186 if (windowObj === null) { 14187 return null; 14188 } 14189 const windowEvent = event || windowObj.event; 14190 const eventType = windowEvent ? windowEvent.type : void 0; 14191 const isSelectionChange = eventType === "selectionchange"; 14192 const useDOMSelection = !getIsProcessingMutations() && (isSelectionChange || eventType === "beforeinput" || eventType === "compositionstart" || eventType === "compositionend" || eventType === "click" && windowEvent && windowEvent.detail === 3 || eventType === "drop" || eventType === void 0); 14193 let anchorDOM, focusDOM, anchorOffset, focusOffset; 14194 if (!$isRangeSelection(lastSelection) || useDOMSelection) { 14195 if (domSelection === null) { 14196 return null; 14197 } 14198 anchorDOM = domSelection.anchorNode; 14199 focusDOM = domSelection.focusNode; 14200 anchorOffset = domSelection.anchorOffset; 14201 focusOffset = domSelection.focusOffset; 14202 if ((isSelectionChange || eventType === void 0) && $isRangeSelection(lastSelection) && !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) { 14203 return lastSelection.clone(); 14204 } 14205 } else { 14206 return lastSelection.clone(); 14207 } 14208 const resolvedSelectionPoints = $internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection); 14209 if (resolvedSelectionPoints === null) { 14210 return null; 14211 } 14212 const [resolvedAnchorPoint, resolvedFocusPoint] = resolvedSelectionPoints; 14213 let format = 0; 14214 let style = ""; 14215 if ($isRangeSelection(lastSelection)) { 14216 const lastAnchor = lastSelection.anchor; 14217 if (resolvedAnchorPoint.key === lastAnchor.key) { 14218 format = lastSelection.format; 14219 style = lastSelection.style; 14220 } else { 14221 const anchorNode = resolvedAnchorPoint.getNode(); 14222 if ($isTextNode(anchorNode)) { 14223 format = anchorNode.getFormat(); 14224 style = anchorNode.getStyle(); 14225 } else if ($isElementNode(anchorNode)) { 14226 format = anchorNode.getTextFormat(); 14227 style = anchorNode.getTextStyle(); 14228 } 14229 } 14230 } 14231 return new RangeSelection(resolvedAnchorPoint, resolvedFocusPoint, format, style); 14232 } 14233 function $validatePoint(name, point) { 14234 const node = $getNodeByKey(point.key); 14235 if (!(node !== void 0)) { 14236 formatDevErrorMessage(`$validatePoint: ${name} key ${point.key} not found in current editorState`); 14237 } 14238 if (point.type === "text") { 14239 if (!$isTextNode(node)) { 14240 formatDevErrorMessage(`$validatePoint: ${name} key ${point.key} is not a TextNode`); 14241 } 14242 const size2 = node.getTextContentSize(); 14243 if (!(point.offset <= size2)) { 14244 formatDevErrorMessage(`$validatePoint: ${name} point.offset > node.getTextContentSize() (${String(point.offset)} > ${String(size2)})`); 14245 } 14246 } else { 14247 if (!$isElementNode(node)) { 14248 formatDevErrorMessage(`$validatePoint: ${name} key ${point.key} is not an ElementNode`); 14249 } 14250 const size2 = node.getChildrenSize(); 14251 if (!(point.offset <= size2)) { 14252 formatDevErrorMessage(`$validatePoint: ${name} point.offset > node.getChildrenSize() (${String(point.offset)} > ${String(size2)})`); 14253 } 14254 } 14255 } 14256 function $getSelection() { 14257 const editorState = getActiveEditorState(); 14258 return editorState._selection; 14259 } 14260 function $getPreviousSelection() { 14261 const editor = getActiveEditor(); 14262 return editor._editorState._selection; 14263 } 14264 function $updateElementSelectionOnCreateDeleteNode(selection, parentNode, nodeOffset, times = 1) { 14265 const anchor = selection.anchor; 14266 const focus = selection.focus; 14267 const anchorNode = anchor.getNode(); 14268 const focusNode = focus.getNode(); 14269 if (!parentNode.is(anchorNode) && !parentNode.is(focusNode)) { 14270 return; 14271 } 14272 const parentKey = parentNode.__key; 14273 if (selection.isCollapsed()) { 14274 const selectionOffset = anchor.offset; 14275 if (nodeOffset <= selectionOffset && times > 0 || nodeOffset < selectionOffset && times < 0) { 14276 const newSelectionOffset = Math.max(0, selectionOffset + times); 14277 anchor.set(parentKey, newSelectionOffset, "element"); 14278 focus.set(parentKey, newSelectionOffset, "element"); 14279 $updateSelectionResolveTextNodes(selection); 14280 } 14281 } else { 14282 const isBackward = selection.isBackward(); 14283 const firstPoint = isBackward ? focus : anchor; 14284 const firstPointNode = firstPoint.getNode(); 14285 const lastPoint = isBackward ? anchor : focus; 14286 const lastPointNode = lastPoint.getNode(); 14287 if (parentNode.is(firstPointNode)) { 14288 const firstPointOffset = firstPoint.offset; 14289 if (nodeOffset <= firstPointOffset && times > 0 || nodeOffset < firstPointOffset && times < 0) { 14290 firstPoint.set(parentKey, Math.max(0, firstPointOffset + times), "element"); 14291 } 14292 } 14293 if (parentNode.is(lastPointNode)) { 14294 const lastPointOffset = lastPoint.offset; 14295 if (nodeOffset <= lastPointOffset && times > 0 || nodeOffset < lastPointOffset && times < 0) { 14296 lastPoint.set(parentKey, Math.max(0, lastPointOffset + times), "element"); 14297 } 14298 } 14299 } 14300 $updateSelectionResolveTextNodes(selection); 14301 } 14302 function $updateSelectionResolveTextNodes(selection) { 14303 const anchor = selection.anchor; 14304 const anchorOffset = anchor.offset; 14305 const focus = selection.focus; 14306 const focusOffset = focus.offset; 14307 const anchorNode = anchor.getNode(); 14308 const focusNode = focus.getNode(); 14309 if (selection.isCollapsed()) { 14310 if (!$isElementNode(anchorNode)) { 14311 return; 14312 } 14313 const childSize = anchorNode.getChildrenSize(); 14314 const anchorOffsetAtEnd = anchorOffset >= childSize; 14315 const child = anchorOffsetAtEnd ? anchorNode.getChildAtIndex(childSize - 1) : anchorNode.getChildAtIndex(anchorOffset); 14316 if ($isTextNode(child)) { 14317 let newOffset = 0; 14318 if (anchorOffsetAtEnd) { 14319 newOffset = child.getTextContentSize(); 14320 } 14321 anchor.set(child.__key, newOffset, "text"); 14322 focus.set(child.__key, newOffset, "text"); 14323 } 14324 return; 14325 } 14326 if ($isElementNode(anchorNode)) { 14327 const childSize = anchorNode.getChildrenSize(); 14328 const anchorOffsetAtEnd = anchorOffset >= childSize; 14329 const child = anchorOffsetAtEnd ? anchorNode.getChildAtIndex(childSize - 1) : anchorNode.getChildAtIndex(anchorOffset); 14330 if ($isTextNode(child)) { 14331 let newOffset = 0; 14332 if (anchorOffsetAtEnd) { 14333 newOffset = child.getTextContentSize(); 14334 } 14335 anchor.set(child.__key, newOffset, "text"); 14336 } 14337 } 14338 if ($isElementNode(focusNode)) { 14339 const childSize = focusNode.getChildrenSize(); 14340 const focusOffsetAtEnd = focusOffset >= childSize; 14341 const child = focusOffsetAtEnd ? focusNode.getChildAtIndex(childSize - 1) : focusNode.getChildAtIndex(focusOffset); 14342 if ($isTextNode(child)) { 14343 let newOffset = 0; 14344 if (focusOffsetAtEnd) { 14345 newOffset = child.getTextContentSize(); 14346 } 14347 focus.set(child.__key, newOffset, "text"); 14348 } 14349 } 14350 } 14351 function applySelectionTransforms(nextEditorState, editor) { 14352 const prevEditorState = editor.getEditorState(); 14353 const prevSelection = prevEditorState._selection; 14354 const nextSelection = nextEditorState._selection; 14355 if ($isRangeSelection(nextSelection)) { 14356 const anchor = nextSelection.anchor; 14357 const focus = nextSelection.focus; 14358 let anchorNode; 14359 if (anchor.type === "text") { 14360 anchorNode = anchor.getNode(); 14361 anchorNode.selectionTransform(prevSelection, nextSelection); 14362 } 14363 if (focus.type === "text") { 14364 const focusNode = focus.getNode(); 14365 if (anchorNode !== focusNode) { 14366 focusNode.selectionTransform(prevSelection, nextSelection); 14367 } 14368 } 14369 } 14370 } 14371 function moveSelectionPointToSibling(point, node, parent, prevSibling, nextSibling) { 14372 let siblingKey = null; 14373 let offset3 = 0; 14374 let type = null; 14375 if (prevSibling !== null) { 14376 siblingKey = prevSibling.__key; 14377 if ($isTextNode(prevSibling)) { 14378 offset3 = prevSibling.getTextContentSize(); 14379 type = "text"; 14380 } else if ($isElementNode(prevSibling)) { 14381 offset3 = prevSibling.getChildrenSize(); 14382 type = "element"; 14383 } 14384 } else { 14385 if (nextSibling !== null) { 14386 siblingKey = nextSibling.__key; 14387 if ($isTextNode(nextSibling)) { 14388 type = "text"; 14389 } else if ($isElementNode(nextSibling)) { 14390 type = "element"; 14391 } 14392 } 14393 } 14394 if (siblingKey !== null && type !== null) { 14395 point.set(siblingKey, offset3, type); 14396 } else { 14397 offset3 = node.getIndexWithinParent(); 14398 if (offset3 === -1) { 14399 offset3 = parent.getChildrenSize(); 14400 } 14401 point.set(parent.__key, offset3, "element"); 14402 } 14403 } 14404 function adjustPointOffsetForMergedSibling(point, isBefore, key, target, textLength) { 14405 if (point.type === "text") { 14406 point.set(key, point.offset + (isBefore ? 0 : textLength), "text"); 14407 } else if (point.offset > target.getIndexWithinParent()) { 14408 point.set(point.key, point.offset - 1, "element"); 14409 } 14410 } 14411 function setDOMSelectionBaseAndExtent(domSelection, nextAnchorDOM, nextAnchorOffset, nextFocusDOM, nextFocusOffset) { 14412 try { 14413 domSelection.setBaseAndExtent(nextAnchorDOM, nextAnchorOffset, nextFocusDOM, nextFocusOffset); 14414 } catch (error) { 14415 { 14416 console.warn(error); 14417 } 14418 } 14419 } 14420 function $getElementAndOffsetForPoint(editor, node, offset3) { 14421 const element = getElementByKeyOrThrow(editor, node.getKey()); 14422 if ($isElementNode(node)) { 14423 const slot = $getEditorDOMRenderConfig(editor).$getDOMSlot(node, element, editor); 14424 return [slot.element, offset3 + slot.getFirstChildOffset()]; 14425 } 14426 return [element, offset3]; 14427 } 14428 function $updateDOMSelection(prevSelection, nextSelection, editor, domSelection, tags, rootElement, nodeCount) { 14429 const anchorDOMNode = domSelection.anchorNode; 14430 const focusDOMNode = domSelection.focusNode; 14431 const anchorOffset = domSelection.anchorOffset; 14432 const focusOffset = domSelection.focusOffset; 14433 const activeElement = document.activeElement; 14434 if (tags.has(COLLABORATION_TAG) && activeElement !== rootElement || activeElement !== null && isSelectionCapturedInDecoratorInput(activeElement)) { 14435 return; 14436 } 14437 if (!$isRangeSelection(nextSelection)) { 14438 if (prevSelection !== null && isSelectionWithinEditor(editor, anchorDOMNode, focusDOMNode)) { 14439 domSelection.removeAllRanges(); 14440 } 14441 return; 14442 } 14443 const anchor = nextSelection.anchor; 14444 const focus = nextSelection.focus; 14445 const anchorNode = anchor.getNode(); 14446 const focusNode = focus.getNode(); 14447 const [anchorDOM, nextAnchorOffset] = $getElementAndOffsetForPoint(editor, anchorNode, anchor.offset); 14448 const [focusDOM, nextFocusOffset] = $getElementAndOffsetForPoint(editor, focusNode, focus.offset); 14449 const nextFormat = nextSelection.format; 14450 const nextStyle = nextSelection.style; 14451 const isCollapsed = nextSelection.isCollapsed(); 14452 let nextAnchorNode = anchorDOM; 14453 let nextFocusNode = focusDOM; 14454 let anchorFormatOrStyleChanged = false; 14455 if (anchor.type === "text") { 14456 nextAnchorNode = getDOMTextNode(anchorDOM); 14457 anchorFormatOrStyleChanged = anchorNode.getFormat() !== nextFormat || anchorNode.getStyle() !== nextStyle; 14458 } else if ($isRangeSelection(prevSelection) && prevSelection.anchor.type === "text") { 14459 anchorFormatOrStyleChanged = true; 14460 } 14461 if (focus.type === "text") { 14462 nextFocusNode = getDOMTextNode(focusDOM); 14463 } 14464 if (nextAnchorNode === null || nextFocusNode === null) { 14465 return; 14466 } 14467 if (isCollapsed && (prevSelection === null || anchorFormatOrStyleChanged || $isRangeSelection(prevSelection) && (prevSelection.format !== nextFormat || prevSelection.style !== nextStyle))) { 14468 markCollapsedSelectionFormat(nextFormat, nextStyle, nextAnchorOffset, anchor.key, performance.now()); 14469 } 14470 if (anchorOffset === nextAnchorOffset && focusOffset === nextFocusOffset && anchorDOMNode === nextAnchorNode && focusDOMNode === nextFocusNode && // Badly interpreted range selection when collapsed - #1482 14471 !(domSelection.type === "Range" && isCollapsed)) { 14472 if (activeElement === null || !rootElement.contains(activeElement)) { 14473 if (!tags.has(SKIP_SELECTION_FOCUS_TAG)) { 14474 rootElement.focus({ 14475 preventScroll: true 14476 }); 14477 } 14478 } 14479 if (anchor.type !== "element") { 14480 return; 14481 } 14482 } 14483 setDOMSelectionBaseAndExtent(domSelection, nextAnchorNode, nextAnchorOffset, nextFocusNode, nextFocusOffset); 14484 if (IS_FIREFOX && nextSelection.isCollapsed() && rootElement !== null && !tags.has(SKIP_SELECTION_FOCUS_TAG) && (document.activeElement === null || !rootElement.contains(document.activeElement))) { 14485 rootElement.focus({ 14486 preventScroll: true 14487 }); 14488 } 14489 if (!tags.has(SKIP_SCROLL_INTO_VIEW_TAG) && nextSelection.isCollapsed() && rootElement !== null && rootElement === document.activeElement) { 14490 const selectionTarget = $isRangeSelection(nextSelection) && nextSelection.anchor.type === "element" ? nextAnchorNode.childNodes[nextAnchorOffset] || null : domSelection.rangeCount > 0 ? domSelection.getRangeAt(0) : null; 14491 if (selectionTarget !== null) { 14492 let selectionRect; 14493 if (selectionTarget instanceof Text) { 14494 const range2 = document.createRange(); 14495 range2.selectNode(selectionTarget); 14496 selectionRect = range2.getBoundingClientRect(); 14497 } else { 14498 selectionRect = selectionTarget.getBoundingClientRect(); 14499 } 14500 scrollIntoViewIfNeeded(editor, selectionRect, rootElement); 14501 } 14502 } 14503 markSelectionChangeFromDOMUpdate(); 14504 } 14505 function $insertNodes(nodes) { 14506 let selection = $getSelection() || $getPreviousSelection(); 14507 if (selection === null) { 14508 selection = $getRoot().selectEnd(); 14509 } 14510 selection.insertNodes(nodes); 14511 } 14512 function $getTextContent() { 14513 const selection = $getSelection(); 14514 if (selection === null) { 14515 return ""; 14516 } 14517 return selection.getTextContent(); 14518 } 14519 function $removeTextAndSplitBlock(selection) { 14520 let selection_ = selection; 14521 if (!selection.isCollapsed()) { 14522 selection_.removeText(); 14523 } 14524 const newSelection = $getSelection(); 14525 if ($isRangeSelection(newSelection)) { 14526 selection_ = newSelection; 14527 } 14528 if (!$isRangeSelection(selection_)) { 14529 formatDevErrorMessage(`Unexpected dirty selection to be null`); 14530 } 14531 const anchor = selection_.anchor; 14532 let node = anchor.getNode(); 14533 let offset3 = anchor.offset; 14534 while (!INTERNAL_$isBlock(node)) { 14535 const prevNode = node; 14536 [node, offset3] = $splitNodeAtPoint(node, offset3); 14537 if (prevNode.is(node)) { 14538 break; 14539 } 14540 } 14541 return offset3; 14542 } 14543 function $splitNodeAtPoint(node, offset3) { 14544 const parent = node.getParent(); 14545 if (!parent) { 14546 const paragraph = $createParagraphNode(); 14547 $getRoot().append(paragraph); 14548 paragraph.select(); 14549 return [$getRoot(), 0]; 14550 } 14551 if ($isTextNode(node)) { 14552 const split = node.splitText(offset3); 14553 if (split.length === 0) { 14554 return [parent, node.getIndexWithinParent()]; 14555 } 14556 const x3 = offset3 === 0 ? 0 : 1; 14557 const index = split[0].getIndexWithinParent() + x3; 14558 return [parent, index]; 14559 } 14560 if (!$isElementNode(node) || offset3 === 0) { 14561 return [parent, node.getIndexWithinParent()]; 14562 } 14563 const firstToAppend = node.getChildAtIndex(offset3); 14564 if (firstToAppend) { 14565 const insertPoint = new RangeSelection($createPoint(node.__key, offset3, "element"), $createPoint(node.__key, offset3, "element"), 0, ""); 14566 const newElement = node.insertNewAfter(insertPoint); 14567 if (newElement) { 14568 newElement.append(firstToAppend, ...firstToAppend.getNextSiblings()); 14569 } 14570 } 14571 return [parent, node.getIndexWithinParent() + 1]; 14572 } 14573 function $wrapInlineNodes(nodes) { 14574 const virtualRoot = $createParagraphNode(); 14575 let currentBlock = null; 14576 for (let i2 = 0; i2 < nodes.length; i2++) { 14577 const node = nodes[i2]; 14578 const isLineBreakNode = $isLineBreakNode(node); 14579 if (isLineBreakNode || $isDecoratorNode(node) && node.isInline() || $isElementNode(node) && node.isInline() || $isTextNode(node) || node.isParentRequired()) { 14580 if (currentBlock === null) { 14581 currentBlock = node.createParentElementNode(); 14582 virtualRoot.append(currentBlock); 14583 if (isLineBreakNode) { 14584 continue; 14585 } 14586 } 14587 if (currentBlock !== null) { 14588 currentBlock.append(node); 14589 } 14590 } else { 14591 virtualRoot.append(node); 14592 currentBlock = null; 14593 } 14594 } 14595 return virtualRoot; 14596 } 14597 function $getNodesFromCaretRangeCompat(range2) { 14598 const nodes = []; 14599 const [beforeSlice, afterSlice] = range2.getTextSlices(); 14600 if (beforeSlice) { 14601 nodes.push(beforeSlice.caret.origin); 14602 } 14603 const seenAncestors = /* @__PURE__ */ new Set(); 14604 const seenElements = /* @__PURE__ */ new Set(); 14605 for (const caret of range2) { 14606 if ($isChildCaret(caret)) { 14607 const { 14608 origin 14609 } = caret; 14610 if (nodes.length === 0) { 14611 seenAncestors.add(origin); 14612 } else { 14613 seenElements.add(origin); 14614 nodes.push(origin); 14615 } 14616 } else { 14617 const { 14618 origin 14619 } = caret; 14620 if (!$isElementNode(origin) || !seenElements.has(origin)) { 14621 nodes.push(origin); 14622 } 14623 } 14624 } 14625 if (afterSlice) { 14626 nodes.push(afterSlice.caret.origin); 14627 } 14628 if ($isSiblingCaret(range2.focus) && $isElementNode(range2.focus.origin) && range2.focus.getNodeAtCaret() === null) { 14629 for (let reverseCaret = $getChildCaret(range2.focus.origin, "previous"); $isChildCaret(reverseCaret) && seenAncestors.has(reverseCaret.origin) && !reverseCaret.origin.isEmpty() && reverseCaret.origin.is(nodes[nodes.length - 1]); reverseCaret = $getAdjacentChildCaret(reverseCaret)) { 14630 seenAncestors.delete(reverseCaret.origin); 14631 nodes.pop(); 14632 } 14633 } 14634 while (nodes.length > 1) { 14635 const lastIncludedNode = nodes[nodes.length - 1]; 14636 if ($isElementNode(lastIncludedNode)) { 14637 if (seenElements.has(lastIncludedNode) || lastIncludedNode.isEmpty() || seenAncestors.has(lastIncludedNode)) ; 14638 else { 14639 nodes.pop(); 14640 continue; 14641 } 14642 } 14643 break; 14644 } 14645 if (nodes.length === 0 && range2.isCollapsed()) { 14646 const normCaret = $normalizeCaret(range2.anchor); 14647 const flippedNormCaret = $normalizeCaret(range2.anchor.getFlipped()); 14648 const $getCandidate = (caret) => $isTextPointCaret(caret) ? caret.origin : caret.getNodeAtCaret(); 14649 const node = $getCandidate(normCaret) || $getCandidate(flippedNormCaret) || (range2.anchor.getNodeAtCaret() ? normCaret.origin : flippedNormCaret.origin); 14650 nodes.push(node); 14651 } 14652 return nodes; 14653 } 14654 function $modifySelectionAroundDecoratorsAndBlocks(selection, alter, isBackward, granularity, mode = "decorators-and-blocks") { 14655 if (alter === "move" && granularity === "character" && !selection.isCollapsed()) { 14656 const [src, dst] = isBackward === selection.isBackward() ? [selection.focus, selection.anchor] : [selection.anchor, selection.focus]; 14657 dst.set(src.key, src.offset, src.type); 14658 return true; 14659 } 14660 const initialFocus = $caretFromPoint(selection.focus, isBackward ? "previous" : "next"); 14661 const isLineBoundary = granularity === "lineboundary"; 14662 const collapse = alter === "move"; 14663 let focus = initialFocus; 14664 let checkForBlock = mode === "decorators-and-blocks"; 14665 if (!$isExtendableTextPointCaret(focus)) { 14666 for (const siblingCaret of focus) { 14667 checkForBlock = false; 14668 const { 14669 origin 14670 } = siblingCaret; 14671 if ($isDecoratorNode(origin) && !origin.isIsolated()) { 14672 focus = siblingCaret; 14673 if (isLineBoundary && origin.isInline()) { 14674 continue; 14675 } 14676 } 14677 break; 14678 } 14679 if (checkForBlock) { 14680 for (const nextCaret of $extendCaretToRange(initialFocus).iterNodeCarets(alter === "extend" ? "shadowRoot" : "root")) { 14681 if ($isChildCaret(nextCaret)) { 14682 if (!nextCaret.origin.isInline()) { 14683 focus = nextCaret; 14684 } 14685 } else if ($isElementNode(nextCaret.origin)) { 14686 continue; 14687 } else if ($isDecoratorNode(nextCaret.origin) && !nextCaret.origin.isInline()) { 14688 focus = nextCaret; 14689 } 14690 break; 14691 } 14692 } 14693 } 14694 if (focus === initialFocus) { 14695 return false; 14696 } 14697 if (collapse && !isLineBoundary && $isDecoratorNode(focus.origin) && focus.origin.isKeyboardSelectable()) { 14698 const nodeSelection = $createNodeSelection(); 14699 nodeSelection.add(focus.origin.getKey()); 14700 $setSelection(nodeSelection); 14701 return true; 14702 } 14703 focus = $normalizeCaret(focus); 14704 if (collapse) { 14705 $setPointFromCaret(selection.anchor, focus); 14706 } 14707 $setPointFromCaret(selection.focus, focus); 14708 return checkForBlock || !isLineBoundary; 14709 } 14710 var activeEditorState = null; 14711 var activeEditor = null; 14712 var isReadOnlyMode = false; 14713 var isAttemptingToRecoverFromReconcilerError = false; 14714 var infiniteTransformCount = 0; 14715 var observerOptions = { 14716 characterData: true, 14717 childList: true, 14718 subtree: true 14719 }; 14720 function isCurrentlyReadOnlyMode() { 14721 return isReadOnlyMode || activeEditorState !== null && activeEditorState._readOnly; 14722 } 14723 function errorOnReadOnly() { 14724 if (isReadOnlyMode) { 14725 { 14726 formatDevErrorMessage(`Cannot use method in read-only mode.`); 14727 } 14728 } 14729 } 14730 function errorOnInfiniteTransforms() { 14731 if (infiniteTransformCount > 99) { 14732 { 14733 formatDevErrorMessage(`One or more transforms are endlessly triggering additional transforms. May have encountered infinite recursion caused by transforms that have their preconditions too lose and/or conflict with each other.`); 14734 } 14735 } 14736 } 14737 function getActiveEditorState() { 14738 if (activeEditorState === null) { 14739 { 14740 formatDevErrorMessage(`Unable to find an active editor state. State helpers or node methods can only be used synchronously during the callback of editor.update(), editor.read(), or editorState.read().${collectBuildInformation()}`); 14741 } 14742 } 14743 return activeEditorState; 14744 } 14745 function getActiveEditor() { 14746 if (activeEditor === null) { 14747 { 14748 formatDevErrorMessage(`Unable to find an active editor. This method can only be used synchronously during the callback of editor.update(), editor.read(), or editor.getEditorState().read(..., {editor}).${collectBuildInformation()}`); 14749 } 14750 } 14751 return activeEditor; 14752 } 14753 function collectBuildInformation() { 14754 let compatibleEditors = 0; 14755 const incompatibleEditors = /* @__PURE__ */ new Set(); 14756 const thisVersion = LexicalEditor.version; 14757 if (typeof window !== "undefined") { 14758 for (const node of document.querySelectorAll("[contenteditable]")) { 14759 const editor = getEditorPropertyFromDOMNode(node); 14760 if (isLexicalEditor(editor)) { 14761 compatibleEditors++; 14762 } else if (editor) { 14763 let version = String(editor.constructor.version || "<0.17.1"); 14764 if (version === thisVersion) { 14765 version += " (separately built, likely a bundler configuration issue)"; 14766 } 14767 incompatibleEditors.add(version); 14768 } 14769 } 14770 } 14771 let output = ` Detected on the page: ${compatibleEditors} compatible editor(s) with version ${thisVersion}`; 14772 if (incompatibleEditors.size) { 14773 output += ` and incompatible editors with versions ${Array.from(incompatibleEditors).join(", ")}`; 14774 } 14775 return output; 14776 } 14777 function internalGetActiveEditor() { 14778 return activeEditor; 14779 } 14780 function internalGetActiveEditorState() { 14781 return activeEditorState; 14782 } 14783 function $applyTransforms(editor, node, transformsCache) { 14784 const type = node.__type; 14785 const registeredNode = getRegisteredNodeOrThrow(editor, type); 14786 let transformsArr = transformsCache.get(type); 14787 if (transformsArr === void 0) { 14788 transformsArr = Array.from(registeredNode.transforms); 14789 transformsCache.set(type, transformsArr); 14790 } 14791 const transformsArrLength = transformsArr.length; 14792 for (let i2 = 0; i2 < transformsArrLength; i2++) { 14793 transformsArr[i2](node); 14794 if (!node.isAttached()) { 14795 break; 14796 } 14797 } 14798 } 14799 function $isNodeValidForTransform(node, compositionKey) { 14800 return node !== void 0 && // We don't want to transform nodes being composed 14801 node.__key !== compositionKey && node.isAttached(); 14802 } 14803 function $normalizeAllDirtyTextNodes(editorState, editor) { 14804 const dirtyLeaves = editor._dirtyLeaves; 14805 const nodeMap = editorState._nodeMap; 14806 for (const nodeKey of dirtyLeaves) { 14807 const node = nodeMap.get(nodeKey); 14808 if ($isTextNode(node) && node.isAttached() && node.isSimpleText() && !node.isUnmergeable()) { 14809 $normalizeTextNode(node); 14810 } 14811 } 14812 } 14813 function addTags(editor, tags) { 14814 if (!tags) { 14815 return; 14816 } 14817 const updateTags = editor._updateTags; 14818 let tags_ = tags; 14819 if (!Array.isArray(tags)) { 14820 tags_ = [tags]; 14821 } 14822 for (const tag of tags_) { 14823 updateTags.add(tag); 14824 } 14825 } 14826 function $applyAllTransforms(editorState, editor) { 14827 const dirtyLeaves = editor._dirtyLeaves; 14828 const dirtyElements = editor._dirtyElements; 14829 const nodeMap = editorState._nodeMap; 14830 const compositionKey = $getCompositionKey(); 14831 const transformsCache = /* @__PURE__ */ new Map(); 14832 let untransformedDirtyLeaves = dirtyLeaves; 14833 let untransformedDirtyLeavesLength = untransformedDirtyLeaves.size; 14834 let untransformedDirtyElements = dirtyElements; 14835 let untransformedDirtyElementsLength = untransformedDirtyElements.size; 14836 while (untransformedDirtyLeavesLength > 0 || untransformedDirtyElementsLength > 0) { 14837 if (untransformedDirtyLeavesLength > 0) { 14838 editor._dirtyLeaves = /* @__PURE__ */ new Set(); 14839 for (const nodeKey of untransformedDirtyLeaves) { 14840 const node = nodeMap.get(nodeKey); 14841 if ($isTextNode(node) && node.isAttached() && node.isSimpleText() && !node.isUnmergeable()) { 14842 $normalizeTextNode(node); 14843 } 14844 if (node !== void 0 && $isNodeValidForTransform(node, compositionKey)) { 14845 $applyTransforms(editor, node, transformsCache); 14846 } 14847 dirtyLeaves.add(nodeKey); 14848 } 14849 untransformedDirtyLeaves = editor._dirtyLeaves; 14850 untransformedDirtyLeavesLength = untransformedDirtyLeaves.size; 14851 if (untransformedDirtyLeavesLength > 0) { 14852 infiniteTransformCount++; 14853 continue; 14854 } 14855 } 14856 editor._dirtyLeaves = /* @__PURE__ */ new Set(); 14857 editor._dirtyElements = /* @__PURE__ */ new Map(); 14858 const rootDirty = untransformedDirtyElements.delete("root"); 14859 if (rootDirty) { 14860 untransformedDirtyElements.set("root", true); 14861 } 14862 for (const currentUntransformedDirtyElement of untransformedDirtyElements) { 14863 const nodeKey = currentUntransformedDirtyElement[0]; 14864 const intentionallyMarkedAsDirty = currentUntransformedDirtyElement[1]; 14865 dirtyElements.set(nodeKey, intentionallyMarkedAsDirty); 14866 if (!intentionallyMarkedAsDirty) { 14867 continue; 14868 } 14869 const node = nodeMap.get(nodeKey); 14870 if (node !== void 0 && $isNodeValidForTransform(node, compositionKey)) { 14871 $applyTransforms(editor, node, transformsCache); 14872 } 14873 } 14874 untransformedDirtyLeaves = editor._dirtyLeaves; 14875 untransformedDirtyLeavesLength = untransformedDirtyLeaves.size; 14876 untransformedDirtyElements = editor._dirtyElements; 14877 untransformedDirtyElementsLength = untransformedDirtyElements.size; 14878 infiniteTransformCount++; 14879 } 14880 editor._dirtyLeaves = dirtyLeaves; 14881 editor._dirtyElements = dirtyElements; 14882 } 14883 function $parseSerializedNode(serializedNode) { 14884 const internalSerializedNode = serializedNode; 14885 return $parseSerializedNodeImpl(internalSerializedNode, getActiveEditor()._nodes); 14886 } 14887 function $parseSerializedNodeImpl(serializedNode, registeredNodes) { 14888 const type = serializedNode.type; 14889 const registeredNode = registeredNodes.get(type); 14890 if (registeredNode === void 0) { 14891 { 14892 formatDevErrorMessage(`parseEditorState: type "${type}" + not found`); 14893 } 14894 } 14895 const nodeClass = registeredNode.klass; 14896 if (serializedNode.type !== nodeClass.getType()) { 14897 { 14898 formatDevErrorMessage(`LexicalNode: Node ${nodeClass.name} does not implement .importJSON().`); 14899 } 14900 } 14901 const node = nodeClass.importJSON(serializedNode); 14902 const children = serializedNode.children; 14903 if ($isElementNode(node) && Array.isArray(children)) { 14904 for (let i2 = 0; i2 < children.length; i2++) { 14905 const serializedJSONChildNode = children[i2]; 14906 const childNode = $parseSerializedNodeImpl(serializedJSONChildNode, registeredNodes); 14907 node.append(childNode); 14908 } 14909 } 14910 return node; 14911 } 14912 function parseEditorState(serializedEditorState, editor, updateFn) { 14913 const editorState = createEmptyEditorState(); 14914 const previousActiveEditorState = activeEditorState; 14915 const previousReadOnlyMode = isReadOnlyMode; 14916 const previousActiveEditor = activeEditor; 14917 const previousDirtyElements = editor._dirtyElements; 14918 const previousDirtyLeaves = editor._dirtyLeaves; 14919 const previousCloneNotNeeded = editor._cloneNotNeeded; 14920 const previousDirtyType = editor._dirtyType; 14921 editor._dirtyElements = /* @__PURE__ */ new Map(); 14922 editor._dirtyLeaves = /* @__PURE__ */ new Set(); 14923 editor._cloneNotNeeded = /* @__PURE__ */ new Set(); 14924 editor._dirtyType = 0; 14925 activeEditorState = editorState; 14926 isReadOnlyMode = false; 14927 activeEditor = editor; 14928 setPendingNodeToClone(null); 14929 try { 14930 const registeredNodes = editor._nodes; 14931 const serializedNode = serializedEditorState.root; 14932 $parseSerializedNodeImpl(serializedNode, registeredNodes); 14933 if (updateFn) { 14934 updateFn(); 14935 } 14936 editorState._readOnly = true; 14937 { 14938 handleDEVOnlyPendingUpdateGuarantees(editorState); 14939 } 14940 } catch (error) { 14941 if (error instanceof Error) { 14942 editor._onError(error); 14943 } 14944 } finally { 14945 editor._dirtyElements = previousDirtyElements; 14946 editor._dirtyLeaves = previousDirtyLeaves; 14947 editor._cloneNotNeeded = previousCloneNotNeeded; 14948 editor._dirtyType = previousDirtyType; 14949 activeEditorState = previousActiveEditorState; 14950 isReadOnlyMode = previousReadOnlyMode; 14951 activeEditor = previousActiveEditor; 14952 } 14953 return editorState; 14954 } 14955 function readEditorState(editor, editorState, callbackFn) { 14956 const previousActiveEditorState = activeEditorState; 14957 const previousReadOnlyMode = isReadOnlyMode; 14958 const previousActiveEditor = activeEditor; 14959 activeEditorState = editorState; 14960 isReadOnlyMode = true; 14961 activeEditor = editor; 14962 try { 14963 return callbackFn(); 14964 } finally { 14965 activeEditorState = previousActiveEditorState; 14966 isReadOnlyMode = previousReadOnlyMode; 14967 activeEditor = previousActiveEditor; 14968 } 14969 } 14970 function handleDEVOnlyPendingUpdateGuarantees(pendingEditorState) { 14971 const nodeMap = pendingEditorState._nodeMap; 14972 nodeMap.set = () => { 14973 throw new Error("Cannot call set() on a frozen Lexical node map"); 14974 }; 14975 nodeMap.clear = () => { 14976 throw new Error("Cannot call clear() on a frozen Lexical node map"); 14977 }; 14978 nodeMap.delete = () => { 14979 throw new Error("Cannot call delete() on a frozen Lexical node map"); 14980 }; 14981 } 14982 function $commitPendingUpdates(editor, recoveryEditorState) { 14983 const pendingEditorState = editor._pendingEditorState; 14984 const rootElement = editor._rootElement; 14985 const shouldSkipDOM = editor._headless || rootElement === null; 14986 if (pendingEditorState === null) { 14987 if (editor._deferred.length > 0) { 14988 triggerDeferredUpdateCallbacks(editor, editor._deferred); 14989 } 14990 return; 14991 } 14992 const currentEditorState = editor._editorState; 14993 const currentSelection = currentEditorState._selection; 14994 const pendingSelection = pendingEditorState._selection; 14995 const needsUpdate = editor._dirtyType !== NO_DIRTY_NODES; 14996 const previousActiveEditorState = activeEditorState; 14997 const previousReadOnlyMode = isReadOnlyMode; 14998 const previousActiveEditor = activeEditor; 14999 const previouslyUpdating = editor._updating; 15000 const observer = editor._observer; 15001 let mutatedNodes2 = null; 15002 editor._pendingEditorState = null; 15003 editor._editorState = pendingEditorState; 15004 if (!shouldSkipDOM && needsUpdate && observer !== null) { 15005 activeEditor = editor; 15006 activeEditorState = pendingEditorState; 15007 isReadOnlyMode = false; 15008 editor._updating = true; 15009 try { 15010 const dirtyType = editor._dirtyType; 15011 const dirtyElements2 = editor._dirtyElements; 15012 const dirtyLeaves2 = editor._dirtyLeaves; 15013 observer.disconnect(); 15014 mutatedNodes2 = $reconcileRoot(currentEditorState, pendingEditorState, editor, dirtyType, dirtyElements2, dirtyLeaves2); 15015 } catch (error) { 15016 if (error instanceof Error) { 15017 editor._onError(error); 15018 } 15019 if (!isAttemptingToRecoverFromReconcilerError) { 15020 resetEditor(editor, null, rootElement, pendingEditorState); 15021 initMutationObserver(editor); 15022 editor._dirtyType = FULL_RECONCILE; 15023 isAttemptingToRecoverFromReconcilerError = true; 15024 $commitPendingUpdates(editor, currentEditorState); 15025 isAttemptingToRecoverFromReconcilerError = false; 15026 } else { 15027 throw error; 15028 } 15029 return; 15030 } finally { 15031 observer.observe(rootElement, observerOptions); 15032 editor._updating = previouslyUpdating; 15033 activeEditorState = previousActiveEditorState; 15034 isReadOnlyMode = previousReadOnlyMode; 15035 activeEditor = previousActiveEditor; 15036 } 15037 } 15038 if (!pendingEditorState._readOnly) { 15039 pendingEditorState._readOnly = true; 15040 { 15041 handleDEVOnlyPendingUpdateGuarantees(pendingEditorState); 15042 if ($isRangeSelection(pendingSelection)) { 15043 Object.freeze(pendingSelection.anchor); 15044 Object.freeze(pendingSelection.focus); 15045 } 15046 Object.freeze(pendingSelection); 15047 } 15048 } 15049 const dirtyLeaves = editor._dirtyLeaves; 15050 const dirtyElements = editor._dirtyElements; 15051 const normalizedNodes = editor._normalizedNodes; 15052 const tags = editor._updateTags; 15053 const deferred = editor._deferred; 15054 if (needsUpdate) { 15055 editor._dirtyType = NO_DIRTY_NODES; 15056 editor._cloneNotNeeded.clear(); 15057 editor._dirtyLeaves = /* @__PURE__ */ new Set(); 15058 editor._dirtyElements = /* @__PURE__ */ new Map(); 15059 editor._normalizedNodes = /* @__PURE__ */ new Set(); 15060 editor._updateTags = /* @__PURE__ */ new Set(); 15061 } 15062 $garbageCollectDetachedDecorators(editor, pendingEditorState); 15063 const domSelection = shouldSkipDOM ? null : getDOMSelection(getWindow(editor)); 15064 if (editor._editable && // domSelection will be null in headless 15065 domSelection !== null && (needsUpdate || pendingSelection === null || pendingSelection.dirty || !pendingSelection.is(currentSelection)) && rootElement !== null && !tags.has(SKIP_DOM_SELECTION_TAG)) { 15066 activeEditor = editor; 15067 activeEditorState = pendingEditorState; 15068 try { 15069 if (observer !== null) { 15070 observer.disconnect(); 15071 } 15072 if (needsUpdate || pendingSelection === null || pendingSelection.dirty) { 15073 const blockCursorElement = editor._blockCursorElement; 15074 if (blockCursorElement !== null) { 15075 removeDOMBlockCursorElement(blockCursorElement, editor, rootElement); 15076 } 15077 $updateDOMSelection(currentSelection, pendingSelection, editor, domSelection, tags, rootElement); 15078 } 15079 updateDOMBlockCursorElement(editor, rootElement, pendingSelection); 15080 } finally { 15081 if (observer !== null) { 15082 observer.observe(rootElement, observerOptions); 15083 } 15084 activeEditor = previousActiveEditor; 15085 activeEditorState = previousActiveEditorState; 15086 } 15087 } 15088 if (mutatedNodes2 !== null) { 15089 triggerMutationListeners(editor, mutatedNodes2, tags, dirtyLeaves, currentEditorState); 15090 } 15091 if (!$isRangeSelection(pendingSelection) && pendingSelection !== null && (currentSelection === null || !currentSelection.is(pendingSelection))) { 15092 editor.dispatchCommand(SELECTION_CHANGE_COMMAND, void 0); 15093 } 15094 const pendingDecorators = editor._pendingDecorators; 15095 if (pendingDecorators !== null) { 15096 editor._decorators = pendingDecorators; 15097 editor._pendingDecorators = null; 15098 triggerListeners("decorator", editor, true, pendingDecorators); 15099 } 15100 triggerTextContentListeners(editor, recoveryEditorState || currentEditorState, pendingEditorState); 15101 triggerListeners("update", editor, true, { 15102 dirtyElements, 15103 dirtyLeaves, 15104 editorState: pendingEditorState, 15105 mutatedNodes: mutatedNodes2, 15106 normalizedNodes, 15107 prevEditorState: recoveryEditorState || currentEditorState, 15108 tags 15109 }); 15110 triggerDeferredUpdateCallbacks(editor, deferred); 15111 $triggerEnqueuedUpdates(editor); 15112 } 15113 function triggerTextContentListeners(editor, currentEditorState, pendingEditorState) { 15114 const currentTextContent = getEditorStateTextContent(currentEditorState); 15115 const latestTextContent = getEditorStateTextContent(pendingEditorState); 15116 if (currentTextContent !== latestTextContent) { 15117 triggerListeners("textcontent", editor, true, latestTextContent); 15118 } 15119 } 15120 function triggerMutationListeners(editor, mutatedNodes2, updateTags, dirtyLeaves, prevEditorState) { 15121 const listeners = Array.from(editor._listeners.mutation); 15122 const listenersLength = listeners.length; 15123 for (let i2 = 0; i2 < listenersLength; i2++) { 15124 const [listener, klassSet] = listeners[i2]; 15125 for (const klass of klassSet) { 15126 const mutatedNodesByType = mutatedNodes2.get(klass); 15127 if (mutatedNodesByType !== void 0) { 15128 listener(mutatedNodesByType, { 15129 dirtyLeaves, 15130 prevEditorState, 15131 updateTags 15132 }); 15133 } 15134 } 15135 } 15136 } 15137 function triggerListeners(type, editor, isCurrentlyEnqueuingUpdates, ...payload) { 15138 const previouslyUpdating = editor._updating; 15139 editor._updating = isCurrentlyEnqueuingUpdates; 15140 try { 15141 const listenerMap = editor._listeners[type]; 15142 const listeners = Array.from(listenerMap); 15143 for (const [listener, unregister] of listeners) { 15144 if (unregister) { 15145 unregister(); 15146 } 15147 const nextUnregister = listener(...payload); 15148 if (listenerMap.has(listener)) { 15149 listenerMap.set(listener, nextUnregister); 15150 } else if (nextUnregister) { 15151 nextUnregister(); 15152 } 15153 } 15154 } finally { 15155 editor._updating = previouslyUpdating; 15156 } 15157 } 15158 function triggerCommandListeners(editor, type, payload, fromEditor) { 15159 const editors = getEditorsToPropagate(editor); 15160 let updatingParentEditor; 15161 for (let i2 = 4; i2 >= 0; i2--) { 15162 for (let e2 = 0; e2 < editors.length; e2++) { 15163 const currentEditor = editors[e2]; 15164 if (e2 > 0 && currentEditor._updating) { 15165 updatingParentEditor = currentEditor; 15166 break; 15167 } 15168 const commandListeners = currentEditor._commands; 15169 const listenerInPriorityOrder = commandListeners.get(type); 15170 if (listenerInPriorityOrder !== void 0) { 15171 const listenersSet = listenerInPriorityOrder[i2]; 15172 if (listenersSet.size > 0) { 15173 let returnVal = false; 15174 updateEditorSync(currentEditor, () => { 15175 for (const listener of listenersSet) { 15176 if (listener(payload, fromEditor)) { 15177 returnVal = true; 15178 return; 15179 } 15180 } 15181 }); 15182 if (returnVal) { 15183 return returnVal; 15184 } 15185 } 15186 } 15187 } 15188 } 15189 if (updatingParentEditor) { 15190 updatingParentEditor.update(() => { 15191 triggerCommandListeners(updatingParentEditor, type, payload, fromEditor); 15192 }); 15193 } 15194 return false; 15195 } 15196 function $triggerEnqueuedUpdates(editor) { 15197 const queuedUpdates = editor._updates; 15198 if (queuedUpdates.length !== 0) { 15199 const queuedUpdate = queuedUpdates.shift(); 15200 if (queuedUpdate) { 15201 const [updateFn, options] = queuedUpdate; 15202 $beginUpdate(editor, updateFn, options); 15203 } 15204 } 15205 } 15206 function triggerDeferredUpdateCallbacks(editor, deferred) { 15207 editor._deferred = []; 15208 if (deferred.length !== 0) { 15209 const previouslyUpdating = editor._updating; 15210 editor._updating = true; 15211 try { 15212 for (let i2 = 0; i2 < deferred.length; i2++) { 15213 deferred[i2](); 15214 } 15215 } finally { 15216 editor._updating = previouslyUpdating; 15217 } 15218 } 15219 } 15220 function $processNestedUpdates(editor, initialSkipTransforms) { 15221 const queuedUpdates = editor._updates; 15222 let skipTransforms = initialSkipTransforms || false; 15223 while (queuedUpdates.length !== 0) { 15224 const queuedUpdate = queuedUpdates.shift(); 15225 if (queuedUpdate) { 15226 const [nextUpdateFn, options] = queuedUpdate; 15227 const pendingEditorState = editor._pendingEditorState; 15228 let onUpdate; 15229 if (options !== void 0) { 15230 onUpdate = options.onUpdate; 15231 if (options.skipTransforms) { 15232 skipTransforms = true; 15233 } 15234 if (options.discrete) { 15235 if (!(pendingEditorState !== null)) { 15236 formatDevErrorMessage(`Unexpected empty pending editor state on discrete nested update`); 15237 } 15238 pendingEditorState._flushSync = true; 15239 } 15240 if (onUpdate) { 15241 editor._deferred.push(onUpdate); 15242 } 15243 addTags(editor, options.tag); 15244 } 15245 if (pendingEditorState == null) { 15246 $beginUpdate(editor, nextUpdateFn, options); 15247 } else { 15248 nextUpdateFn(); 15249 } 15250 } 15251 } 15252 return skipTransforms; 15253 } 15254 function $beginUpdate(editor, updateFn, options) { 15255 const updateTags = editor._updateTags; 15256 let onUpdate; 15257 let skipTransforms = false; 15258 let discrete = false; 15259 if (options !== void 0) { 15260 onUpdate = options.onUpdate; 15261 addTags(editor, options.tag); 15262 skipTransforms = options.skipTransforms || false; 15263 discrete = options.discrete || false; 15264 } 15265 if (onUpdate) { 15266 editor._deferred.push(onUpdate); 15267 } 15268 const currentEditorState = editor._editorState; 15269 let pendingEditorState = editor._pendingEditorState; 15270 let editorStateWasCloned = false; 15271 if (pendingEditorState === null || pendingEditorState._readOnly) { 15272 pendingEditorState = editor._pendingEditorState = cloneEditorState(pendingEditorState || currentEditorState); 15273 editorStateWasCloned = true; 15274 } 15275 pendingEditorState._flushSync = discrete; 15276 const previousActiveEditorState = activeEditorState; 15277 const previousReadOnlyMode = isReadOnlyMode; 15278 const previousActiveEditor = activeEditor; 15279 const previouslyUpdating = editor._updating; 15280 activeEditorState = pendingEditorState; 15281 isReadOnlyMode = false; 15282 editor._updating = true; 15283 activeEditor = editor; 15284 const headless = editor._headless || editor.getRootElement() === null; 15285 setPendingNodeToClone(null); 15286 try { 15287 if (editorStateWasCloned) { 15288 if (headless) { 15289 if (currentEditorState._selection !== null) { 15290 pendingEditorState._selection = currentEditorState._selection.clone(); 15291 } 15292 } else { 15293 pendingEditorState._selection = $internalCreateSelection(editor, options && options.event || null); 15294 } 15295 } 15296 const startingCompositionKey = editor._compositionKey; 15297 updateFn(); 15298 skipTransforms = $processNestedUpdates(editor, skipTransforms); 15299 applySelectionTransforms(pendingEditorState, editor); 15300 if (editor._dirtyType !== NO_DIRTY_NODES) { 15301 if (skipTransforms) { 15302 $normalizeAllDirtyTextNodes(pendingEditorState, editor); 15303 } else { 15304 $applyAllTransforms(pendingEditorState, editor); 15305 } 15306 $processNestedUpdates(editor); 15307 $garbageCollectDetachedNodes(currentEditorState, pendingEditorState, editor._dirtyLeaves, editor._dirtyElements); 15308 } 15309 const endingCompositionKey = editor._compositionKey; 15310 if (startingCompositionKey !== endingCompositionKey) { 15311 pendingEditorState._flushSync = true; 15312 } 15313 const pendingSelection = pendingEditorState._selection; 15314 if ($isRangeSelection(pendingSelection)) { 15315 const pendingNodeMap = pendingEditorState._nodeMap; 15316 const anchorKey = pendingSelection.anchor.key; 15317 const focusKey = pendingSelection.focus.key; 15318 if (pendingNodeMap.get(anchorKey) === void 0 || pendingNodeMap.get(focusKey) === void 0) { 15319 { 15320 formatDevErrorMessage(`updateEditor: selection has been lost because the previously selected nodes have been removed and selection wasn't moved to another node. Ensure selection changes after removing/replacing a selected node.`); 15321 } 15322 } 15323 } else if ($isNodeSelection(pendingSelection)) { 15324 if (pendingSelection._nodes.size === 0) { 15325 pendingEditorState._selection = null; 15326 } 15327 } 15328 } catch (error) { 15329 if (error instanceof Error) { 15330 editor._onError(error); 15331 } 15332 editor._pendingEditorState = currentEditorState; 15333 editor._dirtyType = FULL_RECONCILE; 15334 editor._cloneNotNeeded.clear(); 15335 editor._dirtyLeaves = /* @__PURE__ */ new Set(); 15336 editor._dirtyElements.clear(); 15337 $commitPendingUpdates(editor); 15338 return; 15339 } finally { 15340 activeEditorState = previousActiveEditorState; 15341 isReadOnlyMode = previousReadOnlyMode; 15342 activeEditor = previousActiveEditor; 15343 editor._updating = previouslyUpdating; 15344 infiniteTransformCount = 0; 15345 } 15346 const shouldUpdate = editor._dirtyType !== NO_DIRTY_NODES || editor._deferred.length > 0 || editorStateHasDirtySelection(pendingEditorState, editor); 15347 if (shouldUpdate) { 15348 if (pendingEditorState._flushSync) { 15349 pendingEditorState._flushSync = false; 15350 $commitPendingUpdates(editor); 15351 } else if (editorStateWasCloned) { 15352 scheduleMicroTask(() => { 15353 $commitPendingUpdates(editor); 15354 }); 15355 } 15356 } else { 15357 pendingEditorState._flushSync = false; 15358 if (editorStateWasCloned) { 15359 updateTags.clear(); 15360 editor._deferred = []; 15361 editor._pendingEditorState = null; 15362 } 15363 } 15364 } 15365 function updateEditorSync(editor, updateFn, options) { 15366 if (activeEditor === editor && options === void 0) { 15367 updateFn(); 15368 } else { 15369 $beginUpdate(editor, updateFn, options); 15370 } 15371 } 15372 function updateEditor(editor, updateFn, options) { 15373 if (editor._updating) { 15374 editor._updates.push([updateFn, options]); 15375 } else { 15376 $beginUpdate(editor, updateFn, options); 15377 } 15378 } 15379 var ElementDOMSlot = class _ElementDOMSlot { 15380 element; 15381 before; 15382 after; 15383 constructor(element, before, after) { 15384 this.element = element; 15385 this.before = before || null; 15386 this.after = after || null; 15387 } 15388 /** 15389 * Return a new ElementDOMSlot where all managed children will be inserted before this node 15390 */ 15391 withBefore(before) { 15392 return new _ElementDOMSlot(this.element, before, this.after); 15393 } 15394 /** 15395 * Return a new ElementDOMSlot where all managed children will be inserted after this node 15396 */ 15397 withAfter(after) { 15398 return new _ElementDOMSlot(this.element, this.before, after); 15399 } 15400 /** 15401 * Return a new ElementDOMSlot with an updated root element 15402 */ 15403 withElement(element) { 15404 if (this.element === element) { 15405 return this; 15406 } 15407 return new _ElementDOMSlot(element, this.before, this.after); 15408 } 15409 /** 15410 * Insert the given child before this.before and any reconciler managed line break node, 15411 * or append it if this.before is not defined 15412 */ 15413 insertChild(dom) { 15414 const before = this.before || this.getManagedLineBreak(); 15415 if (!(before === null || before.parentElement === this.element)) { 15416 formatDevErrorMessage(`ElementDOMSlot.insertChild: before is not in element`); 15417 } 15418 this.element.insertBefore(dom, before); 15419 return this; 15420 } 15421 /** 15422 * Remove the managed child from this container, will throw if it was not already there 15423 */ 15424 removeChild(dom) { 15425 if (!(dom.parentElement === this.element)) { 15426 formatDevErrorMessage(`ElementDOMSlot.removeChild: dom is not in element`); 15427 } 15428 this.element.removeChild(dom); 15429 return this; 15430 } 15431 /** 15432 * Replace managed child prevDom with dom. Will throw if prevDom is not a child 15433 * 15434 * @param dom The new node to replace prevDom 15435 * @param prevDom the node that will be replaced 15436 */ 15437 replaceChild(dom, prevDom) { 15438 if (!(prevDom.parentElement === this.element)) { 15439 formatDevErrorMessage(`ElementDOMSlot.replaceChild: prevDom is not in element`); 15440 } 15441 this.element.replaceChild(dom, prevDom); 15442 return this; 15443 } 15444 /** 15445 * Returns the first managed child of this node, 15446 * which will either be this.after.nextSibling or this.element.firstChild, 15447 * and will never be this.before if it is defined. 15448 */ 15449 getFirstChild() { 15450 const firstChild = this.after ? this.after.nextSibling : this.element.firstChild; 15451 return firstChild === this.before || firstChild === this.getManagedLineBreak() ? null : firstChild; 15452 } 15453 /** 15454 * @internal 15455 */ 15456 getManagedLineBreak() { 15457 const element = this.element; 15458 return element.__lexicalLineBreak || null; 15459 } 15460 /** @internal */ 15461 setManagedLineBreak(lineBreakType) { 15462 if (lineBreakType === null) { 15463 this.removeManagedLineBreak(); 15464 } else { 15465 const webkitHack = lineBreakType === "decorator" && (IS_APPLE_WEBKIT || IS_IOS || IS_SAFARI); 15466 this.insertManagedLineBreak(webkitHack); 15467 } 15468 } 15469 /** @internal */ 15470 removeManagedLineBreak() { 15471 const br = this.getManagedLineBreak(); 15472 if (br) { 15473 const element = this.element; 15474 const sibling = br.nodeName === "IMG" ? br.nextSibling : null; 15475 if (sibling) { 15476 element.removeChild(sibling); 15477 } 15478 element.removeChild(br); 15479 element.__lexicalLineBreak = void 0; 15480 } 15481 } 15482 /** @internal */ 15483 insertManagedLineBreak(webkitHack) { 15484 const prevBreak = this.getManagedLineBreak(); 15485 if (prevBreak) { 15486 if (webkitHack === (prevBreak.nodeName === "IMG")) { 15487 return; 15488 } 15489 this.removeManagedLineBreak(); 15490 } 15491 const element = this.element; 15492 const before = this.before; 15493 const br = document.createElement("br"); 15494 element.insertBefore(br, before); 15495 if (webkitHack) { 15496 const img = document.createElement("img"); 15497 img.setAttribute("data-lexical-linebreak", "true"); 15498 img.style.setProperty("display", "inline", "important"); 15499 img.style.setProperty("border", "0px", "important"); 15500 img.style.setProperty("margin", "0px", "important"); 15501 img.alt = ""; 15502 element.insertBefore(img, br); 15503 element.__lexicalLineBreak = img; 15504 } else { 15505 element.__lexicalLineBreak = br; 15506 } 15507 } 15508 /** 15509 * @internal 15510 * 15511 * Returns the offset of the first child 15512 */ 15513 getFirstChildOffset() { 15514 let i2 = 0; 15515 for (let node = this.after; node !== null; node = node.previousSibling) { 15516 i2++; 15517 } 15518 return i2; 15519 } 15520 /** 15521 * @internal 15522 */ 15523 resolveChildIndex(element, elementDOM, initialDOM, initialOffset) { 15524 if (initialDOM === this.element) { 15525 const firstChildOffset = this.getFirstChildOffset(); 15526 return [element, Math.min(firstChildOffset + element.getChildrenSize(), Math.max(firstChildOffset, initialOffset))]; 15527 } 15528 const initialPath = indexPath(elementDOM, initialDOM); 15529 initialPath.push(initialOffset); 15530 const elementPath = indexPath(elementDOM, this.element); 15531 let offset3 = element.getIndexWithinParent(); 15532 for (let i2 = 0; i2 < elementPath.length; i2++) { 15533 const target = initialPath[i2]; 15534 const source = elementPath[i2]; 15535 if (target === void 0 || target < source) { 15536 break; 15537 } else if (target > source) { 15538 offset3 += 1; 15539 break; 15540 } 15541 } 15542 return [element.getParentOrThrow(), offset3]; 15543 } 15544 }; 15545 function indexPath(root, child) { 15546 const path = []; 15547 let node = child; 15548 for (; node !== root && node !== null; node = node.parentNode) { 15549 let i2 = 0; 15550 for (let sibling = node.previousSibling; sibling !== null; sibling = sibling.previousSibling) { 15551 i2++; 15552 } 15553 path.push(i2); 15554 } 15555 if (!(node === root)) { 15556 formatDevErrorMessage(`indexPath: root is not a parent of child`); 15557 } 15558 return path.reverse(); 15559 } 15560 var ElementNode = class extends LexicalNode { 15561 /** @internal */ 15562 /** @internal */ 15563 __first; 15564 /** @internal */ 15565 __last; 15566 /** @internal */ 15567 __size; 15568 /** @internal */ 15569 __format; 15570 /** @internal */ 15571 __style; 15572 /** @internal */ 15573 __indent; 15574 /** @internal */ 15575 __dir; 15576 /** @internal */ 15577 __textFormat; 15578 /** @internal */ 15579 __textStyle; 15580 constructor(key) { 15581 super(key); 15582 this.__first = null; 15583 this.__last = null; 15584 this.__size = 0; 15585 this.__format = 0; 15586 this.__style = ""; 15587 this.__indent = 0; 15588 this.__dir = null; 15589 this.__textFormat = 0; 15590 this.__textStyle = ""; 15591 } 15592 afterCloneFrom(prevNode) { 15593 super.afterCloneFrom(prevNode); 15594 if (this.__key === prevNode.__key) { 15595 this.__first = prevNode.__first; 15596 this.__last = prevNode.__last; 15597 this.__size = prevNode.__size; 15598 } 15599 this.__indent = prevNode.__indent; 15600 this.__format = prevNode.__format; 15601 this.__style = prevNode.__style; 15602 this.__dir = prevNode.__dir; 15603 this.__textFormat = prevNode.__textFormat; 15604 this.__textStyle = prevNode.__textStyle; 15605 } 15606 getFormat() { 15607 const self2 = this.getLatest(); 15608 return self2.__format; 15609 } 15610 getFormatType() { 15611 const format = this.getFormat(); 15612 return ELEMENT_FORMAT_TO_TYPE[format] || ""; 15613 } 15614 getStyle() { 15615 const self2 = this.getLatest(); 15616 return self2.__style; 15617 } 15618 getIndent() { 15619 const self2 = this.getLatest(); 15620 return self2.__indent; 15621 } 15622 getChildren() { 15623 const children = []; 15624 let child = this.getFirstChild(); 15625 while (child !== null) { 15626 children.push(child); 15627 child = child.getNextSibling(); 15628 } 15629 return children; 15630 } 15631 getChildrenKeys() { 15632 const children = []; 15633 let child = this.getFirstChild(); 15634 while (child !== null) { 15635 children.push(child.__key); 15636 child = child.getNextSibling(); 15637 } 15638 return children; 15639 } 15640 getChildrenSize() { 15641 const self2 = this.getLatest(); 15642 return self2.__size; 15643 } 15644 isEmpty() { 15645 return this.getChildrenSize() === 0; 15646 } 15647 isDirty() { 15648 const editor = getActiveEditor(); 15649 const dirtyElements = editor._dirtyElements; 15650 return dirtyElements !== null && dirtyElements.has(this.__key); 15651 } 15652 isLastChild() { 15653 const self2 = this.getLatest(); 15654 const parentLastChild = this.getParentOrThrow().getLastChild(); 15655 return parentLastChild !== null && parentLastChild.is(self2); 15656 } 15657 getAllTextNodes() { 15658 const textNodes = []; 15659 let child = this.getFirstChild(); 15660 while (child !== null) { 15661 if ($isTextNode(child)) { 15662 textNodes.push(child); 15663 } 15664 if ($isElementNode(child)) { 15665 const subChildrenNodes = child.getAllTextNodes(); 15666 textNodes.push(...subChildrenNodes); 15667 } 15668 child = child.getNextSibling(); 15669 } 15670 return textNodes; 15671 } 15672 getFirstDescendant() { 15673 let node = this.getFirstChild(); 15674 while ($isElementNode(node)) { 15675 const child = node.getFirstChild(); 15676 if (child === null) { 15677 break; 15678 } 15679 node = child; 15680 } 15681 return node; 15682 } 15683 getLastDescendant() { 15684 let node = this.getLastChild(); 15685 while ($isElementNode(node)) { 15686 const child = node.getLastChild(); 15687 if (child === null) { 15688 break; 15689 } 15690 node = child; 15691 } 15692 return node; 15693 } 15694 getDescendantByIndex(index) { 15695 const children = this.getChildren(); 15696 const childrenLength = children.length; 15697 if (index >= childrenLength) { 15698 const resolvedNode2 = children[childrenLength - 1]; 15699 return $isElementNode(resolvedNode2) && resolvedNode2.getLastDescendant() || resolvedNode2 || null; 15700 } 15701 const resolvedNode = children[index]; 15702 return $isElementNode(resolvedNode) && resolvedNode.getFirstDescendant() || resolvedNode || null; 15703 } 15704 getFirstChild() { 15705 const self2 = this.getLatest(); 15706 const firstKey = self2.__first; 15707 return firstKey === null ? null : $getNodeByKey(firstKey); 15708 } 15709 getFirstChildOrThrow() { 15710 const firstChild = this.getFirstChild(); 15711 if (firstChild === null) { 15712 { 15713 formatDevErrorMessage(`Expected node ${this.__key} to have a first child.`); 15714 } 15715 } 15716 return firstChild; 15717 } 15718 getLastChild() { 15719 const self2 = this.getLatest(); 15720 const lastKey = self2.__last; 15721 return lastKey === null ? null : $getNodeByKey(lastKey); 15722 } 15723 getLastChildOrThrow() { 15724 const lastChild = this.getLastChild(); 15725 if (lastChild === null) { 15726 { 15727 formatDevErrorMessage(`Expected node ${this.__key} to have a last child.`); 15728 } 15729 } 15730 return lastChild; 15731 } 15732 getChildAtIndex(index) { 15733 const size2 = this.getChildrenSize(); 15734 let node; 15735 let i2; 15736 if (index < size2 / 2) { 15737 node = this.getFirstChild(); 15738 i2 = 0; 15739 while (node !== null && i2 <= index) { 15740 if (i2 === index) { 15741 return node; 15742 } 15743 node = node.getNextSibling(); 15744 i2++; 15745 } 15746 return null; 15747 } 15748 node = this.getLastChild(); 15749 i2 = size2 - 1; 15750 while (node !== null && i2 >= index) { 15751 if (i2 === index) { 15752 return node; 15753 } 15754 node = node.getPreviousSibling(); 15755 i2--; 15756 } 15757 return null; 15758 } 15759 getTextContent() { 15760 let textContent = ""; 15761 const children = this.getChildren(); 15762 const childrenLength = children.length; 15763 for (let i2 = 0; i2 < childrenLength; i2++) { 15764 const child = children[i2]; 15765 textContent += child.getTextContent(); 15766 if ( 15767 // this is an inline $textContentRequiresDoubleLinebreakAtEnd(child) 15768 $isElementNode(child) && i2 !== childrenLength - 1 && !child.isInline() 15769 ) { 15770 textContent += DOUBLE_LINE_BREAK; 15771 } 15772 } 15773 return textContent; 15774 } 15775 getTextContentSize() { 15776 let textContentSize = 0; 15777 const children = this.getChildren(); 15778 const childrenLength = children.length; 15779 for (let i2 = 0; i2 < childrenLength; i2++) { 15780 const child = children[i2]; 15781 textContentSize += child.getTextContentSize(); 15782 if ( 15783 // This is an inline $textContentRequiresDoubleLinebreakAtEnd(child) 15784 $isElementNode(child) && i2 !== childrenLength - 1 && !child.isInline() 15785 ) { 15786 textContentSize += DOUBLE_LINE_BREAK.length; 15787 } 15788 } 15789 return textContentSize; 15790 } 15791 getDirection() { 15792 const self2 = this.getLatest(); 15793 return self2.__dir; 15794 } 15795 getTextFormat() { 15796 const self2 = this.getLatest(); 15797 return self2.__textFormat; 15798 } 15799 hasFormat(type) { 15800 if (type !== "") { 15801 const formatFlag = ELEMENT_TYPE_TO_FORMAT[type]; 15802 return (this.getFormat() & formatFlag) !== 0; 15803 } 15804 return false; 15805 } 15806 hasTextFormat(type) { 15807 const formatFlag = TEXT_TYPE_TO_FORMAT[type]; 15808 return (this.getTextFormat() & formatFlag) !== 0; 15809 } 15810 /** 15811 * Returns the format flags applied to the node as a 32-bit integer. 15812 * 15813 * @returns a number representing the TextFormatTypes applied to the node. 15814 */ 15815 getFormatFlags(type, alignWithFormat) { 15816 const self2 = this.getLatest(); 15817 const format = self2.__textFormat; 15818 return toggleTextFormatType(format, type, alignWithFormat); 15819 } 15820 getTextStyle() { 15821 const self2 = this.getLatest(); 15822 return self2.__textStyle; 15823 } 15824 // Mutators 15825 select(_anchorOffset, _focusOffset) { 15826 errorOnReadOnly(); 15827 const selection = $getSelection(); 15828 let anchorOffset = _anchorOffset; 15829 let focusOffset = _focusOffset; 15830 const childrenCount = this.getChildrenSize(); 15831 if (!this.canBeEmpty()) { 15832 if (_anchorOffset === 0 && _focusOffset === 0) { 15833 const firstChild = this.getFirstChild(); 15834 if ($isTextNode(firstChild) || $isElementNode(firstChild)) { 15835 return firstChild.select(0, 0); 15836 } 15837 } else if ((_anchorOffset === void 0 || _anchorOffset === childrenCount) && (_focusOffset === void 0 || _focusOffset === childrenCount)) { 15838 const lastChild = this.getLastChild(); 15839 if ($isTextNode(lastChild) || $isElementNode(lastChild)) { 15840 return lastChild.select(); 15841 } 15842 } 15843 } 15844 if (anchorOffset === void 0) { 15845 anchorOffset = childrenCount; 15846 } 15847 if (focusOffset === void 0) { 15848 focusOffset = childrenCount; 15849 } 15850 const key = this.__key; 15851 if (!$isRangeSelection(selection)) { 15852 return $internalMakeRangeSelection(key, anchorOffset, key, focusOffset, "element", "element"); 15853 } else { 15854 selection.anchor.set(key, anchorOffset, "element"); 15855 selection.focus.set(key, focusOffset, "element"); 15856 selection.dirty = true; 15857 } 15858 return selection; 15859 } 15860 selectStart() { 15861 const firstNode = this.getFirstDescendant(); 15862 return firstNode ? firstNode.selectStart() : this.select(); 15863 } 15864 selectEnd() { 15865 const lastNode = this.getLastDescendant(); 15866 return lastNode ? lastNode.selectEnd() : this.select(); 15867 } 15868 clear() { 15869 const writableSelf = this.getWritable(); 15870 const children = this.getChildren(); 15871 children.forEach((child) => child.remove()); 15872 return writableSelf; 15873 } 15874 append(...nodesToAppend) { 15875 return this.splice(this.getChildrenSize(), 0, nodesToAppend); 15876 } 15877 setDirection(direction) { 15878 const self2 = this.getWritable(); 15879 self2.__dir = direction; 15880 return self2; 15881 } 15882 setFormat(type) { 15883 const self2 = this.getWritable(); 15884 self2.__format = type !== "" ? ELEMENT_TYPE_TO_FORMAT[type] || 0 : 0; 15885 return this; 15886 } 15887 setStyle(style) { 15888 const self2 = this.getWritable(); 15889 self2.__style = style || ""; 15890 return this; 15891 } 15892 setTextFormat(type) { 15893 const self2 = this.getWritable(); 15894 self2.__textFormat = type; 15895 return self2; 15896 } 15897 setTextStyle(style) { 15898 const self2 = this.getWritable(); 15899 self2.__textStyle = style; 15900 return self2; 15901 } 15902 setIndent(indentLevel) { 15903 const self2 = this.getWritable(); 15904 self2.__indent = indentLevel; 15905 return this; 15906 } 15907 splice(start3, deleteCount, nodesToInsert) { 15908 if (!!$isEphemeral(this)) { 15909 formatDevErrorMessage(`ElementNode.splice: Ephemeral nodes can not mutate their children (key ${this.__key} type ${this.__type})`); 15910 } 15911 const oldSize = this.getChildrenSize(); 15912 const writableSelf = this.getWritable(); 15913 if (!(start3 + deleteCount <= oldSize)) { 15914 formatDevErrorMessage(`ElementNode.splice: start + deleteCount > oldSize (${String(start3)} + ${String(deleteCount)} > ${String(oldSize)})`); 15915 } 15916 const writableSelfKey = writableSelf.__key; 15917 const nodesToInsertKeys = []; 15918 const nodesToRemoveKeys = []; 15919 const nodeAfterRange = this.getChildAtIndex(start3 + deleteCount); 15920 let nodeBeforeRange = null; 15921 let newSize = oldSize - deleteCount + nodesToInsert.length; 15922 if (start3 !== 0) { 15923 if (start3 === oldSize) { 15924 nodeBeforeRange = this.getLastChild(); 15925 } else { 15926 const node = this.getChildAtIndex(start3); 15927 if (node !== null) { 15928 nodeBeforeRange = node.getPreviousSibling(); 15929 } 15930 } 15931 } 15932 if (deleteCount > 0) { 15933 let nodeToDelete = nodeBeforeRange === null ? this.getFirstChild() : nodeBeforeRange.getNextSibling(); 15934 for (let i2 = 0; i2 < deleteCount; i2++) { 15935 if (nodeToDelete === null) { 15936 { 15937 formatDevErrorMessage(`splice: sibling not found`); 15938 } 15939 } 15940 const nextSibling = nodeToDelete.getNextSibling(); 15941 const nodeKeyToDelete = nodeToDelete.__key; 15942 const writableNodeToDelete = nodeToDelete.getWritable(); 15943 removeFromParent(writableNodeToDelete); 15944 nodesToRemoveKeys.push(nodeKeyToDelete); 15945 nodeToDelete = nextSibling; 15946 } 15947 } 15948 let prevNode = nodeBeforeRange; 15949 for (const nodeToInsert of nodesToInsert) { 15950 if (prevNode !== null && nodeToInsert.is(prevNode)) { 15951 nodeBeforeRange = prevNode = prevNode.getPreviousSibling(); 15952 } 15953 const writableNodeToInsert = nodeToInsert.getWritable(); 15954 if (writableNodeToInsert.__parent === writableSelfKey) { 15955 newSize--; 15956 } 15957 removeFromParent(writableNodeToInsert); 15958 const nodeKeyToInsert = nodeToInsert.__key; 15959 if (prevNode === null) { 15960 writableSelf.__first = nodeKeyToInsert; 15961 writableNodeToInsert.__prev = null; 15962 } else { 15963 const writablePrevNode = prevNode.getWritable(); 15964 writablePrevNode.__next = nodeKeyToInsert; 15965 writableNodeToInsert.__prev = writablePrevNode.__key; 15966 } 15967 if (nodeToInsert.__key === writableSelfKey) { 15968 { 15969 formatDevErrorMessage(`append: attempting to append self`); 15970 } 15971 } 15972 writableNodeToInsert.__parent = writableSelfKey; 15973 nodesToInsertKeys.push(nodeKeyToInsert); 15974 prevNode = nodeToInsert; 15975 } 15976 if (start3 + deleteCount === oldSize) { 15977 if (prevNode !== null) { 15978 const writablePrevNode = prevNode.getWritable(); 15979 writablePrevNode.__next = null; 15980 writableSelf.__last = prevNode.__key; 15981 } 15982 } else if (nodeAfterRange !== null) { 15983 const writableNodeAfterRange = nodeAfterRange.getWritable(); 15984 if (prevNode !== null) { 15985 const writablePrevNode = prevNode.getWritable(); 15986 writableNodeAfterRange.__prev = prevNode.__key; 15987 writablePrevNode.__next = nodeAfterRange.__key; 15988 } else { 15989 writableNodeAfterRange.__prev = null; 15990 } 15991 } 15992 writableSelf.__size = newSize; 15993 if (nodesToRemoveKeys.length) { 15994 const selection = $getSelection(); 15995 if ($isRangeSelection(selection)) { 15996 const nodesToRemoveKeySet = new Set(nodesToRemoveKeys); 15997 const nodesToInsertKeySet = new Set(nodesToInsertKeys); 15998 const { 15999 anchor, 16000 focus 16001 } = selection; 16002 if (isPointRemoved(anchor, nodesToRemoveKeySet, nodesToInsertKeySet)) { 16003 moveSelectionPointToSibling(anchor, anchor.getNode(), this, nodeBeforeRange, nodeAfterRange); 16004 } 16005 if (isPointRemoved(focus, nodesToRemoveKeySet, nodesToInsertKeySet)) { 16006 moveSelectionPointToSibling(focus, focus.getNode(), this, nodeBeforeRange, nodeAfterRange); 16007 } 16008 if (newSize === 0 && !this.canBeEmpty() && !$isRootOrShadowRoot(this)) { 16009 this.remove(); 16010 } 16011 } 16012 } 16013 return writableSelf; 16014 } 16015 /** 16016 * @internal 16017 * 16018 * An experimental API that an ElementNode can override to control where its 16019 * children are inserted into the DOM, this is useful to add a wrapping node 16020 * or accessory nodes before or after the children. The root of the node returned 16021 * by createDOM must still be exactly one HTMLElement. 16022 */ 16023 getDOMSlot(element) { 16024 return new ElementDOMSlot(element); 16025 } 16026 exportDOM(editor) { 16027 const { 16028 element 16029 } = super.exportDOM(editor); 16030 if (isHTMLElement(element)) { 16031 const indent = this.getIndent(); 16032 if (indent > 0) { 16033 element.style.paddingInlineStart = `${indent * 40}px`; 16034 } 16035 const direction = this.getDirection(); 16036 if (direction) { 16037 element.dir = direction; 16038 } 16039 } 16040 return { 16041 element 16042 }; 16043 } 16044 // JSON serialization 16045 exportJSON() { 16046 const json = { 16047 children: [], 16048 direction: this.getDirection(), 16049 format: this.getFormatType(), 16050 indent: this.getIndent(), 16051 // As an exception here we invoke super at the end for historical reasons. 16052 // Namely, to preserve the order of the properties and not to break the tests 16053 // that use the serialized string representation. 16054 ...super.exportJSON() 16055 }; 16056 const textFormat = this.getTextFormat(); 16057 const textStyle = this.getTextStyle(); 16058 if ((textFormat !== 0 || textStyle !== "") && !$isRootOrShadowRoot(this) && !this.getChildren().some($isTextNode)) { 16059 if (textFormat !== 0) { 16060 json.textFormat = textFormat; 16061 } 16062 if (textStyle !== "") { 16063 json.textStyle = textStyle; 16064 } 16065 } 16066 return json; 16067 } 16068 updateFromJSON(serializedNode) { 16069 return super.updateFromJSON(serializedNode).setFormat(serializedNode.format).setIndent(serializedNode.indent).setDirection(serializedNode.direction).setTextFormat(serializedNode.textFormat || 0).setTextStyle(serializedNode.textStyle || ""); 16070 } 16071 // These are intended to be extends for specific element heuristics. 16072 insertNewAfter(selection, restoreSelection) { 16073 return null; 16074 } 16075 canIndent() { 16076 return true; 16077 } 16078 /* 16079 * This method controls the behavior of the node during backwards 16080 * deletion (i.e., backspace) when selection is at the beginning of 16081 * the node (offset 0). You may use this to have the node replace 16082 * itself, change its state, or do nothing. When you do make such 16083 * a change, you should return true. 16084 * 16085 * When true is returned, the collapse phase will stop. 16086 * When false is returned, and isInline() is true, and getPreviousSibling() is null, 16087 * then this function will be called on its parent. 16088 */ 16089 collapseAtStart(selection) { 16090 return false; 16091 } 16092 excludeFromCopy(destination) { 16093 return false; 16094 } 16095 /** @deprecated @internal */ 16096 canReplaceWith(replacement) { 16097 return true; 16098 } 16099 /** @deprecated @internal */ 16100 canInsertAfter(node) { 16101 return true; 16102 } 16103 canBeEmpty() { 16104 return true; 16105 } 16106 canInsertTextBefore() { 16107 return true; 16108 } 16109 canInsertTextAfter() { 16110 return true; 16111 } 16112 isInline() { 16113 return false; 16114 } 16115 // A shadow root is a Node that behaves like RootNode. The shadow root (and RootNode) mark the 16116 // end of the hierarchy, most implementations should treat it as there's nothing (upwards) 16117 // beyond this point. For example, node.getTopLevelElement(), when performed inside a TableCellNode 16118 // will return the immediate first child underneath TableCellNode instead of RootNode. 16119 isShadowRoot() { 16120 return false; 16121 } 16122 /** @deprecated @internal */ 16123 canMergeWith(node) { 16124 return false; 16125 } 16126 extractWithChild(child, selection, destination) { 16127 return false; 16128 } 16129 /** 16130 * Determines whether this node, when empty, can merge with a first block 16131 * of nodes being inserted. 16132 * 16133 * This method is specifically called in {@link RangeSelection.insertNodes} 16134 * to determine merging behavior during nodes insertion. 16135 * 16136 * @example 16137 * // In a ListItemNode or QuoteNode implementation: 16138 * canMergeWhenEmpty(): true { 16139 * return true; 16140 * } 16141 */ 16142 canMergeWhenEmpty() { 16143 return false; 16144 } 16145 /** @internal */ 16146 reconcileObservedMutation(dom, editor) { 16147 const slot = $getEditorDOMRenderConfig(editor).$getDOMSlot(this, dom, editor); 16148 let currentDOM = slot.getFirstChild(); 16149 for (let currentNode = this.getFirstChild(); currentNode; currentNode = currentNode.getNextSibling()) { 16150 const correctDOM = editor.getElementByKey(currentNode.getKey()); 16151 if (correctDOM === null) { 16152 continue; 16153 } 16154 if (currentDOM == null) { 16155 slot.insertChild(correctDOM); 16156 currentDOM = correctDOM; 16157 } else if (currentDOM !== correctDOM) { 16158 slot.replaceChild(correctDOM, currentDOM); 16159 } 16160 currentDOM = currentDOM.nextSibling; 16161 } 16162 } 16163 }; 16164 function $isElementNode(node) { 16165 return node instanceof ElementNode; 16166 } 16167 function isPointRemoved(point, nodesToRemoveKeySet, nodesToInsertKeySet) { 16168 let node = point.getNode(); 16169 while (node) { 16170 const nodeKey = node.__key; 16171 if (nodesToRemoveKeySet.has(nodeKey) && !nodesToInsertKeySet.has(nodeKey)) { 16172 return true; 16173 } 16174 node = node.getParent(); 16175 } 16176 return false; 16177 } 16178 var DecoratorNode = class extends LexicalNode { 16179 /** @internal */ 16180 /** 16181 * The returned value is added to the LexicalEditor._decorators 16182 */ 16183 decorate(editor, config) { 16184 return null; 16185 } 16186 isIsolated() { 16187 return false; 16188 } 16189 isInline() { 16190 return true; 16191 } 16192 isKeyboardSelectable() { 16193 return true; 16194 } 16195 }; 16196 function $isDecoratorNode(node) { 16197 return node instanceof DecoratorNode; 16198 } 16199 var RootNode = class _RootNode extends ElementNode { 16200 /** @internal */ 16201 __cachedText; 16202 static getType() { 16203 return "root"; 16204 } 16205 static clone() { 16206 return new _RootNode(); 16207 } 16208 constructor() { 16209 super("root"); 16210 this.__cachedText = null; 16211 } 16212 getTopLevelElementOrThrow() { 16213 { 16214 formatDevErrorMessage(`getTopLevelElementOrThrow: root nodes are not top level elements`); 16215 } 16216 } 16217 getTextContent() { 16218 const cachedText = this.__cachedText; 16219 if (isCurrentlyReadOnlyMode() || getActiveEditor()._dirtyType === NO_DIRTY_NODES) { 16220 if (cachedText !== null) { 16221 return cachedText; 16222 } 16223 } 16224 return super.getTextContent(); 16225 } 16226 remove() { 16227 { 16228 formatDevErrorMessage(`remove: cannot be called on root nodes`); 16229 } 16230 } 16231 replace(node) { 16232 { 16233 formatDevErrorMessage(`replace: cannot be called on root nodes`); 16234 } 16235 } 16236 insertBefore(nodeToInsert) { 16237 { 16238 formatDevErrorMessage(`insertBefore: cannot be called on root nodes`); 16239 } 16240 } 16241 insertAfter(nodeToInsert) { 16242 { 16243 formatDevErrorMessage(`insertAfter: cannot be called on root nodes`); 16244 } 16245 } 16246 // View 16247 updateDOM(prevNode, dom) { 16248 return false; 16249 } 16250 // Mutate 16251 splice(start3, deleteCount, nodesToInsert) { 16252 for (const node of nodesToInsert) { 16253 if (!($isElementNode(node) || $isDecoratorNode(node))) { 16254 formatDevErrorMessage(`rootNode.splice: Only element or decorator nodes can be inserted to the root node`); 16255 } 16256 } 16257 return super.splice(start3, deleteCount, nodesToInsert); 16258 } 16259 static importJSON(serializedNode) { 16260 return $getRoot().updateFromJSON(serializedNode); 16261 } 16262 collapseAtStart() { 16263 return true; 16264 } 16265 }; 16266 function $createRootNode() { 16267 return new RootNode(); 16268 } 16269 function $isRootNode(node) { 16270 return node instanceof RootNode; 16271 } 16272 function editorStateHasDirtySelection(editorState, editor) { 16273 const currentSelection = editor.getEditorState()._selection; 16274 const pendingSelection = editorState._selection; 16275 if (pendingSelection !== null) { 16276 if (pendingSelection.dirty || !pendingSelection.is(currentSelection)) { 16277 return true; 16278 } 16279 } else if (currentSelection !== null) { 16280 return true; 16281 } 16282 return false; 16283 } 16284 function cloneEditorState(current) { 16285 return new EditorState(new Map(current._nodeMap)); 16286 } 16287 function createEmptyEditorState() { 16288 return new EditorState(/* @__PURE__ */ new Map([["root", $createRootNode()]])); 16289 } 16290 function exportNodeToJSON(node) { 16291 const serializedNode = node.exportJSON(); 16292 const nodeClass = node.constructor; 16293 if (serializedNode.type !== nodeClass.getType()) { 16294 { 16295 formatDevErrorMessage(`LexicalNode: Node ${nodeClass.name} does not match the serialized type. Check if .exportJSON() is implemented and it is returning the correct type.`); 16296 } 16297 } 16298 if ($isElementNode(node)) { 16299 const serializedChildren = serializedNode.children; 16300 if (!Array.isArray(serializedChildren)) { 16301 { 16302 formatDevErrorMessage(`LexicalNode: Node ${nodeClass.name} is an element but .exportJSON() does not have a children array.`); 16303 } 16304 } 16305 const children = node.getChildren(); 16306 for (let i2 = 0; i2 < children.length; i2++) { 16307 const child = children[i2]; 16308 const serializedChildNode = exportNodeToJSON(child); 16309 serializedChildren.push(serializedChildNode); 16310 } 16311 } 16312 return serializedNode; 16313 } 16314 function $isEditorState(x3) { 16315 return x3 instanceof EditorState; 16316 } 16317 var EditorState = class _EditorState { 16318 _nodeMap; 16319 _selection; 16320 _flushSync; 16321 _readOnly; 16322 constructor(nodeMap, selection) { 16323 this._nodeMap = nodeMap; 16324 this._selection = selection || null; 16325 this._flushSync = false; 16326 this._readOnly = false; 16327 } 16328 isEmpty() { 16329 return this._nodeMap.size === 1 && this._selection === null; 16330 } 16331 read(callbackFn, options) { 16332 return readEditorState(options && options.editor || null, this, callbackFn); 16333 } 16334 clone(selection) { 16335 const editorState = new _EditorState(this._nodeMap, selection === void 0 ? this._selection : selection); 16336 editorState._readOnly = true; 16337 return editorState; 16338 } 16339 toJSON() { 16340 return readEditorState(null, this, () => ({ 16341 root: exportNodeToJSON($getRoot()) 16342 })); 16343 } 16344 }; 16345 var ArtificialNode__DO_NOT_USE = class extends ElementNode { 16346 static getType() { 16347 return "artificial"; 16348 } 16349 createDOM(config) { 16350 const dom = document.createElement("div"); 16351 return dom; 16352 } 16353 }; 16354 var ParagraphNode = class _ParagraphNode extends ElementNode { 16355 /** @internal */ 16356 static getType() { 16357 return "paragraph"; 16358 } 16359 static clone(node) { 16360 return new _ParagraphNode(node.__key); 16361 } 16362 // View 16363 createDOM(config) { 16364 const dom = document.createElement("p"); 16365 const classNames = getCachedClassNameArray(config.theme, "paragraph"); 16366 if (classNames !== void 0) { 16367 const domClassList = dom.classList; 16368 domClassList.add(...classNames); 16369 } 16370 return dom; 16371 } 16372 updateDOM(prevNode, dom, config) { 16373 return false; 16374 } 16375 static importDOM() { 16376 return { 16377 p: (node) => ({ 16378 conversion: $convertParagraphElement, 16379 priority: 0 16380 }) 16381 }; 16382 } 16383 exportDOM(editor) { 16384 const { 16385 element 16386 } = super.exportDOM(editor); 16387 if (isHTMLElement(element)) { 16388 if (this.isEmpty()) { 16389 element.append(document.createElement("br")); 16390 } 16391 const formatType = this.getFormatType(); 16392 if (formatType) { 16393 element.style.textAlign = formatType; 16394 } 16395 } 16396 return { 16397 element 16398 }; 16399 } 16400 static importJSON(serializedNode) { 16401 return $createParagraphNode().updateFromJSON(serializedNode); 16402 } 16403 exportJSON() { 16404 const json = super.exportJSON(); 16405 if (json.textFormat === void 0 || json.textStyle === void 0) { 16406 const firstTextNode = this.getChildren().find($isTextNode); 16407 if (firstTextNode) { 16408 json.textFormat = firstTextNode.getFormat(); 16409 json.textStyle = firstTextNode.getStyle(); 16410 } else { 16411 json.textFormat = this.getTextFormat(); 16412 json.textStyle = this.getTextStyle(); 16413 } 16414 } 16415 return json; 16416 } 16417 // Mutation 16418 insertNewAfter(rangeSelection, restoreSelection) { 16419 const newElement = $createParagraphNode(); 16420 newElement.setTextFormat(rangeSelection.format); 16421 newElement.setTextStyle(rangeSelection.style); 16422 const direction = this.getDirection(); 16423 newElement.setDirection(direction); 16424 newElement.setFormat(this.getFormatType()); 16425 newElement.setStyle(this.getStyle()); 16426 this.insertAfter(newElement, restoreSelection); 16427 return newElement; 16428 } 16429 collapseAtStart() { 16430 const children = this.getChildren(); 16431 if (children.length === 0 || $isTextNode(children[0]) && children[0].getTextContent().trim() === "") { 16432 const nextSibling = this.getNextSibling(); 16433 if (nextSibling !== null) { 16434 this.selectNext(); 16435 this.remove(); 16436 return true; 16437 } 16438 const prevSibling = this.getPreviousSibling(); 16439 if (prevSibling !== null) { 16440 this.selectPrevious(); 16441 this.remove(); 16442 return true; 16443 } 16444 } 16445 return false; 16446 } 16447 }; 16448 function $convertParagraphElement(element) { 16449 const node = $createParagraphNode(); 16450 if (element.style) { 16451 node.setFormat(element.style.textAlign); 16452 setNodeIndentFromDOM(element, node); 16453 } 16454 if (node.getFormatType() === "") { 16455 const align = element.getAttribute("align"); 16456 if (align) { 16457 if (align && align in ELEMENT_TYPE_TO_FORMAT) { 16458 node.setFormat(align); 16459 } 16460 } 16461 } 16462 return { 16463 node 16464 }; 16465 } 16466 function $createParagraphNode() { 16467 return $applyNodeReplacement(new ParagraphNode()); 16468 } 16469 function $isParagraphNode(node) { 16470 return node instanceof ParagraphNode; 16471 } 16472 var DEFAULT_SKIP_INITIALIZATION = false; 16473 var COMMAND_PRIORITY_EDITOR = 0; 16474 var COMMAND_PRIORITY_LOW = 1; 16475 var COMMAND_PRIORITY_NORMAL = 2; 16476 var COMMAND_PRIORITY_HIGH = 3; 16477 var COMMAND_PRIORITY_CRITICAL = 4; 16478 var COMMAND_PRIORITY_BEFORE_EDITOR = -8; 16479 var COMMAND_PRIORITY_BEFORE_LOW = -7; 16480 var COMMAND_PRIORITY_BEFORE_NORMAL = -6; 16481 var COMMAND_PRIORITY_BEFORE_HIGH = -5; 16482 var COMMAND_PRIORITY_BEFORE_CRITICAL = -4; 16483 function normalizePriority(priority) { 16484 return priority & 7; 16485 } 16486 function resetEditor(editor, prevRootElement, nextRootElement, pendingEditorState) { 16487 const keyNodeMap = editor._keyToDOMMap; 16488 keyNodeMap.clear(); 16489 editor._editorState = createEmptyEditorState(); 16490 editor._pendingEditorState = pendingEditorState; 16491 editor._compositionKey = null; 16492 editor._dirtyType = NO_DIRTY_NODES; 16493 editor._cloneNotNeeded.clear(); 16494 editor._dirtyLeaves = /* @__PURE__ */ new Set(); 16495 editor._dirtyElements.clear(); 16496 editor._normalizedNodes = /* @__PURE__ */ new Set(); 16497 editor._updateTags = /* @__PURE__ */ new Set(); 16498 editor._updates = []; 16499 editor._blockCursorElement = null; 16500 const observer = editor._observer; 16501 if (observer !== null) { 16502 observer.disconnect(); 16503 editor._observer = null; 16504 } 16505 if (prevRootElement !== null) { 16506 prevRootElement.textContent = ""; 16507 } 16508 if (nextRootElement !== null) { 16509 nextRootElement.textContent = ""; 16510 keyNodeMap.set("root", nextRootElement); 16511 } 16512 } 16513 function initializeConversionCache(nodes, additionalConversions) { 16514 const conversionCache = /* @__PURE__ */ new Map(); 16515 const handledConversions = /* @__PURE__ */ new Set(); 16516 const addConversionsToCache = (map) => { 16517 Object.keys(map).forEach((key) => { 16518 let currentCache = conversionCache.get(key); 16519 if (currentCache === void 0) { 16520 currentCache = []; 16521 conversionCache.set(key, currentCache); 16522 } 16523 currentCache.push(map[key]); 16524 }); 16525 }; 16526 nodes.forEach((node) => { 16527 const importDOM = node.klass.importDOM; 16528 if (importDOM == null || handledConversions.has(importDOM)) { 16529 return; 16530 } 16531 handledConversions.add(importDOM); 16532 const map = importDOM.call(node.klass); 16533 if (map !== null) { 16534 addConversionsToCache(map); 16535 } 16536 }); 16537 if (additionalConversions) { 16538 addConversionsToCache(additionalConversions); 16539 } 16540 return conversionCache; 16541 } 16542 function getTransformSetFromKlass(klass) { 16543 const transforms = /* @__PURE__ */ new Set(); 16544 const staticTransforms = /* @__PURE__ */ new Set(); 16545 let currentKlass = klass; 16546 while (currentKlass) { 16547 const { 16548 ownNodeConfig 16549 } = getStaticNodeConfig(currentKlass); 16550 const staticTransform = currentKlass.transform; 16551 if (!staticTransforms.has(staticTransform)) { 16552 staticTransforms.add(staticTransform); 16553 const transform = currentKlass.transform(); 16554 if (transform) { 16555 transforms.add(transform); 16556 } 16557 } 16558 if (ownNodeConfig) { 16559 const $transform = ownNodeConfig.$transform; 16560 if ($transform) { 16561 transforms.add($transform); 16562 } 16563 currentKlass = ownNodeConfig.extends; 16564 } else { 16565 const parent = Object.getPrototypeOf(currentKlass); 16566 currentKlass = parent.prototype instanceof LexicalNode && parent !== LexicalNode ? parent : void 0; 16567 } 16568 } 16569 return transforms; 16570 } 16571 var DEFAULT_EDITOR_DOM_CONFIG = { 16572 $createDOM: (node, editor) => node.createDOM(editor._config, editor), 16573 $decorateDOM: (_node, _prevNode, _dom, _editor) => { 16574 }, 16575 $exportDOM: (node, editor) => { 16576 const registeredNode = getRegisteredNode(editor, node.getType()); 16577 return registeredNode && registeredNode.exportDOM !== void 0 ? registeredNode.exportDOM(editor, node) : node.exportDOM(editor); 16578 }, 16579 $extractWithChild: (node, childNode, selection, destination, _editor) => $isElementNode(node) && node.extractWithChild(childNode, selection, destination), 16580 $getDOMSlot: (node, dom, _editor) => { 16581 if (!$isElementNode(node)) { 16582 formatDevErrorMessage(`$getDOMSlot called on a non-ElementNode (key ${node.getKey()} type ${node.getType()})`); 16583 } 16584 return node.getDOMSlot(dom); 16585 }, 16586 $shouldExclude: (node, _selection, _editor) => $isElementNode(node) && node.excludeFromCopy("html"), 16587 $shouldInclude: (node, selection, _editor) => selection ? node.isSelected(selection) : true, 16588 $updateDOM: (nextNode, prevNode, dom, editor) => nextNode.updateDOM(prevNode, dom, editor._config) 16589 }; 16590 function createEditor(editorConfig) { 16591 const config = editorConfig || {}; 16592 const activeEditor2 = internalGetActiveEditor(); 16593 const theme2 = config.theme || {}; 16594 const parentEditor = editorConfig === void 0 ? activeEditor2 : config.parentEditor || null; 16595 const disableEvents = config.disableEvents || false; 16596 const editorState = createEmptyEditorState(); 16597 const namespace = config.namespace || (parentEditor !== null ? parentEditor._config.namespace : createUID()); 16598 const initialEditorState = config.editorState; 16599 const nodes = [RootNode, TextNode, LineBreakNode, TabNode, ParagraphNode, ArtificialNode__DO_NOT_USE, ...config.nodes || []]; 16600 const { 16601 onError, 16602 html: html2 16603 } = config; 16604 const isEditable = config.editable !== void 0 ? config.editable : true; 16605 let registeredNodes; 16606 if (editorConfig === void 0 && activeEditor2 !== null) { 16607 registeredNodes = activeEditor2._nodes; 16608 } else { 16609 registeredNodes = /* @__PURE__ */ new Map(); 16610 for (let i2 = 0; i2 < nodes.length; i2++) { 16611 let klass = nodes[i2]; 16612 let replace = null; 16613 let replaceWithKlass = null; 16614 if (typeof klass !== "function") { 16615 const options = klass; 16616 klass = options.replace; 16617 replace = options.with; 16618 replaceWithKlass = options.withKlass || null; 16619 } 16620 void getStaticNodeConfig(klass); 16621 { 16622 const name = klass.name; 16623 const nodeType = hasOwnStaticMethod(klass, "getType") && klass.getType(); 16624 if (replaceWithKlass) { 16625 if (!(replaceWithKlass.prototype instanceof klass)) { 16626 formatDevErrorMessage(`${replaceWithKlass.name} doesn't extend the ${name}`); 16627 } 16628 } else if (replace) { 16629 console.warn(`Override for ${name} specifies 'replace' without 'withKlass'. 'withKlass' will be required in a future version.`); 16630 } 16631 if (name !== "RootNode" && nodeType !== "root" && nodeType !== "artificial" && // This is mostly for the unit test suite which 16632 // uses LexicalNode in an otherwise incorrect way 16633 // by mocking its static getType 16634 klass !== LexicalNode) { 16635 ["getType", "clone"].forEach((method) => { 16636 if (!hasOwnStaticMethod(klass, method)) { 16637 console.warn(`${name} must implement static "${method}" method`); 16638 } 16639 }); 16640 if (!hasOwnStaticMethod(klass, "importDOM") && hasOwnExportDOM(klass)) { 16641 console.warn(`${name} should implement "importDOM" if using a custom "exportDOM" method to ensure HTML serialization (important for copy & paste) works as expected`); 16642 } 16643 if (!hasOwnStaticMethod(klass, "importJSON")) { 16644 console.warn(`${name} should implement "importJSON" method to ensure JSON and default HTML serialization works as expected`); 16645 } 16646 } 16647 } 16648 const type = klass.getType(); 16649 const transforms = getTransformSetFromKlass(klass); 16650 registeredNodes.set(type, { 16651 exportDOM: html2 && html2.export ? html2.export.get(klass) : void 0, 16652 klass, 16653 replace, 16654 replaceWithKlass, 16655 sharedNodeState: createSharedNodeState(nodes[i2]), 16656 transforms 16657 }); 16658 } 16659 } 16660 const editor = new LexicalEditor(editorState, parentEditor, registeredNodes, { 16661 disableEvents, 16662 dom: { 16663 ...DEFAULT_EDITOR_DOM_CONFIG, 16664 ...editorConfig && editorConfig.dom 16665 }, 16666 namespace, 16667 theme: theme2 16668 }, onError ? onError : console.error, initializeConversionCache(registeredNodes, html2 ? html2.import : void 0), isEditable, editorConfig); 16669 if (initialEditorState !== void 0) { 16670 editor._pendingEditorState = initialEditorState; 16671 editor._dirtyType = FULL_RECONCILE; 16672 } 16673 registerDefaultCommandHandlers(editor); 16674 return editor; 16675 } 16676 function triggerListener(listenerMap, listener, args) { 16677 const unregister = listenerMap.get(listener); 16678 if (unregister) { 16679 unregister(); 16680 } 16681 listenerMap.set(listener, listener(...args) || void 0); 16682 } 16683 function unregisterListener(listenerMap, listener) { 16684 const unregister = listenerMap.get(listener); 16685 listenerMap.delete(listener); 16686 if (unregister) { 16687 unregister(); 16688 } 16689 } 16690 function registerListener(listenerMap, listener, unregister) { 16691 listenerMap.set(listener, unregister); 16692 return unregisterListener.bind(null, listenerMap, listener); 16693 } 16694 var LexicalEditor = class { 16695 /** @internal */ 16696 /** The version with build identifiers for this editor (since 0.17.1) */ 16697 static version; 16698 /** @internal */ 16699 _headless; 16700 /** @internal */ 16701 _parentEditor; 16702 /** @internal */ 16703 _rootElement; 16704 /** @internal */ 16705 _editorState; 16706 /** @internal */ 16707 _pendingEditorState; 16708 /** @internal */ 16709 _compositionKey; 16710 /** @internal */ 16711 _deferred; 16712 /** @internal */ 16713 _keyToDOMMap; 16714 /** @internal */ 16715 _updates; 16716 /** @internal */ 16717 _updating; 16718 /** @internal */ 16719 _listeners; 16720 /** @internal */ 16721 _commands; 16722 /** @internal */ 16723 _nodes; 16724 /** @internal */ 16725 _decorators; 16726 /** @internal */ 16727 _pendingDecorators; 16728 /** @internal */ 16729 _config; 16730 /** @internal */ 16731 _dirtyType; 16732 /** @internal */ 16733 _cloneNotNeeded; 16734 /** @internal */ 16735 _dirtyLeaves; 16736 /** @internal */ 16737 _dirtyElements; 16738 /** @internal */ 16739 _normalizedNodes; 16740 /** @internal */ 16741 _updateTags; 16742 /** @internal */ 16743 _observer; 16744 /** @internal */ 16745 _key; 16746 /** @internal */ 16747 _onError; 16748 /** @internal */ 16749 _htmlConversions; 16750 /** @internal */ 16751 _window; 16752 /** @internal */ 16753 _editable; 16754 /** @internal */ 16755 _blockCursorElement; 16756 /** @internal */ 16757 _createEditorArgs; 16758 /** @internal */ 16759 constructor(editorState, parentEditor, nodes, config, onError, htmlConversions, editable, createEditorArgs) { 16760 this._createEditorArgs = createEditorArgs; 16761 this._parentEditor = parentEditor; 16762 this._rootElement = null; 16763 this._editorState = editorState; 16764 this._pendingEditorState = null; 16765 this._compositionKey = null; 16766 this._deferred = []; 16767 this._keyToDOMMap = /* @__PURE__ */ new Map(); 16768 this._updates = []; 16769 this._updating = false; 16770 this._listeners = { 16771 decorator: /* @__PURE__ */ new Map(), 16772 editable: /* @__PURE__ */ new Map(), 16773 mutation: /* @__PURE__ */ new Map(), 16774 root: /* @__PURE__ */ new Map(), 16775 textcontent: /* @__PURE__ */ new Map(), 16776 update: /* @__PURE__ */ new Map() 16777 }; 16778 this._commands = /* @__PURE__ */ new Map(); 16779 this._config = config; 16780 this._nodes = nodes; 16781 this._decorators = {}; 16782 this._pendingDecorators = null; 16783 this._dirtyType = NO_DIRTY_NODES; 16784 this._cloneNotNeeded = /* @__PURE__ */ new Set(); 16785 this._dirtyLeaves = /* @__PURE__ */ new Set(); 16786 this._dirtyElements = /* @__PURE__ */ new Map(); 16787 this._normalizedNodes = /* @__PURE__ */ new Set(); 16788 this._updateTags = /* @__PURE__ */ new Set(); 16789 this._observer = null; 16790 this._key = createUID(); 16791 this._onError = onError; 16792 this._htmlConversions = htmlConversions; 16793 this._editable = editable; 16794 this._headless = parentEditor !== null && parentEditor._headless; 16795 this._window = null; 16796 this._blockCursorElement = null; 16797 } 16798 /** 16799 * 16800 * @returns true if the editor is currently in "composition" mode due to receiving input 16801 * through an IME, or 3P extension, for example. Returns false otherwise. 16802 */ 16803 isComposing() { 16804 return this._compositionKey != null; 16805 } 16806 /** 16807 * Registers a listener for Editor update event. Will trigger the provided callback 16808 * each time the editor goes through an update (via {@link LexicalEditor.update}) until the 16809 * teardown function is called. 16810 * 16811 * @returns a teardown function that can be used to cleanup the listener. 16812 */ 16813 registerUpdateListener(listener) { 16814 return registerListener(this._listeners.update, listener); 16815 } 16816 /** 16817 * Registers a listener for for when the editor changes between editable and non-editable states. 16818 * Will trigger the provided callback each time the editor transitions between these states until the 16819 * teardown function is called. 16820 * 16821 * If the listener returns a function, that function will be called before the next transition or 16822 * teardown. 16823 * 16824 * @returns a teardown function that can be used to cleanup the listener. 16825 */ 16826 registerEditableListener(listener) { 16827 return registerListener(this._listeners.editable, listener); 16828 } 16829 /** 16830 * Registers a listener for when the editor's decorator object changes. The decorator object contains 16831 * all DecoratorNode keys -> their decorated value. This is primarily used with external UI frameworks. 16832 * 16833 * Will trigger the provided callback each time the editor transitions between these states until the 16834 * teardown function is called. 16835 * 16836 * @returns a teardown function that can be used to cleanup the listener. 16837 */ 16838 registerDecoratorListener(listener) { 16839 return registerListener(this._listeners.decorator, listener); 16840 } 16841 /** 16842 * Registers a listener for when Lexical commits an update to the DOM and the text content of 16843 * the editor changes from the previous state of the editor. If the text content is the 16844 * same between updates, no notifications to the listeners will happen. 16845 * 16846 * Will trigger the provided callback each time the editor transitions between these states until the 16847 * teardown function is called. 16848 * 16849 * @returns a teardown function that can be used to cleanup the listener. 16850 */ 16851 registerTextContentListener(listener) { 16852 return registerListener(this._listeners.textcontent, listener); 16853 } 16854 /** 16855 * Registers a listener for when the editor's root DOM element (the content editable 16856 * Lexical attaches to) changes. This is primarily used to attach event listeners to the root 16857 * element. The root listener function is executed directly upon registration and then on 16858 * any subsequent update. 16859 * 16860 * Will trigger the provided callback each time the editor transitions between these states until the 16861 * teardown function is called. 16862 * 16863 * If the listener returns a function, that function will be called before the next transition or 16864 * teardown. 16865 * 16866 * @returns a teardown function that can be used to cleanup the listener. 16867 */ 16868 registerRootListener(listener) { 16869 const listenerMap = this._listeners.root; 16870 return mergeRegister(registerListener(listenerMap, listener, listener(this._rootElement, null) || void 0), () => triggerListener(listenerMap, listener, [null, this._rootElement])); 16871 } 16872 /** 16873 * Registers a listener that will trigger anytime the provided command 16874 * is dispatched with {@link LexicalEditor.dispatch}, subject to priority. 16875 * Listeners that run at a higher priority can "intercept" commands and 16876 * prevent them from propagating to other handlers by returning true. 16877 * 16878 * Listeners are always invoked in an {@link LexicalEditor.update} and can 16879 * call dollar functions. 16880 * 16881 * Listeners registered at the same priority level will run 16882 * deterministically in the order of registration. 16883 * 16884 * @param command - the command that will trigger the callback. 16885 * @param listener - the function that will execute when the command is dispatched. 16886 * @param priority - the relative priority of the listener. 0 | 1 | 2 | 3 | 4 16887 * (or {@link COMMAND_PRIORITY_EDITOR} | 16888 * {@link COMMAND_PRIORITY_LOW} | 16889 * {@link COMMAND_PRIORITY_NORMAL} | 16890 * {@link COMMAND_PRIORITY_HIGH} | 16891 * {@link COMMAND_PRIORITY_CRITICAL}) 16892 * @returns a teardown function that can be used to cleanup the listener. 16893 */ 16894 registerCommand(command, listener, priority) { 16895 if (priority === void 0) { 16896 { 16897 formatDevErrorMessage(`Listener for type "command" requires a "priority".`); 16898 } 16899 } 16900 const commandsMap = this._commands; 16901 if (!commandsMap.has(command)) { 16902 commandsMap.set(command, [new DequeSet(), new DequeSet(), new DequeSet(), new DequeSet(), new DequeSet()]); 16903 } 16904 const listenersInPriorityOrder = commandsMap.get(command); 16905 if (listenersInPriorityOrder === void 0) { 16906 { 16907 formatDevErrorMessage(`registerCommand: Command ${String(command)} not found in command map`); 16908 } 16909 } 16910 const normalizedPriority = normalizePriority(priority); 16911 const listeners = listenersInPriorityOrder[normalizedPriority]; 16912 if (normalizedPriority !== priority) { 16913 listeners.addFront(listener); 16914 } else { 16915 listeners.addBack(listener); 16916 } 16917 return () => { 16918 listeners.delete(listener); 16919 if (listenersInPriorityOrder.every((listenersSet) => listenersSet.size === 0)) { 16920 commandsMap.delete(command); 16921 } 16922 }; 16923 } 16924 /** 16925 * Registers a listener that will run when a Lexical node of the provided class is 16926 * mutated. The listener will receive a list of nodes along with the type of mutation 16927 * that was performed on each: created, destroyed, or updated. 16928 * 16929 * One common use case for this is to attach DOM event listeners to the underlying DOM nodes as Lexical nodes are created. 16930 * {@link LexicalEditor.getElementByKey} can be used for this. 16931 * 16932 * If any existing nodes are in the DOM, and skipInitialization is not true, the listener 16933 * will be called immediately with an updateTag of 'registerMutationListener' where all 16934 * nodes have the 'created' NodeMutation. This can be controlled with the skipInitialization option 16935 * (whose default was previously true for backwards compatibility with <=0.16.1 but has been changed to false as of 0.21.0). 16936 * 16937 * @param klass - The class of the node that you want to listen to mutations on. 16938 * @param listener - The logic you want to run when the node is mutated. 16939 * @param options - see {@link MutationListenerOptions} 16940 * @returns a teardown function that can be used to cleanup the listener. 16941 */ 16942 registerMutationListener(klass, listener, options) { 16943 const klassToMutate = this.resolveRegisteredNodeAfterReplacements(this.getRegisteredNode(klass)).klass; 16944 const mutations = this._listeners.mutation; 16945 let klassSet = mutations.get(listener); 16946 if (klassSet === void 0) { 16947 klassSet = /* @__PURE__ */ new Set(); 16948 mutations.set(listener, klassSet); 16949 } 16950 klassSet.add(klassToMutate); 16951 const skipInitialization = options && options.skipInitialization; 16952 if (!(skipInitialization === void 0 ? DEFAULT_SKIP_INITIALIZATION : skipInitialization)) { 16953 this.initializeMutationListener(listener, klassToMutate); 16954 } 16955 return () => { 16956 klassSet.delete(klassToMutate); 16957 if (klassSet.size === 0) { 16958 mutations.delete(listener); 16959 } 16960 }; 16961 } 16962 /** @internal */ 16963 getRegisteredNode(klass) { 16964 const registeredNode = this._nodes.get(klass.getType()); 16965 if (registeredNode === void 0) { 16966 { 16967 formatDevErrorMessage(`Node ${klass.name} has not been registered. Ensure node has been passed to createEditor.`); 16968 } 16969 } 16970 return registeredNode; 16971 } 16972 /** @internal */ 16973 resolveRegisteredNodeAfterReplacements(registeredNode) { 16974 while (registeredNode.replaceWithKlass) { 16975 registeredNode = this.getRegisteredNode(registeredNode.replaceWithKlass); 16976 } 16977 return registeredNode; 16978 } 16979 /** @internal */ 16980 initializeMutationListener(listener, klass) { 16981 const prevEditorState = this._editorState; 16982 const nodeMap = getCachedTypeToNodeMap(prevEditorState).get(klass.getType()); 16983 if (!nodeMap) { 16984 return; 16985 } 16986 const nodeMutationMap = /* @__PURE__ */ new Map(); 16987 for (const k2 of nodeMap.keys()) { 16988 nodeMutationMap.set(k2, "created"); 16989 } 16990 if (nodeMutationMap.size > 0) { 16991 listener(nodeMutationMap, { 16992 dirtyLeaves: /* @__PURE__ */ new Set(), 16993 prevEditorState, 16994 updateTags: /* @__PURE__ */ new Set(["registerMutationListener"]) 16995 }); 16996 } 16997 } 16998 /** @internal */ 16999 registerNodeTransformToKlass(klass, listener) { 17000 const registeredNode = this.getRegisteredNode(klass); 17001 registeredNode.transforms.add(listener); 17002 return registeredNode; 17003 } 17004 /** 17005 * Registers a listener that will run when a Lexical node of the provided class is 17006 * marked dirty during an update. The listener will continue to run as long as the node 17007 * is marked dirty. There are no guarantees around the order of transform execution! 17008 * 17009 * Watch out for infinite loops. See [Node Transforms](https://lexical.dev/docs/concepts/transforms) 17010 * @param klass - The class of the node that you want to run transforms on. 17011 * @param listener - The logic you want to run when the node is updated. 17012 * @returns a teardown function that can be used to cleanup the listener. 17013 */ 17014 registerNodeTransform(klass, listener) { 17015 const registeredNode = this.registerNodeTransformToKlass(klass, listener); 17016 const registeredNodes = [registeredNode]; 17017 const replaceWithKlass = registeredNode.replaceWithKlass; 17018 if (replaceWithKlass != null) { 17019 const registeredReplaceWithNode = this.registerNodeTransformToKlass(replaceWithKlass, listener); 17020 registeredNodes.push(registeredReplaceWithNode); 17021 } 17022 markNodesWithTypesAsDirty(this, registeredNodes.map((node) => node.klass.getType())); 17023 return () => { 17024 registeredNodes.forEach((node) => node.transforms.delete(listener)); 17025 }; 17026 } 17027 /** 17028 * Used to assert that a certain node is registered, usually by plugins to ensure nodes that they 17029 * depend on have been registered. 17030 * @returns True if the editor has registered the provided node type, false otherwise. 17031 */ 17032 hasNode(node) { 17033 return this._nodes.has(node.getType()); 17034 } 17035 /** 17036 * Used to assert that certain nodes are registered, usually by plugins to ensure nodes that they 17037 * depend on have been registered. 17038 * @returns True if the editor has registered all of the provided node types, false otherwise. 17039 */ 17040 hasNodes(nodes) { 17041 return nodes.every(this.hasNode.bind(this)); 17042 } 17043 /** 17044 * Dispatches a command of the specified type with the specified payload. 17045 * This triggers all command listeners (set by {@link LexicalEditor.registerCommand}) 17046 * for this type, passing them the provided payload. The command listeners 17047 * will be triggered in an implicit {@link LexicalEditor.update}, unless 17048 * this was invoked from inside an update in which case that update context 17049 * will be re-used (as if this was a dollar function itself). 17050 * @param type - the type of command listeners to trigger. 17051 * @param payload - the data to pass as an argument to the command listeners. 17052 */ 17053 dispatchCommand(type, payload) { 17054 return dispatchCommand(this, type, payload); 17055 } 17056 /** 17057 * Gets a map of all decorators in the editor. 17058 * @returns A mapping of call decorator keys to their decorated content 17059 */ 17060 getDecorators() { 17061 return this._decorators; 17062 } 17063 /** 17064 * 17065 * @returns the current root element of the editor. If you want to register 17066 * an event listener, do it via {@link LexicalEditor.registerRootListener}, since 17067 * this reference may not be stable. 17068 */ 17069 getRootElement() { 17070 return this._rootElement; 17071 } 17072 /** 17073 * Gets the key of the editor 17074 * @returns The editor key 17075 */ 17076 getKey() { 17077 return this._key; 17078 } 17079 /** 17080 * Imperatively set the root contenteditable element that Lexical listens 17081 * for events on. 17082 */ 17083 setRootElement(nextRootElement) { 17084 const prevRootElement = this._rootElement; 17085 if (nextRootElement !== prevRootElement) { 17086 const classNames = getCachedClassNameArray(this._config.theme, "root"); 17087 const pendingEditorState = this._pendingEditorState || this._editorState; 17088 this._rootElement = nextRootElement; 17089 resetEditor(this, prevRootElement, nextRootElement, pendingEditorState); 17090 if (prevRootElement !== null) { 17091 if (!this._config.disableEvents) { 17092 removeRootElementEvents(prevRootElement); 17093 } 17094 if (classNames != null) { 17095 prevRootElement.classList.remove(...classNames); 17096 } 17097 } 17098 if (nextRootElement !== null) { 17099 const windowObj = getDefaultView(nextRootElement); 17100 const style = nextRootElement.style; 17101 style.userSelect = "text"; 17102 style.whiteSpace = "pre-wrap"; 17103 style.wordBreak = "break-word"; 17104 nextRootElement.setAttribute("data-lexical-editor", "true"); 17105 this._window = windowObj; 17106 this._dirtyType = FULL_RECONCILE; 17107 initMutationObserver(this); 17108 this._updateTags.add(HISTORY_MERGE_TAG); 17109 $commitPendingUpdates(this); 17110 if (!this._config.disableEvents) { 17111 addRootElementEvents(nextRootElement, this); 17112 } 17113 if (classNames != null) { 17114 nextRootElement.classList.add(...classNames); 17115 } 17116 { 17117 const nextRootElementParent = nextRootElement.parentElement; 17118 if (nextRootElementParent != null && ["flex", "inline-flex"].includes(getComputedStyle(nextRootElementParent).display)) { 17119 console.warn(`When using "display: flex" or "display: inline-flex" on an element containing content editable, Chrome may have unwanted focusing behavior when clicking outside of it. Consider wrapping the content editable within a non-flex element.`); 17120 } 17121 } 17122 } else { 17123 this._window = null; 17124 this._updateTags.add(HISTORY_MERGE_TAG); 17125 $commitPendingUpdates(this); 17126 } 17127 triggerListeners("root", this, false, nextRootElement, prevRootElement); 17128 } 17129 } 17130 /** 17131 * Gets the underlying HTMLElement associated with the LexicalNode for the given key. 17132 * @returns the HTMLElement rendered by the LexicalNode associated with the key. 17133 * @param key - the key of the LexicalNode. 17134 */ 17135 getElementByKey(key) { 17136 return this._keyToDOMMap.get(key) || null; 17137 } 17138 /** 17139 * Gets the active editor state. 17140 * @returns The editor state 17141 */ 17142 getEditorState() { 17143 return this._editorState; 17144 } 17145 /** 17146 * Imperatively set the EditorState. Triggers reconciliation like an update. 17147 * @param editorState - the state to set the editor 17148 * @param options - options for the update. 17149 */ 17150 setEditorState(editorState, options) { 17151 if (editorState.isEmpty()) { 17152 { 17153 formatDevErrorMessage(`setEditorState: the editor state is empty. Ensure the editor state's root node never becomes empty.`); 17154 } 17155 } 17156 let writableEditorState = editorState; 17157 if (writableEditorState._readOnly) { 17158 writableEditorState = cloneEditorState(editorState); 17159 writableEditorState._selection = editorState._selection ? editorState._selection.clone() : null; 17160 } 17161 flushRootMutations(this); 17162 const pendingEditorState = this._pendingEditorState; 17163 const tags = this._updateTags; 17164 const tag = options !== void 0 ? options.tag : null; 17165 if (pendingEditorState !== null && !pendingEditorState.isEmpty()) { 17166 if (tag != null) { 17167 tags.add(tag); 17168 } 17169 $commitPendingUpdates(this); 17170 } 17171 this._pendingEditorState = writableEditorState; 17172 this._dirtyType = FULL_RECONCILE; 17173 this._dirtyElements.set("root", false); 17174 this._compositionKey = null; 17175 if (tag != null) { 17176 tags.add(tag); 17177 } 17178 if (!this._updating) { 17179 $commitPendingUpdates(this); 17180 } 17181 } 17182 /** 17183 * Parses a SerializedEditorState (usually produced by {@link EditorState.toJSON}) and returns 17184 * and EditorState object that can be, for example, passed to {@link LexicalEditor.setEditorState}. Typically, 17185 * deserialization from JSON stored in a database uses this method. 17186 * @param maybeStringifiedEditorState 17187 * @param updateFn 17188 * @returns 17189 */ 17190 parseEditorState(maybeStringifiedEditorState, updateFn) { 17191 const serializedEditorState = typeof maybeStringifiedEditorState === "string" ? JSON.parse(maybeStringifiedEditorState) : maybeStringifiedEditorState; 17192 return parseEditorState(serializedEditorState, this, updateFn); 17193 } 17194 /** 17195 * Executes a read of the editor's state, with the 17196 * editor context available (useful for exporting and read-only DOM 17197 * operations). Much like update, but prevents any mutation of the 17198 * editor's state. Any pending updates will be flushed immediately before 17199 * the read. 17200 * @param callbackFn - A function that has access to read-only editor state. 17201 */ 17202 read(callbackFn) { 17203 $commitPendingUpdates(this); 17204 return this.getEditorState().read(callbackFn, { 17205 editor: this 17206 }); 17207 } 17208 /** 17209 * Executes an update to the editor state. The updateFn callback is the ONLY place 17210 * where Lexical editor state can be safely mutated. 17211 * @param updateFn - A function that has access to writable editor state. 17212 * @param options - A bag of options to control the behavior of the update. 17213 */ 17214 update(updateFn, options) { 17215 updateEditor(this, updateFn, options); 17216 } 17217 /** 17218 * Focuses the editor by marking the existing selection as dirty, or by 17219 * creating a new selection at `defaultSelection` if one does not already 17220 * exist. If you want to force a specific selection, you should call 17221 * `root.selectStart()` or `root.selectEnd()` in an update. 17222 * 17223 * @param callbackFn - A function to run after the editor is focused. 17224 * @param options - A bag of options 17225 */ 17226 focus(callbackFn, options = {}) { 17227 const rootElement = this._rootElement; 17228 if (rootElement !== null) { 17229 rootElement.setAttribute("autocapitalize", "off"); 17230 updateEditorSync(this, () => { 17231 const selection = $getSelection(); 17232 const root = $getRoot(); 17233 if (selection !== null) { 17234 if (!selection.dirty) { 17235 $setSelection(selection.clone()); 17236 } 17237 } else if (root.getChildrenSize() !== 0) { 17238 if (options.defaultSelection === "rootStart") { 17239 root.selectStart(); 17240 } else { 17241 root.selectEnd(); 17242 } 17243 } 17244 $addUpdateTag(FOCUS_TAG); 17245 $onUpdate(() => { 17246 rootElement.removeAttribute("autocapitalize"); 17247 if (callbackFn) { 17248 callbackFn(); 17249 } 17250 }); 17251 }); 17252 if (this._pendingEditorState === null) { 17253 rootElement.removeAttribute("autocapitalize"); 17254 } 17255 } 17256 } 17257 /** 17258 * Removes focus from the editor. 17259 */ 17260 blur() { 17261 const rootElement = this._rootElement; 17262 if (rootElement !== null) { 17263 rootElement.blur(); 17264 } 17265 const domSelection = getDOMSelection(this._window); 17266 if (domSelection !== null) { 17267 domSelection.removeAllRanges(); 17268 } 17269 } 17270 /** 17271 * Returns true if the editor is editable, false otherwise. 17272 * @returns True if the editor is editable, false otherwise. 17273 */ 17274 isEditable() { 17275 return this._editable; 17276 } 17277 /** 17278 * Sets the editable property of the editor. When false, the 17279 * editor will not listen for user events on the underling contenteditable. 17280 * @param editable - the value to set the editable mode to. 17281 */ 17282 setEditable(editable) { 17283 if (this._editable !== editable) { 17284 this._editable = editable; 17285 triggerListeners("editable", this, true, editable); 17286 } 17287 } 17288 /** 17289 * Returns a JSON-serializable javascript object NOT a JSON string. 17290 * You still must call JSON.stringify (or something else) to turn the 17291 * state into a string you can transfer over the wire and store in a database. 17292 * 17293 * See {@link LexicalNode.exportJSON} 17294 * 17295 * @returns A JSON-serializable javascript object 17296 */ 17297 toJSON() { 17298 return { 17299 editorState: this._editorState.toJSON() 17300 }; 17301 } 17302 }; 17303 LexicalEditor.version = "0.44.0+dev.esm"; 17304 var pendingNodeToClone = null; 17305 function setPendingNodeToClone(pendingNode) { 17306 pendingNodeToClone = pendingNode; 17307 } 17308 function getPendingNodeToClone() { 17309 const node = pendingNodeToClone; 17310 pendingNodeToClone = null; 17311 return node; 17312 } 17313 var keyCounter = 1; 17314 function resetRandomKey() { 17315 keyCounter = 1; 17316 } 17317 function generateRandomKey() { 17318 return "" + keyCounter++; 17319 } 17320 function getRegisteredNodeOrThrow(editor, nodeType) { 17321 const registeredNode = getRegisteredNode(editor, nodeType); 17322 if (registeredNode === void 0) { 17323 { 17324 formatDevErrorMessage(`registeredNode: Type ${nodeType} not found`); 17325 } 17326 } 17327 return registeredNode; 17328 } 17329 function getRegisteredNode(editor, nodeType) { 17330 return editor._nodes.get(nodeType); 17331 } 17332 var scheduleMicroTask = typeof queueMicrotask === "function" ? queueMicrotask : (fn) => { 17333 Promise.resolve().then(fn); 17334 }; 17335 function $isSelectionCapturedInDecorator(node) { 17336 return $isDecoratorNode($getNearestNodeFromDOMNode(node)); 17337 } 17338 function isSelectionCapturedInDecoratorInput(anchorDOM) { 17339 const activeElement = document.activeElement; 17340 if (!isHTMLElement(activeElement)) { 17341 return false; 17342 } 17343 const nodeName = activeElement.nodeName; 17344 return $isDecoratorNode($getNearestNodeFromDOMNode(anchorDOM)) && (nodeName === "INPUT" || nodeName === "TEXTAREA" || activeElement.contentEditable === "true" && getEditorPropertyFromDOMNode(activeElement) == null); 17345 } 17346 function isSelectionWithinEditor(editor, anchorDOM, focusDOM) { 17347 const rootElement = editor.getRootElement(); 17348 try { 17349 return rootElement !== null && rootElement.contains(anchorDOM) && rootElement.contains(focusDOM) && // Ignore if selection is within nested editor 17350 anchorDOM !== null && !isSelectionCapturedInDecoratorInput(anchorDOM) && getNearestEditorFromDOMNode(anchorDOM) === editor; 17351 } catch (_error) { 17352 return false; 17353 } 17354 } 17355 function isLexicalEditor(editor) { 17356 return editor instanceof LexicalEditor; 17357 } 17358 function getNearestEditorFromDOMNode(node) { 17359 let currentNode = node; 17360 while (currentNode != null) { 17361 const editor = getEditorPropertyFromDOMNode(currentNode); 17362 if (isLexicalEditor(editor)) { 17363 return editor; 17364 } 17365 currentNode = getParentElement(currentNode); 17366 } 17367 return null; 17368 } 17369 function getEditorPropertyFromDOMNode(node) { 17370 return node ? node.__lexicalEditor : null; 17371 } 17372 function getTextDirection(text2) { 17373 if (RTL_REGEX.test(text2)) { 17374 return "rtl"; 17375 } 17376 if (LTR_REGEX.test(text2)) { 17377 return "ltr"; 17378 } 17379 return null; 17380 } 17381 function $isTokenOrTab(node) { 17382 return $isTabNode(node) || node.isToken(); 17383 } 17384 function $isTokenOrSegmented(node) { 17385 return $isTokenOrTab(node) || node.isSegmented(); 17386 } 17387 function isDOMTextNode(node) { 17388 return isDOMNode(node) && node.nodeType === DOM_TEXT_TYPE; 17389 } 17390 function isDOMDocumentNode(node) { 17391 return isDOMNode(node) && node.nodeType === DOM_DOCUMENT_TYPE; 17392 } 17393 function getDOMTextNode(element) { 17394 let node = element; 17395 while (node != null) { 17396 if (isDOMTextNode(node)) { 17397 return node; 17398 } 17399 node = node.firstChild; 17400 } 17401 return null; 17402 } 17403 function toggleTextFormatType(format, type, alignWithFormat) { 17404 const activeFormat = TEXT_TYPE_TO_FORMAT[type]; 17405 if (alignWithFormat !== null && (format & activeFormat) === (alignWithFormat & activeFormat)) { 17406 return format; 17407 } 17408 let newFormat = format ^ activeFormat; 17409 if (type === "subscript") { 17410 newFormat &= ~TEXT_TYPE_TO_FORMAT.superscript; 17411 } else if (type === "superscript") { 17412 newFormat &= ~TEXT_TYPE_TO_FORMAT.subscript; 17413 } else if (type === "lowercase") { 17414 newFormat &= ~TEXT_TYPE_TO_FORMAT.uppercase; 17415 newFormat &= ~TEXT_TYPE_TO_FORMAT.capitalize; 17416 } else if (type === "uppercase") { 17417 newFormat &= ~TEXT_TYPE_TO_FORMAT.lowercase; 17418 newFormat &= ~TEXT_TYPE_TO_FORMAT.capitalize; 17419 } else if (type === "capitalize") { 17420 newFormat &= ~TEXT_TYPE_TO_FORMAT.lowercase; 17421 newFormat &= ~TEXT_TYPE_TO_FORMAT.uppercase; 17422 } 17423 return newFormat; 17424 } 17425 function $isLeafNode(node) { 17426 return $isTextNode(node) || $isLineBreakNode(node) || $isDecoratorNode(node); 17427 } 17428 function $setNodeKey(node, existingKey) { 17429 const pendingNode = getPendingNodeToClone(); 17430 existingKey = existingKey || pendingNode && pendingNode.__key; 17431 if (existingKey != null) { 17432 { 17433 errorOnNodeKeyConstructorMismatch(node, existingKey, pendingNode); 17434 } 17435 node.__key = existingKey; 17436 return; 17437 } 17438 errorOnReadOnly(); 17439 errorOnInfiniteTransforms(); 17440 const editor = getActiveEditor(); 17441 const editorState = getActiveEditorState(); 17442 const key = generateRandomKey(); 17443 editorState._nodeMap.set(key, node); 17444 if ($isElementNode(node)) { 17445 editor._dirtyElements.set(key, true); 17446 } else { 17447 editor._dirtyLeaves.add(key); 17448 } 17449 editor._cloneNotNeeded.add(key); 17450 editor._dirtyType = HAS_DIRTY_NODES; 17451 node.__key = key; 17452 } 17453 function errorOnNodeKeyConstructorMismatch(node, existingKey, pendingNode) { 17454 const editorState = internalGetActiveEditorState(); 17455 if (!editorState) { 17456 return; 17457 } 17458 const existingNode = editorState._nodeMap.get(existingKey); 17459 if (pendingNode) { 17460 if (!(existingKey === pendingNode.__key)) { 17461 formatDevErrorMessage(`Lexical node with constructor ${node.constructor.name} (type ${node.getType()}) has an incorrect clone implementation, got ${String(existingKey)} for nodeKey when expecting ${pendingNode.__key}`); 17462 } 17463 } 17464 if (existingNode && existingNode.constructor !== node.constructor) { 17465 if (node.constructor.name !== existingNode.constructor.name) { 17466 { 17467 formatDevErrorMessage(`Lexical node with constructor ${node.constructor.name} attempted to re-use key from node in active editor state with constructor ${existingNode.constructor.name}. Keys must not be re-used when the type is changed.`); 17468 } 17469 } else { 17470 { 17471 formatDevErrorMessage(`Lexical node with constructor ${node.constructor.name} attempted to re-use key from node in active editor state with different constructor with the same name (possibly due to invalid Hot Module Replacement). Keys must not be re-used when the type is changed.`); 17472 } 17473 } 17474 } 17475 } 17476 function internalMarkParentElementsAsDirty(parentKey, nodeMap, dirtyElements) { 17477 let nextParentKey = parentKey; 17478 while (nextParentKey !== null) { 17479 if (dirtyElements.has(nextParentKey)) { 17480 return; 17481 } 17482 const node = nodeMap.get(nextParentKey); 17483 if (node === void 0) { 17484 break; 17485 } 17486 dirtyElements.set(nextParentKey, false); 17487 nextParentKey = node.__parent; 17488 } 17489 } 17490 function removeFromParent(node) { 17491 const oldParent = node.getParent(); 17492 if (oldParent !== null) { 17493 const writableNode = node.getWritable(); 17494 const writableParent = oldParent.getWritable(); 17495 const prevSibling = node.getPreviousSibling(); 17496 const nextSibling = node.getNextSibling(); 17497 const nextSiblingKey = nextSibling !== null ? nextSibling.__key : null; 17498 const prevSiblingKey = prevSibling !== null ? prevSibling.__key : null; 17499 const writablePrevSibling = prevSibling !== null ? prevSibling.getWritable() : null; 17500 const writableNextSibling = nextSibling !== null ? nextSibling.getWritable() : null; 17501 if (prevSibling === null) { 17502 writableParent.__first = nextSiblingKey; 17503 } 17504 if (nextSibling === null) { 17505 writableParent.__last = prevSiblingKey; 17506 } 17507 if (writablePrevSibling !== null) { 17508 writablePrevSibling.__next = nextSiblingKey; 17509 } 17510 if (writableNextSibling !== null) { 17511 writableNextSibling.__prev = prevSiblingKey; 17512 } 17513 writableNode.__prev = null; 17514 writableNode.__next = null; 17515 writableNode.__parent = null; 17516 writableParent.__size--; 17517 } 17518 } 17519 function internalMarkNodeAsDirty(node) { 17520 errorOnInfiniteTransforms(); 17521 if (!!$isEphemeral(node)) { 17522 formatDevErrorMessage(`internalMarkNodeAsDirty: Ephemeral nodes must not be marked as dirty (key ${node.__key} type ${node.__type})`); 17523 } 17524 const latest = node.getLatest(); 17525 const parent = latest.__parent; 17526 const editorState = getActiveEditorState(); 17527 const editor = getActiveEditor(); 17528 const nodeMap = editorState._nodeMap; 17529 const dirtyElements = editor._dirtyElements; 17530 if (parent !== null) { 17531 internalMarkParentElementsAsDirty(parent, nodeMap, dirtyElements); 17532 } 17533 const key = latest.__key; 17534 editor._dirtyType = HAS_DIRTY_NODES; 17535 if ($isElementNode(node)) { 17536 dirtyElements.set(key, true); 17537 } else { 17538 editor._dirtyLeaves.add(key); 17539 } 17540 } 17541 function internalMarkSiblingsAsDirty(node) { 17542 const previousNode = node.getPreviousSibling(); 17543 const nextNode = node.getNextSibling(); 17544 if (previousNode !== null) { 17545 internalMarkNodeAsDirty(previousNode); 17546 } 17547 if (nextNode !== null) { 17548 internalMarkNodeAsDirty(nextNode); 17549 } 17550 } 17551 function $setCompositionKey(compositionKey) { 17552 errorOnReadOnly(); 17553 const editor = getActiveEditor(); 17554 const previousCompositionKey = editor._compositionKey; 17555 if (compositionKey !== previousCompositionKey) { 17556 editor._compositionKey = compositionKey; 17557 if (previousCompositionKey !== null) { 17558 const node = $getNodeByKey(previousCompositionKey); 17559 if (node !== null) { 17560 node.getWritable(); 17561 } 17562 } 17563 if (compositionKey !== null) { 17564 const node = $getNodeByKey(compositionKey); 17565 if (node !== null) { 17566 node.getWritable(); 17567 } 17568 } 17569 } 17570 } 17571 function $getCompositionKey() { 17572 if (isCurrentlyReadOnlyMode()) { 17573 return null; 17574 } 17575 const editor = getActiveEditor(); 17576 return editor._compositionKey; 17577 } 17578 function $getNodeByKey(key, _editorState) { 17579 const editorState = _editorState || getActiveEditorState(); 17580 const node = editorState._nodeMap.get(key); 17581 if (node === void 0) { 17582 return null; 17583 } 17584 return node; 17585 } 17586 function $getNodeFromDOMNode(dom, editorState) { 17587 const editor = getActiveEditor(); 17588 const key = getNodeKeyFromDOMNode(dom, editor); 17589 if (key !== void 0) { 17590 return $getNodeByKey(key, editorState); 17591 } 17592 return null; 17593 } 17594 function setNodeKeyOnDOMNode(dom, editor, key) { 17595 const prop = `__lexicalKey_${editor._key}`; 17596 dom[prop] = key; 17597 } 17598 function getNodeKeyFromDOMNode(dom, editor) { 17599 const prop = `__lexicalKey_${editor._key}`; 17600 return dom[prop]; 17601 } 17602 function $getNearestNodeFromDOMNode(startingDOM, editorState) { 17603 let dom = startingDOM; 17604 while (dom != null) { 17605 const node = $getNodeFromDOMNode(dom, editorState); 17606 if (node !== null) { 17607 return node; 17608 } 17609 dom = getParentElement(dom); 17610 } 17611 return null; 17612 } 17613 function cloneDecorators(editor) { 17614 const currentDecorators = editor._decorators; 17615 const pendingDecorators = Object.assign({}, currentDecorators); 17616 editor._pendingDecorators = pendingDecorators; 17617 return pendingDecorators; 17618 } 17619 function getEditorStateTextContent(editorState) { 17620 return editorState.read(() => $getRoot().getTextContent()); 17621 } 17622 function markNodesWithTypesAsDirty(editor, types) { 17623 const cachedMap = getCachedTypeToNodeMap(editor.getEditorState()); 17624 const dirtyNodeMaps = []; 17625 for (const type of types) { 17626 const nodeMap = cachedMap.get(type); 17627 if (nodeMap) { 17628 dirtyNodeMaps.push(nodeMap); 17629 } 17630 } 17631 if (dirtyNodeMaps.length === 0) { 17632 return; 17633 } 17634 editor.update(() => { 17635 for (const nodeMap of dirtyNodeMaps) { 17636 for (const nodeKey of nodeMap.keys()) { 17637 const latest = $getNodeByKey(nodeKey); 17638 if (latest) { 17639 latest.markDirty(); 17640 } 17641 } 17642 } 17643 }, editor._pendingEditorState === null ? { 17644 tag: HISTORY_MERGE_TAG 17645 } : void 0); 17646 } 17647 function $getRoot() { 17648 return internalGetRoot(getActiveEditorState()); 17649 } 17650 function internalGetRoot(editorState) { 17651 return editorState._nodeMap.get("root"); 17652 } 17653 function $setSelection(selection) { 17654 errorOnReadOnly(); 17655 const editorState = getActiveEditorState(); 17656 if (selection !== null) { 17657 { 17658 if (Object.isFrozen(selection)) { 17659 { 17660 formatDevErrorMessage(`$setSelection called on frozen selection object. Ensure selection is cloned before passing in.`); 17661 } 17662 } 17663 } 17664 selection.dirty = true; 17665 selection.setCachedNodes(null); 17666 } 17667 editorState._selection = selection; 17668 } 17669 function $flushMutations() { 17670 errorOnReadOnly(); 17671 const editor = getActiveEditor(); 17672 flushRootMutations(editor); 17673 } 17674 function $getNodeFromDOM(dom) { 17675 const editor = getActiveEditor(); 17676 const nodeKey = getNodeKeyFromDOMTree(dom, editor); 17677 if (nodeKey === null) { 17678 const rootElement = editor.getRootElement(); 17679 if (dom === rootElement) { 17680 return $getNodeByKey("root"); 17681 } 17682 return null; 17683 } 17684 return $getNodeByKey(nodeKey); 17685 } 17686 function getNodeKeyFromDOMTree(dom, editor) { 17687 let node = dom; 17688 while (node != null) { 17689 const key = getNodeKeyFromDOMNode(node, editor); 17690 if (key !== void 0) { 17691 return key; 17692 } 17693 node = getParentElement(node); 17694 } 17695 return null; 17696 } 17697 function doesContainSurrogatePair(str) { 17698 return /[\uD800-\uDBFF][\uDC00-\uDFFF]/g.test(str); 17699 } 17700 function getEditorsToPropagate(editor) { 17701 const editorsToPropagate = []; 17702 for (let currentEditor = editor; currentEditor !== null; currentEditor = currentEditor._parentEditor) { 17703 editorsToPropagate.push(currentEditor); 17704 } 17705 return editorsToPropagate; 17706 } 17707 function createUID() { 17708 return Math.random().toString(36).replace(/[^a-z]+/g, "").substring(0, 5); 17709 } 17710 function getAnchorTextFromDOM(anchorNode) { 17711 return isDOMTextNode(anchorNode) ? anchorNode.nodeValue : null; 17712 } 17713 function $updateSelectedTextFromDOM(isCompositionEnd, editor, data) { 17714 const domSelection = getDOMSelection(getWindow(editor)); 17715 if (domSelection === null) { 17716 return; 17717 } 17718 const anchorNode = domSelection.anchorNode; 17719 let { 17720 anchorOffset, 17721 focusOffset 17722 } = domSelection; 17723 if (anchorNode !== null) { 17724 let textContent = getAnchorTextFromDOM(anchorNode); 17725 const node = $getNearestNodeFromDOMNode(anchorNode); 17726 if (textContent !== null && $isTextNode(node)) { 17727 if ((textContent === COMPOSITION_SUFFIX || textContent === COMPOSITION_START_CHAR) && data) { 17728 const offset3 = data.length; 17729 textContent = data; 17730 anchorOffset = offset3; 17731 focusOffset = offset3; 17732 } 17733 if (textContent !== null) { 17734 $updateTextNodeFromDOMContent(node, textContent, anchorOffset, focusOffset, isCompositionEnd); 17735 } 17736 } 17737 } 17738 } 17739 function $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focusOffset, compositionEnd) { 17740 let node = textNode; 17741 if (node.isAttached() && (compositionEnd || !node.isDirty())) { 17742 const isComposing = node.isComposing(); 17743 let normalizedTextContent = textContent; 17744 if (isComposing || compositionEnd) { 17745 if (textContent.endsWith(COMPOSITION_SUFFIX)) { 17746 normalizedTextContent = textContent.slice(0, -COMPOSITION_SUFFIX.length); 17747 } 17748 if (compositionEnd) { 17749 const char = COMPOSITION_START_CHAR; 17750 let index; 17751 while ((index = normalizedTextContent.indexOf(char)) !== -1) { 17752 normalizedTextContent = normalizedTextContent.slice(0, index) + normalizedTextContent.slice(index + char.length); 17753 if (anchorOffset !== null && anchorOffset > index) { 17754 anchorOffset = Math.max(index, anchorOffset - char.length); 17755 } 17756 if (focusOffset !== null && focusOffset > index) { 17757 focusOffset = Math.max(index, focusOffset - char.length); 17758 } 17759 } 17760 } 17761 } 17762 const prevTextContent = node.getTextContent(); 17763 if (compositionEnd || normalizedTextContent !== prevTextContent) { 17764 if (normalizedTextContent === "") { 17765 $setCompositionKey(null); 17766 if (!IS_SAFARI && !IS_IOS && !IS_APPLE_WEBKIT) { 17767 const editor = getActiveEditor(); 17768 setTimeout(() => { 17769 editor.update(() => { 17770 if (node.isAttached()) { 17771 node.remove(); 17772 } 17773 }); 17774 }, 20); 17775 } else { 17776 node.remove(); 17777 } 17778 return; 17779 } 17780 const parent = node.getParent(); 17781 const prevSelection = $getPreviousSelection(); 17782 const prevTextContentSize = node.getTextContentSize(); 17783 const compositionKey = $getCompositionKey(); 17784 const nodeKey = node.getKey(); 17785 if (node.isToken() || compositionKey !== null && nodeKey === compositionKey && !isComposing || // Check if character was added at the start or boundaries when not insertable, and we need 17786 // to clear this input from occurring as that action wasn't permitted. 17787 $isRangeSelection(prevSelection) && (parent !== null && !parent.canInsertTextBefore() && prevSelection.anchor.offset === 0 || prevSelection.anchor.key === textNode.__key && prevSelection.anchor.offset === 0 && !node.canInsertTextBefore() && !isComposing || prevSelection.focus.key === textNode.__key && prevSelection.focus.offset === prevTextContentSize && !node.canInsertTextAfter() && !isComposing)) { 17788 node.markDirty(); 17789 return; 17790 } 17791 const selection = $getSelection(); 17792 if (!$isRangeSelection(selection) || anchorOffset === null || focusOffset === null) { 17793 $setTextContentWithSelection(node, normalizedTextContent, selection); 17794 return; 17795 } 17796 selection.setTextNodeRange(node, anchorOffset, node, focusOffset); 17797 if (node.isSegmented()) { 17798 const originalTextContent = node.getTextContent(); 17799 const replacement = $createTextNode(originalTextContent); 17800 node.replace(replacement); 17801 node = replacement; 17802 } 17803 $setTextContentWithSelection(node, normalizedTextContent, selection); 17804 } 17805 } 17806 } 17807 function $setTextContentWithSelection(node, textContent, selection) { 17808 node.setTextContent(textContent); 17809 if ($isRangeSelection(selection)) { 17810 const key = node.getKey(); 17811 for (const k2 of ["anchor", "focus"]) { 17812 const pt = selection[k2]; 17813 if (pt.type === "text" && pt.key === key) { 17814 pt.offset = $getTextNodeOffset(node, pt.offset, "clamp"); 17815 } 17816 } 17817 } 17818 } 17819 function $previousSiblingDoesNotAcceptText(node) { 17820 const previousSibling = node.getPreviousSibling(); 17821 return ($isTextNode(previousSibling) || $isElementNode(previousSibling) && previousSibling.isInline()) && !previousSibling.canInsertTextAfter(); 17822 } 17823 function $shouldInsertTextAfterOrBeforeTextNode(selection, node) { 17824 if (node.isSegmented()) { 17825 return true; 17826 } 17827 if (!selection.isCollapsed()) { 17828 return false; 17829 } 17830 const offset3 = selection.anchor.offset; 17831 const parent = node.getParentOrThrow(); 17832 const isToken = $isTokenOrTab(node); 17833 if (offset3 === 0) { 17834 return !node.canInsertTextBefore() || !parent.canInsertTextBefore() && !node.isComposing() || isToken || $previousSiblingDoesNotAcceptText(node); 17835 } else if (offset3 === node.getTextContentSize()) { 17836 return !node.canInsertTextAfter() || !parent.canInsertTextAfter() && !node.isComposing() || isToken; 17837 } else { 17838 return false; 17839 } 17840 } 17841 function matchModifier(event, mask, prop) { 17842 const expected = mask[prop] || false; 17843 return expected === "any" || expected === event[prop]; 17844 } 17845 function isModifierMatch(event, mask) { 17846 return matchModifier(event, mask, "altKey") && matchModifier(event, mask, "ctrlKey") && matchModifier(event, mask, "shiftKey") && matchModifier(event, mask, "metaKey"); 17847 } 17848 function isExactShortcutMatch(event, expectedKey, mask) { 17849 if (!isModifierMatch(event, mask)) { 17850 return false; 17851 } 17852 if (event.key.toLowerCase() === expectedKey.toLowerCase()) { 17853 return true; 17854 } 17855 if (expectedKey.length > 1) { 17856 return false; 17857 } 17858 if (event.key.length === 1 && event.key.charCodeAt(0) <= 127) { 17859 return false; 17860 } 17861 if (event.code.startsWith("Digit") && /^\d$/.test(expectedKey)) { 17862 return event.code === `Digit${expectedKey}`; 17863 } 17864 const expectedCode = "Key" + expectedKey.toUpperCase(); 17865 return event.code === expectedCode; 17866 } 17867 var CONTROL_OR_META = { 17868 ctrlKey: !IS_APPLE, 17869 metaKey: IS_APPLE 17870 }; 17871 var CONTROL_OR_ALT = { 17872 altKey: IS_APPLE, 17873 ctrlKey: !IS_APPLE 17874 }; 17875 function isTab(event) { 17876 return isExactShortcutMatch(event, "Tab", { 17877 shiftKey: "any" 17878 }); 17879 } 17880 function isBold(event) { 17881 return isExactShortcutMatch(event, "b", CONTROL_OR_META); 17882 } 17883 function isItalic(event) { 17884 return isExactShortcutMatch(event, "i", CONTROL_OR_META); 17885 } 17886 function isUnderline(event) { 17887 return isExactShortcutMatch(event, "u", CONTROL_OR_META); 17888 } 17889 function isParagraph(event) { 17890 return isExactShortcutMatch(event, "Enter", { 17891 altKey: "any", 17892 ctrlKey: "any", 17893 metaKey: "any" 17894 }); 17895 } 17896 function isLineBreak(event) { 17897 return isExactShortcutMatch(event, "Enter", { 17898 altKey: "any", 17899 ctrlKey: "any", 17900 metaKey: "any", 17901 shiftKey: true 17902 }); 17903 } 17904 function isOpenLineBreak(event) { 17905 return IS_APPLE && isExactShortcutMatch(event, "o", { 17906 ctrlKey: true 17907 }); 17908 } 17909 function isDeleteWordBackward(event) { 17910 return isExactShortcutMatch(event, "Backspace", CONTROL_OR_ALT); 17911 } 17912 function isDeleteWordForward(event) { 17913 return isExactShortcutMatch(event, "Delete", CONTROL_OR_ALT); 17914 } 17915 function isDeleteLineBackward(event) { 17916 return IS_APPLE && isExactShortcutMatch(event, "Backspace", { 17917 metaKey: true 17918 }); 17919 } 17920 function isDeleteLineForward(event) { 17921 return IS_APPLE && (isExactShortcutMatch(event, "Delete", { 17922 metaKey: true 17923 }) || isExactShortcutMatch(event, "k", { 17924 ctrlKey: true 17925 })); 17926 } 17927 function isDeleteBackward(event) { 17928 return isExactShortcutMatch(event, "Backspace", { 17929 shiftKey: "any" 17930 }) || IS_APPLE && isExactShortcutMatch(event, "h", { 17931 ctrlKey: true 17932 }); 17933 } 17934 function isDeleteForward(event) { 17935 return isExactShortcutMatch(event, "Delete", {}) || IS_APPLE && isExactShortcutMatch(event, "d", { 17936 ctrlKey: true 17937 }); 17938 } 17939 function isUndo(event) { 17940 return isExactShortcutMatch(event, "z", CONTROL_OR_META); 17941 } 17942 function isRedo(event) { 17943 if (IS_APPLE) { 17944 return isExactShortcutMatch(event, "z", { 17945 metaKey: true, 17946 shiftKey: true 17947 }); 17948 } 17949 return isExactShortcutMatch(event, "y", { 17950 ctrlKey: true 17951 }) || isExactShortcutMatch(event, "z", { 17952 ctrlKey: true, 17953 shiftKey: true 17954 }); 17955 } 17956 function isCopy(event) { 17957 return isExactShortcutMatch(event, "c", CONTROL_OR_META); 17958 } 17959 function isCut(event) { 17960 return isExactShortcutMatch(event, "x", CONTROL_OR_META); 17961 } 17962 function isMoveBackward(event) { 17963 return isExactShortcutMatch(event, "ArrowLeft", { 17964 shiftKey: "any" 17965 }); 17966 } 17967 function isMoveToStart(event) { 17968 return isExactShortcutMatch(event, "ArrowLeft", CONTROL_OR_META); 17969 } 17970 function isMoveForward(event) { 17971 return isExactShortcutMatch(event, "ArrowRight", { 17972 shiftKey: "any" 17973 }); 17974 } 17975 function isMoveToEnd(event) { 17976 return isExactShortcutMatch(event, "ArrowRight", CONTROL_OR_META); 17977 } 17978 function isMoveUp(event) { 17979 return isExactShortcutMatch(event, "ArrowUp", { 17980 altKey: "any", 17981 shiftKey: "any" 17982 }); 17983 } 17984 function isMoveDown(event) { 17985 return isExactShortcutMatch(event, "ArrowDown", { 17986 altKey: "any", 17987 shiftKey: "any" 17988 }); 17989 } 17990 function isModifier(event) { 17991 return event.ctrlKey || event.shiftKey || event.altKey || event.metaKey; 17992 } 17993 function isSpace(event) { 17994 return event.key === " "; 17995 } 17996 function isBackspace(event) { 17997 return event.key === "Backspace"; 17998 } 17999 function isEscape(event) { 18000 return event.key === "Escape"; 18001 } 18002 function isDelete(event) { 18003 return event.key === "Delete"; 18004 } 18005 function isSelectAll(event) { 18006 return isExactShortcutMatch(event, "a", CONTROL_OR_META); 18007 } 18008 function $selectAll(selection) { 18009 const root = $getRoot(); 18010 if ($isRangeSelection(selection)) { 18011 const anchor = selection.anchor; 18012 const focus = selection.focus; 18013 const anchorNode = anchor.getNode(); 18014 const topParent = anchorNode.getTopLevelElementOrThrow(); 18015 const rootNode = topParent.getParentOrThrow(); 18016 anchor.set(rootNode.getKey(), 0, "element"); 18017 focus.set(rootNode.getKey(), rootNode.getChildrenSize(), "element"); 18018 $normalizeSelection(selection); 18019 return selection; 18020 } else { 18021 const newSelection = root.select(0, root.getChildrenSize()); 18022 $setSelection($normalizeSelection(newSelection)); 18023 return newSelection; 18024 } 18025 } 18026 function getCachedClassNameArray(classNamesTheme, classNameThemeType) { 18027 if (classNamesTheme.__lexicalClassNameCache === void 0) { 18028 classNamesTheme.__lexicalClassNameCache = {}; 18029 } 18030 const classNamesCache = classNamesTheme.__lexicalClassNameCache; 18031 const cachedClassNames = classNamesCache[classNameThemeType]; 18032 if (cachedClassNames !== void 0) { 18033 return cachedClassNames; 18034 } 18035 const classNames = classNamesTheme[classNameThemeType]; 18036 if (typeof classNames === "string") { 18037 const classNamesArr = normalizeClassNames(classNames); 18038 classNamesCache[classNameThemeType] = classNamesArr; 18039 return classNamesArr; 18040 } 18041 return classNames; 18042 } 18043 function setMutatedNode(mutatedNodes2, registeredNodes, mutationListeners, node, mutation) { 18044 if (mutationListeners.size === 0) { 18045 return; 18046 } 18047 const nodeType = node.__type; 18048 const nodeKey = node.__key; 18049 const registeredNode = registeredNodes.get(nodeType); 18050 if (registeredNode === void 0) { 18051 { 18052 formatDevErrorMessage(`Type ${nodeType} not in registeredNodes`); 18053 } 18054 } 18055 const klass = registeredNode.klass; 18056 let mutatedNodesByType = mutatedNodes2.get(klass); 18057 if (mutatedNodesByType === void 0) { 18058 mutatedNodesByType = /* @__PURE__ */ new Map(); 18059 mutatedNodes2.set(klass, mutatedNodesByType); 18060 } 18061 const prevMutation = mutatedNodesByType.get(nodeKey); 18062 const isMove = prevMutation === "destroyed" && mutation === "created"; 18063 if (prevMutation === void 0 || isMove) { 18064 mutatedNodesByType.set(nodeKey, isMove ? "updated" : mutation); 18065 } 18066 } 18067 function $nodesOfType(klass) { 18068 const klassType = klass.getType(); 18069 const editorState = getActiveEditorState(); 18070 if (editorState._readOnly) { 18071 const nodes2 = getCachedTypeToNodeMap(editorState).get(klassType); 18072 return nodes2 ? Array.from(nodes2.values()) : []; 18073 } 18074 const nodes = editorState._nodeMap; 18075 const nodesOfType = []; 18076 for (const [, node] of nodes) { 18077 if (node instanceof klass && node.__type === klassType && node.isAttached()) { 18078 nodesOfType.push(node); 18079 } 18080 } 18081 return nodesOfType; 18082 } 18083 function resolveElement(element, isBackward, focusOffset) { 18084 const parent = element.getParent(); 18085 let offset3 = focusOffset; 18086 let block = element; 18087 if (parent !== null) { 18088 if (isBackward && focusOffset === 0) { 18089 offset3 = block.getIndexWithinParent(); 18090 block = parent; 18091 } else if (!isBackward && focusOffset === block.getChildrenSize()) { 18092 offset3 = block.getIndexWithinParent() + 1; 18093 block = parent; 18094 } 18095 } 18096 return block.getChildAtIndex(isBackward ? offset3 - 1 : offset3); 18097 } 18098 function $getAdjacentNode(focus, isBackward) { 18099 const focusOffset = focus.offset; 18100 if (focus.type === "element") { 18101 const block = focus.getNode(); 18102 return resolveElement(block, isBackward, focusOffset); 18103 } else { 18104 const focusNode = focus.getNode(); 18105 if (isBackward && focusOffset === 0 || !isBackward && focusOffset === focusNode.getTextContentSize()) { 18106 const possibleNode = isBackward ? focusNode.getPreviousSibling() : focusNode.getNextSibling(); 18107 if (possibleNode === null) { 18108 return resolveElement(focusNode.getParentOrThrow(), isBackward, focusNode.getIndexWithinParent() + (isBackward ? 0 : 1)); 18109 } 18110 return possibleNode; 18111 } 18112 } 18113 return null; 18114 } 18115 function isFirefoxClipboardEvents(editor) { 18116 const event = getWindow(editor).event; 18117 const inputType = event && event.inputType; 18118 return inputType === "insertFromPaste" || inputType === "insertFromPasteAsQuotation"; 18119 } 18120 function dispatchCommand(editor, command, payload) { 18121 return triggerCommandListeners(editor, command, payload, editor); 18122 } 18123 function getElementByKeyOrThrow(editor, key) { 18124 const element = editor._keyToDOMMap.get(key); 18125 if (element === void 0) { 18126 { 18127 formatDevErrorMessage(`Reconciliation: could not find DOM element for node key ${key}`); 18128 } 18129 } 18130 return element; 18131 } 18132 function getParentElement(node) { 18133 const parentElement = node.assignedSlot || node.parentElement; 18134 return isDocumentFragment(parentElement) ? parentElement.host : parentElement; 18135 } 18136 function getDOMOwnerDocument(target) { 18137 return isDOMDocumentNode(target) ? target : isHTMLElement(target) ? target.ownerDocument : null; 18138 } 18139 function scrollIntoViewIfNeeded(editor, selectionRect, rootElement) { 18140 const doc = getDOMOwnerDocument(rootElement); 18141 const defaultView = getDefaultView(doc); 18142 if (doc === null || defaultView === null) { 18143 return; 18144 } 18145 let { 18146 top: currentTop, 18147 bottom: currentBottom 18148 } = selectionRect; 18149 let targetTop = 0; 18150 let targetBottom = 0; 18151 let element = rootElement; 18152 while (element !== null) { 18153 const isBodyElement = element === doc.body; 18154 if (isBodyElement) { 18155 targetTop = 0; 18156 targetBottom = getWindow(editor).innerHeight; 18157 const computedStyle = defaultView.getComputedStyle(doc.documentElement); 18158 const scrollPaddingTop = parseFloat(computedStyle.scrollPaddingTop); 18159 const scrollPaddingBottom = parseFloat(computedStyle.scrollPaddingBottom); 18160 if (isFinite(scrollPaddingTop)) { 18161 targetTop += scrollPaddingTop; 18162 } 18163 if (isFinite(scrollPaddingBottom)) { 18164 targetBottom -= scrollPaddingBottom; 18165 } 18166 } else { 18167 const targetRect = element.getBoundingClientRect(); 18168 targetTop = targetRect.top; 18169 targetBottom = targetRect.bottom; 18170 } 18171 let diff = 0; 18172 if (currentTop < targetTop) { 18173 diff = -(targetTop - currentTop); 18174 } else if (currentBottom > targetBottom) { 18175 diff = currentBottom - targetBottom; 18176 } 18177 if (diff !== 0) { 18178 if (isBodyElement) { 18179 defaultView.scrollBy(0, diff); 18180 } else { 18181 const scrollTop = element.scrollTop; 18182 element.scrollTop += diff; 18183 const yOffset = element.scrollTop - scrollTop; 18184 currentTop -= yOffset; 18185 currentBottom -= yOffset; 18186 } 18187 } 18188 if (isBodyElement) { 18189 break; 18190 } 18191 element = getParentElement(element); 18192 } 18193 } 18194 function $hasUpdateTag(tag) { 18195 const editor = getActiveEditor(); 18196 return editor._updateTags.has(tag); 18197 } 18198 function $addUpdateTag(tag) { 18199 errorOnReadOnly(); 18200 const editor = getActiveEditor(); 18201 editor._updateTags.add(tag); 18202 } 18203 function $onUpdate(updateFn) { 18204 errorOnReadOnly(); 18205 const editor = getActiveEditor(); 18206 editor._deferred.push(updateFn); 18207 } 18208 function $maybeMoveChildrenSelectionToParent(parentNode) { 18209 const selection = $getSelection(); 18210 if (!$isRangeSelection(selection) || !$isElementNode(parentNode)) { 18211 return selection; 18212 } 18213 const { 18214 anchor, 18215 focus 18216 } = selection; 18217 const anchorNode = anchor.getNode(); 18218 const focusNode = focus.getNode(); 18219 if ($hasAncestor(anchorNode, parentNode)) { 18220 anchor.set(parentNode.__key, 0, "element"); 18221 } 18222 if ($hasAncestor(focusNode, parentNode)) { 18223 focus.set(parentNode.__key, 0, "element"); 18224 } 18225 return selection; 18226 } 18227 function $hasAncestor(child, targetNode) { 18228 let parent = child.getParent(); 18229 while (parent !== null) { 18230 if (parent.is(targetNode)) { 18231 return true; 18232 } 18233 parent = parent.getParent(); 18234 } 18235 return false; 18236 } 18237 function getDefaultView(domElem) { 18238 const ownerDoc = getDOMOwnerDocument(domElem); 18239 return ownerDoc ? ownerDoc.defaultView : null; 18240 } 18241 function getWindow(editor) { 18242 const windowObj = editor._window; 18243 if (windowObj === null) { 18244 { 18245 formatDevErrorMessage(`window object not found`); 18246 } 18247 } 18248 return windowObj; 18249 } 18250 function $isInlineElementOrDecoratorNode(node) { 18251 return $isElementNode(node) && node.isInline() || $isDecoratorNode(node) && node.isInline(); 18252 } 18253 function $getNearestRootOrShadowRoot(node) { 18254 let parent = node.getParentOrThrow(); 18255 while (parent !== null) { 18256 if ($isRootOrShadowRoot(parent)) { 18257 return parent; 18258 } 18259 parent = parent.getParentOrThrow(); 18260 } 18261 return parent; 18262 } 18263 function $isRootOrShadowRoot(node) { 18264 return $isRootNode(node) || $isElementNode(node) && node.isShadowRoot(); 18265 } 18266 function $copyNode(node, skipReset = false) { 18267 const copy = node.constructor.clone(node); 18268 $setNodeKey(copy, null); 18269 copy.afterCloneFrom(node); 18270 if (!skipReset) { 18271 copy.resetOnCopyNodeFrom(node); 18272 } 18273 return copy; 18274 } 18275 function $applyNodeReplacement(node) { 18276 const editor = getActiveEditor(); 18277 const nodeType = node.getType(); 18278 const registeredNode = getRegisteredNode(editor, nodeType); 18279 if (!(registeredNode !== void 0)) { 18280 formatDevErrorMessage(`$applyNodeReplacement node ${node.constructor.name} with type ${nodeType} must be registered to the editor. You can do this by passing the node class via the "nodes" array in the editor config.`); 18281 } 18282 const { 18283 replace, 18284 replaceWithKlass 18285 } = registeredNode; 18286 if (replace !== null) { 18287 const replacementNode = replace(node); 18288 const replacementNodeKlass = replacementNode.constructor; 18289 if (replaceWithKlass !== null) { 18290 if (!(replacementNode instanceof replaceWithKlass)) { 18291 formatDevErrorMessage(`$applyNodeReplacement failed. Expected replacement node to be an instance of ${replaceWithKlass.name} with type ${replaceWithKlass.getType()} but returned ${replacementNodeKlass.name} with type ${replacementNodeKlass.getType()} from original node ${node.constructor.name} with type ${nodeType}`); 18292 } 18293 } else { 18294 if (!(replacementNode instanceof node.constructor && replacementNodeKlass !== node.constructor)) { 18295 formatDevErrorMessage(`$applyNodeReplacement failed. Ensure replacement node ${replacementNodeKlass.name} with type ${replacementNodeKlass.getType()} is a subclass of the original node ${node.constructor.name} with type ${nodeType}.`); 18296 } 18297 } 18298 if (!(replacementNode.__key !== node.__key)) { 18299 formatDevErrorMessage(`$applyNodeReplacement failed. Ensure that the key argument is *not* used in your replace function (from node ${node.constructor.name} with type ${nodeType} to node ${replacementNodeKlass.name} with type ${replacementNodeKlass.getType()}), Node keys must never be re-used except by the static clone method.`); 18300 } 18301 return replacementNode; 18302 } 18303 return node; 18304 } 18305 function errorOnInsertTextNodeOnRoot(node, insertNode) { 18306 const parentNode = node.getParent(); 18307 if ($isRootNode(parentNode) && !$isElementNode(insertNode) && !$isDecoratorNode(insertNode)) { 18308 { 18309 formatDevErrorMessage(`Only element or decorator nodes can be inserted in to the root node`); 18310 } 18311 } 18312 } 18313 function $getNodeByKeyOrThrow(key) { 18314 const node = $getNodeByKey(key); 18315 if (node === null) { 18316 { 18317 formatDevErrorMessage(`Expected node with key ${key} to exist but it's not in the nodeMap.`); 18318 } 18319 } 18320 return node; 18321 } 18322 function createBlockCursorElement(editorConfig) { 18323 const theme2 = editorConfig.theme; 18324 const element = document.createElement("div"); 18325 element.contentEditable = "false"; 18326 element.setAttribute("data-lexical-cursor", "true"); 18327 let blockCursorTheme = theme2.blockCursor; 18328 if (blockCursorTheme !== void 0) { 18329 if (typeof blockCursorTheme === "string") { 18330 const classNamesArr = normalizeClassNames(blockCursorTheme); 18331 blockCursorTheme = theme2.blockCursor = classNamesArr; 18332 } 18333 if (blockCursorTheme !== void 0) { 18334 element.classList.add(...blockCursorTheme); 18335 } 18336 } 18337 return element; 18338 } 18339 function needsBlockCursor(node) { 18340 return ($isDecoratorNode(node) || $isElementNode(node) && !node.canBeEmpty()) && !node.isInline(); 18341 } 18342 function removeDOMBlockCursorElement(blockCursorElement, editor, rootElement) { 18343 rootElement.style.removeProperty("caret-color"); 18344 editor._blockCursorElement = null; 18345 const parentElement = blockCursorElement.parentElement; 18346 if (parentElement !== null) { 18347 parentElement.removeChild(blockCursorElement); 18348 } 18349 } 18350 function updateDOMBlockCursorElement(editor, rootElement, nextSelection) { 18351 let blockCursorElement = editor._blockCursorElement; 18352 if ($isRangeSelection(nextSelection) && nextSelection.isCollapsed() && nextSelection.anchor.type === "element" && rootElement.contains(document.activeElement)) { 18353 const anchor = nextSelection.anchor; 18354 const elementNode = anchor.getNode(); 18355 const offset3 = anchor.offset; 18356 const elementNodeSize = elementNode.getChildrenSize(); 18357 let isBlockCursor = false; 18358 let insertBeforeElement = null; 18359 if (offset3 === elementNodeSize) { 18360 const child = elementNode.getChildAtIndex(offset3 - 1); 18361 if (needsBlockCursor(child)) { 18362 isBlockCursor = true; 18363 } 18364 } else { 18365 const child = elementNode.getChildAtIndex(offset3); 18366 if (child !== null && needsBlockCursor(child)) { 18367 const sibling = child.getPreviousSibling(); 18368 if (sibling === null || needsBlockCursor(sibling)) { 18369 isBlockCursor = true; 18370 insertBeforeElement = editor.getElementByKey(child.__key); 18371 } 18372 } 18373 } 18374 if (isBlockCursor) { 18375 const elementDOM = editor.getElementByKey(elementNode.__key); 18376 if (blockCursorElement === null) { 18377 editor._blockCursorElement = blockCursorElement = createBlockCursorElement(editor._config); 18378 } 18379 rootElement.style.caretColor = "transparent"; 18380 if (insertBeforeElement === null) { 18381 elementDOM.appendChild(blockCursorElement); 18382 } else { 18383 elementDOM.insertBefore(blockCursorElement, insertBeforeElement); 18384 } 18385 return; 18386 } 18387 } 18388 if (blockCursorElement !== null) { 18389 removeDOMBlockCursorElement(blockCursorElement, editor, rootElement); 18390 } 18391 } 18392 function getDOMSelection(targetWindow) { 18393 return !CAN_USE_DOM ? null : (targetWindow || window).getSelection(); 18394 } 18395 function getDOMSelectionFromTarget(eventTarget) { 18396 const defaultView = getDefaultView(eventTarget); 18397 return defaultView ? defaultView.getSelection() : null; 18398 } 18399 function $splitNode(node, offset3) { 18400 let startNode = node.getChildAtIndex(offset3); 18401 if (startNode == null) { 18402 startNode = node; 18403 } 18404 if (!!$isRootOrShadowRoot(node)) { 18405 formatDevErrorMessage(`Can not call $splitNode() on root element`); 18406 } 18407 const recurse = (currentNode) => { 18408 const parent = currentNode.getParentOrThrow(); 18409 const isParentRoot = $isRootOrShadowRoot(parent); 18410 const nodeToMove = currentNode === startNode && !isParentRoot ? currentNode : $copyNode(currentNode); 18411 if (isParentRoot) { 18412 if (!($isElementNode(currentNode) && $isElementNode(nodeToMove))) { 18413 formatDevErrorMessage(`Children of a root must be ElementNode`); 18414 } 18415 currentNode.insertAfter(nodeToMove); 18416 return [currentNode, nodeToMove, nodeToMove]; 18417 } else { 18418 const [leftTree2, rightTree2, newParent] = recurse(parent); 18419 const nextSiblings = currentNode.getNextSiblings(); 18420 newParent.append(nodeToMove, ...nextSiblings); 18421 return [leftTree2, rightTree2, nodeToMove]; 18422 } 18423 }; 18424 const [leftTree, rightTree] = recurse(startNode); 18425 return [leftTree, rightTree]; 18426 } 18427 function isHTMLAnchorElement(x3) { 18428 return isHTMLElement(x3) && x3.tagName === "A"; 18429 } 18430 function isHTMLElement(x3) { 18431 return isDOMNode(x3) && x3.nodeType === DOM_ELEMENT_TYPE; 18432 } 18433 function isDOMNode(x3) { 18434 return typeof x3 === "object" && x3 !== null && "nodeType" in x3 && typeof x3.nodeType === "number"; 18435 } 18436 function isDocumentFragment(x3) { 18437 return isDOMNode(x3) && x3.nodeType === DOM_DOCUMENT_FRAGMENT_TYPE; 18438 } 18439 function isInlineDomNode(node) { 18440 const inlineNodes = new RegExp(/^(a|abbr|acronym|b|cite|code|del|em|i|ins|kbd|label|mark|output|q|ruby|s|samp|span|strong|sub|sup|time|u|tt|var|#text)$/, "i"); 18441 return node.nodeName.match(inlineNodes) !== null; 18442 } 18443 function isBlockDomNode(node) { 18444 const blockNodes = new RegExp(/^(address|article|aside|blockquote|canvas|dd|div|dl|dt|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hr|li|main|nav|noscript|ol|p|pre|section|table|td|tfoot|ul|video)$/, "i"); 18445 return node.nodeName.match(blockNodes) !== null; 18446 } 18447 function INTERNAL_$isBlock(node) { 18448 if ($isDecoratorNode(node) && !node.isInline()) { 18449 return true; 18450 } 18451 if (!$isElementNode(node) || $isRootOrShadowRoot(node)) { 18452 return false; 18453 } 18454 const firstChild = node.getFirstChild(); 18455 const isLeafElement = firstChild === null || $isLineBreakNode(firstChild) || $isTextNode(firstChild) || firstChild.isInline(); 18456 return !node.isInline() && node.canBeEmpty() !== false && isLeafElement; 18457 } 18458 function $getEditor() { 18459 return getActiveEditor(); 18460 } 18461 function $getEditorDOMRenderConfig(editor = $getEditor()) { 18462 return editor._config.dom || DEFAULT_EDITOR_DOM_CONFIG; 18463 } 18464 var cachedNodeMaps = /* @__PURE__ */ new WeakMap(); 18465 var EMPTY_TYPE_TO_NODE_MAP = /* @__PURE__ */ new Map(); 18466 function getCachedTypeToNodeMap(editorState) { 18467 if (!editorState._readOnly && editorState.isEmpty()) { 18468 return EMPTY_TYPE_TO_NODE_MAP; 18469 } 18470 if (!editorState._readOnly) { 18471 formatDevErrorMessage(`getCachedTypeToNodeMap called with a writable EditorState`); 18472 } 18473 let typeToNodeMap = cachedNodeMaps.get(editorState); 18474 if (!typeToNodeMap) { 18475 typeToNodeMap = computeTypeToNodeMap(editorState); 18476 cachedNodeMaps.set(editorState, typeToNodeMap); 18477 } 18478 return typeToNodeMap; 18479 } 18480 function computeTypeToNodeMap(editorState) { 18481 const typeToNodeMap = /* @__PURE__ */ new Map(); 18482 for (const [nodeKey, node] of editorState._nodeMap) { 18483 const nodeType = node.__type; 18484 let nodeMap = typeToNodeMap.get(nodeType); 18485 if (!nodeMap) { 18486 nodeMap = /* @__PURE__ */ new Map(); 18487 typeToNodeMap.set(nodeType, nodeMap); 18488 } 18489 nodeMap.set(nodeKey, node); 18490 } 18491 return typeToNodeMap; 18492 } 18493 function $cloneWithProperties(latestNode) { 18494 const constructor = latestNode.constructor; 18495 const mutableNode = constructor.clone(latestNode); 18496 mutableNode.afterCloneFrom(latestNode); 18497 { 18498 if (!(mutableNode.__key === latestNode.__key)) { 18499 formatDevErrorMessage(`$cloneWithProperties: ${constructor.name}.clone(node) (with type '${constructor.getType()}') did not return a node with the same key, make sure to specify node.__key as the last argument to the constructor`); 18500 } 18501 if (!(mutableNode.__parent === latestNode.__parent && mutableNode.__next === latestNode.__next && mutableNode.__prev === latestNode.__prev)) { 18502 formatDevErrorMessage(`$cloneWithProperties: ${constructor.name}.clone(node) (with type '${constructor.getType()}') overrode afterCloneFrom but did not call super.afterCloneFrom(prevNode)`); 18503 } 18504 } 18505 return mutableNode; 18506 } 18507 function $cloneWithPropertiesEphemeral(latestNode) { 18508 return $markEphemeral($cloneWithProperties(latestNode)); 18509 } 18510 function setNodeIndentFromDOM(elementDom, elementNode) { 18511 const indentSize = parseInt(elementDom.style.paddingInlineStart, 10) || 0; 18512 const indent = Math.round(indentSize / 40); 18513 elementNode.setIndent(indent); 18514 } 18515 function setDOMUnmanaged(elementDom) { 18516 const el = elementDom; 18517 el.__lexicalUnmanaged = true; 18518 } 18519 function isDOMUnmanaged(elementDom) { 18520 const el = elementDom; 18521 return el.__lexicalUnmanaged === true; 18522 } 18523 function hasOwn(o2, k2) { 18524 return Object.prototype.hasOwnProperty.call(o2, k2); 18525 } 18526 function hasOwnStaticMethod(klass, k2) { 18527 return hasOwn(klass, k2) && klass[k2] !== LexicalNode[k2]; 18528 } 18529 function hasOwnExportDOM(klass) { 18530 return hasOwn(klass.prototype, "exportDOM"); 18531 } 18532 function isAbstractNodeClass(klass) { 18533 if (!(klass === LexicalNode || klass.prototype instanceof LexicalNode)) { 18534 let ownNodeType = "<unknown>"; 18535 let version = "<unknown>"; 18536 try { 18537 ownNodeType = klass.getType(); 18538 } catch (_err) { 18539 } 18540 try { 18541 if (LexicalEditor.version) { 18542 version = JSON.parse(LexicalEditor.version); 18543 } 18544 } catch (_err) { 18545 } 18546 { 18547 formatDevErrorMessage(`${klass.name} (type ${ownNodeType}) does not subclass LexicalNode from the lexical package used by this editor (version ${version}). All lexical and @lexical/* packages used by an editor must have identical versions. If you suspect the version does match, then the problem may be caused by multiple copies of the same lexical module (e.g. both esm and cjs, or included directly in multiple entrypoints).`); 18548 } 18549 } 18550 return klass === DecoratorNode || klass === ElementNode || klass === LexicalNode; 18551 } 18552 function getStaticNodeConfig(klass) { 18553 const nodeConfigRecord = PROTOTYPE_CONFIG_METHOD in klass.prototype ? klass.prototype[PROTOTYPE_CONFIG_METHOD]() : void 0; 18554 const isAbstract = isAbstractNodeClass(klass); 18555 const nodeType = !isAbstract && hasOwnStaticMethod(klass, "getType") ? klass.getType() : void 0; 18556 let ownNodeConfig; 18557 let ownNodeType = nodeType; 18558 if (nodeConfigRecord) { 18559 if (nodeType) { 18560 ownNodeConfig = nodeConfigRecord[nodeType]; 18561 } else { 18562 for (const [k2, v3] of Object.entries(nodeConfigRecord)) { 18563 ownNodeType = k2; 18564 ownNodeConfig = v3; 18565 } 18566 } 18567 } 18568 if (!isAbstract && ownNodeType) { 18569 if (!hasOwnStaticMethod(klass, "getType")) { 18570 klass.getType = () => ownNodeType; 18571 } 18572 if (!hasOwnStaticMethod(klass, "clone")) { 18573 if (TextNode.length === 0) { 18574 if (!(klass.length === 0)) { 18575 formatDevErrorMessage(`${klass.name} (type ${ownNodeType}) must implement a static clone method since its constructor has ${String(klass.length)} required arguments (expecting 0). Use an explicit default in the first argument of your constructor(prop: T=X, nodeKey?: NodeKey).`); 18576 } 18577 } 18578 klass.clone = (prevNode) => { 18579 setPendingNodeToClone(prevNode); 18580 return new klass(); 18581 }; 18582 } 18583 if (!hasOwnStaticMethod(klass, "importJSON")) { 18584 if (TextNode.length === 0) { 18585 if (!(klass.length === 0)) { 18586 formatDevErrorMessage(`${klass.name} (type ${ownNodeType}) must implement a static importJSON method since its constructor has ${String(klass.length)} required arguments (expecting 0). Use an explicit default in the first argument of your constructor(prop: T=X, nodeKey?: NodeKey).`); 18587 } 18588 } 18589 klass.importJSON = ownNodeConfig && ownNodeConfig.$importJSON || ((serializedNode) => new klass().updateFromJSON(serializedNode)); 18590 } 18591 if (!hasOwnStaticMethod(klass, "importDOM") && ownNodeConfig) { 18592 const { 18593 importDOM 18594 } = ownNodeConfig; 18595 if (importDOM) { 18596 klass.importDOM = () => importDOM; 18597 } 18598 } 18599 } 18600 return { 18601 ownNodeConfig, 18602 ownNodeType 18603 }; 18604 } 18605 function $create(klass) { 18606 const editor = $getEditor(); 18607 errorOnReadOnly(); 18608 const registeredNode = editor.resolveRegisteredNodeAfterReplacements(editor.getRegisteredNode(klass)); 18609 return new registeredNode.klass(); 18610 } 18611 var $findMatchingParent = (startingNode, findFn) => { 18612 let curr = startingNode; 18613 while (curr != null && !$isRootNode(curr)) { 18614 if (findFn(curr)) { 18615 return curr; 18616 } 18617 curr = curr.getParent(); 18618 } 18619 return null; 18620 }; 18621 function $createChildrenArray(element, nodeMap) { 18622 const children = []; 18623 let nodeKey = element.__first; 18624 while (nodeKey !== null) { 18625 const node = nodeMap === null ? $getNodeByKey(nodeKey) : nodeMap.get(nodeKey); 18626 if (node === null || node === void 0) { 18627 { 18628 formatDevErrorMessage(`$createChildrenArray: node does not exist in nodeMap`); 18629 } 18630 } 18631 children.push(nodeKey); 18632 nodeKey = node.__next; 18633 } 18634 return children; 18635 } 18636 var FLIP_DIRECTION = { 18637 next: "previous", 18638 previous: "next" 18639 }; 18640 var AbstractCaret = class { 18641 origin; 18642 constructor(origin) { 18643 this.origin = origin; 18644 } 18645 [Symbol.iterator]() { 18646 return makeStepwiseIterator({ 18647 hasNext: $isSiblingCaret, 18648 initial: this.getAdjacentCaret(), 18649 map: (caret) => caret, 18650 step: (caret) => caret.getAdjacentCaret() 18651 }); 18652 } 18653 getAdjacentCaret() { 18654 return $getSiblingCaret(this.getNodeAtCaret(), this.direction); 18655 } 18656 getSiblingCaret() { 18657 return $getSiblingCaret(this.origin, this.direction); 18658 } 18659 remove() { 18660 const node = this.getNodeAtCaret(); 18661 if (node) { 18662 node.remove(); 18663 } 18664 return this; 18665 } 18666 replaceOrInsert(node, includeChildren) { 18667 const target = this.getNodeAtCaret(); 18668 if (node.is(this.origin) || node.is(target)) ; 18669 else if (target === null) { 18670 this.insert(node); 18671 } else { 18672 target.replace(node, includeChildren); 18673 } 18674 return this; 18675 } 18676 splice(deleteCount, nodes, nodesDirection = "next") { 18677 const nodeIter = nodesDirection === this.direction ? nodes : Array.from(nodes).reverse(); 18678 let caret = this; 18679 const parent = this.getParentAtCaret(); 18680 const nodesToRemove = /* @__PURE__ */ new Map(); 18681 for (let removeCaret = caret.getAdjacentCaret(); removeCaret !== null && nodesToRemove.size < deleteCount; removeCaret = removeCaret.getAdjacentCaret()) { 18682 const writableNode = removeCaret.origin.getWritable(); 18683 nodesToRemove.set(writableNode.getKey(), writableNode); 18684 } 18685 for (const node of nodeIter) { 18686 if (nodesToRemove.size > 0) { 18687 const target = caret.getNodeAtCaret(); 18688 if (target) { 18689 nodesToRemove.delete(target.getKey()); 18690 nodesToRemove.delete(node.getKey()); 18691 if (target.is(node) || caret.origin.is(node)) ; 18692 else { 18693 const nodeParent = node.getParent(); 18694 if (nodeParent && nodeParent.is(parent)) { 18695 node.remove(); 18696 } 18697 target.replace(node); 18698 } 18699 } else { 18700 if (!(target !== null)) { 18701 formatDevErrorMessage(`NodeCaret.splice: Underflow of expected nodesToRemove during splice (keys: ${Array.from(nodesToRemove).join(" ")})`); 18702 } 18703 } 18704 } else { 18705 caret.insert(node); 18706 } 18707 caret = $getSiblingCaret(node, this.direction); 18708 } 18709 for (const node of nodesToRemove.values()) { 18710 node.remove(); 18711 } 18712 return this; 18713 } 18714 }; 18715 var AbstractChildCaret = class _AbstractChildCaret extends AbstractCaret { 18716 type = "child"; 18717 getLatest() { 18718 const origin = this.origin.getLatest(); 18719 return origin === this.origin ? this : $getChildCaret(origin, this.direction); 18720 } 18721 /** 18722 * Get the SiblingCaret from this origin in the same direction. 18723 * 18724 * @param mode 'root' to return null at the root, 'shadowRoot' to return null at the root or any shadow root 18725 * @returns A SiblingCaret with this origin, or null if origin is a root according to mode. 18726 */ 18727 getParentCaret(mode = "root") { 18728 return $getSiblingCaret($filterByMode(this.getParentAtCaret(), mode), this.direction); 18729 } 18730 getFlipped() { 18731 const dir = flipDirection(this.direction); 18732 return $getSiblingCaret(this.getNodeAtCaret(), dir) || $getChildCaret(this.origin, dir); 18733 } 18734 getParentAtCaret() { 18735 return this.origin; 18736 } 18737 getChildCaret() { 18738 return this; 18739 } 18740 isSameNodeCaret(other) { 18741 return other instanceof _AbstractChildCaret && this.direction === other.direction && this.origin.is(other.origin); 18742 } 18743 isSamePointCaret(other) { 18744 return this.isSameNodeCaret(other); 18745 } 18746 }; 18747 var ChildCaretFirst = class extends AbstractChildCaret { 18748 direction = "next"; 18749 getNodeAtCaret() { 18750 return this.origin.getFirstChild(); 18751 } 18752 insert(node) { 18753 this.origin.splice(0, 0, [node]); 18754 return this; 18755 } 18756 }; 18757 var ChildCaretLast = class extends AbstractChildCaret { 18758 direction = "previous"; 18759 getNodeAtCaret() { 18760 return this.origin.getLastChild(); 18761 } 18762 insert(node) { 18763 this.origin.splice(this.origin.getChildrenSize(), 0, [node]); 18764 return this; 18765 } 18766 }; 18767 var MODE_PREDICATE = { 18768 root: $isRootNode, 18769 shadowRoot: $isRootOrShadowRoot 18770 }; 18771 function flipDirection(direction) { 18772 return FLIP_DIRECTION[direction]; 18773 } 18774 function $filterByMode(node, mode = "root") { 18775 return MODE_PREDICATE[mode](node) ? null : node; 18776 } 18777 var AbstractSiblingCaret = class _AbstractSiblingCaret extends AbstractCaret { 18778 type = "sibling"; 18779 getLatest() { 18780 const origin = this.origin.getLatest(); 18781 return origin === this.origin ? this : $getSiblingCaret(origin, this.direction); 18782 } 18783 getSiblingCaret() { 18784 return this; 18785 } 18786 getParentAtCaret() { 18787 return this.origin.getParent(); 18788 } 18789 getChildCaret() { 18790 return $isElementNode(this.origin) ? $getChildCaret(this.origin, this.direction) : null; 18791 } 18792 getParentCaret(mode = "root") { 18793 return $getSiblingCaret($filterByMode(this.getParentAtCaret(), mode), this.direction); 18794 } 18795 getFlipped() { 18796 const dir = flipDirection(this.direction); 18797 return $getSiblingCaret(this.getNodeAtCaret(), dir) || $getChildCaret(this.origin.getParentOrThrow(), dir); 18798 } 18799 isSamePointCaret(other) { 18800 return other instanceof _AbstractSiblingCaret && this.direction === other.direction && this.origin.is(other.origin); 18801 } 18802 isSameNodeCaret(other) { 18803 return (other instanceof _AbstractSiblingCaret || other instanceof AbstractTextPointCaret) && this.direction === other.direction && this.origin.is(other.origin); 18804 } 18805 }; 18806 var AbstractTextPointCaret = class _AbstractTextPointCaret extends AbstractCaret { 18807 type = "text"; 18808 offset; 18809 constructor(origin, offset3) { 18810 super(origin); 18811 this.offset = offset3; 18812 } 18813 getLatest() { 18814 const origin = this.origin.getLatest(); 18815 return origin === this.origin ? this : $getTextPointCaret(origin, this.direction, this.offset); 18816 } 18817 getParentAtCaret() { 18818 return this.origin.getParent(); 18819 } 18820 getChildCaret() { 18821 return null; 18822 } 18823 getParentCaret(mode = "root") { 18824 return $getSiblingCaret($filterByMode(this.getParentAtCaret(), mode), this.direction); 18825 } 18826 getFlipped() { 18827 return $getTextPointCaret(this.origin, flipDirection(this.direction), this.offset); 18828 } 18829 isSamePointCaret(other) { 18830 return other instanceof _AbstractTextPointCaret && this.direction === other.direction && this.origin.is(other.origin) && this.offset === other.offset; 18831 } 18832 isSameNodeCaret(other) { 18833 return (other instanceof AbstractSiblingCaret || other instanceof _AbstractTextPointCaret) && this.direction === other.direction && this.origin.is(other.origin); 18834 } 18835 getSiblingCaret() { 18836 return $getSiblingCaret(this.origin, this.direction); 18837 } 18838 }; 18839 function $isTextPointCaret(caret) { 18840 return caret instanceof AbstractTextPointCaret; 18841 } 18842 function $isNodeCaret(caret) { 18843 return caret instanceof AbstractCaret; 18844 } 18845 function $isSiblingCaret(caret) { 18846 return caret instanceof AbstractSiblingCaret; 18847 } 18848 function $isChildCaret(caret) { 18849 return caret instanceof AbstractChildCaret; 18850 } 18851 var SiblingCaretNext = class extends AbstractSiblingCaret { 18852 direction = "next"; 18853 getNodeAtCaret() { 18854 return this.origin.getNextSibling(); 18855 } 18856 insert(node) { 18857 this.origin.insertAfter(node); 18858 return this; 18859 } 18860 }; 18861 var SiblingCaretPrevious = class extends AbstractSiblingCaret { 18862 direction = "previous"; 18863 getNodeAtCaret() { 18864 return this.origin.getPreviousSibling(); 18865 } 18866 insert(node) { 18867 this.origin.insertBefore(node); 18868 return this; 18869 } 18870 }; 18871 var TextPointCaretNext = class extends AbstractTextPointCaret { 18872 direction = "next"; 18873 getNodeAtCaret() { 18874 return this.origin.getNextSibling(); 18875 } 18876 insert(node) { 18877 this.origin.insertAfter(node); 18878 return this; 18879 } 18880 }; 18881 var TextPointCaretPrevious = class extends AbstractTextPointCaret { 18882 direction = "previous"; 18883 getNodeAtCaret() { 18884 return this.origin.getPreviousSibling(); 18885 } 18886 insert(node) { 18887 this.origin.insertBefore(node); 18888 return this; 18889 } 18890 }; 18891 var TEXT_CTOR = { 18892 next: TextPointCaretNext, 18893 previous: TextPointCaretPrevious 18894 }; 18895 var SIBLING_CTOR = { 18896 next: SiblingCaretNext, 18897 previous: SiblingCaretPrevious 18898 }; 18899 var CHILD_CTOR = { 18900 next: ChildCaretFirst, 18901 previous: ChildCaretLast 18902 }; 18903 function $getSiblingCaret(origin, direction) { 18904 return origin ? new SIBLING_CTOR[direction](origin) : null; 18905 } 18906 function $getTextPointCaret(origin, direction, offset3) { 18907 return origin ? new TEXT_CTOR[direction](origin, $getTextNodeOffset(origin, offset3)) : null; 18908 } 18909 function $getTextNodeOffset(origin, offset3, mode = "error") { 18910 const size2 = origin.getTextContentSize(); 18911 let numericOffset = offset3 === "next" ? size2 : offset3 === "previous" ? 0 : offset3; 18912 if (numericOffset < 0 || numericOffset > size2) { 18913 if (!(mode === "clamp")) { 18914 formatDevErrorMessage(`$getTextNodeOffset: invalid offset ${String(offset3)} for size ${String(size2)} at key ${origin.getKey()}`); 18915 } 18916 numericOffset = numericOffset < 0 ? 0 : size2; 18917 } 18918 return numericOffset; 18919 } 18920 function $getTextPointCaretSlice(caret, distance) { 18921 return new TextPointCaretSliceImpl(caret, distance); 18922 } 18923 function $getChildCaret(origin, direction) { 18924 return $isElementNode(origin) ? new CHILD_CTOR[direction](origin) : null; 18925 } 18926 function $getChildCaretOrSelf(caret) { 18927 return caret && caret.getChildCaret() || caret; 18928 } 18929 function $getAdjacentChildCaret(caret) { 18930 return caret && $getChildCaretOrSelf(caret.getAdjacentCaret()); 18931 } 18932 var CaretRangeImpl = class _CaretRangeImpl { 18933 type = "node-caret-range"; 18934 direction; 18935 anchor; 18936 focus; 18937 constructor(anchor, focus, direction) { 18938 this.anchor = anchor; 18939 this.focus = focus; 18940 this.direction = direction; 18941 } 18942 getLatest() { 18943 const anchor = this.anchor.getLatest(); 18944 const focus = this.focus.getLatest(); 18945 return anchor === this.anchor && focus === this.focus ? this : new _CaretRangeImpl(anchor, focus, this.direction); 18946 } 18947 isCollapsed() { 18948 return this.anchor.isSamePointCaret(this.focus); 18949 } 18950 getTextSlices() { 18951 const getSlice = (k2) => { 18952 const caret = this[k2].getLatest(); 18953 return $isTextPointCaret(caret) ? $getSliceFromTextPointCaret(caret, k2) : null; 18954 }; 18955 const anchorSlice = getSlice("anchor"); 18956 const focusSlice = getSlice("focus"); 18957 if (anchorSlice && focusSlice) { 18958 const { 18959 caret: anchorCaret 18960 } = anchorSlice; 18961 const { 18962 caret: focusCaret 18963 } = focusSlice; 18964 if (anchorCaret.isSameNodeCaret(focusCaret)) { 18965 return [$getTextPointCaretSlice(anchorCaret, focusCaret.offset - anchorCaret.offset), null]; 18966 } 18967 } 18968 return [anchorSlice, focusSlice]; 18969 } 18970 iterNodeCarets(rootMode = "root") { 18971 const anchor = $isTextPointCaret(this.anchor) ? this.anchor.getSiblingCaret() : this.anchor.getLatest(); 18972 const focus = this.focus.getLatest(); 18973 const isTextFocus = $isTextPointCaret(focus); 18974 const step = (state) => state.isSameNodeCaret(focus) ? null : $getAdjacentChildCaret(state) || state.getParentCaret(rootMode); 18975 return makeStepwiseIterator({ 18976 hasNext: (state) => state !== null && !(isTextFocus && focus.isSameNodeCaret(state)), 18977 initial: anchor.isSameNodeCaret(focus) ? null : step(anchor), 18978 map: (state) => state, 18979 step 18980 }); 18981 } 18982 [Symbol.iterator]() { 18983 return this.iterNodeCarets("root"); 18984 } 18985 }; 18986 var TextPointCaretSliceImpl = class { 18987 type = "slice"; 18988 caret; 18989 distance; 18990 constructor(caret, distance) { 18991 this.caret = caret; 18992 this.distance = distance; 18993 } 18994 getSliceIndices() { 18995 const { 18996 distance, 18997 caret: { 18998 offset: offset3 18999 } 19000 } = this; 19001 const offsetB = offset3 + distance; 19002 return offsetB < offset3 ? [offsetB, offset3] : [offset3, offsetB]; 19003 } 19004 getTextContent() { 19005 const [startIndex, endIndex] = this.getSliceIndices(); 19006 return this.caret.origin.getTextContent().slice(startIndex, endIndex); 19007 } 19008 getTextContentSize() { 19009 return Math.abs(this.distance); 19010 } 19011 removeTextSlice() { 19012 const { 19013 caret: { 19014 origin, 19015 direction 19016 } 19017 } = this; 19018 const [indexStart, indexEnd] = this.getSliceIndices(); 19019 const text2 = origin.getTextContent(); 19020 return $getTextPointCaret(origin.setTextContent(text2.slice(0, indexStart) + text2.slice(indexEnd)), direction, indexStart); 19021 } 19022 }; 19023 function $getSliceFromTextPointCaret(caret, anchorOrFocus) { 19024 const { 19025 direction, 19026 origin 19027 } = caret; 19028 const offsetB = $getTextNodeOffset(origin, anchorOrFocus === "focus" ? flipDirection(direction) : direction); 19029 return $getTextPointCaretSlice(caret, offsetB - caret.offset); 19030 } 19031 function $isTextPointCaretSlice(caretOrSlice) { 19032 return caretOrSlice instanceof TextPointCaretSliceImpl; 19033 } 19034 function $extendCaretToRange(anchor) { 19035 return $getCaretRange(anchor, $getSiblingCaret($getRoot(), anchor.direction)); 19036 } 19037 function $getCollapsedCaretRange(anchor) { 19038 return $getCaretRange(anchor, anchor); 19039 } 19040 function $getCaretRange(anchor, focus) { 19041 if (!(anchor.direction === focus.direction)) { 19042 formatDevErrorMessage(`$getCaretRange: anchor and focus must be in the same direction`); 19043 } 19044 return new CaretRangeImpl(anchor, focus, anchor.direction); 19045 } 19046 function makeStepwiseIterator(config) { 19047 const { 19048 initial, 19049 hasNext, 19050 step, 19051 map 19052 } = config; 19053 let state = initial; 19054 return { 19055 [Symbol.iterator]() { 19056 return this; 19057 }, 19058 next() { 19059 if (!hasNext(state)) { 19060 return { 19061 done: true, 19062 value: void 0 19063 }; 19064 } 19065 const rval = { 19066 done: false, 19067 value: map(state) 19068 }; 19069 state = step(state); 19070 return rval; 19071 } 19072 }; 19073 } 19074 function compareNumber(a2, b3) { 19075 return Math.sign(a2 - b3); 19076 } 19077 function $comparePointCaretNext(a2, b3) { 19078 const compare = $getCommonAncestor(a2.origin, b3.origin); 19079 if (!(compare !== null)) { 19080 formatDevErrorMessage(`$comparePointCaretNext: a (key ${a2.origin.getKey()}) and b (key ${b3.origin.getKey()}) do not have a common ancestor`); 19081 } 19082 switch (compare.type) { 19083 case "same": { 19084 const aIsText = a2.type === "text"; 19085 const bIsText = b3.type === "text"; 19086 return aIsText && bIsText ? compareNumber(a2.offset, b3.offset) : a2.type === b3.type ? 0 : aIsText ? -1 : bIsText ? 1 : a2.type === "child" ? -1 : 1; 19087 } 19088 case "ancestor": { 19089 return a2.type === "child" ? -1 : 1; 19090 } 19091 case "descendant": { 19092 return b3.type === "child" ? 1 : -1; 19093 } 19094 case "branch": { 19095 return $getCommonAncestorResultBranchOrder(compare); 19096 } 19097 } 19098 } 19099 function $getCommonAncestorResultBranchOrder(compare) { 19100 const { 19101 a: a2, 19102 b: b3 19103 } = compare; 19104 const aKey = a2.__key; 19105 const bKey = b3.__key; 19106 let na = a2; 19107 let nb = b3; 19108 for (; na && nb; na = na.getNextSibling(), nb = nb.getNextSibling()) { 19109 if (na.__key === bKey) { 19110 return -1; 19111 } else if (nb.__key === aKey) { 19112 return 1; 19113 } 19114 } 19115 return na === null ? 1 : -1; 19116 } 19117 function $isSameNode(reference, other) { 19118 return other.is(reference); 19119 } 19120 function $initialElementTuple(node) { 19121 return $isElementNode(node) ? [node.getLatest(), null] : [node.getParent(), node.getLatest()]; 19122 } 19123 function $getCommonAncestor(a2, b3) { 19124 if (a2.is(b3)) { 19125 return { 19126 commonAncestor: a2, 19127 type: "same" 19128 }; 19129 } 19130 const aMap = /* @__PURE__ */ new Map(); 19131 for (let [parent, child] = $initialElementTuple(a2); parent; child = parent, parent = parent.getParent()) { 19132 aMap.set(parent, child); 19133 } 19134 for (let [parent, child] = $initialElementTuple(b3); parent; child = parent, parent = parent.getParent()) { 19135 const aChild = aMap.get(parent); 19136 if (aChild === void 0) ; 19137 else if (aChild === null) { 19138 if (!$isSameNode(a2, parent)) { 19139 formatDevErrorMessage(`$originComparison: ancestor logic error`); 19140 } 19141 return { 19142 commonAncestor: parent, 19143 type: "ancestor" 19144 }; 19145 } else if (child === null) { 19146 if (!$isSameNode(b3, parent)) { 19147 formatDevErrorMessage(`$originComparison: descendant logic error`); 19148 } 19149 return { 19150 commonAncestor: parent, 19151 type: "descendant" 19152 }; 19153 } else { 19154 if (!(($isElementNode(aChild) || $isSameNode(a2, aChild)) && ($isElementNode(child) || $isSameNode(b3, child)) && parent.is(aChild.getParent()) && parent.is(child.getParent()))) { 19155 formatDevErrorMessage(`$originComparison: branch logic error`); 19156 } 19157 return { 19158 a: aChild, 19159 b: child, 19160 commonAncestor: parent, 19161 type: "branch" 19162 }; 19163 } 19164 } 19165 return null; 19166 } 19167 function $caretFromPoint(point, direction) { 19168 const { 19169 type, 19170 key, 19171 offset: offset3 19172 } = point; 19173 const node = $getNodeByKeyOrThrow(point.key); 19174 if (type === "text") { 19175 if (!$isTextNode(node)) { 19176 formatDevErrorMessage(`$caretFromPoint: Node with type ${node.getType()} and key ${key} that does not inherit from TextNode encountered for text point`); 19177 } 19178 return $getTextPointCaret(node, direction, offset3); 19179 } 19180 if (!$isElementNode(node)) { 19181 formatDevErrorMessage(`$caretFromPoint: Node with type ${node.getType()} and key ${key} that does not inherit from ElementNode encountered for element point`); 19182 } 19183 return $getChildCaretAtIndex(node, point.offset, direction); 19184 } 19185 function $setPointFromCaret(point, caret) { 19186 const { 19187 origin, 19188 direction 19189 } = caret; 19190 const isNext = direction === "next"; 19191 if ($isTextPointCaret(caret)) { 19192 point.set(origin.getKey(), caret.offset, "text"); 19193 } else if ($isSiblingCaret(caret)) { 19194 if ($isTextNode(origin)) { 19195 point.set(origin.getKey(), $getTextNodeOffset(origin, direction), "text"); 19196 } else { 19197 point.set(origin.getParentOrThrow().getKey(), origin.getIndexWithinParent() + (isNext ? 1 : 0), "element"); 19198 } 19199 } else { 19200 if (!($isChildCaret(caret) && $isElementNode(origin))) { 19201 formatDevErrorMessage(`$setPointFromCaret: exhaustiveness check`); 19202 } 19203 point.set(origin.getKey(), isNext ? 0 : origin.getChildrenSize(), "element"); 19204 } 19205 } 19206 function $setSelectionFromCaretRange(caretRange) { 19207 const currentSelection = $getSelection(); 19208 const selection = $isRangeSelection(currentSelection) ? currentSelection : $createRangeSelection(); 19209 $updateRangeSelectionFromCaretRange(selection, caretRange); 19210 $setSelection(selection); 19211 return selection; 19212 } 19213 function $updateRangeSelectionFromCaretRange(selection, caretRange) { 19214 $setPointFromCaret(selection.anchor, caretRange.anchor); 19215 $setPointFromCaret(selection.focus, caretRange.focus); 19216 } 19217 function $caretRangeFromSelection(selection) { 19218 const { 19219 anchor, 19220 focus 19221 } = selection; 19222 const anchorCaret = $caretFromPoint(anchor, "next"); 19223 const focusCaret = $caretFromPoint(focus, "next"); 19224 const direction = $comparePointCaretNext(anchorCaret, focusCaret) <= 0 ? "next" : "previous"; 19225 return $getCaretRange($getCaretInDirection(anchorCaret, direction), $getCaretInDirection(focusCaret, direction)); 19226 } 19227 function $rewindSiblingCaret(caret) { 19228 const { 19229 direction, 19230 origin 19231 } = caret; 19232 const rewindOrigin = $getSiblingCaret(origin, flipDirection(direction)).getNodeAtCaret(); 19233 return rewindOrigin ? $getSiblingCaret(rewindOrigin, direction) : $getChildCaret(origin.getParentOrThrow(), direction); 19234 } 19235 function $getAnchorCandidates(anchor, rootMode = "root") { 19236 const carets = [anchor]; 19237 for (let parent = $isChildCaret(anchor) ? anchor.getParentCaret(rootMode) : anchor.getSiblingCaret(); parent !== null; parent = parent.getParentCaret(rootMode)) { 19238 carets.push($rewindSiblingCaret(parent)); 19239 } 19240 return carets; 19241 } 19242 function $isCaretAttached(caret) { 19243 return !!caret && caret.origin.isAttached(); 19244 } 19245 function $removeTextFromCaretRange(initialRange, sliceMode = "removeEmptySlices") { 19246 if (initialRange.isCollapsed()) { 19247 return initialRange; 19248 } 19249 const rootMode = "root"; 19250 const nextDirection = "next"; 19251 let sliceState = sliceMode; 19252 const range2 = $getCaretRangeInDirection(initialRange, nextDirection); 19253 const anchorCandidates = $getAnchorCandidates(range2.anchor, rootMode); 19254 const focusCandidates = $getAnchorCandidates(range2.focus.getFlipped(), rootMode); 19255 const seenStart = /* @__PURE__ */ new Set(); 19256 const removedNodes = []; 19257 for (const caret of range2.iterNodeCarets(rootMode)) { 19258 if ($isChildCaret(caret)) { 19259 seenStart.add(caret.origin.getKey()); 19260 } else if ($isSiblingCaret(caret)) { 19261 const { 19262 origin 19263 } = caret; 19264 if (!$isElementNode(origin) || seenStart.has(origin.getKey())) { 19265 removedNodes.push(origin); 19266 } 19267 } 19268 } 19269 for (const node of removedNodes) { 19270 node.remove(); 19271 } 19272 for (const slice of range2.getTextSlices()) { 19273 if (!slice) { 19274 continue; 19275 } 19276 const { 19277 origin 19278 } = slice.caret; 19279 const contentSize = origin.getTextContentSize(); 19280 const caretBefore = $rewindSiblingCaret($getSiblingCaret(origin, nextDirection)); 19281 const mode = origin.getMode(); 19282 if (Math.abs(slice.distance) === contentSize && sliceState === "removeEmptySlices" || mode === "token" && slice.distance !== 0) { 19283 caretBefore.remove(); 19284 } else if (slice.distance !== 0) { 19285 sliceState = "removeEmptySlices"; 19286 let nextCaret = slice.removeTextSlice(); 19287 const sliceOrigin = slice.caret.origin; 19288 if (mode === "segmented") { 19289 const src = nextCaret.origin; 19290 const plainTextNode = $createTextNode(src.getTextContent()).setStyle(src.getStyle()).setFormat(src.getFormat()); 19291 caretBefore.replaceOrInsert(plainTextNode); 19292 nextCaret = $getTextPointCaret(plainTextNode, nextDirection, nextCaret.offset); 19293 } 19294 if (sliceOrigin.is(anchorCandidates[0].origin)) { 19295 anchorCandidates[0] = nextCaret; 19296 } 19297 if (sliceOrigin.is(focusCandidates[0].origin)) { 19298 focusCandidates[0] = nextCaret.getFlipped(); 19299 } 19300 } 19301 } 19302 let anchorCandidate; 19303 let focusCandidate; 19304 for (const candidate of anchorCandidates) { 19305 if ($isCaretAttached(candidate)) { 19306 anchorCandidate = $normalizeCaret(candidate); 19307 break; 19308 } 19309 } 19310 for (const candidate of focusCandidates) { 19311 if ($isCaretAttached(candidate)) { 19312 focusCandidate = $normalizeCaret(candidate); 19313 break; 19314 } 19315 } 19316 const mergeTargets = $getBlockMergeTargets(anchorCandidate, focusCandidate, seenStart); 19317 if (mergeTargets) { 19318 const [anchorBlock, focusBlock] = mergeTargets; 19319 $getChildCaret(anchorBlock, "previous").splice(0, focusBlock.getChildren()); 19320 let parent = focusBlock.getParent(); 19321 focusBlock.remove(true); 19322 while (parent && parent.isEmpty()) { 19323 const element = parent; 19324 parent = parent.getParent(); 19325 element.remove(true); 19326 } 19327 } 19328 const bestCandidate = [anchorCandidate, focusCandidate, ...anchorCandidates, ...focusCandidates].find($isCaretAttached); 19329 if (bestCandidate) { 19330 const anchor = $getCaretInDirection($normalizeCaret(bestCandidate), initialRange.direction); 19331 return $getCollapsedCaretRange(anchor); 19332 } 19333 { 19334 formatDevErrorMessage(`$removeTextFromCaretRange: selection was lost, could not find a new anchor given candidates with keys: ${JSON.stringify(anchorCandidates.map((n2) => n2.origin.__key))}`); 19335 } 19336 } 19337 function $getBlockMergeTargets(anchor, focus, seenStart) { 19338 if (!anchor || !focus) { 19339 return null; 19340 } 19341 const anchorParent = anchor.getParentAtCaret(); 19342 const focusParent = focus.getParentAtCaret(); 19343 if (!anchorParent || !focusParent) { 19344 return null; 19345 } 19346 const anchorElements = anchorParent.getParents().reverse(); 19347 anchorElements.push(anchorParent); 19348 const focusElements = focusParent.getParents().reverse(); 19349 focusElements.push(focusParent); 19350 const maxLen = Math.min(anchorElements.length, focusElements.length); 19351 let commonAncestorCount; 19352 for (commonAncestorCount = 0; commonAncestorCount < maxLen && anchorElements[commonAncestorCount] === focusElements[commonAncestorCount]; commonAncestorCount++) { 19353 } 19354 const $getBlock = (arr, predicate) => { 19355 let block; 19356 for (let i2 = commonAncestorCount; i2 < arr.length; i2++) { 19357 const ancestor = arr[i2]; 19358 if ($isRootOrShadowRoot(ancestor)) { 19359 return; 19360 } else if (!block && predicate(ancestor)) { 19361 block = ancestor; 19362 } 19363 } 19364 return block; 19365 }; 19366 const anchorBlock = $getBlock(anchorElements, INTERNAL_$isBlock); 19367 const focusBlock = anchorBlock && $getBlock(focusElements, (node) => seenStart.has(node.getKey()) && INTERNAL_$isBlock(node)); 19368 return anchorBlock && focusBlock ? [anchorBlock, focusBlock] : null; 19369 } 19370 function $getDeepestChildOrSelf(initialCaret) { 19371 let caret = initialCaret; 19372 while ($isChildCaret(caret)) { 19373 const adjacent = $getAdjacentChildCaret(caret); 19374 if (!$isChildCaret(adjacent)) { 19375 break; 19376 } 19377 caret = adjacent; 19378 } 19379 return caret; 19380 } 19381 function $normalizeCaret(initialCaret) { 19382 const caret = $getDeepestChildOrSelf(initialCaret.getLatest()); 19383 const { 19384 direction 19385 } = caret; 19386 if ($isTextNode(caret.origin)) { 19387 return $isTextPointCaret(caret) ? caret : $getTextPointCaret(caret.origin, direction, direction); 19388 } 19389 const adj = caret.getAdjacentCaret(); 19390 return $isSiblingCaret(adj) && $isTextNode(adj.origin) ? $getTextPointCaret(adj.origin, direction, flipDirection(direction)) : caret; 19391 } 19392 function $isExtendableTextPointCaret(caret) { 19393 return $isTextPointCaret(caret) && caret.offset !== $getTextNodeOffset(caret.origin, caret.direction); 19394 } 19395 function $getCaretInDirection(caret, direction) { 19396 return caret.direction === direction ? caret : caret.getFlipped(); 19397 } 19398 function $getCaretRangeInDirection(range2, direction) { 19399 if (range2.direction === direction) { 19400 return range2; 19401 } 19402 return $getCaretRange( 19403 // focus and anchor get flipped here 19404 $getCaretInDirection(range2.focus, direction), 19405 $getCaretInDirection(range2.anchor, direction) 19406 ); 19407 } 19408 function $getChildCaretAtIndex(parent, index, direction) { 19409 let caret = $getChildCaret(parent, "next"); 19410 for (let i2 = 0; i2 < index; i2++) { 19411 const nextCaret = caret.getAdjacentCaret(); 19412 if (nextCaret === null) { 19413 break; 19414 } 19415 caret = nextCaret; 19416 } 19417 return $getCaretInDirection(caret, direction); 19418 } 19419 function $getAdjacentSiblingOrParentSiblingCaret(startCaret, rootMode = "root") { 19420 let depthDiff = 0; 19421 let caret = startCaret; 19422 let nextCaret = $getAdjacentChildCaret(caret); 19423 while (nextCaret === null) { 19424 depthDiff--; 19425 nextCaret = caret.getParentCaret(rootMode); 19426 if (!nextCaret) { 19427 return null; 19428 } 19429 caret = nextCaret; 19430 nextCaret = $getAdjacentChildCaret(caret); 19431 } 19432 return nextCaret && [nextCaret, depthDiff]; 19433 } 19434 function $getAdjacentNodes(initialCaret) { 19435 const siblings = []; 19436 for (let caret = initialCaret.getAdjacentCaret(); caret; caret = caret.getAdjacentCaret()) { 19437 siblings.push(caret.origin); 19438 } 19439 return siblings; 19440 } 19441 function $splitTextPointCaret(textPointCaret) { 19442 const { 19443 origin, 19444 offset: offset3, 19445 direction 19446 } = textPointCaret; 19447 if (offset3 === $getTextNodeOffset(origin, direction)) { 19448 return textPointCaret.getSiblingCaret(); 19449 } else if (offset3 === $getTextNodeOffset(origin, flipDirection(direction))) { 19450 return $rewindSiblingCaret(textPointCaret.getSiblingCaret()); 19451 } 19452 const [textNode] = origin.splitText(offset3); 19453 if (!$isTextNode(textNode)) { 19454 formatDevErrorMessage(`$splitTextPointCaret: splitText must return at least one TextNode`); 19455 } 19456 return $getCaretInDirection($getSiblingCaret(textNode, "next"), direction); 19457 } 19458 function $alwaysSplit(_node, _edge) { 19459 return true; 19460 } 19461 function $splitAtPointCaretNext(pointCaret, { 19462 $copyElementNode = $copyNode, 19463 $splitTextPointCaretNext = $splitTextPointCaret, 19464 rootMode = "shadowRoot", 19465 $shouldSplit = $alwaysSplit, 19466 removeEmptyDestination = false 19467 } = {}) { 19468 if ($isTextPointCaret(pointCaret)) { 19469 return $splitTextPointCaretNext(pointCaret); 19470 } 19471 const parentCaret = pointCaret.getParentCaret(rootMode); 19472 if (parentCaret) { 19473 const { 19474 origin 19475 } = parentCaret; 19476 if ($isChildCaret(pointCaret)) { 19477 const beforeParentCaret = $rewindSiblingCaret(parentCaret); 19478 if (removeEmptyDestination && origin.isEmpty()) { 19479 origin.remove(); 19480 return beforeParentCaret; 19481 } 19482 if (!(origin.canBeEmpty() && $shouldSplit(origin, "first"))) { 19483 return beforeParentCaret; 19484 } 19485 } 19486 const siblings = $getAdjacentNodes(pointCaret); 19487 if (siblings.length > 0 || !removeEmptyDestination && origin.canBeEmpty() && $shouldSplit(origin, "last")) { 19488 parentCaret.insert($copyElementNode(origin).splice(0, 0, siblings)); 19489 } 19490 } 19491 return parentCaret; 19492 } 19493 // @__NO_SIDE_EFFECTS__ 19494 function defineExtension(extension) { 19495 return extension; 19496 } 19497 // @__NO_SIDE_EFFECTS__ 19498 function configExtension(...args) { 19499 return args; 19500 } 19501 // @__NO_SIDE_EFFECTS__ 19502 function declarePeerDependency(name, config) { 19503 return [name, config]; 19504 } 19505 // @__NO_SIDE_EFFECTS__ 19506 function safeCast(value) { 19507 return value; 19508 } 19509 function shallowMergeConfig(config, overrides) { 19510 if (!overrides || config === overrides) { 19511 return config; 19512 } 19513 for (const k2 in overrides) { 19514 if (config[k2] !== overrides[k2]) { 19515 return { 19516 ...config, 19517 ...overrides 19518 }; 19519 } 19520 } 19521 return config; 19522 } 19523 function normalizeClassNames(...classNames) { 19524 const rval = []; 19525 for (const className of classNames) { 19526 if (className && typeof className === "string") { 19527 for (const [s2] of className.matchAll(/\S+/g)) { 19528 rval.push(s2); 19529 } 19530 } 19531 } 19532 return rval; 19533 } 19534 function addClassNamesToElement(element, ...classNames) { 19535 const classesToAdd = normalizeClassNames(...classNames); 19536 if (classesToAdd.length > 0) { 19537 element.classList.add(...classesToAdd); 19538 } 19539 } 19540 function removeClassNamesFromElement(element, ...classNames) { 19541 const classesToRemove = normalizeClassNames(...classNames); 19542 if (classesToRemove.length > 0) { 19543 element.classList.remove(...classesToRemove); 19544 } 19545 } 19546 function mergeRegister(...func) { 19547 return () => { 19548 for (let i2 = func.length - 1; i2 >= 0; i2--) { 19549 func[i2](); 19550 } 19551 func.length = 0; 19552 }; 19553 } 19554 19555
vendor: 12,287 bytes, lines 19555-19792
19555// node_modules/lexical/Lexical.mjs 19556 var mod = true ? Lexical_dev_exports : Lexical_prod_exports; 19557 var $addUpdateTag2 = mod.$addUpdateTag; 19558 var $applyNodeReplacement2 = mod.$applyNodeReplacement; 19559 var $caretFromPoint2 = mod.$caretFromPoint; 19560 var $caretRangeFromSelection2 = mod.$caretRangeFromSelection; 19561 var $cloneWithProperties2 = mod.$cloneWithProperties; 19562 var $cloneWithPropertiesEphemeral2 = mod.$cloneWithPropertiesEphemeral; 19563 var $comparePointCaretNext2 = mod.$comparePointCaretNext; 19564 var $copyNode2 = mod.$copyNode; 19565 var $create2 = mod.$create; 19566 var $createChildrenArray2 = mod.$createChildrenArray; 19567 var $createLineBreakNode2 = mod.$createLineBreakNode; 19568 var $createNodeSelection2 = mod.$createNodeSelection; 19569 var $createParagraphNode2 = mod.$createParagraphNode; 19570 var $createPoint2 = mod.$createPoint; 19571 var $createRangeSelection2 = mod.$createRangeSelection; 19572 var $createRangeSelectionFromDom2 = mod.$createRangeSelectionFromDom; 19573 var $createTabNode2 = mod.$createTabNode; 19574 var $createTextNode2 = mod.$createTextNode; 19575 var $extendCaretToRange2 = mod.$extendCaretToRange; 19576 var $findMatchingParent2 = mod.$findMatchingParent; 19577 var $getAdjacentChildCaret2 = mod.$getAdjacentChildCaret; 19578 var $getAdjacentNode2 = mod.$getAdjacentNode; 19579 var $getAdjacentSiblingOrParentSiblingCaret2 = mod.$getAdjacentSiblingOrParentSiblingCaret; 19580 var $getCaretInDirection2 = mod.$getCaretInDirection; 19581 var $getCaretRange2 = mod.$getCaretRange; 19582 var $getCaretRangeInDirection2 = mod.$getCaretRangeInDirection; 19583 var $getCharacterOffsets2 = mod.$getCharacterOffsets; 19584 var $getChildCaret2 = mod.$getChildCaret; 19585 var $getChildCaretAtIndex2 = mod.$getChildCaretAtIndex; 19586 var $getChildCaretOrSelf2 = mod.$getChildCaretOrSelf; 19587 var $getCollapsedCaretRange2 = mod.$getCollapsedCaretRange; 19588 var $getCommonAncestor2 = mod.$getCommonAncestor; 19589 var $getCommonAncestorResultBranchOrder2 = mod.$getCommonAncestorResultBranchOrder; 19590 var $getEditor2 = mod.$getEditor; 19591 var $getEditorDOMRenderConfig2 = mod.$getEditorDOMRenderConfig; 19592 var $getNearestNodeFromDOMNode2 = mod.$getNearestNodeFromDOMNode; 19593 var $getNearestRootOrShadowRoot2 = mod.$getNearestRootOrShadowRoot; 19594 var $getNodeByKey2 = mod.$getNodeByKey; 19595 var $getNodeByKeyOrThrow2 = mod.$getNodeByKeyOrThrow; 19596 var $getNodeFromDOMNode2 = mod.$getNodeFromDOMNode; 19597 var $getPreviousSelection2 = mod.$getPreviousSelection; 19598 var $getRoot2 = mod.$getRoot; 19599 var $getSelection2 = mod.$getSelection; 19600 var $getSiblingCaret2 = mod.$getSiblingCaret; 19601 var $getState2 = mod.$getState; 19602 var $getStateChange2 = mod.$getStateChange; 19603 var $getTextContent2 = mod.$getTextContent; 19604 var $getTextNodeOffset2 = mod.$getTextNodeOffset; 19605 var $getTextPointCaret2 = mod.$getTextPointCaret; 19606 var $getTextPointCaretSlice2 = mod.$getTextPointCaretSlice; 19607 var $getWritableNodeState2 = mod.$getWritableNodeState; 19608 var $hasAncestor2 = mod.$hasAncestor; 19609 var $hasUpdateTag2 = mod.$hasUpdateTag; 19610 var $insertNodes2 = mod.$insertNodes; 19611 var $isBlockElementNode2 = mod.$isBlockElementNode; 19612 var $isChildCaret2 = mod.$isChildCaret; 19613 var $isDecoratorNode2 = mod.$isDecoratorNode; 19614 var $isEditorState2 = mod.$isEditorState; 19615 var $isElementNode2 = mod.$isElementNode; 19616 var $isExtendableTextPointCaret2 = mod.$isExtendableTextPointCaret; 19617 var $isInlineElementOrDecoratorNode2 = mod.$isInlineElementOrDecoratorNode; 19618 var $isLeafNode2 = mod.$isLeafNode; 19619 var $isLexicalNode2 = mod.$isLexicalNode; 19620 var $isLineBreakNode2 = mod.$isLineBreakNode; 19621 var $isNodeCaret2 = mod.$isNodeCaret; 19622 var $isNodeSelection2 = mod.$isNodeSelection; 19623 var $isParagraphNode2 = mod.$isParagraphNode; 19624 var $isRangeSelection2 = mod.$isRangeSelection; 19625 var $isRootNode2 = mod.$isRootNode; 19626 var $isRootOrShadowRoot2 = mod.$isRootOrShadowRoot; 19627 var $isSiblingCaret2 = mod.$isSiblingCaret; 19628 var $isTabNode2 = mod.$isTabNode; 19629 var $isTextNode2 = mod.$isTextNode; 19630 var $isTextPointCaret2 = mod.$isTextPointCaret; 19631 var $isTextPointCaretSlice2 = mod.$isTextPointCaretSlice; 19632 var $isTokenOrSegmented2 = mod.$isTokenOrSegmented; 19633 var $isTokenOrTab2 = mod.$isTokenOrTab; 19634 var $nodesOfType2 = mod.$nodesOfType; 19635 var $normalizeCaret2 = mod.$normalizeCaret; 19636 var $normalizeSelection__EXPERIMENTAL = mod.$normalizeSelection__EXPERIMENTAL; 19637 var $onUpdate2 = mod.$onUpdate; 19638 var $parseSerializedNode2 = mod.$parseSerializedNode; 19639 var $removeTextFromCaretRange2 = mod.$removeTextFromCaretRange; 19640 var $rewindSiblingCaret2 = mod.$rewindSiblingCaret; 19641 var $selectAll2 = mod.$selectAll; 19642 var $setCompositionKey2 = mod.$setCompositionKey; 19643 var $setPointFromCaret2 = mod.$setPointFromCaret; 19644 var $setSelection2 = mod.$setSelection; 19645 var $setSelectionFromCaretRange2 = mod.$setSelectionFromCaretRange; 19646 var $setState2 = mod.$setState; 19647 var $splitAtPointCaretNext2 = mod.$splitAtPointCaretNext; 19648 var $splitNode2 = mod.$splitNode; 19649 var $updateRangeSelectionFromCaretRange2 = mod.$updateRangeSelectionFromCaretRange; 19650 var ArtificialNode__DO_NOT_USE2 = mod.ArtificialNode__DO_NOT_USE; 19651 var BEFORE_INPUT_COMMAND2 = mod.BEFORE_INPUT_COMMAND; 19652 var BLUR_COMMAND2 = mod.BLUR_COMMAND; 19653 var CAN_REDO_COMMAND2 = mod.CAN_REDO_COMMAND; 19654 var CAN_UNDO_COMMAND2 = mod.CAN_UNDO_COMMAND; 19655 var CLEAR_EDITOR_COMMAND2 = mod.CLEAR_EDITOR_COMMAND; 19656 var CLEAR_HISTORY_COMMAND2 = mod.CLEAR_HISTORY_COMMAND; 19657 var CLICK_COMMAND2 = mod.CLICK_COMMAND; 19658 var COLLABORATION_TAG2 = mod.COLLABORATION_TAG; 19659 var COMMAND_PRIORITY_BEFORE_CRITICAL2 = mod.COMMAND_PRIORITY_BEFORE_CRITICAL; 19660 var COMMAND_PRIORITY_BEFORE_EDITOR2 = mod.COMMAND_PRIORITY_BEFORE_EDITOR; 19661 var COMMAND_PRIORITY_BEFORE_HIGH2 = mod.COMMAND_PRIORITY_BEFORE_HIGH; 19662 var COMMAND_PRIORITY_BEFORE_LOW2 = mod.COMMAND_PRIORITY_BEFORE_LOW; 19663 var COMMAND_PRIORITY_BEFORE_NORMAL2 = mod.COMMAND_PRIORITY_BEFORE_NORMAL; 19664 var COMMAND_PRIORITY_CRITICAL2 = mod.COMMAND_PRIORITY_CRITICAL; 19665 var COMMAND_PRIORITY_EDITOR2 = mod.COMMAND_PRIORITY_EDITOR; 19666 var COMMAND_PRIORITY_HIGH2 = mod.COMMAND_PRIORITY_HIGH; 19667 var COMMAND_PRIORITY_LOW2 = mod.COMMAND_PRIORITY_LOW; 19668 var COMMAND_PRIORITY_NORMAL2 = mod.COMMAND_PRIORITY_NORMAL; 19669 var COMPOSITION_END_COMMAND2 = mod.COMPOSITION_END_COMMAND; 19670 var COMPOSITION_END_TAG2 = mod.COMPOSITION_END_TAG; 19671 var COMPOSITION_START_COMMAND2 = mod.COMPOSITION_START_COMMAND; 19672 var COMPOSITION_START_TAG2 = mod.COMPOSITION_START_TAG; 19673 var CONTROLLED_TEXT_INSERTION_COMMAND2 = mod.CONTROLLED_TEXT_INSERTION_COMMAND; 19674 var COPY_COMMAND2 = mod.COPY_COMMAND; 19675 var CUT_COMMAND2 = mod.CUT_COMMAND; 19676 var DEFAULT_EDITOR_DOM_CONFIG2 = mod.DEFAULT_EDITOR_DOM_CONFIG; 19677 var DELETE_CHARACTER_COMMAND2 = mod.DELETE_CHARACTER_COMMAND; 19678 var DELETE_LINE_COMMAND2 = mod.DELETE_LINE_COMMAND; 19679 var DELETE_WORD_COMMAND2 = mod.DELETE_WORD_COMMAND; 19680 var DRAGEND_COMMAND2 = mod.DRAGEND_COMMAND; 19681 var DRAGOVER_COMMAND2 = mod.DRAGOVER_COMMAND; 19682 var DRAGSTART_COMMAND2 = mod.DRAGSTART_COMMAND; 19683 var DROP_COMMAND2 = mod.DROP_COMMAND; 19684 var DecoratorNode2 = mod.DecoratorNode; 19685 var ElementNode2 = mod.ElementNode; 19686 var FOCUS_COMMAND2 = mod.FOCUS_COMMAND; 19687 var FORMAT_ELEMENT_COMMAND2 = mod.FORMAT_ELEMENT_COMMAND; 19688 var FORMAT_TEXT_COMMAND2 = mod.FORMAT_TEXT_COMMAND; 19689 var HISTORIC_TAG2 = mod.HISTORIC_TAG; 19690 var HISTORY_MERGE_TAG2 = mod.HISTORY_MERGE_TAG; 19691 var HISTORY_PUSH_TAG2 = mod.HISTORY_PUSH_TAG; 19692 var INDENT_CONTENT_COMMAND2 = mod.INDENT_CONTENT_COMMAND; 19693 var INPUT_COMMAND2 = mod.INPUT_COMMAND; 19694 var INSERT_LINE_BREAK_COMMAND2 = mod.INSERT_LINE_BREAK_COMMAND; 19695 var INSERT_PARAGRAPH_COMMAND2 = mod.INSERT_PARAGRAPH_COMMAND; 19696 var INSERT_TAB_COMMAND2 = mod.INSERT_TAB_COMMAND; 19697 var INTERNAL_$isBlock2 = mod.INTERNAL_$isBlock; 19698 var IS_ALL_FORMATTING2 = mod.IS_ALL_FORMATTING; 19699 var IS_BOLD2 = mod.IS_BOLD; 19700 var IS_CODE2 = mod.IS_CODE; 19701 var IS_HIGHLIGHT2 = mod.IS_HIGHLIGHT; 19702 var IS_ITALIC2 = mod.IS_ITALIC; 19703 var IS_STRIKETHROUGH2 = mod.IS_STRIKETHROUGH; 19704 var IS_SUBSCRIPT2 = mod.IS_SUBSCRIPT; 19705 var IS_SUPERSCRIPT2 = mod.IS_SUPERSCRIPT; 19706 var IS_UNDERLINE2 = mod.IS_UNDERLINE; 19707 var KEY_ARROW_DOWN_COMMAND2 = mod.KEY_ARROW_DOWN_COMMAND; 19708 var KEY_ARROW_LEFT_COMMAND2 = mod.KEY_ARROW_LEFT_COMMAND; 19709 var KEY_ARROW_RIGHT_COMMAND2 = mod.KEY_ARROW_RIGHT_COMMAND; 19710 var KEY_ARROW_UP_COMMAND2 = mod.KEY_ARROW_UP_COMMAND; 19711 var KEY_BACKSPACE_COMMAND2 = mod.KEY_BACKSPACE_COMMAND; 19712 var KEY_DELETE_COMMAND2 = mod.KEY_DELETE_COMMAND; 19713 var KEY_DOWN_COMMAND2 = mod.KEY_DOWN_COMMAND; 19714 var KEY_ENTER_COMMAND2 = mod.KEY_ENTER_COMMAND; 19715 var KEY_ESCAPE_COMMAND2 = mod.KEY_ESCAPE_COMMAND; 19716 var KEY_MODIFIER_COMMAND2 = mod.KEY_MODIFIER_COMMAND; 19717 var KEY_SPACE_COMMAND2 = mod.KEY_SPACE_COMMAND; 19718 var KEY_TAB_COMMAND2 = mod.KEY_TAB_COMMAND; 19719 var LineBreakNode2 = mod.LineBreakNode; 19720 var MOVE_TO_END2 = mod.MOVE_TO_END; 19721 var MOVE_TO_START2 = mod.MOVE_TO_START; 19722 var NODE_STATE_KEY2 = mod.NODE_STATE_KEY; 19723 var OUTDENT_CONTENT_COMMAND2 = mod.OUTDENT_CONTENT_COMMAND; 19724 var PASTE_COMMAND2 = mod.PASTE_COMMAND; 19725 var PASTE_TAG2 = mod.PASTE_TAG; 19726 var ParagraphNode2 = mod.ParagraphNode; 19727 var REDO_COMMAND2 = mod.REDO_COMMAND; 19728 var REMOVE_TEXT_COMMAND2 = mod.REMOVE_TEXT_COMMAND; 19729 var RootNode2 = mod.RootNode; 19730 var SELECTION_CHANGE_COMMAND2 = mod.SELECTION_CHANGE_COMMAND; 19731 var SELECTION_INSERT_CLIPBOARD_NODES_COMMAND2 = mod.SELECTION_INSERT_CLIPBOARD_NODES_COMMAND; 19732 var SELECT_ALL_COMMAND2 = mod.SELECT_ALL_COMMAND; 19733 var SKIP_COLLAB_TAG2 = mod.SKIP_COLLAB_TAG; 19734 var SKIP_DOM_SELECTION_TAG2 = mod.SKIP_DOM_SELECTION_TAG; 19735 var SKIP_SCROLL_INTO_VIEW_TAG2 = mod.SKIP_SCROLL_INTO_VIEW_TAG; 19736 var SKIP_SELECTION_FOCUS_TAG2 = mod.SKIP_SELECTION_FOCUS_TAG; 19737 var TEXT_TYPE_TO_FORMAT2 = mod.TEXT_TYPE_TO_FORMAT; 19738 var TabNode2 = mod.TabNode; 19739 var TextNode2 = mod.TextNode; 19740 var UNDO_COMMAND2 = mod.UNDO_COMMAND; 19741 var addClassNamesToElement2 = mod.addClassNamesToElement; 19742 var buildImportMap2 = mod.buildImportMap; 19743 var configExtension2 = mod.configExtension; 19744 var createCommand2 = mod.createCommand; 19745 var createEditor2 = mod.createEditor; 19746 var createSharedNodeState2 = mod.createSharedNodeState; 19747 var createState2 = mod.createState; 19748 var declarePeerDependency2 = mod.declarePeerDependency; 19749 var defineExtension2 = mod.defineExtension; 19750 var flipDirection2 = mod.flipDirection; 19751 var getDOMOwnerDocument2 = mod.getDOMOwnerDocument; 19752 var getDOMSelection2 = mod.getDOMSelection; 19753 var getDOMSelectionFromTarget2 = mod.getDOMSelectionFromTarget; 19754 var getDOMTextNode2 = mod.getDOMTextNode; 19755 var getEditorPropertyFromDOMNode2 = mod.getEditorPropertyFromDOMNode; 19756 var getNearestEditorFromDOMNode2 = mod.getNearestEditorFromDOMNode; 19757 var getRegisteredNode2 = mod.getRegisteredNode; 19758 var getRegisteredNodeOrThrow2 = mod.getRegisteredNodeOrThrow; 19759 var getStaticNodeConfig2 = mod.getStaticNodeConfig; 19760 var getStyleObjectFromCSS2 = mod.getStyleObjectFromCSS; 19761 var getTextDirection2 = mod.getTextDirection; 19762 var getTransformSetFromKlass2 = mod.getTransformSetFromKlass; 19763 var isBlockDomNode2 = mod.isBlockDomNode; 19764 var isCurrentlyReadOnlyMode2 = mod.isCurrentlyReadOnlyMode; 19765 var isDOMDocumentNode2 = mod.isDOMDocumentNode; 19766 var isDOMNode2 = mod.isDOMNode; 19767 var isDOMTextNode2 = mod.isDOMTextNode; 19768 var isDOMUnmanaged2 = mod.isDOMUnmanaged; 19769 var isDocumentFragment2 = mod.isDocumentFragment; 19770 var isExactShortcutMatch2 = mod.isExactShortcutMatch; 19771 var isHTMLAnchorElement2 = mod.isHTMLAnchorElement; 19772 var isHTMLElement2 = mod.isHTMLElement; 19773 var isInlineDomNode2 = mod.isInlineDomNode; 19774 var isLexicalEditor2 = mod.isLexicalEditor; 19775 var isModifierMatch2 = mod.isModifierMatch; 19776 var isSelectionCapturedInDecoratorInput2 = mod.isSelectionCapturedInDecoratorInput; 19777 var isSelectionWithinEditor2 = mod.isSelectionWithinEditor; 19778 var makeStepwiseIterator2 = mod.makeStepwiseIterator; 19779 var mergeRegister2 = mod.mergeRegister; 19780 var normalizeClassNames2 = mod.normalizeClassNames; 19781 var removeClassNamesFromElement2 = mod.removeClassNamesFromElement; 19782 var removeFromParent2 = mod.removeFromParent; 19783 var resetRandomKey2 = mod.resetRandomKey; 19784 var safeCast2 = mod.safeCast; 19785 var setDOMStyleFromCSS2 = mod.setDOMStyleFromCSS; 19786 var setDOMStyleObject2 = mod.setDOMStyleObject; 19787 var setDOMUnmanaged2 = mod.setDOMUnmanaged; 19788 var setNodeIndentFromDOM2 = mod.setNodeIndentFromDOM; 19789 var shallowMergeConfig2 = mod.shallowMergeConfig; 19790 var toggleTextFormatType2 = mod.toggleTextFormatType; 19791 19792
vendor: 26,913 bytes, lines 19792-20507
19792// node_modules/@lexical/selection/LexicalSelection.dev.mjs 19793 function formatDevErrorMessage2(message) { 19794 throw new Error(message); 19795 } 19796 function warnOnlyOnce2(message) { 19797 { 19798 let run = false; 19799 return () => { 19800 if (!run) { 19801 console.warn(message); 19802 } 19803 run = true; 19804 }; 19805 } 19806 } 19807 function getDOMTextNode3(element) { 19808 let node = element; 19809 while (node != null) { 19810 if (node.nodeType === Node.TEXT_NODE) { 19811 return node; 19812 } 19813 node = node.firstChild; 19814 } 19815 return null; 19816 } 19817 function getDOMIndexWithinParent(node) { 19818 const parent = node.parentNode; 19819 if (parent == null) { 19820 throw new Error("Should never happen"); 19821 } 19822 return [parent, Array.from(parent.childNodes).indexOf(node)]; 19823 } 19824 function createDOMRange(editor, anchorNode, _anchorOffset, focusNode, _focusOffset) { 19825 const anchorKey = anchorNode.getKey(); 19826 const focusKey = focusNode.getKey(); 19827 const range2 = document.createRange(); 19828 let anchorDOM = editor.getElementByKey(anchorKey); 19829 let focusDOM = editor.getElementByKey(focusKey); 19830 let anchorOffset = _anchorOffset; 19831 let focusOffset = _focusOffset; 19832 if ($isTextNode2(anchorNode)) { 19833 anchorDOM = getDOMTextNode3(anchorDOM); 19834 } 19835 if ($isTextNode2(focusNode)) { 19836 focusDOM = getDOMTextNode3(focusDOM); 19837 } 19838 if (anchorNode === void 0 || focusNode === void 0 || anchorDOM === null || focusDOM === null) { 19839 return null; 19840 } 19841 if (anchorDOM.nodeName === "BR") { 19842 [anchorDOM, anchorOffset] = getDOMIndexWithinParent(anchorDOM); 19843 } 19844 if (focusDOM.nodeName === "BR") { 19845 [focusDOM, focusOffset] = getDOMIndexWithinParent(focusDOM); 19846 } 19847 const firstChild = anchorDOM.firstChild; 19848 if (anchorDOM === focusDOM && firstChild != null && firstChild.nodeName === "BR" && anchorOffset === 0 && focusOffset === 0) { 19849 focusOffset = 1; 19850 } 19851 try { 19852 range2.setStart(anchorDOM, anchorOffset); 19853 range2.setEnd(focusDOM, focusOffset); 19854 } catch (_e2) { 19855 return null; 19856 } 19857 if (range2.collapsed && (anchorOffset !== focusOffset || anchorKey !== focusKey)) { 19858 range2.setStart(focusDOM, focusOffset); 19859 range2.setEnd(anchorDOM, anchorOffset); 19860 } 19861 return range2; 19862 } 19863 function createRectsFromDOMRange(editor, range2) { 19864 const rootElement = editor.getRootElement(); 19865 if (rootElement === null) { 19866 return []; 19867 } 19868 const rootRect = rootElement.getBoundingClientRect(); 19869 const computedStyle = getComputedStyle(rootElement); 19870 const rootPadding = parseFloat(computedStyle.paddingLeft) + parseFloat(computedStyle.paddingRight); 19871 const selectionRects = Array.from(range2.getClientRects()); 19872 let selectionRectsLength = selectionRects.length; 19873 selectionRects.sort((a2, b3) => { 19874 const top = a2.top - b3.top; 19875 if (Math.abs(top) <= 3) { 19876 return a2.left - b3.left; 19877 } 19878 return top; 19879 }); 19880 let prevRect; 19881 for (let i2 = 0; i2 < selectionRectsLength; i2++) { 19882 const selectionRect = selectionRects[i2]; 19883 const isOverlappingRect = prevRect && prevRect.top <= selectionRect.top && prevRect.top + prevRect.height > selectionRect.top && prevRect.left + prevRect.width > selectionRect.left; 19884 const selectionSpansElement = selectionRect.width + rootPadding === rootRect.width; 19885 if (isOverlappingRect || selectionSpansElement) { 19886 selectionRects.splice(i2--, 1); 19887 selectionRectsLength--; 19888 continue; 19889 } 19890 prevRect = selectionRect; 19891 } 19892 return selectionRects; 19893 } 19894 function getCSSFromStyleObject(styles) { 19895 let css = ""; 19896 for (const style in styles) { 19897 if (style) { 19898 css += `${style}: ${styles[style]};`; 19899 } 19900 } 19901 return css; 19902 } 19903 function $getComputedStyleForElement(element) { 19904 const editor = $getEditor2(); 19905 const domElement = editor.getElementByKey(element.getKey()); 19906 if (domElement === null) { 19907 return null; 19908 } 19909 const view = domElement.ownerDocument.defaultView; 19910 if (view === null) { 19911 return null; 19912 } 19913 return view.getComputedStyle(domElement); 19914 } 19915 function $getComputedStyleForParent(node) { 19916 const parent = $isRootNode2(node) ? node : node.getParentOrThrow(); 19917 return $getComputedStyleForElement(parent); 19918 } 19919 function $isParentRTL(node) { 19920 const styles = $getComputedStyleForParent(node); 19921 return styles !== null && styles.direction === "rtl"; 19922 } 19923 function $sliceSelectedTextNodeContent(selection, textNode, mutates = "self") { 19924 const anchorAndFocus = selection.getStartEndPoints(); 19925 if (textNode.isSelected(selection) && !$isTokenOrSegmented2(textNode) && anchorAndFocus !== null) { 19926 const [anchor, focus] = anchorAndFocus; 19927 const isBackward = selection.isBackward(); 19928 const anchorNode = anchor.getNode(); 19929 const focusNode = focus.getNode(); 19930 const isAnchor = textNode.is(anchorNode); 19931 const isFocus = textNode.is(focusNode); 19932 if (isAnchor || isFocus) { 19933 const [anchorOffset, focusOffset] = $getCharacterOffsets2(selection); 19934 const isSame = anchorNode.is(focusNode); 19935 const isFirst = textNode.is(isBackward ? focusNode : anchorNode); 19936 const isLast = textNode.is(isBackward ? anchorNode : focusNode); 19937 let startOffset = 0; 19938 let endOffset = void 0; 19939 if (isSame) { 19940 startOffset = anchorOffset > focusOffset ? focusOffset : anchorOffset; 19941 endOffset = anchorOffset > focusOffset ? anchorOffset : focusOffset; 19942 } else if (isFirst) { 19943 const offset3 = isBackward ? focusOffset : anchorOffset; 19944 startOffset = offset3; 19945 endOffset = void 0; 19946 } else if (isLast) { 19947 const offset3 = isBackward ? anchorOffset : focusOffset; 19948 startOffset = 0; 19949 endOffset = offset3; 19950 } 19951 const text2 = textNode.__text.slice(startOffset, endOffset); 19952 if (text2 !== textNode.__text) { 19953 if (mutates === "clone") { 19954 textNode = $cloneWithPropertiesEphemeral2(textNode); 19955 } 19956 textNode.__text = text2; 19957 } 19958 } 19959 } 19960 return textNode; 19961 } 19962 function $isAtNodeEnd(point) { 19963 if (point.type === "text") { 19964 return point.offset === point.getNode().getTextContentSize(); 19965 } 19966 const node = point.getNode(); 19967 if (!$isElementNode2(node)) { 19968 formatDevErrorMessage2(`isAtNodeEnd: node must be a TextNode or ElementNode`); 19969 } 19970 return point.offset === node.getChildrenSize(); 19971 } 19972 function $trimTextContentFromAnchor(editor, anchor, delCount) { 19973 let currentNode = anchor.getNode(); 19974 let remaining = delCount; 19975 if ($isElementNode2(currentNode)) { 19976 const descendantNode = currentNode.getDescendantByIndex(anchor.offset); 19977 if (descendantNode !== null) { 19978 currentNode = descendantNode; 19979 } 19980 } 19981 while (remaining > 0 && currentNode !== null) { 19982 if ($isElementNode2(currentNode)) { 19983 const lastDescendant = currentNode.getLastDescendant(); 19984 if (lastDescendant !== null) { 19985 currentNode = lastDescendant; 19986 } 19987 } 19988 let nextNode = currentNode.getPreviousSibling(); 19989 let additionalElementWhitespace = 0; 19990 if (nextNode === null) { 19991 let parent = currentNode.getParentOrThrow(); 19992 let parentSibling = parent.getPreviousSibling(); 19993 while (parentSibling === null) { 19994 parent = parent.getParent(); 19995 if (parent === null) { 19996 nextNode = null; 19997 break; 19998 } 19999 parentSibling = parent.getPreviousSibling(); 20000 } 20001 if (parent !== null) { 20002 additionalElementWhitespace = parent.isInline() ? 0 : 2; 20003 nextNode = parentSibling; 20004 } 20005 } 20006 let text2 = currentNode.getTextContent(); 20007 if (text2 === "" && $isElementNode2(currentNode) && !currentNode.isInline()) { 20008 text2 = "\n\n"; 20009 } 20010 const currentNodeSize = text2.length; 20011 if (!$isTextNode2(currentNode) || remaining >= currentNodeSize) { 20012 const parent = currentNode.getParent(); 20013 currentNode.remove(); 20014 if (parent != null && parent.getChildrenSize() === 0 && !$isRootNode2(parent)) { 20015 parent.remove(); 20016 } 20017 remaining -= currentNodeSize + additionalElementWhitespace; 20018 currentNode = nextNode; 20019 } else { 20020 const key = currentNode.getKey(); 20021 const prevTextContent = editor.getEditorState().read(() => { 20022 const prevNode = $getNodeByKey2(key); 20023 if ($isTextNode2(prevNode) && prevNode.isSimpleText()) { 20024 return prevNode.getTextContent(); 20025 } 20026 return null; 20027 }); 20028 const offset3 = currentNodeSize - remaining; 20029 const slicedText = text2.slice(0, offset3); 20030 if (prevTextContent !== null && prevTextContent !== text2) { 20031 const prevSelection = $getPreviousSelection2(); 20032 let target = currentNode; 20033 if (!currentNode.isSimpleText()) { 20034 const textNode = $createTextNode2(prevTextContent); 20035 currentNode.replace(textNode); 20036 target = textNode; 20037 } else { 20038 currentNode.setTextContent(prevTextContent); 20039 } 20040 if ($isRangeSelection2(prevSelection) && prevSelection.isCollapsed()) { 20041 const prevOffset = prevSelection.anchor.offset; 20042 target.select(prevOffset, prevOffset); 20043 } 20044 } else if (currentNode.isSimpleText()) { 20045 const isSelected = anchor.key === key; 20046 let anchorOffset = anchor.offset; 20047 if (anchorOffset < remaining) { 20048 anchorOffset = currentNodeSize; 20049 } 20050 const splitStart = isSelected ? anchorOffset - remaining : 0; 20051 const splitEnd = isSelected ? anchorOffset : offset3; 20052 if (isSelected && splitStart === 0) { 20053 const [excessNode] = currentNode.splitText(splitStart, splitEnd); 20054 excessNode.remove(); 20055 } else { 20056 const [, excessNode] = currentNode.splitText(splitStart, splitEnd); 20057 excessNode.remove(); 20058 } 20059 } else { 20060 const textNode = $createTextNode2(slicedText); 20061 currentNode.replace(textNode); 20062 } 20063 remaining = 0; 20064 } 20065 } 20066 } 20067 var $addNodeStyle = warnOnlyOnce2("$addNodeStyle is a deprecated no-op and calls should be removed"); 20068 function $patchStyle(target, patch2) { 20069 if (!($isRangeSelection2(target) ? target.isCollapsed() : $isTextNode2(target) || $isElementNode2(target))) { 20070 formatDevErrorMessage2(`$patchStyle must only be called with a TextNode, ElementNode, or collapsed RangeSelection`); 20071 } 20072 const prevStyles = getStyleObjectFromCSS2($isRangeSelection2(target) ? target.style : $isTextNode2(target) ? target.getStyle() : target.getTextStyle()); 20073 const newStyles = Object.entries(patch2).reduce((styles, [key, value]) => { 20074 if (typeof value === "function") { 20075 styles[key] = value(prevStyles[key], target); 20076 } else if (value === null) { 20077 delete styles[key]; 20078 } else { 20079 styles[key] = value; 20080 } 20081 return styles; 20082 }, { 20083 ...prevStyles 20084 }); 20085 const newCSSText = getCSSFromStyleObject(newStyles); 20086 if ($isRangeSelection2(target) || $isTextNode2(target)) { 20087 target.setStyle(newCSSText); 20088 } else { 20089 target.setTextStyle(newCSSText); 20090 } 20091 } 20092 function $patchStyleText(selection, patch2) { 20093 if ($isRangeSelection2(selection) && selection.isCollapsed()) { 20094 $patchStyle(selection, patch2); 20095 const emptyNode = selection.anchor.getNode(); 20096 if ($isElementNode2(emptyNode) && emptyNode.isEmpty()) { 20097 $patchStyle(emptyNode, patch2); 20098 } 20099 } 20100 $forEachSelectedTextNode((textNode) => { 20101 $patchStyle(textNode, patch2); 20102 }); 20103 const nodes = selection.getNodes(); 20104 if (nodes.length > 0) { 20105 const patchedElementKeys = /* @__PURE__ */ new Set(); 20106 for (const node of nodes) { 20107 if (!$isElementNode2(node) || !node.canBeEmpty() || node.getChildrenSize() !== 0) { 20108 continue; 20109 } 20110 const key = node.getKey(); 20111 if (patchedElementKeys.has(key)) { 20112 continue; 20113 } 20114 patchedElementKeys.add(key); 20115 $patchStyle(node, patch2); 20116 } 20117 } 20118 } 20119 function $forEachSelectedTextNode(fn) { 20120 const selection = $getSelection2(); 20121 if (!selection) { 20122 return; 20123 } 20124 const slicedTextNodes = /* @__PURE__ */ new Map(); 20125 const getSliceIndices = (node) => slicedTextNodes.get(node.getKey()) || [0, node.getTextContentSize()]; 20126 if ($isRangeSelection2(selection)) { 20127 for (const slice of $caretRangeFromSelection2(selection).getTextSlices()) { 20128 if (slice) { 20129 slicedTextNodes.set(slice.caret.origin.getKey(), slice.getSliceIndices()); 20130 } 20131 } 20132 } 20133 const selectedNodes = selection.getNodes(); 20134 for (const selectedNode of selectedNodes) { 20135 if (!($isTextNode2(selectedNode) && selectedNode.canHaveFormat())) { 20136 continue; 20137 } 20138 const [startOffset, endOffset] = getSliceIndices(selectedNode); 20139 if (endOffset === startOffset) { 20140 continue; 20141 } 20142 if ($isTokenOrSegmented2(selectedNode) || startOffset === 0 && endOffset === selectedNode.getTextContentSize()) { 20143 fn(selectedNode); 20144 } else { 20145 const splitNodes = selectedNode.splitText(startOffset, endOffset); 20146 const replacement = splitNodes[startOffset === 0 ? 0 : 1]; 20147 fn(replacement); 20148 } 20149 } 20150 if ($isRangeSelection2(selection) && selection.anchor.type === "text" && selection.focus.type === "text" && selection.anchor.key === selection.focus.key) { 20151 $ensureForwardRangeSelection(selection); 20152 } 20153 } 20154 function $ensureForwardRangeSelection(selection) { 20155 if (selection.isBackward()) { 20156 const { 20157 anchor, 20158 focus 20159 } = selection; 20160 const { 20161 key, 20162 offset: offset3, 20163 type 20164 } = anchor; 20165 anchor.set(focus.key, focus.offset, focus.type); 20166 focus.set(key, offset3, type); 20167 } 20168 } 20169 function $copyBlockFormatIndent(srcNode, destNode) { 20170 const format = srcNode.getFormatType(); 20171 const indent = srcNode.getIndent(); 20172 if (format !== destNode.getFormatType()) { 20173 destNode.setFormat(format); 20174 } 20175 if (indent !== destNode.getIndent()) { 20176 destNode.setIndent(indent); 20177 } 20178 } 20179 function $setBlocksType(selection, $createElement, $afterCreateElement = $copyBlockFormatIndent) { 20180 if (selection === null) { 20181 return; 20182 } 20183 const anchorAndFocus = selection.getStartEndPoints(); 20184 const blockMap = /* @__PURE__ */ new Map(); 20185 let newSelection = null; 20186 if (anchorAndFocus) { 20187 const [anchor, focus] = anchorAndFocus; 20188 newSelection = $createRangeSelection2(); 20189 newSelection.anchor.set(anchor.key, anchor.offset, anchor.type); 20190 newSelection.focus.set(focus.key, focus.offset, focus.type); 20191 const anchorBlock = $findMatchingParent2(anchor.getNode(), INTERNAL_$isBlock2); 20192 const focusBlock = $findMatchingParent2(focus.getNode(), INTERNAL_$isBlock2); 20193 if ($isElementNode2(anchorBlock)) { 20194 blockMap.set(anchorBlock.getKey(), anchorBlock); 20195 } 20196 if ($isElementNode2(focusBlock)) { 20197 blockMap.set(focusBlock.getKey(), focusBlock); 20198 } 20199 } 20200 for (const node of selection.getNodes()) { 20201 if ($isElementNode2(node) && INTERNAL_$isBlock2(node)) { 20202 blockMap.set(node.getKey(), node); 20203 } else if (anchorAndFocus === null) { 20204 const ancestorBlock = $findMatchingParent2(node, INTERNAL_$isBlock2); 20205 if ($isElementNode2(ancestorBlock)) { 20206 blockMap.set(ancestorBlock.getKey(), ancestorBlock); 20207 } 20208 } 20209 } 20210 for (const [key, prevNode] of blockMap) { 20211 const element = $createElement(); 20212 $afterCreateElement(prevNode, element); 20213 prevNode.replace(element, true); 20214 if (newSelection) { 20215 if (key === newSelection.anchor.key) { 20216 newSelection.anchor.set(element.getKey(), newSelection.anchor.offset, newSelection.anchor.type); 20217 } 20218 if (key === newSelection.focus.key) { 20219 newSelection.focus.set(element.getKey(), newSelection.focus.offset, newSelection.focus.type); 20220 } 20221 } 20222 } 20223 if (newSelection && selection.is($getSelection2())) { 20224 $setSelection2(newSelection); 20225 } 20226 } 20227 function isPointAttached(point) { 20228 return point.getNode().isAttached(); 20229 } 20230 function $removeParentEmptyElements(startingNode) { 20231 let node = startingNode; 20232 while (node !== null && !$isRootOrShadowRoot2(node)) { 20233 const latest = node.getLatest(); 20234 const parentNode = node.getParent(); 20235 if (latest.getChildrenSize() === 0) { 20236 node.remove(true); 20237 } 20238 node = parentNode; 20239 } 20240 } 20241 function $wrapNodes(selection, createElement2, wrappingElement = null) { 20242 const anchorAndFocus = selection.getStartEndPoints(); 20243 const anchor = anchorAndFocus ? anchorAndFocus[0] : null; 20244 const nodes = selection.getNodes(); 20245 const nodesLength = nodes.length; 20246 if (anchor !== null && (nodesLength === 0 || nodesLength === 1 && anchor.type === "element" && anchor.getNode().getChildrenSize() === 0)) { 20247 const target = anchor.type === "text" ? anchor.getNode().getParentOrThrow() : anchor.getNode(); 20248 const children = target.getChildren(); 20249 let element = createElement2(); 20250 element.setFormat(target.getFormatType()); 20251 element.setIndent(target.getIndent()); 20252 children.forEach((child) => element.append(child)); 20253 if (wrappingElement) { 20254 element = wrappingElement.append(element); 20255 } 20256 target.replace(element); 20257 return; 20258 } 20259 let topLevelNode = null; 20260 let descendants = []; 20261 for (let i2 = 0; i2 < nodesLength; i2++) { 20262 const node = nodes[i2]; 20263 if ($isRootOrShadowRoot2(node)) { 20264 $wrapNodesImpl(selection, descendants, descendants.length, createElement2, wrappingElement); 20265 descendants = []; 20266 topLevelNode = node; 20267 } else if (topLevelNode === null || topLevelNode !== null && $hasAncestor2(node, topLevelNode)) { 20268 descendants.push(node); 20269 } else { 20270 $wrapNodesImpl(selection, descendants, descendants.length, createElement2, wrappingElement); 20271 descendants = [node]; 20272 } 20273 } 20274 $wrapNodesImpl(selection, descendants, descendants.length, createElement2, wrappingElement); 20275 } 20276 function $wrapNodesImpl(selection, nodes, nodesLength, createElement2, wrappingElement = null) { 20277 if (nodes.length === 0) { 20278 return; 20279 } 20280 const firstNode = nodes[0]; 20281 const elementMapping = /* @__PURE__ */ new Map(); 20282 const elements = []; 20283 let target = $isElementNode2(firstNode) ? firstNode : firstNode.getParentOrThrow(); 20284 if (target.isInline()) { 20285 target = target.getParentOrThrow(); 20286 } 20287 let targetIsPrevSibling = false; 20288 while (target !== null) { 20289 const prevSibling = target.getPreviousSibling(); 20290 if (prevSibling !== null) { 20291 target = prevSibling; 20292 targetIsPrevSibling = true; 20293 break; 20294 } 20295 target = target.getParentOrThrow(); 20296 if ($isRootOrShadowRoot2(target)) { 20297 break; 20298 } 20299 } 20300 const emptyElements = /* @__PURE__ */ new Set(); 20301 for (let i2 = 0; i2 < nodesLength; i2++) { 20302 const node = nodes[i2]; 20303 if ($isElementNode2(node) && node.getChildrenSize() === 0) { 20304 emptyElements.add(node.getKey()); 20305 } 20306 } 20307 const movedNodes = /* @__PURE__ */ new Set(); 20308 for (let i2 = 0; i2 < nodesLength; i2++) { 20309 const node = nodes[i2]; 20310 let parent = node.getParent(); 20311 if (parent !== null && parent.isInline()) { 20312 parent = parent.getParent(); 20313 } 20314 if (parent !== null && $isLeafNode2(node) && !movedNodes.has(node.getKey())) { 20315 const parentKey = parent.getKey(); 20316 if (elementMapping.get(parentKey) === void 0) { 20317 const targetElement = createElement2(); 20318 targetElement.setFormat(parent.getFormatType()); 20319 targetElement.setIndent(parent.getIndent()); 20320 elements.push(targetElement); 20321 elementMapping.set(parentKey, targetElement); 20322 parent.getChildren().forEach((child) => { 20323 targetElement.append(child); 20324 movedNodes.add(child.getKey()); 20325 if ($isElementNode2(child)) { 20326 child.getChildrenKeys().forEach((key) => movedNodes.add(key)); 20327 } 20328 }); 20329 $removeParentEmptyElements(parent); 20330 } 20331 } else if (emptyElements.has(node.getKey())) { 20332 if (!$isElementNode2(node)) { 20333 formatDevErrorMessage2(`Expected node in emptyElements to be an ElementNode`); 20334 } 20335 const targetElement = createElement2(); 20336 targetElement.setFormat(node.getFormatType()); 20337 targetElement.setIndent(node.getIndent()); 20338 elements.push(targetElement); 20339 node.remove(true); 20340 } 20341 } 20342 if (wrappingElement !== null) { 20343 for (let i2 = 0; i2 < elements.length; i2++) { 20344 const element = elements[i2]; 20345 wrappingElement.append(element); 20346 } 20347 } 20348 let lastElement = null; 20349 if ($isRootOrShadowRoot2(target)) { 20350 if (targetIsPrevSibling) { 20351 if (wrappingElement !== null) { 20352 target.insertAfter(wrappingElement); 20353 } else { 20354 for (let i2 = elements.length - 1; i2 >= 0; i2--) { 20355 const element = elements[i2]; 20356 target.insertAfter(element); 20357 } 20358 } 20359 } else { 20360 const firstChild = target.getFirstChild(); 20361 if ($isElementNode2(firstChild)) { 20362 target = firstChild; 20363 } 20364 if (firstChild === null) { 20365 if (wrappingElement) { 20366 target.append(wrappingElement); 20367 } else { 20368 for (let i2 = 0; i2 < elements.length; i2++) { 20369 const element = elements[i2]; 20370 target.append(element); 20371 lastElement = element; 20372 } 20373 } 20374 } else { 20375 if (wrappingElement !== null) { 20376 firstChild.insertBefore(wrappingElement); 20377 } else { 20378 for (let i2 = 0; i2 < elements.length; i2++) { 20379 const element = elements[i2]; 20380 firstChild.insertBefore(element); 20381 lastElement = element; 20382 } 20383 } 20384 } 20385 } 20386 } else { 20387 if (wrappingElement) { 20388 target.insertAfter(wrappingElement); 20389 } else { 20390 for (let i2 = elements.length - 1; i2 >= 0; i2--) { 20391 const element = elements[i2]; 20392 target.insertAfter(element); 20393 lastElement = element; 20394 } 20395 } 20396 } 20397 const prevSelection = $getPreviousSelection2(); 20398 if ($isRangeSelection2(prevSelection) && isPointAttached(prevSelection.anchor) && isPointAttached(prevSelection.focus)) { 20399 $setSelection2(prevSelection.clone()); 20400 } else if (lastElement !== null) { 20401 lastElement.selectEnd(); 20402 } else { 20403 selection.dirty = true; 20404 } 20405 } 20406 function $isEditorVerticalOrientation(selection) { 20407 const computedStyle = $getComputedStyle(selection); 20408 return computedStyle !== null && computedStyle.writingMode === "vertical-rl"; 20409 } 20410 function $getComputedStyle(selection) { 20411 const anchorNode = selection.anchor.getNode(); 20412 if ($isElementNode2(anchorNode)) { 20413 return $getComputedStyleForElement(anchorNode); 20414 } 20415 return $getComputedStyleForParent(anchorNode); 20416 } 20417 function $shouldOverrideDefaultCharacterSelection(selection, isBackward) { 20418 const isVertical = $isEditorVerticalOrientation(selection); 20419 let adjustedIsBackward = isVertical ? !isBackward : isBackward; 20420 if ($isParentElementRTL(selection)) { 20421 adjustedIsBackward = !adjustedIsBackward; 20422 } 20423 const focusCaret = $caretFromPoint2(selection.focus, adjustedIsBackward ? "previous" : "next"); 20424 if ($isExtendableTextPointCaret2(focusCaret)) { 20425 return false; 20426 } 20427 for (const nextCaret of $extendCaretToRange2(focusCaret)) { 20428 if ($isChildCaret2(nextCaret)) { 20429 return !nextCaret.origin.isInline(); 20430 } else if ($isElementNode2(nextCaret.origin)) { 20431 continue; 20432 } else if ($isDecoratorNode2(nextCaret.origin)) { 20433 return true; 20434 } 20435 break; 20436 } 20437 return false; 20438 } 20439 function $moveCaretSelection(selection, isHoldingShift, isBackward, granularity) { 20440 selection.modify(isHoldingShift ? "extend" : "move", isBackward, granularity); 20441 } 20442 function $isParentElementRTL(selection) { 20443 const computedStyle = $getComputedStyle(selection); 20444 return computedStyle !== null && computedStyle.direction === "rtl"; 20445 } 20446 function $moveCharacter(selection, isHoldingShift, isBackward) { 20447 const isRTL2 = $isParentElementRTL(selection); 20448 const isVertical = $isEditorVerticalOrientation(selection); 20449 let adjustedIsBackward; 20450 if (isVertical) { 20451 adjustedIsBackward = !isBackward; 20452 } else if (isRTL2) { 20453 adjustedIsBackward = !isBackward; 20454 } else { 20455 adjustedIsBackward = isBackward; 20456 } 20457 $moveCaretSelection(selection, isHoldingShift, adjustedIsBackward, "character"); 20458 } 20459 function $getNodeStyleValueForProperty(node, styleProperty, defaultValue) { 20460 const css = node.getStyle(); 20461 const styleObject = getStyleObjectFromCSS2(css); 20462 if (styleObject !== null) { 20463 return styleObject[styleProperty] || defaultValue; 20464 } 20465 return defaultValue; 20466 } 20467 function $getSelectionStyleValueForProperty(selection, styleProperty, defaultValue = "") { 20468 let styleValue = null; 20469 const nodes = selection.getNodes(); 20470 const anchor = selection.anchor; 20471 const focus = selection.focus; 20472 const isBackward = selection.isBackward(); 20473 const startNode = isBackward ? focus.getNode() : anchor.getNode(); 20474 const endNode = isBackward ? anchor.getNode() : focus.getNode(); 20475 const startOffset = isBackward ? focus.offset : anchor.offset; 20476 const endOffset = isBackward ? anchor.offset : focus.offset; 20477 if ($isRangeSelection2(selection) && selection.isCollapsed() && selection.style !== "") { 20478 const css = selection.style; 20479 const styleObject = getStyleObjectFromCSS2(css); 20480 if (styleObject !== null && styleProperty in styleObject) { 20481 return styleObject[styleProperty]; 20482 } 20483 } 20484 for (let i2 = 0; i2 < nodes.length; i2++) { 20485 const node = nodes[i2]; 20486 if (i2 === 0 && node.is(startNode) && $isTextNode2(node) && startOffset === node.getTextContentSize()) { 20487 continue; 20488 } 20489 if (i2 !== 0 && node.is(endNode) && endOffset === 0) { 20490 continue; 20491 } 20492 if ($isTextNode2(node)) { 20493 const nodeStyleValue = $getNodeStyleValueForProperty(node, styleProperty, defaultValue); 20494 if (styleValue === null) { 20495 styleValue = nodeStyleValue; 20496 } else if (styleValue !== nodeStyleValue) { 20497 styleValue = ""; 20498 break; 20499 } 20500 } 20501 } 20502 return styleValue === null ? defaultValue : styleValue; 20503 } 20504 var getStyleObjectFromCSS3 = getStyleObjectFromCSS2; 20505 var trimTextContentFromAnchor = $trimTextContentFromAnchor; 20506 20507
vendor: 1,602 bytes, lines 20507-20535
20507// node_modules/@lexical/selection/LexicalSelection.mjs 20508 var mod2 = true ? LexicalSelection_dev_exports : LexicalSelection_prod_exports; 20509 var $addNodeStyle2 = mod2.$addNodeStyle; 20510 var $cloneWithProperties3 = mod2.$cloneWithProperties; 20511 var $copyBlockFormatIndent2 = mod2.$copyBlockFormatIndent; 20512 var $ensureForwardRangeSelection2 = mod2.$ensureForwardRangeSelection; 20513 var $forEachSelectedTextNode2 = mod2.$forEachSelectedTextNode; 20514 var $getComputedStyleForElement2 = mod2.$getComputedStyleForElement; 20515 var $getComputedStyleForParent2 = mod2.$getComputedStyleForParent; 20516 var $getSelectionStyleValueForProperty2 = mod2.$getSelectionStyleValueForProperty; 20517 var $isAtNodeEnd2 = mod2.$isAtNodeEnd; 20518 var $isParentElementRTL2 = mod2.$isParentElementRTL; 20519 var $isParentRTL2 = mod2.$isParentRTL; 20520 var $moveCaretSelection2 = mod2.$moveCaretSelection; 20521 var $moveCharacter2 = mod2.$moveCharacter; 20522 var $patchStyleText2 = mod2.$patchStyleText; 20523 var $selectAll3 = mod2.$selectAll; 20524 var $setBlocksType2 = mod2.$setBlocksType; 20525 var $shouldOverrideDefaultCharacterSelection2 = mod2.$shouldOverrideDefaultCharacterSelection; 20526 var $sliceSelectedTextNodeContent2 = mod2.$sliceSelectedTextNodeContent; 20527 var $trimTextContentFromAnchor2 = mod2.$trimTextContentFromAnchor; 20528 var $wrapNodes2 = mod2.$wrapNodes; 20529 var createDOMRange2 = mod2.createDOMRange; 20530 var createRectsFromDOMRange2 = mod2.createRectsFromDOMRange; 20531 var getCSSFromStyleObject2 = mod2.getCSSFromStyleObject; 20532 var getStyleObjectFromCSS4 = mod2.getStyleObjectFromCSS; 20533 var trimTextContentFromAnchor2 = mod2.trimTextContentFromAnchor; 20534 20535
vendor: 884 bytes, lines 20535-20557
20535// node_modules/@lexical/link/LexicalLink.dev.mjs 20536 var LexicalLink_dev_exports = {}; 20537 __export(LexicalLink_dev_exports, { 20538 $createAutoLinkNode: () => $createAutoLinkNode, 20539 $createLinkNode: () => $createLinkNode, 20540 $isAutoLinkNode: () => $isAutoLinkNode, 20541 $isLinkNode: () => $isLinkNode, 20542 $toggleLink: () => $toggleLink, 20543 AutoLinkExtension: () => AutoLinkExtension, 20544 AutoLinkNode: () => AutoLinkNode, 20545 ClickableLinkExtension: () => ClickableLinkExtension, 20546 LinkExtension: () => LinkExtension, 20547 LinkNode: () => LinkNode, 20548 TOGGLE_LINK_COMMAND: () => TOGGLE_LINK_COMMAND, 20549 createLinkMatcherWithRegExp: () => createLinkMatcherWithRegExp, 20550 formatUrl: () => formatUrl, 20551 registerAutoLink: () => registerAutoLink, 20552 registerClickableLink: () => registerClickableLink, 20553 registerLink: () => registerLink, 20554 toggleLink: () => toggleLink 20555 }); 20556 20557
vendor: 28,232 bytes, lines 20557-21302
20557// node_modules/@lexical/utils/LexicalUtils.dev.mjs 20558 var LexicalUtils_dev_exports = {}; 20559 __export(LexicalUtils_dev_exports, { 20560 $descendantsMatching: () => $descendantsMatching, 20561 $dfs: () => $dfs, 20562 $dfsIterator: () => $dfsIterator, 20563 $filter: () => $filter, 20564 $findMatchingParent: () => $findMatchingParent2, 20565 $firstToLastIterator: () => $firstToLastIterator, 20566 $getAdjacentCaret: () => $getAdjacentCaret, 20567 $getAdjacentSiblingOrParentSiblingCaret: () => $getAdjacentSiblingOrParentSiblingCaret2, 20568 $getDepth: () => $getDepth, 20569 $getNearestBlockElementAncestorOrThrow: () => $getNearestBlockElementAncestorOrThrow, 20570 $getNearestNodeOfType: () => $getNearestNodeOfType, 20571 $getNextRightPreorderNode: () => $getNextRightPreorderNode, 20572 $getNextSiblingOrParentSibling: () => $getNextSiblingOrParentSibling, 20573 $handleIndentAndOutdent: () => $handleIndentAndOutdent, 20574 $insertFirst: () => $insertFirst, 20575 $insertNodeIntoLeaf: () => $insertNodeIntoLeaf, 20576 $insertNodeToNearestRoot: () => $insertNodeToNearestRoot, 20577 $insertNodeToNearestRootAtCaret: () => $insertNodeToNearestRootAtCaret, 20578 $isEditorIsNestedEditor: () => $isEditorIsNestedEditor, 20579 $lastToFirstIterator: () => $lastToFirstIterator, 20580 $restoreEditorState: () => $restoreEditorState, 20581 $reverseDfs: () => $reverseDfs, 20582 $reverseDfsIterator: () => $reverseDfsIterator, 20583 $splitNode: () => $splitNode2, 20584 $unwrapAndFilterDescendants: () => $unwrapAndFilterDescendants, 20585 $unwrapNode: () => $unwrapNode, 20586 $wrapNodeInElement: () => $wrapNodeInElement, 20587 CAN_USE_BEFORE_INPUT: () => CAN_USE_BEFORE_INPUT2, 20588 CAN_USE_DOM: () => CAN_USE_DOM2, 20589 IS_ANDROID: () => IS_ANDROID2, 20590 IS_ANDROID_CHROME: () => IS_ANDROID_CHROME2, 20591 IS_APPLE: () => IS_APPLE2, 20592 IS_APPLE_WEBKIT: () => IS_APPLE_WEBKIT2, 20593 IS_CHROME: () => IS_CHROME2, 20594 IS_FIREFOX: () => IS_FIREFOX2, 20595 IS_IOS: () => IS_IOS2, 20596 IS_SAFARI: () => IS_SAFARI2, 20597 addClassNamesToElement: () => addClassNamesToElement2, 20598 calculateZoomLevel: () => calculateZoomLevel, 20599 isBlockDomNode: () => isBlockDomNode2, 20600 isHTMLAnchorElement: () => isHTMLAnchorElement2, 20601 isHTMLElement: () => isHTMLElement2, 20602 isInlineDomNode: () => isInlineDomNode2, 20603 isMimeType: () => isMimeType, 20604 makeStateWrapper: () => makeStateWrapper, 20605 markSelection: () => markSelection, 20606 mediaFileReader: () => mediaFileReader, 20607 mergeRegister: () => mergeRegister2, 20608 objectKlassEquals: () => objectKlassEquals, 20609 positionNodeOnRange: () => mlcPositionNodeOnRange, 20610 registerNestedElementResolver: () => registerNestedElementResolver, 20611 removeClassNamesFromElement: () => removeClassNamesFromElement2, 20612 selectionAlwaysOnDisplay: () => selectionAlwaysOnDisplay 20613 }); 20614 function formatDevErrorMessage3(message) { 20615 throw new Error(message); 20616 } 20617 var CAN_USE_DOM$1 = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined"; 20618 var documentMode2 = CAN_USE_DOM$1 && "documentMode" in document ? document.documentMode : null; 20619 var IS_APPLE$1 = CAN_USE_DOM$1 && /Mac|iPod|iPhone|iPad/.test(navigator.platform); 20620 var IS_FIREFOX$1 = CAN_USE_DOM$1 && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent); 20621 var CAN_USE_BEFORE_INPUT$1 = CAN_USE_DOM$1 && "InputEvent" in window && !documentMode2 ? "getTargetRanges" in new window.InputEvent("input") : false; 20622 var IS_IOS$1 = CAN_USE_DOM$1 && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; 20623 var IS_ANDROID$1 = CAN_USE_DOM$1 && /Android/.test(navigator.userAgent); 20624 var IS_SAFARI$1 = CAN_USE_DOM$1 && /Version\/[\d.]+.*Safari/.test(navigator.userAgent) && !IS_ANDROID$1; 20625 var IS_CHROME$1 = CAN_USE_DOM$1 && /^(?=.*Chrome).*/i.test(navigator.userAgent); 20626 var IS_ANDROID_CHROME$1 = CAN_USE_DOM$1 && IS_ANDROID$1 && IS_CHROME$1; 20627 var IS_APPLE_WEBKIT$1 = CAN_USE_DOM$1 && /AppleWebKit\/[\d.]+/.test(navigator.userAgent) && IS_APPLE$1 && !IS_CHROME$1; 20628 function px(value) { 20629 return `${value}px`; 20630 } 20631 var mutationObserverConfig = { 20632 attributes: true, 20633 characterData: true, 20634 childList: true, 20635 subtree: true 20636 }; 20637 function prependDOMNode(parent, node) { 20638 parent.insertBefore(node, parent.firstChild); 20639 } 20640 function mlcPositionNodeOnRange(editor, range2, onReposition) { 20641 let rootDOMNode = null; 20642 let parentDOMNode = null; 20643 let observer = null; 20644 let lastNodes = []; 20645 const wrapperNode = document.createElement("div"); 20646 wrapperNode.style.position = "relative"; 20647 function position() { 20648 if (!(rootDOMNode !== null)) { 20649 formatDevErrorMessage3(`Unexpected null rootDOMNode`); 20650 } 20651 if (!(parentDOMNode !== null)) { 20652 formatDevErrorMessage3(`Unexpected null parentDOMNode`); 20653 } 20654 const { 20655 left: parentLeft, 20656 top: parentTop 20657 } = parentDOMNode.getBoundingClientRect(); 20658 const rects = createRectsFromDOMRange2(editor, range2); 20659 if (!wrapperNode.isConnected) { 20660 prependDOMNode(parentDOMNode, wrapperNode); 20661 } 20662 let hasRepositioned = false; 20663 for (let i2 = 0; i2 < rects.length; i2++) { 20664 const rect = rects[i2]; 20665 const rectNode = lastNodes[i2] || document.createElement("div"); 20666 const rectNodeStyle = rectNode.style; 20667 if (rectNodeStyle.position !== "absolute") { 20668 rectNodeStyle.position = "absolute"; 20669 hasRepositioned = true; 20670 } 20671 const left = px(rect.left - parentLeft); 20672 if (rectNodeStyle.left !== left) { 20673 rectNodeStyle.left = left; 20674 hasRepositioned = true; 20675 } 20676 const top = px(rect.top - parentTop); 20677 if (rectNodeStyle.top !== top) { 20678 rectNode.style.top = top; 20679 hasRepositioned = true; 20680 } 20681 const width = px(rect.width); 20682 if (rectNodeStyle.width !== width) { 20683 rectNode.style.width = width; 20684 hasRepositioned = true; 20685 } 20686 const height = px(rect.height); 20687 if (rectNodeStyle.height !== height) { 20688 rectNode.style.height = height; 20689 hasRepositioned = true; 20690 } 20691 if (rectNode.parentNode !== wrapperNode) { 20692 wrapperNode.append(rectNode); 20693 hasRepositioned = true; 20694 } 20695 lastNodes[i2] = rectNode; 20696 } 20697 while (lastNodes.length > rects.length) { 20698 lastNodes.pop(); 20699 } 20700 if (hasRepositioned) { 20701 onReposition(lastNodes); 20702 } 20703 } 20704 function stop() { 20705 parentDOMNode = null; 20706 rootDOMNode = null; 20707 if (observer !== null) { 20708 observer.disconnect(); 20709 } 20710 observer = null; 20711 wrapperNode.remove(); 20712 for (const node of lastNodes) { 20713 node.remove(); 20714 } 20715 lastNodes = []; 20716 } 20717 function restart() { 20718 const currentRootDOMNode = editor.getRootElement(); 20719 if (currentRootDOMNode === null) { 20720 return stop(); 20721 } 20722 const currentParentDOMNode = currentRootDOMNode.parentElement; 20723 if (!isHTMLElement2(currentParentDOMNode)) { 20724 return stop(); 20725 } 20726 stop(); 20727 rootDOMNode = currentRootDOMNode; 20728 parentDOMNode = currentParentDOMNode; 20729 observer = new MutationObserver((mutations) => { 20730 const nextRootDOMNode = editor.getRootElement(); 20731 const nextParentDOMNode = nextRootDOMNode && nextRootDOMNode.parentElement; 20732 if (nextRootDOMNode !== rootDOMNode || nextParentDOMNode !== parentDOMNode) { 20733 return restart(); 20734 } 20735 for (const mutation of mutations) { 20736 if (!wrapperNode.contains(mutation.target)) { 20737 return position(); 20738 } 20739 } 20740 }); 20741 observer.observe(currentParentDOMNode, mutationObserverConfig); 20742 position(); 20743 } 20744 const removeRootListener = editor.registerRootListener(restart); 20745 return () => { 20746 removeRootListener(); 20747 stop(); 20748 }; 20749 } 20750 function $getOrderedSelectionPoints(selection) { 20751 const points = selection.getStartEndPoints(); 20752 return selection.isBackward() ? [points[1], points[0]] : points; 20753 } 20754 function $rangeTargetFromPoint(point, node, dom) { 20755 if (point.type === "text" || !$isElementNode2(node)) { 20756 const textDOM = getDOMTextNode2(dom) || dom; 20757 return [textDOM, point.offset]; 20758 } else { 20759 const editor = $getEditor2(); 20760 const slot = $getEditorDOMRenderConfig2(editor).$getDOMSlot(node, dom, editor); 20761 return [slot.element, slot.getFirstChildOffset() + point.offset]; 20762 } 20763 } 20764 function $rangeFromPoints(editor, start3, startNode, startDOM, end, endNode, endDOM) { 20765 const editorDocument = editor._window ? editor._window.document : document; 20766 const range2 = editorDocument.createRange(); 20767 range2.setStart(...$rangeTargetFromPoint(start3, startNode, startDOM)); 20768 range2.setEnd(...$rangeTargetFromPoint(end, endNode, endDOM)); 20769 return range2; 20770 } 20771 function defaultOnReposition(domNodes) { 20772 for (const domNode of domNodes) { 20773 const domNodeStyle = domNode.style; 20774 if (domNodeStyle.background !== "Highlight") { 20775 domNodeStyle.background = "Highlight"; 20776 } 20777 if (domNodeStyle.color !== "HighlightText") { 20778 domNodeStyle.color = "HighlightText"; 20779 } 20780 if (domNodeStyle.marginTop !== px(-1.5)) { 20781 domNodeStyle.marginTop = px(-1.5); 20782 } 20783 if (domNodeStyle.paddingTop !== px(4)) { 20784 domNodeStyle.paddingTop = px(4); 20785 } 20786 if (domNodeStyle.paddingBottom !== px(0)) { 20787 domNodeStyle.paddingBottom = px(0); 20788 } 20789 } 20790 } 20791 function markSelection(editor, onReposition = defaultOnReposition) { 20792 let previousAnchorNode = null; 20793 let previousAnchorNodeDOM = null; 20794 let previousAnchorOffset = null; 20795 let previousFocusNode = null; 20796 let previousFocusNodeDOM = null; 20797 let previousFocusOffset = null; 20798 let removeRangeListener = () => { 20799 }; 20800 function compute(editorState) { 20801 editorState.read(() => { 20802 const selection = $getSelection2(); 20803 if (!$isRangeSelection2(selection)) { 20804 previousAnchorNode = null; 20805 previousAnchorOffset = null; 20806 previousFocusNode = null; 20807 previousFocusOffset = null; 20808 removeRangeListener(); 20809 removeRangeListener = () => { 20810 }; 20811 return; 20812 } 20813 const [start3, end] = $getOrderedSelectionPoints(selection); 20814 const currentStartNode = start3.getNode(); 20815 const currentStartNodeKey = currentStartNode.getKey(); 20816 const currentStartOffset = start3.offset; 20817 const currentEndNode = end.getNode(); 20818 const currentEndNodeKey = currentEndNode.getKey(); 20819 const currentEndOffset = end.offset; 20820 const currentStartNodeDOM = editor.getElementByKey(currentStartNodeKey); 20821 const currentEndNodeDOM = editor.getElementByKey(currentEndNodeKey); 20822 const differentStartDOM = previousAnchorNode === null || currentStartNodeDOM !== previousAnchorNodeDOM || currentStartOffset !== previousAnchorOffset || currentStartNodeKey !== previousAnchorNode.getKey(); 20823 const differentEndDOM = previousFocusNode === null || currentEndNodeDOM !== previousFocusNodeDOM || currentEndOffset !== previousFocusOffset || currentEndNodeKey !== previousFocusNode.getKey(); 20824 if ((differentStartDOM || differentEndDOM) && currentStartNodeDOM !== null && currentEndNodeDOM !== null) { 20825 const range2 = $rangeFromPoints(editor, start3, currentStartNode, currentStartNodeDOM, end, currentEndNode, currentEndNodeDOM); 20826 removeRangeListener(); 20827 removeRangeListener = mlcPositionNodeOnRange(editor, range2, onReposition); 20828 } 20829 previousAnchorNode = currentStartNode; 20830 previousAnchorNodeDOM = currentStartNodeDOM; 20831 previousAnchorOffset = currentStartOffset; 20832 previousFocusNode = currentEndNode; 20833 previousFocusNodeDOM = currentEndNodeDOM; 20834 previousFocusOffset = currentEndOffset; 20835 }); 20836 } 20837 compute(editor.getEditorState()); 20838 return mergeRegister2(editor.registerUpdateListener(({ 20839 editorState 20840 }) => compute(editorState)), () => { 20841 removeRangeListener(); 20842 }); 20843 } 20844 function selectionAlwaysOnDisplay(editor, onReposition) { 20845 let removeSelectionMark = null; 20846 const onSelectionChange2 = () => { 20847 const domSelection = getSelection(); 20848 const domAnchorNode = domSelection && domSelection.anchorNode; 20849 const editorRootElement = editor.getRootElement(); 20850 const isSelectionInsideEditor = domAnchorNode !== null && editorRootElement !== null && editorRootElement.contains(domAnchorNode); 20851 if (isSelectionInsideEditor) { 20852 if (removeSelectionMark !== null) { 20853 removeSelectionMark(); 20854 removeSelectionMark = null; 20855 } 20856 } else { 20857 if (removeSelectionMark === null) { 20858 removeSelectionMark = markSelection(editor, onReposition); 20859 } 20860 } 20861 }; 20862 return editor.registerRootListener((rootElement) => { 20863 if (rootElement) { 20864 const document2 = rootElement.ownerDocument; 20865 document2.addEventListener("selectionchange", onSelectionChange2); 20866 onSelectionChange2(); 20867 return () => { 20868 if (removeSelectionMark !== null) { 20869 removeSelectionMark(); 20870 } 20871 document2.removeEventListener("selectionchange", onSelectionChange2); 20872 }; 20873 } 20874 }); 20875 } 20876 var CAN_USE_BEFORE_INPUT2 = CAN_USE_BEFORE_INPUT$1; 20877 var CAN_USE_DOM2 = CAN_USE_DOM$1; 20878 var IS_ANDROID2 = IS_ANDROID$1; 20879 var IS_ANDROID_CHROME2 = IS_ANDROID_CHROME$1; 20880 var IS_APPLE2 = IS_APPLE$1; 20881 var IS_APPLE_WEBKIT2 = IS_APPLE_WEBKIT$1; 20882 var IS_CHROME2 = IS_CHROME$1; 20883 var IS_FIREFOX2 = IS_FIREFOX$1; 20884 var IS_IOS2 = IS_IOS$1; 20885 var IS_SAFARI2 = IS_SAFARI$1; 20886 function isMimeType(file, acceptableMimeTypes) { 20887 for (const acceptableType of acceptableMimeTypes) { 20888 if (file.type.startsWith(acceptableType)) { 20889 return true; 20890 } 20891 } 20892 return false; 20893 } 20894 function mediaFileReader(files, acceptableMimeTypes) { 20895 const filesIterator = files[Symbol.iterator](); 20896 return new Promise((resolve, reject) => { 20897 const processed = []; 20898 const handleNextFile = () => { 20899 const { 20900 done, 20901 value: file 20902 } = filesIterator.next(); 20903 if (done) { 20904 return resolve(processed); 20905 } 20906 const fileReader = new FileReader(); 20907 fileReader.addEventListener("error", reject); 20908 fileReader.addEventListener("load", () => { 20909 const result = fileReader.result; 20910 if (typeof result === "string") { 20911 processed.push({ 20912 file, 20913 result 20914 }); 20915 } 20916 handleNextFile(); 20917 }); 20918 if (isMimeType(file, acceptableMimeTypes)) { 20919 fileReader.readAsDataURL(file); 20920 } else { 20921 handleNextFile(); 20922 } 20923 }; 20924 handleNextFile(); 20925 }); 20926 } 20927 function $dfs(startNode, endNode) { 20928 return Array.from($dfsIterator(startNode, endNode)); 20929 } 20930 function $getAdjacentCaret(caret) { 20931 return caret ? caret.getAdjacentCaret() : null; 20932 } 20933 function $reverseDfs(startNode, endNode) { 20934 return Array.from($reverseDfsIterator(startNode, endNode)); 20935 } 20936 function $dfsIterator(startNode, endNode) { 20937 return $dfsCaretIterator("next", startNode, endNode); 20938 } 20939 function $getEndCaret(startNode, direction) { 20940 const rval = $getAdjacentSiblingOrParentSiblingCaret2($getSiblingCaret2(startNode, direction)); 20941 return rval && rval[0]; 20942 } 20943 function $dfsCaretIterator(direction, startNode, endNode) { 20944 const root = $getRoot2(); 20945 const start3 = startNode || root; 20946 const startCaret = $isElementNode2(start3) ? $getChildCaret2(start3, direction) : $getSiblingCaret2(start3, direction); 20947 const startDepth = $getDepth(start3); 20948 const endCaret = endNode ? $getAdjacentChildCaret2($getChildCaretOrSelf2($getSiblingCaret2(endNode, direction))) || $getEndCaret(endNode, direction) : $getEndCaret(start3, direction); 20949 let depth = startDepth; 20950 return makeStepwiseIterator2({ 20951 hasNext: (state) => state !== null, 20952 initial: startCaret, 20953 map: (state) => ({ 20954 depth, 20955 node: state.origin 20956 }), 20957 step: (state) => { 20958 if (state.isSameNodeCaret(endCaret)) { 20959 return null; 20960 } 20961 if ($isChildCaret2(state)) { 20962 depth++; 20963 } 20964 const rval = $getAdjacentSiblingOrParentSiblingCaret2(state); 20965 if (!rval || rval[0].isSameNodeCaret(endCaret)) { 20966 return null; 20967 } 20968 depth += rval[1]; 20969 return rval[0]; 20970 } 20971 }); 20972 } 20973 function $getNextSiblingOrParentSibling(node) { 20974 const rval = $getAdjacentSiblingOrParentSiblingCaret2($getSiblingCaret2(node, "next")); 20975 return rval && [rval[0].origin, rval[1]]; 20976 } 20977 function $getDepth(node) { 20978 let depth = -1; 20979 for (let innerNode = node; innerNode !== null; innerNode = innerNode.getParent()) { 20980 depth++; 20981 } 20982 return depth; 20983 } 20984 function $getNextRightPreorderNode(startingNode) { 20985 const startCaret = $getChildCaretOrSelf2($getSiblingCaret2(startingNode, "previous")); 20986 const next = $getAdjacentSiblingOrParentSiblingCaret2(startCaret, "root"); 20987 return next && next[0].origin; 20988 } 20989 function $reverseDfsIterator(startNode, endNode) { 20990 return $dfsCaretIterator("previous", startNode, endNode); 20991 } 20992 function $getNearestNodeOfType(node, klass) { 20993 let parent = node; 20994 while (parent != null) { 20995 if (parent instanceof klass) { 20996 return parent; 20997 } 20998 parent = parent.getParent(); 20999 } 21000 return null; 21001 } 21002 function $getNearestBlockElementAncestorOrThrow(startNode) { 21003 const blockNode = $findMatchingParent2(startNode, (node) => $isElementNode2(node) && !node.isInline()); 21004 if (!$isElementNode2(blockNode)) { 21005 { 21006 formatDevErrorMessage3(`Expected node ${startNode.__key} to have closest block element node.`); 21007 } 21008 } 21009 return blockNode; 21010 } 21011 function registerNestedElementResolver(editor, targetNode, cloneNode, handleOverlap) { 21012 const $isTargetNode = (node) => { 21013 return node instanceof targetNode; 21014 }; 21015 const $findMatch = (node) => { 21016 const children = node.getChildren(); 21017 for (let i2 = 0; i2 < children.length; i2++) { 21018 const child = children[i2]; 21019 if ($isTargetNode(child)) { 21020 return null; 21021 } 21022 } 21023 let parentNode = node; 21024 let childNode = node; 21025 while (parentNode !== null) { 21026 childNode = parentNode; 21027 parentNode = parentNode.getParent(); 21028 if ($isTargetNode(parentNode)) { 21029 return { 21030 child: childNode, 21031 parent: parentNode 21032 }; 21033 } 21034 } 21035 return null; 21036 }; 21037 const $elementNodeTransform = (node) => { 21038 const match = $findMatch(node); 21039 if (match !== null) { 21040 const { 21041 child, 21042 parent 21043 } = match; 21044 if (child.is(node)) { 21045 handleOverlap(parent, node); 21046 const nextSiblings = child.getNextSiblings(); 21047 const nextSiblingsLength = nextSiblings.length; 21048 parent.insertAfter(child); 21049 if (nextSiblingsLength !== 0) { 21050 const newParent = cloneNode(parent); 21051 child.insertAfter(newParent); 21052 for (let i2 = 0; i2 < nextSiblingsLength; i2++) { 21053 newParent.append(nextSiblings[i2]); 21054 } 21055 } 21056 if (!parent.canBeEmpty() && parent.getChildrenSize() === 0) { 21057 parent.remove(); 21058 } 21059 } 21060 } 21061 }; 21062 return editor.registerNodeTransform(targetNode, $elementNodeTransform); 21063 } 21064 function $restoreEditorState(editor, editorState) { 21065 const FULL_RECONCILE2 = 2; 21066 const nodeMap = /* @__PURE__ */ new Map(); 21067 const activeEditorState2 = editor._pendingEditorState; 21068 for (const [key, node] of editorState._nodeMap) { 21069 nodeMap.set(key, $cloneWithProperties2(node)); 21070 } 21071 if (activeEditorState2) { 21072 activeEditorState2._nodeMap = nodeMap; 21073 } 21074 editor._dirtyType = FULL_RECONCILE2; 21075 const selection = editorState._selection; 21076 $setSelection2(selection === null ? null : selection.clone()); 21077 } 21078 function $insertNodeToNearestRoot(node) { 21079 const selection = $getSelection2() || $getPreviousSelection2(); 21080 let initialCaret; 21081 if ($isRangeSelection2(selection)) { 21082 initialCaret = $caretFromPoint2(selection.focus, "next"); 21083 } else { 21084 if (selection != null) { 21085 const nodes = selection.getNodes(); 21086 const lastNode = nodes[nodes.length - 1]; 21087 if (lastNode) { 21088 initialCaret = $getSiblingCaret2(lastNode, "next"); 21089 } 21090 } 21091 initialCaret = initialCaret || $getChildCaret2($getRoot2(), "previous").getFlipped().insert($createParagraphNode2()); 21092 } 21093 const insertCaret = $insertNodeToNearestRootAtCaret(node, initialCaret); 21094 const adjacent = $getAdjacentChildCaret2(insertCaret); 21095 const selectionCaret = $isChildCaret2(adjacent) ? $normalizeCaret2(adjacent) : insertCaret; 21096 $setSelectionFromCaretRange2($getCollapsedCaretRange2(selectionCaret)); 21097 return node.getLatest(); 21098 } 21099 function $insertNodeToNearestRootAtCaret(node, caret, options) { 21100 let insertCaret = $getCaretInDirection2(caret, "next"); 21101 if ($isTextPointCaret2(insertCaret)) { 21102 if (insertCaret.offset === 0) { 21103 insertCaret = $getSiblingCaret2(insertCaret.origin, "previous").getFlipped(); 21104 } else if (insertCaret.offset === insertCaret.origin.getTextContentSize()) { 21105 insertCaret = $getSiblingCaret2(insertCaret.origin, "next"); 21106 } 21107 } 21108 if (insertCaret.origin.is(node)) { 21109 if (!$isSiblingCaret2(insertCaret)) { 21110 formatDevErrorMessage3(`$insertNodeToNearestRootAtCaret node ${node.getKey()} of type ${node.getType()} can not be inserted into itself`); 21111 } 21112 insertCaret = $rewindSiblingCaret2(insertCaret); 21113 } 21114 if (node.is(insertCaret.getNodeAtCaret()) || node.is(insertCaret.getFlipped().getNodeAtCaret())) { 21115 node.remove(true); 21116 } 21117 for (let nextCaret = insertCaret; nextCaret; nextCaret = $splitAtPointCaretNext2(nextCaret, options)) { 21118 insertCaret = nextCaret; 21119 } 21120 if (!!$isTextPointCaret2(insertCaret)) { 21121 formatDevErrorMessage3(`$insertNodeToNearestRootAtCaret: An unattached TextNode can not be split`); 21122 } 21123 insertCaret.insert(node.isInline() ? $createParagraphNode2().append(node) : node); 21124 return $getCaretInDirection2($getSiblingCaret2(node.getLatest(), "next"), caret.direction); 21125 } 21126 function $insertNodeIntoLeaf(node) { 21127 const selection = $getSelection2(); 21128 if (!$isRangeSelection2(selection)) { 21129 if (selection) { 21130 selection.insertNodes([node]); 21131 } 21132 return; 21133 } 21134 const caretRange = $caretRangeFromSelection2(selection); 21135 let insertCaret = $getCaretRangeInDirection2($removeTextFromCaretRange2(caretRange), "next").anchor; 21136 if ($isTextPointCaret2(insertCaret)) { 21137 const nextAnchor = $splitAtPointCaretNext2(insertCaret); 21138 if (!nextAnchor) { 21139 return; 21140 } 21141 insertCaret = nextAnchor; 21142 } 21143 const focus = insertCaret.getFlipped(); 21144 focus.insert(node); 21145 $setSelectionFromCaretRange2($getCaretRange2(focus, focus)); 21146 } 21147 function $wrapNodeInElement(node, createElementNode) { 21148 const elementNode = createElementNode(); 21149 node.replace(elementNode); 21150 elementNode.append(node); 21151 return elementNode; 21152 } 21153 function objectKlassEquals(object, objectClass) { 21154 return object !== null ? Object.getPrototypeOf(object).constructor.name === objectClass.name : false; 21155 } 21156 function $filter(nodes, filterFn) { 21157 const result = []; 21158 for (let i2 = 0; i2 < nodes.length; i2++) { 21159 const node = filterFn(nodes[i2]); 21160 if (node !== null) { 21161 result.push(node); 21162 } 21163 } 21164 return result; 21165 } 21166 function $handleIndentAndOutdent(indentOrOutdent) { 21167 const selection = $getSelection2(); 21168 if (!$isRangeSelection2(selection)) { 21169 return false; 21170 } 21171 const alreadyHandled = /* @__PURE__ */ new Set(); 21172 const nodes = selection.getNodes(); 21173 for (let i2 = 0; i2 < nodes.length; i2++) { 21174 const node = nodes[i2]; 21175 const key = node.getKey(); 21176 if (alreadyHandled.has(key)) { 21177 continue; 21178 } 21179 const parentBlock = $findMatchingParent2(node, (parentNode) => $isElementNode2(parentNode) && !parentNode.isInline()); 21180 if (parentBlock === null) { 21181 continue; 21182 } 21183 const parentKey = parentBlock.getKey(); 21184 if (parentBlock.canIndent() && !alreadyHandled.has(parentKey)) { 21185 alreadyHandled.add(parentKey); 21186 indentOrOutdent(parentBlock); 21187 } 21188 } 21189 return alreadyHandled.size > 0; 21190 } 21191 function $insertFirst(parent, node) { 21192 $getChildCaret2(parent, "next").insert(node); 21193 } 21194 var NEEDS_MANUAL_ZOOM = IS_FIREFOX2 || !CAN_USE_DOM2 ? false : void 0; 21195 function needsManualZoom() { 21196 if (NEEDS_MANUAL_ZOOM === void 0) { 21197 const div = document.createElement("div"); 21198 div.style.position = "absolute"; 21199 div.style.opacity = "0"; 21200 div.style.width = "100px"; 21201 div.style.left = "-1000px"; 21202 document.body.appendChild(div); 21203 const noZoom = div.getBoundingClientRect(); 21204 div.style.setProperty("zoom", "2"); 21205 NEEDS_MANUAL_ZOOM = div.getBoundingClientRect().width === noZoom.width; 21206 document.body.removeChild(div); 21207 } 21208 return NEEDS_MANUAL_ZOOM; 21209 } 21210 function calculateZoomLevel(element, useManualZoom = false) { 21211 let zoom = 1; 21212 if (needsManualZoom() || useManualZoom) { 21213 while (element) { 21214 zoom *= Number(window.getComputedStyle(element).getPropertyValue("zoom")); 21215 element = element.parentElement; 21216 } 21217 } 21218 return zoom; 21219 } 21220 function $isEditorIsNestedEditor(editor) { 21221 return editor._parentEditor !== null; 21222 } 21223 function $unwrapAndFilterDescendants(root, $predicate) { 21224 return $unwrapAndFilterDescendantsImpl(root, $predicate, null); 21225 } 21226 function $unwrapAndFilterDescendantsImpl(root, $predicate, $onSuccess) { 21227 let didMutate = false; 21228 for (const node of $lastToFirstIterator(root)) { 21229 if ($predicate(node)) { 21230 if ($onSuccess !== null) { 21231 $onSuccess(node); 21232 } 21233 continue; 21234 } 21235 didMutate = true; 21236 if ($isElementNode2(node)) { 21237 $unwrapAndFilterDescendantsImpl(node, $predicate, $onSuccess || ((child) => node.insertAfter(child))); 21238 } 21239 node.remove(); 21240 } 21241 return didMutate; 21242 } 21243 function $descendantsMatching(children, $predicate) { 21244 const result = []; 21245 const stack = Array.from(children).reverse(); 21246 for (let child = stack.pop(); child !== void 0; child = stack.pop()) { 21247 if ($predicate(child)) { 21248 result.push(child); 21249 } else if ($isElementNode2(child)) { 21250 for (const grandchild of $lastToFirstIterator(child)) { 21251 stack.push(grandchild); 21252 } 21253 } 21254 } 21255 return result; 21256 } 21257 function $firstToLastIterator(node) { 21258 return $childIterator($getChildCaret2(node, "next")); 21259 } 21260 function $lastToFirstIterator(node) { 21261 return $childIterator($getChildCaret2(node, "previous")); 21262 } 21263 function $childIterator(startCaret) { 21264 const seen = /* @__PURE__ */ new Set(); 21265 return makeStepwiseIterator2({ 21266 hasNext: $isSiblingCaret2, 21267 initial: startCaret.getAdjacentCaret(), 21268 map: (caret) => { 21269 const origin = caret.origin.getLatest(); 21270 if (seen !== null) { 21271 const key = origin.getKey(); 21272 if (!!seen.has(key)) { 21273 formatDevErrorMessage3(`$childIterator: Cycle detected, node with key ${String(key)} has already been traversed`); 21274 } 21275 seen.add(key); 21276 } 21277 return origin; 21278 }, 21279 step: (caret) => caret.getAdjacentCaret() 21280 }); 21281 } 21282 function $unwrapNode(node) { 21283 $rewindSiblingCaret2($getSiblingCaret2(node, "next")).splice(1, node.getChildren()); 21284 } 21285 function makeStateWrapper(stateConfig) { 21286 const $get = (node) => $getState2(node, stateConfig); 21287 const $set = (node, valueOrUpdater) => $setState2(node, stateConfig, valueOrUpdater); 21288 return { 21289 $get, 21290 $set, 21291 accessors: [$get, $set], 21292 makeGetterMethod: () => function $getter() { 21293 return $get(this); 21294 }, 21295 makeSetterMethod: () => function $setter(valueOrUpdater) { 21296 return $set(this, valueOrUpdater); 21297 }, 21298 stateConfig 21299 }; 21300 } 21301 21302
vendor: 2,879 bytes, lines 21302-21358
21302// node_modules/@lexical/utils/LexicalUtils.mjs 21303 var mod3 = true ? LexicalUtils_dev_exports : LexicalUtils_prod_exports; 21304 var $descendantsMatching2 = mod3.$descendantsMatching; 21305 var $dfs2 = mod3.$dfs; 21306 var $dfsIterator2 = mod3.$dfsIterator; 21307 var $filter2 = mod3.$filter; 21308 var $findMatchingParent3 = mod3.$findMatchingParent; 21309 var $firstToLastIterator2 = mod3.$firstToLastIterator; 21310 var $getAdjacentCaret2 = mod3.$getAdjacentCaret; 21311 var $getAdjacentSiblingOrParentSiblingCaret3 = mod3.$getAdjacentSiblingOrParentSiblingCaret; 21312 var $getDepth2 = mod3.$getDepth; 21313 var $getNearestBlockElementAncestorOrThrow2 = mod3.$getNearestBlockElementAncestorOrThrow; 21314 var $getNearestNodeOfType2 = mod3.$getNearestNodeOfType; 21315 var $getNextRightPreorderNode2 = mod3.$getNextRightPreorderNode; 21316 var $getNextSiblingOrParentSibling2 = mod3.$getNextSiblingOrParentSibling; 21317 var $handleIndentAndOutdent2 = mod3.$handleIndentAndOutdent; 21318 var $insertFirst2 = mod3.$insertFirst; 21319 var $insertNodeIntoLeaf2 = mod3.$insertNodeIntoLeaf; 21320 var $insertNodeToNearestRoot2 = mod3.$insertNodeToNearestRoot; 21321 var $insertNodeToNearestRootAtCaret2 = mod3.$insertNodeToNearestRootAtCaret; 21322 var $isEditorIsNestedEditor2 = mod3.$isEditorIsNestedEditor; 21323 var $lastToFirstIterator2 = mod3.$lastToFirstIterator; 21324 var $restoreEditorState2 = mod3.$restoreEditorState; 21325 var $reverseDfs2 = mod3.$reverseDfs; 21326 var $reverseDfsIterator2 = mod3.$reverseDfsIterator; 21327 var $splitNode3 = mod3.$splitNode; 21328 var $unwrapAndFilterDescendants2 = mod3.$unwrapAndFilterDescendants; 21329 var $unwrapNode2 = mod3.$unwrapNode; 21330 var $wrapNodeInElement2 = mod3.$wrapNodeInElement; 21331 var CAN_USE_BEFORE_INPUT3 = mod3.CAN_USE_BEFORE_INPUT; 21332 var CAN_USE_DOM3 = mod3.CAN_USE_DOM; 21333 var IS_ANDROID3 = mod3.IS_ANDROID; 21334 var IS_ANDROID_CHROME3 = mod3.IS_ANDROID_CHROME; 21335 var IS_APPLE3 = mod3.IS_APPLE; 21336 var IS_APPLE_WEBKIT3 = mod3.IS_APPLE_WEBKIT; 21337 var IS_CHROME3 = mod3.IS_CHROME; 21338 var IS_FIREFOX3 = mod3.IS_FIREFOX; 21339 var IS_IOS3 = mod3.IS_IOS; 21340 var IS_SAFARI3 = mod3.IS_SAFARI; 21341 var addClassNamesToElement3 = mod3.addClassNamesToElement; 21342 var calculateZoomLevel2 = mod3.calculateZoomLevel; 21343 var isBlockDomNode3 = mod3.isBlockDomNode; 21344 var isHTMLAnchorElement3 = mod3.isHTMLAnchorElement; 21345 var isHTMLElement3 = mod3.isHTMLElement; 21346 var isInlineDomNode3 = mod3.isInlineDomNode; 21347 var isMimeType2 = mod3.isMimeType; 21348 var makeStateWrapper2 = mod3.makeStateWrapper; 21349 var markSelection2 = mod3.markSelection; 21350 var mediaFileReader2 = mod3.mediaFileReader; 21351 var mergeRegister3 = mod3.mergeRegister; 21352 var objectKlassEquals2 = mod3.objectKlassEquals; 21353 var positionNodeOnRange = mod3.positionNodeOnRange; 21354 var registerNestedElementResolver2 = mod3.registerNestedElementResolver; 21355 var removeClassNamesFromElement3 = mod3.removeClassNamesFromElement; 21356 var selectionAlwaysOnDisplay2 = mod3.selectionAlwaysOnDisplay; 21357 21358
vendor: 54,201 bytes, lines 21358-23024
21358// node_modules/@lexical/extension/LexicalExtension.dev.mjs 21359 var LexicalExtension_dev_exports = {}; 21360 __export(LexicalExtension_dev_exports, { 21361 $createHorizontalRuleNode: () => $createHorizontalRuleNode, 21362 $isDecoratorTextNode: () => $isDecoratorTextNode, 21363 $isHorizontalRuleNode: () => $isHorizontalRuleNode, 21364 AutoFocusExtension: () => AutoFocusExtension, 21365 ClearEditorExtension: () => ClearEditorExtension, 21366 DecoratorTextExtension: () => DecoratorTextExtension, 21367 DecoratorTextNode: () => DecoratorTextNode, 21368 EditorStateExtension: () => EditorStateExtension, 21369 HorizontalRuleExtension: () => HorizontalRuleExtension, 21370 HorizontalRuleNode: () => HorizontalRuleNode, 21371 INSERT_HORIZONTAL_RULE_COMMAND: () => INSERT_HORIZONTAL_RULE_COMMAND, 21372 InitialStateExtension: () => InitialStateExtension, 21373 LexicalBuilder: () => LexicalBuilder, 21374 NestedEditorExtension: () => NestedEditorExtension, 21375 NodeSelectionExtension: () => NodeSelectionExtension, 21376 SelectionAlwaysOnDisplayExtension: () => SelectionAlwaysOnDisplayExtension, 21377 TabIndentationExtension: () => TabIndentationExtension, 21378 applyFormatFromStyle: () => applyFormatFromStyle, 21379 applyFormatToDom: () => applyFormatToDom, 21380 batch: () => n, 21381 buildEditorFromExtensions: () => buildEditorFromExtensions, 21382 computed: () => g, 21383 configExtension: () => configExtension2, 21384 declarePeerDependency: () => declarePeerDependency2, 21385 defineExtension: () => defineExtension2, 21386 effect: () => j, 21387 getExtensionDependencyFromEditor: () => getExtensionDependencyFromEditor, 21388 getKnownTypesAndNodes: () => getKnownTypesAndNodes, 21389 getPeerDependencyFromEditor: () => getPeerDependencyFromEditor, 21390 getPeerDependencyFromEditorOrThrow: () => getPeerDependencyFromEditorOrThrow, 21391 namedSignals: () => namedSignals, 21392 registerClearEditor: () => registerClearEditor, 21393 registerTabIndentation: () => registerTabIndentation, 21394 safeCast: () => safeCast2, 21395 shallowMergeConfig: () => shallowMergeConfig2, 21396 signal: () => a, 21397 untracked: () => h, 21398 watchedSignal: () => watchedSignal 21399 }); 21400 var i = Symbol.for("preact-signals"); 21401 function t() { 21402 if (e > 1) { 21403 e--; 21404 return; 21405 } 21406 let i2, t2 = false; 21407 !function() { 21408 let i3 = r; 21409 r = void 0; 21410 while (void 0 !== i3) { 21411 if (i3.S.v === i3.v) i3.S.i = i3.i; 21412 i3 = i3.o; 21413 } 21414 }(); 21415 while (void 0 !== s) { 21416 let n2 = s; 21417 s = void 0; 21418 u++; 21419 while (void 0 !== n2) { 21420 const o2 = n2.u; 21421 n2.u = void 0; 21422 n2.f &= -3; 21423 if (!(8 & n2.f) && w(n2)) try { 21424 n2.c(); 21425 } catch (n3) { 21426 if (!t2) { 21427 i2 = n3; 21428 t2 = true; 21429 } 21430 } 21431 n2 = o2; 21432 } 21433 } 21434 u = 0; 21435 e--; 21436 if (t2) throw i2; 21437 } 21438 function n(i2) { 21439 if (e > 0) return i2(); 21440 d = ++c; 21441 e++; 21442 try { 21443 return i2(); 21444 } finally { 21445 t(); 21446 } 21447 } 21448 var o; 21449 var s; 21450 function h(i2) { 21451 const t2 = o; 21452 o = void 0; 21453 try { 21454 return i2(); 21455 } finally { 21456 o = t2; 21457 } 21458 } 21459 var r; 21460 var e = 0; 21461 var u = 0; 21462 var c = 0; 21463 var d = 0; 21464 var v = 0; 21465 function l(i2) { 21466 if (void 0 === o) return; 21467 let t2 = i2.n; 21468 if (void 0 === t2 || t2.t !== o) { 21469 t2 = { i: 0, S: i2, p: o.s, n: void 0, t: o, e: void 0, x: void 0, r: t2 }; 21470 if (void 0 !== o.s) o.s.n = t2; 21471 o.s = t2; 21472 i2.n = t2; 21473 if (32 & o.f) i2.S(t2); 21474 return t2; 21475 } else if (-1 === t2.i) { 21476 t2.i = 0; 21477 if (void 0 !== t2.n) { 21478 t2.n.p = t2.p; 21479 if (void 0 !== t2.p) t2.p.n = t2.n; 21480 t2.p = o.s; 21481 t2.n = void 0; 21482 o.s.n = t2; 21483 o.s = t2; 21484 } 21485 return t2; 21486 } 21487 } 21488 function y(i2, t2) { 21489 this.v = i2; 21490 this.i = 0; 21491 this.n = void 0; 21492 this.t = void 0; 21493 this.l = 0; 21494 this.W = null == t2 ? void 0 : t2.watched; 21495 this.Z = null == t2 ? void 0 : t2.unwatched; 21496 this.name = null == t2 ? void 0 : t2.name; 21497 } 21498 y.prototype.brand = i; 21499 y.prototype.h = function() { 21500 return true; 21501 }; 21502 y.prototype.S = function(i2) { 21503 const t2 = this.t; 21504 if (t2 !== i2 && void 0 === i2.e) { 21505 i2.x = t2; 21506 this.t = i2; 21507 if (void 0 !== t2) t2.e = i2; 21508 else h(() => { 21509 var i3; 21510 null == (i3 = this.W) || i3.call(this); 21511 }); 21512 } 21513 }; 21514 y.prototype.U = function(i2) { 21515 if (void 0 !== this.t) { 21516 const t2 = i2.e, n2 = i2.x; 21517 if (void 0 !== t2) { 21518 t2.x = n2; 21519 i2.e = void 0; 21520 } 21521 if (void 0 !== n2) { 21522 n2.e = t2; 21523 i2.x = void 0; 21524 } 21525 if (i2 === this.t) { 21526 this.t = n2; 21527 if (void 0 === n2) h(() => { 21528 var i3; 21529 null == (i3 = this.Z) || i3.call(this); 21530 }); 21531 } 21532 } 21533 }; 21534 y.prototype.subscribe = function(i2) { 21535 return j(() => { 21536 const t2 = this.value, n2 = o; 21537 o = void 0; 21538 try { 21539 i2(t2); 21540 } finally { 21541 o = n2; 21542 } 21543 }, { name: "sub" }); 21544 }; 21545 y.prototype.valueOf = function() { 21546 return this.value; 21547 }; 21548 y.prototype.toString = function() { 21549 return this.value + ""; 21550 }; 21551 y.prototype.toJSON = function() { 21552 return this.value; 21553 }; 21554 y.prototype.peek = function() { 21555 const i2 = o; 21556 o = void 0; 21557 try { 21558 return this.value; 21559 } finally { 21560 o = i2; 21561 } 21562 }; 21563 Object.defineProperty(y.prototype, "value", { get() { 21564 const i2 = l(this); 21565 if (void 0 !== i2) i2.i = this.i; 21566 return this.v; 21567 }, set(i2) { 21568 if (i2 !== this.v) { 21569 if (u > 100) throw new Error("Cycle detected"); 21570 !function(i3) { 21571 if (0 !== e && 0 === u) { 21572 if (i3.l !== d) { 21573 i3.l = d; 21574 r = { S: i3, v: i3.v, i: i3.i, o: r }; 21575 } 21576 } 21577 }(this); 21578 this.v = i2; 21579 this.i++; 21580 v++; 21581 e++; 21582 try { 21583 for (let i3 = this.t; void 0 !== i3; i3 = i3.x) i3.t.N(); 21584 } finally { 21585 t(); 21586 } 21587 } 21588 } }); 21589 function a(i2, t2) { 21590 return new y(i2, t2); 21591 } 21592 function w(i2) { 21593 for (let t2 = i2.s; void 0 !== t2; t2 = t2.n) if (t2.S.i !== t2.i || !t2.S.h() || t2.S.i !== t2.i) return true; 21594 return false; 21595 } 21596 function _(i2) { 21597 for (let t2 = i2.s; void 0 !== t2; t2 = t2.n) { 21598 const n2 = t2.S.n; 21599 if (void 0 !== n2) t2.r = n2; 21600 t2.S.n = t2; 21601 t2.i = -1; 21602 if (void 0 === t2.n) { 21603 i2.s = t2; 21604 break; 21605 } 21606 } 21607 } 21608 function b(i2) { 21609 let t2, n2 = i2.s; 21610 while (void 0 !== n2) { 21611 const i3 = n2.p; 21612 if (-1 === n2.i) { 21613 n2.S.U(n2); 21614 if (void 0 !== i3) i3.n = n2.n; 21615 if (void 0 !== n2.n) n2.n.p = i3; 21616 } else t2 = n2; 21617 n2.S.n = n2.r; 21618 if (void 0 !== n2.r) n2.r = void 0; 21619 n2 = i3; 21620 } 21621 i2.s = t2; 21622 } 21623 function p(i2, t2) { 21624 y.call(this, void 0); 21625 this.x = i2; 21626 this.s = void 0; 21627 this.g = v - 1; 21628 this.f = 4; 21629 this.W = null == t2 ? void 0 : t2.watched; 21630 this.Z = null == t2 ? void 0 : t2.unwatched; 21631 this.name = null == t2 ? void 0 : t2.name; 21632 } 21633 p.prototype = new y(); 21634 p.prototype.h = function() { 21635 this.f &= -3; 21636 if (1 & this.f) return false; 21637 if (32 == (36 & this.f)) return true; 21638 this.f &= -5; 21639 if (this.g === v) return true; 21640 this.g = v; 21641 this.f |= 1; 21642 if (this.i > 0 && !w(this)) { 21643 this.f &= -2; 21644 return true; 21645 } 21646 const i2 = o; 21647 try { 21648 _(this); 21649 o = this; 21650 const i3 = this.x(); 21651 if (16 & this.f || this.v !== i3 || 0 === this.i) { 21652 this.v = i3; 21653 this.f &= -17; 21654 this.i++; 21655 } 21656 } catch (i3) { 21657 this.v = i3; 21658 this.f |= 16; 21659 this.i++; 21660 } 21661 o = i2; 21662 b(this); 21663 this.f &= -2; 21664 return true; 21665 }; 21666 p.prototype.S = function(i2) { 21667 if (void 0 === this.t) { 21668 this.f |= 36; 21669 for (let i3 = this.s; void 0 !== i3; i3 = i3.n) i3.S.S(i3); 21670 } 21671 y.prototype.S.call(this, i2); 21672 }; 21673 p.prototype.U = function(i2) { 21674 if (void 0 !== this.t) { 21675 y.prototype.U.call(this, i2); 21676 if (void 0 === this.t) { 21677 this.f &= -33; 21678 for (let i3 = this.s; void 0 !== i3; i3 = i3.n) i3.S.U(i3); 21679 } 21680 } 21681 }; 21682 p.prototype.N = function() { 21683 if (!(2 & this.f)) { 21684 this.f |= 6; 21685 for (let i2 = this.t; void 0 !== i2; i2 = i2.x) i2.t.N(); 21686 } 21687 }; 21688 Object.defineProperty(p.prototype, "value", { get() { 21689 if (1 & this.f) throw new Error("Cycle detected"); 21690 const i2 = l(this); 21691 this.h(); 21692 if (void 0 !== i2) i2.i = this.i; 21693 if (16 & this.f) throw this.v; 21694 return this.v; 21695 } }); 21696 function g(i2, t2) { 21697 return new p(i2, t2); 21698 } 21699 function S(i2) { 21700 const n2 = i2.m; 21701 i2.m = void 0; 21702 if ("function" == typeof n2) { 21703 e++; 21704 const s2 = o; 21705 o = void 0; 21706 try { 21707 n2(); 21708 } catch (t2) { 21709 i2.f &= -2; 21710 i2.f |= 8; 21711 m(i2); 21712 throw t2; 21713 } finally { 21714 o = s2; 21715 t(); 21716 } 21717 } 21718 } 21719 function m(i2) { 21720 for (let t2 = i2.s; void 0 !== t2; t2 = t2.n) t2.S.U(t2); 21721 i2.x = void 0; 21722 i2.s = void 0; 21723 S(i2); 21724 } 21725 function x(i2) { 21726 if (o !== this) throw new Error("Out-of-order effect"); 21727 b(this); 21728 o = i2; 21729 this.f &= -2; 21730 if (8 & this.f) m(this); 21731 t(); 21732 } 21733 function E(i2, t2) { 21734 this.x = i2; 21735 this.m = void 0; 21736 this.s = void 0; 21737 this.u = void 0; 21738 this.f = 32; 21739 this.name = null == t2 ? void 0 : t2.name; 21740 } 21741 E.prototype.c = function() { 21742 const i2 = this.S(); 21743 try { 21744 if (8 & this.f) return; 21745 if (void 0 === this.x) return; 21746 const t2 = this.x(); 21747 if ("function" == typeof t2) this.m = t2; 21748 } finally { 21749 i2(); 21750 } 21751 }; 21752 E.prototype.S = function() { 21753 if (1 & this.f) throw new Error("Cycle detected"); 21754 this.f |= 1; 21755 this.f &= -9; 21756 S(this); 21757 _(this); 21758 e++; 21759 const i2 = o; 21760 o = this; 21761 return x.bind(this, i2); 21762 }; 21763 E.prototype.N = function() { 21764 if (!(2 & this.f)) { 21765 this.f |= 2; 21766 this.u = s; 21767 s = this; 21768 } 21769 }; 21770 E.prototype.d = function() { 21771 this.f |= 8; 21772 if (!(1 & this.f)) m(this); 21773 }; 21774 E.prototype.dispose = function() { 21775 this.d(); 21776 }; 21777 function j(i2, t2) { 21778 const n2 = new E(i2, t2); 21779 try { 21780 n2.c(); 21781 } catch (i3) { 21782 n2.d(); 21783 throw i3; 21784 } 21785 const o2 = n2.d.bind(n2); 21786 o2[Symbol.dispose] = o2; 21787 return o2; 21788 } 21789 function namedSignals(defaults, opts = {}) { 21790 const initial = {}; 21791 for (const k2 in defaults) { 21792 const v3 = opts[k2]; 21793 const store = a(v3 === void 0 ? defaults[k2] : v3); 21794 initial[k2] = store; 21795 } 21796 return initial; 21797 } 21798 var AutoFocusExtension = defineExtension2({ 21799 build: (editor, config, state) => { 21800 return namedSignals(config); 21801 }, 21802 config: safeCast2({ 21803 defaultSelection: "rootEnd", 21804 disabled: false 21805 }), 21806 name: "@lexical/extension/AutoFocus", 21807 register(editor, config, state) { 21808 const stores = state.getOutput(); 21809 return j(() => stores.disabled.value ? void 0 : editor.registerRootListener((rootElement) => { 21810 editor.focus(() => { 21811 const activeElement = document.activeElement; 21812 if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) { 21813 rootElement.focus({ 21814 preventScroll: true 21815 }); 21816 } 21817 }, { 21818 defaultSelection: stores.defaultSelection.peek() 21819 }); 21820 })); 21821 } 21822 }); 21823 function $defaultOnClear() { 21824 const root = $getRoot2(); 21825 const selection = $getSelection2(); 21826 const paragraph = $createParagraphNode2(); 21827 root.clear(); 21828 root.append(paragraph); 21829 if (selection !== null) { 21830 paragraph.select(); 21831 } 21832 if ($isRangeSelection2(selection)) { 21833 selection.format = 0; 21834 } 21835 } 21836 function registerClearEditor(editor, $onClear = $defaultOnClear) { 21837 return editor.registerCommand(CLEAR_EDITOR_COMMAND2, (payload) => { 21838 editor.update($onClear); 21839 return true; 21840 }, COMMAND_PRIORITY_EDITOR2); 21841 } 21842 var ClearEditorExtension = defineExtension2({ 21843 build(editor, config, state) { 21844 return namedSignals(config); 21845 }, 21846 config: safeCast2({ 21847 $onClear: $defaultOnClear 21848 }), 21849 name: "@lexical/extension/ClearEditor", 21850 register(editor, config, state) { 21851 const { 21852 $onClear 21853 } = state.getOutput(); 21854 return j(() => registerClearEditor(editor, $onClear.value)); 21855 } 21856 }); 21857 function getKnownTypesAndNodes(config) { 21858 const types = /* @__PURE__ */ new Set(); 21859 const nodes = /* @__PURE__ */ new Set(); 21860 for (const klassOrReplacement of getNodeConfig(config)) { 21861 const klass = typeof klassOrReplacement === "function" ? klassOrReplacement : klassOrReplacement.replace; 21862 void getStaticNodeConfig2(klass); 21863 types.add(klass.getType()); 21864 nodes.add(klass); 21865 } 21866 return { 21867 nodes, 21868 types 21869 }; 21870 } 21871 function getNodeConfig(config) { 21872 return (typeof config.nodes === "function" ? config.nodes() : config.nodes) || []; 21873 } 21874 var formatState = createState2("format", { 21875 parse: (value) => typeof value === "number" ? value : 0 21876 }); 21877 var DecoratorTextNode = class extends DecoratorNode2 { 21878 $config() { 21879 return this.config("decorator-text", { 21880 extends: DecoratorNode2, 21881 stateConfigs: [{ 21882 flat: true, 21883 stateConfig: formatState 21884 }] 21885 }); 21886 } 21887 getFormat() { 21888 return $getState2(this, formatState); 21889 } 21890 getFormatFlags(type, alignWithFormat) { 21891 return toggleTextFormatType2(this.getFormat(), type, alignWithFormat); 21892 } 21893 hasFormat(type) { 21894 const formatFlag = TEXT_TYPE_TO_FORMAT2[type]; 21895 return (this.getFormat() & formatFlag) !== 0; 21896 } 21897 setFormat(type) { 21898 return $setState2(this, formatState, type); 21899 } 21900 toggleFormat(type) { 21901 const format = this.getFormat(); 21902 const newFormat = toggleTextFormatType2(format, type, null); 21903 return this.setFormat(newFormat); 21904 } 21905 isInline() { 21906 return true; 21907 } 21908 createDOM() { 21909 return document.createElement("span"); 21910 } 21911 updateDOM() { 21912 return false; 21913 } 21914 }; 21915 function $isDecoratorTextNode(node) { 21916 return node instanceof DecoratorTextNode; 21917 } 21918 function applyFormatFromStyle(lexicalNode, style, shouldApply) { 21919 const fontWeight = style.fontWeight; 21920 const textDecoration = style.textDecoration.split(" "); 21921 const hasBoldFontWeight = fontWeight === "700" || fontWeight === "bold"; 21922 const hasLinethroughTextDecoration = textDecoration.includes("line-through"); 21923 const hasItalicFontStyle = style.fontStyle === "italic"; 21924 const hasUnderlineTextDecoration = textDecoration.includes("underline"); 21925 const verticalAlign = style.verticalAlign; 21926 if (hasBoldFontWeight && !lexicalNode.hasFormat("bold")) { 21927 lexicalNode.toggleFormat("bold"); 21928 } 21929 if (hasLinethroughTextDecoration && !lexicalNode.hasFormat("strikethrough")) { 21930 lexicalNode.toggleFormat("strikethrough"); 21931 } 21932 if (hasItalicFontStyle && !lexicalNode.hasFormat("italic")) { 21933 lexicalNode.toggleFormat("italic"); 21934 } 21935 if (hasUnderlineTextDecoration && !lexicalNode.hasFormat("underline")) { 21936 lexicalNode.toggleFormat("underline"); 21937 } 21938 if (verticalAlign === "sub" && !lexicalNode.hasFormat("subscript")) { 21939 lexicalNode.toggleFormat("subscript"); 21940 } 21941 if (verticalAlign === "super" && !lexicalNode.hasFormat("superscript")) { 21942 lexicalNode.toggleFormat("superscript"); 21943 } 21944 if (shouldApply && !lexicalNode.hasFormat(shouldApply)) { 21945 lexicalNode.toggleFormat(shouldApply); 21946 } 21947 return lexicalNode; 21948 } 21949 function applyFormatToDom(lexicalNode, domNode, tagNameToFormat = DEFAULT_TAG_NAME_TO_FORMAT) { 21950 for (const [tag, format] of Object.entries(tagNameToFormat)) { 21951 if (lexicalNode.hasFormat(format)) { 21952 domNode = wrapElementWith2(domNode, tag); 21953 } 21954 } 21955 return domNode; 21956 } 21957 function wrapElementWith2(element, tag) { 21958 const el = document.createElement(tag); 21959 el.appendChild(element); 21960 return el; 21961 } 21962 var DEFAULT_TAG_NAME_TO_FORMAT = { 21963 b: "bold", 21964 code: "code", 21965 em: "italic", 21966 i: "italic", 21967 mark: "highlight", 21968 s: "strikethrough", 21969 strong: "bold", 21970 sub: "subscript", 21971 sup: "superscript", 21972 u: "underline" 21973 }; 21974 var DecoratorTextExtension = defineExtension2({ 21975 name: "@lexical/extension/DecoratorText", 21976 nodes: () => [DecoratorTextNode], 21977 register(editor, config, state) { 21978 return editor.registerCommand(FORMAT_TEXT_COMMAND2, (formatType) => { 21979 const selection = $getSelection2(); 21980 if ($isNodeSelection2(selection) || $isRangeSelection2(selection)) { 21981 for (const node of selection.getNodes()) { 21982 if ($isDecoratorTextNode(node)) { 21983 node.toggleFormat(formatType); 21984 } 21985 } 21986 } 21987 return false; 21988 }, COMMAND_PRIORITY_LOW2); 21989 } 21990 }); 21991 function watchedSignal(getSnapshot, register) { 21992 let dispose; 21993 return a(getSnapshot(), { 21994 unwatched() { 21995 if (dispose) { 21996 dispose(); 21997 dispose = void 0; 21998 } 21999 }, 22000 watched() { 22001 this.value = getSnapshot(); 22002 dispose = register(this); 22003 } 22004 }); 22005 } 22006 var EditorStateExtension = defineExtension2({ 22007 build(editor) { 22008 return watchedSignal(() => editor.getEditorState(), (editorStateSignal) => editor.registerUpdateListener((payload) => { 22009 editorStateSignal.value = payload.editorState; 22010 })); 22011 }, 22012 name: "@lexical/extension/EditorState" 22013 }); 22014 function formatDevErrorMessage4(message) { 22015 throw new Error(message); 22016 } 22017 function deepThemeMergeInPlace(a2, b3) { 22018 if (a2 && b3 && !Array.isArray(b3) && typeof a2 === "object" && typeof b3 === "object") { 22019 const aObj = a2; 22020 const bObj = b3; 22021 for (const k2 in bObj) { 22022 aObj[k2] = deepThemeMergeInPlace(aObj[k2], bObj[k2]); 22023 } 22024 return a2; 22025 } 22026 return b3; 22027 } 22028 var ExtensionRepStateIds = { 22029 /* eslint-disable sort-keys-fix/sort-keys-fix */ 22030 unmarked: 0, 22031 temporary: 1, 22032 permanent: 2, 22033 configured: 3, 22034 initialized: 4, 22035 built: 5, 22036 registered: 6, 22037 afterRegistration: 7 22038 /* eslint-enable sort-keys-fix/sort-keys-fix */ 22039 }; 22040 function isExactlyUnmarkedExtensionRepState(state) { 22041 return state.id === ExtensionRepStateIds.unmarked; 22042 } 22043 function isExactlyTemporaryExtensionRepState(state) { 22044 return state.id === ExtensionRepStateIds.temporary; 22045 } 22046 function isExactlyPermanentExtensionRepState(state) { 22047 return state.id === ExtensionRepStateIds.permanent; 22048 } 22049 function isConfiguredExtensionRepState(state) { 22050 return state.id >= ExtensionRepStateIds.configured; 22051 } 22052 function isInitializedExtensionRepState(state) { 22053 return state.id >= ExtensionRepStateIds.initialized; 22054 } 22055 function isBuiltExtensionRepState(state) { 22056 return state.id >= ExtensionRepStateIds.built; 22057 } 22058 function isAfterRegistrationState(state) { 22059 return state.id >= ExtensionRepStateIds.afterRegistration; 22060 } 22061 function applyTemporaryMark(state) { 22062 if (!isExactlyUnmarkedExtensionRepState(state)) { 22063 formatDevErrorMessage4(`LexicalBuilder: Can not apply a temporary mark from state id ${String(state.id)} (expected ${String(ExtensionRepStateIds.unmarked)} unmarked)`); 22064 } 22065 return Object.assign(state, { 22066 id: ExtensionRepStateIds.temporary 22067 }); 22068 } 22069 function applyPermanentMark(state) { 22070 if (!isExactlyTemporaryExtensionRepState(state)) { 22071 formatDevErrorMessage4(`LexicalBuilder: Can not apply a permanent mark from state id ${String(state.id)} (expected ${String(ExtensionRepStateIds.temporary)} temporary)`); 22072 } 22073 return Object.assign(state, { 22074 id: ExtensionRepStateIds.permanent 22075 }); 22076 } 22077 function applyConfiguredState(state, config, registerState) { 22078 return Object.assign(state, { 22079 config, 22080 id: ExtensionRepStateIds.configured, 22081 registerState 22082 }); 22083 } 22084 function applyInitializedState(state, initResult, registerState) { 22085 return Object.assign(state, { 22086 id: ExtensionRepStateIds.initialized, 22087 initResult, 22088 registerState 22089 }); 22090 } 22091 function applyBuiltState(state, output, registerState) { 22092 return Object.assign(state, { 22093 id: ExtensionRepStateIds.built, 22094 output, 22095 registerState 22096 }); 22097 } 22098 function applyRegisteredState(state) { 22099 return Object.assign(state, { 22100 id: ExtensionRepStateIds.registered 22101 }); 22102 } 22103 function applyAfterRegistrationState(state) { 22104 return Object.assign(state, { 22105 id: ExtensionRepStateIds.afterRegistration 22106 }); 22107 } 22108 function rollbackToBuiltState(state) { 22109 return Object.assign(state, { 22110 id: ExtensionRepStateIds.built 22111 }); 22112 } 22113 var emptySet = /* @__PURE__ */ new Set(); 22114 var ExtensionRep = class { 22115 builder; 22116 configs; 22117 _dependency; 22118 _peerNameSet; 22119 extension; 22120 state; 22121 _signal; 22122 constructor(builder, extension) { 22123 this.builder = builder; 22124 this.extension = extension; 22125 this.configs = /* @__PURE__ */ new Set(); 22126 this.state = { 22127 id: ExtensionRepStateIds.unmarked 22128 }; 22129 } 22130 mergeConfigs() { 22131 let config = this.extension.config || {}; 22132 const mergeConfig = this.extension.mergeConfig ? this.extension.mergeConfig.bind(this.extension) : shallowMergeConfig2; 22133 for (const cfg of this.configs) { 22134 config = mergeConfig(config, cfg); 22135 } 22136 return config; 22137 } 22138 init(editorConfig) { 22139 const initialState = this.state; 22140 if (!isExactlyPermanentExtensionRepState(initialState)) { 22141 formatDevErrorMessage4(`ExtensionRep: Can not configure from state id ${String(initialState.id)}`); 22142 } 22143 const initState = { 22144 getDependency: this.getInitDependency.bind(this), 22145 getDirectDependentNames: this.getDirectDependentNames.bind(this), 22146 getPeer: this.getInitPeer.bind(this), 22147 getPeerNameSet: this.getPeerNameSet.bind(this) 22148 }; 22149 const buildState = { 22150 ...initState, 22151 getDependency: this.getDependency.bind(this), 22152 getInitResult: this.getInitResult.bind(this), 22153 getPeer: this.getPeer.bind(this) 22154 }; 22155 const state = applyConfiguredState(initialState, this.mergeConfigs(), initState); 22156 this.state = state; 22157 let initResult; 22158 if (this.extension.init) { 22159 initResult = this.extension.init(editorConfig, state.config, initState); 22160 } 22161 this.state = applyInitializedState(state, initResult, buildState); 22162 } 22163 build(editor) { 22164 const state = this.state; 22165 if (!(state.id === ExtensionRepStateIds.initialized)) { 22166 formatDevErrorMessage4(`ExtensionRep: register called in state id ${String(state.id)} (expected ${String(ExtensionRepStateIds.built)} initialized)`); 22167 } 22168 let output; 22169 if (this.extension.build) { 22170 output = this.extension.build(editor, state.config, state.registerState); 22171 } 22172 const registerState = { 22173 ...state.registerState, 22174 getOutput: () => output, 22175 getSignal: this.getSignal.bind(this) 22176 }; 22177 this.state = applyBuiltState(state, output, registerState); 22178 } 22179 register(editor, signal2) { 22180 this._signal = signal2; 22181 const state = this.state; 22182 if (!(state.id === ExtensionRepStateIds.built)) { 22183 formatDevErrorMessage4(`ExtensionRep: register called in state id ${String(state.id)} (expected ${String(ExtensionRepStateIds.built)} built)`); 22184 } 22185 const cleanup = this.extension.register && this.extension.register(editor, state.config, state.registerState); 22186 this.state = applyRegisteredState(state); 22187 return () => { 22188 const afterRegistrationState = this.state; 22189 if (!(afterRegistrationState.id === ExtensionRepStateIds.afterRegistration)) { 22190 formatDevErrorMessage4(`ExtensionRep: rollbackToBuiltState called in state id ${String(state.id)} (expected ${String(ExtensionRepStateIds.afterRegistration)} afterRegistration)`); 22191 } 22192 this.state = rollbackToBuiltState(afterRegistrationState); 22193 if (cleanup) { 22194 cleanup(); 22195 } 22196 }; 22197 } 22198 afterRegistration(editor) { 22199 const state = this.state; 22200 if (!(state.id === ExtensionRepStateIds.registered)) { 22201 formatDevErrorMessage4(`ExtensionRep: afterRegistration called in state id ${String(state.id)} (expected ${String(ExtensionRepStateIds.registered)} registered)`); 22202 } 22203 let rval; 22204 if (this.extension.afterRegistration) { 22205 rval = this.extension.afterRegistration(editor, state.config, state.registerState); 22206 } 22207 this.state = applyAfterRegistrationState(state); 22208 return rval; 22209 } 22210 getSignal() { 22211 if (!(this._signal !== void 0)) { 22212 formatDevErrorMessage4(`ExtensionRep.getSignal() called before register`); 22213 } 22214 return this._signal; 22215 } 22216 getInitResult() { 22217 if (!(this.extension.init !== void 0)) { 22218 formatDevErrorMessage4(`ExtensionRep: getInitResult() called for Extension ${this.extension.name} that does not define init`); 22219 } 22220 const state = this.state; 22221 if (!isInitializedExtensionRepState(state)) { 22222 formatDevErrorMessage4(`ExtensionRep: getInitResult() called for ExtensionRep in state id ${String(state.id)} < ${String(ExtensionRepStateIds.initialized)} (initialized)`); 22223 } 22224 return state.initResult; 22225 } 22226 getInitPeer(name) { 22227 const rep = this.builder.extensionNameMap.get(name); 22228 return rep ? rep.getExtensionInitDependency() : void 0; 22229 } 22230 getExtensionInitDependency() { 22231 const state = this.state; 22232 if (!isConfiguredExtensionRepState(state)) { 22233 formatDevErrorMessage4(`ExtensionRep: getExtensionInitDependency called in state id ${String(state.id)} (expected >= ${String(ExtensionRepStateIds.configured)} configured)`); 22234 } 22235 return { 22236 config: state.config 22237 }; 22238 } 22239 getPeer(name) { 22240 const rep = this.builder.extensionNameMap.get(name); 22241 return rep ? rep.getExtensionDependency() : void 0; 22242 } 22243 getInitDependency(dep) { 22244 const rep = this.builder.getExtensionRep(dep); 22245 if (!(rep !== void 0)) { 22246 formatDevErrorMessage4(`LexicalExtensionBuilder: Extension ${this.extension.name} missing dependency extension ${dep.name} to be in registry`); 22247 } 22248 return rep.getExtensionInitDependency(); 22249 } 22250 getDependency(dep) { 22251 const rep = this.builder.getExtensionRep(dep); 22252 if (!(rep !== void 0)) { 22253 formatDevErrorMessage4(`LexicalExtensionBuilder: Extension ${this.extension.name} missing dependency extension ${dep.name} to be in registry`); 22254 } 22255 return rep.getExtensionDependency(); 22256 } 22257 getState() { 22258 const state = this.state; 22259 if (!isAfterRegistrationState(state)) { 22260 formatDevErrorMessage4(`ExtensionRep getState called in state id ${String(state.id)} (expected ${String(ExtensionRepStateIds.afterRegistration)} afterRegistration)`); 22261 } 22262 return state; 22263 } 22264 getDirectDependentNames() { 22265 return this.builder.incomingEdges.get(this.extension.name) || emptySet; 22266 } 22267 getPeerNameSet() { 22268 let s2 = this._peerNameSet; 22269 if (!s2) { 22270 s2 = new Set((this.extension.peerDependencies || []).map(([name]) => name)); 22271 this._peerNameSet = s2; 22272 } 22273 return s2; 22274 } 22275 getExtensionDependency() { 22276 if (!this._dependency) { 22277 const state = this.state; 22278 if (!isBuiltExtensionRepState(state)) { 22279 formatDevErrorMessage4(`Extension ${this.extension.name} used as a dependency before build`); 22280 } 22281 this._dependency = { 22282 config: state.config, 22283 init: state.initResult, 22284 output: state.output 22285 }; 22286 } 22287 return this._dependency; 22288 } 22289 }; 22290 var HISTORY_MERGE_OPTIONS = { 22291 tag: HISTORY_MERGE_TAG2 22292 }; 22293 function $defaultInitializer() { 22294 const root = $getRoot2(); 22295 if (root.isEmpty()) { 22296 root.append($createParagraphNode2()); 22297 } 22298 } 22299 var InitialStateExtension = defineExtension2({ 22300 config: safeCast2({ 22301 setOptions: HISTORY_MERGE_OPTIONS, 22302 updateOptions: HISTORY_MERGE_OPTIONS 22303 }), 22304 init({ 22305 $initialEditorState = $defaultInitializer 22306 }) { 22307 return { 22308 $initialEditorState, 22309 initialized: false 22310 }; 22311 }, 22312 // eslint-disable-next-line sort-keys-fix/sort-keys-fix -- typescript inference is order dependent here for some reason 22313 afterRegistration(editor, { 22314 updateOptions, 22315 setOptions 22316 }, state) { 22317 const initResult = state.getInitResult(); 22318 if (!initResult.initialized) { 22319 initResult.initialized = true; 22320 const { 22321 $initialEditorState 22322 } = initResult; 22323 if ($isEditorState2($initialEditorState)) { 22324 editor.setEditorState($initialEditorState, setOptions); 22325 } else if (typeof $initialEditorState === "function") { 22326 editor.update(() => { 22327 $initialEditorState(editor); 22328 }, updateOptions); 22329 } else if ($initialEditorState && (typeof $initialEditorState === "string" || typeof $initialEditorState === "object")) { 22330 const parsedEditorState = editor.parseEditorState($initialEditorState); 22331 editor.setEditorState(parsedEditorState, setOptions); 22332 } 22333 } 22334 return () => { 22335 }; 22336 }, 22337 name: "@lexical/extension/InitialState", 22338 // These are automatically added by createEditor, we add them here so they are 22339 // visible during extensionRep.init so extensions can see all known types before the 22340 // editor is created. 22341 // (excluding ArtificialNode__DO_NOT_USE because it isn't really public API 22342 // and shouldn't change anything) 22343 nodes: [RootNode2, TextNode2, LineBreakNode2, TabNode2, ParagraphNode2] 22344 }); 22345 var builderSymbol = Symbol.for("@lexical/extension/LexicalBuilder"); 22346 function buildEditorFromExtensions(...extensions) { 22347 return LexicalBuilder.fromExtensions(extensions).buildEditor(); 22348 } 22349 function noop() { 22350 } 22351 function defaultOnError(err) { 22352 throw err; 22353 } 22354 function maybeWithBuilder(editor) { 22355 return editor; 22356 } 22357 function normalizeExtensionArgument(arg) { 22358 return Array.isArray(arg) ? arg : [arg]; 22359 } 22360 var PACKAGE_VERSION = "0.44.0+dev.esm"; 22361 var LexicalBuilder = class _LexicalBuilder { 22362 roots; 22363 extensionNameMap; 22364 outgoingConfigEdges; 22365 incomingEdges; 22366 conflicts; 22367 _sortedExtensionReps; 22368 PACKAGE_VERSION; 22369 constructor(roots) { 22370 this.outgoingConfigEdges = /* @__PURE__ */ new Map(); 22371 this.incomingEdges = /* @__PURE__ */ new Map(); 22372 this.extensionNameMap = /* @__PURE__ */ new Map(); 22373 this.conflicts = /* @__PURE__ */ new Map(); 22374 this.PACKAGE_VERSION = PACKAGE_VERSION; 22375 this.roots = roots; 22376 for (const extension of roots) { 22377 this.addExtension(extension); 22378 } 22379 } 22380 static fromExtensions(extensions) { 22381 const roots = [normalizeExtensionArgument(InitialStateExtension)]; 22382 for (const extension of extensions) { 22383 roots.push(normalizeExtensionArgument(extension)); 22384 } 22385 return new _LexicalBuilder(roots); 22386 } 22387 static maybeFromEditor(editor) { 22388 const builder = maybeWithBuilder(editor)[builderSymbol]; 22389 if (builder) { 22390 if (!(builder.PACKAGE_VERSION === PACKAGE_VERSION)) { 22391 formatDevErrorMessage4(`LexicalBuilder.fromEditor: The given editor was created with LexicalBuilder ${builder.PACKAGE_VERSION} but this version is ${PACKAGE_VERSION}. A project should have exactly one copy of LexicalBuilder`); 22392 } 22393 if (!(builder instanceof _LexicalBuilder)) { 22394 formatDevErrorMessage4(`LexicalBuilder.fromEditor: There are multiple copies of the same version of LexicalBuilder in your project, and this editor was created with another one. Your project, or one of its dependencies, has its package.json and/or bundler configured incorrectly.`); 22395 } 22396 } 22397 return builder; 22398 } 22399 /** Look up the editor that was created by this LexicalBuilder or throw */ 22400 static fromEditor(editor) { 22401 const builder = _LexicalBuilder.maybeFromEditor(editor); 22402 if (!(builder !== void 0)) { 22403 formatDevErrorMessage4(`LexicalBuilder.fromEditor: The given editor was not created with LexicalBuilder`); 22404 } 22405 return builder; 22406 } 22407 constructEditor() { 22408 const { 22409 $initialEditorState: _$initialEditorState, 22410 onError, 22411 ...editorConfig 22412 } = this.buildCreateEditorArgs(); 22413 const editor = Object.assign(createEditor2({ 22414 ...editorConfig, 22415 ...onError ? { 22416 onError: (err) => { 22417 onError(err, editor); 22418 } 22419 } : {} 22420 }), { 22421 [builderSymbol]: this 22422 }); 22423 for (const extensionRep of this.sortedExtensionReps()) { 22424 extensionRep.build(editor); 22425 } 22426 return editor; 22427 } 22428 buildEditor() { 22429 let disposeOnce = noop; 22430 function dispose() { 22431 try { 22432 disposeOnce(); 22433 } finally { 22434 disposeOnce = noop; 22435 } 22436 } 22437 const editor = Object.assign(this.constructEditor(), { 22438 dispose, 22439 [Symbol.dispose]: dispose 22440 }); 22441 disposeOnce = mergeRegister2(this.registerEditor(editor), () => editor.setRootElement(null)); 22442 return editor; 22443 } 22444 hasExtensionByName(name) { 22445 return this.extensionNameMap.has(name); 22446 } 22447 getExtensionRep(extension) { 22448 const rep = this.extensionNameMap.get(extension.name); 22449 if (rep) { 22450 if (!(rep.extension === extension)) { 22451 formatDevErrorMessage4(`LexicalBuilder: A registered extension with name ${extension.name} exists but does not match the given extension`); 22452 } 22453 return rep; 22454 } 22455 } 22456 addEdge(fromExtensionName, toExtensionName, configs) { 22457 const outgoing = this.outgoingConfigEdges.get(fromExtensionName); 22458 if (outgoing) { 22459 outgoing.set(toExtensionName, configs); 22460 } else { 22461 this.outgoingConfigEdges.set(fromExtensionName, /* @__PURE__ */ new Map([[toExtensionName, configs]])); 22462 } 22463 const incoming = this.incomingEdges.get(toExtensionName); 22464 if (incoming) { 22465 incoming.add(fromExtensionName); 22466 } else { 22467 this.incomingEdges.set(toExtensionName, /* @__PURE__ */ new Set([fromExtensionName])); 22468 } 22469 } 22470 addExtension(arg) { 22471 if (!(this._sortedExtensionReps === void 0)) { 22472 formatDevErrorMessage4(`LexicalBuilder: addExtension called after finalization`); 22473 } 22474 const normalized = normalizeExtensionArgument(arg); 22475 const [extension] = normalized; 22476 if (!(typeof extension.name === "string")) { 22477 formatDevErrorMessage4(`LexicalBuilder: extension name must be string, not ${typeof extension.name}`); 22478 } 22479 let extensionRep = this.extensionNameMap.get(extension.name); 22480 if (!(extensionRep === void 0 || extensionRep.extension === extension)) { 22481 formatDevErrorMessage4(`LexicalBuilder: Multiple extensions registered with name ${extension.name}, names must be unique`); 22482 } 22483 if (!extensionRep) { 22484 extensionRep = new ExtensionRep(this, extension); 22485 this.extensionNameMap.set(extension.name, extensionRep); 22486 const hasConflict = this.conflicts.get(extension.name); 22487 if (typeof hasConflict === "string") { 22488 { 22489 formatDevErrorMessage4(`LexicalBuilder: extension ${extension.name} conflicts with ${hasConflict}`); 22490 } 22491 } 22492 for (const name of extension.conflictsWith || []) { 22493 if (!!this.extensionNameMap.has(name)) { 22494 formatDevErrorMessage4(`LexicalBuilder: extension ${extension.name} conflicts with ${name}`); 22495 } 22496 this.conflicts.set(name, extension.name); 22497 } 22498 for (const dep of extension.dependencies || []) { 22499 const normDep = normalizeExtensionArgument(dep); 22500 this.addEdge(extension.name, normDep[0].name, normDep.slice(1)); 22501 this.addExtension(normDep); 22502 } 22503 for (const [depName, config] of extension.peerDependencies || []) { 22504 this.addEdge(extension.name, depName, config ? [config] : []); 22505 } 22506 } 22507 } 22508 sortedExtensionReps() { 22509 if (this._sortedExtensionReps) { 22510 return this._sortedExtensionReps; 22511 } 22512 const sortedExtensionReps = []; 22513 const visit = (rep, fromExtensionName) => { 22514 let mark = rep.state; 22515 if (isExactlyPermanentExtensionRepState(mark)) { 22516 return; 22517 } 22518 const extensionName = rep.extension.name; 22519 if (!isExactlyUnmarkedExtensionRepState(mark)) { 22520 formatDevErrorMessage4(`LexicalBuilder: Circular dependency detected for Extension ${extensionName} from ${fromExtensionName || "[unknown]"}`); 22521 } 22522 mark = applyTemporaryMark(mark); 22523 rep.state = mark; 22524 const outgoingConfigEdges = this.outgoingConfigEdges.get(extensionName); 22525 if (outgoingConfigEdges) { 22526 for (const toExtensionName of outgoingConfigEdges.keys()) { 22527 const toRep = this.extensionNameMap.get(toExtensionName); 22528 if (toRep) { 22529 visit(toRep, extensionName); 22530 } 22531 } 22532 } 22533 mark = applyPermanentMark(mark); 22534 rep.state = mark; 22535 sortedExtensionReps.push(rep); 22536 }; 22537 for (const rep of this.extensionNameMap.values()) { 22538 if (isExactlyUnmarkedExtensionRepState(rep.state)) { 22539 visit(rep); 22540 } 22541 } 22542 for (const rep of sortedExtensionReps) { 22543 for (const [toExtensionName, configs] of this.outgoingConfigEdges.get(rep.extension.name) || []) { 22544 if (configs.length > 0) { 22545 const toRep = this.extensionNameMap.get(toExtensionName); 22546 if (toRep) { 22547 for (const config of configs) { 22548 toRep.configs.add(config); 22549 } 22550 } 22551 } 22552 } 22553 } 22554 for (const [extension, ...configs] of this.roots) { 22555 if (configs.length > 0) { 22556 const toRep = this.extensionNameMap.get(extension.name); 22557 if (!(toRep !== void 0)) { 22558 formatDevErrorMessage4(`LexicalBuilder: Expecting existing ExtensionRep for ${extension.name}`); 22559 } 22560 for (const config of configs) { 22561 toRep.configs.add(config); 22562 } 22563 } 22564 } 22565 this._sortedExtensionReps = sortedExtensionReps; 22566 return this._sortedExtensionReps; 22567 } 22568 registerEditor(editor) { 22569 const extensionReps = this.sortedExtensionReps(); 22570 const controller = new AbortController(); 22571 const cleanups = [() => controller.abort()]; 22572 const signal2 = controller.signal; 22573 for (const extensionRep of extensionReps) { 22574 const cleanup = extensionRep.register(editor, signal2); 22575 if (cleanup) { 22576 cleanups.push(cleanup); 22577 } 22578 } 22579 for (const extensionRep of extensionReps) { 22580 const cleanup = extensionRep.afterRegistration(editor); 22581 if (cleanup) { 22582 cleanups.push(cleanup); 22583 } 22584 } 22585 return mergeRegister2(...cleanups); 22586 } 22587 buildCreateEditorArgs() { 22588 const config = {}; 22589 const nodes = /* @__PURE__ */ new Set(); 22590 const replacedNodes = /* @__PURE__ */ new Map(); 22591 const htmlExport = /* @__PURE__ */ new Map(); 22592 const htmlImport = {}; 22593 const theme2 = {}; 22594 const extensionReps = this.sortedExtensionReps(); 22595 for (const extensionRep of extensionReps) { 22596 const { 22597 extension 22598 } = extensionRep; 22599 if (extension.onError !== void 0) { 22600 config.onError = extension.onError; 22601 } 22602 if (extension.disableEvents !== void 0) { 22603 config.disableEvents = extension.disableEvents; 22604 } 22605 if (extension.parentEditor !== void 0) { 22606 config.parentEditor = extension.parentEditor; 22607 } 22608 if (extension.editable !== void 0) { 22609 config.editable = extension.editable; 22610 } 22611 if (extension.namespace !== void 0) { 22612 config.namespace = extension.namespace; 22613 } 22614 if (extension.$initialEditorState !== void 0) { 22615 config.$initialEditorState = extension.$initialEditorState; 22616 } 22617 if (extension.nodes) { 22618 for (const node of getNodeConfig(extension)) { 22619 if (typeof node !== "function") { 22620 const conflictExtension = replacedNodes.get(node.replace); 22621 if (conflictExtension) { 22622 { 22623 formatDevErrorMessage4(`LexicalBuilder: Extension ${extension.name} can not register replacement for node ${node.replace.name} because ${conflictExtension.extension.name} already did`); 22624 } 22625 } 22626 replacedNodes.set(node.replace, extensionRep); 22627 } 22628 nodes.add(node); 22629 } 22630 } 22631 if (extension.html) { 22632 if (extension.html.export) { 22633 for (const [k2, v3] of extension.html.export.entries()) { 22634 htmlExport.set(k2, v3); 22635 } 22636 } 22637 if (extension.html.import) { 22638 Object.assign(htmlImport, extension.html.import); 22639 } 22640 } 22641 if (extension.theme) { 22642 deepThemeMergeInPlace(theme2, extension.theme); 22643 } 22644 } 22645 if (Object.keys(theme2).length > 0) { 22646 config.theme = theme2; 22647 } 22648 if (nodes.size) { 22649 config.nodes = [...nodes]; 22650 } 22651 const hasImport = Object.keys(htmlImport).length > 0; 22652 const hasExport = htmlExport.size > 0; 22653 if (hasImport || hasExport) { 22654 config.html = {}; 22655 if (hasImport) { 22656 config.html.import = htmlImport; 22657 } 22658 if (hasExport) { 22659 config.html.export = htmlExport; 22660 } 22661 } 22662 for (const extensionRep of extensionReps) { 22663 extensionRep.init(config); 22664 } 22665 if (!config.onError) { 22666 config.onError = defaultOnError; 22667 } 22668 return config; 22669 } 22670 }; 22671 function getExtensionDependencyFromEditor(editor, extension) { 22672 const builder = LexicalBuilder.fromEditor(editor); 22673 const rep = builder.getExtensionRep(extension); 22674 if (!(rep !== void 0)) { 22675 formatDevErrorMessage4(`getExtensionDependencyFromEditor: Extension ${extension.name} was not built when creating this editor`); 22676 } 22677 return rep.getExtensionDependency(); 22678 } 22679 function getPeerDependencyFromEditor(editor, extensionName) { 22680 const builder = LexicalBuilder.maybeFromEditor(editor); 22681 if (!builder) return void 0; 22682 const peer = builder.extensionNameMap.get(extensionName); 22683 return peer ? peer.getExtensionDependency() : void 0; 22684 } 22685 function getPeerDependencyFromEditorOrThrow(editor, extensionName) { 22686 const dep = getPeerDependencyFromEditor(editor, extensionName); 22687 if (!(dep !== void 0)) { 22688 formatDevErrorMessage4(`getPeerDependencyFromEditorOrThrow: Editor was not built with Extension ${extensionName}`); 22689 } 22690 return dep; 22691 } 22692 var EMPTY_SET = /* @__PURE__ */ new Set(); 22693 var NodeSelectionExtension = defineExtension2({ 22694 build(editor, config, state) { 22695 const editorStateStore = state.getDependency(EditorStateExtension).output; 22696 const watchedNodeStore = a({ 22697 watchedNodeKeys: /* @__PURE__ */ new Map() 22698 }); 22699 const selectedNodeKeys = watchedSignal(() => void 0, () => j(() => { 22700 const prevSelectedNodeKeys = selectedNodeKeys.peek(); 22701 const { 22702 watchedNodeKeys 22703 } = watchedNodeStore.value; 22704 let nextSelectedNodeKeys; 22705 let didChange = false; 22706 editorStateStore.value.read(() => { 22707 const selection = $getSelection2(); 22708 if (selection) { 22709 for (const [key, listeners] of watchedNodeKeys.entries()) { 22710 if (listeners.size === 0) { 22711 watchedNodeKeys.delete(key); 22712 continue; 22713 } 22714 const node = $getNodeByKey2(key); 22715 const isSelected = node && node.isSelected() || false; 22716 didChange = didChange || isSelected !== (prevSelectedNodeKeys ? prevSelectedNodeKeys.has(key) : false); 22717 if (isSelected) { 22718 nextSelectedNodeKeys = nextSelectedNodeKeys || /* @__PURE__ */ new Set(); 22719 nextSelectedNodeKeys.add(key); 22720 } 22721 } 22722 } 22723 }); 22724 if (!(!didChange && nextSelectedNodeKeys && prevSelectedNodeKeys && nextSelectedNodeKeys.size === prevSelectedNodeKeys.size)) { 22725 selectedNodeKeys.value = nextSelectedNodeKeys; 22726 } 22727 })); 22728 function watchNodeKey(key) { 22729 const watcher = g(() => (selectedNodeKeys.value || EMPTY_SET).has(key)); 22730 const { 22731 watchedNodeKeys 22732 } = watchedNodeStore.peek(); 22733 let listeners = watchedNodeKeys.get(key); 22734 const hadListener = listeners !== void 0; 22735 listeners = listeners || /* @__PURE__ */ new Set(); 22736 listeners.add(watcher); 22737 if (!hadListener) { 22738 watchedNodeKeys.set(key, listeners); 22739 watchedNodeStore.value = { 22740 watchedNodeKeys 22741 }; 22742 } 22743 return watcher; 22744 } 22745 return { 22746 watchNodeKey 22747 }; 22748 }, 22749 dependencies: [EditorStateExtension], 22750 name: "@lexical/extension/NodeSelection" 22751 }); 22752 var INSERT_HORIZONTAL_RULE_COMMAND = createCommand2("INSERT_HORIZONTAL_RULE_COMMAND"); 22753 var HorizontalRuleNode = class _HorizontalRuleNode extends DecoratorNode2 { 22754 static getType() { 22755 return "horizontalrule"; 22756 } 22757 static clone(node) { 22758 return new _HorizontalRuleNode(node.__key); 22759 } 22760 static importJSON(serializedNode) { 22761 return $createHorizontalRuleNode().updateFromJSON(serializedNode); 22762 } 22763 static importDOM() { 22764 return { 22765 hr: () => ({ 22766 conversion: $convertHorizontalRuleElement, 22767 priority: 0 22768 }) 22769 }; 22770 } 22771 exportDOM() { 22772 return { 22773 element: document.createElement("hr") 22774 }; 22775 } 22776 createDOM(config) { 22777 const element = document.createElement("hr"); 22778 addClassNamesToElement2(element, config.theme.hr); 22779 return element; 22780 } 22781 getTextContent() { 22782 return "\n"; 22783 } 22784 isInline() { 22785 return false; 22786 } 22787 updateDOM() { 22788 return false; 22789 } 22790 }; 22791 function $convertHorizontalRuleElement() { 22792 return { 22793 node: $createHorizontalRuleNode() 22794 }; 22795 } 22796 function $createHorizontalRuleNode() { 22797 return $create2(HorizontalRuleNode); 22798 } 22799 function $isHorizontalRuleNode(node) { 22800 return node instanceof HorizontalRuleNode; 22801 } 22802 function $toggleNodeSelection(node, shiftKey = false) { 22803 const selection = $getSelection2(); 22804 const wasSelected = node.isSelected(); 22805 const key = node.getKey(); 22806 let nodeSelection; 22807 if (shiftKey && $isNodeSelection2(selection)) { 22808 nodeSelection = selection; 22809 } else { 22810 nodeSelection = $createNodeSelection2(); 22811 $setSelection2(nodeSelection); 22812 } 22813 if (wasSelected) { 22814 nodeSelection.delete(key); 22815 } else { 22816 nodeSelection.add(key); 22817 } 22818 } 22819 var HorizontalRuleExtension = defineExtension2({ 22820 dependencies: [EditorStateExtension, NodeSelectionExtension], 22821 name: "@lexical/extension/HorizontalRule", 22822 nodes: () => [HorizontalRuleNode], 22823 register(editor, config, state) { 22824 const { 22825 watchNodeKey 22826 } = state.getDependency(NodeSelectionExtension).output; 22827 const nodeSelectionStore = a({ 22828 nodeSelections: /* @__PURE__ */ new Map() 22829 }); 22830 const isSelectedClassName = editor._config.theme.hrSelected ?? "selected"; 22831 return mergeRegister2(editor.registerCommand(INSERT_HORIZONTAL_RULE_COMMAND, (type) => { 22832 const selection = $getSelection2(); 22833 if (!$isRangeSelection2(selection)) { 22834 return false; 22835 } 22836 const focusNode = selection.focus.getNode(); 22837 if (focusNode !== null) { 22838 const horizontalRuleNode = $createHorizontalRuleNode(); 22839 $insertNodeToNearestRoot2(horizontalRuleNode); 22840 } 22841 return true; 22842 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(CLICK_COMMAND2, (event) => { 22843 if (isDOMNode2(event.target)) { 22844 const node = $getNodeFromDOMNode2(event.target); 22845 if ($isHorizontalRuleNode(node)) { 22846 $toggleNodeSelection(node, event.shiftKey); 22847 return true; 22848 } 22849 } 22850 return false; 22851 }, COMMAND_PRIORITY_LOW2), editor.registerMutationListener(HorizontalRuleNode, (nodes, payload) => { 22852 n(() => { 22853 let didChange = false; 22854 const { 22855 nodeSelections 22856 } = nodeSelectionStore.peek(); 22857 for (const [k2, v3] of nodes.entries()) { 22858 if (v3 === "destroyed") { 22859 nodeSelections.delete(k2); 22860 didChange = true; 22861 } else { 22862 const prev = nodeSelections.get(k2); 22863 const dom = editor.getElementByKey(k2); 22864 if (prev) { 22865 prev.domNode.value = dom; 22866 } else { 22867 didChange = true; 22868 nodeSelections.set(k2, { 22869 domNode: a(dom), 22870 selectedSignal: watchNodeKey(k2) 22871 }); 22872 } 22873 } 22874 } 22875 if (didChange) { 22876 nodeSelectionStore.value = { 22877 nodeSelections 22878 }; 22879 } 22880 }); 22881 }), j(() => { 22882 const effects = []; 22883 for (const { 22884 domNode, 22885 selectedSignal 22886 } of nodeSelectionStore.value.nodeSelections.values()) { 22887 effects.push(j(() => { 22888 const dom = domNode.value; 22889 if (dom) { 22890 const isSelected = selectedSignal.value; 22891 if (isSelected) { 22892 addClassNamesToElement2(dom, isSelectedClassName); 22893 } else { 22894 removeClassNamesFromElement2(dom, isSelectedClassName); 22895 } 22896 } 22897 })); 22898 } 22899 return mergeRegister2(...effects); 22900 })); 22901 } 22902 }); 22903 function $defaultGetParentEditor() { 22904 const editor = $getEditor2(); 22905 LexicalBuilder.fromEditor(editor); 22906 return editor; 22907 } 22908 var NestedEditorExtension = defineExtension2({ 22909 build: (editor, config) => namedSignals({ 22910 inheritEditableFromParent: config.inheritEditableFromParent 22911 }), 22912 config: safeCast2({ 22913 $getParentEditor: $defaultGetParentEditor, 22914 inheritEditableFromParent: false 22915 }), 22916 init: (editorConfig, config, state) => { 22917 const parentEditor = config.$getParentEditor(); 22918 editorConfig.parentEditor = parentEditor; 22919 editorConfig.theme = editorConfig.theme || parentEditor._config.theme; 22920 }, 22921 name: "@lexical/extension/NestedEditor", 22922 register: (editor, config, state) => j(() => { 22923 const parentEditor = editor._parentEditor; 22924 if (parentEditor) { 22925 if (state.getOutput().inheritEditableFromParent.value) { 22926 editor.setEditable(parentEditor.isEditable()); 22927 return parentEditor.registerEditableListener(editor.setEditable.bind(editor)); 22928 } 22929 } 22930 }) 22931 }); 22932 var SelectionAlwaysOnDisplayExtension = defineExtension2({ 22933 build: (editor, config, state) => namedSignals(config), 22934 config: safeCast2({ 22935 disabled: false, 22936 onReposition: void 0 22937 }), 22938 name: "@lexical/utils/SelectionAlwaysOnDisplay", 22939 register: (editor, config, state) => { 22940 const stores = state.getOutput(); 22941 return j(() => { 22942 if (!stores.disabled.value) { 22943 return selectionAlwaysOnDisplay2(editor, stores.onReposition.value); 22944 } 22945 }); 22946 } 22947 }); 22948 function $indentOverTab(selection) { 22949 const nodes = selection.getNodes(); 22950 const canIndentBlockNodes = nodes.filter((node) => $isBlockElementNode2(node) && node.canIndent()); 22951 if (canIndentBlockNodes.length > 0) { 22952 return true; 22953 } 22954 const anchor = selection.anchor; 22955 const focus = selection.focus; 22956 const first = focus.isBefore(anchor) ? focus : anchor; 22957 const firstNode = first.getNode(); 22958 const firstBlock = $getNearestBlockElementAncestorOrThrow2(firstNode); 22959 if (firstBlock.canIndent()) { 22960 const firstBlockKey = firstBlock.getKey(); 22961 let selectionAtStart = $createRangeSelection2(); 22962 selectionAtStart.anchor.set(firstBlockKey, 0, "element"); 22963 selectionAtStart.focus.set(firstBlockKey, 0, "element"); 22964 selectionAtStart = $normalizeSelection__EXPERIMENTAL(selectionAtStart); 22965 if (selectionAtStart.anchor.is(first)) { 22966 return true; 22967 } 22968 } 22969 return false; 22970 } 22971 function $defaultCanIndent(node) { 22972 return node.canBeEmpty(); 22973 } 22974 function registerTabIndentation(editor, maxIndent, $canIndent = $defaultCanIndent) { 22975 return mergeRegister2(editor.registerCommand(KEY_TAB_COMMAND2, (event) => { 22976 const selection = $getSelection2(); 22977 if (!$isRangeSelection2(selection)) { 22978 return false; 22979 } 22980 event.preventDefault(); 22981 const command = $indentOverTab(selection) ? event.shiftKey ? OUTDENT_CONTENT_COMMAND2 : INDENT_CONTENT_COMMAND2 : INSERT_TAB_COMMAND2; 22982 return editor.dispatchCommand(command, void 0); 22983 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(INDENT_CONTENT_COMMAND2, () => { 22984 const currentMaxIndent = typeof maxIndent === "number" ? maxIndent : maxIndent ? maxIndent.peek() : null; 22985 const selection = $getSelection2(); 22986 if (!$isRangeSelection2(selection)) { 22987 return false; 22988 } 22989 const $currentCanIndent = typeof $canIndent === "function" ? $canIndent : $canIndent.peek(); 22990 return $handleIndentAndOutdent2((block) => { 22991 if ($currentCanIndent(block)) { 22992 const newIndent = block.getIndent() + 1; 22993 if (!currentMaxIndent || newIndent < currentMaxIndent) { 22994 block.setIndent(newIndent); 22995 } 22996 } 22997 }); 22998 }, COMMAND_PRIORITY_CRITICAL2)); 22999 } 23000 var TabIndentationExtension = defineExtension2({ 23001 build(editor, config, state) { 23002 return namedSignals(config); 23003 }, 23004 config: safeCast2({ 23005 $canIndent: $defaultCanIndent, 23006 disabled: false, 23007 maxIndent: null 23008 }), 23009 name: "@lexical/extension/TabIndentation", 23010 register(editor, config, state) { 23011 const { 23012 disabled, 23013 maxIndent, 23014 $canIndent 23015 } = state.getOutput(); 23016 return j(() => { 23017 if (!disabled.value) { 23018 return registerTabIndentation(editor, maxIndent, $canIndent); 23019 } 23020 }); 23021 } 23022 }); 23023 23024
vendor: 2,222 bytes, lines 23024-23065
23024// node_modules/@lexical/extension/LexicalExtension.mjs 23025 var mod4 = true ? LexicalExtension_dev_exports : LexicalExtension_prod_exports; 23026 var $createHorizontalRuleNode2 = mod4.$createHorizontalRuleNode; 23027 var $isDecoratorTextNode2 = mod4.$isDecoratorTextNode; 23028 var $isHorizontalRuleNode2 = mod4.$isHorizontalRuleNode; 23029 var AutoFocusExtension2 = mod4.AutoFocusExtension; 23030 var ClearEditorExtension2 = mod4.ClearEditorExtension; 23031 var DecoratorTextExtension2 = mod4.DecoratorTextExtension; 23032 var DecoratorTextNode2 = mod4.DecoratorTextNode; 23033 var EditorStateExtension2 = mod4.EditorStateExtension; 23034 var HorizontalRuleExtension2 = mod4.HorizontalRuleExtension; 23035 var HorizontalRuleNode2 = mod4.HorizontalRuleNode; 23036 var INSERT_HORIZONTAL_RULE_COMMAND2 = mod4.INSERT_HORIZONTAL_RULE_COMMAND; 23037 var InitialStateExtension2 = mod4.InitialStateExtension; 23038 var LexicalBuilder2 = mod4.LexicalBuilder; 23039 var NestedEditorExtension2 = mod4.NestedEditorExtension; 23040 var NodeSelectionExtension2 = mod4.NodeSelectionExtension; 23041 var SelectionAlwaysOnDisplayExtension2 = mod4.SelectionAlwaysOnDisplayExtension; 23042 var TabIndentationExtension2 = mod4.TabIndentationExtension; 23043 var applyFormatFromStyle2 = mod4.applyFormatFromStyle; 23044 var applyFormatToDom2 = mod4.applyFormatToDom; 23045 var batch = mod4.batch; 23046 var buildEditorFromExtensions2 = mod4.buildEditorFromExtensions; 23047 var computed = mod4.computed; 23048 var configExtension3 = mod4.configExtension; 23049 var declarePeerDependency3 = mod4.declarePeerDependency; 23050 var defineExtension3 = mod4.defineExtension; 23051 var effect = mod4.effect; 23052 var getExtensionDependencyFromEditor2 = mod4.getExtensionDependencyFromEditor; 23053 var getKnownTypesAndNodes2 = mod4.getKnownTypesAndNodes; 23054 var getPeerDependencyFromEditor2 = mod4.getPeerDependencyFromEditor; 23055 var getPeerDependencyFromEditorOrThrow2 = mod4.getPeerDependencyFromEditorOrThrow; 23056 var namedSignals2 = mod4.namedSignals; 23057 var registerClearEditor2 = mod4.registerClearEditor; 23058 var registerTabIndentation2 = mod4.registerTabIndentation; 23059 var safeCast3 = mod4.safeCast; 23060 var shallowMergeConfig3 = mod4.shallowMergeConfig; 23061 var signal = mod4.signal; 23062 var untracked = mod4.untracked; 23063 var watchedSignal2 = mod4.watchedSignal; 23064 23065
vendor: 39,032 bytes, lines 23065-24196
23065// node_modules/@lexical/link/LexicalLink.dev.mjs 23066 function formatDevErrorMessage5(message) { 23067 throw new Error(message); 23068 } 23069 var SUPPORTED_URL_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:", "mailto:", "sms:", "tel:"]); 23070 var LinkNode = class _LinkNode extends ElementNode2 { 23071 /** @internal */ 23072 __url; 23073 /** @internal */ 23074 __target; 23075 /** @internal */ 23076 __rel; 23077 /** @internal */ 23078 __title; 23079 static getType() { 23080 return "link"; 23081 } 23082 static clone(node) { 23083 return new _LinkNode(node.__url, { 23084 rel: node.__rel, 23085 target: node.__target, 23086 title: node.__title 23087 }, node.__key); 23088 } 23089 constructor(url = "", attributes = {}, key) { 23090 super(key); 23091 const { 23092 target = null, 23093 rel = null, 23094 title = null 23095 } = attributes; 23096 this.__url = url; 23097 this.__target = target; 23098 this.__rel = rel; 23099 this.__title = title; 23100 } 23101 afterCloneFrom(prevNode) { 23102 super.afterCloneFrom(prevNode); 23103 this.__url = prevNode.__url; 23104 this.__rel = prevNode.__rel; 23105 this.__target = prevNode.__target; 23106 this.__title = prevNode.__title; 23107 } 23108 createDOM(config) { 23109 const element = document.createElement("a"); 23110 this.updateLinkDOM(null, element, config); 23111 addClassNamesToElement3(element, config.theme.link); 23112 return element; 23113 } 23114 updateLinkDOM(prevNode, anchor, config) { 23115 if (isHTMLAnchorElement3(anchor)) { 23116 if (!prevNode || prevNode.__url !== this.__url) { 23117 anchor.href = this.sanitizeUrl(this.__url); 23118 } 23119 for (const attr of ["target", "rel", "title"]) { 23120 const key = `__${attr}`; 23121 const value = this[key]; 23122 if (!prevNode || prevNode[key] !== value) { 23123 if (value) { 23124 anchor[attr] = value; 23125 } else { 23126 anchor.removeAttribute(attr); 23127 } 23128 } 23129 } 23130 } 23131 } 23132 updateDOM(prevNode, anchor, config) { 23133 this.updateLinkDOM(prevNode, anchor, config); 23134 return false; 23135 } 23136 static importDOM() { 23137 return { 23138 a: (node) => ({ 23139 conversion: $convertAnchorElement, 23140 priority: 1 23141 }) 23142 }; 23143 } 23144 static importJSON(serializedNode) { 23145 return $createLinkNode().updateFromJSON(serializedNode); 23146 } 23147 updateFromJSON(serializedNode) { 23148 return super.updateFromJSON(serializedNode).setURL(serializedNode.url).setRel(serializedNode.rel || null).setTarget(serializedNode.target || null).setTitle(serializedNode.title || null); 23149 } 23150 sanitizeUrl(url) { 23151 url = formatUrl(url); 23152 try { 23153 const parsedUrl = new URL(formatUrl(url)); 23154 if (!SUPPORTED_URL_PROTOCOLS.has(parsedUrl.protocol)) { 23155 return "about:blank"; 23156 } 23157 } catch (_unused) { 23158 return url; 23159 } 23160 return url; 23161 } 23162 exportJSON() { 23163 return { 23164 ...super.exportJSON(), 23165 rel: this.getRel(), 23166 target: this.getTarget(), 23167 title: this.getTitle(), 23168 url: this.getURL() 23169 }; 23170 } 23171 getURL() { 23172 return this.getLatest().__url; 23173 } 23174 setURL(url) { 23175 const writable = this.getWritable(); 23176 writable.__url = url; 23177 return writable; 23178 } 23179 getTarget() { 23180 return this.getLatest().__target; 23181 } 23182 setTarget(target) { 23183 const writable = this.getWritable(); 23184 writable.__target = target; 23185 return writable; 23186 } 23187 getRel() { 23188 return this.getLatest().__rel; 23189 } 23190 setRel(rel) { 23191 const writable = this.getWritable(); 23192 writable.__rel = rel; 23193 return writable; 23194 } 23195 getTitle() { 23196 return this.getLatest().__title; 23197 } 23198 setTitle(title) { 23199 const writable = this.getWritable(); 23200 writable.__title = title; 23201 return writable; 23202 } 23203 insertNewAfter(_3, restoreSelection = true) { 23204 const linkNode = $copyNode2(this); 23205 this.insertAfter(linkNode, restoreSelection); 23206 return linkNode; 23207 } 23208 canInsertTextBefore() { 23209 return false; 23210 } 23211 canInsertTextAfter() { 23212 return false; 23213 } 23214 canBeEmpty() { 23215 return false; 23216 } 23217 isInline() { 23218 return true; 23219 } 23220 extractWithChild(child, selection, destination) { 23221 if (!$isRangeSelection2(selection)) { 23222 return false; 23223 } 23224 const anchorNode = selection.anchor.getNode(); 23225 const focusNode = selection.focus.getNode(); 23226 return this.isParentOf(anchorNode) && this.isParentOf(focusNode) && selection.getTextContent().length > 0; 23227 } 23228 isEmailURI() { 23229 return this.__url.startsWith("mailto:"); 23230 } 23231 isWebSiteURI() { 23232 return this.__url.startsWith("https://") || this.__url.startsWith("http://"); 23233 } 23234 shouldMergeAdjacentLink(otherLink) { 23235 return this.getType() === otherLink.getType() && this.__url === otherLink.__url && this.__target === otherLink.__target && this.__rel === otherLink.__rel && this.__title === otherLink.__title; 23236 } 23237 }; 23238 function $saveCaretPair(point) { 23239 const next = $caretFromPoint2(point, "next"); 23240 return [next, next.getFlipped()]; 23241 } 23242 function $restoreCaretPair(point, pair) { 23243 for (const caret of pair) { 23244 if (caret.origin.isAttached()) { 23245 const normalized = $normalizeCaret2(caret); 23246 $setPointFromCaret2(point, normalized); 23247 return; 23248 } 23249 } 23250 } 23251 function $linkNodeTransform(link) { 23252 const selection = $getSelection2(); 23253 let anchorPair = null; 23254 let focusPair = null; 23255 if ($isRangeSelection2(selection)) { 23256 anchorPair = $saveCaretPair(selection.anchor); 23257 focusPair = $saveCaretPair(selection.focus); 23258 } 23259 function $restoreSelection() { 23260 if ($isRangeSelection2(selection)) { 23261 $restoreCaretPair(selection.anchor, anchorPair); 23262 $restoreCaretPair(selection.focus, focusPair); 23263 $normalizeSelection__EXPERIMENTAL(selection); 23264 } 23265 } 23266 let transformed = false; 23267 for (const caret of $getChildCaret2(link, "next")) { 23268 const node = caret.origin; 23269 if ($isElementNode2(node) && !node.isInline()) { 23270 const blockChildren = node.getChildren(); 23271 if (blockChildren.length > 0) { 23272 const innerLink = $copyNode2(link); 23273 innerLink.append(...blockChildren); 23274 node.append(innerLink); 23275 transformed = true; 23276 } 23277 $insertNodeToNearestRootAtCaret2(node, $rewindSiblingCaret2(caret), { 23278 $shouldSplit: () => false 23279 }); 23280 } 23281 } 23282 function $fixMergeBoundaryCaret(pair, absorbingLink, mergingLink) { 23283 const [next, prev] = pair; 23284 const $isAffected = (caret) => $isSiblingCaret2(caret) && caret.origin.is(absorbingLink); 23285 if (!$isAffected(next) && !$isAffected(prev)) { 23286 return pair; 23287 } 23288 const fixed = $normalizeCaret2($getChildCaret2(mergingLink, "next")); 23289 return [fixed, fixed.getFlipped()]; 23290 } 23291 if (link.isAttached()) { 23292 const prevSibling = link.getPreviousSibling(); 23293 if ($isLinkNode(prevSibling) && prevSibling.shouldMergeAdjacentLink(link)) { 23294 if (anchorPair) { 23295 anchorPair = $fixMergeBoundaryCaret(anchorPair, prevSibling, link); 23296 } 23297 if (focusPair) { 23298 focusPair = $fixMergeBoundaryCaret(focusPair, prevSibling, link); 23299 } 23300 prevSibling.append(...link.getChildren()); 23301 link.remove(); 23302 $restoreSelection(); 23303 return; 23304 } 23305 const nextSibling = link.getNextSibling(); 23306 if ($isLinkNode(nextSibling) && link.shouldMergeAdjacentLink(nextSibling)) { 23307 if (anchorPair) { 23308 anchorPair = $fixMergeBoundaryCaret(anchorPair, link, nextSibling); 23309 } 23310 if (focusPair) { 23311 focusPair = $fixMergeBoundaryCaret(focusPair, link, nextSibling); 23312 } 23313 link.append(...nextSibling.getChildren()); 23314 nextSibling.remove(); 23315 transformed = true; 23316 } 23317 } 23318 if (!transformed) { 23319 return; 23320 } 23321 if (!link.canBeEmpty() && link.isEmpty()) { 23322 const parent = link.getParent(); 23323 link.remove(); 23324 if (parent && parent.isEmpty()) { 23325 parent.remove(); 23326 } 23327 } 23328 $restoreSelection(); 23329 } 23330 function $convertAnchorElement(domNode) { 23331 let node = null; 23332 if (isHTMLAnchorElement3(domNode)) { 23333 const content = domNode.textContent; 23334 if (content !== null && content !== "" || domNode.children.length > 0) { 23335 node = $createLinkNode(domNode.getAttribute("href") || "", { 23336 rel: domNode.getAttribute("rel"), 23337 target: domNode.getAttribute("target"), 23338 title: domNode.getAttribute("title") 23339 }); 23340 } 23341 } 23342 return { 23343 node 23344 }; 23345 } 23346 function $createLinkNode(url = "", attributes) { 23347 return $applyNodeReplacement2(new LinkNode(url, attributes)); 23348 } 23349 function $isLinkNode(node) { 23350 return node instanceof LinkNode; 23351 } 23352 var AutoLinkNode = class _AutoLinkNode extends LinkNode { 23353 /** @internal */ 23354 /** Indicates whether the autolink was ever unlinked. **/ 23355 __isUnlinked; 23356 constructor(url = "", attributes = {}, key) { 23357 super(url, attributes, key); 23358 this.__isUnlinked = attributes.isUnlinked !== void 0 && attributes.isUnlinked !== null ? attributes.isUnlinked : false; 23359 } 23360 afterCloneFrom(prevNode) { 23361 super.afterCloneFrom(prevNode); 23362 this.__isUnlinked = prevNode.__isUnlinked; 23363 } 23364 static getType() { 23365 return "autolink"; 23366 } 23367 static clone(node) { 23368 return new _AutoLinkNode(node.__url, { 23369 isUnlinked: node.__isUnlinked, 23370 rel: node.__rel, 23371 target: node.__target, 23372 title: node.__title 23373 }, node.__key); 23374 } 23375 shouldMergeAdjacentLink(_otherLink) { 23376 return false; 23377 } 23378 getIsUnlinked() { 23379 return this.__isUnlinked; 23380 } 23381 setIsUnlinked(value) { 23382 const self2 = this.getWritable(); 23383 self2.__isUnlinked = value; 23384 return self2; 23385 } 23386 createDOM(config) { 23387 if (this.__isUnlinked) { 23388 return document.createElement("span"); 23389 } else { 23390 return super.createDOM(config); 23391 } 23392 } 23393 updateDOM(prevNode, anchor, config) { 23394 return super.updateDOM(prevNode, anchor, config) || prevNode.__isUnlinked !== this.__isUnlinked; 23395 } 23396 static importJSON(serializedNode) { 23397 return $createAutoLinkNode().updateFromJSON(serializedNode); 23398 } 23399 updateFromJSON(serializedNode) { 23400 return super.updateFromJSON(serializedNode).setIsUnlinked(serializedNode.isUnlinked || false); 23401 } 23402 static importDOM() { 23403 return null; 23404 } 23405 exportJSON() { 23406 return { 23407 ...super.exportJSON(), 23408 isUnlinked: this.__isUnlinked 23409 }; 23410 } 23411 insertNewAfter(_3, restoreSelection = true) { 23412 const linkNode = $createAutoLinkNode(this.__url, { 23413 isUnlinked: this.__isUnlinked, 23414 rel: this.__rel, 23415 target: this.__target, 23416 title: this.__title 23417 }); 23418 this.insertAfter(linkNode, restoreSelection); 23419 return linkNode; 23420 } 23421 }; 23422 function $createAutoLinkNode(url = "", attributes) { 23423 return $applyNodeReplacement2(new AutoLinkNode(url, attributes)); 23424 } 23425 function $isAutoLinkNode(node) { 23426 return node instanceof AutoLinkNode; 23427 } 23428 var TOGGLE_LINK_COMMAND = createCommand2("TOGGLE_LINK_COMMAND"); 23429 function $getPointNode(point, offset3) { 23430 if (point.type === "element") { 23431 const node = point.getNode(); 23432 if (!$isElementNode2(node)) { 23433 formatDevErrorMessage5(`$getPointNode: element point is not an ElementNode`); 23434 } 23435 const childNode = node.getChildren()[point.offset + offset3]; 23436 return childNode || null; 23437 } 23438 return null; 23439 } 23440 function $withSelectedNodes($fn) { 23441 const initialSelection = $getSelection2(); 23442 if (!$isRangeSelection2(initialSelection)) { 23443 return $fn(); 23444 } 23445 const normalized = $normalizeSelection__EXPERIMENTAL(initialSelection); 23446 const isBackwards = normalized.isBackward(); 23447 const anchorNode = $getPointNode(normalized.anchor, isBackwards ? -1 : 0); 23448 const focusNode = $getPointNode(normalized.focus, isBackwards ? 0 : -1); 23449 const rval = $fn(); 23450 if (anchorNode || focusNode) { 23451 const updatedSelection = $getSelection2(); 23452 if ($isRangeSelection2(updatedSelection)) { 23453 const finalSelection = updatedSelection.clone(); 23454 if (anchorNode) { 23455 const anchorParent = anchorNode.getParent(); 23456 if (anchorParent) { 23457 finalSelection.anchor.set(anchorParent.getKey(), anchorNode.getIndexWithinParent() + (isBackwards ? 1 : 0), "element"); 23458 } 23459 } 23460 if (focusNode) { 23461 const focusParent = focusNode.getParent(); 23462 if (focusParent) { 23463 finalSelection.focus.set(focusParent.getKey(), focusNode.getIndexWithinParent() + (isBackwards ? 0 : 1), "element"); 23464 } 23465 } 23466 $setSelection2($normalizeSelection__EXPERIMENTAL(finalSelection)); 23467 } 23468 } 23469 return rval; 23470 } 23471 function $splitLinkAtSelection(parentLink, extractedNodes) { 23472 const extractedKeys = new Set(extractedNodes.filter((n2) => parentLink.isParentOf(n2)).map((n2) => n2.getKey())); 23473 const allChildren = parentLink.getChildren(); 23474 const isExtractedChild = (child) => extractedKeys.has(child.getKey()) || $isElementNode2(child) && extractedNodes.some((n2) => parentLink.isParentOf(n2) && child.isParentOf(n2)); 23475 const extractedChildren = allChildren.filter(isExtractedChild); 23476 if (extractedChildren.length === allChildren.length) { 23477 allChildren.forEach((child) => parentLink.insertBefore(child)); 23478 parentLink.remove(); 23479 return; 23480 } 23481 const firstExtractedIndex = allChildren.findIndex(isExtractedChild); 23482 const lastExtractedIndex = allChildren.findLastIndex(isExtractedChild); 23483 const isAtStart = firstExtractedIndex === 0; 23484 const isAtEnd = lastExtractedIndex === allChildren.length - 1; 23485 if (isAtStart) { 23486 extractedChildren.forEach((child) => parentLink.insertBefore(child)); 23487 } else if (isAtEnd) { 23488 for (let i2 = extractedChildren.length - 1; i2 >= 0; i2--) { 23489 parentLink.insertAfter(extractedChildren[i2]); 23490 } 23491 } else { 23492 for (let i2 = extractedChildren.length - 1; i2 >= 0; i2--) { 23493 parentLink.insertAfter(extractedChildren[i2]); 23494 } 23495 const trailingChildren = allChildren.slice(lastExtractedIndex + 1); 23496 if (trailingChildren.length > 0) { 23497 const newLink = $copyNode2(parentLink); 23498 extractedChildren[extractedChildren.length - 1].insertAfter(newLink); 23499 trailingChildren.forEach((child) => newLink.append(child)); 23500 } 23501 } 23502 } 23503 function $toggleLink(urlOrAttributes, attributes = {}) { 23504 let url; 23505 if (urlOrAttributes && typeof urlOrAttributes === "object") { 23506 const { 23507 url: urlProp, 23508 ...rest 23509 } = urlOrAttributes; 23510 url = urlProp; 23511 attributes = { 23512 ...rest, 23513 ...attributes 23514 }; 23515 } else { 23516 url = urlOrAttributes; 23517 } 23518 const { 23519 target, 23520 title 23521 } = attributes; 23522 const rel = attributes.rel === void 0 ? "noreferrer" : attributes.rel; 23523 const selection = $getSelection2(); 23524 if (selection === null || !$isRangeSelection2(selection) && !$isNodeSelection2(selection)) { 23525 return; 23526 } 23527 if ($isNodeSelection2(selection)) { 23528 const nodes2 = selection.getNodes(); 23529 if (nodes2.length === 0) { 23530 return; 23531 } 23532 nodes2.forEach((node) => { 23533 if (url === null) { 23534 const linkParent = $findMatchingParent3(node, (parent) => !$isAutoLinkNode(parent) && $isLinkNode(parent)); 23535 if (linkParent) { 23536 linkParent.insertBefore(node); 23537 if (linkParent.getChildren().length === 0) { 23538 linkParent.remove(); 23539 } 23540 } 23541 } else { 23542 const existingLink = $findMatchingParent3(node, (parent) => !$isAutoLinkNode(parent) && $isLinkNode(parent)); 23543 if (existingLink) { 23544 existingLink.setURL(url); 23545 if (target !== void 0) { 23546 existingLink.setTarget(target); 23547 } 23548 if (rel !== void 0) { 23549 existingLink.setRel(rel); 23550 } 23551 } else { 23552 const linkNode = $createLinkNode(url, { 23553 rel, 23554 target 23555 }); 23556 node.insertBefore(linkNode); 23557 linkNode.append(node); 23558 } 23559 } 23560 }); 23561 return; 23562 } 23563 if (selection.isCollapsed() && url === null) { 23564 for (const node of selection.getNodes()) { 23565 const parentLink = $findMatchingParent3(node, (parent) => !$isAutoLinkNode(parent) && $isLinkNode(parent)); 23566 if (parentLink !== null) { 23567 parentLink.getChildren().forEach((child) => { 23568 parentLink.insertBefore(child); 23569 }); 23570 parentLink.remove(); 23571 } 23572 return; 23573 } 23574 } 23575 const nodes = selection.extract(); 23576 if (url === null) { 23577 const processedLinks = /* @__PURE__ */ new Set(); 23578 nodes.forEach((node) => { 23579 const parentLink = $findMatchingParent3(node, (parent) => !$isAutoLinkNode(parent) && $isLinkNode(parent)); 23580 if (parentLink !== null) { 23581 const linkKey = parentLink.getKey(); 23582 if (processedLinks.has(linkKey)) { 23583 return; 23584 } 23585 $splitLinkAtSelection(parentLink, nodes); 23586 processedLinks.add(linkKey); 23587 } 23588 }); 23589 return; 23590 } 23591 const updatedNodes = /* @__PURE__ */ new Set(); 23592 const updateLinkNode = (linkNode) => { 23593 if (updatedNodes.has(linkNode.getKey())) { 23594 return; 23595 } 23596 updatedNodes.add(linkNode.getKey()); 23597 linkNode.setURL(url); 23598 if (target !== void 0) { 23599 linkNode.setTarget(target); 23600 } 23601 if (rel !== void 0) { 23602 linkNode.setRel(rel); 23603 } 23604 if (title !== void 0) { 23605 linkNode.setTitle(title); 23606 } 23607 }; 23608 if (nodes.length === 1) { 23609 const firstNode = nodes[0]; 23610 const linkNode = $findMatchingParent3(firstNode, $isLinkNode); 23611 if (linkNode !== null) { 23612 return updateLinkNode(linkNode); 23613 } 23614 } 23615 $withSelectedNodes(() => { 23616 let linkNode = null; 23617 for (const node of nodes) { 23618 if (!node.isAttached()) { 23619 continue; 23620 } 23621 const parentLinkNode = $findMatchingParent3(node, $isLinkNode); 23622 if (parentLinkNode) { 23623 updateLinkNode(parentLinkNode); 23624 continue; 23625 } 23626 if ($isElementNode2(node)) { 23627 if (!node.isInline()) { 23628 continue; 23629 } 23630 if ($isLinkNode(node)) { 23631 if (!$isAutoLinkNode(node) && (linkNode === null || !linkNode.getParentOrThrow().isParentOf(node))) { 23632 updateLinkNode(node); 23633 linkNode = node; 23634 continue; 23635 } 23636 for (const child of node.getChildren()) { 23637 node.insertBefore(child); 23638 } 23639 node.remove(); 23640 continue; 23641 } 23642 } 23643 const prevLinkNode = node.getPreviousSibling(); 23644 if ($isLinkNode(prevLinkNode) && prevLinkNode.is(linkNode)) { 23645 prevLinkNode.append(node); 23646 continue; 23647 } 23648 linkNode = $createLinkNode(url, { 23649 rel, 23650 target, 23651 title 23652 }); 23653 node.insertAfter(linkNode); 23654 linkNode.append(node); 23655 } 23656 }); 23657 } 23658 var PHONE_NUMBER_REGEX = /^\+?[0-9\s()-]{5,}$/; 23659 function formatUrl(url) { 23660 if (url.match(/^[a-z][a-z0-9+.-]*:/i)) { 23661 return url; 23662 } else if (url.match(/^[/#.]/)) { 23663 return url; 23664 } else if (url.includes("@")) { 23665 return `mailto:${url}`; 23666 } else if (PHONE_NUMBER_REGEX.test(url)) { 23667 return `tel:${url}`; 23668 } 23669 return `https://${url}`; 23670 } 23671 var defaultProps = { 23672 attributes: void 0, 23673 validateUrl: void 0 23674 }; 23675 function registerLink(editor, stores) { 23676 return mergeRegister3(editor.registerNodeTransform(LinkNode, $linkNodeTransform), editor.registerCommand(TOGGLE_LINK_COMMAND, (payload) => { 23677 const validateUrl = stores.validateUrl.peek(); 23678 const attributes = stores.attributes.peek(); 23679 if (payload === null) { 23680 $toggleLink(null); 23681 return true; 23682 } else if (typeof payload === "string") { 23683 if (validateUrl === void 0 || validateUrl(payload)) { 23684 $toggleLink(payload, attributes); 23685 return true; 23686 } 23687 return false; 23688 } else { 23689 const { 23690 url, 23691 target, 23692 rel, 23693 title 23694 } = payload; 23695 $toggleLink(url, { 23696 ...attributes, 23697 rel, 23698 target, 23699 title 23700 }); 23701 return true; 23702 } 23703 }, COMMAND_PRIORITY_EDITOR2), effect(() => { 23704 const validateUrl = stores.validateUrl.value; 23705 if (!validateUrl) { 23706 return; 23707 } 23708 const attributes = stores.attributes.value; 23709 return editor.registerCommand(PASTE_COMMAND2, (event) => { 23710 const selection = $getSelection2(); 23711 if (!$isRangeSelection2(selection) || selection.isCollapsed() || !objectKlassEquals2(event, ClipboardEvent)) { 23712 return false; 23713 } 23714 if (event.clipboardData === null) { 23715 return false; 23716 } 23717 const clipboardText = event.clipboardData.getData("text"); 23718 if (!validateUrl(clipboardText)) { 23719 return false; 23720 } 23721 if (!selection.getNodes().some((node) => $isElementNode2(node))) { 23722 editor.dispatchCommand(TOGGLE_LINK_COMMAND, { 23723 ...attributes, 23724 url: clipboardText 23725 }); 23726 event.preventDefault(); 23727 return true; 23728 } 23729 return false; 23730 }, COMMAND_PRIORITY_LOW2); 23731 })); 23732 } 23733 var LinkExtension = defineExtension2({ 23734 build(editor, config, state) { 23735 return namedSignals2(config); 23736 }, 23737 config: defaultProps, 23738 mergeConfig(config, overrides) { 23739 const merged = shallowMergeConfig2(config, overrides); 23740 if (config.attributes) { 23741 merged.attributes = shallowMergeConfig2(config.attributes, merged.attributes); 23742 } 23743 return merged; 23744 }, 23745 name: "@lexical/link/Link", 23746 nodes: () => [LinkNode], 23747 register(editor, config, state) { 23748 return registerLink(editor, state.getOutput()); 23749 } 23750 }); 23751 function findMatchingDOM(startNode, predicate) { 23752 let node = startNode; 23753 while (node != null) { 23754 if (predicate(node)) { 23755 return node; 23756 } 23757 node = node.parentNode; 23758 } 23759 return null; 23760 } 23761 function registerClickableLink(editor, stores, eventOptions = {}) { 23762 const onClick2 = (event) => { 23763 const target = event.target; 23764 if (!isDOMNode2(target)) { 23765 return; 23766 } 23767 const nearestEditor = getNearestEditorFromDOMNode2(target); 23768 if (nearestEditor === null) { 23769 return; 23770 } 23771 let url = null; 23772 let urlTarget = null; 23773 nearestEditor.update(() => { 23774 const clickedNode = $getNearestNodeFromDOMNode2(target); 23775 if (clickedNode !== null) { 23776 const maybeLinkNode = $findMatchingParent3(clickedNode, $isElementNode2); 23777 if (!stores.disabled.peek()) { 23778 if ($isLinkNode(maybeLinkNode)) { 23779 url = maybeLinkNode.sanitizeUrl(maybeLinkNode.getURL()); 23780 urlTarget = maybeLinkNode.getTarget(); 23781 } else { 23782 const a2 = findMatchingDOM(target, isHTMLAnchorElement3); 23783 if (a2 !== null) { 23784 url = a2.href; 23785 urlTarget = a2.target; 23786 } 23787 } 23788 } 23789 } 23790 }); 23791 if (url === null || url === "") { 23792 return; 23793 } 23794 const selection = editor.getEditorState().read($getSelection2, { 23795 editor 23796 }); 23797 if ($isRangeSelection2(selection) && !selection.isCollapsed()) { 23798 event.preventDefault(); 23799 return; 23800 } 23801 const isMiddle = event.type === "auxclick" && event.button === 1; 23802 window.open(url, stores.newTab.peek() || isMiddle || event.metaKey || event.ctrlKey || urlTarget === "_blank" ? "_blank" : "_self"); 23803 event.preventDefault(); 23804 }; 23805 const onMouseUp = (event) => { 23806 if (event.button === 1) { 23807 onClick2(event); 23808 } 23809 }; 23810 return editor.registerRootListener((rootElement) => { 23811 if (rootElement) { 23812 rootElement.addEventListener("click", onClick2, eventOptions); 23813 rootElement.addEventListener("mouseup", onMouseUp, eventOptions); 23814 return () => { 23815 rootElement.removeEventListener("click", onClick2); 23816 rootElement.removeEventListener("mouseup", onMouseUp); 23817 }; 23818 } 23819 }); 23820 } 23821 var ClickableLinkExtension = defineExtension2({ 23822 build(editor, config, state) { 23823 return namedSignals2(config); 23824 }, 23825 config: safeCast2({ 23826 disabled: false, 23827 newTab: false 23828 }), 23829 dependencies: [LinkExtension], 23830 name: "@lexical/link/ClickableLink", 23831 register(editor, config, state) { 23832 return registerClickableLink(editor, state.getOutput()); 23833 } 23834 }); 23835 function createLinkMatcherWithRegExp(regExp, urlTransformer = (text2) => text2) { 23836 return (text2) => { 23837 const match = regExp.exec(text2); 23838 if (match === null) { 23839 return null; 23840 } 23841 return { 23842 index: match.index, 23843 length: match[0].length, 23844 text: match[0], 23845 url: urlTransformer(match[0]) 23846 }; 23847 }; 23848 } 23849 function findFirstMatch(text2, matchers) { 23850 for (let i2 = 0; i2 < matchers.length; i2++) { 23851 const match = matchers[i2](text2); 23852 if (match) { 23853 return match; 23854 } 23855 } 23856 return null; 23857 } 23858 var PUNCTUATION_OR_SPACE = /[.,;\s]/; 23859 function isSeparator(char, separatorRegex) { 23860 return separatorRegex.test(char); 23861 } 23862 function endsWithSeparator(textContent, separatorRegex) { 23863 return isSeparator(textContent[textContent.length - 1], separatorRegex); 23864 } 23865 function startsWithSeparator(textContent, separatorRegex) { 23866 return isSeparator(textContent[0], separatorRegex); 23867 } 23868 function startsWithTLD(textContent, isEmail) { 23869 if (isEmail) { 23870 return /^\.[a-zA-Z]{2,}/.test(textContent); 23871 } else { 23872 return /^\.[a-zA-Z0-9]{1,}/.test(textContent); 23873 } 23874 } 23875 function isPreviousNodeValid(node, separatorRegex) { 23876 let previousNode = node.getPreviousSibling(); 23877 if ($isElementNode2(previousNode)) { 23878 previousNode = previousNode.getLastDescendant(); 23879 } 23880 return previousNode === null || $isLineBreakNode2(previousNode) || $isTextNode2(previousNode) && endsWithSeparator(previousNode.getTextContent(), separatorRegex); 23881 } 23882 function isNextNodeValid(node, separatorRegex) { 23883 let nextNode = node.getNextSibling(); 23884 if ($isElementNode2(nextNode)) { 23885 nextNode = nextNode.getFirstDescendant(); 23886 } 23887 return nextNode === null || $isLineBreakNode2(nextNode) || $isTextNode2(nextNode) && startsWithSeparator(nextNode.getTextContent(), separatorRegex); 23888 } 23889 function isContentAroundIsValid(matchStart, matchEnd, separatorRegex, text2, nodes) { 23890 const contentBeforeIsValid = matchStart > 0 ? isSeparator(text2[matchStart - 1], separatorRegex) : isPreviousNodeValid(nodes[0], separatorRegex); 23891 if (!contentBeforeIsValid) { 23892 return false; 23893 } 23894 const contentAfterIsValid = matchEnd < text2.length ? isSeparator(text2[matchEnd], separatorRegex) : isNextNodeValid(nodes[nodes.length - 1], separatorRegex); 23895 return contentAfterIsValid; 23896 } 23897 function extractMatchingNodes(nodes, startIndex, endIndex) { 23898 const unmodifiedBeforeNodes = []; 23899 const matchingNodes = []; 23900 const unmodifiedAfterNodes = []; 23901 let matchingOffset = 0; 23902 let currentOffset = 0; 23903 const currentNodes = [...nodes]; 23904 while (currentNodes.length > 0) { 23905 const currentNode = currentNodes[0]; 23906 const currentNodeText = currentNode.getTextContent(); 23907 const currentNodeLength = currentNodeText.length; 23908 const currentNodeStart = currentOffset; 23909 const currentNodeEnd = currentOffset + currentNodeLength; 23910 if (currentNodeEnd <= startIndex) { 23911 unmodifiedBeforeNodes.push(currentNode); 23912 matchingOffset += currentNodeLength; 23913 } else if (currentNodeStart >= endIndex) { 23914 unmodifiedAfterNodes.push(currentNode); 23915 } else { 23916 matchingNodes.push(currentNode); 23917 } 23918 currentOffset += currentNodeLength; 23919 currentNodes.shift(); 23920 } 23921 return [matchingOffset, unmodifiedBeforeNodes, matchingNodes, unmodifiedAfterNodes]; 23922 } 23923 function $createAutoLinkNode_(nodes, startIndex, endIndex, match) { 23924 const linkNode = $createAutoLinkNode(match.url, match.attributes); 23925 if (nodes.length === 1) { 23926 let remainingTextNode = nodes[0]; 23927 let linkTextNode; 23928 if (startIndex === 0) { 23929 [linkTextNode, remainingTextNode] = remainingTextNode.splitText(endIndex); 23930 } else { 23931 [, linkTextNode, remainingTextNode] = remainingTextNode.splitText(startIndex, endIndex); 23932 } 23933 const textNode = $createTextNode2(match.text); 23934 textNode.setFormat(linkTextNode.getFormat()); 23935 textNode.setDetail(linkTextNode.getDetail()); 23936 textNode.setStyle(linkTextNode.getStyle()); 23937 linkNode.append(textNode); 23938 linkTextNode.replace(linkNode); 23939 return remainingTextNode; 23940 } else if (nodes.length > 1) { 23941 const firstTextNode = nodes[0]; 23942 let offset3 = firstTextNode.getTextContent().length; 23943 let firstLinkTextNode; 23944 if (startIndex === 0) { 23945 firstLinkTextNode = firstTextNode; 23946 } else { 23947 [, firstLinkTextNode] = firstTextNode.splitText(startIndex); 23948 } 23949 const linkNodes = []; 23950 let remainingTextNode; 23951 for (let i2 = 1; i2 < nodes.length; i2++) { 23952 const currentNode = nodes[i2]; 23953 const currentNodeText = currentNode.getTextContent(); 23954 const currentNodeLength = currentNodeText.length; 23955 const currentNodeStart = offset3; 23956 const currentNodeEnd = offset3 + currentNodeLength; 23957 if (currentNodeStart < endIndex) { 23958 if (currentNodeEnd <= endIndex) { 23959 linkNodes.push(currentNode); 23960 } else { 23961 const [linkTextNode, endNode] = currentNode.splitText(endIndex - currentNodeStart); 23962 linkNodes.push(linkTextNode); 23963 remainingTextNode = endNode; 23964 } 23965 } 23966 offset3 += currentNodeLength; 23967 } 23968 const selection = $getSelection2(); 23969 const selectedTextNode = selection ? selection.getNodes().find($isTextNode2) : void 0; 23970 const textNode = $createTextNode2(firstLinkTextNode.getTextContent()); 23971 textNode.setFormat(firstLinkTextNode.getFormat()); 23972 textNode.setDetail(firstLinkTextNode.getDetail()); 23973 textNode.setStyle(firstLinkTextNode.getStyle()); 23974 linkNode.append(textNode, ...linkNodes); 23975 if (selectedTextNode && selectedTextNode === firstLinkTextNode) { 23976 if ($isRangeSelection2(selection)) { 23977 textNode.select(selection.anchor.offset, selection.focus.offset); 23978 } else if ($isNodeSelection2(selection)) { 23979 textNode.select(0, textNode.getTextContent().length); 23980 } 23981 } 23982 firstLinkTextNode.replace(linkNode); 23983 return remainingTextNode; 23984 } 23985 return void 0; 23986 } 23987 function $handleLinkCreation(nodes, matchers, onChange, separatorRegex) { 23988 for (const node of nodes) { 23989 const parent = node.getParent(); 23990 if ($isAutoLinkNode(parent) && !parent.getIsUnlinked()) { 23991 return; 23992 } 23993 } 23994 let currentNodes = [...nodes]; 23995 const initialText = currentNodes.map((node) => node.getTextContent()).join(""); 23996 let text2 = initialText; 23997 let match; 23998 let invalidMatchEnd = 0; 23999 while ((match = findFirstMatch(text2, matchers)) && match !== null) { 24000 const matchStart = match.index; 24001 const matchLength = match.length; 24002 const matchEnd = matchStart + matchLength; 24003 const isValid = isContentAroundIsValid(invalidMatchEnd + matchStart, invalidMatchEnd + matchEnd, separatorRegex, initialText, currentNodes); 24004 if (isValid) { 24005 const [matchingOffset, , matchingNodes, unmodifiedAfterNodes] = extractMatchingNodes(currentNodes, invalidMatchEnd + matchStart, invalidMatchEnd + matchEnd); 24006 let alreadyLinked = false; 24007 for (const node of matchingNodes) { 24008 const parent = node.getParent(); 24009 if ($isAutoLinkNode(parent) && !parent.getIsUnlinked()) { 24010 alreadyLinked = true; 24011 break; 24012 } 24013 } 24014 if (alreadyLinked) { 24015 invalidMatchEnd += matchEnd; 24016 text2 = text2.substring(matchEnd); 24017 continue; 24018 } 24019 const actualMatchStart = invalidMatchEnd + matchStart - matchingOffset; 24020 const actualMatchEnd = invalidMatchEnd + matchEnd - matchingOffset; 24021 const remainingTextNode = $createAutoLinkNode_(matchingNodes, actualMatchStart, actualMatchEnd, match); 24022 currentNodes = remainingTextNode ? [remainingTextNode, ...unmodifiedAfterNodes] : unmodifiedAfterNodes; 24023 onChange(match.url, null); 24024 invalidMatchEnd = 0; 24025 } else { 24026 invalidMatchEnd += matchEnd; 24027 } 24028 text2 = text2.substring(matchEnd); 24029 } 24030 } 24031 function handleLinkEdit(linkNode, matchers, onChange, separatorRegex) { 24032 const children = linkNode.getChildren(); 24033 const childrenLength = children.length; 24034 for (let i2 = 0; i2 < childrenLength; i2++) { 24035 const child = children[i2]; 24036 if (!$isTextNode2(child) || !child.isSimpleText()) { 24037 replaceWithChildren(linkNode); 24038 onChange(null, linkNode.getURL()); 24039 return; 24040 } 24041 } 24042 const text2 = linkNode.getTextContent(); 24043 const match = findFirstMatch(text2, matchers); 24044 if (match === null || match.text !== text2) { 24045 replaceWithChildren(linkNode); 24046 onChange(null, linkNode.getURL()); 24047 return; 24048 } 24049 if (!isPreviousNodeValid(linkNode, separatorRegex) || !isNextNodeValid(linkNode, separatorRegex)) { 24050 replaceWithChildren(linkNode); 24051 onChange(null, linkNode.getURL()); 24052 return; 24053 } 24054 const url = linkNode.getURL(); 24055 if (url !== match.url) { 24056 linkNode.setURL(match.url); 24057 onChange(match.url, url); 24058 } 24059 if (match.attributes) { 24060 const rel = linkNode.getRel(); 24061 if (rel !== match.attributes.rel) { 24062 linkNode.setRel(match.attributes.rel || null); 24063 onChange(match.attributes.rel || null, rel); 24064 } 24065 const target = linkNode.getTarget(); 24066 if (target !== match.attributes.target) { 24067 linkNode.setTarget(match.attributes.target || null); 24068 onChange(match.attributes.target || null, target); 24069 } 24070 } 24071 } 24072 function handleBadNeighbors(textNode, matchers, onChange, separatorRegex) { 24073 const parent = textNode.getParent(); 24074 const previousSibling = textNode.getPreviousSibling(); 24075 const nextSibling = textNode.getNextSibling(); 24076 const text2 = textNode.getTextContent(); 24077 if ($isAutoLinkNode(parent) && !parent.getIsUnlinked()) { 24078 return; 24079 } 24080 if ($isAutoLinkNode(previousSibling) && !previousSibling.getIsUnlinked()) { 24081 if (previousSibling.is(textNode.getPreviousSibling()) && textNode.getParent() === previousSibling.getParent()) { 24082 if (!startsWithSeparator(text2, separatorRegex)) { 24083 replaceWithChildren(previousSibling); 24084 onChange(null, previousSibling.getURL()); 24085 return; 24086 } 24087 if (startsWithTLD(text2, previousSibling.isEmailURI())) { 24088 const combinedText = previousSibling.getTextContent() + text2; 24089 const match = findFirstMatch(combinedText, matchers); 24090 if (match !== null && match.text === combinedText) { 24091 previousSibling.append(textNode); 24092 handleLinkEdit(previousSibling, matchers, onChange, separatorRegex); 24093 onChange(null, previousSibling.getURL()); 24094 } 24095 } 24096 } 24097 } 24098 if ($isAutoLinkNode(nextSibling) && !nextSibling.getIsUnlinked() && !endsWithSeparator(text2, separatorRegex)) { 24099 if (nextSibling.is(textNode.getNextSibling()) && textNode.getParent() === nextSibling.getParent()) { 24100 replaceWithChildren(nextSibling); 24101 onChange(null, nextSibling.getURL()); 24102 } 24103 } 24104 } 24105 function replaceWithChildren(node) { 24106 const children = node.getChildren(); 24107 const childrenLength = children.length; 24108 for (let j3 = childrenLength - 1; j3 >= 0; j3--) { 24109 node.insertAfter(children[j3]); 24110 } 24111 node.remove(); 24112 return children.map((child) => child.getLatest()); 24113 } 24114 function getTextNodesToMatch(textNode) { 24115 const textNodesToMatch = [textNode]; 24116 let nextSibling = textNode.getNextSibling(); 24117 while (nextSibling !== null && $isTextNode2(nextSibling) && nextSibling.isSimpleText()) { 24118 textNodesToMatch.push(nextSibling); 24119 if (/[\s]/.test(nextSibling.getTextContent())) { 24120 break; 24121 } 24122 nextSibling = nextSibling.getNextSibling(); 24123 } 24124 return textNodesToMatch; 24125 } 24126 var defaultConfig = { 24127 changeHandlers: [], 24128 excludeParents: [], 24129 matchers: [], 24130 separatorRegex: PUNCTUATION_OR_SPACE 24131 }; 24132 function registerAutoLink(editor, config = defaultConfig) { 24133 const { 24134 matchers, 24135 changeHandlers, 24136 excludeParents, 24137 separatorRegex = PUNCTUATION_OR_SPACE 24138 } = config; 24139 const onChange = (url, prevUrl) => { 24140 for (const handler of changeHandlers) { 24141 handler(url, prevUrl); 24142 } 24143 }; 24144 return mergeRegister3(editor.registerNodeTransform(TextNode2, (textNode) => { 24145 const parent = textNode.getParentOrThrow(); 24146 const previous = textNode.getPreviousSibling(); 24147 if ($isAutoLinkNode(parent)) { 24148 handleLinkEdit(parent, matchers, onChange, separatorRegex); 24149 } else if (!$isLinkNode(parent) && !excludeParents.some((pred) => pred(parent))) { 24150 if (textNode.isSimpleText() && (startsWithSeparator(textNode.getTextContent(), separatorRegex) || !$isAutoLinkNode(previous))) { 24151 const textNodesToMatch = getTextNodesToMatch(textNode); 24152 $handleLinkCreation(textNodesToMatch, matchers, onChange, separatorRegex); 24153 } 24154 handleBadNeighbors(textNode, matchers, onChange, separatorRegex); 24155 } 24156 }), editor.registerCommand( 24157 TOGGLE_LINK_COMMAND, 24158 (payload) => { 24159 const selection = $getSelection2(); 24160 if (payload !== null || !$isRangeSelection2(selection)) { 24161 return false; 24162 } 24163 const nodes = selection.extract(); 24164 nodes.forEach((node) => { 24165 const parent = node.getParent(); 24166 if ($isAutoLinkNode(parent)) { 24167 parent.setIsUnlinked(!parent.getIsUnlinked()); 24168 parent.markDirty(); 24169 } 24170 }); 24171 return false; 24172 }, 24173 // Has to be higher than TOGGLE_LINK_COMMAND in LinkExtension 24174 COMMAND_PRIORITY_LOW2 24175 )); 24176 } 24177 var AutoLinkExtension = defineExtension2({ 24178 config: defaultConfig, 24179 dependencies: [LinkExtension], 24180 mergeConfig(config, overrides) { 24181 const merged = shallowMergeConfig2(config, overrides); 24182 for (const k2 of ["matchers", "changeHandlers", "excludeParents"]) { 24183 const v3 = overrides[k2]; 24184 if (Array.isArray(v3)) { 24185 merged[k2] = [...config[k2], ...v3]; 24186 } 24187 } 24188 return merged; 24189 }, 24190 name: "@lexical/link/AutoLink", 24191 nodes: [AutoLinkNode], 24192 register: registerAutoLink 24193 }); 24194 var toggleLink = $toggleLink; 24195 24196
vendor: 924 bytes, lines 24196-24216
24196// node_modules/@lexical/link/LexicalLink.mjs 24197 var mod5 = true ? LexicalLink_dev_exports : LexicalLink_prod_exports; 24198 var $createAutoLinkNode2 = mod5.$createAutoLinkNode; 24199 var $createLinkNode2 = mod5.$createLinkNode; 24200 var $isAutoLinkNode2 = mod5.$isAutoLinkNode; 24201 var $isLinkNode2 = mod5.$isLinkNode; 24202 var $toggleLink2 = mod5.$toggleLink; 24203 var AutoLinkExtension2 = mod5.AutoLinkExtension; 24204 var AutoLinkNode2 = mod5.AutoLinkNode; 24205 var ClickableLinkExtension2 = mod5.ClickableLinkExtension; 24206 var LinkExtension2 = mod5.LinkExtension; 24207 var LinkNode2 = mod5.LinkNode; 24208 var TOGGLE_LINK_COMMAND2 = mod5.TOGGLE_LINK_COMMAND; 24209 var createLinkMatcherWithRegExp2 = mod5.createLinkMatcherWithRegExp; 24210 var formatUrl2 = mod5.formatUrl; 24211 var registerAutoLink2 = mod5.registerAutoLink; 24212 var registerClickableLink2 = mod5.registerClickableLink; 24213 var registerLink2 = mod5.registerLink; 24214 var toggleLink2 = mod5.toggleLink; 24215 24216
vendor: 54,913 bytes, lines 24216-25724
24216// node_modules/@lexical/list/LexicalList.dev.mjs 24217 var LexicalList_dev_exports = {}; 24218 __export(LexicalList_dev_exports, { 24219 $createListItemNode: () => $createListItemNode, 24220 $createListNode: () => $createListNode, 24221 $getListDepth: () => $getListDepth, 24222 $handleListInsertParagraph: () => $handleListInsertParagraph, 24223 $insertList: () => $insertList, 24224 $isListItemNode: () => $isListItemNode, 24225 $isListNode: () => $isListNode, 24226 $removeList: () => $removeList, 24227 CheckListExtension: () => CheckListExtension, 24228 INSERT_CHECK_LIST_COMMAND: () => INSERT_CHECK_LIST_COMMAND, 24229 INSERT_ORDERED_LIST_COMMAND: () => INSERT_ORDERED_LIST_COMMAND, 24230 INSERT_UNORDERED_LIST_COMMAND: () => INSERT_UNORDERED_LIST_COMMAND, 24231 ListExtension: () => ListExtension, 24232 ListItemNode: () => ListItemNode, 24233 ListNode: () => ListNode, 24234 REMOVE_LIST_COMMAND: () => REMOVE_LIST_COMMAND, 24235 UPDATE_LIST_START_COMMAND: () => UPDATE_LIST_START_COMMAND, 24236 insertList: () => insertList, 24237 registerCheckList: () => registerCheckList, 24238 registerList: () => registerList, 24239 registerListStrictIndentTransform: () => registerListStrictIndentTransform, 24240 removeList: () => removeList 24241 }); 24242 function formatDevErrorMessage6(message) { 24243 throw new Error(message); 24244 } 24245 function $getListDepth(listNode) { 24246 let depth = 1; 24247 let parent = listNode.getParent(); 24248 while (parent != null) { 24249 if ($isListItemNode(parent)) { 24250 const parentList = parent.getParent(); 24251 if ($isListNode(parentList)) { 24252 depth++; 24253 parent = parentList.getParent(); 24254 continue; 24255 } 24256 { 24257 formatDevErrorMessage6(`A ListItemNode must have a ListNode for a parent.`); 24258 } 24259 } 24260 return depth; 24261 } 24262 return depth; 24263 } 24264 function $getTopListNode(listItem) { 24265 let list = listItem.getParent(); 24266 if (!$isListNode(list)) { 24267 { 24268 formatDevErrorMessage6(`A ListItemNode must have a ListNode for a parent.`); 24269 } 24270 } 24271 let parent = list; 24272 while (parent !== null) { 24273 parent = parent.getParent(); 24274 if ($isListNode(parent)) { 24275 list = parent; 24276 } 24277 } 24278 return list; 24279 } 24280 function $getAllListItems(node) { 24281 let listItemNodes = []; 24282 const listChildren = node.getChildren().filter($isListItemNode); 24283 for (let i2 = 0; i2 < listChildren.length; i2++) { 24284 const listItemNode = listChildren[i2]; 24285 const firstChild = listItemNode.getFirstChild(); 24286 if ($isListNode(firstChild)) { 24287 listItemNodes = listItemNodes.concat($getAllListItems(firstChild)); 24288 } else { 24289 listItemNodes.push(listItemNode); 24290 } 24291 } 24292 return listItemNodes; 24293 } 24294 function isNestedListNode(node) { 24295 return $isListItemNode(node) && $isListNode(node.getFirstChild()); 24296 } 24297 function $removeHighestEmptyListParent(sublist) { 24298 let emptyListPtr = sublist; 24299 while (emptyListPtr.getNextSibling() == null && emptyListPtr.getPreviousSibling() == null) { 24300 const parent = emptyListPtr.getParent(); 24301 if (parent == null || !($isListItemNode(parent) || $isListNode(parent))) { 24302 break; 24303 } 24304 emptyListPtr = parent; 24305 } 24306 emptyListPtr.remove(); 24307 } 24308 function $wrapInListItem(node) { 24309 const listItemWrapper = $createListItemNode(); 24310 return listItemWrapper.append(node); 24311 } 24312 function $getNewListStart(list, listItem) { 24313 return list.getStart() + listItem.getIndexWithinParent(); 24314 } 24315 function $isSelectingEmptyListItem(anchorNode, nodes) { 24316 return $isListItemNode(anchorNode) && (nodes.length === 0 || nodes.length === 1 && anchorNode.is(nodes[0]) && anchorNode.getChildrenSize() === 0); 24317 } 24318 function $insertList(listType) { 24319 const selection = $getSelection2(); 24320 if (selection !== null) { 24321 let nodes = selection.getNodes(); 24322 if ($isRangeSelection2(selection)) { 24323 const anchorAndFocus = selection.getStartEndPoints(); 24324 if (!(anchorAndFocus !== null)) { 24325 formatDevErrorMessage6(`insertList: anchor should be defined`); 24326 } 24327 const [anchor] = anchorAndFocus; 24328 const anchorNode = anchor.getNode(); 24329 const anchorNodeParent = anchorNode.getParent(); 24330 if ($isRootOrShadowRoot2(anchorNode)) { 24331 const firstChild = anchorNode.getFirstChild(); 24332 if (firstChild) { 24333 nodes = firstChild.selectStart().getNodes(); 24334 } else { 24335 const paragraph = $createParagraphNode2(); 24336 anchorNode.append(paragraph); 24337 nodes = paragraph.select().getNodes(); 24338 } 24339 } else if ($isSelectingEmptyListItem(anchorNode, nodes)) { 24340 const list = $createListNode(listType); 24341 if ($isRootOrShadowRoot2(anchorNodeParent)) { 24342 anchorNode.replace(list); 24343 const listItem = $createListItemNode(); 24344 if ($isElementNode2(anchorNode)) { 24345 listItem.setFormat(anchorNode.getFormatType()); 24346 listItem.setIndent(anchorNode.getIndent()); 24347 } 24348 list.append(listItem); 24349 } else if ($isListItemNode(anchorNode)) { 24350 const parent = anchorNode.getParentOrThrow(); 24351 append(list, parent.getChildren()); 24352 parent.replace(list); 24353 } 24354 return; 24355 } 24356 } 24357 const handled = /* @__PURE__ */ new Set(); 24358 for (let i2 = 0; i2 < nodes.length; i2++) { 24359 const node = nodes[i2]; 24360 if ($isElementNode2(node) && node.isEmpty() && !$isListItemNode(node) && !handled.has(node.getKey())) { 24361 $createListOrMerge(node, listType); 24362 continue; 24363 } 24364 let parent = $isLeafNode2(node) ? node.getParent() : $isListItemNode(node) && node.isEmpty() ? node : null; 24365 while (parent != null) { 24366 const parentKey = parent.getKey(); 24367 if ($isListNode(parent)) { 24368 if (!handled.has(parentKey)) { 24369 const newListNode = $createListNode(listType); 24370 append(newListNode, parent.getChildren()); 24371 parent.replace(newListNode); 24372 handled.add(parentKey); 24373 } 24374 break; 24375 } else { 24376 const nextParent = parent.getParent(); 24377 if ($isRootOrShadowRoot2(nextParent) && !handled.has(parentKey)) { 24378 handled.add(parentKey); 24379 $createListOrMerge(parent, listType); 24380 break; 24381 } 24382 parent = nextParent; 24383 } 24384 } 24385 } 24386 } 24387 } 24388 function append(node, nodesToAppend) { 24389 node.splice(node.getChildrenSize(), 0, nodesToAppend); 24390 } 24391 function $createListOrMerge(node, listType) { 24392 if ($isListNode(node)) { 24393 return node; 24394 } 24395 const previousSibling = node.getPreviousSibling(); 24396 const nextSibling = node.getNextSibling(); 24397 const listItem = $createListItemNode(); 24398 append(listItem, node.getChildren()); 24399 let targetList; 24400 if ($isListNode(previousSibling) && listType === previousSibling.getListType()) { 24401 previousSibling.append(listItem); 24402 if ($isListNode(nextSibling) && listType === nextSibling.getListType()) { 24403 append(previousSibling, nextSibling.getChildren()); 24404 nextSibling.remove(); 24405 } 24406 targetList = previousSibling; 24407 } else if ($isListNode(nextSibling) && listType === nextSibling.getListType()) { 24408 nextSibling.getFirstChildOrThrow().insertBefore(listItem); 24409 targetList = nextSibling; 24410 } else { 24411 const list = $createListNode(listType); 24412 list.append(listItem); 24413 node.replace(list); 24414 targetList = list; 24415 } 24416 listItem.setFormat(node.getFormatType()); 24417 listItem.setIndent(node.getIndent()); 24418 const selection = $getSelection2(); 24419 if ($isRangeSelection2(selection)) { 24420 if (targetList.getKey() === selection.anchor.key) { 24421 selection.anchor.set(listItem.getKey(), selection.anchor.offset, "element"); 24422 } 24423 if (targetList.getKey() === selection.focus.key) { 24424 selection.focus.set(listItem.getKey(), selection.focus.offset, "element"); 24425 } 24426 } 24427 node.remove(); 24428 return targetList; 24429 } 24430 function mergeLists(list1, list2) { 24431 const listItem1 = list1.getLastChild(); 24432 const listItem2 = list2.getFirstChild(); 24433 if (listItem1 && listItem2 && isNestedListNode(listItem1) && isNestedListNode(listItem2)) { 24434 mergeLists(listItem1.getFirstChild(), listItem2.getFirstChild()); 24435 listItem2.remove(); 24436 } 24437 const toMerge = list2.getChildren(); 24438 if (toMerge.length > 0) { 24439 list1.append(...toMerge); 24440 } 24441 list2.remove(); 24442 } 24443 function $removeList() { 24444 const selection = $getSelection2(); 24445 if ($isRangeSelection2(selection)) { 24446 const listNodes = /* @__PURE__ */ new Set(); 24447 const nodes = selection.getNodes(); 24448 const anchorNode = selection.anchor.getNode(); 24449 if ($isSelectingEmptyListItem(anchorNode, nodes)) { 24450 listNodes.add($getTopListNode(anchorNode)); 24451 } else { 24452 for (let i2 = 0; i2 < nodes.length; i2++) { 24453 const node = nodes[i2]; 24454 if ($isLeafNode2(node)) { 24455 const listItemNode = $getNearestNodeOfType2(node, ListItemNode); 24456 if (listItemNode != null) { 24457 listNodes.add($getTopListNode(listItemNode)); 24458 } 24459 } 24460 } 24461 } 24462 for (const listNode of listNodes) { 24463 let insertionPoint = listNode; 24464 const listItems = $getAllListItems(listNode); 24465 for (const listItemNode of listItems) { 24466 const paragraph = $createParagraphNode2().setTextStyle(selection.style).setTextFormat(selection.format); 24467 append(paragraph, listItemNode.getChildren()); 24468 insertionPoint.insertAfter(paragraph); 24469 insertionPoint = paragraph; 24470 if (listItemNode.__key === selection.anchor.key) { 24471 $setPointFromCaret2(selection.anchor, $normalizeCaret2($getChildCaret2(paragraph, "next"))); 24472 } 24473 if (listItemNode.__key === selection.focus.key) { 24474 $setPointFromCaret2(selection.focus, $normalizeCaret2($getChildCaret2(paragraph, "next"))); 24475 } 24476 listItemNode.remove(); 24477 } 24478 listNode.remove(); 24479 } 24480 } 24481 } 24482 function updateChildrenListItemValue(list) { 24483 const isNotChecklist = list.getListType() !== "check"; 24484 let value = list.getStart(); 24485 for (const child of list.getChildren()) { 24486 if ($isListItemNode(child)) { 24487 if (child.getValue() !== value) { 24488 child.setValue(value); 24489 } 24490 if (isNotChecklist && child.getLatest().__checked != null) { 24491 child.setChecked(void 0); 24492 } 24493 if (!$isListNode(child.getFirstChild())) { 24494 value++; 24495 } 24496 } 24497 } 24498 } 24499 function mergeNextSiblingListIfSameType(list) { 24500 const nextSibling = list.getNextSibling(); 24501 if ($isListNode(nextSibling) && list.getListType() === nextSibling.getListType()) { 24502 mergeLists(list, nextSibling); 24503 } 24504 } 24505 function $handleIndent(listItemNode) { 24506 const removed = /* @__PURE__ */ new Set(); 24507 if (isNestedListNode(listItemNode) || removed.has(listItemNode.getKey())) { 24508 return; 24509 } 24510 const parent = listItemNode.getParent(); 24511 const nextSibling = listItemNode.getNextSibling(); 24512 const previousSibling = listItemNode.getPreviousSibling(); 24513 if (isNestedListNode(nextSibling) && isNestedListNode(previousSibling)) { 24514 const innerList = previousSibling.getFirstChild(); 24515 if ($isListNode(innerList)) { 24516 innerList.append(listItemNode); 24517 const nextInnerList = nextSibling.getFirstChild(); 24518 if ($isListNode(nextInnerList)) { 24519 const children = nextInnerList.getChildren(); 24520 append(innerList, children); 24521 nextSibling.remove(); 24522 removed.add(nextSibling.getKey()); 24523 } 24524 } 24525 } else if (isNestedListNode(nextSibling)) { 24526 const innerList = nextSibling.getFirstChild(); 24527 if ($isListNode(innerList)) { 24528 const firstChild = innerList.getFirstChild(); 24529 if (firstChild !== null) { 24530 firstChild.insertBefore(listItemNode); 24531 } 24532 } 24533 } else if (isNestedListNode(previousSibling)) { 24534 const innerList = previousSibling.getFirstChild(); 24535 if ($isListNode(innerList)) { 24536 innerList.append(listItemNode); 24537 } 24538 } else { 24539 if ($isListNode(parent)) { 24540 const newListItem = $copyNode2(listItemNode); 24541 const newList = $copyNode2(parent); 24542 newListItem.append(newList); 24543 newList.append(listItemNode); 24544 if (previousSibling) { 24545 previousSibling.insertAfter(newListItem); 24546 } else if (nextSibling) { 24547 nextSibling.insertBefore(newListItem); 24548 } else { 24549 parent.append(newListItem); 24550 } 24551 } 24552 } 24553 } 24554 function $handleOutdent(listItemNode) { 24555 if (isNestedListNode(listItemNode)) { 24556 return; 24557 } 24558 const parentList = listItemNode.getParent(); 24559 const grandparentListItem = parentList ? parentList.getParent() : void 0; 24560 const greatGrandparentList = grandparentListItem ? grandparentListItem.getParent() : void 0; 24561 if ($isListNode(greatGrandparentList) && $isListItemNode(grandparentListItem) && $isListNode(parentList)) { 24562 const firstChild = parentList ? parentList.getFirstChild() : void 0; 24563 const lastChild = parentList ? parentList.getLastChild() : void 0; 24564 if (listItemNode.is(firstChild)) { 24565 grandparentListItem.insertBefore(listItemNode); 24566 if (parentList.isEmpty()) { 24567 grandparentListItem.remove(); 24568 } 24569 } else if (listItemNode.is(lastChild)) { 24570 grandparentListItem.insertAfter(listItemNode); 24571 if (parentList.isEmpty()) { 24572 grandparentListItem.remove(); 24573 } 24574 } else { 24575 const previousSiblingsListItem = $copyNode2(listItemNode); 24576 const previousSiblingsList = $copyNode2(parentList); 24577 previousSiblingsListItem.append(previousSiblingsList); 24578 listItemNode.getPreviousSiblings().forEach((sibling) => previousSiblingsList.append(sibling)); 24579 const nextSiblingsListItem = $copyNode2(listItemNode); 24580 const nextSiblingsList = $copyNode2(parentList); 24581 nextSiblingsListItem.append(nextSiblingsList); 24582 append(nextSiblingsList, listItemNode.getNextSiblings()); 24583 grandparentListItem.insertBefore(previousSiblingsListItem); 24584 grandparentListItem.insertAfter(nextSiblingsListItem); 24585 grandparentListItem.replace(listItemNode); 24586 } 24587 } 24588 } 24589 function $handleListInsertParagraph(restoreNumbering = false) { 24590 const selection = $getSelection2(); 24591 if (!$isRangeSelection2(selection) || !selection.isCollapsed()) { 24592 return false; 24593 } 24594 const anchor = selection.anchor.getNode(); 24595 let listItem = null; 24596 if ($isListItemNode(anchor) && anchor.getChildrenSize() === 0) { 24597 listItem = anchor; 24598 } else if ($isTextNode2(anchor)) { 24599 const parentListItem = anchor.getParent(); 24600 if ($isListItemNode(parentListItem) && parentListItem.getChildren().every((node) => $isTextNode2(node) && node.getTextContent().trim() === "")) { 24601 listItem = parentListItem; 24602 } 24603 } 24604 if (listItem === null) { 24605 return false; 24606 } 24607 const topListNode = $getTopListNode(listItem); 24608 const parent = listItem.getParent(); 24609 if (!$isListNode(parent)) { 24610 formatDevErrorMessage6(`A ListItemNode must have a ListNode for a parent.`); 24611 } 24612 const grandparent = parent.getParent(); 24613 let replacementNode; 24614 if ($isRootOrShadowRoot2(grandparent)) { 24615 replacementNode = $createParagraphNode2(); 24616 topListNode.insertAfter(replacementNode); 24617 } else if ($isListItemNode(grandparent)) { 24618 replacementNode = $copyNode2(grandparent); 24619 grandparent.insertAfter(replacementNode); 24620 } else { 24621 return false; 24622 } 24623 replacementNode.setTextStyle(selection.style).setTextFormat(selection.format).select(); 24624 const nextSiblings = listItem.getNextSiblings(); 24625 if (nextSiblings.length > 0) { 24626 const newStart = restoreNumbering ? $getNewListStart(parent, listItem) : 1; 24627 const newList = $copyNode2(parent).setStart(newStart); 24628 if ($isListItemNode(replacementNode)) { 24629 const newListItem = $copyNode2(replacementNode); 24630 newListItem.append(newList); 24631 replacementNode.insertAfter(newListItem); 24632 } else { 24633 replacementNode.insertAfter(newList); 24634 } 24635 newList.append(...nextSiblings); 24636 } 24637 $removeHighestEmptyListParent(listItem); 24638 return true; 24639 } 24640 function applyMarkerStyles(dom, node, prevNode) { 24641 const nextTextStyle = node.__textStyle; 24642 const prevTextStyle = prevNode ? prevNode.__textStyle : ""; 24643 if (prevNode !== null && prevTextStyle === nextTextStyle) { 24644 return; 24645 } 24646 const styles = getStyleObjectFromCSS2(nextTextStyle); 24647 for (const k2 in styles) { 24648 dom.style.setProperty(`--listitem-marker-${k2}`, styles[k2]); 24649 } 24650 if (prevTextStyle !== "") { 24651 for (const k2 in getStyleObjectFromCSS2(prevTextStyle)) { 24652 if (!(k2 in styles)) { 24653 dom.style.removeProperty(`--listitem-marker-${k2}`); 24654 } 24655 } 24656 } 24657 } 24658 var ListItemNode = class extends ElementNode2 { 24659 /** @internal */ 24660 __value; 24661 /** @internal */ 24662 __checked; 24663 /** @internal */ 24664 $config() { 24665 return this.config("listitem", { 24666 $transform: (node) => { 24667 const parent = node.getParent(); 24668 if ($isListNode(parent)) { 24669 if (parent.getListType() !== "check" && node.getChecked() != null) { 24670 node.setChecked(void 0); 24671 } 24672 } else if (parent) { 24673 const newParent = node.createParentElementNode(); 24674 if (!$isListNode(newParent)) { 24675 formatDevErrorMessage6(`ListItemNode.createParentElementNode() must return a ListNode`); 24676 } 24677 const children = [node]; 24678 for (const dir of ["previous", "next"]) { 24679 children.reverse(); 24680 for (const { 24681 origin 24682 } of $getSiblingCaret2(node, dir)) { 24683 if (!$isListItemNode(origin)) { 24684 break; 24685 } 24686 children.push(origin); 24687 } 24688 } 24689 node.insertBefore(newParent); 24690 newParent.splice(0, 0, children); 24691 if (!$isRootOrShadowRoot2(parent)) { 24692 $insertNodeToNearestRootAtCaret2(newParent, $rewindSiblingCaret2($getSiblingCaret2(newParent, "next")), { 24693 $shouldSplit: () => false, 24694 removeEmptyDestination: true 24695 }); 24696 if (parent.isEmpty() && parent.isAttached()) { 24697 parent.remove(); 24698 } 24699 } 24700 } 24701 }, 24702 extends: ElementNode2, 24703 importDOM: buildImportMap2({ 24704 li: () => ({ 24705 conversion: $convertListItemElement, 24706 priority: 0 24707 }) 24708 }) 24709 }); 24710 } 24711 constructor(value = 1, checked = void 0, key) { 24712 super(key); 24713 this.__value = value === void 0 ? 1 : value; 24714 this.__checked = checked; 24715 } 24716 afterCloneFrom(prevNode) { 24717 super.afterCloneFrom(prevNode); 24718 this.__value = prevNode.__value; 24719 this.__checked = prevNode.__checked; 24720 } 24721 createDOM(config) { 24722 const element = document.createElement("li"); 24723 this.updateListItemDOM(null, element, config); 24724 return element; 24725 } 24726 updateListItemDOM(prevNode, dom, config) { 24727 updateListItemChecked(dom, this, prevNode); 24728 dom.value = this.__value; 24729 $setListItemThemeClassNames(dom, config.theme, this); 24730 const prevStyle = prevNode ? prevNode.__style : ""; 24731 const nextStyle = this.__style; 24732 if (prevStyle !== nextStyle) { 24733 setDOMStyleFromCSS2(dom.style, nextStyle, prevStyle); 24734 } 24735 applyMarkerStyles(dom, this, prevNode); 24736 } 24737 updateDOM(prevNode, dom, config) { 24738 const element = dom; 24739 this.updateListItemDOM(prevNode, element, config); 24740 return false; 24741 } 24742 updateFromJSON(serializedNode) { 24743 return super.updateFromJSON(serializedNode).setValue(serializedNode.value).setChecked(serializedNode.checked); 24744 } 24745 exportDOM(editor) { 24746 const element = this.createDOM(editor._config); 24747 const formatType = this.getFormatType(); 24748 if (formatType) { 24749 element.style.textAlign = formatType; 24750 } 24751 const direction = this.getDirection(); 24752 if (direction) { 24753 element.dir = direction; 24754 } 24755 if (isNestedListNode(this)) { 24756 return { 24757 after(containerElement) { 24758 if (isHTMLElement2(containerElement)) { 24759 const prevSibling = containerElement.previousElementSibling; 24760 if (isHTMLElement2(prevSibling) && prevSibling.nodeName === "LI") { 24761 while (containerElement.firstChild) { 24762 prevSibling.append(containerElement.firstChild); 24763 } 24764 containerElement.remove(); 24765 } 24766 } 24767 return containerElement; 24768 }, 24769 element 24770 }; 24771 } 24772 return { 24773 element 24774 }; 24775 } 24776 exportJSON() { 24777 return { 24778 ...super.exportJSON(), 24779 checked: this.getChecked(), 24780 value: this.getValue() 24781 }; 24782 } 24783 append(...nodes) { 24784 for (let i2 = 0; i2 < nodes.length; i2++) { 24785 const node = nodes[i2]; 24786 if ($isElementNode2(node) && this.canMergeWith(node)) { 24787 const children = node.getChildren(); 24788 this.append(...children); 24789 node.remove(); 24790 } else { 24791 super.append(node); 24792 } 24793 } 24794 return this; 24795 } 24796 replace(replaceWithNode, includeChildren) { 24797 if ($isListItemNode(replaceWithNode)) { 24798 return super.replace(replaceWithNode); 24799 } 24800 this.setIndent(0); 24801 const list = this.getParentOrThrow(); 24802 if (!$isListNode(list)) { 24803 return replaceWithNode; 24804 } 24805 if (list.__first === this.getKey()) { 24806 list.insertBefore(replaceWithNode); 24807 } else if (list.__last === this.getKey()) { 24808 list.insertAfter(replaceWithNode); 24809 } else { 24810 const newList = $copyNode2(list); 24811 let nextSibling = this.getNextSibling(); 24812 while (nextSibling) { 24813 const nodeToAppend = nextSibling; 24814 nextSibling = nextSibling.getNextSibling(); 24815 newList.append(nodeToAppend); 24816 } 24817 list.insertAfter(replaceWithNode); 24818 replaceWithNode.insertAfter(newList); 24819 } 24820 if (includeChildren) { 24821 if (!$isElementNode2(replaceWithNode)) { 24822 formatDevErrorMessage6(`includeChildren should only be true for ElementNodes`); 24823 } 24824 this.getChildren().forEach((child) => { 24825 replaceWithNode.append(child); 24826 }); 24827 } 24828 this.remove(); 24829 if (list.getChildrenSize() === 0) { 24830 list.remove(); 24831 } 24832 return replaceWithNode; 24833 } 24834 insertAfter(node, restoreSelection = true) { 24835 const listNode = this.getParentOrThrow(); 24836 if (!$isListNode(listNode)) { 24837 { 24838 formatDevErrorMessage6(`insertAfter: list node is not parent of list item node`); 24839 } 24840 } 24841 if ($isListItemNode(node)) { 24842 return super.insertAfter(node, restoreSelection); 24843 } 24844 const siblings = this.getNextSiblings(); 24845 listNode.insertAfter(node, restoreSelection); 24846 if (siblings.length !== 0) { 24847 const newListNode = $copyNode2(listNode); 24848 siblings.forEach((sibling) => newListNode.append(sibling)); 24849 node.insertAfter(newListNode, restoreSelection); 24850 } 24851 return node; 24852 } 24853 remove(preserveEmptyParent) { 24854 const prevSibling = this.getPreviousSibling(); 24855 const nextSibling = this.getNextSibling(); 24856 super.remove(preserveEmptyParent); 24857 if (prevSibling && nextSibling && isNestedListNode(prevSibling) && isNestedListNode(nextSibling)) { 24858 mergeLists(prevSibling.getFirstChild(), nextSibling.getFirstChild()); 24859 nextSibling.remove(); 24860 } 24861 } 24862 resetOnCopyNodeFrom(original) { 24863 super.resetOnCopyNodeFrom(original); 24864 if (original.getChecked()) { 24865 this.setChecked(false); 24866 } 24867 } 24868 insertNewAfter(_3, restoreSelection = true) { 24869 const newElement = $copyNode2(this); 24870 this.insertAfter(newElement, restoreSelection); 24871 return newElement; 24872 } 24873 collapseAtStart(selection) { 24874 const paragraph = $createParagraphNode2(); 24875 const children = this.getChildren(); 24876 children.forEach((child) => paragraph.append(child)); 24877 const listNode = this.getParentOrThrow(); 24878 const listNodeParent = listNode.getParentOrThrow(); 24879 const isIndented = $isListItemNode(listNodeParent); 24880 if (listNode.getChildrenSize() === 1) { 24881 if (isIndented) { 24882 listNode.remove(); 24883 listNodeParent.select(); 24884 } else { 24885 listNode.insertBefore(paragraph); 24886 listNode.remove(); 24887 const anchor = selection.anchor; 24888 const focus = selection.focus; 24889 const key = paragraph.getKey(); 24890 if (anchor.type === "element" && anchor.getNode().is(this)) { 24891 anchor.set(key, anchor.offset, "element"); 24892 } 24893 if (focus.type === "element" && focus.getNode().is(this)) { 24894 focus.set(key, focus.offset, "element"); 24895 } 24896 } 24897 } else { 24898 listNode.insertBefore(paragraph); 24899 this.remove(); 24900 } 24901 return true; 24902 } 24903 getValue() { 24904 const self2 = this.getLatest(); 24905 return self2.__value; 24906 } 24907 setValue(value) { 24908 const self2 = this.getWritable(); 24909 self2.__value = value; 24910 return self2; 24911 } 24912 getChecked() { 24913 const self2 = this.getLatest(); 24914 let listType; 24915 const parent = this.getParent(); 24916 if ($isListNode(parent)) { 24917 listType = parent.getListType(); 24918 } 24919 return listType === "check" ? Boolean(self2.__checked) : void 0; 24920 } 24921 setChecked(checked) { 24922 const self2 = this.getWritable(); 24923 self2.__checked = checked; 24924 return self2; 24925 } 24926 toggleChecked() { 24927 const self2 = this.getWritable(); 24928 return self2.setChecked(!self2.__checked); 24929 } 24930 getIndent() { 24931 const parent = this.getParent(); 24932 if (parent === null || !this.isAttached()) { 24933 return this.getLatest().__indent; 24934 } 24935 let listNodeParent = parent.getParentOrThrow(); 24936 let indentLevel = 0; 24937 while ($isListItemNode(listNodeParent)) { 24938 listNodeParent = listNodeParent.getParentOrThrow().getParentOrThrow(); 24939 indentLevel++; 24940 } 24941 return indentLevel; 24942 } 24943 setIndent(indent) { 24944 if (!(typeof indent === "number")) { 24945 formatDevErrorMessage6(`Invalid indent value.`); 24946 } 24947 indent = Math.floor(indent); 24948 if (!(indent >= 0)) { 24949 formatDevErrorMessage6(`Indent value must be non-negative.`); 24950 } 24951 let currentIndent = this.getIndent(); 24952 while (currentIndent !== indent) { 24953 if (currentIndent < indent) { 24954 $handleIndent(this); 24955 currentIndent++; 24956 } else { 24957 $handleOutdent(this); 24958 currentIndent--; 24959 } 24960 } 24961 return this; 24962 } 24963 /** @deprecated @internal */ 24964 canInsertAfter(node) { 24965 return $isListItemNode(node); 24966 } 24967 /** @deprecated @internal */ 24968 canReplaceWith(replacement) { 24969 return $isListItemNode(replacement); 24970 } 24971 canMergeWith(node) { 24972 return $isListItemNode(node) || $isParagraphNode2(node); 24973 } 24974 extractWithChild(child, selection) { 24975 if (!$isRangeSelection2(selection)) { 24976 return false; 24977 } 24978 const anchorNode = selection.anchor.getNode(); 24979 const focusNode = selection.focus.getNode(); 24980 return this.isParentOf(anchorNode) && this.isParentOf(focusNode) && this.getTextContent().length === selection.getTextContent().length; 24981 } 24982 isParentRequired() { 24983 return true; 24984 } 24985 createParentElementNode() { 24986 return $createListNode("bullet"); 24987 } 24988 canMergeWhenEmpty() { 24989 return true; 24990 } 24991 }; 24992 function $setListItemThemeClassNames(dom, editorThemeClasses, node) { 24993 const classesToAdd = []; 24994 const classesToRemove = []; 24995 const listTheme = editorThemeClasses.list; 24996 const listItemClassName = listTheme ? listTheme.listitem : void 0; 24997 let nestedListItemClassName; 24998 if (listTheme && listTheme.nested) { 24999 nestedListItemClassName = listTheme.nested.listitem; 25000 } 25001 if (listItemClassName !== void 0) { 25002 classesToAdd.push(...normalizeClassNames2(listItemClassName)); 25003 } 25004 if (listTheme) { 25005 const parentNode = node.getParent(); 25006 const isCheckList = $isListNode(parentNode) && parentNode.getListType() === "check"; 25007 const checked = node.getChecked(); 25008 if (!isCheckList || checked) { 25009 classesToRemove.push(listTheme.listitemUnchecked); 25010 } 25011 if (!isCheckList || !checked) { 25012 classesToRemove.push(listTheme.listitemChecked); 25013 } 25014 if (isCheckList) { 25015 classesToAdd.push(checked ? listTheme.listitemChecked : listTheme.listitemUnchecked); 25016 } 25017 } 25018 if (nestedListItemClassName !== void 0) { 25019 const nestedListItemClasses = normalizeClassNames2(nestedListItemClassName); 25020 if (node.getChildren().some((child) => $isListNode(child))) { 25021 classesToAdd.push(...nestedListItemClasses); 25022 } else { 25023 classesToRemove.push(...nestedListItemClasses); 25024 } 25025 } 25026 if (classesToRemove.length > 0) { 25027 removeClassNamesFromElement3(dom, ...classesToRemove); 25028 } 25029 if (classesToAdd.length > 0) { 25030 addClassNamesToElement3(dom, ...classesToAdd); 25031 } 25032 } 25033 function updateListItemChecked(dom, listItemNode, prevListItemNode) { 25034 const parent = listItemNode.getParent(); 25035 const isCheckbox = $isListNode(parent) && parent.getListType() === "check" && // Only add attributes for leaf list items 25036 !$isListNode(listItemNode.getFirstChild()); 25037 if (!isCheckbox) { 25038 dom.removeAttribute("role"); 25039 dom.removeAttribute("tabIndex"); 25040 dom.removeAttribute("aria-checked"); 25041 } else { 25042 dom.setAttribute("role", "checkbox"); 25043 dom.setAttribute("tabIndex", "-1"); 25044 if (!prevListItemNode || listItemNode.__checked !== prevListItemNode.__checked) { 25045 dom.setAttribute("aria-checked", listItemNode.getChecked() ? "true" : "false"); 25046 } 25047 } 25048 } 25049 function $convertListItemElement(domNode) { 25050 const isGitHubCheckList = domNode.classList.contains("task-list-item"); 25051 if (isGitHubCheckList) { 25052 for (const child of domNode.children) { 25053 if (child.tagName === "INPUT") { 25054 return $convertCheckboxInput(child); 25055 } 25056 } 25057 } 25058 const isJoplinCheckList = domNode.classList.contains("joplin-checkbox"); 25059 if (isJoplinCheckList) { 25060 for (const child of domNode.children) { 25061 if (child.classList.contains("checkbox-wrapper") && child.children.length > 0 && child.children[0].tagName === "INPUT") { 25062 return $convertCheckboxInput(child.children[0]); 25063 } 25064 } 25065 } 25066 const ariaCheckedAttr = domNode.getAttribute("aria-checked"); 25067 const checked = ariaCheckedAttr === "true" ? true : ariaCheckedAttr === "false" ? false : void 0; 25068 return { 25069 node: $createListItemNode(checked) 25070 }; 25071 } 25072 function $convertCheckboxInput(domNode) { 25073 const isCheckboxInput = domNode.getAttribute("type") === "checkbox"; 25074 if (!isCheckboxInput) { 25075 return { 25076 node: null 25077 }; 25078 } 25079 const checked = domNode.hasAttribute("checked"); 25080 return { 25081 node: $createListItemNode(checked) 25082 }; 25083 } 25084 function $createListItemNode(checked) { 25085 return $applyNodeReplacement2(new ListItemNode(void 0, checked)); 25086 } 25087 function $isListItemNode(node) { 25088 return node instanceof ListItemNode; 25089 } 25090 var ListNode = class extends ElementNode2 { 25091 /** @internal */ 25092 __tag; 25093 /** @internal */ 25094 __start; 25095 /** @internal */ 25096 __listType; 25097 /** @internal */ 25098 $config() { 25099 return this.config("list", { 25100 $transform: (node) => { 25101 mergeNextSiblingListIfSameType(node); 25102 updateChildrenListItemValue(node); 25103 }, 25104 extends: ElementNode2, 25105 importDOM: buildImportMap2({ 25106 ol: () => ({ 25107 conversion: $convertListNode, 25108 priority: 0 25109 }), 25110 ul: () => ({ 25111 conversion: $convertListNode, 25112 priority: 0 25113 }) 25114 }) 25115 }); 25116 } 25117 constructor(listType = "number", start3 = 1, key) { 25118 super(key); 25119 const _listType = TAG_TO_LIST_TYPE[listType] || listType; 25120 this.__listType = _listType; 25121 this.__tag = _listType === "number" ? "ol" : "ul"; 25122 this.__start = start3; 25123 } 25124 afterCloneFrom(prevNode) { 25125 super.afterCloneFrom(prevNode); 25126 this.__listType = prevNode.__listType; 25127 this.__tag = prevNode.__tag; 25128 this.__start = prevNode.__start; 25129 } 25130 getTag() { 25131 return this.getLatest().__tag; 25132 } 25133 setListType(type) { 25134 const writable = this.getWritable(); 25135 writable.__listType = type; 25136 writable.__tag = type === "number" ? "ol" : "ul"; 25137 return writable; 25138 } 25139 getListType() { 25140 return this.getLatest().__listType; 25141 } 25142 getStart() { 25143 return this.getLatest().__start; 25144 } 25145 setStart(start3) { 25146 const self2 = this.getWritable(); 25147 self2.__start = start3; 25148 return self2; 25149 } 25150 // View 25151 createDOM(config, _editor) { 25152 const tag = this.__tag; 25153 const dom = document.createElement(tag); 25154 if (this.__start !== 1) { 25155 dom.setAttribute("start", String(this.__start)); 25156 } 25157 dom.__lexicalListType = this.__listType; 25158 $setListThemeClassNames(dom, config.theme, this); 25159 return dom; 25160 } 25161 updateDOM(prevNode, dom, config) { 25162 if (prevNode.__tag !== this.__tag || prevNode.__listType !== this.__listType) { 25163 return true; 25164 } 25165 $setListThemeClassNames(dom, config.theme, this); 25166 if (prevNode.__start !== this.__start) { 25167 dom.setAttribute("start", String(this.__start)); 25168 } 25169 return false; 25170 } 25171 updateFromJSON(serializedNode) { 25172 return super.updateFromJSON(serializedNode).setListType(serializedNode.listType).setStart(serializedNode.start); 25173 } 25174 exportDOM(editor) { 25175 const element = this.createDOM(editor._config, editor); 25176 if (isHTMLElement3(element)) { 25177 if (this.__start !== 1) { 25178 element.setAttribute("start", String(this.__start)); 25179 } 25180 if (this.__listType === "check") { 25181 element.setAttribute("__lexicalListType", "check"); 25182 } 25183 } 25184 return { 25185 element 25186 }; 25187 } 25188 exportJSON() { 25189 return { 25190 ...super.exportJSON(), 25191 listType: this.getListType(), 25192 start: this.getStart(), 25193 tag: this.getTag() 25194 }; 25195 } 25196 canBeEmpty() { 25197 return false; 25198 } 25199 canIndent() { 25200 return false; 25201 } 25202 splice(start3, deleteCount, nodesToInsert) { 25203 const exampleListItem = nodesToInsert.find($isListItemNode) ?? this.getChildren().find($isListItemNode); 25204 const $newListItem = exampleListItem ? () => $copyNode2(exampleListItem) : $createListItemNode; 25205 let listItemNodesToInsert = nodesToInsert; 25206 for (let i2 = 0; i2 < nodesToInsert.length; i2++) { 25207 const node = nodesToInsert[i2]; 25208 if (!$isListItemNode(node)) { 25209 if (listItemNodesToInsert === nodesToInsert) { 25210 listItemNodesToInsert = [...nodesToInsert]; 25211 } 25212 listItemNodesToInsert[i2] = $newListItem().append($isElementNode2(node) && !($isListNode(node) || node.isInline()) ? $createTextNode2(node.getTextContent()) : node); 25213 } 25214 } 25215 return super.splice(start3, deleteCount, listItemNodesToInsert); 25216 } 25217 extractWithChild(child) { 25218 return $isListItemNode(child); 25219 } 25220 }; 25221 function $setListThemeClassNames(dom, editorThemeClasses, node) { 25222 const classesToAdd = []; 25223 const classesToRemove = []; 25224 const listTheme = editorThemeClasses.list; 25225 if (listTheme !== void 0) { 25226 const listLevelsClassNames = listTheme[`${node.__tag}Depth`] || []; 25227 const listDepth = $getListDepth(node) - 1; 25228 const normalizedListDepth = listDepth % listLevelsClassNames.length; 25229 const listLevelClassName = listLevelsClassNames[normalizedListDepth]; 25230 const listClassName = listTheme[node.__tag]; 25231 let nestedListClassName; 25232 const nestedListTheme = listTheme.nested; 25233 const checklistClassName = listTheme.checklist; 25234 if (nestedListTheme !== void 0 && nestedListTheme.list) { 25235 nestedListClassName = nestedListTheme.list; 25236 } 25237 if (listClassName !== void 0) { 25238 classesToAdd.push(listClassName); 25239 } 25240 if (checklistClassName !== void 0 && node.__listType === "check") { 25241 classesToAdd.push(checklistClassName); 25242 } 25243 if (listLevelClassName !== void 0) { 25244 classesToAdd.push(...normalizeClassNames2(listLevelClassName)); 25245 for (let i2 = 0; i2 < listLevelsClassNames.length; i2++) { 25246 if (i2 !== normalizedListDepth) { 25247 classesToRemove.push(node.__tag + i2); 25248 } 25249 } 25250 } 25251 if (nestedListClassName !== void 0) { 25252 const nestedListItemClasses = normalizeClassNames2(nestedListClassName); 25253 if (listDepth > 1) { 25254 classesToAdd.push(...nestedListItemClasses); 25255 } else { 25256 classesToRemove.push(...nestedListItemClasses); 25257 } 25258 } 25259 } 25260 if (classesToRemove.length > 0) { 25261 removeClassNamesFromElement3(dom, ...classesToRemove); 25262 } 25263 if (classesToAdd.length > 0) { 25264 addClassNamesToElement3(dom, ...classesToAdd); 25265 } 25266 } 25267 function $normalizeChildren(nodes) { 25268 const normalizedListItems = []; 25269 for (let i2 = 0; i2 < nodes.length; i2++) { 25270 const node = nodes[i2]; 25271 if ($isListItemNode(node)) { 25272 normalizedListItems.push(node); 25273 const children = node.getChildren(); 25274 if (children.length > 1) { 25275 children.forEach((child) => { 25276 if ($isListNode(child)) { 25277 normalizedListItems.push($wrapInListItem(child)); 25278 } 25279 }); 25280 } 25281 } else { 25282 normalizedListItems.push($wrapInListItem(node)); 25283 } 25284 } 25285 return normalizedListItems; 25286 } 25287 function isDomChecklist(domNode) { 25288 if (domNode.getAttribute("__lexicallisttype") === "check" || // is github checklist 25289 domNode.classList.contains("contains-task-list") || // is joplin checklist 25290 domNode.getAttribute("data-is-checklist") === "1") { 25291 return true; 25292 } 25293 for (const child of domNode.childNodes) { 25294 if (isHTMLElement3(child) && child.hasAttribute("aria-checked")) { 25295 return true; 25296 } 25297 } 25298 return false; 25299 } 25300 function $convertListNode(domNode) { 25301 const nodeName = domNode.nodeName.toLowerCase(); 25302 let node = null; 25303 if (nodeName === "ol") { 25304 const start3 = domNode.start; 25305 node = $createListNode("number", start3); 25306 } else if (nodeName === "ul") { 25307 if (isDomChecklist(domNode)) { 25308 node = $createListNode("check"); 25309 } else { 25310 node = $createListNode("bullet"); 25311 } 25312 } 25313 return { 25314 after: $normalizeChildren, 25315 node 25316 }; 25317 } 25318 var TAG_TO_LIST_TYPE = { 25319 ol: "number", 25320 ul: "bullet" 25321 }; 25322 function $createListNode(listType = "number", start3 = 1) { 25323 return $applyNodeReplacement2(new ListNode(listType, start3)); 25324 } 25325 function $isListNode(node) { 25326 return node instanceof ListNode; 25327 } 25328 var INSERT_CHECK_LIST_COMMAND = createCommand2("INSERT_CHECK_LIST_COMMAND"); 25329 function registerCheckList(editor, options) { 25330 const disableTakeFocusOnClick = options && options.disableTakeFocusOnClick || false; 25331 const peekDisableTakeFocusOnClick = typeof disableTakeFocusOnClick === "boolean" ? () => disableTakeFocusOnClick : disableTakeFocusOnClick.peek.bind(disableTakeFocusOnClick); 25332 const DEDUP_WINDOW_MS = 500; 25333 const isWithinDedupWindow = (event) => { 25334 const target = event.target; 25335 if (!isHTMLElement3(target)) { 25336 return false; 25337 } 25338 const last = target.__lexicalCheckListLastHandled; 25339 return last !== void 0 && event.timeStamp - last < DEDUP_WINDOW_MS; 25340 }; 25341 const recordHandled = (event) => { 25342 const target = event.target; 25343 if (isHTMLElement3(target)) { 25344 target.__lexicalCheckListLastHandled = event.timeStamp; 25345 } 25346 }; 25347 const configHandleClick = (event) => { 25348 if (isWithinDedupWindow(event)) { 25349 return; 25350 } 25351 recordHandled(event); 25352 handleClick(event, peekDisableTakeFocusOnClick()); 25353 }; 25354 const configHandlePointerUp = (event) => { 25355 if (event.pointerType !== "touch") { 25356 return; 25357 } 25358 if (isWithinDedupWindow(event)) { 25359 return; 25360 } 25361 recordHandled(event); 25362 handleClick(event, peekDisableTakeFocusOnClick()); 25363 }; 25364 const configHandleSelectDefaults = (event) => { 25365 handleSelectDefaults(event, peekDisableTakeFocusOnClick()); 25366 }; 25367 return mergeRegister3(editor.registerCommand(INSERT_CHECK_LIST_COMMAND, () => { 25368 $insertList("check"); 25369 return true; 25370 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(KEY_ARROW_DOWN_COMMAND2, (event) => { 25371 return handleArrowUpOrDown(event, editor, false); 25372 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(KEY_ARROW_UP_COMMAND2, (event) => { 25373 return handleArrowUpOrDown(event, editor, true); 25374 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(KEY_ESCAPE_COMMAND2, () => { 25375 const activeItem = getActiveCheckListItem(); 25376 if (activeItem != null) { 25377 const rootElement = editor.getRootElement(); 25378 if (rootElement != null) { 25379 rootElement.focus(); 25380 } 25381 return true; 25382 } 25383 return false; 25384 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(KEY_SPACE_COMMAND2, (event) => { 25385 const activeItem = getActiveCheckListItem(); 25386 if (activeItem != null && editor.isEditable()) { 25387 editor.update(() => { 25388 const listItemNode = $getNearestNodeFromDOMNode2(activeItem); 25389 if ($isListItemNode(listItemNode)) { 25390 event.preventDefault(); 25391 listItemNode.toggleChecked(); 25392 } 25393 }); 25394 return true; 25395 } 25396 return false; 25397 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(KEY_ARROW_LEFT_COMMAND2, (event) => { 25398 return editor.getEditorState().read(() => { 25399 const selection = $getSelection2(); 25400 if ($isRangeSelection2(selection) && selection.isCollapsed()) { 25401 const { 25402 anchor 25403 } = selection; 25404 const isElement2 = anchor.type === "element"; 25405 if (isElement2 || anchor.offset === 0) { 25406 const anchorNode = anchor.getNode(); 25407 const elementNode = $findMatchingParent3(anchorNode, (node) => $isElementNode2(node) && !node.isInline()); 25408 if ($isListItemNode(elementNode)) { 25409 const parent = elementNode.getParent(); 25410 if ($isListNode(parent) && parent.getListType() === "check" && (isElement2 || elementNode.getFirstDescendant() === anchorNode)) { 25411 const domNode = editor.getElementByKey(elementNode.__key); 25412 if (domNode != null && document.activeElement !== domNode) { 25413 domNode.focus(); 25414 event.preventDefault(); 25415 return true; 25416 } 25417 } 25418 } 25419 } 25420 } 25421 return false; 25422 }); 25423 }, COMMAND_PRIORITY_LOW2), editor.registerRootListener((rootElement) => { 25424 if (rootElement !== null) { 25425 rootElement.addEventListener("click", configHandleClick); 25426 rootElement.addEventListener("pointerup", configHandlePointerUp); 25427 rootElement.addEventListener("pointerdown", configHandleSelectDefaults, { 25428 capture: true 25429 }); 25430 rootElement.addEventListener("mousedown", configHandleSelectDefaults, { 25431 capture: true 25432 }); 25433 rootElement.addEventListener("touchstart", configHandleSelectDefaults, { 25434 capture: true, 25435 passive: false 25436 }); 25437 return () => { 25438 rootElement.removeEventListener("click", configHandleClick); 25439 rootElement.removeEventListener("pointerup", configHandlePointerUp); 25440 rootElement.removeEventListener("pointerdown", configHandleSelectDefaults, { 25441 capture: true 25442 }); 25443 rootElement.removeEventListener("mousedown", configHandleSelectDefaults, { 25444 capture: true 25445 }); 25446 rootElement.removeEventListener("touchstart", configHandleSelectDefaults, { 25447 capture: true 25448 }); 25449 }; 25450 } 25451 })); 25452 } 25453 function handleCheckItemEvent(event, callback) { 25454 const target = event.target; 25455 if (!isHTMLElement3(target)) { 25456 return; 25457 } 25458 const firstChild = target.firstChild; 25459 if (isHTMLElement3(firstChild) && (firstChild.tagName === "UL" || firstChild.tagName === "OL")) { 25460 return; 25461 } 25462 const parentNode = target.parentNode; 25463 if (!parentNode || parentNode.__lexicalListType !== "check") { 25464 return; 25465 } 25466 let clientX = null; 25467 let pointerType = null; 25468 if ("clientX" in event) { 25469 clientX = event.clientX; 25470 } else if ("touches" in event) { 25471 const touches = event.touches; 25472 if (touches.length > 0) { 25473 clientX = touches[0].clientX; 25474 pointerType = "touch"; 25475 } 25476 } 25477 if (clientX == null) { 25478 return; 25479 } 25480 const rect = target.getBoundingClientRect(); 25481 const zoom = calculateZoomLevel2(target); 25482 const clientXInPixels = clientX / zoom; 25483 const beforeStyles = window.getComputedStyle ? window.getComputedStyle(target, "::before") : { 25484 width: "0px" 25485 }; 25486 const beforeWidthInPixels = parseFloat(beforeStyles.width); 25487 const isTouchEvent = pointerType === "touch" || "pointerType" in event && event.pointerType === "touch"; 25488 const clickAreaPadding = isTouchEvent ? 32 : 0; 25489 if (target.dir === "rtl" ? clientXInPixels < rect.right + clickAreaPadding && clientXInPixels > rect.right - beforeWidthInPixels - clickAreaPadding : clientXInPixels > rect.left - clickAreaPadding && clientXInPixels < rect.left + beforeWidthInPixels + clickAreaPadding) { 25490 callback(); 25491 } 25492 } 25493 function handleClick(event, disableFocusOnClick) { 25494 handleCheckItemEvent(event, () => { 25495 if (isHTMLElement3(event.target)) { 25496 const domNode = event.target; 25497 const editor = getNearestEditorFromDOMNode2(domNode); 25498 if (editor != null && editor.isEditable()) { 25499 editor.update(() => { 25500 const node = $getNearestNodeFromDOMNode2(domNode); 25501 if ($isListItemNode(node)) { 25502 if (disableFocusOnClick) { 25503 $addUpdateTag2(SKIP_SELECTION_FOCUS_TAG2); 25504 $addUpdateTag2(SKIP_DOM_SELECTION_TAG2); 25505 } else { 25506 domNode.focus(); 25507 } 25508 node.toggleChecked(); 25509 } 25510 }); 25511 } 25512 } 25513 }); 25514 } 25515 function handleSelectDefaults(event, disableTakeFocusOnClick) { 25516 handleCheckItemEvent(event, () => { 25517 event.preventDefault(); 25518 if (disableTakeFocusOnClick) { 25519 event.stopPropagation(); 25520 } 25521 }); 25522 } 25523 function getActiveCheckListItem() { 25524 const activeElement = document.activeElement; 25525 return isHTMLElement3(activeElement) && activeElement.tagName === "LI" && activeElement.parentNode != null && // @ts-ignore internal field 25526 activeElement.parentNode.__lexicalListType === "check" ? activeElement : null; 25527 } 25528 function findCheckListItemSibling(node, backward) { 25529 let sibling = backward ? node.getPreviousSibling() : node.getNextSibling(); 25530 let parent = node; 25531 while (sibling == null && $isListItemNode(parent)) { 25532 parent = parent.getParentOrThrow().getParent(); 25533 if (parent != null) { 25534 sibling = backward ? parent.getPreviousSibling() : parent.getNextSibling(); 25535 } 25536 } 25537 while ($isListItemNode(sibling)) { 25538 const firstChild = backward ? sibling.getLastChild() : sibling.getFirstChild(); 25539 if (!$isListNode(firstChild)) { 25540 return sibling; 25541 } 25542 sibling = backward ? firstChild.getLastChild() : firstChild.getFirstChild(); 25543 } 25544 return null; 25545 } 25546 function handleArrowUpOrDown(event, editor, backward) { 25547 const activeItem = getActiveCheckListItem(); 25548 if (activeItem != null) { 25549 editor.update(() => { 25550 const listItem = $getNearestNodeFromDOMNode2(activeItem); 25551 if (!$isListItemNode(listItem)) { 25552 return; 25553 } 25554 const nextListItem = findCheckListItemSibling(listItem, backward); 25555 if (nextListItem != null) { 25556 nextListItem.selectStart(); 25557 const dom = editor.getElementByKey(nextListItem.__key); 25558 if (dom != null) { 25559 event.preventDefault(); 25560 setTimeout(() => { 25561 dom.focus(); 25562 }, 0); 25563 } 25564 } 25565 }); 25566 } 25567 return false; 25568 } 25569 var UPDATE_LIST_START_COMMAND = createCommand2("UPDATE_LIST_START_COMMAND"); 25570 var INSERT_UNORDERED_LIST_COMMAND = createCommand2("INSERT_UNORDERED_LIST_COMMAND"); 25571 var INSERT_ORDERED_LIST_COMMAND = createCommand2("INSERT_ORDERED_LIST_COMMAND"); 25572 var REMOVE_LIST_COMMAND = createCommand2("REMOVE_LIST_COMMAND"); 25573 function registerList(editor, options) { 25574 const removeListener = mergeRegister3(editor.registerCommand(INSERT_ORDERED_LIST_COMMAND, () => { 25575 $insertList("number"); 25576 return true; 25577 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(UPDATE_LIST_START_COMMAND, (payload) => { 25578 const { 25579 listNodeKey, 25580 newStart 25581 } = payload; 25582 const listNode = $getNodeByKey2(listNodeKey); 25583 if (!$isListNode(listNode)) { 25584 return false; 25585 } 25586 if (listNode.getListType() === "number") { 25587 listNode.setStart(newStart); 25588 updateChildrenListItemValue(listNode); 25589 } 25590 return true; 25591 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(INSERT_UNORDERED_LIST_COMMAND, () => { 25592 $insertList("bullet"); 25593 return true; 25594 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(REMOVE_LIST_COMMAND, () => { 25595 $removeList(); 25596 return true; 25597 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(INSERT_PARAGRAPH_COMMAND2, () => { 25598 const shouldRestore = options && options.restoreNumbering; 25599 return $handleListInsertParagraph(!!shouldRestore); 25600 }, COMMAND_PRIORITY_LOW2), editor.registerNodeTransform(ListItemNode, (node) => { 25601 const firstChild = node.getFirstChild(); 25602 if (firstChild) { 25603 if ($isTextNode2(firstChild)) { 25604 const style = firstChild.getStyle(); 25605 const format = firstChild.getFormat(); 25606 if (node.getTextStyle() !== style) { 25607 node.setTextStyle(style); 25608 } 25609 if (node.getTextFormat() !== format) { 25610 node.setTextFormat(format); 25611 } 25612 } 25613 } else { 25614 const selection = $getSelection2(); 25615 if ($isRangeSelection2(selection) && (selection.style !== node.getTextStyle() || selection.format !== node.getTextFormat()) && selection.isCollapsed() && node.is(selection.anchor.getNode())) { 25616 node.setTextStyle(selection.style).setTextFormat(selection.format); 25617 } 25618 } 25619 }), editor.registerNodeTransform(TextNode2, (node) => { 25620 const listItemParentNode = node.getParent(); 25621 if ($isListItemNode(listItemParentNode) && node.is(listItemParentNode.getFirstChild())) { 25622 const style = node.getStyle(); 25623 const format = node.getFormat(); 25624 if (style !== listItemParentNode.getTextStyle() || format !== listItemParentNode.getTextFormat()) { 25625 listItemParentNode.setTextStyle(style).setTextFormat(format); 25626 } 25627 } 25628 })); 25629 return removeListener; 25630 } 25631 function registerListStrictIndentTransform(editor) { 25632 const $formatListIndentStrict = (listItemNode) => { 25633 const listNode = listItemNode.getParent(); 25634 if ($isListNode(listItemNode.getFirstChild()) || !$isListNode(listNode)) { 25635 return; 25636 } 25637 const startingListItemNode = $findMatchingParent3(listItemNode, (node) => $isListItemNode(node) && $isListNode(node.getParent()) && $isListItemNode(node.getPreviousSibling())); 25638 if (startingListItemNode === null && listItemNode.getIndent() > 0) { 25639 listItemNode.setIndent(0); 25640 } else if ($isListItemNode(startingListItemNode)) { 25641 const prevListItemNode = startingListItemNode.getPreviousSibling(); 25642 if ($isListItemNode(prevListItemNode)) { 25643 const endListItemNode = $findChildrenEndListItemNode(prevListItemNode); 25644 const endListNode = endListItemNode.getParent(); 25645 if ($isListNode(endListNode)) { 25646 const prevDepth = $getListDepth(endListNode); 25647 const depth = $getListDepth(listNode); 25648 if (prevDepth + 1 < depth) { 25649 listItemNode.setIndent(prevDepth); 25650 } 25651 } 25652 } 25653 } 25654 }; 25655 const $processListWithStrictIndent = (listNode) => { 25656 const queue = [listNode]; 25657 while (queue.length > 0) { 25658 const node = queue.shift(); 25659 if (!$isListNode(node)) { 25660 continue; 25661 } 25662 for (const child of node.getChildren()) { 25663 if ($isListItemNode(child)) { 25664 $formatListIndentStrict(child); 25665 const firstChild = child.getFirstChild(); 25666 if ($isListNode(firstChild)) { 25667 queue.push(firstChild); 25668 } 25669 } 25670 } 25671 } 25672 }; 25673 return editor.registerNodeTransform(ListNode, $processListWithStrictIndent); 25674 } 25675 function $findChildrenEndListItemNode(listItemNode) { 25676 let current = listItemNode; 25677 let firstChild = current.getFirstChild(); 25678 while ($isListNode(firstChild)) { 25679 const lastChild = firstChild.getLastChild(); 25680 if ($isListItemNode(lastChild)) { 25681 current = lastChild; 25682 firstChild = current.getFirstChild(); 25683 } else { 25684 break; 25685 } 25686 } 25687 return current; 25688 } 25689 function insertList(editor, listType) { 25690 editor.update(() => $insertList(listType)); 25691 } 25692 function removeList(editor) { 25693 editor.update(() => $removeList()); 25694 } 25695 var ListExtension = defineExtension2({ 25696 build(editor, config, state) { 25697 return namedSignals2(config); 25698 }, 25699 config: safeCast2({ 25700 hasStrictIndent: false, 25701 shouldPreserveNumbering: false 25702 }), 25703 name: "@lexical/list/List", 25704 nodes: () => [ListNode, ListItemNode], 25705 register(editor, config, state) { 25706 const stores = state.getOutput(); 25707 return mergeRegister3(effect(() => { 25708 return registerList(editor, { 25709 restoreNumbering: stores.shouldPreserveNumbering.value 25710 }); 25711 }), effect(() => stores.hasStrictIndent.value ? registerListStrictIndentTransform(editor) : void 0)); 25712 } 25713 }); 25714 var CheckListExtension = defineExtension2({ 25715 build: (editor, config) => namedSignals2(config), 25716 config: safeCast2({ 25717 disableTakeFocusOnClick: false 25718 }), 25719 dependencies: [ListExtension], 25720 name: "@lexical/list/CheckList", 25721 register: (editor, config, state) => registerCheckList(editor, state.getOutput()) 25722 }); 25723 25724
vendor: 1,253 bytes, lines 25724-25749
25724// node_modules/@lexical/list/LexicalList.mjs 25725 var mod6 = true ? LexicalList_dev_exports : LexicalList_prod_exports; 25726 var $createListItemNode2 = mod6.$createListItemNode; 25727 var $createListNode2 = mod6.$createListNode; 25728 var $getListDepth2 = mod6.$getListDepth; 25729 var $handleListInsertParagraph2 = mod6.$handleListInsertParagraph; 25730 var $insertList2 = mod6.$insertList; 25731 var $isListItemNode2 = mod6.$isListItemNode; 25732 var $isListNode2 = mod6.$isListNode; 25733 var $removeList2 = mod6.$removeList; 25734 var CheckListExtension2 = mod6.CheckListExtension; 25735 var INSERT_CHECK_LIST_COMMAND2 = mod6.INSERT_CHECK_LIST_COMMAND; 25736 var INSERT_ORDERED_LIST_COMMAND2 = mod6.INSERT_ORDERED_LIST_COMMAND; 25737 var INSERT_UNORDERED_LIST_COMMAND2 = mod6.INSERT_UNORDERED_LIST_COMMAND; 25738 var ListExtension2 = mod6.ListExtension; 25739 var ListItemNode2 = mod6.ListItemNode; 25740 var ListNode2 = mod6.ListNode; 25741 var REMOVE_LIST_COMMAND2 = mod6.REMOVE_LIST_COMMAND; 25742 var UPDATE_LIST_START_COMMAND2 = mod6.UPDATE_LIST_START_COMMAND; 25743 var insertList2 = mod6.insertList; 25744 var registerCheckList2 = mod6.registerCheckList; 25745 var registerList2 = mod6.registerList; 25746 var registerListStrictIndentTransform2 = mod6.registerListStrictIndentTransform; 25747 var removeList2 = mod6.removeList; 25748 25749
vendor: 251 bytes, lines 25749-25756
25749// node_modules/@lexical/plain-text/LexicalPlainText.dev.mjs 25750 var LexicalPlainText_dev_exports = {}; 25751 __export(LexicalPlainText_dev_exports, { 25752 PlainTextExtension: () => PlainTextExtension, 25753 registerPlainText: () => registerPlainText 25754 }); 25755 25756
vendor: 980 bytes, lines 25756-25774
25756// node_modules/@lexical/clipboard/LexicalClipboard.dev.mjs 25757 var LexicalClipboard_dev_exports = {}; 25758 __export(LexicalClipboard_dev_exports, { 25759 $generateJSONFromSelectedNodes: () => $generateJSONFromSelectedNodes, 25760 $generateNodesFromSerializedNodes: () => $generateNodesFromSerializedNodes, 25761 $getClipboardDataFromSelection: () => $getClipboardDataFromSelection, 25762 $getHtmlContent: () => $getHtmlContent, 25763 $getLexicalContent: () => $getLexicalContent, 25764 $handlePlainTextDrop: () => $handlePlainTextDrop, 25765 $handleRichTextDrop: () => $handleRichTextDrop, 25766 $insertDataTransferForPlainText: () => $insertDataTransferForPlainText, 25767 $insertDataTransferForRichText: () => $insertDataTransferForRichText, 25768 $insertGeneratedNodes: () => $insertGeneratedNodes, 25769 $writeDragSourceToDataTransfer: () => $writeDragSourceToDataTransfer, 25770 copyToClipboard: () => copyToClipboard, 25771 setLexicalClipboardDataTransfer: () => setLexicalClipboardDataTransfer 25772 }); 25773 25774
vendor: 24,728 bytes, lines 25774-26476
25774// node_modules/@lexical/html/LexicalHtml.dev.mjs 25775 var LexicalHtml_dev_exports = {}; 25776 __export(LexicalHtml_dev_exports, { 25777 $generateDOMFromNodes: () => $generateDOMFromNodes, 25778 $generateDOMFromRoot: () => $generateDOMFromRoot, 25779 $generateHtmlFromNodes: () => $generateHtmlFromNodes, 25780 $generateNodesFromDOM: () => $generateNodesFromDOM, 25781 $getRenderContextValue: () => $getRenderContextValue, 25782 $withRenderContext: () => $withRenderContext, 25783 DOMRenderExtension: () => DOMRenderExtension, 25784 RenderContextExport: () => RenderContextExport, 25785 RenderContextRoot: () => RenderContextRoot, 25786 contextUpdater: () => contextUpdater, 25787 contextValue: () => contextValue, 25788 createRenderState: () => createRenderState, 25789 domOverride: () => domOverride 25790 }); 25791 function formatDevErrorMessage7(message) { 25792 throw new Error(message); 25793 } 25794 var activeContext; 25795 function getContextValue(contextRecord, cfg) { 25796 const { 25797 key 25798 } = cfg; 25799 return contextRecord && key in contextRecord ? contextRecord[key] : cfg.defaultValue; 25800 } 25801 function getEditorContext(editor) { 25802 return activeContext && activeContext.editor === editor ? activeContext : void 0; 25803 } 25804 function getContextRecord(sym, editor) { 25805 const editorContext = getEditorContext(editor); 25806 return editorContext && editorContext[sym]; 25807 } 25808 function toPair(contextRecord, pairOrUpdater) { 25809 if ("cfg" in pairOrUpdater) { 25810 const { 25811 cfg, 25812 updater 25813 } = pairOrUpdater; 25814 return [cfg, updater(getContextValue(contextRecord, cfg))]; 25815 } 25816 return pairOrUpdater; 25817 } 25818 function contextFromPairs(pairs, parent) { 25819 let rval = parent; 25820 for (const pairOrUpdater of pairs) { 25821 const [k2, v3] = toPair(rval, pairOrUpdater); 25822 const key = k2.key; 25823 if (rval === parent && getContextValue(rval, k2) === v3) { 25824 continue; 25825 } 25826 const ctx = rval || createChildContext(parent); 25827 ctx[key] = v3; 25828 rval = ctx; 25829 } 25830 return rval; 25831 } 25832 function createChildContext(parent) { 25833 return Object.create(parent || null); 25834 } 25835 function contextValue(cfg, value) { 25836 return [cfg, value]; 25837 } 25838 function contextUpdater(cfg, updater) { 25839 return { 25840 cfg, 25841 updater 25842 }; 25843 } 25844 // @__NO_SIDE_EFFECTS__ 25845 function $withFullContext(sym, contextRecord, f, editor = $getEditor2()) { 25846 const prevDOMContext = activeContext; 25847 const parentEditorContext = getEditorContext(editor); 25848 try { 25849 activeContext = { 25850 ...parentEditorContext, 25851 editor, 25852 [sym]: contextRecord 25853 }; 25854 return f(); 25855 } finally { 25856 activeContext = prevDOMContext; 25857 } 25858 } 25859 // @__NO_SIDE_EFFECTS__ 25860 function $withContext(sym, $defaults = () => void 0) { 25861 return (cfg, editor = $getEditor2()) => { 25862 return (f) => { 25863 const parentEditorContext = getEditorContext(editor); 25864 const parentContextRecord = parentEditorContext && parentEditorContext[sym]; 25865 const contextRecord = contextFromPairs(cfg, parentContextRecord || $defaults(editor)); 25866 if (!contextRecord || contextRecord === parentContextRecord) { 25867 return f(); 25868 } 25869 return /* @__PURE__ */ $withFullContext(sym, contextRecord, f, editor); 25870 }; 25871 }; 25872 } 25873 // @__NO_SIDE_EFFECTS__ 25874 function createContextState(tag, name, getDefaultValue, isEqual2) { 25875 return Object.assign(createState2(Symbol(name), { 25876 isEqual: isEqual2, 25877 parse: getDefaultValue 25878 }), { 25879 [tag]: true 25880 }); 25881 } 25882 var DOMRenderExtensionName = "@lexical/html/DOM"; 25883 var DOMRenderContextSymbol = Symbol.for("@lexical/html/DOMExportContext"); 25884 var ALWAYS_TRUE = () => true; 25885 function buildTypeTree(editorConfig) { 25886 const t2 = {}; 25887 const { 25888 nodes 25889 } = getKnownTypesAndNodes2(editorConfig); 25890 for (const klass of nodes) { 25891 const type = klass.getType(); 25892 t2[type] = { 25893 klass, 25894 types: {} 25895 }; 25896 } 25897 for (const baseRec of Object.values(t2)) { 25898 if (baseRec) { 25899 const baseType = baseRec.klass.getType(); 25900 for (let { 25901 klass 25902 } = baseRec; $isLexicalNode2(klass.prototype); klass = Object.getPrototypeOf(klass)) { 25903 const { 25904 ownNodeType 25905 } = getStaticNodeConfig2(klass); 25906 const superRec = ownNodeType && t2[ownNodeType]; 25907 if (superRec) { 25908 superRec.types[baseType] = true; 25909 } 25910 } 25911 } 25912 } 25913 return t2; 25914 } 25915 function buildNodePredicate(klass) { 25916 return (node) => node instanceof klass; 25917 } 25918 function getPredicate(typeTree, { 25919 nodes 25920 }) { 25921 if (nodes === "*") { 25922 return ALWAYS_TRUE; 25923 } 25924 let types = {}; 25925 const predicates = []; 25926 for (const klassOrPredicate of nodes) { 25927 if ("getType" in klassOrPredicate) { 25928 const type = klassOrPredicate.getType(); 25929 if (types) { 25930 const tree = typeTree[type]; 25931 if (!(tree !== void 0)) { 25932 formatDevErrorMessage7(`Node class ${klassOrPredicate.name} with type ${type} not registered in editor`); 25933 } 25934 types = Object.assign(types, tree.types); 25935 } 25936 predicates.push(buildNodePredicate(klassOrPredicate)); 25937 } else { 25938 types = void 0; 25939 predicates.push(klassOrPredicate); 25940 } 25941 } 25942 if (types) { 25943 return types; 25944 } else if (predicates.length === 1) { 25945 return predicates[0]; 25946 } 25947 return (node) => { 25948 for (const predicate of predicates) { 25949 if (predicate(node)) { 25950 return true; 25951 } 25952 } 25953 return false; 25954 }; 25955 } 25956 function makePrerender() { 25957 return { 25958 $createDOM: [], 25959 $decorateDOM: [], 25960 $exportDOM: [], 25961 $extractWithChild: [], 25962 $getDOMSlot: [], 25963 $shouldExclude: [], 25964 $shouldInclude: [], 25965 $updateDOM: [] 25966 }; 25967 } 25968 function ignoreNext2(acc) { 25969 return (node, _$next, editor) => acc(node, editor); 25970 } 25971 function ignoreNext3(acc) { 25972 return (node, a2, _$next, editor) => acc(node, a2, editor); 25973 } 25974 function ignoreNext4(acc) { 25975 return (node, a2, b3, _$next, editor) => acc(node, a2, b3, editor); 25976 } 25977 function ignoreNext5(acc) { 25978 return (node, a2, b3, c2, _$next, editor) => acc(node, a2, b3, c2, editor); 25979 } 25980 function merge2($acc, $getOverride) { 25981 return (node, editor) => { 25982 const $next = () => $acc(node, editor); 25983 const $override = $getOverride(node); 25984 return $override ? $override(node, $next, editor) : $next(); 25985 }; 25986 } 25987 function merge3(acc, $getOverride) { 25988 return (node, a2, editor) => { 25989 const $next = () => acc(node, a2, editor); 25990 const $override = $getOverride(node); 25991 return $override ? $override(node, a2, $next, editor) : $next(); 25992 }; 25993 } 25994 function merge4($acc, $getOverride) { 25995 return (node, a2, b3, editor) => { 25996 const $next = () => $acc(node, a2, b3, editor); 25997 const $override = $getOverride(node); 25998 return $override ? $override(node, a2, b3, $next, editor) : $next(); 25999 }; 26000 } 26001 function merge5(acc, $getOverride) { 26002 return (node, a2, b3, c2, editor) => { 26003 const $next = () => acc(node, a2, b3, c2, editor); 26004 const $override = $getOverride(node); 26005 return $override ? $override(node, a2, b3, c2, $next, editor) : $next(); 26006 }; 26007 } 26008 function sequence4($acc, $getOverride) { 26009 return (node, a2, b3, editor) => { 26010 $acc(node, a2, b3, editor); 26011 const $override = $getOverride(node); 26012 if ($override) { 26013 $override(node, a2, b3, editor); 26014 } 26015 }; 26016 } 26017 function compilePrerenderKey(prerender, k2, defaults, mergeFunction, ignoreNextFunction) { 26018 let acc = defaults[k2]; 26019 for (const pair of prerender[k2]) { 26020 if (typeof pair[0] === "function") { 26021 const [$predicate, $override] = pair; 26022 acc = mergeFunction(acc, (node) => $predicate(node) && $override || void 0); 26023 } else { 26024 const typeOverrides = pair[1]; 26025 const compiled = {}; 26026 for (const type in typeOverrides) { 26027 const arr = typeOverrides[type]; 26028 if (arr) { 26029 compiled[type] = arr.reduce(($acc, $override) => mergeFunction($acc, () => $override), acc); 26030 } 26031 } 26032 acc = mergeFunction(acc, (node) => { 26033 const f = compiled[node.getType()]; 26034 return f && ignoreNextFunction(f); 26035 }); 26036 } 26037 } 26038 defaults[k2] = acc; 26039 } 26040 function addOverride(prerender, k2, predicateOrTypes, override) { 26041 if (!override) { 26042 return; 26043 } 26044 const arr = prerender[k2]; 26045 if (typeof predicateOrTypes === "function") { 26046 arr.push([predicateOrTypes, override]); 26047 } else { 26048 const last = arr[arr.length - 1]; 26049 let types; 26050 if (last && last[0] === "types") { 26051 types = last[1]; 26052 } else { 26053 types = {}; 26054 arr.push(["types", types]); 26055 } 26056 for (const type in predicateOrTypes) { 26057 const typeArr = types[type] || []; 26058 types[type] = typeArr; 26059 typeArr.push(override); 26060 } 26061 } 26062 } 26063 function isWildcard(override) { 26064 return override.nodes === "*"; 26065 } 26066 function sortedOverrides(overrides) { 26067 const byWildcard = []; 26068 const byPredicate = []; 26069 const byNode = []; 26070 for (const override of overrides) { 26071 if (isWildcard(override)) { 26072 byWildcard.push(override); 26073 } else if (Array.isArray(override.nodes)) { 26074 for (const klassOrPredicate of override.nodes) { 26075 if ($isLexicalNode2(klassOrPredicate.prototype)) { 26076 byNode.push(override.nodes.length === 1 ? override : { 26077 ...override, 26078 nodes: [klassOrPredicate] 26079 }); 26080 } else { 26081 byPredicate.push(override.nodes.length === 1 ? override : { 26082 ...override, 26083 nodes: [klassOrPredicate] 26084 }); 26085 } 26086 } 26087 } 26088 } 26089 const depths = /* @__PURE__ */ new Map(); 26090 const depthOf = (klass) => { 26091 let depth = depths.get(klass); 26092 if (depth === void 0) { 26093 depth = 0; 26094 for (let k2 = klass; $isLexicalNode2(k2.prototype); k2 = Object.getPrototypeOf(k2)) { 26095 depth++; 26096 } 26097 depths.set(klass, depth); 26098 } 26099 return depth; 26100 }; 26101 byNode.sort((a2, b3) => depthOf(a2.nodes[0]) - depthOf(b3.nodes[0])); 26102 return [...byNode, ...byPredicate, ...byWildcard]; 26103 } 26104 function precompileDOMRenderConfigOverrides(editorConfig, overrides) { 26105 const typeTree = buildTypeTree(editorConfig); 26106 const prerender = makePrerender(); 26107 for (const override of sortedOverrides(overrides)) { 26108 const predicateOrTypes = getPredicate(typeTree, override); 26109 for (const k_ in prerender) { 26110 const k2 = k_; 26111 addOverride(prerender, k2, predicateOrTypes, override[k2]); 26112 } 26113 } 26114 return prerender; 26115 } 26116 function identity(v3) { 26117 return v3; 26118 } 26119 function compileDOMRenderConfigOverrides(editorConfig, { 26120 overrides 26121 }) { 26122 const prerender = precompileDOMRenderConfigOverrides(editorConfig, overrides); 26123 const dom = { 26124 ...DEFAULT_EDITOR_DOM_CONFIG2, 26125 ...editorConfig.dom 26126 }; 26127 compilePrerenderKey(prerender, "$createDOM", dom, merge2, ignoreNext2); 26128 compilePrerenderKey(prerender, "$exportDOM", dom, merge2, ignoreNext2); 26129 compilePrerenderKey(prerender, "$extractWithChild", dom, merge5, ignoreNext5); 26130 compilePrerenderKey(prerender, "$getDOMSlot", dom, merge3, ignoreNext3); 26131 compilePrerenderKey(prerender, "$shouldExclude", dom, merge3, ignoreNext3); 26132 compilePrerenderKey(prerender, "$shouldInclude", dom, merge3, ignoreNext3); 26133 compilePrerenderKey(prerender, "$updateDOM", dom, merge4, ignoreNext4); 26134 compilePrerenderKey(prerender, "$decorateDOM", dom, sequence4, identity); 26135 return dom; 26136 } 26137 var DOMRenderExtension = defineExtension2({ 26138 build(editor, config, state) { 26139 return { 26140 defaults: contextFromPairs(config.contextDefaults, void 0) 26141 }; 26142 }, 26143 config: { 26144 contextDefaults: [], 26145 overrides: [] 26146 }, 26147 html: { 26148 // Define a RootNode export for $generateDOMFromRoot 26149 export: /* @__PURE__ */ new Map([[RootNode2, () => { 26150 const element = document.createElement("div"); 26151 element.role = "textbox"; 26152 return { 26153 element 26154 }; 26155 }]]) 26156 }, 26157 init(editorConfig, config) { 26158 editorConfig.dom = compileDOMRenderConfigOverrides(editorConfig, config); 26159 }, 26160 mergeConfig(config, partial) { 26161 const merged = shallowMergeConfig2(config, partial); 26162 for (const k2 of ["overrides", "contextDefaults"]) { 26163 if (partial[k2]) { 26164 merged[k2] = [...config[k2], ...partial[k2]]; 26165 } 26166 } 26167 return merged; 26168 }, 26169 name: DOMRenderExtensionName 26170 }); 26171 // @__NO_SIDE_EFFECTS__ 26172 function createRenderState(name, getDefaultValue, isEqual2) { 26173 return /* @__PURE__ */ createContextState(DOMRenderContextSymbol, name, getDefaultValue, isEqual2); 26174 } 26175 var RenderContextRoot = /* @__PURE__ */ createRenderState("root", Boolean); 26176 var RenderContextExport = /* @__PURE__ */ createRenderState("isExport", Boolean); 26177 function getDefaultRenderContext(editor) { 26178 const builder = LexicalBuilder2.maybeFromEditor(editor); 26179 return builder && builder.hasExtensionByName(DOMRenderExtensionName) ? getExtensionDependencyFromEditor2(editor, DOMRenderExtension).output.defaults : void 0; 26180 } 26181 function getRenderContext(editor) { 26182 return getContextRecord(DOMRenderContextSymbol, editor) || getDefaultRenderContext(editor); 26183 } 26184 function $getRenderContextValue(cfg, editor = $getEditor2()) { 26185 return getContextValue(getRenderContext(editor), cfg); 26186 } 26187 var $withRenderContext = /* @__PURE__ */ $withContext(DOMRenderContextSymbol, getDefaultRenderContext); 26188 // @__NO_SIDE_EFFECTS__ 26189 function domOverride(nodes, config) { 26190 return { 26191 ...config, 26192 nodes 26193 }; 26194 } 26195 function isStyleRule(rule) { 26196 return rule.constructor.name === CSSStyleRule.name; 26197 } 26198 function inlineStylesFromStyleSheets(doc) { 26199 if (doc.querySelector("style") === null) { 26200 return; 26201 } 26202 const originalInlineStyles = /* @__PURE__ */ new Map(); 26203 function getOriginalInlineProps(el) { 26204 let props = originalInlineStyles.get(el); 26205 if (props === void 0) { 26206 props = /* @__PURE__ */ new Set(); 26207 for (let i2 = 0; i2 < el.style.length; i2++) { 26208 props.add(el.style[i2]); 26209 } 26210 originalInlineStyles.set(el, props); 26211 } 26212 return props; 26213 } 26214 try { 26215 for (const sheet of Array.from(doc.styleSheets)) { 26216 let rules; 26217 try { 26218 rules = sheet.cssRules; 26219 } catch (_unused) { 26220 continue; 26221 } 26222 for (const rule of Array.from(rules)) { 26223 if (!isStyleRule(rule)) { 26224 continue; 26225 } 26226 let elements; 26227 try { 26228 elements = doc.querySelectorAll(rule.selectorText); 26229 } catch (_unused2) { 26230 continue; 26231 } 26232 for (const el of Array.from(elements)) { 26233 if (!isHTMLElement2(el)) { 26234 continue; 26235 } 26236 const originalProps = getOriginalInlineProps(el); 26237 for (let i2 = 0; i2 < rule.style.length; i2++) { 26238 const prop = rule.style[i2]; 26239 if (!originalProps.has(prop)) { 26240 el.style.setProperty(prop, rule.style.getPropertyValue(prop), rule.style.getPropertyPriority(prop)); 26241 } 26242 } 26243 } 26244 } 26245 } 26246 } catch (_unused3) { 26247 } 26248 } 26249 var IGNORE_TAGS = /* @__PURE__ */ new Set(["STYLE", "SCRIPT"]); 26250 function $generateNodesFromDOM(editor, dom) { 26251 if (isDOMDocumentNode2(dom)) { 26252 inlineStylesFromStyleSheets(dom); 26253 } 26254 const elements = isDOMDocumentNode2(dom) ? dom.body.childNodes : dom.childNodes; 26255 const lexicalNodes = []; 26256 const allArtificialNodes = []; 26257 for (const element of elements) { 26258 if (!IGNORE_TAGS.has(element.nodeName)) { 26259 const lexicalNode = $createNodesFromDOM(element, editor, allArtificialNodes, false); 26260 if (lexicalNode !== null) { 26261 for (const node of lexicalNode) { 26262 lexicalNodes.push(node); 26263 } 26264 } 26265 } 26266 } 26267 $unwrapArtificialNodes(allArtificialNodes); 26268 return lexicalNodes; 26269 } 26270 function $generateDOMFromNodes(container, selection = null, editor = $getEditor2()) { 26271 return $withRenderContext([contextValue(RenderContextExport, true)], editor)(() => { 26272 const root = $getRoot2(); 26273 const domConfig = $getEditorDOMRenderConfig2(editor); 26274 const parentElementAppend = container.append.bind(container); 26275 for (const topLevelNode of root.getChildren()) { 26276 $appendNodesToHTML(editor, topLevelNode, parentElementAppend, selection, domConfig); 26277 } 26278 return container; 26279 }); 26280 } 26281 function $generateDOMFromRoot(container, root = $getRoot2()) { 26282 const editor = $getEditor2(); 26283 return $withRenderContext([contextValue(RenderContextExport, true), contextValue(RenderContextRoot, true)], editor)(() => { 26284 const selection = null; 26285 const domConfig = $getEditorDOMRenderConfig2(editor); 26286 const parentElementAppend = container.append.bind(container); 26287 $appendNodesToHTML(editor, root, parentElementAppend, selection, domConfig); 26288 return container; 26289 }); 26290 } 26291 function $generateHtmlFromNodes(editor, selection = null) { 26292 if (typeof document === "undefined" || typeof window === "undefined" && typeof global.window === "undefined") { 26293 { 26294 formatDevErrorMessage7(`To use $generateHtmlFromNodes in headless mode please initialize a headless browser implementation such as JSDom or use withDOM from @lexical/headless/dom before calling this function.`); 26295 } 26296 } 26297 return $generateDOMFromNodes(document.createElement("div"), selection, editor).innerHTML; 26298 } 26299 function $appendNodesToHTML(editor, currentNode, parentElementAppend, selection = null, domConfig = $getEditorDOMRenderConfig2(editor)) { 26300 let shouldInclude = domConfig.$shouldInclude(currentNode, selection, editor); 26301 const shouldExclude = domConfig.$shouldExclude(currentNode, selection, editor); 26302 let target = currentNode; 26303 if (selection !== null && $isTextNode2(currentNode)) { 26304 target = $sliceSelectedTextNodeContent2(selection, currentNode, "clone"); 26305 } 26306 const exportProps = domConfig.$exportDOM(target, editor); 26307 const { 26308 element, 26309 after, 26310 append: append2, 26311 $getChildNodes 26312 } = exportProps; 26313 if (!element) { 26314 return false; 26315 } 26316 const fragment = document.createDocumentFragment(); 26317 const children = $getChildNodes ? $getChildNodes() : $isElementNode2(target) ? target.getChildren() : []; 26318 const fragmentAppend = fragment.append.bind(fragment); 26319 for (const childNode of children) { 26320 const shouldIncludeChild = $appendNodesToHTML(editor, childNode, fragmentAppend, selection, domConfig); 26321 if (!shouldInclude && shouldIncludeChild && domConfig.$extractWithChild(currentNode, childNode, selection, "html", editor)) { 26322 shouldInclude = true; 26323 } 26324 } 26325 if (shouldInclude && !shouldExclude) { 26326 if (isHTMLElement2(element) || isDocumentFragment2(element)) { 26327 if (append2) { 26328 append2(fragment); 26329 } else { 26330 element.append(fragment); 26331 } 26332 } 26333 parentElementAppend(element); 26334 if (after) { 26335 const newElement = after.call(target, element); 26336 if (newElement) { 26337 if (isDocumentFragment2(element)) { 26338 element.replaceChildren(newElement); 26339 } else { 26340 element.replaceWith(newElement); 26341 } 26342 } 26343 } 26344 } else { 26345 parentElementAppend(fragment); 26346 } 26347 return shouldInclude; 26348 } 26349 function getConversionFunction(domNode, editor) { 26350 const { 26351 nodeName 26352 } = domNode; 26353 const cachedConversions = editor._htmlConversions.get(nodeName.toLowerCase()); 26354 let currentConversion = null; 26355 if (cachedConversions !== void 0) { 26356 for (const cachedConversion of cachedConversions) { 26357 const domConversion = cachedConversion(domNode); 26358 if (domConversion !== null && (currentConversion === null || // Given equal priority, prefer the last registered importer 26359 // which is typically an application custom node or HTMLConfig['import'] 26360 (currentConversion.priority || 0) <= (domConversion.priority || 0))) { 26361 currentConversion = domConversion; 26362 } 26363 } 26364 } 26365 return currentConversion !== null ? currentConversion.conversion : null; 26366 } 26367 function $createNodesFromDOM(node, editor, allArtificialNodes, hasBlockAncestorLexicalNode, forChildMap = /* @__PURE__ */ new Map(), parentLexicalNode) { 26368 const lexicalNodes = []; 26369 if (IGNORE_TAGS.has(node.nodeName)) { 26370 return lexicalNodes; 26371 } 26372 let currentLexicalNode = null; 26373 const transformFunction = getConversionFunction(node, editor); 26374 const transformOutput = transformFunction ? transformFunction(node) : null; 26375 let postTransform = null; 26376 if (transformOutput !== null) { 26377 postTransform = transformOutput.after; 26378 const transformNodes = transformOutput.node; 26379 currentLexicalNode = Array.isArray(transformNodes) ? transformNodes[transformNodes.length - 1] : transformNodes; 26380 if (currentLexicalNode !== null) { 26381 for (const [, forChildFunction] of forChildMap) { 26382 currentLexicalNode = forChildFunction(currentLexicalNode, parentLexicalNode); 26383 if (!currentLexicalNode) { 26384 break; 26385 } 26386 } 26387 if (currentLexicalNode) { 26388 lexicalNodes.push(...Array.isArray(transformNodes) ? transformNodes : [currentLexicalNode]); 26389 } 26390 } 26391 if (transformOutput.forChild != null) { 26392 forChildMap.set(node.nodeName, transformOutput.forChild); 26393 } 26394 } 26395 const children = node.childNodes; 26396 let childLexicalNodes = []; 26397 const hasBlockAncestorLexicalNodeForChildren = currentLexicalNode != null && $isRootOrShadowRoot2(currentLexicalNode) ? false : currentLexicalNode != null && $isBlockElementNode2(currentLexicalNode) || hasBlockAncestorLexicalNode; 26398 for (let i2 = 0; i2 < children.length; i2++) { 26399 childLexicalNodes.push(...$createNodesFromDOM(children[i2], editor, allArtificialNodes, hasBlockAncestorLexicalNodeForChildren, new Map(forChildMap), currentLexicalNode)); 26400 } 26401 if (postTransform != null) { 26402 childLexicalNodes = postTransform(childLexicalNodes); 26403 } 26404 if (isBlockDomNode2(node)) { 26405 if (!hasBlockAncestorLexicalNodeForChildren) { 26406 childLexicalNodes = wrapContinuousInlines(node, childLexicalNodes, $createParagraphNode2); 26407 } else { 26408 childLexicalNodes = wrapContinuousInlines(node, childLexicalNodes, () => { 26409 const artificialNode = new ArtificialNode__DO_NOT_USE2(); 26410 allArtificialNodes.push(artificialNode); 26411 return artificialNode; 26412 }); 26413 } 26414 } 26415 if (currentLexicalNode == null) { 26416 if (childLexicalNodes.length > 0) { 26417 for (const childNode of childLexicalNodes) { 26418 lexicalNodes.push(childNode); 26419 } 26420 } else { 26421 if (isBlockDomNode2(node) && isDomNodeBetweenTwoInlineNodes(node)) { 26422 lexicalNodes.push($createLineBreakNode2()); 26423 } 26424 } 26425 } else { 26426 if ($isElementNode2(currentLexicalNode)) { 26427 currentLexicalNode.append(...childLexicalNodes); 26428 } 26429 } 26430 return lexicalNodes; 26431 } 26432 function wrapContinuousInlines(domNode, nodes, createWrapperFn) { 26433 const textAlign = domNode.style.textAlign; 26434 const out = []; 26435 let continuousInlines = []; 26436 for (let i2 = 0; i2 < nodes.length; i2++) { 26437 const node = nodes[i2]; 26438 if ($isBlockElementNode2(node)) { 26439 if (textAlign && !node.getFormat()) { 26440 node.setFormat(textAlign); 26441 } 26442 out.push(node); 26443 } else { 26444 continuousInlines.push(node); 26445 if (i2 === nodes.length - 1 || i2 < nodes.length - 1 && $isBlockElementNode2(nodes[i2 + 1])) { 26446 const wrapper = createWrapperFn(); 26447 wrapper.setFormat(textAlign); 26448 wrapper.append(...continuousInlines); 26449 out.push(wrapper); 26450 continuousInlines = []; 26451 } 26452 } 26453 } 26454 return out; 26455 } 26456 function $unwrapArtificialNodes(allArtificialNodes) { 26457 for (const node of allArtificialNodes) { 26458 if (node.getParent() && node.getNextSibling() instanceof ArtificialNode__DO_NOT_USE2) { 26459 node.insertAfter($createLineBreakNode2()); 26460 } 26461 } 26462 for (const node of allArtificialNodes) { 26463 const parent = node.getParent(); 26464 if (parent) { 26465 parent.splice(node.getIndexWithinParent(), 1, node.getChildren()); 26466 } 26467 } 26468 } 26469 function isDomNodeBetweenTwoInlineNodes(node) { 26470 if (node.nextSibling == null || node.previousSibling == null) { 26471 return false; 26472 } 26473 return isInlineDomNode2(node.nextSibling) && isInlineDomNode2(node.previousSibling); 26474 } 26475 26476
vendor: 806 bytes, lines 26476-26492
26476// node_modules/@lexical/html/LexicalHtml.mjs 26477 var mod7 = true ? LexicalHtml_dev_exports : LexicalHtml_prod_exports; 26478 var $generateDOMFromNodes2 = mod7.$generateDOMFromNodes; 26479 var $generateDOMFromRoot2 = mod7.$generateDOMFromRoot; 26480 var $generateHtmlFromNodes2 = mod7.$generateHtmlFromNodes; 26481 var $generateNodesFromDOM2 = mod7.$generateNodesFromDOM; 26482 var $getRenderContextValue2 = mod7.$getRenderContextValue; 26483 var $withRenderContext2 = mod7.$withRenderContext; 26484 var DOMRenderExtension2 = mod7.DOMRenderExtension; 26485 var RenderContextExport2 = mod7.RenderContextExport; 26486 var RenderContextRoot2 = mod7.RenderContextRoot; 26487 var contextUpdater2 = mod7.contextUpdater; 26488 var contextValue2 = mod7.contextValue; 26489 var createRenderState2 = mod7.createRenderState; 26490 var domOverride2 = mod7.domOverride; 26491 26492
vendor: 17,374 bytes, lines 26492-26978
26492// node_modules/@lexical/clipboard/LexicalClipboard.dev.mjs 26493 function formatDevErrorMessage8(message) { 26494 throw new Error(message); 26495 } 26496 function caretFromPoint(x3, y3) { 26497 if (typeof document.caretRangeFromPoint !== "undefined") { 26498 const range2 = document.caretRangeFromPoint(x3, y3); 26499 if (range2 === null) { 26500 return null; 26501 } 26502 return { 26503 node: range2.startContainer, 26504 offset: range2.startOffset 26505 }; 26506 } else if (document.caretPositionFromPoint !== "undefined") { 26507 const range2 = document.caretPositionFromPoint(x3, y3); 26508 if (range2 === null) { 26509 return null; 26510 } 26511 return { 26512 node: range2.offsetNode, 26513 offset: range2.offset 26514 }; 26515 } else { 26516 return null; 26517 } 26518 } 26519 function $getHtmlContent(editor, selection = $getSelection2()) { 26520 if (selection == null) { 26521 { 26522 formatDevErrorMessage8(`Expected valid LexicalSelection`); 26523 } 26524 } 26525 if ($isRangeSelection2(selection) && selection.isCollapsed() || selection.getNodes().length === 0) { 26526 return ""; 26527 } 26528 return $generateHtmlFromNodes2(editor, selection); 26529 } 26530 function $getLexicalContent(editor, selection = $getSelection2()) { 26531 if (selection == null) { 26532 { 26533 formatDevErrorMessage8(`Expected valid LexicalSelection`); 26534 } 26535 } 26536 if ($isRangeSelection2(selection) && selection.isCollapsed() || selection.getNodes().length === 0) { 26537 return null; 26538 } 26539 return JSON.stringify($generateJSONFromSelectedNodes(editor, selection)); 26540 } 26541 function $insertDataTransferForPlainText(dataTransfer, selection) { 26542 const text2 = dataTransfer.getData("text/plain") || dataTransfer.getData("text/uri-list"); 26543 if (text2 != null) { 26544 selection.insertRawText(text2); 26545 } 26546 } 26547 function $insertDataTransferForRichText(dataTransfer, selection, editor) { 26548 const lexicalString = dataTransfer.getData("application/x-lexical-editor"); 26549 if (lexicalString) { 26550 try { 26551 const payload = JSON.parse(lexicalString); 26552 if (payload.namespace === editor._config.namespace && Array.isArray(payload.nodes)) { 26553 const nodes = $generateNodesFromSerializedNodes(payload.nodes); 26554 return $insertGeneratedNodes(editor, nodes, selection); 26555 } 26556 } catch (error) { 26557 console.error(error); 26558 } 26559 } 26560 const htmlString = dataTransfer.getData("text/html"); 26561 const plainString = dataTransfer.getData("text/plain"); 26562 if (htmlString && plainString !== htmlString) { 26563 try { 26564 const parser = new DOMParser(); 26565 const dom = parser.parseFromString(trustHTML(htmlString), "text/html"); 26566 const nodes = $generateNodesFromDOM2(editor, dom); 26567 return $insertGeneratedNodes(editor, nodes, selection); 26568 } catch (error) { 26569 console.error(error); 26570 } 26571 } 26572 const text2 = plainString || dataTransfer.getData("text/uri-list"); 26573 if (text2 != null) { 26574 if ($isRangeSelection2(selection)) { 26575 const parts = text2.split(/(\r?\n|\t)/); 26576 if (parts[parts.length - 1] === "") { 26577 parts.pop(); 26578 } 26579 for (let i2 = 0; i2 < parts.length; i2++) { 26580 const currentSelection = $getSelection2(); 26581 if ($isRangeSelection2(currentSelection)) { 26582 const part = parts[i2]; 26583 if (part === "\n" || part === "\r\n") { 26584 currentSelection.insertParagraph(); 26585 } else if (part === " ") { 26586 currentSelection.insertNodes([$createTabNode2()]); 26587 } else { 26588 currentSelection.insertText(part); 26589 } 26590 } 26591 } 26592 } else { 26593 selection.insertRawText(text2); 26594 } 26595 } 26596 } 26597 var LEXICAL_DRAG_MIME_TYPE = "application/x-lexical-drag"; 26598 function $writeDragSourceToDataTransfer(dataTransfer, editor) { 26599 const marker = { 26600 editorKey: editor.getKey() 26601 }; 26602 dataTransfer.setData(LEXICAL_DRAG_MIME_TYPE, JSON.stringify(marker)); 26603 } 26604 function isLexicalDragMarker(value) { 26605 return value !== null && typeof value === "object" && "editorKey" in value && typeof value.editorKey === "string"; 26606 } 26607 function readDragMarker(dataTransfer) { 26608 const raw = dataTransfer.getData(LEXICAL_DRAG_MIME_TYPE); 26609 if (!raw) { 26610 return null; 26611 } 26612 let parsed; 26613 try { 26614 parsed = JSON.parse(raw); 26615 } catch (_unused) { 26616 return null; 26617 } 26618 return isLexicalDragMarker(parsed) ? parsed : null; 26619 } 26620 function findEditorRootByKey(key, doc) { 26621 const elements = doc.querySelectorAll('[data-lexical-editor="true"]'); 26622 for (const el of Array.from(elements)) { 26623 const editor = el.__lexicalEditor; 26624 if (editor && editor.getKey() === key) { 26625 return el; 26626 } 26627 } 26628 return null; 26629 } 26630 function $resolveDropPointCaret(event) { 26631 const hit = caretFromPoint(event.clientX, event.clientY); 26632 if (hit === null) { 26633 return null; 26634 } 26635 const node = $getNearestNodeFromDOMNode2(hit.node); 26636 if (node === null) { 26637 return null; 26638 } 26639 if ($isTextNode2(node)) { 26640 return $getTextPointCaret2(node, "next", hit.offset); 26641 } 26642 if ($isElementNode2(node)) { 26643 return $getChildCaretAtIndex2(node, hit.offset, "next"); 26644 } 26645 const parent = node.getParent(); 26646 if (parent === null) { 26647 return null; 26648 } 26649 return $getChildCaretAtIndex2(parent, node.getIndexWithinParent() + 1, "next"); 26650 } 26651 function $isDropCaretInsideSelection(dropCaret, selection) { 26652 const { 26653 anchor: start3, 26654 focus: end 26655 } = $getCaretRangeInDirection2($caretRangeFromSelection2(selection), "next"); 26656 return $comparePointCaretNext2(start3, dropCaret) < 0 && $comparePointCaretNext2(dropCaret, end) < 0; 26657 } 26658 function $doDrop(event, editor, $insertDataTransfer) { 26659 const dataTransfer = event.dataTransfer; 26660 if (dataTransfer === null) { 26661 return false; 26662 } 26663 const marker = readDragMarker(dataTransfer); 26664 if (marker === null) { 26665 return false; 26666 } 26667 const dropCaret = $resolveDropPointCaret(event); 26668 if (dropCaret === null) { 26669 return false; 26670 } 26671 const stableDropCaret = $splitAtPointCaretNext2(dropCaret); 26672 if (stableDropCaret === null) { 26673 return false; 26674 } 26675 const isSameEditorDrag = marker.editorKey === editor.getKey(); 26676 const currentSelection = $getSelection2(); 26677 if (isSameEditorDrag) { 26678 if (!$isRangeSelection2(currentSelection) || currentSelection.isCollapsed()) { 26679 return false; 26680 } 26681 if ($isDropCaretInsideSelection(dropCaret, currentSelection)) { 26682 event.preventDefault(); 26683 return true; 26684 } 26685 currentSelection.removeText(); 26686 } 26687 if (!stableDropCaret.origin.isAttached()) { 26688 event.preventDefault(); 26689 return true; 26690 } 26691 const dropSelection = $setSelectionFromCaretRange2($getCollapsedCaretRange2(stableDropCaret)); 26692 $insertDataTransfer(dataTransfer, dropSelection, editor); 26693 if (!isSameEditorDrag) { 26694 const rootElement = editor.getRootElement(); 26695 const doc = rootElement ? rootElement.ownerDocument : null; 26696 const sourceRoot = doc ? findEditorRootByKey(marker.editorKey, doc) : null; 26697 if (sourceRoot !== null) { 26698 sourceRoot.dispatchEvent(new InputEvent("beforeinput", { 26699 bubbles: true, 26700 cancelable: true, 26701 inputType: "deleteByDrag" 26702 })); 26703 } 26704 } 26705 event.preventDefault(); 26706 return true; 26707 } 26708 function $handleRichTextDrop(event, editor) { 26709 return $doDrop(event, editor, $insertDataTransferForRichText); 26710 } 26711 function $handlePlainTextDrop(event, editor) { 26712 return $doDrop(event, editor, (dataTransfer, selection) => $insertDataTransferForPlainText(dataTransfer, selection)); 26713 } 26714 function trustHTML(html2) { 26715 if (window.trustedTypes && window.trustedTypes.createPolicy) { 26716 const policy = window.trustedTypes.createPolicy("lexical", { 26717 createHTML: (input) => input 26718 }); 26719 return policy.createHTML(html2); 26720 } 26721 return html2; 26722 } 26723 function $insertGeneratedNodes(editor, nodes, selection) { 26724 if (!editor.dispatchCommand(SELECTION_INSERT_CLIPBOARD_NODES_COMMAND2, { 26725 nodes, 26726 selection 26727 })) { 26728 selection.insertNodes(nodes); 26729 $updateSelectionOnInsert(selection); 26730 } 26731 return; 26732 } 26733 function $updateSelectionOnInsert(selection) { 26734 if ($isRangeSelection2(selection) && selection.isCollapsed()) { 26735 const anchor = selection.anchor; 26736 let nodeToInspect = null; 26737 const anchorCaret = $caretFromPoint2(anchor, "previous"); 26738 if (anchorCaret) { 26739 if ($isTextPointCaret2(anchorCaret)) { 26740 nodeToInspect = anchorCaret.origin; 26741 } else { 26742 const range2 = $getCaretRange2(anchorCaret, $getChildCaret2($getRoot2(), "next").getFlipped()); 26743 for (const caret of range2) { 26744 if ($isTextNode2(caret.origin)) { 26745 nodeToInspect = caret.origin; 26746 break; 26747 } else if ($isElementNode2(caret.origin) && !caret.origin.isInline()) { 26748 break; 26749 } 26750 } 26751 } 26752 } 26753 if (nodeToInspect && $isTextNode2(nodeToInspect)) { 26754 const newFormat = nodeToInspect.getFormat(); 26755 const newStyle = nodeToInspect.getStyle(); 26756 if (selection.format !== newFormat || selection.style !== newStyle) { 26757 selection.format = newFormat; 26758 selection.style = newStyle; 26759 selection.dirty = true; 26760 } 26761 } 26762 } 26763 } 26764 function exportNodeToJSON2(node) { 26765 const serializedNode = node.exportJSON(); 26766 const nodeClass = node.constructor; 26767 if (serializedNode.type !== nodeClass.getType()) { 26768 { 26769 formatDevErrorMessage8(`LexicalNode: Node ${nodeClass.name} does not implement .exportJSON().`); 26770 } 26771 } 26772 if ($isElementNode2(node)) { 26773 const serializedChildren = serializedNode.children; 26774 if (!Array.isArray(serializedChildren)) { 26775 { 26776 formatDevErrorMessage8(`LexicalNode: Node ${nodeClass.name} is an element but .exportJSON() does not have a children array.`); 26777 } 26778 } 26779 } 26780 return serializedNode; 26781 } 26782 function $appendNodesToJSON(editor, selection, currentNode, targetArray = []) { 26783 let shouldInclude = selection !== null ? currentNode.isSelected(selection) : true; 26784 const shouldExclude = $isElementNode2(currentNode) && currentNode.excludeFromCopy("html"); 26785 let target = currentNode; 26786 if (selection !== null && $isTextNode2(target)) { 26787 target = $sliceSelectedTextNodeContent2(selection, target, "clone"); 26788 } 26789 const children = $isElementNode2(target) ? target.getChildren() : []; 26790 const serializedNode = exportNodeToJSON2(target); 26791 if ($isTextNode2(target) && target.getTextContentSize() === 0) { 26792 shouldInclude = false; 26793 } 26794 for (let i2 = 0; i2 < children.length; i2++) { 26795 const childNode = children[i2]; 26796 const shouldIncludeChild = $appendNodesToJSON(editor, selection, childNode, serializedNode.children); 26797 if (!shouldInclude && $isElementNode2(currentNode) && shouldIncludeChild && currentNode.extractWithChild(childNode, selection, "clone")) { 26798 shouldInclude = true; 26799 } 26800 } 26801 if (shouldInclude && !shouldExclude) { 26802 targetArray.push(serializedNode); 26803 } else if (Array.isArray(serializedNode.children)) { 26804 for (let i2 = 0; i2 < serializedNode.children.length; i2++) { 26805 const serializedChildNode = serializedNode.children[i2]; 26806 targetArray.push(serializedChildNode); 26807 } 26808 } 26809 return shouldInclude; 26810 } 26811 function $generateJSONFromSelectedNodes(editor, selection) { 26812 const nodes = []; 26813 const root = $getRoot2(); 26814 const topLevelChildren = root.getChildren(); 26815 for (let i2 = 0; i2 < topLevelChildren.length; i2++) { 26816 const topLevelNode = topLevelChildren[i2]; 26817 $appendNodesToJSON(editor, selection, topLevelNode, nodes); 26818 } 26819 return { 26820 namespace: editor._config.namespace, 26821 nodes 26822 }; 26823 } 26824 function $generateNodesFromSerializedNodes(serializedNodes) { 26825 const nodes = []; 26826 for (let i2 = 0; i2 < serializedNodes.length; i2++) { 26827 const serializedNode = serializedNodes[i2]; 26828 const node = $parseSerializedNode2(serializedNode); 26829 nodes.push(node); 26830 } 26831 return nodes; 26832 } 26833 var EVENT_LATENCY = 50; 26834 var clipboardEventTimeout = null; 26835 async function copyToClipboard(editor, event, data) { 26836 if (clipboardEventTimeout !== null) { 26837 return false; 26838 } 26839 if (event !== null) { 26840 return new Promise((resolve, reject) => { 26841 editor.update(() => { 26842 resolve($copyToClipboardEvent(editor, event, data)); 26843 }); 26844 }); 26845 } 26846 const rootElement = editor.getRootElement(); 26847 const editorWindow = editor._window || window; 26848 const windowDocument = editorWindow.document; 26849 const domSelection = getDOMSelection2(editorWindow); 26850 if (rootElement === null || domSelection === null) { 26851 return false; 26852 } 26853 const element = windowDocument.createElement("span"); 26854 element.style.position = "fixed"; 26855 element.style.top = "-1000px"; 26856 element.append(windowDocument.createTextNode("#")); 26857 rootElement.append(element); 26858 const range2 = new Range(); 26859 range2.setStart(element, 0); 26860 range2.setEnd(element, 1); 26861 domSelection.removeAllRanges(); 26862 domSelection.addRange(range2); 26863 return new Promise((resolve, reject) => { 26864 const removeListener = editor.registerCommand(COPY_COMMAND2, (secondEvent) => { 26865 if (objectKlassEquals2(secondEvent, ClipboardEvent)) { 26866 removeListener(); 26867 if (clipboardEventTimeout !== null) { 26868 editorWindow.clearTimeout(clipboardEventTimeout); 26869 clipboardEventTimeout = null; 26870 } 26871 resolve($copyToClipboardEvent(editor, secondEvent, data)); 26872 } 26873 return true; 26874 }, COMMAND_PRIORITY_CRITICAL2); 26875 clipboardEventTimeout = editorWindow.setTimeout(() => { 26876 removeListener(); 26877 clipboardEventTimeout = null; 26878 resolve(false); 26879 }, EVENT_LATENCY); 26880 windowDocument.execCommand("copy"); 26881 element.remove(); 26882 }); 26883 } 26884 function $copyToClipboardEvent(editor, event, data) { 26885 if (data === void 0) { 26886 const domSelection = getDOMSelection2(editor._window); 26887 const selection = $getSelection2(); 26888 if (!selection || selection.isCollapsed()) { 26889 return false; 26890 } 26891 if (!domSelection) { 26892 return false; 26893 } 26894 const anchorDOM = domSelection.anchorNode; 26895 const focusDOM = domSelection.focusNode; 26896 if (anchorDOM !== null && focusDOM !== null && !isSelectionWithinEditor2(editor, anchorDOM, focusDOM)) { 26897 return false; 26898 } 26899 data = $getClipboardDataFromSelection(selection); 26900 } 26901 event.preventDefault(); 26902 const clipboardData = event.clipboardData; 26903 if (clipboardData === null) { 26904 return false; 26905 } 26906 setLexicalClipboardDataTransfer(clipboardData, data); 26907 return true; 26908 } 26909 var clipboardDataFunctions = [["text/html", $getHtmlContent], ["application/x-lexical-editor", $getLexicalContent]]; 26910 function $getClipboardDataFromSelection(selection = $getSelection2()) { 26911 return $getClipboardDataWithConfigFromSelection($getExportConfig(), selection); 26912 } 26913 function setLexicalClipboardDataTransfer(clipboardData, data) { 26914 for (const [k2] of clipboardDataFunctions) { 26915 if (data[k2] === void 0) { 26916 clipboardData.setData(k2, ""); 26917 } 26918 } 26919 for (const k2 in data) { 26920 const v3 = data[k2]; 26921 if (v3 !== void 0) { 26922 clipboardData.setData(k2, v3); 26923 } 26924 } 26925 } 26926 function $getExportConfig() { 26927 const editor = $getEditor2(); 26928 const builder = LexicalBuilder2.maybeFromEditor(editor); 26929 if (builder && builder.hasExtensionByName(GetClipboardDataExtension.name)) { 26930 return getExtensionDependencyFromEditor2(editor, GetClipboardDataExtension).output; 26931 } 26932 return DEFAULT_EXPORT_MIME_TYPE; 26933 } 26934 var DEFAULT_EXPORT_MIME_TYPE = { 26935 "application/x-lexical-editor": [(sel, next) => sel ? $getLexicalContent($getEditor2(), sel) : next()], 26936 "text/html": [(sel, next) => sel ? $getHtmlContent($getEditor2(), sel) : next()], 26937 "text/plain": [(sel, next) => sel ? sel.getTextContent() : next()] 26938 }; 26939 function $getClipboardDataWithConfigFromSelection($exportMimeType, selection) { 26940 const clipboardData = { 26941 "text/plain": "" 26942 }; 26943 for (const [k2, fns] of Object.entries($exportMimeType)) { 26944 const v3 = callExportMimeTypeFunctionStack(fns, selection); 26945 if (v3 !== null) { 26946 clipboardData[k2] = v3; 26947 } 26948 } 26949 return clipboardData; 26950 } 26951 function callExportMimeTypeFunctionStack(fns, selection) { 26952 const callAt = (i2) => fns[i2] ? fns[i2](selection, callAt.bind(null, i2 - 1)) : null; 26953 return callAt(fns.length - 1); 26954 } 26955 var GetClipboardDataExtension = defineExtension2({ 26956 build(editor, config, state) { 26957 return config.$exportMimeType; 26958 }, 26959 config: safeCast2({ 26960 $exportMimeType: DEFAULT_EXPORT_MIME_TYPE 26961 }), 26962 mergeConfig(config, partial) { 26963 const merged = shallowMergeConfig2(config, partial); 26964 if (partial.$exportMimeType) { 26965 const $exportMimeType = { 26966 ...config.$exportMimeType 26967 }; 26968 for (const [k2, v3] of Object.entries(partial.$exportMimeType)) { 26969 $exportMimeType[k2] = [...$exportMimeType[k2], ...v3]; 26970 } 26971 merged.$exportMimeType = $exportMimeType; 26972 } 26973 return merged; 26974 }, 26975 name: "@lexical/clipboard/GetClipboardData" 26976 }); 26977 26978
vendor: 1,008 bytes, lines 26978-26994
26978// node_modules/@lexical/clipboard/LexicalClipboard.mjs 26979 var mod8 = true ? LexicalClipboard_dev_exports : LexicalClipboard_prod_exports; 26980 var $generateJSONFromSelectedNodes2 = mod8.$generateJSONFromSelectedNodes; 26981 var $generateNodesFromSerializedNodes2 = mod8.$generateNodesFromSerializedNodes; 26982 var $getClipboardDataFromSelection2 = mod8.$getClipboardDataFromSelection; 26983 var $getHtmlContent2 = mod8.$getHtmlContent; 26984 var $getLexicalContent2 = mod8.$getLexicalContent; 26985 var $handlePlainTextDrop2 = mod8.$handlePlainTextDrop; 26986 var $handleRichTextDrop2 = mod8.$handleRichTextDrop; 26987 var $insertDataTransferForPlainText2 = mod8.$insertDataTransferForPlainText; 26988 var $insertDataTransferForRichText2 = mod8.$insertDataTransferForRichText; 26989 var $insertGeneratedNodes2 = mod8.$insertGeneratedNodes; 26990 var $writeDragSourceToDataTransfer2 = mod8.$writeDragSourceToDataTransfer; 26991 var copyToClipboard2 = mod8.copyToClipboard; 26992 var setLexicalClipboardDataTransfer2 = mod8.setLexicalClipboardDataTransfer; 26993 26994
vendor: 3,179 bytes, lines 26994-27072
26994// node_modules/@lexical/dragon/LexicalDragon.dev.mjs 26995 var LexicalDragon_dev_exports = {}; 26996 __export(LexicalDragon_dev_exports, { 26997 DragonExtension: () => DragonExtension, 26998 registerDragonSupport: () => registerDragonSupport 26999 }); 27000 function registerDragonSupport(editor) { 27001 const origin = window.location.origin; 27002 const handler = (event) => { 27003 if (event.origin !== origin) { 27004 return; 27005 } 27006 const rootElement = editor.getRootElement(); 27007 if (document.activeElement !== rootElement) { 27008 return; 27009 } 27010 const data = event.data; 27011 if (typeof data === "string") { 27012 let parsedData; 27013 try { 27014 parsedData = JSON.parse(data); 27015 } catch (_e2) { 27016 return; 27017 } 27018 if (parsedData && parsedData.protocol === "nuanria_messaging" && parsedData.type === "request") { 27019 const payload = parsedData.payload; 27020 if (payload && payload.functionId === "makeChanges") { 27021 const args = payload.args; 27022 if (args) { 27023 const [elementStart, elementLength, text2, selStart, selLength] = args; 27024 editor.update(() => { 27025 const selection = $getSelection2(); 27026 if ($isRangeSelection2(selection)) { 27027 const anchor = selection.anchor; 27028 let anchorNode = anchor.getNode(); 27029 let setSelStart = 0; 27030 let setSelEnd = 0; 27031 if ($isTextNode2(anchorNode)) { 27032 if (elementStart >= 0 && elementLength >= 0) { 27033 setSelStart = elementStart; 27034 setSelEnd = elementStart + elementLength; 27035 selection.setTextNodeRange(anchorNode, setSelStart, anchorNode, setSelEnd); 27036 } 27037 } 27038 if (setSelStart !== setSelEnd || text2 !== "") { 27039 selection.insertRawText(text2); 27040 anchorNode = anchor.getNode(); 27041 } 27042 if ($isTextNode2(anchorNode)) { 27043 setSelStart = selStart; 27044 setSelEnd = selStart + selLength; 27045 const anchorNodeTextLength = anchorNode.getTextContentSize(); 27046 setSelStart = setSelStart > anchorNodeTextLength ? anchorNodeTextLength : setSelStart; 27047 setSelEnd = setSelEnd > anchorNodeTextLength ? anchorNodeTextLength : setSelEnd; 27048 selection.setTextNodeRange(anchorNode, setSelStart, anchorNode, setSelEnd); 27049 } 27050 event.stopImmediatePropagation(); 27051 } 27052 }); 27053 } 27054 } 27055 } 27056 } 27057 }; 27058 window.addEventListener("message", handler, true); 27059 return () => { 27060 window.removeEventListener("message", handler, true); 27061 }; 27062 } 27063 var DragonExtension = defineExtension2({ 27064 build: (editor, config, state) => namedSignals2(config), 27065 config: safeCast2({ 27066 disabled: typeof window === "undefined" 27067 }), 27068 name: "@lexical/dragon", 27069 register: (editor, config, state) => effect(() => state.getOutput().disabled.value ? void 0 : registerDragonSupport(editor)) 27070 }); 27071 27072
vendor: 235 bytes, lines 27072-27077
27072// node_modules/@lexical/dragon/LexicalDragon.mjs 27073 var mod9 = true ? LexicalDragon_dev_exports : LexicalDragon_prod_exports; 27074 var DragonExtension2 = mod9.DragonExtension; 27075 var registerDragonSupport2 = mod9.registerDragonSupport; 27076 27077
vendor: 8,489 bytes, lines 27077-27284
27077// node_modules/@lexical/plain-text/LexicalPlainText.dev.mjs 27078 var CAN_USE_DOM4 = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined"; 27079 var documentMode3 = CAN_USE_DOM4 && "documentMode" in document ? document.documentMode : null; 27080 var IS_APPLE4 = CAN_USE_DOM4 && /Mac|iPod|iPhone|iPad/.test(navigator.platform); 27081 var CAN_USE_BEFORE_INPUT4 = CAN_USE_DOM4 && "InputEvent" in window && !documentMode3 ? "getTargetRanges" in new window.InputEvent("input") : false; 27082 var IS_IOS4 = CAN_USE_DOM4 && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; 27083 var IS_ANDROID4 = CAN_USE_DOM4 && /Android/.test(navigator.userAgent); 27084 var IS_SAFARI4 = CAN_USE_DOM4 && /Version\/[\d.]+.*Safari/.test(navigator.userAgent) && !IS_ANDROID4; 27085 var IS_CHROME4 = CAN_USE_DOM4 && /^(?=.*Chrome).*/i.test(navigator.userAgent); 27086 var IS_APPLE_WEBKIT4 = CAN_USE_DOM4 && /AppleWebKit\/[\d.]+/.test(navigator.userAgent) && IS_APPLE4 && !IS_CHROME4; 27087 function onCopyForPlainText(event, editor) { 27088 editor.update(() => { 27089 if (event !== null) { 27090 const clipboardData = objectKlassEquals2(event, KeyboardEvent) ? null : event.clipboardData; 27091 const selection = $getSelection2(); 27092 if (selection !== null && !selection.isCollapsed() && clipboardData != null) { 27093 event.preventDefault(); 27094 const htmlString = $getHtmlContent2(editor); 27095 if (htmlString !== null) { 27096 clipboardData.setData("text/html", htmlString); 27097 } 27098 clipboardData.setData("text/plain", selection.getTextContent()); 27099 } 27100 } 27101 }); 27102 } 27103 function onPasteForPlainText(event, editor) { 27104 event.preventDefault(); 27105 editor.update(() => { 27106 const selection = $getSelection2(); 27107 const clipboardData = objectKlassEquals2(event, ClipboardEvent) ? event.clipboardData : null; 27108 if (clipboardData != null && $isRangeSelection2(selection)) { 27109 $insertDataTransferForPlainText2(clipboardData, selection); 27110 } 27111 }, { 27112 tag: PASTE_TAG2 27113 }); 27114 } 27115 function onCutForPlainText(event, editor) { 27116 onCopyForPlainText(event, editor); 27117 editor.update(() => { 27118 const selection = $getSelection2(); 27119 if ($isRangeSelection2(selection)) { 27120 selection.removeText(); 27121 } 27122 }); 27123 } 27124 function registerPlainText(editor) { 27125 const removeListener = mergeRegister3(editor.registerCommand(DELETE_CHARACTER_COMMAND2, (isBackward) => { 27126 const selection = $getSelection2(); 27127 if (!$isRangeSelection2(selection)) { 27128 return false; 27129 } 27130 selection.deleteCharacter(isBackward); 27131 return true; 27132 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(DELETE_WORD_COMMAND2, (isBackward) => { 27133 const selection = $getSelection2(); 27134 if (!$isRangeSelection2(selection)) { 27135 return false; 27136 } 27137 selection.deleteWord(isBackward); 27138 return true; 27139 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(DELETE_LINE_COMMAND2, (isBackward) => { 27140 const selection = $getSelection2(); 27141 if (!$isRangeSelection2(selection)) { 27142 return false; 27143 } 27144 selection.deleteLine(isBackward); 27145 return true; 27146 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(CONTROLLED_TEXT_INSERTION_COMMAND2, (eventOrText) => { 27147 const selection = $getSelection2(); 27148 if (!$isRangeSelection2(selection)) { 27149 return false; 27150 } 27151 if (typeof eventOrText === "string") { 27152 selection.insertText(eventOrText); 27153 } else { 27154 const dataTransfer = eventOrText.dataTransfer; 27155 if (dataTransfer != null) { 27156 $insertDataTransferForPlainText2(dataTransfer, selection); 27157 } else { 27158 const data = eventOrText.data; 27159 if (data) { 27160 selection.insertText(data); 27161 } 27162 } 27163 } 27164 return true; 27165 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(REMOVE_TEXT_COMMAND2, () => { 27166 const selection = $getSelection2(); 27167 if (!$isRangeSelection2(selection)) { 27168 return false; 27169 } 27170 selection.removeText(); 27171 return true; 27172 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(INSERT_LINE_BREAK_COMMAND2, (selectStart) => { 27173 const selection = $getSelection2(); 27174 if (!$isRangeSelection2(selection)) { 27175 return false; 27176 } 27177 selection.insertLineBreak(selectStart); 27178 return true; 27179 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(INSERT_PARAGRAPH_COMMAND2, () => { 27180 const selection = $getSelection2(); 27181 if (!$isRangeSelection2(selection)) { 27182 return false; 27183 } 27184 selection.insertLineBreak(); 27185 return true; 27186 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_ARROW_LEFT_COMMAND2, (payload) => { 27187 const selection = $getSelection2(); 27188 if (!$isRangeSelection2(selection)) { 27189 return false; 27190 } 27191 const event = payload; 27192 const isHoldingShift = event.shiftKey; 27193 if ($shouldOverrideDefaultCharacterSelection2(selection, true)) { 27194 event.preventDefault(); 27195 $moveCharacter2(selection, isHoldingShift, true); 27196 return true; 27197 } 27198 return false; 27199 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_ARROW_RIGHT_COMMAND2, (payload) => { 27200 const selection = $getSelection2(); 27201 if (!$isRangeSelection2(selection)) { 27202 return false; 27203 } 27204 const event = payload; 27205 const isHoldingShift = event.shiftKey; 27206 if ($shouldOverrideDefaultCharacterSelection2(selection, false)) { 27207 event.preventDefault(); 27208 $moveCharacter2(selection, isHoldingShift, false); 27209 return true; 27210 } 27211 return false; 27212 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_BACKSPACE_COMMAND2, (event) => { 27213 const selection = $getSelection2(); 27214 if (!$isRangeSelection2(selection)) { 27215 return false; 27216 } 27217 if (IS_IOS4 && navigator.language === "ko-KR") { 27218 return false; 27219 } 27220 event.preventDefault(); 27221 return editor.dispatchCommand(DELETE_CHARACTER_COMMAND2, true); 27222 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_DELETE_COMMAND2, (event) => { 27223 const selection = $getSelection2(); 27224 if (!$isRangeSelection2(selection)) { 27225 return false; 27226 } 27227 event.preventDefault(); 27228 return editor.dispatchCommand(DELETE_CHARACTER_COMMAND2, false); 27229 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_ENTER_COMMAND2, (event) => { 27230 const selection = $getSelection2(); 27231 if (!$isRangeSelection2(selection)) { 27232 return false; 27233 } 27234 if (event !== null) { 27235 if ((IS_IOS4 || IS_SAFARI4 || IS_APPLE_WEBKIT4) && CAN_USE_BEFORE_INPUT4) { 27236 return false; 27237 } 27238 event.preventDefault(); 27239 } 27240 return editor.dispatchCommand(INSERT_LINE_BREAK_COMMAND2, false); 27241 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(SELECT_ALL_COMMAND2, () => { 27242 $selectAll2(); 27243 return true; 27244 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(COPY_COMMAND2, (event) => { 27245 const selection = $getSelection2(); 27246 if (!$isRangeSelection2(selection)) { 27247 return false; 27248 } 27249 onCopyForPlainText(event, editor); 27250 return true; 27251 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(CUT_COMMAND2, (event) => { 27252 const selection = $getSelection2(); 27253 if (!$isRangeSelection2(selection)) { 27254 return false; 27255 } 27256 onCutForPlainText(event, editor); 27257 return true; 27258 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(PASTE_COMMAND2, (event) => { 27259 const selection = $getSelection2(); 27260 if (!$isRangeSelection2(selection)) { 27261 return false; 27262 } 27263 onPasteForPlainText(event, editor); 27264 return true; 27265 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(DROP_COMMAND2, (event) => $handlePlainTextDrop2(event, editor), COMMAND_PRIORITY_EDITOR2), editor.registerCommand(DRAGSTART_COMMAND2, (event) => { 27266 const selection = $getSelection2(); 27267 if (!$isRangeSelection2(selection)) { 27268 return false; 27269 } 27270 if (!selection.isCollapsed() && event.dataTransfer !== null) { 27271 $writeDragSourceToDataTransfer2(event.dataTransfer, editor); 27272 } 27273 return true; 27274 }, COMMAND_PRIORITY_EDITOR2)); 27275 return removeListener; 27276 } 27277 var PlainTextExtension = defineExtension2({ 27278 conflictsWith: ["@lexical/rich-text"], 27279 dependencies: [DragonExtension2], 27280 name: "@lexical/plain-text", 27281 register: registerPlainText 27282 }); 27283 27284
vendor: 249 bytes, lines 27284-27289
27284// node_modules/@lexical/plain-text/LexicalPlainText.mjs 27285 var mod10 = true ? LexicalPlainText_dev_exports : LexicalPlainText_prod_exports; 27286 var PlainTextExtension2 = mod10.PlainTextExtension; 27287 var registerPlainText2 = mod10.registerPlainText; 27288 27289
vendor: 26,248 bytes, lines 27289-28030
27289// node_modules/@lexical/rich-text/LexicalRichText.dev.mjs 27290 var LexicalRichText_dev_exports = {}; 27291 __export(LexicalRichText_dev_exports, { 27292 $createHeadingNode: () => $createHeadingNode, 27293 $createQuoteNode: () => $createQuoteNode, 27294 $isHeadingNode: () => $isHeadingNode, 27295 $isQuoteNode: () => $isQuoteNode, 27296 DRAG_DROP_PASTE: () => DRAG_DROP_PASTE, 27297 HeadingNode: () => HeadingNode, 27298 QuoteNode: () => QuoteNode, 27299 RichTextExtension: () => RichTextExtension, 27300 eventFiles: () => eventFiles, 27301 registerRichText: () => registerRichText 27302 }); 27303 function caretFromPoint2(x3, y3) { 27304 if (typeof document.caretRangeFromPoint !== "undefined") { 27305 const range2 = document.caretRangeFromPoint(x3, y3); 27306 if (range2 === null) { 27307 return null; 27308 } 27309 return { 27310 node: range2.startContainer, 27311 offset: range2.startOffset 27312 }; 27313 } else if (document.caretPositionFromPoint !== "undefined") { 27314 const range2 = document.caretPositionFromPoint(x3, y3); 27315 if (range2 === null) { 27316 return null; 27317 } 27318 return { 27319 node: range2.offsetNode, 27320 offset: range2.offset 27321 }; 27322 } else { 27323 return null; 27324 } 27325 } 27326 var CAN_USE_DOM5 = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined"; 27327 var documentMode4 = CAN_USE_DOM5 && "documentMode" in document ? document.documentMode : null; 27328 var IS_APPLE5 = CAN_USE_DOM5 && /Mac|iPod|iPhone|iPad/.test(navigator.platform); 27329 var CAN_USE_BEFORE_INPUT5 = CAN_USE_DOM5 && "InputEvent" in window && !documentMode4 ? "getTargetRanges" in new window.InputEvent("input") : false; 27330 var IS_IOS5 = CAN_USE_DOM5 && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; 27331 var IS_ANDROID5 = CAN_USE_DOM5 && /Android/.test(navigator.userAgent); 27332 var IS_SAFARI5 = CAN_USE_DOM5 && /Version\/[\d.]+.*Safari/.test(navigator.userAgent) && !IS_ANDROID5; 27333 var IS_CHROME5 = CAN_USE_DOM5 && /^(?=.*Chrome).*/i.test(navigator.userAgent); 27334 var IS_APPLE_WEBKIT5 = CAN_USE_DOM5 && /AppleWebKit\/[\d.]+/.test(navigator.userAgent) && IS_APPLE5 && !IS_CHROME5; 27335 var DRAG_DROP_PASTE = createCommand2("DRAG_DROP_PASTE_FILE"); 27336 var QuoteNode = class _QuoteNode extends ElementNode2 { 27337 static getType() { 27338 return "quote"; 27339 } 27340 static clone(node) { 27341 return new _QuoteNode(node.__key); 27342 } 27343 // View 27344 createDOM(config) { 27345 const element = document.createElement("blockquote"); 27346 addClassNamesToElement3(element, config.theme.quote); 27347 return element; 27348 } 27349 updateDOM(prevNode, dom) { 27350 return false; 27351 } 27352 static importDOM() { 27353 return { 27354 blockquote: (node) => ({ 27355 conversion: $convertBlockquoteElement, 27356 priority: 0 27357 }) 27358 }; 27359 } 27360 exportDOM(editor) { 27361 const { 27362 element 27363 } = super.exportDOM(editor); 27364 if (isHTMLElement3(element)) { 27365 if (this.isEmpty()) { 27366 element.append(document.createElement("br")); 27367 } 27368 const formatType = this.getFormatType(); 27369 if (formatType) { 27370 element.style.textAlign = formatType; 27371 } 27372 const direction = this.getDirection(); 27373 if (direction) { 27374 element.dir = direction; 27375 } 27376 } 27377 return { 27378 element 27379 }; 27380 } 27381 static importJSON(serializedNode) { 27382 return $createQuoteNode().updateFromJSON(serializedNode); 27383 } 27384 // Mutation 27385 insertNewAfter(_3, restoreSelection) { 27386 const newBlock = $createParagraphNode2(); 27387 const direction = this.getDirection(); 27388 newBlock.setDirection(direction); 27389 this.insertAfter(newBlock, restoreSelection); 27390 return newBlock; 27391 } 27392 collapseAtStart() { 27393 const paragraph = $createParagraphNode2(); 27394 const children = this.getChildren(); 27395 children.forEach((child) => paragraph.append(child)); 27396 this.replace(paragraph); 27397 return true; 27398 } 27399 canMergeWhenEmpty() { 27400 return true; 27401 } 27402 }; 27403 function $createQuoteNode() { 27404 return $applyNodeReplacement2(new QuoteNode()); 27405 } 27406 function $isQuoteNode(node) { 27407 return node instanceof QuoteNode; 27408 } 27409 var HeadingNode = class _HeadingNode extends ElementNode2 { 27410 /** @internal */ 27411 __tag; 27412 static getType() { 27413 return "heading"; 27414 } 27415 static clone(node) { 27416 return new _HeadingNode(node.__tag, node.__key); 27417 } 27418 afterCloneFrom(prevNode) { 27419 super.afterCloneFrom(prevNode); 27420 this.__tag = prevNode.__tag; 27421 } 27422 constructor(tag = "h1", key) { 27423 super(key); 27424 this.__tag = tag; 27425 } 27426 getTag() { 27427 return this.getLatest().__tag; 27428 } 27429 setTag(tag) { 27430 const self2 = this.getWritable(); 27431 self2.__tag = tag; 27432 return self2; 27433 } 27434 // View 27435 createDOM(config) { 27436 const tag = this.__tag; 27437 const element = document.createElement(tag); 27438 const theme2 = config.theme; 27439 const classNames = theme2.heading; 27440 if (classNames !== void 0) { 27441 const className = classNames[tag]; 27442 addClassNamesToElement3(element, className); 27443 } 27444 return element; 27445 } 27446 updateDOM(prevNode, dom, config) { 27447 return prevNode.__tag !== this.__tag; 27448 } 27449 static importDOM() { 27450 return { 27451 h1: (node) => ({ 27452 conversion: $convertHeadingElement, 27453 priority: 0 27454 }), 27455 h2: (node) => ({ 27456 conversion: $convertHeadingElement, 27457 priority: 0 27458 }), 27459 h3: (node) => ({ 27460 conversion: $convertHeadingElement, 27461 priority: 0 27462 }), 27463 h4: (node) => ({ 27464 conversion: $convertHeadingElement, 27465 priority: 0 27466 }), 27467 h5: (node) => ({ 27468 conversion: $convertHeadingElement, 27469 priority: 0 27470 }), 27471 h6: (node) => ({ 27472 conversion: $convertHeadingElement, 27473 priority: 0 27474 }), 27475 p: (node) => { 27476 const paragraph = node; 27477 const firstChild = paragraph.firstChild; 27478 if (firstChild !== null && isGoogleDocsTitle(firstChild)) { 27479 return { 27480 conversion: () => ({ 27481 node: null 27482 }), 27483 priority: 3 27484 }; 27485 } 27486 return null; 27487 }, 27488 span: (node) => { 27489 if (isGoogleDocsTitle(node)) { 27490 return { 27491 conversion: (domNode) => { 27492 return { 27493 node: $createHeadingNode("h1") 27494 }; 27495 }, 27496 priority: 3 27497 }; 27498 } 27499 return null; 27500 } 27501 }; 27502 } 27503 exportDOM(editor) { 27504 const { 27505 element 27506 } = super.exportDOM(editor); 27507 if (isHTMLElement3(element)) { 27508 if (this.isEmpty()) { 27509 element.append(document.createElement("br")); 27510 } 27511 const formatType = this.getFormatType(); 27512 if (formatType) { 27513 element.style.textAlign = formatType; 27514 } 27515 const direction = this.getDirection(); 27516 if (direction) { 27517 element.dir = direction; 27518 } 27519 } 27520 return { 27521 element 27522 }; 27523 } 27524 static importJSON(serializedNode) { 27525 return $createHeadingNode(serializedNode.tag).updateFromJSON(serializedNode); 27526 } 27527 updateFromJSON(serializedNode) { 27528 return super.updateFromJSON(serializedNode).setTag(serializedNode.tag); 27529 } 27530 exportJSON() { 27531 return { 27532 ...super.exportJSON(), 27533 tag: this.getTag() 27534 }; 27535 } 27536 // Mutation 27537 insertNewAfter(selection, restoreSelection = true) { 27538 const anchorOffet = selection ? selection.anchor.offset : 0; 27539 const lastDesc = this.getLastDescendant(); 27540 const isAtEnd = !lastDesc || selection && selection.anchor.key === lastDesc.getKey() && anchorOffet === lastDesc.getTextContentSize(); 27541 const newElement = isAtEnd || !selection ? $createParagraphNode2() : $createHeadingNode(this.getTag()); 27542 const direction = this.getDirection(); 27543 newElement.setDirection(direction); 27544 this.insertAfter(newElement, restoreSelection); 27545 if (anchorOffet === 0 && !this.isEmpty() && selection) { 27546 const paragraph = $createParagraphNode2(); 27547 paragraph.select(); 27548 this.replace(paragraph, true); 27549 } 27550 return newElement; 27551 } 27552 collapseAtStart() { 27553 const newElement = !this.isEmpty() ? $createHeadingNode(this.getTag()) : $createParagraphNode2(); 27554 const children = this.getChildren(); 27555 children.forEach((child) => newElement.append(child)); 27556 this.replace(newElement); 27557 return true; 27558 } 27559 extractWithChild() { 27560 return true; 27561 } 27562 }; 27563 function isGoogleDocsTitle(domNode) { 27564 if (domNode.nodeName.toLowerCase() === "span") { 27565 return domNode.style.fontSize === "26pt"; 27566 } 27567 return false; 27568 } 27569 function $convertHeadingElement(element) { 27570 const nodeName = element.nodeName.toLowerCase(); 27571 let node = null; 27572 if (nodeName === "h1" || nodeName === "h2" || nodeName === "h3" || nodeName === "h4" || nodeName === "h5" || nodeName === "h6") { 27573 node = $createHeadingNode(nodeName); 27574 if (element.style !== null) { 27575 setNodeIndentFromDOM2(element, node); 27576 node.setFormat(element.style.textAlign); 27577 } 27578 } 27579 return { 27580 node 27581 }; 27582 } 27583 function $convertBlockquoteElement(element) { 27584 const node = $createQuoteNode(); 27585 if (element.style !== null) { 27586 node.setFormat(element.style.textAlign); 27587 setNodeIndentFromDOM2(element, node); 27588 } 27589 return { 27590 node 27591 }; 27592 } 27593 function $createHeadingNode(headingTag = "h1") { 27594 return $applyNodeReplacement2(new HeadingNode(headingTag)); 27595 } 27596 function $isHeadingNode(node) { 27597 return node instanceof HeadingNode; 27598 } 27599 function onPasteForRichText(event, editor) { 27600 event.preventDefault(); 27601 editor.update(() => { 27602 const selection = $getSelection2(); 27603 const clipboardData = objectKlassEquals2(event, InputEvent) || objectKlassEquals2(event, KeyboardEvent) ? null : event.clipboardData; 27604 if (clipboardData != null && selection !== null) { 27605 $insertDataTransferForRichText2(clipboardData, selection, editor); 27606 } 27607 }, { 27608 tag: PASTE_TAG2 27609 }); 27610 } 27611 async function onCutForRichText(event, editor) { 27612 await copyToClipboard2(editor, objectKlassEquals2(event, ClipboardEvent) ? event : null); 27613 editor.update(() => { 27614 const selection = $getSelection2(); 27615 if ($isRangeSelection2(selection)) { 27616 selection.removeText(); 27617 } else if ($isNodeSelection2(selection)) { 27618 selection.getNodes().forEach((node) => node.remove()); 27619 } 27620 }); 27621 } 27622 function eventFiles(event) { 27623 let dataTransfer = null; 27624 if (objectKlassEquals2(event, DragEvent)) { 27625 dataTransfer = event.dataTransfer; 27626 } else if (objectKlassEquals2(event, ClipboardEvent)) { 27627 dataTransfer = event.clipboardData; 27628 } 27629 if (dataTransfer === null) { 27630 return [false, [], false]; 27631 } 27632 const types = dataTransfer.types; 27633 const hasFiles = types.includes("Files"); 27634 const hasContent = types.includes("text/html") || types.includes("text/plain"); 27635 return [hasFiles, Array.from(dataTransfer.files), hasContent]; 27636 } 27637 function $isTargetWithinDecorator(target) { 27638 const node = $getNearestNodeFromDOMNode2(target); 27639 return $isDecoratorNode2(node); 27640 } 27641 function $isSelectionAtEndOfRoot(selection) { 27642 const focus = selection.focus; 27643 return focus.key === "root" && focus.offset === $getRoot2().getChildrenSize(); 27644 } 27645 function $isSelectionCollapsedAtFrontOfIndentedBlock(selection) { 27646 if (!selection.isCollapsed()) { 27647 return false; 27648 } 27649 const { 27650 anchor 27651 } = selection; 27652 if (anchor.offset !== 0) { 27653 return false; 27654 } 27655 const anchorNode = anchor.getNode(); 27656 if ($isRootNode2(anchorNode)) { 27657 return false; 27658 } 27659 const element = $getNearestBlockElementAncestorOrThrow2(anchorNode); 27660 return element.getIndent() > 0 && (element.is(anchorNode) || anchorNode.is(element.getFirstDescendant())); 27661 } 27662 function $resetCapitalization(selection) { 27663 for (const format of ["lowercase", "uppercase", "capitalize"]) { 27664 if (selection.hasFormat(format)) { 27665 selection.toggleFormat(format); 27666 } 27667 } 27668 } 27669 function registerRichText(editor) { 27670 const removeListener = mergeRegister3(editor.registerCommand(CLICK_COMMAND2, (payload) => { 27671 const selection = $getSelection2(); 27672 if ($isNodeSelection2(selection)) { 27673 selection.clear(); 27674 return true; 27675 } 27676 return false; 27677 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(DELETE_CHARACTER_COMMAND2, (isBackward) => { 27678 const selection = $getSelection2(); 27679 if ($isRangeSelection2(selection)) { 27680 selection.deleteCharacter(isBackward); 27681 return true; 27682 } else if ($isNodeSelection2(selection)) { 27683 selection.deleteNodes(); 27684 return true; 27685 } 27686 return false; 27687 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(DELETE_WORD_COMMAND2, (isBackward) => { 27688 const selection = $getSelection2(); 27689 if (!$isRangeSelection2(selection)) { 27690 return false; 27691 } 27692 selection.deleteWord(isBackward); 27693 return true; 27694 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(DELETE_LINE_COMMAND2, (isBackward) => { 27695 const selection = $getSelection2(); 27696 if (!$isRangeSelection2(selection)) { 27697 return false; 27698 } 27699 selection.deleteLine(isBackward); 27700 return true; 27701 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(CONTROLLED_TEXT_INSERTION_COMMAND2, (eventOrText) => { 27702 const selection = $getSelection2(); 27703 if (typeof eventOrText === "string") { 27704 if (selection !== null) { 27705 selection.insertText(eventOrText); 27706 } 27707 } else { 27708 if (selection === null) { 27709 return false; 27710 } 27711 const dataTransfer = eventOrText.dataTransfer; 27712 if (dataTransfer != null) { 27713 $insertDataTransferForRichText2(dataTransfer, selection, editor); 27714 } else if ($isRangeSelection2(selection)) { 27715 const data = eventOrText.data; 27716 if (data) { 27717 selection.insertText(data); 27718 } 27719 return true; 27720 } 27721 } 27722 return true; 27723 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(REMOVE_TEXT_COMMAND2, () => { 27724 const selection = $getSelection2(); 27725 if (!$isRangeSelection2(selection)) { 27726 return false; 27727 } 27728 selection.removeText(); 27729 return true; 27730 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(FORMAT_TEXT_COMMAND2, (format) => { 27731 const selection = $getSelection2(); 27732 if (!$isRangeSelection2(selection)) { 27733 return false; 27734 } 27735 selection.formatText(format); 27736 return true; 27737 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(FORMAT_ELEMENT_COMMAND2, (format) => { 27738 const selection = $getSelection2(); 27739 if (!$isRangeSelection2(selection) && !$isNodeSelection2(selection)) { 27740 return false; 27741 } 27742 const nodes = selection.getNodes(); 27743 for (const node of nodes) { 27744 const element = $findMatchingParent3(node, (parentNode) => $isElementNode2(parentNode) && !parentNode.isInline()); 27745 if (element !== null) { 27746 element.setFormat(format); 27747 } 27748 } 27749 return true; 27750 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(INSERT_LINE_BREAK_COMMAND2, (selectStart) => { 27751 const selection = $getSelection2(); 27752 if (!$isRangeSelection2(selection)) { 27753 return false; 27754 } 27755 selection.insertLineBreak(selectStart); 27756 return true; 27757 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(INSERT_PARAGRAPH_COMMAND2, () => { 27758 const selection = $getSelection2(); 27759 if (!$isRangeSelection2(selection)) { 27760 return false; 27761 } 27762 selection.insertParagraph(); 27763 return true; 27764 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(INSERT_TAB_COMMAND2, () => { 27765 const tabNode = $createTabNode2(); 27766 const selection = $getSelection2(); 27767 if ($isRangeSelection2(selection)) { 27768 tabNode.setFormat(selection.format); 27769 tabNode.setStyle(selection.style); 27770 } 27771 $insertNodes2([tabNode]); 27772 return true; 27773 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(INDENT_CONTENT_COMMAND2, () => { 27774 return $handleIndentAndOutdent2((block) => { 27775 const indent = block.getIndent(); 27776 block.setIndent(indent + 1); 27777 }); 27778 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(OUTDENT_CONTENT_COMMAND2, () => { 27779 return $handleIndentAndOutdent2((block) => { 27780 const indent = block.getIndent(); 27781 if (indent > 0) { 27782 block.setIndent(Math.max(0, indent - 1)); 27783 } 27784 }); 27785 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_ARROW_UP_COMMAND2, (event) => { 27786 const selection = $getSelection2(); 27787 if ($isNodeSelection2(selection)) { 27788 const nodes = selection.getNodes(); 27789 if (nodes.length > 0) { 27790 event.preventDefault(); 27791 nodes[0].selectPrevious(); 27792 return true; 27793 } 27794 } else if ($isRangeSelection2(selection)) { 27795 const possibleNode = $getAdjacentNode2(selection.focus, true); 27796 if (!event.shiftKey && $isDecoratorNode2(possibleNode) && !possibleNode.isIsolated() && !possibleNode.isInline()) { 27797 possibleNode.selectPrevious(); 27798 event.preventDefault(); 27799 return true; 27800 } 27801 } 27802 return false; 27803 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_ARROW_DOWN_COMMAND2, (event) => { 27804 const selection = $getSelection2(); 27805 if ($isNodeSelection2(selection)) { 27806 const nodes = selection.getNodes(); 27807 if (nodes.length > 0) { 27808 event.preventDefault(); 27809 nodes[0].selectNext(0, 0); 27810 return true; 27811 } 27812 } else if ($isRangeSelection2(selection)) { 27813 if ($isSelectionAtEndOfRoot(selection)) { 27814 event.preventDefault(); 27815 return true; 27816 } 27817 const possibleNode = $getAdjacentNode2(selection.focus, false); 27818 if (!event.shiftKey && $isDecoratorNode2(possibleNode) && !possibleNode.isIsolated() && !possibleNode.isInline()) { 27819 possibleNode.selectNext(); 27820 event.preventDefault(); 27821 return true; 27822 } 27823 } 27824 return false; 27825 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_ARROW_LEFT_COMMAND2, (event) => { 27826 const selection = $getSelection2(); 27827 if ($isNodeSelection2(selection)) { 27828 const nodes = selection.getNodes(); 27829 if (nodes.length > 0) { 27830 event.preventDefault(); 27831 if ($isParentRTL2(nodes[0])) { 27832 nodes[0].selectNext(0, 0); 27833 } else { 27834 nodes[0].selectPrevious(); 27835 } 27836 return true; 27837 } 27838 } 27839 if (!$isRangeSelection2(selection)) { 27840 return false; 27841 } 27842 if ($shouldOverrideDefaultCharacterSelection2(selection, true)) { 27843 const isHoldingShift = event.shiftKey; 27844 event.preventDefault(); 27845 $moveCharacter2(selection, isHoldingShift, true); 27846 return true; 27847 } 27848 return false; 27849 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_ARROW_RIGHT_COMMAND2, (event) => { 27850 const selection = $getSelection2(); 27851 if ($isNodeSelection2(selection)) { 27852 const nodes = selection.getNodes(); 27853 if (nodes.length > 0) { 27854 event.preventDefault(); 27855 if ($isParentRTL2(nodes[0])) { 27856 nodes[0].selectPrevious(); 27857 } else { 27858 nodes[0].selectNext(0, 0); 27859 } 27860 return true; 27861 } 27862 } 27863 if (!$isRangeSelection2(selection)) { 27864 return false; 27865 } 27866 const isHoldingShift = event.shiftKey; 27867 if ($shouldOverrideDefaultCharacterSelection2(selection, false)) { 27868 event.preventDefault(); 27869 $moveCharacter2(selection, isHoldingShift, false); 27870 return true; 27871 } 27872 return false; 27873 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_BACKSPACE_COMMAND2, (event) => { 27874 if ($isTargetWithinDecorator(event.target)) { 27875 return false; 27876 } 27877 const selection = $getSelection2(); 27878 if ($isRangeSelection2(selection)) { 27879 if ($isSelectionCollapsedAtFrontOfIndentedBlock(selection)) { 27880 event.preventDefault(); 27881 return editor.dispatchCommand(OUTDENT_CONTENT_COMMAND2, void 0); 27882 } 27883 if (IS_IOS5 && navigator.language === "ko-KR") { 27884 return false; 27885 } 27886 } else if (!$isNodeSelection2(selection)) { 27887 return false; 27888 } 27889 event.preventDefault(); 27890 return editor.dispatchCommand(DELETE_CHARACTER_COMMAND2, true); 27891 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_DELETE_COMMAND2, (event) => { 27892 if ($isTargetWithinDecorator(event.target)) { 27893 return false; 27894 } 27895 const selection = $getSelection2(); 27896 if (!($isRangeSelection2(selection) || $isNodeSelection2(selection))) { 27897 return false; 27898 } 27899 event.preventDefault(); 27900 return editor.dispatchCommand(DELETE_CHARACTER_COMMAND2, false); 27901 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_ENTER_COMMAND2, (event) => { 27902 const selection = $getSelection2(); 27903 if (!$isRangeSelection2(selection)) { 27904 return false; 27905 } 27906 $resetCapitalization(selection); 27907 if (event !== null) { 27908 if ((IS_IOS5 || IS_SAFARI5 || IS_APPLE_WEBKIT5) && CAN_USE_BEFORE_INPUT5) { 27909 return false; 27910 } 27911 event.preventDefault(); 27912 if (event.shiftKey) { 27913 return editor.dispatchCommand(INSERT_LINE_BREAK_COMMAND2, false); 27914 } 27915 } 27916 return editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND2, void 0); 27917 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_ESCAPE_COMMAND2, () => { 27918 const selection = $getSelection2(); 27919 if (!$isRangeSelection2(selection)) { 27920 return false; 27921 } 27922 editor.blur(); 27923 return true; 27924 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(DROP_COMMAND2, (event) => { 27925 const [, files] = eventFiles(event); 27926 if (files.length > 0) { 27927 const x3 = event.clientX; 27928 const y3 = event.clientY; 27929 const eventRange = caretFromPoint2(x3, y3); 27930 if (eventRange !== null) { 27931 const { 27932 offset: domOffset, 27933 node: domNode 27934 } = eventRange; 27935 const node = $getNearestNodeFromDOMNode2(domNode); 27936 if (node !== null) { 27937 const selection = $createRangeSelection2(); 27938 if ($isTextNode2(node)) { 27939 selection.anchor.set(node.getKey(), domOffset, "text"); 27940 selection.focus.set(node.getKey(), domOffset, "text"); 27941 } else { 27942 const parentKey = node.getParentOrThrow().getKey(); 27943 const offset3 = node.getIndexWithinParent() + 1; 27944 selection.anchor.set(parentKey, offset3, "element"); 27945 selection.focus.set(parentKey, offset3, "element"); 27946 } 27947 const normalizedSelection = $normalizeSelection__EXPERIMENTAL(selection); 27948 $setSelection2(normalizedSelection); 27949 } 27950 editor.dispatchCommand(DRAG_DROP_PASTE, files); 27951 } 27952 event.preventDefault(); 27953 return true; 27954 } 27955 return $handleRichTextDrop2(event, editor); 27956 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(DRAGSTART_COMMAND2, (event) => { 27957 const [isFileTransfer] = eventFiles(event); 27958 const selection = $getSelection2(); 27959 if (isFileTransfer && !$isRangeSelection2(selection)) { 27960 return false; 27961 } 27962 if ($isRangeSelection2(selection) && !selection.isCollapsed() && event.dataTransfer !== null) { 27963 setLexicalClipboardDataTransfer2(event.dataTransfer, $getClipboardDataFromSelection2(selection)); 27964 $writeDragSourceToDataTransfer2(event.dataTransfer, editor); 27965 } 27966 return true; 27967 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(DRAGOVER_COMMAND2, (event) => { 27968 const [isFileTransfer] = eventFiles(event); 27969 const selection = $getSelection2(); 27970 if (isFileTransfer && !$isRangeSelection2(selection)) { 27971 return false; 27972 } 27973 const x3 = event.clientX; 27974 const y3 = event.clientY; 27975 const eventRange = caretFromPoint2(x3, y3); 27976 if (eventRange !== null) { 27977 const node = $getNearestNodeFromDOMNode2(eventRange.node); 27978 if ($isDecoratorNode2(node)) { 27979 event.preventDefault(); 27980 } 27981 } 27982 return true; 27983 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(SELECT_ALL_COMMAND2, () => { 27984 $selectAll2(); 27985 return true; 27986 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(COPY_COMMAND2, (event) => { 27987 copyToClipboard2(editor, objectKlassEquals2(event, ClipboardEvent) ? event : null); 27988 return true; 27989 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(CUT_COMMAND2, (event) => { 27990 onCutForRichText(event, editor); 27991 return true; 27992 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(PASTE_COMMAND2, (event) => { 27993 const [, files, hasTextContent] = eventFiles(event); 27994 if (files.length > 0 && !hasTextContent) { 27995 editor.dispatchCommand(DRAG_DROP_PASTE, files); 27996 return true; 27997 } 27998 if (isDOMNode2(event.target) && isSelectionCapturedInDecoratorInput2(event.target)) { 27999 return false; 28000 } 28001 const selection = $getSelection2(); 28002 if (selection !== null) { 28003 onPasteForRichText(event, editor); 28004 return true; 28005 } 28006 return false; 28007 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_SPACE_COMMAND2, (_3) => { 28008 const selection = $getSelection2(); 28009 if ($isRangeSelection2(selection)) { 28010 $resetCapitalization(selection); 28011 } 28012 return false; 28013 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(KEY_TAB_COMMAND2, (_3) => { 28014 const selection = $getSelection2(); 28015 if ($isRangeSelection2(selection)) { 28016 $resetCapitalization(selection); 28017 } 28018 return false; 28019 }, COMMAND_PRIORITY_EDITOR2)); 28020 return removeListener; 28021 } 28022 var RichTextExtension = defineExtension2({ 28023 conflictsWith: ["@lexical/plain-text"], 28024 dependencies: [DragonExtension2], 28025 name: "@lexical/rich-text", 28026 nodes: () => [HeadingNode, QuoteNode], 28027 register: registerRichText 28028 }); 28029 28030
vendor: 595 bytes, lines 28030-28043
28030// node_modules/@lexical/rich-text/LexicalRichText.mjs 28031 var mod11 = true ? LexicalRichText_dev_exports : LexicalRichText_prod_exports; 28032 var $createHeadingNode2 = mod11.$createHeadingNode; 28033 var $createQuoteNode2 = mod11.$createQuoteNode; 28034 var $isHeadingNode2 = mod11.$isHeadingNode; 28035 var $isQuoteNode2 = mod11.$isQuoteNode; 28036 var DRAG_DROP_PASTE2 = mod11.DRAG_DROP_PASTE; 28037 var HeadingNode2 = mod11.HeadingNode; 28038 var QuoteNode2 = mod11.QuoteNode; 28039 var RichTextExtension2 = mod11.RichTextExtension; 28040 var eventFiles2 = mod11.eventFiles; 28041 var registerRichText2 = mod11.registerRichText; 28042 28043
vendor: 13,026 bytes, lines 28043-28383
28043// node_modules/@lexical/history/LexicalHistory.dev.mjs 28044 var LexicalHistory_dev_exports = {}; 28045 __export(LexicalHistory_dev_exports, { 28046 HistoryExtension: () => HistoryExtension, 28047 SharedHistoryExtension: () => SharedHistoryExtension, 28048 createEmptyHistoryState: () => createEmptyHistoryState, 28049 registerHistory: () => registerHistory 28050 }); 28051 var HISTORY_MERGE = 0; 28052 var HISTORY_PUSH = 1; 28053 var DISCARD_HISTORY_CANDIDATE = 2; 28054 var OTHER = 0; 28055 var COMPOSING_CHARACTER = 1; 28056 var INSERT_CHARACTER_AFTER_SELECTION = 2; 28057 var DELETE_CHARACTER_BEFORE_SELECTION = 3; 28058 var DELETE_CHARACTER_AFTER_SELECTION = 4; 28059 function getDirtyNodes(editorState, dirtyLeaves, dirtyElements) { 28060 const nodeMap = editorState._nodeMap; 28061 const nodes = []; 28062 for (const dirtyLeafKey of dirtyLeaves) { 28063 const dirtyLeaf = nodeMap.get(dirtyLeafKey); 28064 if (dirtyLeaf !== void 0) { 28065 nodes.push(dirtyLeaf); 28066 } 28067 } 28068 for (const [dirtyElementKey, intentionallyMarkedAsDirty] of dirtyElements) { 28069 if (!intentionallyMarkedAsDirty) { 28070 continue; 28071 } 28072 const dirtyElement = nodeMap.get(dirtyElementKey); 28073 if (dirtyElement !== void 0 && !$isRootNode2(dirtyElement)) { 28074 nodes.push(dirtyElement); 28075 } 28076 } 28077 return nodes; 28078 } 28079 function getChangeType(prevEditorState, nextEditorState, dirtyLeavesSet, dirtyElementsSet, isComposing) { 28080 if (prevEditorState === null || dirtyLeavesSet.size === 0 && dirtyElementsSet.size === 0 && !isComposing) { 28081 return OTHER; 28082 } 28083 const nextSelection = nextEditorState._selection; 28084 const prevSelection = prevEditorState._selection; 28085 if (isComposing) { 28086 return COMPOSING_CHARACTER; 28087 } 28088 if (!$isRangeSelection2(nextSelection) || !$isRangeSelection2(prevSelection) || !prevSelection.isCollapsed() || !nextSelection.isCollapsed()) { 28089 return OTHER; 28090 } 28091 const dirtyNodes = getDirtyNodes(nextEditorState, dirtyLeavesSet, dirtyElementsSet); 28092 if (dirtyNodes.length === 0) { 28093 return OTHER; 28094 } 28095 if (dirtyNodes.length > 1) { 28096 const nextNodeMap = nextEditorState._nodeMap; 28097 const nextAnchorNode = nextNodeMap.get(nextSelection.anchor.key); 28098 const prevAnchorNode = nextNodeMap.get(prevSelection.anchor.key); 28099 if (nextAnchorNode && prevAnchorNode && !prevEditorState._nodeMap.has(nextAnchorNode.__key) && $isTextNode2(nextAnchorNode) && nextAnchorNode.__text.length === 1 && nextSelection.anchor.offset === 1) { 28100 return INSERT_CHARACTER_AFTER_SELECTION; 28101 } 28102 return OTHER; 28103 } 28104 const nextDirtyNode = dirtyNodes[0]; 28105 const prevDirtyNode = prevEditorState._nodeMap.get(nextDirtyNode.__key); 28106 if (!$isTextNode2(prevDirtyNode) || !$isTextNode2(nextDirtyNode) || prevDirtyNode.__mode !== nextDirtyNode.__mode) { 28107 return OTHER; 28108 } 28109 const prevText = prevDirtyNode.__text; 28110 const nextText = nextDirtyNode.__text; 28111 if (prevText === nextText) { 28112 return OTHER; 28113 } 28114 const nextAnchor = nextSelection.anchor; 28115 const prevAnchor = prevSelection.anchor; 28116 if (nextAnchor.key !== prevAnchor.key || nextAnchor.type !== "text") { 28117 return OTHER; 28118 } 28119 const nextAnchorOffset = nextAnchor.offset; 28120 const prevAnchorOffset = prevAnchor.offset; 28121 const textDiff = nextText.length - prevText.length; 28122 if (textDiff === 1 && prevAnchorOffset === nextAnchorOffset - 1) { 28123 return INSERT_CHARACTER_AFTER_SELECTION; 28124 } 28125 if (textDiff === -1 && prevAnchorOffset === nextAnchorOffset + 1) { 28126 return DELETE_CHARACTER_BEFORE_SELECTION; 28127 } 28128 if (textDiff === -1 && prevAnchorOffset === nextAnchorOffset) { 28129 return DELETE_CHARACTER_AFTER_SELECTION; 28130 } 28131 return OTHER; 28132 } 28133 function isTextNodeUnchanged(key, prevEditorState, nextEditorState) { 28134 const prevNode = prevEditorState._nodeMap.get(key); 28135 const nextNode = nextEditorState._nodeMap.get(key); 28136 const prevSelection = prevEditorState._selection; 28137 const nextSelection = nextEditorState._selection; 28138 const isDeletingLine = $isRangeSelection2(prevSelection) && $isRangeSelection2(nextSelection) && prevSelection.anchor.type === "element" && prevSelection.focus.type === "element" && nextSelection.anchor.type === "text" && nextSelection.focus.type === "text"; 28139 if (!isDeletingLine && $isTextNode2(prevNode) && $isTextNode2(nextNode) && prevNode.__parent === nextNode.__parent) { 28140 return JSON.stringify(prevEditorState.read(() => prevNode.exportJSON())) === JSON.stringify(nextEditorState.read(() => nextNode.exportJSON())); 28141 } 28142 return false; 28143 } 28144 function createMergeActionGetter(editor, delayOrStore, dateNow) { 28145 let prevChangeTime = dateNow(); 28146 let prevChangeType = OTHER; 28147 let compositionStartTime = prevChangeTime; 28148 let compositionStartChangeType = OTHER; 28149 let compositionStartState = null; 28150 return (prevEditorState, nextEditorState, currentHistoryEntry, dirtyLeaves, dirtyElements, tags) => { 28151 const changeTime = dateNow(); 28152 if (tags.has(COMPOSITION_START_TAG2)) { 28153 compositionStartTime = prevChangeTime; 28154 compositionStartChangeType = prevChangeType; 28155 compositionStartState = prevEditorState; 28156 } 28157 if (tags.has(HISTORIC_TAG2)) { 28158 prevChangeType = OTHER; 28159 prevChangeTime = changeTime; 28160 return DISCARD_HISTORY_CANDIDATE; 28161 } 28162 const isCompositionEnd = tags.has(COMPOSITION_END_TAG2); 28163 if (isCompositionEnd && compositionStartState) { 28164 prevChangeTime = compositionStartTime; 28165 prevChangeType = compositionStartChangeType; 28166 prevEditorState = compositionStartState; 28167 } 28168 const changeType = getChangeType(prevEditorState, nextEditorState, dirtyLeaves, dirtyElements, editor.isComposing()); 28169 const mergeAction = (() => { 28170 const isSameEditor = currentHistoryEntry === null || currentHistoryEntry.editor === editor; 28171 const shouldPushHistory = tags.has(HISTORY_PUSH_TAG2); 28172 const shouldMergeHistory = !shouldPushHistory && isSameEditor && tags.has(HISTORY_MERGE_TAG2); 28173 if (shouldMergeHistory) { 28174 return HISTORY_MERGE; 28175 } 28176 if (changeType === COMPOSING_CHARACTER) { 28177 return DISCARD_HISTORY_CANDIDATE; 28178 } 28179 if (prevEditorState === null) { 28180 return HISTORY_PUSH; 28181 } 28182 const selection = nextEditorState._selection; 28183 const hasDirtyNodes = dirtyLeaves.size > 0 || dirtyElements.size > 0; 28184 if (!hasDirtyNodes) { 28185 if (selection !== null) { 28186 return HISTORY_MERGE; 28187 } 28188 return DISCARD_HISTORY_CANDIDATE; 28189 } 28190 const delay2 = typeof delayOrStore === "number" ? delayOrStore : delayOrStore.peek(); 28191 if (shouldPushHistory === false && changeType !== OTHER && changeType === prevChangeType && changeTime < prevChangeTime + delay2 && isSameEditor) { 28192 return HISTORY_MERGE; 28193 } 28194 if (dirtyLeaves.size === 1) { 28195 const dirtyLeafKey = Array.from(dirtyLeaves)[0]; 28196 if (isTextNodeUnchanged(dirtyLeafKey, prevEditorState, nextEditorState)) { 28197 return HISTORY_MERGE; 28198 } 28199 } 28200 return HISTORY_PUSH; 28201 })(); 28202 prevChangeTime = changeTime; 28203 prevChangeType = changeType; 28204 return mergeAction; 28205 }; 28206 } 28207 function redo(editor, historyState) { 28208 const redoStack = historyState.redoStack; 28209 const undoStack = historyState.undoStack; 28210 if (redoStack.length !== 0) { 28211 const current = historyState.current; 28212 if (current !== null) { 28213 undoStack.push(current); 28214 editor.dispatchCommand(CAN_UNDO_COMMAND2, true); 28215 } 28216 const historyStateEntry = redoStack.pop(); 28217 if (redoStack.length === 0) { 28218 editor.dispatchCommand(CAN_REDO_COMMAND2, false); 28219 } 28220 historyState.current = historyStateEntry || null; 28221 if (historyStateEntry) { 28222 historyStateEntry.editor.setEditorState(historyStateEntry.editorState, { 28223 tag: HISTORIC_TAG2 28224 }); 28225 } 28226 } 28227 } 28228 function undo(editor, historyState) { 28229 const redoStack = historyState.redoStack; 28230 const undoStack = historyState.undoStack; 28231 const undoStackLength = undoStack.length; 28232 if (undoStackLength !== 0) { 28233 const current = historyState.current; 28234 const historyStateEntry = undoStack.pop(); 28235 if (current !== null) { 28236 redoStack.push(current); 28237 editor.dispatchCommand(CAN_REDO_COMMAND2, true); 28238 } 28239 if (undoStack.length === 0) { 28240 editor.dispatchCommand(CAN_UNDO_COMMAND2, false); 28241 } 28242 historyState.current = historyStateEntry || null; 28243 if (historyStateEntry) { 28244 historyStateEntry.editor.setEditorState(historyStateEntry.editorState, { 28245 tag: HISTORIC_TAG2 28246 }); 28247 } 28248 } 28249 } 28250 function clearHistory(historyState) { 28251 historyState.undoStack = []; 28252 historyState.redoStack = []; 28253 historyState.current = null; 28254 } 28255 function registerHistory(editor, historyState, delay2, dateNow = Date.now) { 28256 const getMergeAction = createMergeActionGetter(editor, delay2, dateNow); 28257 const applyChange = ({ 28258 editorState, 28259 prevEditorState, 28260 dirtyLeaves, 28261 dirtyElements, 28262 tags 28263 }) => { 28264 const current = historyState.current; 28265 const redoStack = historyState.redoStack; 28266 const undoStack = historyState.undoStack; 28267 const currentEditorState = current === null ? null : current.editorState; 28268 if (current !== null && editorState === currentEditorState) { 28269 return; 28270 } 28271 const mergeAction = getMergeAction(prevEditorState, editorState, current, dirtyLeaves, dirtyElements, tags); 28272 if (mergeAction === HISTORY_PUSH) { 28273 if (redoStack.length !== 0) { 28274 historyState.redoStack = []; 28275 editor.dispatchCommand(CAN_REDO_COMMAND2, false); 28276 } 28277 if (current !== null) { 28278 undoStack.push({ 28279 ...current 28280 }); 28281 editor.dispatchCommand(CAN_UNDO_COMMAND2, true); 28282 } 28283 } else if (mergeAction === DISCARD_HISTORY_CANDIDATE) { 28284 return; 28285 } 28286 historyState.current = { 28287 editor, 28288 editorState 28289 }; 28290 }; 28291 return mergeRegister3(editor.registerCommand(UNDO_COMMAND2, () => { 28292 undo(editor, historyState); 28293 return true; 28294 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(REDO_COMMAND2, () => { 28295 redo(editor, historyState); 28296 return true; 28297 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(CLEAR_EDITOR_COMMAND2, () => { 28298 clearHistory(historyState); 28299 return false; 28300 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(CLEAR_HISTORY_COMMAND2, () => { 28301 clearHistory(historyState); 28302 editor.dispatchCommand(CAN_REDO_COMMAND2, false); 28303 editor.dispatchCommand(CAN_UNDO_COMMAND2, false); 28304 return true; 28305 }, COMMAND_PRIORITY_EDITOR2), editor.registerUpdateListener(applyChange)); 28306 } 28307 function createEmptyHistoryState() { 28308 return { 28309 current: null, 28310 redoStack: [], 28311 undoStack: [] 28312 }; 28313 } 28314 var HistoryExtension = defineExtension2({ 28315 build: (editor, { 28316 delay: delay2, 28317 createInitialHistoryState, 28318 disabled, 28319 now 28320 }) => namedSignals2({ 28321 delay: delay2, 28322 disabled, 28323 historyState: createInitialHistoryState(editor), 28324 now 28325 }), 28326 config: safeCast2({ 28327 createInitialHistoryState: createEmptyHistoryState, 28328 delay: 300, 28329 disabled: typeof window === "undefined", 28330 now: Date.now 28331 }), 28332 name: "@lexical/history/History", 28333 register: (editor, config, state) => { 28334 const stores = state.getOutput(); 28335 return effect(() => stores.disabled.value ? void 0 : registerHistory(editor, stores.historyState.value, stores.delay, () => stores.now.peek()())); 28336 } 28337 }); 28338 function getHistoryPeer(editor) { 28339 return editor ? getPeerDependencyFromEditor2(editor, HistoryExtension.name) : null; 28340 } 28341 var SharedHistoryExtension = defineExtension2({ 28342 build: (editor, { 28343 disabled, 28344 parentEditor 28345 }) => namedSignals2({ 28346 disabled, 28347 parentEditor: parentEditor || editor._parentEditor 28348 }), 28349 config: safeCast2({ 28350 disabled: false, 28351 parentEditor: null 28352 }), 28353 dependencies: [configExtension2(HistoryExtension, { 28354 disabled: true 28355 })], 28356 name: "@lexical/history/SharedHistory", 28357 register(editor, _config, state) { 28358 return effect(() => { 28359 const { 28360 disabled, 28361 parentEditor 28362 } = state.getOutput(); 28363 if (!disabled.value) { 28364 const { 28365 output 28366 } = state.getDependency(HistoryExtension); 28367 const parentPeer = getHistoryPeer(parentEditor.value); 28368 if (!parentPeer) { 28369 return; 28370 } 28371 const parentOutput = parentPeer.output; 28372 batch(() => { 28373 output.delay.value = parentOutput.delay.value; 28374 output.historyState.value = parentOutput.historyState.value; 28375 output.now.value = parentOutput.now.value; 28376 output.disabled.value = parentOutput.disabled.value; 28377 }); 28378 } 28379 }); 28380 } 28381 }); 28382 28383
vendor: 358 bytes, lines 28383-28390
28383// node_modules/@lexical/history/LexicalHistory.mjs 28384 var mod12 = true ? LexicalHistory_dev_exports : LexicalHistory_prod_exports; 28385 var HistoryExtension2 = mod12.HistoryExtension; 28386 var SharedHistoryExtension2 = mod12.SharedHistoryExtension; 28387 var createEmptyHistoryState2 = mod12.createEmptyHistoryState; 28388 var registerHistory2 = mod12.registerHistory; 28389 28390
vendor: 1,413 bytes, lines 28390-28419
28390// node_modules/@lexical/code/LexicalCode.dev.mjs 28391 var LexicalCode_dev_exports = {}; 28392 __export(LexicalCode_dev_exports, { 28393 $createCodeHighlightNode: () => $createCodeHighlightNode2, 28394 $createCodeNode: () => $createCodeNode2, 28395 $getCodeLineDirection: () => $getCodeLineDirection2, 28396 $getEndOfCodeInLine: () => $getEndOfCodeInLine2, 28397 $getFirstCodeNodeOfLine: () => $getFirstCodeNodeOfLine2, 28398 $getLastCodeNodeOfLine: () => $getLastCodeNodeOfLine2, 28399 $getStartOfCodeInLine: () => $getStartOfCodeInLine2, 28400 $isCodeHighlightNode: () => $isCodeHighlightNode2, 28401 $isCodeNode: () => $isCodeNode2, 28402 CODE_LANGUAGE_FRIENDLY_NAME_MAP: () => CODE_LANGUAGE_FRIENDLY_NAME_MAP3, 28403 CODE_LANGUAGE_MAP: () => CODE_LANGUAGE_MAP3, 28404 CodeExtension: () => CodeExtension2, 28405 CodeHighlightNode: () => CodeHighlightNode2, 28406 CodeNode: () => CodeNode2, 28407 DEFAULT_CODE_LANGUAGE: () => DEFAULT_CODE_LANGUAGE2, 28408 PrismTokenizer: () => PrismTokenizer3, 28409 getCodeLanguageOptions: () => getCodeLanguageOptions3, 28410 getCodeLanguages: () => getCodeLanguages3, 28411 getCodeThemeOptions: () => getCodeThemeOptions3, 28412 getDefaultCodeLanguage: () => getDefaultCodeLanguage2, 28413 getLanguageFriendlyName: () => getLanguageFriendlyName3, 28414 normalizeCodeLang: () => normalizeCodeLang, 28415 normalizeCodeLanguage: () => normalizeCodeLanguage3, 28416 registerCodeHighlighting: () => registerCodeHighlighting3 28417 }); 28418 28419
vendor: 803 bytes, lines 28419-28436
28419// node_modules/@lexical/code-prism/LexicalCodePrism.dev.mjs 28420 var LexicalCodePrism_dev_exports = {}; 28421 __export(LexicalCodePrism_dev_exports, { 28422 CODE_LANGUAGE_FRIENDLY_NAME_MAP: () => CODE_LANGUAGE_FRIENDLY_NAME_MAP, 28423 CODE_LANGUAGE_MAP: () => CODE_LANGUAGE_MAP, 28424 CodePrismExtension: () => CodePrismExtension, 28425 PrismTokenizer: () => PrismTokenizer, 28426 getCodeLanguageOptions: () => getCodeLanguageOptions, 28427 getCodeLanguages: () => getCodeLanguages, 28428 getCodeThemeOptions: () => getCodeThemeOptions, 28429 getLanguageFriendlyName: () => getLanguageFriendlyName, 28430 isCodeLanguageLoaded: () => isCodeLanguageLoaded, 28431 loadCodeLanguage: () => loadCodeLanguage, 28432 normalizeCodeLanguage: () => normalizeCodeLanguage, 28433 registerCodeHighlighting: () => registerCodeHighlighting 28434 }); 28435 28436
vendor: 20,219 bytes, lines 28436-29061
28436// node_modules/@lexical/code-core/LexicalCodeCore.dev.mjs 28437 var LexicalCodeCore_dev_exports = {}; 28438 __export(LexicalCodeCore_dev_exports, { 28439 $createCodeHighlightNode: () => $createCodeHighlightNode, 28440 $createCodeNode: () => $createCodeNode, 28441 $getCodeLineDirection: () => $getCodeLineDirection, 28442 $getEndOfCodeInLine: () => $getEndOfCodeInLine, 28443 $getFirstCodeNodeOfLine: () => $getFirstCodeNodeOfLine, 28444 $getLastCodeNodeOfLine: () => $getLastCodeNodeOfLine, 28445 $getStartOfCodeInLine: () => $getStartOfCodeInLine, 28446 $isCodeHighlightNode: () => $isCodeHighlightNode, 28447 $isCodeNode: () => $isCodeNode, 28448 CodeExtension: () => CodeExtension, 28449 CodeHighlightNode: () => CodeHighlightNode, 28450 CodeNode: () => CodeNode, 28451 DEFAULT_CODE_LANGUAGE: () => DEFAULT_CODE_LANGUAGE, 28452 getDefaultCodeLanguage: () => getDefaultCodeLanguage 28453 }); 28454 function warnOnlyOnce3(message) { 28455 { 28456 let run = false; 28457 return () => { 28458 if (!run) { 28459 console.warn(message); 28460 } 28461 run = true; 28462 }; 28463 } 28464 } 28465 function formatDevErrorMessage9(message) { 28466 throw new Error(message); 28467 } 28468 function $getLastMatchingCodeNode(anchor, direction) { 28469 let matchingNode = anchor; 28470 for (let caret = $getSiblingCaret2(anchor, direction); caret && ($isCodeHighlightNode(caret.origin) || $isTabNode2(caret.origin)); caret = caret.getAdjacentCaret()) { 28471 matchingNode = caret.origin; 28472 } 28473 return matchingNode; 28474 } 28475 function $getFirstCodeNodeOfLine(anchor) { 28476 return $getLastMatchingCodeNode(anchor, "previous"); 28477 } 28478 function $getLastCodeNodeOfLine(anchor) { 28479 return $getLastMatchingCodeNode(anchor, "next"); 28480 } 28481 function $getCodeLineDirection(anchor) { 28482 const start3 = $getFirstCodeNodeOfLine(anchor); 28483 const end = $getLastCodeNodeOfLine(anchor); 28484 let node = start3; 28485 while (node !== null) { 28486 if ($isCodeHighlightNode(node)) { 28487 const direction = getTextDirection2(node.getTextContent()); 28488 if (direction !== null) { 28489 return direction; 28490 } 28491 } 28492 if (node === end) { 28493 break; 28494 } 28495 node = node.getNextSibling(); 28496 } 28497 const parent = start3.getParent(); 28498 if ($isElementNode2(parent)) { 28499 const parentDirection = parent.getDirection(); 28500 if (parentDirection === "ltr" || parentDirection === "rtl") { 28501 return parentDirection; 28502 } 28503 } 28504 return null; 28505 } 28506 function $getStartOfCodeInLine(anchor, offset3) { 28507 let last = null; 28508 let lastNonBlank = null; 28509 let node = anchor; 28510 let nodeOffset = offset3; 28511 let nodeTextContent = anchor.getTextContent(); 28512 while (true) { 28513 if (nodeOffset === 0) { 28514 node = node.getPreviousSibling(); 28515 if (node === null) { 28516 break; 28517 } 28518 if (!($isCodeHighlightNode(node) || $isTabNode2(node) || $isLineBreakNode2(node))) { 28519 formatDevErrorMessage9(`Expected a valid Code Node: CodeHighlightNode, TabNode, LineBreakNode`); 28520 } 28521 if ($isLineBreakNode2(node)) { 28522 last = { 28523 node, 28524 offset: 1 28525 }; 28526 break; 28527 } 28528 nodeOffset = Math.max(0, node.getTextContentSize() - 1); 28529 nodeTextContent = node.getTextContent(); 28530 } else { 28531 nodeOffset--; 28532 } 28533 const character = nodeTextContent[nodeOffset]; 28534 if ($isCodeHighlightNode(node) && character !== " ") { 28535 lastNonBlank = { 28536 node, 28537 offset: nodeOffset 28538 }; 28539 } 28540 } 28541 if (lastNonBlank !== null) { 28542 return lastNonBlank; 28543 } 28544 let codeCharacterAtAnchorOffset = null; 28545 if (offset3 < anchor.getTextContentSize()) { 28546 if ($isCodeHighlightNode(anchor)) { 28547 codeCharacterAtAnchorOffset = anchor.getTextContent()[offset3]; 28548 } 28549 } else { 28550 const nextSibling = anchor.getNextSibling(); 28551 if ($isCodeHighlightNode(nextSibling)) { 28552 codeCharacterAtAnchorOffset = nextSibling.getTextContent()[0]; 28553 } 28554 } 28555 if (codeCharacterAtAnchorOffset !== null && codeCharacterAtAnchorOffset !== " ") { 28556 return last; 28557 } else { 28558 const nextNonBlank = findNextNonBlankInLine(anchor, offset3); 28559 if (nextNonBlank !== null) { 28560 return nextNonBlank; 28561 } else { 28562 return last; 28563 } 28564 } 28565 } 28566 function findNextNonBlankInLine(anchor, offset3) { 28567 let node = anchor; 28568 let nodeOffset = offset3; 28569 let nodeTextContent = anchor.getTextContent(); 28570 let nodeTextContentSize = anchor.getTextContentSize(); 28571 while (true) { 28572 if (!$isCodeHighlightNode(node) || nodeOffset === nodeTextContentSize) { 28573 node = node.getNextSibling(); 28574 if (node === null || $isLineBreakNode2(node)) { 28575 return null; 28576 } 28577 if ($isCodeHighlightNode(node)) { 28578 nodeOffset = 0; 28579 nodeTextContent = node.getTextContent(); 28580 nodeTextContentSize = node.getTextContentSize(); 28581 } 28582 } 28583 if ($isCodeHighlightNode(node)) { 28584 if (nodeTextContent[nodeOffset] !== " ") { 28585 return { 28586 node, 28587 offset: nodeOffset 28588 }; 28589 } 28590 nodeOffset++; 28591 } 28592 } 28593 } 28594 function $getEndOfCodeInLine(anchor) { 28595 const lastNode = $getLastCodeNodeOfLine(anchor); 28596 if (!!$isLineBreakNode2(lastNode)) { 28597 formatDevErrorMessage9(`Unexpected lineBreakNode in getEndOfCodeInLine`); 28598 } 28599 return lastNode; 28600 } 28601 var DEFAULT_CODE_LANGUAGE = "javascript"; 28602 var getDefaultCodeLanguage = () => DEFAULT_CODE_LANGUAGE; 28603 function hasChildDOMNodeTag(node, tagName) { 28604 for (const child of node.childNodes) { 28605 if (isHTMLElement2(child) && child.tagName === tagName) { 28606 return true; 28607 } 28608 hasChildDOMNodeTag(child, tagName); 28609 } 28610 return false; 28611 } 28612 var LANGUAGE_DATA_ATTRIBUTE = "data-language"; 28613 var HIGHLIGHT_LANGUAGE_DATA_ATTRIBUTE = "data-highlight-language"; 28614 var THEME_DATA_ATTRIBUTE = "data-theme"; 28615 var noExtensionDeprecation = warnOnlyOnce3("Using CodeNode without CodeExtension is deprecated"); 28616 var CodeNode = class _CodeNode extends ElementNode2 { 28617 /** @internal */ 28618 __language; 28619 /** @internal */ 28620 __theme; 28621 /** @internal */ 28622 __isSyntaxHighlightSupported; 28623 static getType() { 28624 return "code"; 28625 } 28626 static clone(node) { 28627 return new _CodeNode(node.__language, node.__key); 28628 } 28629 constructor(language, key) { 28630 super(key); 28631 this.__language = language || void 0; 28632 this.__isSyntaxHighlightSupported = false; 28633 this.__theme = void 0; 28634 } 28635 afterCloneFrom(prevNode) { 28636 super.afterCloneFrom(prevNode); 28637 this.__language = prevNode.__language; 28638 this.__theme = prevNode.__theme; 28639 this.__isSyntaxHighlightSupported = prevNode.__isSyntaxHighlightSupported; 28640 } 28641 // View 28642 createDOM(config) { 28643 const element = document.createElement("code"); 28644 addClassNamesToElement2(element, config.theme.code); 28645 element.setAttribute("spellcheck", "false"); 28646 const language = this.getLanguage(); 28647 if (language) { 28648 element.setAttribute(LANGUAGE_DATA_ATTRIBUTE, language); 28649 if (this.getIsSyntaxHighlightSupported()) { 28650 element.setAttribute(HIGHLIGHT_LANGUAGE_DATA_ATTRIBUTE, language); 28651 } 28652 } 28653 const theme2 = this.getTheme(); 28654 if (theme2) { 28655 element.setAttribute(THEME_DATA_ATTRIBUTE, theme2); 28656 } 28657 const style = this.getStyle(); 28658 if (style) { 28659 setDOMStyleFromCSS2(element.style, style); 28660 } 28661 return element; 28662 } 28663 updateDOM(prevNode, dom, config) { 28664 const language = this.__language; 28665 const prevLanguage = prevNode.__language; 28666 if (language) { 28667 if (language !== prevLanguage) { 28668 dom.setAttribute(LANGUAGE_DATA_ATTRIBUTE, language); 28669 } 28670 } else if (prevLanguage) { 28671 dom.removeAttribute(LANGUAGE_DATA_ATTRIBUTE); 28672 } 28673 const isSyntaxHighlightSupported = this.__isSyntaxHighlightSupported; 28674 const prevIsSyntaxHighlightSupported = prevNode.__isSyntaxHighlightSupported; 28675 if (prevIsSyntaxHighlightSupported && prevLanguage) { 28676 if (isSyntaxHighlightSupported && language) { 28677 if (language !== prevLanguage) { 28678 dom.setAttribute(HIGHLIGHT_LANGUAGE_DATA_ATTRIBUTE, language); 28679 } 28680 } else { 28681 dom.removeAttribute(HIGHLIGHT_LANGUAGE_DATA_ATTRIBUTE); 28682 } 28683 } else if (isSyntaxHighlightSupported && language) { 28684 dom.setAttribute(HIGHLIGHT_LANGUAGE_DATA_ATTRIBUTE, language); 28685 } 28686 const theme2 = this.__theme; 28687 const prevTheme = prevNode.__theme; 28688 if (theme2) { 28689 if (theme2 !== prevTheme) { 28690 dom.setAttribute(THEME_DATA_ATTRIBUTE, theme2); 28691 } 28692 } else if (prevTheme) { 28693 dom.removeAttribute(THEME_DATA_ATTRIBUTE); 28694 } 28695 const style = this.__style; 28696 const prevStyle = prevNode.__style; 28697 if (style !== prevStyle) { 28698 setDOMStyleFromCSS2(dom.style, style, prevStyle); 28699 } 28700 return false; 28701 } 28702 exportDOM(editor) { 28703 const element = document.createElement("pre"); 28704 addClassNamesToElement2(element, editor._config.theme.code); 28705 element.setAttribute("spellcheck", "false"); 28706 const language = this.getLanguage(); 28707 if (language) { 28708 element.setAttribute(LANGUAGE_DATA_ATTRIBUTE, language); 28709 if (this.getIsSyntaxHighlightSupported()) { 28710 element.setAttribute(HIGHLIGHT_LANGUAGE_DATA_ATTRIBUTE, language); 28711 } 28712 } 28713 const theme2 = this.getTheme(); 28714 if (theme2) { 28715 element.setAttribute(THEME_DATA_ATTRIBUTE, theme2); 28716 } 28717 const style = this.getStyle(); 28718 if (style) { 28719 setDOMStyleFromCSS2(element.style, style); 28720 } 28721 return { 28722 element 28723 }; 28724 } 28725 static importDOM() { 28726 return { 28727 // Typically <pre> is used for code blocks, and <code> for inline code styles 28728 // but if it's a multi line <code> we'll create a block. Pass through to 28729 // inline format handled by TextNode otherwise. 28730 code: (node) => { 28731 const isMultiLine = node.textContent != null && (/\r?\n/.test(node.textContent) || hasChildDOMNodeTag(node, "BR")); 28732 return isMultiLine ? { 28733 conversion: $convertPreElement, 28734 priority: 1 28735 } : null; 28736 }, 28737 div: () => ({ 28738 conversion: $convertDivElement, 28739 priority: 1 28740 }), 28741 pre: () => ({ 28742 conversion: $convertPreElement, 28743 priority: 0 28744 }), 28745 table: (node) => { 28746 const table = node; 28747 if (isGitHubCodeTable(table)) { 28748 return { 28749 conversion: $convertTableElement, 28750 priority: 3 28751 }; 28752 } 28753 return null; 28754 }, 28755 td: (node) => { 28756 const td = node; 28757 const table = td.closest("table"); 28758 if (isGitHubCodeCell(td) || table && isGitHubCodeTable(table)) { 28759 return { 28760 conversion: convertCodeNoop, 28761 priority: 3 28762 }; 28763 } 28764 return null; 28765 }, 28766 tr: (node) => { 28767 const tr = node; 28768 const table = tr.closest("table"); 28769 if (table && isGitHubCodeTable(table)) { 28770 return { 28771 conversion: convertCodeNoop, 28772 priority: 3 28773 }; 28774 } 28775 return null; 28776 } 28777 }; 28778 } 28779 static importJSON(serializedNode) { 28780 return $createCodeNode().updateFromJSON(serializedNode); 28781 } 28782 updateFromJSON(serializedNode) { 28783 return super.updateFromJSON(serializedNode).setLanguage(serializedNode.language).setTheme(serializedNode.theme); 28784 } 28785 exportJSON() { 28786 return { 28787 ...super.exportJSON(), 28788 language: this.getLanguage(), 28789 theme: this.getTheme() 28790 }; 28791 } 28792 // Mutation 28793 insertNewAfter(selection, restoreSelection = true) { 28794 if (!getPeerDependencyFromEditor2($getEditor2(), "@lexical/code")) { 28795 noExtensionDeprecation(); 28796 const el = $exitCodeNodeOnEnter(selection); 28797 if (el) { 28798 return el; 28799 } 28800 } 28801 const { 28802 anchor, 28803 focus 28804 } = selection; 28805 const firstPoint = anchor.isBefore(focus) ? anchor : focus; 28806 const firstSelectionNode = firstPoint.getNode(); 28807 if ($isTextNode2(firstSelectionNode)) { 28808 let node = $getFirstCodeNodeOfLine(firstSelectionNode); 28809 const insertNodes = []; 28810 while (true) { 28811 if ($isTabNode2(node)) { 28812 insertNodes.push($createTabNode2()); 28813 node = node.getNextSibling(); 28814 } else if ($isCodeHighlightNode(node)) { 28815 let spaces = 0; 28816 const text2 = node.getTextContent(); 28817 const textSize = node.getTextContentSize(); 28818 while (spaces < textSize && text2[spaces] === " ") { 28819 spaces++; 28820 } 28821 if (spaces !== 0) { 28822 insertNodes.push($createCodeHighlightNode(" ".repeat(spaces))); 28823 } 28824 if (spaces !== textSize) { 28825 break; 28826 } 28827 node = node.getNextSibling(); 28828 } else { 28829 break; 28830 } 28831 } 28832 const split = firstSelectionNode.splitText(anchor.offset)[0]; 28833 const x3 = anchor.offset === 0 ? 0 : 1; 28834 const index = split.getIndexWithinParent() + x3; 28835 const codeNode = firstSelectionNode.getParentOrThrow(); 28836 const nodesToInsert = [$createLineBreakNode2(), ...insertNodes]; 28837 codeNode.splice(index, 0, nodesToInsert); 28838 const last = insertNodes[insertNodes.length - 1]; 28839 if (last) { 28840 last.select(); 28841 } else if (anchor.offset === 0) { 28842 split.selectPrevious(); 28843 } else { 28844 split.getNextSibling().selectNext(0, 0); 28845 } 28846 } 28847 if ($isCodeNode(firstSelectionNode)) { 28848 const { 28849 offset: offset3 28850 } = selection.anchor; 28851 firstSelectionNode.splice(offset3, 0, [$createLineBreakNode2()]); 28852 firstSelectionNode.select(offset3 + 1, offset3 + 1); 28853 } 28854 return null; 28855 } 28856 canIndent() { 28857 return false; 28858 } 28859 collapseAtStart() { 28860 const paragraph = $createParagraphNode2(); 28861 const children = this.getChildren(); 28862 children.forEach((child) => paragraph.append(child)); 28863 this.replace(paragraph); 28864 return true; 28865 } 28866 setLanguage(language) { 28867 const writable = this.getWritable(); 28868 writable.__language = language || void 0; 28869 return writable; 28870 } 28871 getLanguage() { 28872 return this.getLatest().__language; 28873 } 28874 setIsSyntaxHighlightSupported(isSupported) { 28875 const writable = this.getWritable(); 28876 writable.__isSyntaxHighlightSupported = isSupported; 28877 return writable; 28878 } 28879 getIsSyntaxHighlightSupported() { 28880 return this.getLatest().__isSyntaxHighlightSupported; 28881 } 28882 setTheme(theme2) { 28883 const writable = this.getWritable(); 28884 writable.__theme = theme2 || void 0; 28885 return writable; 28886 } 28887 getTheme() { 28888 return this.getLatest().__theme; 28889 } 28890 }; 28891 function $createCodeNode(language, theme2) { 28892 return $create2(CodeNode).setLanguage(language).setTheme(theme2); 28893 } 28894 function $isCodeNode(node) { 28895 return node instanceof CodeNode; 28896 } 28897 function $convertPreElement(domNode) { 28898 const language = domNode.getAttribute(LANGUAGE_DATA_ATTRIBUTE); 28899 return { 28900 node: $createCodeNode(language) 28901 }; 28902 } 28903 function $convertDivElement(domNode) { 28904 const div = domNode; 28905 const isCode = isCodeElement(div); 28906 if (!isCode && !isCodeChildElement(div)) { 28907 return { 28908 node: null 28909 }; 28910 } 28911 return { 28912 node: isCode ? $createCodeNode() : null 28913 }; 28914 } 28915 function $convertTableElement() { 28916 return { 28917 node: $createCodeNode() 28918 }; 28919 } 28920 function convertCodeNoop() { 28921 return { 28922 node: null 28923 }; 28924 } 28925 function isCodeElement(div) { 28926 return div.style.fontFamily.match("monospace") !== null; 28927 } 28928 function isCodeChildElement(node) { 28929 let parent = node.parentElement; 28930 while (parent !== null) { 28931 if (isCodeElement(parent)) { 28932 return true; 28933 } 28934 parent = parent.parentElement; 28935 } 28936 return false; 28937 } 28938 function isGitHubCodeCell(cell) { 28939 return cell.classList.contains("js-file-line"); 28940 } 28941 function isGitHubCodeTable(table) { 28942 return table.classList.contains("js-file-line-container"); 28943 } 28944 function $exitCodeNodeOnEnter(selection) { 28945 const { 28946 anchor 28947 } = selection; 28948 if (selection.isCollapsed() && anchor.type === "element") { 28949 const codeNode = anchor.getNode(); 28950 if ($isCodeNode(codeNode)) { 28951 const childrenSize = codeNode.getChildrenSize(); 28952 if (childrenSize >= 2 && anchor.offset === childrenSize) { 28953 const lastChild = codeNode.getLastChild(); 28954 if ($isLineBreakNode2(lastChild) && $isLineBreakNode2(lastChild.getPreviousSibling())) { 28955 const newElement = $createParagraphNode2(); 28956 codeNode.splice(childrenSize - 2, 2, []).insertAfter(newElement, false); 28957 newElement.select(); 28958 return newElement; 28959 } 28960 } 28961 } 28962 } 28963 return null; 28964 } 28965 var CodeHighlightNode = class _CodeHighlightNode extends TextNode2 { 28966 /** @internal */ 28967 __highlightType; 28968 constructor(text2 = "", highlightType, key) { 28969 super(text2, key); 28970 this.__highlightType = highlightType; 28971 } 28972 static getType() { 28973 return "code-highlight"; 28974 } 28975 static clone(node) { 28976 return new _CodeHighlightNode(node.__text, node.__highlightType || void 0, node.__key); 28977 } 28978 afterCloneFrom(prevNode) { 28979 super.afterCloneFrom(prevNode); 28980 this.__highlightType = prevNode.__highlightType; 28981 } 28982 getHighlightType() { 28983 const self2 = this.getLatest(); 28984 return self2.__highlightType; 28985 } 28986 setHighlightType(highlightType) { 28987 const self2 = this.getWritable(); 28988 self2.__highlightType = highlightType || void 0; 28989 return self2; 28990 } 28991 canHaveFormat() { 28992 return false; 28993 } 28994 createDOM(config) { 28995 const element = super.createDOM(config); 28996 const className = getHighlightThemeClass(config.theme, this.__highlightType); 28997 addClassNamesToElement2(element, className); 28998 return element; 28999 } 29000 updateDOM(prevNode, dom, config) { 29001 const update = super.updateDOM(prevNode, dom, config); 29002 const prevClassName = getHighlightThemeClass(config.theme, prevNode.__highlightType); 29003 const nextClassName = getHighlightThemeClass(config.theme, this.__highlightType); 29004 if (prevClassName !== nextClassName) { 29005 if (prevClassName) { 29006 removeClassNamesFromElement2(dom, prevClassName); 29007 } 29008 if (nextClassName) { 29009 addClassNamesToElement2(dom, nextClassName); 29010 } 29011 } 29012 return update; 29013 } 29014 static importJSON(serializedNode) { 29015 return $createCodeHighlightNode().updateFromJSON(serializedNode); 29016 } 29017 updateFromJSON(serializedNode) { 29018 return super.updateFromJSON(serializedNode).setHighlightType(serializedNode.highlightType); 29019 } 29020 exportJSON() { 29021 return { 29022 ...super.exportJSON(), 29023 highlightType: this.getHighlightType() 29024 }; 29025 } 29026 // Prevent formatting (bold, underline, etc) 29027 setFormat(format) { 29028 return this; 29029 } 29030 isParentRequired() { 29031 return true; 29032 } 29033 createParentElementNode() { 29034 return $createCodeNode(); 29035 } 29036 }; 29037 function getHighlightThemeClass(theme2, highlightType) { 29038 return highlightType && theme2 && theme2.codeHighlight && theme2.codeHighlight[highlightType]; 29039 } 29040 function $createCodeHighlightNode(text2 = "", highlightType) { 29041 return $applyNodeReplacement2(new CodeHighlightNode(text2, highlightType)); 29042 } 29043 function $isCodeHighlightNode(node) { 29044 return node instanceof CodeHighlightNode; 29045 } 29046 var CodeExtension = defineExtension2({ 29047 name: "@lexical/code", 29048 nodes: () => [CodeNode, CodeHighlightNode], 29049 register(editor) { 29050 return editor.registerCommand(KEY_ENTER_COMMAND2, (event) => { 29051 const selection = $getSelection2(); 29052 if ($isRangeSelection2(selection) && $exitCodeNodeOnEnter(selection)) { 29053 event.preventDefault(); 29054 return true; 29055 } 29056 return false; 29057 }, COMMAND_PRIORITY_LOW2); 29058 } 29059 }); 29060 29061
vendor: 905 bytes, lines 29061-29078
29061// node_modules/@lexical/code-core/LexicalCodeCore.mjs 29062 var mod13 = true ? LexicalCodeCore_dev_exports : LexicalCodeCore_prod_exports; 29063 var $createCodeHighlightNode2 = mod13.$createCodeHighlightNode; 29064 var $createCodeNode2 = mod13.$createCodeNode; 29065 var $getCodeLineDirection2 = mod13.$getCodeLineDirection; 29066 var $getEndOfCodeInLine2 = mod13.$getEndOfCodeInLine; 29067 var $getFirstCodeNodeOfLine2 = mod13.$getFirstCodeNodeOfLine; 29068 var $getLastCodeNodeOfLine2 = mod13.$getLastCodeNodeOfLine; 29069 var $getStartOfCodeInLine2 = mod13.$getStartOfCodeInLine; 29070 var $isCodeHighlightNode2 = mod13.$isCodeHighlightNode; 29071 var $isCodeNode2 = mod13.$isCodeNode; 29072 var CodeExtension2 = mod13.CodeExtension; 29073 var CodeHighlightNode2 = mod13.CodeHighlightNode; 29074 var CodeNode2 = mod13.CodeNode; 29075 var DEFAULT_CODE_LANGUAGE2 = mod13.DEFAULT_CODE_LANGUAGE; 29076 var getDefaultCodeLanguage2 = mod13.getDefaultCodeLanguage; 29077 29078
vendor: 27,232 bytes, lines 29078-29828
29078// node_modules/@lexical/code-prism/LexicalCodePrism.dev.mjs 29079 var import_prismjs2 = __toESM(require_prism(), 1); 29080 function formatDevErrorMessage10(message) { 29081 throw new Error(message); 29082 } 29083 (function(Prism3) { 29084 Prism3.languages.diff = { 29085 "coord": [ 29086 // Match all kinds of coord lines (prefixed by "+++", "---" or "***"). 29087 /^(?:\*{3}|-{3}|\+{3}).*$/m, 29088 // Match "@@ ... @@" coord lines in unified diff. 29089 /^@@.*@@$/m, 29090 // Match coord lines in normal diff (starts with a number). 29091 /^\d.*$/m 29092 ] 29093 // deleted, inserted, unchanged, diff 29094 }; 29095 var PREFIXES = { 29096 "deleted-sign": "-", 29097 "deleted-arrow": "<", 29098 "inserted-sign": "+", 29099 "inserted-arrow": ">", 29100 "unchanged": " ", 29101 "diff": "!" 29102 }; 29103 Object.keys(PREFIXES).forEach(function(name) { 29104 var prefix = PREFIXES[name]; 29105 var alias = []; 29106 if (!/^\w+$/.test(name)) { 29107 alias.push(/\w+/.exec(name)[0]); 29108 } 29109 if (name === "diff") { 29110 alias.push("bold"); 29111 } 29112 Prism3.languages.diff[name] = { 29113 pattern: RegExp("^(?:[" + prefix + "].*(?:\r\n?|\n|(?![\\s\\S])))+", "m"), 29114 alias, 29115 inside: { 29116 "line": { 29117 pattern: /(.)(?=[\s\S]).*(?:\r\n?|\n)?/, 29118 lookbehind: true 29119 }, 29120 "prefix": { 29121 pattern: /[\s\S]/, 29122 alias: /\w+/.exec(name)[0] 29123 } 29124 } 29125 }; 29126 }); 29127 Object.defineProperty(Prism3.languages.diff, "PREFIXES", { 29128 value: PREFIXES 29129 }); 29130 })(Prism); 29131 var Prism$1 = globalThis.Prism || window.Prism; 29132 var CODE_LANGUAGE_FRIENDLY_NAME_MAP = { 29133 c: "C", 29134 clike: "C-like", 29135 cpp: "C++", 29136 css: "CSS", 29137 html: "HTML", 29138 java: "Java", 29139 js: "JavaScript", 29140 markdown: "Markdown", 29141 objc: "Objective-C", 29142 plain: "Plain Text", 29143 powershell: "PowerShell", 29144 py: "Python", 29145 rust: "Rust", 29146 sql: "SQL", 29147 swift: "Swift", 29148 typescript: "TypeScript", 29149 xml: "XML" 29150 }; 29151 var CODE_LANGUAGE_MAP = { 29152 cpp: "cpp", 29153 java: "java", 29154 javascript: "js", 29155 md: "markdown", 29156 plaintext: "plain", 29157 python: "py", 29158 text: "plain", 29159 ts: "typescript" 29160 }; 29161 function normalizeCodeLanguage(lang) { 29162 return CODE_LANGUAGE_MAP[lang] || lang; 29163 } 29164 function getLanguageFriendlyName(lang) { 29165 const _lang = normalizeCodeLanguage(lang); 29166 return CODE_LANGUAGE_FRIENDLY_NAME_MAP[_lang] || _lang; 29167 } 29168 var getCodeLanguages = () => Object.keys(Prism$1.languages).filter( 29169 // Prism has several language helpers mixed into languages object 29170 // so filtering them out here to get langs list 29171 (language) => typeof Prism$1.languages[language] !== "function" 29172 ).sort(); 29173 function getCodeLanguageOptions() { 29174 const options = []; 29175 for (const [lang, friendlyName] of Object.entries(CODE_LANGUAGE_FRIENDLY_NAME_MAP)) { 29176 options.push([lang, friendlyName]); 29177 } 29178 return options; 29179 } 29180 function getCodeThemeOptions() { 29181 const options = []; 29182 return options; 29183 } 29184 function getDiffedLanguage(language) { 29185 const DIFF_LANGUAGE_REGEX = /^diff-([\w-]+)/i; 29186 const diffLanguageMatch = DIFF_LANGUAGE_REGEX.exec(language); 29187 return diffLanguageMatch ? diffLanguageMatch[1] : null; 29188 } 29189 function isCodeLanguageLoaded(language) { 29190 const diffedLanguage = getDiffedLanguage(language); 29191 const langId = diffedLanguage ? diffedLanguage : language; 29192 try { 29193 return langId ? Prism$1.languages.hasOwnProperty(langId) : false; 29194 } catch (_unused) { 29195 return false; 29196 } 29197 } 29198 async function loadCodeLanguage(language, editor, codeNodeKey) { 29199 } 29200 function getTextContent(token) { 29201 if (typeof token === "string") { 29202 return token; 29203 } else if (Array.isArray(token)) { 29204 return token.map(getTextContent).join(""); 29205 } else { 29206 return getTextContent(token.content); 29207 } 29208 } 29209 function tokenizeDiffHighlight(tokens, language) { 29210 const diffLanguage = language; 29211 const diffGrammar = Prism$1.languages[diffLanguage]; 29212 const env = { 29213 tokens 29214 }; 29215 const PREFIXES = Prism$1.languages.diff.PREFIXES; 29216 for (const token of env.tokens) { 29217 if (typeof token === "string" || !(token.type in PREFIXES) || !Array.isArray(token.content)) { 29218 continue; 29219 } 29220 const type = token.type; 29221 let insertedPrefixes = 0; 29222 const getPrefixToken = () => { 29223 insertedPrefixes++; 29224 return new Prism$1.Token("prefix", PREFIXES[type], type.replace(/^(\w+).*/, "$1")); 29225 }; 29226 const withoutPrefixes = token.content.filter((t2) => typeof t2 === "string" || t2.type !== "prefix"); 29227 const prefixCount = token.content.length - withoutPrefixes.length; 29228 const diffTokens = Prism$1.tokenize(getTextContent(withoutPrefixes), diffGrammar); 29229 diffTokens.unshift(getPrefixToken()); 29230 const LINE_BREAK = /\r\n|\n/g; 29231 const insertAfterLineBreakString = (text2) => { 29232 const result = []; 29233 LINE_BREAK.lastIndex = 0; 29234 let last = 0; 29235 let m3; 29236 while (insertedPrefixes < prefixCount && (m3 = LINE_BREAK.exec(text2))) { 29237 const end = m3.index + m3[0].length; 29238 result.push(text2.slice(last, end)); 29239 last = end; 29240 result.push(getPrefixToken()); 29241 } 29242 if (result.length === 0) { 29243 return void 0; 29244 } 29245 if (last < text2.length) { 29246 result.push(text2.slice(last)); 29247 } 29248 return result; 29249 }; 29250 const insertAfterLineBreak = (toks) => { 29251 for (let i2 = 0; i2 < toks.length && insertedPrefixes < prefixCount; i2++) { 29252 const tok = toks[i2]; 29253 if (typeof tok === "string") { 29254 const inserted = insertAfterLineBreakString(tok); 29255 if (inserted) { 29256 toks.splice(i2, 1, ...inserted); 29257 i2 += inserted.length - 1; 29258 } 29259 } else if (typeof tok.content === "string") { 29260 const inserted = insertAfterLineBreakString(tok.content); 29261 if (inserted) { 29262 tok.content = inserted; 29263 } 29264 } else if (Array.isArray(tok.content)) { 29265 insertAfterLineBreak(tok.content); 29266 } else { 29267 insertAfterLineBreak([tok.content]); 29268 } 29269 } 29270 }; 29271 insertAfterLineBreak(diffTokens); 29272 if (insertedPrefixes < prefixCount) { 29273 diffTokens.push(getPrefixToken()); 29274 } 29275 token.content = diffTokens; 29276 } 29277 return env.tokens; 29278 } 29279 function $getHighlightNodes(codeNode, language) { 29280 const DIFF_LANGUAGE_REGEX = /^diff-([\w-]+)/i; 29281 const diffLanguageMatch = DIFF_LANGUAGE_REGEX.exec(language); 29282 const code = codeNode.getTextContent(); 29283 let tokens = Prism$1.tokenize(code, Prism$1.languages[diffLanguageMatch ? "diff" : language]); 29284 if (diffLanguageMatch) { 29285 tokens = tokenizeDiffHighlight(tokens, diffLanguageMatch[1]); 29286 } 29287 return $mapTokensToLexicalStructure(tokens); 29288 } 29289 function $mapTokensToLexicalStructure(tokens, type) { 29290 const nodes = []; 29291 for (const token of tokens) { 29292 if (typeof token === "string") { 29293 const partials = token.split(/(\n|\t)/); 29294 const partialsLength = partials.length; 29295 for (let i2 = 0; i2 < partialsLength; i2++) { 29296 const part = partials[i2]; 29297 if (part === "\n" || part === "\r\n") { 29298 nodes.push($createLineBreakNode2()); 29299 } else if (part === " ") { 29300 nodes.push($createTabNode2()); 29301 } else if (part.length > 0) { 29302 nodes.push($createCodeHighlightNode2(part, type)); 29303 } 29304 } 29305 } else { 29306 const { 29307 content, 29308 alias 29309 } = token; 29310 if (typeof content === "string") { 29311 nodes.push(...$mapTokensToLexicalStructure([content], token.type === "prefix" && typeof alias === "string" ? alias : token.type)); 29312 } else if (Array.isArray(content)) { 29313 nodes.push(...$mapTokensToLexicalStructure(content, token.type === "unchanged" ? void 0 : token.type)); 29314 } 29315 } 29316 } 29317 return nodes; 29318 } 29319 var PrismTokenizer = { 29320 $tokenize(codeNode, language) { 29321 return $getHighlightNodes(codeNode, language || this.defaultLanguage); 29322 }, 29323 defaultLanguage: DEFAULT_CODE_LANGUAGE2, 29324 tokenize(code, language) { 29325 return Prism$1.tokenize(code, Prism$1.languages[language || ""] || Prism$1.languages[this.defaultLanguage]); 29326 } 29327 }; 29328 function $textNodeTransform(editor, tokenizer, transformState, node) { 29329 const parentNode = node.getParent(); 29330 if ($isCodeNode2(parentNode)) { 29331 $codeNodeTransform(editor, tokenizer, transformState, parentNode); 29332 } else if ($isCodeHighlightNode2(node)) { 29333 node.replace($createTextNode2(node.__text)); 29334 } 29335 } 29336 function updateCodeGutter(node, editor) { 29337 const codeElement = editor.getElementByKey(node.getKey()); 29338 if (codeElement === null) { 29339 return; 29340 } 29341 const children = node.getChildren(); 29342 const childrenLength = children.length; 29343 if (childrenLength === codeElement.__cachedChildrenLength) { 29344 return; 29345 } 29346 codeElement.__cachedChildrenLength = childrenLength; 29347 let gutter = "1"; 29348 let count = 1; 29349 for (let i2 = 0; i2 < childrenLength; i2++) { 29350 if ($isLineBreakNode2(children[i2])) { 29351 gutter += "\n" + ++count; 29352 } 29353 } 29354 codeElement.setAttribute("data-gutter", gutter); 29355 } 29356 function $codeNodeTransform(editor, tokenizer, transformState, node) { 29357 const { 29358 nodesCurrentlyHighlighting 29359 } = transformState; 29360 const nodeKey = node.getKey(); 29361 if (node.getLanguage() === void 0) { 29362 node.setLanguage(tokenizer.defaultLanguage); 29363 } 29364 const language = node.getLanguage() || tokenizer.defaultLanguage; 29365 if (isCodeLanguageLoaded(language)) { 29366 if (!node.getIsSyntaxHighlightSupported()) { 29367 node.setIsSyntaxHighlightSupported(true); 29368 } 29369 } else { 29370 if (node.getIsSyntaxHighlightSupported()) { 29371 node.setIsSyntaxHighlightSupported(false); 29372 } 29373 loadCodeLanguage(language, editor, nodeKey); 29374 return; 29375 } 29376 if (nodesCurrentlyHighlighting.has(nodeKey)) { 29377 return; 29378 } 29379 nodesCurrentlyHighlighting.add(nodeKey); 29380 if (!transformState.didTransform) { 29381 transformState.didTransform = true; 29382 $onUpdate2(() => { 29383 transformState.didTransform = false; 29384 nodesCurrentlyHighlighting.clear(); 29385 }); 29386 } 29387 $updateAndRetainSelection(nodeKey, () => { 29388 const currentNode = $getNodeByKey2(nodeKey); 29389 if (!$isCodeNode2(currentNode) || !currentNode.isAttached()) { 29390 return false; 29391 } 29392 const currentLanguage = currentNode.getLanguage() || tokenizer.defaultLanguage; 29393 const highlightNodes = tokenizer.$tokenize(currentNode, currentLanguage); 29394 const diffRange = getDiffRange(currentNode.getChildren(), highlightNodes); 29395 const { 29396 from, 29397 to, 29398 nodesForReplacement 29399 } = diffRange; 29400 if (from !== to || nodesForReplacement.length) { 29401 node.splice(from, to - from, nodesForReplacement); 29402 return true; 29403 } 29404 return false; 29405 }); 29406 } 29407 function $updateAndRetainSelection(nodeKey, updateFn) { 29408 const node = $getNodeByKey2(nodeKey); 29409 if (!$isCodeNode2(node) || !node.isAttached()) { 29410 return; 29411 } 29412 const selection = $getSelection2(); 29413 if (!$isRangeSelection2(selection)) { 29414 updateFn(); 29415 return; 29416 } 29417 const anchor = selection.anchor; 29418 const anchorOffset = anchor.offset; 29419 const isNewLineAnchor = anchor.type === "element" && $isLineBreakNode2(node.getChildAtIndex(anchor.offset - 1)); 29420 let textOffset = 0; 29421 if (!isNewLineAnchor) { 29422 const anchorNode = anchor.getNode(); 29423 textOffset = anchorOffset + anchorNode.getPreviousSiblings().reduce((offset3, _node) => { 29424 return offset3 + _node.getTextContentSize(); 29425 }, 0); 29426 } 29427 const hasChanges = updateFn(); 29428 if (!hasChanges) { 29429 return; 29430 } 29431 if (isNewLineAnchor) { 29432 anchor.getNode().select(anchorOffset, anchorOffset); 29433 return; 29434 } 29435 node.getChildren().some((_node) => { 29436 const isText = $isTextNode2(_node); 29437 if (isText || $isLineBreakNode2(_node)) { 29438 const textContentSize = _node.getTextContentSize(); 29439 if (isText && textContentSize >= textOffset) { 29440 _node.select(textOffset, textOffset); 29441 return true; 29442 } 29443 textOffset -= textContentSize; 29444 } 29445 return false; 29446 }); 29447 } 29448 function getDiffRange(prevNodes, nextNodes) { 29449 let leadingMatch = 0; 29450 while (leadingMatch < prevNodes.length) { 29451 if (!isEqual(prevNodes[leadingMatch], nextNodes[leadingMatch])) { 29452 break; 29453 } 29454 leadingMatch++; 29455 } 29456 const prevNodesLength = prevNodes.length; 29457 const nextNodesLength = nextNodes.length; 29458 const maxTrailingMatch = Math.min(prevNodesLength, nextNodesLength) - leadingMatch; 29459 let trailingMatch = 0; 29460 while (trailingMatch < maxTrailingMatch) { 29461 trailingMatch++; 29462 if (!isEqual(prevNodes[prevNodesLength - trailingMatch], nextNodes[nextNodesLength - trailingMatch])) { 29463 trailingMatch--; 29464 break; 29465 } 29466 } 29467 const from = leadingMatch; 29468 const to = prevNodesLength - trailingMatch; 29469 const nodesForReplacement = nextNodes.slice(leadingMatch, nextNodesLength - trailingMatch); 29470 return { 29471 from, 29472 nodesForReplacement, 29473 to 29474 }; 29475 } 29476 function isEqual(nodeA, nodeB) { 29477 return $isCodeHighlightNode2(nodeA) && $isCodeHighlightNode2(nodeB) && nodeA.__text === nodeB.__text && nodeA.__highlightType === nodeB.__highlightType || $isTabNode2(nodeA) && $isTabNode2(nodeB) || $isLineBreakNode2(nodeA) && $isLineBreakNode2(nodeB); 29478 } 29479 function $isSelectionInCode(selection) { 29480 if (!$isRangeSelection2(selection)) { 29481 return false; 29482 } 29483 const anchorNode = selection.anchor.getNode(); 29484 const maybeAnchorCodeNode = $isCodeNode2(anchorNode) ? anchorNode : anchorNode.getParent(); 29485 const focusNode = selection.focus.getNode(); 29486 const maybeFocusCodeNode = $isCodeNode2(focusNode) ? focusNode : focusNode.getParent(); 29487 return $isCodeNode2(maybeAnchorCodeNode) && maybeAnchorCodeNode.is(maybeFocusCodeNode); 29488 } 29489 function $getCodeLines(selection) { 29490 const nodes = selection.getNodes(); 29491 const lines = []; 29492 if (nodes.length === 1 && $isCodeNode2(nodes[0])) { 29493 return lines; 29494 } 29495 let lastLine = []; 29496 for (let i2 = 0; i2 < nodes.length; i2++) { 29497 const node = nodes[i2]; 29498 if (!($isCodeHighlightNode2(node) || $isTabNode2(node) || $isLineBreakNode2(node))) { 29499 formatDevErrorMessage10(`Expected selection to be inside CodeBlock and consisting of CodeHighlightNode, TabNode and LineBreakNode`); 29500 } 29501 if ($isLineBreakNode2(node)) { 29502 if (lastLine.length > 0) { 29503 lines.push(lastLine); 29504 lastLine = []; 29505 } 29506 } else { 29507 lastLine.push(node); 29508 } 29509 } 29510 if (lastLine.length > 0) { 29511 const selectionEnd = selection.isBackward() ? selection.anchor : selection.focus; 29512 const lastPoint = $createPoint2(lastLine[0].getKey(), 0, "text"); 29513 if (!selectionEnd.is(lastPoint)) { 29514 lines.push(lastLine); 29515 } 29516 } 29517 return lines; 29518 } 29519 function $handleTab(shiftKey) { 29520 const selection = $getSelection2(); 29521 if (!$isRangeSelection2(selection) || !$isSelectionInCode(selection)) { 29522 return null; 29523 } 29524 const indentOrOutdent = !shiftKey ? INDENT_CONTENT_COMMAND2 : OUTDENT_CONTENT_COMMAND2; 29525 const tabOrOutdent = !shiftKey ? INSERT_TAB_COMMAND2 : OUTDENT_CONTENT_COMMAND2; 29526 const anchor = selection.anchor; 29527 const focus = selection.focus; 29528 if (anchor.is(focus)) { 29529 return tabOrOutdent; 29530 } 29531 const codeLines = $getCodeLines(selection); 29532 if (codeLines.length !== 1) { 29533 return indentOrOutdent; 29534 } 29535 const codeLine = codeLines[0]; 29536 const codeLineLength = codeLine.length; 29537 if (!(codeLineLength !== 0)) { 29538 formatDevErrorMessage10(`$getCodeLines only extracts non-empty lines`); 29539 } 29540 let selectionFirst; 29541 let selectionLast; 29542 if (selection.isBackward()) { 29543 selectionFirst = focus; 29544 selectionLast = anchor; 29545 } else { 29546 selectionFirst = anchor; 29547 selectionLast = focus; 29548 } 29549 const firstOfLine = $getFirstCodeNodeOfLine2(codeLine[0]); 29550 const lastOfLine = $getLastCodeNodeOfLine2(codeLine[0]); 29551 const anchorOfLine = $createPoint2(firstOfLine.getKey(), 0, "text"); 29552 const focusOfLine = $createPoint2(lastOfLine.getKey(), lastOfLine.getTextContentSize(), "text"); 29553 if (selectionFirst.isBefore(anchorOfLine)) { 29554 return indentOrOutdent; 29555 } 29556 if (focusOfLine.isBefore(selectionLast)) { 29557 return indentOrOutdent; 29558 } 29559 if (anchorOfLine.isBefore(selectionFirst) || selectionLast.isBefore(focusOfLine)) { 29560 return tabOrOutdent; 29561 } 29562 return indentOrOutdent; 29563 } 29564 function $handleMultilineIndent(type) { 29565 const selection = $getSelection2(); 29566 if (!$isRangeSelection2(selection) || !$isSelectionInCode(selection)) { 29567 return false; 29568 } 29569 const codeLines = $getCodeLines(selection); 29570 const codeLinesLength = codeLines.length; 29571 if (codeLinesLength === 0 && selection.isCollapsed()) { 29572 if (type === INDENT_CONTENT_COMMAND2) { 29573 selection.insertNodes([$createTabNode2()]); 29574 } 29575 return true; 29576 } 29577 if (codeLinesLength === 0 && type === INDENT_CONTENT_COMMAND2 && selection.getTextContent() === "\n") { 29578 const tabNode = $createTabNode2(); 29579 const lineBreakNode = $createLineBreakNode2(); 29580 const direction = selection.isBackward() ? "previous" : "next"; 29581 selection.insertNodes([tabNode, lineBreakNode]); 29582 $setSelectionFromCaretRange2($getCaretRangeInDirection2($getCaretRange2($getTextPointCaret2(tabNode, "next", 0), $normalizeCaret2($getSiblingCaret2(lineBreakNode, "next"))), direction)); 29583 return true; 29584 } 29585 for (let i2 = 0; i2 < codeLinesLength; i2++) { 29586 const line = codeLines[i2]; 29587 if (line.length > 0) { 29588 let firstOfLine = line[0]; 29589 if (i2 === 0) { 29590 firstOfLine = $getFirstCodeNodeOfLine2(firstOfLine); 29591 } 29592 if (type === INDENT_CONTENT_COMMAND2) { 29593 const tabNode = $createTabNode2(); 29594 firstOfLine.insertBefore(tabNode); 29595 if (i2 === 0) { 29596 const anchorKey = selection.isBackward() ? "focus" : "anchor"; 29597 const anchorLine = $createPoint2(firstOfLine.getKey(), 0, "text"); 29598 if (selection[anchorKey].is(anchorLine)) { 29599 selection[anchorKey].set(tabNode.getKey(), 0, "text"); 29600 } 29601 } 29602 } else if ($isTabNode2(firstOfLine)) { 29603 firstOfLine.remove(); 29604 } 29605 } 29606 } 29607 return true; 29608 } 29609 function $handleShiftLines(type, event) { 29610 const selection = $getSelection2(); 29611 if (!$isRangeSelection2(selection)) { 29612 return false; 29613 } 29614 const { 29615 anchor, 29616 focus 29617 } = selection; 29618 const anchorOffset = anchor.offset; 29619 const focusOffset = focus.offset; 29620 const anchorNode = anchor.getNode(); 29621 const focusNode = focus.getNode(); 29622 const arrowIsUp = type === KEY_ARROW_UP_COMMAND2; 29623 if (!$isSelectionInCode(selection) || !($isCodeHighlightNode2(anchorNode) || $isTabNode2(anchorNode)) || !($isCodeHighlightNode2(focusNode) || $isTabNode2(focusNode))) { 29624 return false; 29625 } 29626 if (!event.altKey) { 29627 if (selection.isCollapsed()) { 29628 const codeNode = anchorNode.getParentOrThrow(); 29629 if (arrowIsUp && anchorOffset === 0 && anchorNode.getPreviousSibling() === null) { 29630 const codeNodeSibling = codeNode.getPreviousSibling(); 29631 if (codeNodeSibling === null) { 29632 codeNode.selectPrevious(); 29633 event.preventDefault(); 29634 return true; 29635 } 29636 } else if (!arrowIsUp && anchorOffset === anchorNode.getTextContentSize() && anchorNode.getNextSibling() === null) { 29637 const codeNodeSibling = codeNode.getNextSibling(); 29638 if (codeNodeSibling === null) { 29639 codeNode.selectNext(); 29640 event.preventDefault(); 29641 return true; 29642 } 29643 } 29644 } 29645 return false; 29646 } 29647 let start3; 29648 let end; 29649 if (anchorNode.isBefore(focusNode)) { 29650 start3 = $getFirstCodeNodeOfLine2(anchorNode); 29651 end = $getLastCodeNodeOfLine2(focusNode); 29652 } else { 29653 start3 = $getFirstCodeNodeOfLine2(focusNode); 29654 end = $getLastCodeNodeOfLine2(anchorNode); 29655 } 29656 if (start3 == null || end == null) { 29657 return false; 29658 } 29659 const range2 = start3.getNodesBetween(end); 29660 for (let i2 = 0; i2 < range2.length; i2++) { 29661 const node = range2[i2]; 29662 if (!$isCodeHighlightNode2(node) && !$isTabNode2(node) && !$isLineBreakNode2(node)) { 29663 return false; 29664 } 29665 } 29666 event.preventDefault(); 29667 event.stopPropagation(); 29668 const linebreak = arrowIsUp ? start3.getPreviousSibling() : end.getNextSibling(); 29669 if (!$isLineBreakNode2(linebreak)) { 29670 return true; 29671 } 29672 const sibling = arrowIsUp ? linebreak.getPreviousSibling() : linebreak.getNextSibling(); 29673 if (sibling == null) { 29674 return true; 29675 } 29676 const maybeInsertionPoint = $isCodeHighlightNode2(sibling) || $isTabNode2(sibling) || $isLineBreakNode2(sibling) ? arrowIsUp ? $getFirstCodeNodeOfLine2(sibling) : $getLastCodeNodeOfLine2(sibling) : null; 29677 let insertionPoint = maybeInsertionPoint != null ? maybeInsertionPoint : sibling; 29678 linebreak.remove(); 29679 range2.forEach((node) => node.remove()); 29680 if (type === KEY_ARROW_UP_COMMAND2) { 29681 range2.forEach((node) => insertionPoint.insertBefore(node)); 29682 insertionPoint.insertBefore(linebreak); 29683 } else { 29684 insertionPoint.insertAfter(linebreak); 29685 insertionPoint = linebreak; 29686 range2.forEach((node) => { 29687 insertionPoint.insertAfter(node); 29688 insertionPoint = node; 29689 }); 29690 } 29691 selection.setTextNodeRange(anchorNode, anchorOffset, focusNode, focusOffset); 29692 return true; 29693 } 29694 function $handleMoveTo(type, event) { 29695 const selection = $getSelection2(); 29696 if (!$isRangeSelection2(selection)) { 29697 return false; 29698 } 29699 const { 29700 anchor, 29701 focus 29702 } = selection; 29703 const anchorNode = anchor.getNode(); 29704 const focusNode = focus.getNode(); 29705 const isMoveToStart2 = type === MOVE_TO_START2; 29706 if (!$isSelectionInCode(selection) || !($isCodeHighlightNode2(anchorNode) || $isTabNode2(anchorNode)) || !($isCodeHighlightNode2(focusNode) || $isTabNode2(focusNode))) { 29707 return false; 29708 } 29709 const focusLineNode = focusNode; 29710 const direction = $getCodeLineDirection2(focusLineNode); 29711 const moveToStart = direction === "rtl" ? !isMoveToStart2 : isMoveToStart2; 29712 if (moveToStart) { 29713 const start3 = $getStartOfCodeInLine2(focusLineNode, focus.offset); 29714 if (start3 !== null) { 29715 const { 29716 node, 29717 offset: offset3 29718 } = start3; 29719 if ($isLineBreakNode2(node)) { 29720 node.selectNext(0, 0); 29721 } else { 29722 selection.setTextNodeRange(node, offset3, node, offset3); 29723 } 29724 } else { 29725 focusLineNode.getParentOrThrow().selectStart(); 29726 } 29727 } else { 29728 const node = $getEndOfCodeInLine2(focusLineNode); 29729 node.select(); 29730 } 29731 event.preventDefault(); 29732 event.stopPropagation(); 29733 return true; 29734 } 29735 function registerCodeHighlighting(editor, tokenizer) { 29736 if (!editor.hasNodes([CodeNode2, CodeHighlightNode2])) { 29737 throw new Error("CodeHighlightPlugin: CodeNode or CodeHighlightNode not registered on editor"); 29738 } 29739 if (tokenizer == null) { 29740 tokenizer = PrismTokenizer; 29741 } 29742 const registrations = []; 29743 if (editor._headless !== true) { 29744 registrations.push(editor.registerMutationListener(CodeNode2, (mutations) => { 29745 editor.getEditorState().read(() => { 29746 for (const [key, type] of mutations) { 29747 if (type !== "destroyed") { 29748 const node = $getNodeByKey2(key); 29749 if (node !== null) { 29750 updateCodeGutter(node, editor); 29751 } 29752 } 29753 } 29754 }); 29755 }, { 29756 skipInitialization: false 29757 })); 29758 } 29759 const transformState = { 29760 didTransform: false, 29761 nodesCurrentlyHighlighting: /* @__PURE__ */ new Set() 29762 }; 29763 registrations.push(editor.registerNodeTransform(CodeNode2, $codeNodeTransform.bind(null, editor, tokenizer, transformState)), editor.registerNodeTransform(TextNode2, $textNodeTransform.bind(null, editor, tokenizer, transformState)), editor.registerNodeTransform(CodeHighlightNode2, $textNodeTransform.bind(null, editor, tokenizer, transformState)), editor.registerCommand(KEY_TAB_COMMAND2, (event) => { 29764 const command = $handleTab(event.shiftKey); 29765 if (command === null) { 29766 return false; 29767 } 29768 event.preventDefault(); 29769 editor.dispatchCommand(command, void 0); 29770 return true; 29771 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(INSERT_TAB_COMMAND2, () => { 29772 const selection = $getSelection2(); 29773 if (!$isSelectionInCode(selection)) { 29774 return false; 29775 } 29776 $insertNodes2([$createTabNode2()]); 29777 return true; 29778 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(INDENT_CONTENT_COMMAND2, (payload) => $handleMultilineIndent(INDENT_CONTENT_COMMAND2), COMMAND_PRIORITY_LOW2), editor.registerCommand(OUTDENT_CONTENT_COMMAND2, (payload) => $handleMultilineIndent(OUTDENT_CONTENT_COMMAND2), COMMAND_PRIORITY_LOW2), editor.registerCommand(KEY_ARROW_UP_COMMAND2, (event) => { 29779 const selection = $getSelection2(); 29780 if (!$isRangeSelection2(selection) || !$isSelectionInCode(selection)) { 29781 return false; 29782 } 29783 const firstNode = $getRoot2().getFirstDescendant(); 29784 const { 29785 anchor 29786 } = selection; 29787 const anchorNode = anchor.getNode(); 29788 if (firstNode && anchorNode && firstNode.getKey() === anchorNode.getKey()) { 29789 return false; 29790 } 29791 return $handleShiftLines(KEY_ARROW_UP_COMMAND2, event); 29792 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(KEY_ARROW_DOWN_COMMAND2, (event) => { 29793 const selection = $getSelection2(); 29794 if (!$isRangeSelection2(selection) || !$isSelectionInCode(selection)) { 29795 return false; 29796 } 29797 const lastNode = $getRoot2().getLastDescendant(); 29798 const { 29799 anchor 29800 } = selection; 29801 const anchorNode = anchor.getNode(); 29802 if (lastNode && anchorNode && lastNode.getKey() === anchorNode.getKey()) { 29803 return false; 29804 } 29805 return $handleShiftLines(KEY_ARROW_DOWN_COMMAND2, event); 29806 }, COMMAND_PRIORITY_LOW2), editor.registerCommand(MOVE_TO_START2, (event) => $handleMoveTo(MOVE_TO_START2, event), COMMAND_PRIORITY_LOW2), editor.registerCommand(MOVE_TO_END2, (event) => $handleMoveTo(MOVE_TO_END2, event), COMMAND_PRIORITY_LOW2)); 29807 return mergeRegister2(...registrations); 29808 } 29809 var CodePrismExtension = defineExtension2({ 29810 build: (editor, config) => namedSignals2(config), 29811 config: safeCast2({ 29812 disabled: false, 29813 tokenizer: PrismTokenizer 29814 }), 29815 dependencies: [CodeExtension2], 29816 name: "@lexical/code-prism", 29817 register: (editor, config, state) => { 29818 const stores = state.getOutput(); 29819 return effect(() => { 29820 if (stores.disabled.value) { 29821 return; 29822 } 29823 return registerCodeHighlighting(editor, stores.tokenizer.value); 29824 }); 29825 } 29826 }); 29827 29828
vendor: 15,907 bytes, lines 29828-30122
29828// node_modules/@lexical/code-prism/LexicalCodePrism.prod.mjs 29829 var import_prismjs3 = __toESM(require_prism(), 1); 29830 function J(e2, ...t2) { 29831 const n2 = new URL("https://lexical.dev/docs/error"), r2 = new URLSearchParams(); 29832 r2.append("code", e2); 29833 for (const e3 of t2) r2.append("v", e3); 29834 throw n2.search = r2.toString(), Error(`Minified Lexical error #${e2}; visit ${n2.toString()} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`); 29835 } 29836 !function(e2) { 29837 e2.languages.diff = { coord: [/^(?:\*{3}|-{3}|\+{3}).*$/m, /^@@.*@@$/m, /^\d.*$/m] }; 29838 var t2 = { "deleted-sign": "-", "deleted-arrow": "<", "inserted-sign": "+", "inserted-arrow": ">", unchanged: " ", diff: "!" }; 29839 Object.keys(t2).forEach(function(n2) { 29840 var r2 = t2[n2], o2 = []; 29841 /^\w+$/.test(n2) || o2.push(/\w+/.exec(n2)[0]), "diff" === n2 && o2.push("bold"), e2.languages.diff[n2] = { pattern: RegExp("^(?:[" + r2 + "].*(?:\r\n?|\n|(?![\\s\\S])))+", "m"), alias: o2, inside: { line: { pattern: /(.)(?=[\s\S]).*(?:\r\n?|\n)?/, lookbehind: true }, prefix: { pattern: /[\s\S]/, alias: /\w+/.exec(n2)[0] } } }; 29842 }), Object.defineProperty(e2.languages.diff, "PREFIXES", { value: t2 }); 29843 }(Prism); 29844 var U = globalThis.Prism || window.Prism; 29845 function te(e2) { 29846 const t2 = function(e3) { 29847 const t3 = /^diff-([\w-]+)/i.exec(e3); 29848 return t3 ? t3[1] : null; 29849 }(e2), n2 = t2 || e2; 29850 try { 29851 return !!n2 && U.languages.hasOwnProperty(n2); 29852 } catch (e3) { 29853 return false; 29854 } 29855 } 29856 async function ne(e2, t2, n2) { 29857 } 29858 function re(e2) { 29859 return "string" == typeof e2 ? e2 : Array.isArray(e2) ? e2.map(re).join("") : re(e2.content); 29860 } 29861 function oe(e2, t2) { 29862 const n2 = /^diff-([\w-]+)/i.exec(t2), r2 = e2.getTextContent(); 29863 let o2 = U.tokenize(r2, U.languages[n2 ? "diff" : t2]); 29864 return n2 && (o2 = function(e3, t3) { 29865 const n3 = t3, r3 = U.languages[n3], o3 = { tokens: e3 }, s2 = U.languages.diff.PREFIXES; 29866 for (const e4 of o3.tokens) { 29867 if ("string" == typeof e4 || !(e4.type in s2) || !Array.isArray(e4.content)) continue; 29868 const t4 = e4.type; 29869 let n4 = 0; 29870 const o4 = () => (n4++, new U.Token("prefix", s2[t4], t4.replace(/^(\w+).*/, "$1"))), i2 = e4.content.filter((e5) => "string" == typeof e5 || "prefix" !== e5.type), c2 = e4.content.length - i2.length, l4 = U.tokenize(re(i2), r3); 29871 l4.unshift(o4()); 29872 const a2 = /\r\n|\n/g, f = (e5) => { 29873 const t5 = []; 29874 a2.lastIndex = 0; 29875 let r4, s3 = 0; 29876 for (; n4 < c2 && (r4 = a2.exec(e5)); ) { 29877 const n5 = r4.index + r4[0].length; 29878 t5.push(e5.slice(s3, n5)), s3 = n5, t5.push(o4()); 29879 } 29880 if (0 !== t5.length) return s3 < e5.length && t5.push(e5.slice(s3)), t5; 29881 }, u2 = (e5) => { 29882 for (let t5 = 0; t5 < e5.length && n4 < c2; t5++) { 29883 const n5 = e5[t5]; 29884 if ("string" == typeof n5) { 29885 const r4 = f(n5); 29886 r4 && (e5.splice(t5, 1, ...r4), t5 += r4.length - 1); 29887 } else if ("string" == typeof n5.content) { 29888 const e6 = f(n5.content); 29889 e6 && (n5.content = e6); 29890 } else Array.isArray(n5.content) ? u2(n5.content) : u2([n5.content]); 29891 } 29892 }; 29893 u2(l4), n4 < c2 && l4.push(o4()), e4.content = l4; 29894 } 29895 return o3.tokens; 29896 }(o2, n2[1])), se(o2); 29897 } 29898 function se(t2, n2) { 29899 const r2 = []; 29900 for (const o2 of t2) if ("string" == typeof o2) { 29901 const t3 = o2.split(/(\n|\t)/), s2 = t3.length; 29902 for (let o3 = 0; o3 < s2; o3++) { 29903 const s3 = t3[o3]; 29904 "\n" === s3 || "\r\n" === s3 ? r2.push($createLineBreakNode2()) : " " === s3 ? r2.push($createTabNode2()) : s3.length > 0 && r2.push($createCodeHighlightNode2(s3, n2)); 29905 } 29906 } else { 29907 const { content: e2, alias: t3 } = o2; 29908 "string" == typeof e2 ? r2.push(...se([e2], "prefix" === o2.type && "string" == typeof t3 ? t3 : o2.type)) : Array.isArray(e2) && r2.push(...se(e2, "unchanged" === o2.type ? void 0 : o2.type)); 29909 } 29910 return r2; 29911 } 29912 var ie = { $tokenize(e2, t2) { 29913 return oe(e2, t2 || this.defaultLanguage); 29914 }, defaultLanguage: DEFAULT_CODE_LANGUAGE2, tokenize(e2, t2) { 29915 return U.tokenize(e2, U.languages[t2 || ""] || U.languages[this.defaultLanguage]); 29916 } }; 29917 function ce(e2, t2, o2, s2) { 29918 const i2 = s2.getParent(); 29919 $isCodeNode2(i2) ? ae(e2, t2, o2, i2) : $isCodeHighlightNode2(s2) && s2.replace($createTextNode2(s2.__text)); 29920 } 29921 function le(e2, t2) { 29922 const n2 = t2.getElementByKey(e2.getKey()); 29923 if (null === n2) return; 29924 const r2 = e2.getChildren(), o2 = r2.length; 29925 if (o2 === n2.__cachedChildrenLength) return; 29926 n2.__cachedChildrenLength = o2; 29927 let s2 = "1", i2 = 1; 29928 for (let e3 = 0; e3 < o2; e3++) $isLineBreakNode2(r2[e3]) && (s2 += "\n" + ++i2); 29929 n2.setAttribute("data-gutter", s2); 29930 } 29931 function ae(e2, t2, r2, o2) { 29932 const { nodesCurrentlyHighlighting: s2 } = r2, i2 = o2.getKey(); 29933 void 0 === o2.getLanguage() && o2.setLanguage(t2.defaultLanguage); 29934 const c2 = o2.getLanguage() || t2.defaultLanguage; 29935 if (!te(c2)) return o2.getIsSyntaxHighlightSupported() && o2.setIsSyntaxHighlightSupported(false), void ne(); 29936 o2.getIsSyntaxHighlightSupported() || o2.setIsSyntaxHighlightSupported(true), s2.has(i2) || (s2.add(i2), r2.didTransform || (r2.didTransform = true, $onUpdate2(() => { 29937 r2.didTransform = false, s2.clear(); 29938 })), function(e3, t3) { 29939 const r3 = $getNodeByKey2(e3); 29940 if (!$isCodeNode2(r3) || !r3.isAttached()) return; 29941 const o3 = $getSelection2(); 29942 if (!$isRangeSelection2(o3)) return void t3(); 29943 const s3 = o3.anchor, i3 = s3.offset, c3 = "element" === s3.type && $isLineBreakNode2(r3.getChildAtIndex(s3.offset - 1)); 29944 let l4 = 0; 29945 if (!c3) { 29946 const e4 = s3.getNode(); 29947 l4 = i3 + e4.getPreviousSiblings().reduce((e5, t4) => e5 + t4.getTextContentSize(), 0); 29948 } 29949 if (!t3()) return; 29950 if (c3) return void s3.getNode().select(i3, i3); 29951 r3.getChildren().some((e4) => { 29952 const t4 = $isTextNode2(e4); 29953 if (t4 || $isLineBreakNode2(e4)) { 29954 const n2 = e4.getTextContentSize(); 29955 if (t4 && n2 >= l4) return e4.select(l4, l4), true; 29956 l4 -= n2; 29957 } 29958 return false; 29959 }); 29960 }(i2, () => { 29961 const e3 = $getNodeByKey2(i2); 29962 if (!$isCodeNode2(e3) || !e3.isAttached()) return false; 29963 const r3 = e3.getLanguage() || t2.defaultLanguage, s3 = t2.$tokenize(e3, r3), c3 = function(e4, t3) { 29964 let n2 = 0; 29965 for (; n2 < e4.length && fe(e4[n2], t3[n2]); ) n2++; 29966 const r4 = e4.length, o3 = t3.length, s4 = Math.min(r4, o3) - n2; 29967 let i3 = 0; 29968 for (; i3 < s4; ) if (i3++, !fe(e4[r4 - i3], t3[o3 - i3])) { 29969 i3--; 29970 break; 29971 } 29972 const c4 = n2, l5 = r4 - i3, a3 = t3.slice(n2, o3 - i3); 29973 return { from: c4, nodesForReplacement: a3, to: l5 }; 29974 }(e3.getChildren(), s3), { from: l4, to: a2, nodesForReplacement: f } = c3; 29975 return !(l4 === a2 && !f.length) && (o2.splice(l4, a2 - l4, f), true); 29976 })); 29977 } 29978 function fe(e2, t2) { 29979 return $isCodeHighlightNode2(e2) && $isCodeHighlightNode2(t2) && e2.__text === t2.__text && e2.__highlightType === t2.__highlightType || $isTabNode2(e2) && $isTabNode2(t2) || $isLineBreakNode2(e2) && $isLineBreakNode2(t2); 29980 } 29981 function ue(e2) { 29982 if (!$isRangeSelection2(e2)) return false; 29983 const t2 = e2.anchor.getNode(), r2 = $isCodeNode2(t2) ? t2 : t2.getParent(), o2 = e2.focus.getNode(), s2 = $isCodeNode2(o2) ? o2 : o2.getParent(); 29984 return $isCodeNode2(r2) && r2.is(s2); 29985 } 29986 function ge(e2) { 29987 const t2 = e2.getNodes(), o2 = []; 29988 if (1 === t2.length && $isCodeNode2(t2[0])) return o2; 29989 let s2 = []; 29990 for (let e3 = 0; e3 < t2.length; e3++) { 29991 const n2 = t2[e3]; 29992 $isCodeHighlightNode2(n2) || $isTabNode2(n2) || $isLineBreakNode2(n2) || J(169), $isLineBreakNode2(n2) ? s2.length > 0 && (o2.push(s2), s2 = []) : s2.push(n2); 29993 } 29994 if (s2.length > 0) { 29995 const t3 = e2.isBackward() ? e2.anchor : e2.focus, n2 = $createPoint2(s2[0].getKey(), 0, "text"); 29996 t3.is(n2) || o2.push(s2); 29997 } 29998 return o2; 29999 } 30000 function pe(e2) { 30001 const t2 = $getSelection2(); 30002 if (!$isRangeSelection2(t2) || !ue(t2)) return false; 30003 const n2 = ge(t2), r2 = n2.length; 30004 if (0 === r2 && t2.isCollapsed()) return e2 === INDENT_CONTENT_COMMAND2 && t2.insertNodes([$createTabNode2()]), true; 30005 if (0 === r2 && e2 === INDENT_CONTENT_COMMAND2 && "\n" === t2.getTextContent()) { 30006 const e3 = $createTabNode2(), n3 = $createLineBreakNode2(), r3 = t2.isBackward() ? "previous" : "next"; 30007 return t2.insertNodes([e3, n3]), $setSelectionFromCaretRange2($getCaretRangeInDirection2($getCaretRange2($getTextPointCaret2(e3, "next", 0), $normalizeCaret2($getSiblingCaret2(n3, "next"))), r3)), true; 30008 } 30009 for (let s2 = 0; s2 < r2; s2++) { 30010 const r3 = n2[s2]; 30011 if (r3.length > 0) { 30012 let n3 = r3[0]; 30013 if (0 === s2 && (n3 = $getFirstCodeNodeOfLine2(n3)), e2 === INDENT_CONTENT_COMMAND2) { 30014 const e3 = $createTabNode2(); 30015 if (n3.insertBefore(e3), 0 === s2) { 30016 const r4 = t2.isBackward() ? "focus" : "anchor", o2 = $createPoint2(n3.getKey(), 0, "text"); 30017 t2[r4].is(o2) && t2[r4].set(e3.getKey(), 0, "text"); 30018 } 30019 } else $isTabNode2(n3) && n3.remove(); 30020 } 30021 } 30022 return true; 30023 } 30024 function de(e2, t2) { 30025 const n2 = $getSelection2(); 30026 if (!$isRangeSelection2(n2)) return false; 30027 const { anchor: i2, focus: c2 } = n2, l4 = i2.offset, a2 = c2.offset, f = i2.getNode(), u2 = c2.getNode(), g2 = e2 === KEY_ARROW_UP_COMMAND2; 30028 if (!ue(n2) || !$isCodeHighlightNode2(f) && !$isTabNode2(f) || !$isCodeHighlightNode2(u2) && !$isTabNode2(u2)) return false; 30029 if (!t2.altKey) { 30030 if (n2.isCollapsed()) { 30031 const e3 = f.getParentOrThrow(); 30032 if (g2 && 0 === l4 && null === f.getPreviousSibling()) { 30033 if (null === e3.getPreviousSibling()) return e3.selectPrevious(), t2.preventDefault(), true; 30034 } else if (!g2 && l4 === f.getTextContentSize() && null === f.getNextSibling()) { 30035 if (null === e3.getNextSibling()) return e3.selectNext(), t2.preventDefault(), true; 30036 } 30037 } 30038 return false; 30039 } 30040 let p2, d3; 30041 if (f.isBefore(u2) ? (p2 = $getFirstCodeNodeOfLine2(f), d3 = $getLastCodeNodeOfLine2(u2)) : (p2 = $getFirstCodeNodeOfLine2(u2), d3 = $getLastCodeNodeOfLine2(f)), null == p2 || null == d3) return false; 30042 const m3 = p2.getNodesBetween(d3); 30043 for (let e3 = 0; e3 < m3.length; e3++) { 30044 const t3 = m3[e3]; 30045 if (!$isCodeHighlightNode2(t3) && !$isTabNode2(t3) && !$isLineBreakNode2(t3)) return false; 30046 } 30047 t2.preventDefault(), t2.stopPropagation(); 30048 const h2 = g2 ? p2.getPreviousSibling() : d3.getNextSibling(); 30049 if (!$isLineBreakNode2(h2)) return true; 30050 const x3 = g2 ? h2.getPreviousSibling() : h2.getNextSibling(); 30051 if (null == x3) return true; 30052 const j3 = $isCodeHighlightNode2(x3) || $isTabNode2(x3) || $isLineBreakNode2(x3) ? g2 ? $getFirstCodeNodeOfLine2(x3) : $getLastCodeNodeOfLine2(x3) : null; 30053 let w3 = null != j3 ? j3 : x3; 30054 return h2.remove(), m3.forEach((e3) => e3.remove()), e2 === KEY_ARROW_UP_COMMAND2 ? (m3.forEach((e3) => w3.insertBefore(e3)), w3.insertBefore(h2)) : (w3.insertAfter(h2), w3 = h2, m3.forEach((e3) => { 30055 w3.insertAfter(e3), w3 = e3; 30056 })), n2.setTextNodeRange(f, l4, u2, a2), true; 30057 } 30058 function me(e2, t2) { 30059 const n2 = $getSelection2(); 30060 if (!$isRangeSelection2(n2)) return false; 30061 const { anchor: o2, focus: s2 } = n2, a2 = o2.getNode(), f = s2.getNode(), u2 = e2 === MOVE_TO_START2; 30062 if (!ue(n2) || !$isCodeHighlightNode2(a2) && !$isTabNode2(a2) || !$isCodeHighlightNode2(f) && !$isTabNode2(f)) return false; 30063 const g2 = f; 30064 if ("rtl" === $getCodeLineDirection2(g2) ? !u2 : u2) { 30065 const e3 = $getStartOfCodeInLine2(g2, s2.offset); 30066 if (null !== e3) { 30067 const { node: t3, offset: r2 } = e3; 30068 $isLineBreakNode2(t3) ? t3.selectNext(0, 0) : n2.setTextNodeRange(t3, r2, t3, r2); 30069 } else g2.getParentOrThrow().selectStart(); 30070 } else { 30071 $getEndOfCodeInLine2(g2).select(); 30072 } 30073 return t2.preventDefault(), t2.stopPropagation(), true; 30074 } 30075 function he(e2, t2) { 30076 if (!e2.hasNodes([CodeNode2, CodeHighlightNode2])) throw new Error("CodeHighlightPlugin: CodeNode or CodeHighlightNode not registered on editor"); 30077 null == t2 && (t2 = ie); 30078 const n2 = []; 30079 true !== e2._headless && n2.push(e2.registerMutationListener(CodeNode2, (t3) => { 30080 e2.getEditorState().read(() => { 30081 for (const [n3, r3] of t3) if ("destroyed" !== r3) { 30082 const t4 = $getNodeByKey2(n3); 30083 null !== t4 && le(t4, e2); 30084 } 30085 }); 30086 }, { skipInitialization: false })); 30087 const r2 = { didTransform: false, nodesCurrentlyHighlighting: /* @__PURE__ */ new Set() }; 30088 return n2.push(e2.registerNodeTransform(CodeNode2, ae.bind(null, e2, t2, r2)), e2.registerNodeTransform(TextNode2, ce.bind(null, e2, t2, r2)), e2.registerNodeTransform(CodeHighlightNode2, ce.bind(null, e2, t2, r2)), e2.registerCommand(KEY_TAB_COMMAND2, (t3) => { 30089 const n3 = function(e3) { 30090 const t4 = $getSelection2(); 30091 if (!$isRangeSelection2(t4) || !ue(t4)) return null; 30092 const n4 = e3 ? OUTDENT_CONTENT_COMMAND2 : INDENT_CONTENT_COMMAND2, r3 = e3 ? OUTDENT_CONTENT_COMMAND2 : INSERT_TAB_COMMAND2, i2 = t4.anchor, c2 = t4.focus; 30093 if (i2.is(c2)) return r3; 30094 const l4 = ge(t4); 30095 if (1 !== l4.length) return n4; 30096 const a2 = l4[0]; 30097 let f, u2; 30098 0 === a2.length && J(285), t4.isBackward() ? (f = c2, u2 = i2) : (f = i2, u2 = c2); 30099 const g2 = $getFirstCodeNodeOfLine2(a2[0]), p2 = $getLastCodeNodeOfLine2(a2[0]), d3 = $createPoint2(g2.getKey(), 0, "text"), m3 = $createPoint2(p2.getKey(), p2.getTextContentSize(), "text"); 30100 return f.isBefore(d3) || m3.isBefore(u2) ? n4 : d3.isBefore(f) || u2.isBefore(m3) ? r3 : n4; 30101 }(t3.shiftKey); 30102 return null !== n3 && (t3.preventDefault(), e2.dispatchCommand(n3, void 0), true); 30103 }, COMMAND_PRIORITY_LOW2), e2.registerCommand(INSERT_TAB_COMMAND2, () => !!ue($getSelection2()) && ($insertNodes2([$createTabNode2()]), true), COMMAND_PRIORITY_LOW2), e2.registerCommand(INDENT_CONTENT_COMMAND2, (e3) => pe(INDENT_CONTENT_COMMAND2), COMMAND_PRIORITY_LOW2), e2.registerCommand(OUTDENT_CONTENT_COMMAND2, (e3) => pe(OUTDENT_CONTENT_COMMAND2), COMMAND_PRIORITY_LOW2), e2.registerCommand(KEY_ARROW_UP_COMMAND2, (e3) => { 30104 const t3 = $getSelection2(); 30105 if (!$isRangeSelection2(t3) || !ue(t3)) return false; 30106 const n3 = $getRoot2().getFirstDescendant(), { anchor: r3 } = t3, o2 = r3.getNode(); 30107 return (!n3 || !o2 || n3.getKey() !== o2.getKey()) && de(KEY_ARROW_UP_COMMAND2, e3); 30108 }, COMMAND_PRIORITY_LOW2), e2.registerCommand(KEY_ARROW_DOWN_COMMAND2, (e3) => { 30109 const t3 = $getSelection2(); 30110 if (!$isRangeSelection2(t3) || !ue(t3)) return false; 30111 const n3 = $getRoot2().getLastDescendant(), { anchor: r3 } = t3, o2 = r3.getNode(); 30112 return (!n3 || !o2 || n3.getKey() !== o2.getKey()) && de(KEY_ARROW_DOWN_COMMAND2, e3); 30113 }, COMMAND_PRIORITY_LOW2), e2.registerCommand(MOVE_TO_START2, (e3) => me(MOVE_TO_START2, e3), COMMAND_PRIORITY_LOW2), e2.registerCommand(MOVE_TO_END2, (e3) => me(MOVE_TO_END2, e3), COMMAND_PRIORITY_LOW2)), mergeRegister2(...n2); 30114 } 30115 var ye = defineExtension2({ build: (e2, t2) => namedSignals2(t2), config: safeCast2({ disabled: false, tokenizer: ie }), dependencies: [CodeExtension2], name: "@lexical/code-prism", register: (e2, t2, n2) => { 30116 const r2 = n2.getOutput(); 30117 return effect(() => { 30118 if (!r2.disabled.value) return he(e2, r2.tokenizer.value); 30119 }); 30120 } }); 30121 30122
vendor: 841 bytes, lines 30122-30137
30122// node_modules/@lexical/code-prism/LexicalCodePrism.mjs 30123 var mod14 = true ? LexicalCodePrism_dev_exports : LexicalCodePrism_prod_exports; 30124 var CODE_LANGUAGE_FRIENDLY_NAME_MAP2 = mod14.CODE_LANGUAGE_FRIENDLY_NAME_MAP; 30125 var CODE_LANGUAGE_MAP2 = mod14.CODE_LANGUAGE_MAP; 30126 var CodePrismExtension2 = mod14.CodePrismExtension; 30127 var PrismTokenizer2 = mod14.PrismTokenizer; 30128 var getCodeLanguageOptions2 = mod14.getCodeLanguageOptions; 30129 var getCodeLanguages2 = mod14.getCodeLanguages; 30130 var getCodeThemeOptions2 = mod14.getCodeThemeOptions; 30131 var getLanguageFriendlyName2 = mod14.getLanguageFriendlyName; 30132 var isCodeLanguageLoaded2 = mod14.isCodeLanguageLoaded; 30133 var loadCodeLanguage2 = mod14.loadCodeLanguage; 30134 var normalizeCodeLanguage2 = mod14.normalizeCodeLanguage; 30135 var registerCodeHighlighting2 = mod14.registerCodeHighlighting; 30136 30137
vendor: 594 bytes, lines 30137-30149
30137// node_modules/@lexical/code/LexicalCode.dev.mjs 30138 var CODE_LANGUAGE_FRIENDLY_NAME_MAP3 = CODE_LANGUAGE_FRIENDLY_NAME_MAP2; 30139 var CODE_LANGUAGE_MAP3 = CODE_LANGUAGE_MAP2; 30140 var getCodeLanguageOptions3 = getCodeLanguageOptions2; 30141 var getCodeLanguages3 = getCodeLanguages2; 30142 var getCodeThemeOptions3 = getCodeThemeOptions2; 30143 var getLanguageFriendlyName3 = getLanguageFriendlyName2; 30144 var normalizeCodeLang = normalizeCodeLanguage2; 30145 var normalizeCodeLanguage3 = normalizeCodeLanguage2; 30146 var PrismTokenizer3 = PrismTokenizer2; 30147 var registerCodeHighlighting3 = registerCodeHighlighting2; 30148 30149
vendor: 1,476 bytes, lines 30149-30176
30149// node_modules/@lexical/code/LexicalCode.mjs 30150 var mod15 = true ? LexicalCode_dev_exports : LexicalCode_prod_exports; 30151 var $createCodeHighlightNode3 = mod15.$createCodeHighlightNode; 30152 var $createCodeNode3 = mod15.$createCodeNode; 30153 var $getCodeLineDirection3 = mod15.$getCodeLineDirection; 30154 var $getEndOfCodeInLine3 = mod15.$getEndOfCodeInLine; 30155 var $getFirstCodeNodeOfLine3 = mod15.$getFirstCodeNodeOfLine; 30156 var $getLastCodeNodeOfLine3 = mod15.$getLastCodeNodeOfLine; 30157 var $getStartOfCodeInLine3 = mod15.$getStartOfCodeInLine; 30158 var $isCodeHighlightNode3 = mod15.$isCodeHighlightNode; 30159 var $isCodeNode3 = mod15.$isCodeNode; 30160 var CODE_LANGUAGE_FRIENDLY_NAME_MAP4 = mod15.CODE_LANGUAGE_FRIENDLY_NAME_MAP; 30161 var CODE_LANGUAGE_MAP4 = mod15.CODE_LANGUAGE_MAP; 30162 var CodeExtension3 = mod15.CodeExtension; 30163 var CodeHighlightNode3 = mod15.CodeHighlightNode; 30164 var CodeNode3 = mod15.CodeNode; 30165 var DEFAULT_CODE_LANGUAGE3 = mod15.DEFAULT_CODE_LANGUAGE; 30166 var PrismTokenizer4 = mod15.PrismTokenizer; 30167 var getCodeLanguageOptions4 = mod15.getCodeLanguageOptions; 30168 var getCodeLanguages4 = mod15.getCodeLanguages; 30169 var getCodeThemeOptions4 = mod15.getCodeThemeOptions; 30170 var getDefaultCodeLanguage3 = mod15.getDefaultCodeLanguage; 30171 var getLanguageFriendlyName4 = mod15.getLanguageFriendlyName; 30172 var normalizeCodeLang2 = mod15.normalizeCodeLang; 30173 var normalizeCodeLanguage4 = mod15.normalizeCodeLanguage; 30174 var registerCodeHighlighting4 = mod15.registerCodeHighlighting; 30175 30176
vendor: 57,908 bytes, lines 30176-31670
30176// node_modules/@lexical/markdown/LexicalMarkdown.dev.mjs 30177 var LexicalMarkdown_dev_exports = {}; 30178 __export(LexicalMarkdown_dev_exports, { 30179 $convertFromMarkdownString: () => $convertFromMarkdownString, 30180 $convertToMarkdownString: () => $convertToMarkdownString, 30181 BOLD_ITALIC_STAR: () => BOLD_ITALIC_STAR, 30182 BOLD_ITALIC_UNDERSCORE: () => BOLD_ITALIC_UNDERSCORE, 30183 BOLD_STAR: () => BOLD_STAR, 30184 BOLD_UNDERSCORE: () => BOLD_UNDERSCORE, 30185 CHECK_LIST: () => CHECK_LIST, 30186 CODE: () => CODE, 30187 ELEMENT_TRANSFORMERS: () => ELEMENT_TRANSFORMERS, 30188 HEADING: () => HEADING, 30189 HIGHLIGHT: () => HIGHLIGHT, 30190 INLINE_CODE: () => INLINE_CODE, 30191 ITALIC_STAR: () => ITALIC_STAR, 30192 ITALIC_UNDERSCORE: () => ITALIC_UNDERSCORE, 30193 LINK: () => LINK, 30194 MULTILINE_ELEMENT_TRANSFORMERS: () => MULTILINE_ELEMENT_TRANSFORMERS, 30195 ORDERED_LIST: () => ORDERED_LIST, 30196 QUOTE: () => QUOTE, 30197 STRIKETHROUGH: () => STRIKETHROUGH, 30198 TEXT_FORMAT_TRANSFORMERS: () => TEXT_FORMAT_TRANSFORMERS, 30199 TEXT_MATCH_TRANSFORMERS: () => TEXT_MATCH_TRANSFORMERS, 30200 TRANSFORMERS: () => TRANSFORMERS, 30201 UNORDERED_LIST: () => UNORDERED_LIST, 30202 registerMarkdownShortcuts: () => registerMarkdownShortcuts 30203 }); 30204 function indexBy(list, callback) { 30205 const index = {}; 30206 for (const item of list) { 30207 const key = callback(item); 30208 if (!key) { 30209 continue; 30210 } 30211 if (index[key]) { 30212 index[key].push(item); 30213 } else { 30214 index[key] = [item]; 30215 } 30216 } 30217 return index; 30218 } 30219 function transformersByType(transformers) { 30220 const byType = indexBy(transformers, (t2) => t2.type); 30221 return { 30222 element: byType.element || [], 30223 multilineElement: byType["multiline-element"] || [], 30224 textFormat: byType["text-format"] || [], 30225 textMatch: byType["text-match"] || [] 30226 }; 30227 } 30228 var PUNCTUATION_OR_SPACE2 = /[!-/:-@[-`{-~\s]/; 30229 var WHITESPACE = /[ \t\n\r\f]/; 30230 var PUNCTUATION = /[!"#$%&'()*+,\-./:;<=>?@[\]^_`{|}~]/; 30231 var MARKDOWN_EMPTY_LINE_REG_EXP = /^\s{0,3}$/; 30232 function isEmptyParagraph(node) { 30233 if (!$isParagraphNode2(node)) { 30234 return false; 30235 } 30236 const firstChild = node.getFirstChild(); 30237 return firstChild == null || node.getChildrenSize() === 1 && $isTextNode2(firstChild) && MARKDOWN_EMPTY_LINE_REG_EXP.test(firstChild.getTextContent()); 30238 } 30239 function unescapeText(value) { 30240 return value.replace(/\\([!-/:-@[-`{-~])/g, "$1").replace(/&#(\d+);/g, (_3, codePoint) => String.fromCodePoint(Number(codePoint))); 30241 } 30242 function createMarkdownExport(transformers, shouldPreserveNewLines = false) { 30243 const byType = transformersByType(transformers); 30244 const elementTransformers = [...byType.multilineElement, ...byType.element]; 30245 const isNewlineDelimited = !shouldPreserveNewLines; 30246 const textFormatTransformers = byType.textFormat.filter((transformer) => transformer.format.length === 1).sort((a2, b3) => { 30247 return Number(a2.format.includes("code")) - Number(b3.format.includes("code")); 30248 }); 30249 return (node) => { 30250 const output = []; 30251 const children = (node || $getRoot2()).getChildren(); 30252 for (let i2 = 0; i2 < children.length; i2++) { 30253 const child = children[i2]; 30254 const result = exportTopLevelElements(child, elementTransformers, textFormatTransformers, byType.textMatch, shouldPreserveNewLines); 30255 if (result != null) { 30256 output.push( 30257 // separate consecutive group of texts with a line break: eg. ["hello", "world"] -> ["hello", "/nworld"] 30258 isNewlineDelimited && i2 > 0 && !isEmptyParagraph(child) && !isEmptyParagraph(children[i2 - 1]) ? "\n".concat(result) : result 30259 ); 30260 } 30261 } 30262 return output.join("\n"); 30263 }; 30264 } 30265 function exportTopLevelElements(node, elementTransformers, textTransformersIndex, textMatchTransformers, shouldPreserveNewLines) { 30266 for (const transformer of elementTransformers) { 30267 if (!transformer.export) { 30268 continue; 30269 } 30270 const result = transformer.export(node, (_node) => exportChildren(_node, textTransformersIndex, textMatchTransformers, void 0, void 0, shouldPreserveNewLines)); 30271 if (result != null) { 30272 return result; 30273 } 30274 } 30275 if ($isElementNode2(node)) { 30276 return exportChildren(node, textTransformersIndex, textMatchTransformers, void 0, void 0, shouldPreserveNewLines); 30277 } else if ($isDecoratorNode2(node)) { 30278 return node.getTextContent(); 30279 } else { 30280 return null; 30281 } 30282 } 30283 function exportChildren(node, textTransformersIndex, textMatchTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines = false) { 30284 const output = []; 30285 const children = node.getChildren(); 30286 if (!unclosedTags) { 30287 unclosedTags = []; 30288 } 30289 if (!unclosableTags) { 30290 unclosableTags = []; 30291 } 30292 mainLoop: for (const child of children) { 30293 for (const transformer of textMatchTransformers) { 30294 if (!transformer.export) { 30295 continue; 30296 } 30297 const result = transformer.export(child, (parentNode) => exportChildren( 30298 parentNode, 30299 textTransformersIndex, 30300 textMatchTransformers, 30301 unclosedTags, 30302 // Add current unclosed tags to the list of unclosable tags - we don't want nested tags from 30303 // textmatch transformers to close the outer ones, as that may result in invalid markdown. 30304 // E.g. **text [text**](https://lexical.io) 30305 // is invalid markdown, as the closing ** is inside the link. 30306 // 30307 [...unclosableTags, ...unclosedTags], 30308 shouldPreserveNewLines 30309 ), (textNode, textContent) => exportTextFormat(textNode, textContent, textTransformersIndex, unclosedTags, unclosableTags, shouldPreserveNewLines)); 30310 if (result != null) { 30311 output.push(result); 30312 continue mainLoop; 30313 } 30314 } 30315 if ($isLineBreakNode2(child)) { 30316 output.push("\n"); 30317 } else if ($isTextNode2(child)) { 30318 output.push(exportTextFormat(child, child.getTextContent(), textTransformersIndex, unclosedTags, unclosableTags, shouldPreserveNewLines)); 30319 } else if ($isElementNode2(child)) { 30320 output.push(exportChildren(child, textTransformersIndex, textMatchTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines)); 30321 } else if ($isDecoratorNode2(child)) { 30322 output.push(child.getTextContent()); 30323 } 30324 } 30325 return output.join(""); 30326 } 30327 function exportTextFormat(node, textContent, textTransformers, unclosedTags, unclosableTags, shouldPreserveNewLines = false) { 30328 let output = textContent; 30329 if (!node.hasFormat("code")) { 30330 output = shouldPreserveNewLines ? output.replace(/([*_`~])/g, "\\$1") : output.replace(/([*_`~\\])/g, "\\$1"); 30331 } 30332 const match = output.match(/^(\s*)(.*?)(\s*)$/s) || ["", "", output, ""]; 30333 const leadingSpace = match[1]; 30334 const trimmedOutput = match[2]; 30335 const trailingSpace = match[3]; 30336 const isWhitespaceOnly = trimmedOutput === ""; 30337 let openingTags = ""; 30338 let closingTagsBefore = ""; 30339 let closingTagsAfter = ""; 30340 const prevNode = getTextSibling(node, true); 30341 const nextNode = getTextSibling(node, false); 30342 const applied = /* @__PURE__ */ new Set(); 30343 for (const transformer of textTransformers) { 30344 const format = transformer.format[0]; 30345 const tag = transformer.tag; 30346 if (checkHasFormat(node, format) && !applied.has(format)) { 30347 applied.add(format); 30348 if (!checkHasFormat(prevNode, format) || !unclosedTags.find((element) => element.tag === tag)) { 30349 unclosedTags.push({ 30350 format, 30351 tag 30352 }); 30353 openingTags += tag; 30354 } 30355 } 30356 } 30357 for (let i2 = 0; i2 < unclosedTags.length; i2++) { 30358 const nodeHasFormat = hasFormat(node, unclosedTags[i2].format); 30359 const nextNodeHasFormat = hasFormat(nextNode, unclosedTags[i2].format); 30360 if (nodeHasFormat && nextNodeHasFormat) { 30361 continue; 30362 } 30363 const unhandledUnclosedTags = [...unclosedTags]; 30364 while (unhandledUnclosedTags.length > i2) { 30365 const unclosedTag = unhandledUnclosedTags.pop(); 30366 if (unclosableTags && unclosedTag && unclosableTags.find((element) => element.tag === unclosedTag.tag)) { 30367 continue; 30368 } 30369 if (unclosedTag && typeof unclosedTag.tag === "string") { 30370 if (!nodeHasFormat) { 30371 closingTagsBefore += unclosedTag.tag; 30372 } else if (!nextNodeHasFormat) { 30373 closingTagsAfter += unclosedTag.tag; 30374 } 30375 } 30376 unclosedTags.pop(); 30377 } 30378 break; 30379 } 30380 if (isWhitespaceOnly && !node.hasFormat("code")) { 30381 return closingTagsBefore + output; 30382 } 30383 return closingTagsBefore + leadingSpace + openingTags + trimmedOutput + closingTagsAfter + trailingSpace; 30384 } 30385 function getTextSibling(node, backward) { 30386 const sibling = backward ? node.getPreviousSibling() : node.getNextSibling(); 30387 if ($isTextNode2(sibling)) { 30388 return sibling; 30389 } 30390 return null; 30391 } 30392 function hasFormat(node, format) { 30393 return $isTextNode2(node) && node.hasFormat(format); 30394 } 30395 function checkHasFormat(n2, f) { 30396 if (!hasFormat(n2, f)) { 30397 return false; 30398 } 30399 if (f === "code") { 30400 return true; 30401 } 30402 if (n2 && /^\s*$/.test(n2.getTextContent())) { 30403 return false; 30404 } 30405 return true; 30406 } 30407 function findOutermostTextFormatTransformer(textNode, textFormatTransformersIndex) { 30408 const textContent = textNode.getTextContent(); 30409 const codeRegex = textFormatTransformersIndex.fullMatchRegExpByTag["`"]; 30410 const codeTransformer = textFormatTransformersIndex.transformersByTag["`"]; 30411 const excludeRanges = []; 30412 let codeMatch = null; 30413 if (codeRegex && codeTransformer) { 30414 const globalRegex = new RegExp(codeRegex.source, "g"); 30415 const matches = Array.from(textContent.matchAll(globalRegex)); 30416 for (const match of matches) { 30417 const startIndex = match.index + match[1].length; 30418 const endIndex = match.index + match[0].length; 30419 if (!codeMatch) { 30420 codeMatch = { 30421 content: match[3], 30422 endIndex, 30423 startIndex, 30424 tag: "`" 30425 }; 30426 } 30427 excludeRanges.push({ 30428 end: endIndex, 30429 start: startIndex 30430 }); 30431 } 30432 } 30433 const delimiters = scanDelimiters(textContent, textFormatTransformersIndex, excludeRanges); 30434 const emphasisMatch = delimiters.length > 0 ? processEmphasis(textContent, delimiters, textFormatTransformersIndex) : null; 30435 let resultMatch = null; 30436 let resultTransformer = null; 30437 if (codeMatch && emphasisMatch) { 30438 if (emphasisMatch.startIndex <= codeMatch.startIndex && emphasisMatch.endIndex >= codeMatch.endIndex) { 30439 resultMatch = emphasisMatch; 30440 resultTransformer = textFormatTransformersIndex.transformersByTag[emphasisMatch.tag]; 30441 } else { 30442 resultMatch = codeMatch; 30443 resultTransformer = codeTransformer; 30444 } 30445 } else if (codeMatch) { 30446 resultMatch = codeMatch; 30447 resultTransformer = codeTransformer; 30448 } else if (emphasisMatch) { 30449 resultMatch = emphasisMatch; 30450 resultTransformer = textFormatTransformersIndex.transformersByTag[emphasisMatch.tag]; 30451 } 30452 if (!resultMatch || !resultTransformer) { 30453 return null; 30454 } 30455 const regexMatch = [textContent.slice(resultMatch.startIndex, resultMatch.endIndex), resultMatch.tag, resultMatch.content]; 30456 regexMatch.index = resultMatch.startIndex; 30457 regexMatch.input = textContent; 30458 return { 30459 endIndex: resultMatch.endIndex, 30460 match: regexMatch, 30461 startIndex: resultMatch.startIndex, 30462 transformer: resultTransformer 30463 }; 30464 } 30465 function scanDelimiters(text2, transformersIndex, excludeRanges = []) { 30466 const delimiters = []; 30467 const delimiterChars = new Set(Object.keys(transformersIndex.transformersByTag).filter((tag) => tag[0] !== "`").map((tag) => tag[0])); 30468 const isEscaped = (index) => { 30469 let count = 0; 30470 for (let i3 = index - 1; i3 >= 0 && text2[i3] === "\\"; i3--) { 30471 count++; 30472 } 30473 return count % 2 === 1; 30474 }; 30475 const isInExcludedRange = (index) => { 30476 return excludeRanges.some((range2) => index >= range2.start && index < range2.end); 30477 }; 30478 let i2 = 0; 30479 while (i2 < text2.length) { 30480 const char = text2[i2]; 30481 if (!delimiterChars.has(char) || isEscaped(i2) || isInExcludedRange(i2)) { 30482 i2++; 30483 continue; 30484 } 30485 let len = 1; 30486 while (i2 + len < text2.length && text2[i2 + len] === char) { 30487 len++; 30488 } 30489 const canOpen = canEmphasis(char, text2, i2, len, true); 30490 const canClose = canEmphasis(char, text2, i2, len, false); 30491 if (canOpen || canClose) { 30492 delimiters.push({ 30493 active: true, 30494 canClose, 30495 canOpen, 30496 char, 30497 index: i2, 30498 length: len, 30499 originalLength: len 30500 }); 30501 } 30502 i2 += len; 30503 } 30504 return delimiters; 30505 } 30506 function processEmphasis(text2, delimiters, transformersIndex) { 30507 const openersBottom = {}; 30508 let currentPos = 0; 30509 let result = null; 30510 while (currentPos < delimiters.length) { 30511 const closer = delimiters[currentPos]; 30512 if (!closer.active || !closer.canClose || closer.length === 0) { 30513 currentPos++; 30514 continue; 30515 } 30516 const bottomKey = `${closer.char}${closer.canOpen}`; 30517 const bottom = openersBottom[bottomKey] ?? -1; 30518 let foundOpener = false; 30519 for (let openIdx = currentPos - 1; openIdx > bottom; openIdx--) { 30520 const opener = delimiters[openIdx]; 30521 if (!opener.active || !opener.canOpen || opener.length === 0 || opener.char !== closer.char) { 30522 continue; 30523 } 30524 if (opener.canClose || closer.canOpen) { 30525 const sum = opener.originalLength + closer.originalLength; 30526 if (sum % 3 === 0 && opener.originalLength % 3 !== 0 && closer.originalLength % 3 !== 0) { 30527 continue; 30528 } 30529 } 30530 const maxLen = Math.min(opener.length, closer.length); 30531 const matchedTag = Object.keys(transformersIndex.transformersByTag).filter((t2) => t2[0] === opener.char && t2.length <= maxLen).sort((a2, b3) => b3.length - a2.length)[0]; 30532 if (!matchedTag) { 30533 continue; 30534 } 30535 foundOpener = true; 30536 const matchLen = matchedTag.length; 30537 const match = { 30538 content: text2.slice(opener.index + opener.length, closer.index), 30539 endIndex: closer.index + matchLen, 30540 startIndex: opener.index + (opener.length - matchLen), 30541 tag: matchedTag 30542 }; 30543 if (!result || match.startIndex < result.startIndex || match.startIndex === result.startIndex && match.endIndex > result.endIndex) { 30544 result = match; 30545 } 30546 for (let j3 = openIdx + 1; j3 < currentPos; j3++) { 30547 delimiters[j3].active = false; 30548 } 30549 opener.length -= matchLen; 30550 closer.length -= matchLen; 30551 opener.active = opener.length > 0; 30552 if (closer.length > 0) { 30553 closer.index += matchLen; 30554 } else { 30555 closer.active = false; 30556 currentPos++; 30557 } 30558 break; 30559 } 30560 if (!foundOpener) { 30561 openersBottom[bottomKey] = currentPos - 1; 30562 if (!closer.canOpen) { 30563 closer.active = false; 30564 } 30565 currentPos++; 30566 } 30567 } 30568 return result; 30569 } 30570 function canEmphasis(char, text2, index, length, isOpen) { 30571 if (!isFlanking(text2, index, length, isOpen)) { 30572 return false; 30573 } 30574 if (char === "*") { 30575 return true; 30576 } 30577 if (char === "_") { 30578 if (!isFlanking(text2, index, length, !isOpen)) { 30579 return true; 30580 } 30581 const adjacentChar = isOpen ? text2[index - 1] : text2[index + length]; 30582 return adjacentChar !== void 0 && PUNCTUATION.test(adjacentChar); 30583 } 30584 return true; 30585 } 30586 function isFlanking(text2, index, length, isLeft) { 30587 const charBefore = text2[index - 1]; 30588 const charAfter = text2[index + length]; 30589 const [primary, secondary] = isLeft ? [charAfter, charBefore] : [charBefore, charAfter]; 30590 if (primary === void 0 || WHITESPACE.test(primary)) { 30591 return false; 30592 } 30593 if (!PUNCTUATION.test(primary)) { 30594 return true; 30595 } 30596 return secondary === void 0 || WHITESPACE.test(secondary) || PUNCTUATION.test(secondary); 30597 } 30598 function importTextFormatTransformer(textNode, startIndex, endIndex, transformer, match) { 30599 const textContent = textNode.getTextContent(); 30600 let transformedNode, nodeAfter, nodeBefore; 30601 if (match[0] === textContent) { 30602 transformedNode = textNode; 30603 } else { 30604 if (startIndex === 0) { 30605 [transformedNode, nodeAfter] = textNode.splitText(endIndex); 30606 } else { 30607 [nodeBefore, transformedNode, nodeAfter] = textNode.splitText(startIndex, endIndex); 30608 } 30609 } 30610 transformedNode.setTextContent(match[2]); 30611 if (transformer) { 30612 for (const format of transformer.format) { 30613 if (!transformedNode.hasFormat(format)) { 30614 transformedNode.toggleFormat(format); 30615 } 30616 } 30617 } 30618 return { 30619 nodeAfter, 30620 nodeBefore, 30621 transformedNode 30622 }; 30623 } 30624 function findOutermostTextMatchTransformer(textNode_, textMatchTransformers) { 30625 const textNode = textNode_; 30626 let foundMatchStartIndex = void 0; 30627 let foundMatchEndIndex = void 0; 30628 let foundMatchTransformer = void 0; 30629 let foundMatch = void 0; 30630 for (const transformer of textMatchTransformers) { 30631 if (!transformer.replace || !transformer.importRegExp) { 30632 continue; 30633 } 30634 const match = textNode.getTextContent().match(transformer.importRegExp); 30635 if (!match) { 30636 continue; 30637 } 30638 const startIndex = match.index || 0; 30639 const endIndex = transformer.getEndIndex ? transformer.getEndIndex(textNode, match) : startIndex + match[0].length; 30640 if (endIndex === false) { 30641 continue; 30642 } 30643 if (foundMatchStartIndex === void 0 || foundMatchEndIndex === void 0 || // Wraps previous match or is strictly before it. 30644 startIndex < foundMatchStartIndex && (endIndex > foundMatchEndIndex || endIndex <= foundMatchStartIndex)) { 30645 foundMatchStartIndex = startIndex; 30646 foundMatchEndIndex = endIndex; 30647 foundMatchTransformer = transformer; 30648 foundMatch = match; 30649 } 30650 } 30651 if (foundMatchStartIndex === void 0 || foundMatchEndIndex === void 0 || foundMatchTransformer === void 0 || foundMatch === void 0) { 30652 return null; 30653 } 30654 return { 30655 endIndex: foundMatchEndIndex, 30656 match: foundMatch, 30657 startIndex: foundMatchStartIndex, 30658 transformer: foundMatchTransformer 30659 }; 30660 } 30661 function importFoundTextMatchTransformer(textNode, startIndex, endIndex, transformer, match) { 30662 let transformedNode, nodeAfter, nodeBefore; 30663 if (startIndex === 0) { 30664 [transformedNode, nodeAfter] = textNode.splitText(endIndex); 30665 } else { 30666 [nodeBefore, transformedNode, nodeAfter] = textNode.splitText(startIndex, endIndex); 30667 } 30668 if (!transformer.replace) { 30669 return null; 30670 } 30671 const potentialTransformedNode = transformer.replace(transformedNode, match); 30672 return { 30673 nodeAfter, 30674 nodeBefore, 30675 transformedNode: potentialTransformedNode || void 0 30676 }; 30677 } 30678 function canContainTransformableMarkdown(node) { 30679 return $isTextNode2(node) && !node.hasFormat("code"); 30680 } 30681 function importTextTransformers(textNode, textFormatTransformersIndex, textMatchTransformers) { 30682 let foundTextFormat = findOutermostTextFormatTransformer(textNode, textFormatTransformersIndex); 30683 let foundTextMatch = findOutermostTextMatchTransformer(textNode, textMatchTransformers); 30684 if (foundTextFormat && foundTextMatch) { 30685 if (foundTextFormat.startIndex <= foundTextMatch.startIndex && foundTextFormat.endIndex >= foundTextMatch.endIndex || // foundTextMatch is not contained within foundTextFormat 30686 foundTextMatch.startIndex > foundTextFormat.endIndex) { 30687 foundTextMatch = null; 30688 } else { 30689 foundTextFormat = null; 30690 } 30691 } 30692 if (foundTextFormat) { 30693 const result = importTextFormatTransformer(textNode, foundTextFormat.startIndex, foundTextFormat.endIndex, foundTextFormat.transformer, foundTextFormat.match); 30694 if (canContainTransformableMarkdown(result.nodeAfter)) { 30695 importTextTransformers(result.nodeAfter, textFormatTransformersIndex, textMatchTransformers); 30696 } 30697 if (canContainTransformableMarkdown(result.nodeBefore)) { 30698 importTextTransformers(result.nodeBefore, textFormatTransformersIndex, textMatchTransformers); 30699 } 30700 if (canContainTransformableMarkdown(result.transformedNode)) { 30701 importTextTransformers(result.transformedNode, textFormatTransformersIndex, textMatchTransformers); 30702 } 30703 } else if (foundTextMatch) { 30704 const result = importFoundTextMatchTransformer(textNode, foundTextMatch.startIndex, foundTextMatch.endIndex, foundTextMatch.transformer, foundTextMatch.match); 30705 if (!result) { 30706 return; 30707 } 30708 if (canContainTransformableMarkdown(result.nodeAfter)) { 30709 importTextTransformers(result.nodeAfter, textFormatTransformersIndex, textMatchTransformers); 30710 } 30711 if (canContainTransformableMarkdown(result.nodeBefore)) { 30712 importTextTransformers(result.nodeBefore, textFormatTransformersIndex, textMatchTransformers); 30713 } 30714 if (canContainTransformableMarkdown(result.transformedNode)) { 30715 importTextTransformers(result.transformedNode, textFormatTransformersIndex, textMatchTransformers); 30716 } 30717 } 30718 const textContent = textNode.getTextContent(); 30719 const unescapedText = unescapeText(textContent); 30720 textNode.setTextContent(unescapedText); 30721 } 30722 function createMarkdownImport(transformers, shouldPreserveNewLines = false) { 30723 const byType = transformersByType(transformers); 30724 const textFormatTransformersIndex = createTextFormatTransformersIndex(byType.textFormat); 30725 return (markdownString, node) => { 30726 const lines = markdownString.split("\n"); 30727 const linesLength = lines.length; 30728 const root = node || $getRoot2(); 30729 root.clear(); 30730 for (let i2 = 0; i2 < linesLength; i2++) { 30731 const lineText = lines[i2]; 30732 const [imported, shiftedIndex] = $importMultiline(lines, i2, byType.multilineElement, root); 30733 if (imported) { 30734 i2 = shiftedIndex; 30735 continue; 30736 } 30737 $importBlocks(lineText, root, byType.element, textFormatTransformersIndex, byType.textMatch, shouldPreserveNewLines); 30738 } 30739 const children = root.getChildren(); 30740 for (const child of children) { 30741 if (!shouldPreserveNewLines && isEmptyParagraph(child) && root.getChildrenSize() > 1) { 30742 child.remove(); 30743 continue; 30744 } 30745 if ($isElementNode2(child)) { 30746 for (const textNode of child.getAllTextNodes()) { 30747 $normalizeMarkdownTextNode(textNode); 30748 } 30749 } 30750 } 30751 if ($getSelection2() !== null) { 30752 root.selectStart(); 30753 } 30754 }; 30755 } 30756 function $importMultiline(lines, startLineIndex, multilineElementTransformers, rootNode) { 30757 for (const transformer of multilineElementTransformers) { 30758 const { 30759 handleImportAfterStartMatch, 30760 regExpEnd, 30761 regExpStart, 30762 replace 30763 } = transformer; 30764 const startMatch = lines[startLineIndex].match(regExpStart); 30765 if (!startMatch) { 30766 continue; 30767 } 30768 if (handleImportAfterStartMatch) { 30769 const result = handleImportAfterStartMatch({ 30770 lines, 30771 rootNode, 30772 startLineIndex, 30773 startMatch, 30774 transformer 30775 }); 30776 if (result === null) { 30777 continue; 30778 } else if (result) { 30779 return result; 30780 } 30781 } 30782 const regexpEndRegex = typeof regExpEnd === "object" && "regExp" in regExpEnd ? regExpEnd.regExp : regExpEnd; 30783 const isEndOptional = regExpEnd && typeof regExpEnd === "object" && "optional" in regExpEnd ? regExpEnd.optional : !regExpEnd; 30784 let endLineIndex = startLineIndex; 30785 const linesLength = lines.length; 30786 while (endLineIndex < linesLength) { 30787 const endMatch = regexpEndRegex ? lines[endLineIndex].match(regexpEndRegex) : null; 30788 if (!endMatch) { 30789 if (!isEndOptional || isEndOptional && endLineIndex < linesLength - 1) { 30790 endLineIndex++; 30791 continue; 30792 } 30793 } 30794 if (endMatch && startLineIndex === endLineIndex && endMatch.index === startMatch.index) { 30795 endLineIndex++; 30796 continue; 30797 } 30798 const linesInBetween = []; 30799 if (endMatch && startLineIndex === endLineIndex) { 30800 linesInBetween.push(lines[startLineIndex].slice(startMatch[0].length, -endMatch[0].length)); 30801 } else { 30802 for (let i2 = startLineIndex; i2 <= endLineIndex; i2++) { 30803 if (i2 === startLineIndex) { 30804 const text2 = lines[i2].slice(startMatch[0].length); 30805 linesInBetween.push(text2); 30806 } else if (i2 === endLineIndex && endMatch) { 30807 const text2 = lines[i2].slice(0, -endMatch[0].length); 30808 linesInBetween.push(text2); 30809 } else { 30810 linesInBetween.push(lines[i2]); 30811 } 30812 } 30813 } 30814 if (replace(rootNode, null, startMatch, endMatch, linesInBetween, true) !== false) { 30815 return [true, endLineIndex]; 30816 } 30817 break; 30818 } 30819 } 30820 return [false, startLineIndex]; 30821 } 30822 function $importBlocks(lineText, rootNode, elementTransformers, textFormatTransformersIndex, textMatchTransformers, shouldPreserveNewLines) { 30823 const textNode = $createTextNode2(lineText); 30824 const elementNode = $createParagraphNode2(); 30825 elementNode.append(textNode); 30826 rootNode.append(elementNode); 30827 for (const { 30828 regExp, 30829 replace 30830 } of elementTransformers) { 30831 const match = lineText.match(regExp); 30832 if (match) { 30833 textNode.setTextContent(lineText.slice(match[0].length)); 30834 if (replace(elementNode, [textNode], match, true) !== false) { 30835 break; 30836 } 30837 } 30838 } 30839 importTextTransformers(textNode, textFormatTransformersIndex, textMatchTransformers); 30840 if (elementNode.isAttached() && lineText.length > 0) { 30841 const previousNode = elementNode.getPreviousSibling(); 30842 if (!shouldPreserveNewLines && // Only append if we're not preserving newlines 30843 ($isParagraphNode2(previousNode) || $isQuoteNode2(previousNode) || $isListNode2(previousNode))) { 30844 let targetNode = previousNode; 30845 if ($isListNode2(previousNode)) { 30846 const lastDescendant = previousNode.getLastDescendant(); 30847 if (lastDescendant == null) { 30848 targetNode = null; 30849 } else { 30850 targetNode = $findMatchingParent3(lastDescendant, $isListItemNode2); 30851 } 30852 } 30853 if (targetNode != null && targetNode.getTextContentSize() > 0) { 30854 const lastChild = targetNode.getLastChild(); 30855 if ($isTextNode2(lastChild)) { 30856 const lastText = lastChild.getTextContent(); 30857 if (lastText.endsWith("\\")) { 30858 lastChild.setTextContent(lastText.slice(0, -1)); 30859 } else if (/ {2,}$/.test(lastText)) { 30860 lastChild.setTextContent(lastText.replace(/ {2,}$/, "")); 30861 } 30862 } 30863 targetNode.splice(targetNode.getChildrenSize(), 0, [$createLineBreakNode2(), ...elementNode.getChildren()]); 30864 elementNode.remove(); 30865 } 30866 } 30867 } 30868 } 30869 function $normalizeMarkdownTextNode(textNode) { 30870 const tabOffsets = /* @__PURE__ */ new Set(); 30871 const text2 = textNode.getTextContent(); 30872 let index = text2.indexOf(" "); 30873 while (index !== -1) { 30874 tabOffsets.add(index); 30875 tabOffsets.add(index + 1); 30876 index = text2.indexOf(" ", index + 1); 30877 } 30878 const splitNodes = textNode.splitText(...tabOffsets); 30879 splitNodes.forEach((node) => { 30880 if (node.getTextContent() === " ") { 30881 node.replace($createTabNode2()); 30882 } 30883 }); 30884 } 30885 function createTextFormatTransformersIndex(textTransformers) { 30886 const transformersByTag = {}; 30887 const fullMatchRegExpByTag = {}; 30888 const openTagsRegExp = []; 30889 for (const transformer of textTransformers) { 30890 const { 30891 tag 30892 } = transformer; 30893 transformersByTag[tag] = transformer; 30894 const tagRegExp = tag.replace(/(\*|\^|\+)/g, "\\$1"); 30895 openTagsRegExp.push(tagRegExp); 30896 if (tag.length === 1) { 30897 if (tag === "`") { 30898 fullMatchRegExpByTag[tag] = new RegExp(`(^|[^\\\\\`])(\`)((?:\\\\\`|[^\`])+?)(\`)(?!\`)`); 30899 } else { 30900 fullMatchRegExpByTag[tag] = new RegExp(`(^|[^\\\\${tagRegExp}])(${tagRegExp})((\\\\${tagRegExp})?.*?[^${tagRegExp}\\s](\\\\${tagRegExp})?)(${tagRegExp})(?![\\\\${tagRegExp}])`); 30901 } 30902 } else { 30903 fullMatchRegExpByTag[tag] = new RegExp(`(^|[^\\\\])(${tagRegExp})((\\\\${tagRegExp})?.*?[^\\s](\\\\${tagRegExp})?)(${tagRegExp})(?!\\\\)`); 30904 } 30905 } 30906 return { 30907 // Reg exp to find open tag + content + close tag 30908 fullMatchRegExpByTag, 30909 // Regexp to locate *any* potential opening tag (longest first). 30910 // The former (?<!\\) escape guard has been removed â the delimiter 30911 // scanner's isEscaped() check handles escape filtering at match time. 30912 openTagsRegExp: new RegExp(`(${openTagsRegExp.join("|")})`, "g"), 30913 transformersByTag 30914 }; 30915 } 30916 function formatDevErrorMessage11(message) { 30917 throw new Error(message); 30918 } 30919 var ORDERED_LIST_REGEX = /^(\s*)(\d{1,})\.\s/; 30920 var UNORDERED_LIST_REGEX = /^(\s*)[-*+]\s/; 30921 var CHECK_LIST_REGEX = /^(\s*)(?:[-*+]\s)?\s?(\[(\s|x)?\])\s/i; 30922 var HEADING_REGEX = /^(#{1,6})\s/; 30923 var QUOTE_REGEX = /^>\s/; 30924 var CODE_START_REGEX = /^([ \t]*`{3,})([\w-]+)?[ \t]?/; 30925 var CODE_END_REGEX = /^[ \t]*`{3,}$/; 30926 var CODE_SINGLE_LINE_REGEX = /^[ \t]*```[^`]+(?:(?:`{1,2}|`{4,})[^`]+)*```(?:[^`]|$)/; 30927 var TABLE_ROW_REG_EXP = /^(?:\|)(.+)(?:\|)\s?$/; 30928 var TABLE_ROW_DIVIDER_REG_EXP = /^(\| ?:?-*:? ?)+\|\s?$/; 30929 var TAG_START_REGEX = /^<[a-z_][\w-]*(?:\s[^<>]*)?\/?>/i; 30930 var TAG_END_REGEX = /^<\/[a-z_][\w-]*\s*>/i; 30931 var ENDS_WITH = (regex) => new RegExp(`(?:${regex.source})$`, regex.flags); 30932 var listMarkerState = createState2("mdListMarker", { 30933 parse: (v3) => typeof v3 === "string" && /^[-*+]$/.test(v3) ? v3 : "-", 30934 resetOnCopyNode: true 30935 }); 30936 var codeFenceState = createState2("mdCodeFence", { 30937 parse: (val) => { 30938 if (typeof val === "string" && /^`{3,}$/.test(val)) { 30939 return val; 30940 } 30941 return "```"; 30942 }, 30943 resetOnCopyNode: true 30944 }); 30945 var createBlockNode = (createNode) => { 30946 return (parentNode, children, match, isImport) => { 30947 const node = createNode(match); 30948 node.append(...children); 30949 parentNode.replace(node); 30950 if (!isImport) { 30951 node.select(0, 0); 30952 } 30953 }; 30954 }; 30955 var LIST_INDENT_SIZE = 4; 30956 function getIndent(whitespaces) { 30957 const tabs = whitespaces.match(/\t/g); 30958 const spaces = whitespaces.match(/ /g); 30959 let indent = 0; 30960 if (tabs) { 30961 indent += tabs.length; 30962 } 30963 if (spaces) { 30964 indent += Math.floor(spaces.length / LIST_INDENT_SIZE); 30965 } 30966 return indent; 30967 } 30968 var listReplace = (listType) => { 30969 return (parentNode, children, match, isImport) => { 30970 const previousNode = parentNode.getPreviousSibling(); 30971 const nextNode = parentNode.getNextSibling(); 30972 const listItem = $createListItemNode2(listType === "check" ? match[3] === "x" : void 0); 30973 const firstMatchChar = match[0].trim()[0]; 30974 const listMarker = (listType === "bullet" || listType === "check") && firstMatchChar === listMarkerState.parse(firstMatchChar) ? firstMatchChar : void 0; 30975 if ($isListNode2(nextNode) && nextNode.getListType() === listType) { 30976 if (listMarker) { 30977 $setState2(nextNode, listMarkerState, listMarker); 30978 } 30979 const firstChild = nextNode.getFirstChild(); 30980 if (firstChild !== null) { 30981 firstChild.insertBefore(listItem); 30982 } else { 30983 nextNode.append(listItem); 30984 } 30985 parentNode.remove(); 30986 } else if ($isListNode2(previousNode) && previousNode.getListType() === listType) { 30987 if (listMarker) { 30988 $setState2(previousNode, listMarkerState, listMarker); 30989 } 30990 previousNode.append(listItem); 30991 parentNode.remove(); 30992 } else { 30993 const list = $createListNode2(listType, listType === "number" ? Number(match[2]) : void 0); 30994 if (listMarker) { 30995 $setState2(list, listMarkerState, listMarker); 30996 } 30997 list.append(listItem); 30998 parentNode.replace(list); 30999 } 31000 listItem.append(...children); 31001 if (!isImport) { 31002 listItem.select(0, 0); 31003 } 31004 const indent = getIndent(match[1]); 31005 if (indent) { 31006 listItem.setIndent(indent); 31007 } 31008 }; 31009 }; 31010 var $listExport = (listNode, exportChildren2, depth) => { 31011 const output = []; 31012 const children = listNode.getChildren(); 31013 let index = 0; 31014 for (const listItemNode of children) { 31015 if ($isListItemNode2(listItemNode)) { 31016 if (listItemNode.getChildrenSize() === 1) { 31017 const firstChild = listItemNode.getFirstChild(); 31018 if ($isListNode2(firstChild)) { 31019 output.push($listExport(firstChild, exportChildren2, depth + 1)); 31020 continue; 31021 } 31022 } 31023 const indent = " ".repeat(depth * LIST_INDENT_SIZE); 31024 const listType = listNode.getListType(); 31025 const listMarker = $getState2(listNode, listMarkerState); 31026 const prefix = listType === "number" ? `${listNode.getStart() + index}. ` : listType === "check" ? `${listMarker} [${listItemNode.getChecked() ? "x" : " "}] ` : listMarker + " "; 31027 let childrenText = exportChildren2(listItemNode); 31028 if (listType !== "number") { 31029 childrenText = childrenText.replace(/^(\s{0,3}\d+)(\.\s)/, "$1\\$2"); 31030 } 31031 output.push(indent + prefix + childrenText); 31032 index++; 31033 } 31034 } 31035 return output.join("\n"); 31036 }; 31037 var HEADING = { 31038 dependencies: [HeadingNode2], 31039 export: (node, exportChildren2) => { 31040 if (!$isHeadingNode2(node)) { 31041 return null; 31042 } 31043 const level = Number(node.getTag().slice(1)); 31044 return "#".repeat(level) + " " + exportChildren2(node); 31045 }, 31046 regExp: HEADING_REGEX, 31047 replace: createBlockNode((match) => { 31048 const tag = "h" + match[1].length; 31049 return $createHeadingNode2(tag); 31050 }), 31051 type: "element" 31052 }; 31053 var QUOTE = { 31054 dependencies: [QuoteNode2], 31055 export: (node, exportChildren2) => { 31056 if (!$isQuoteNode2(node)) { 31057 return null; 31058 } 31059 const lines = exportChildren2(node).split("\n"); 31060 const output = []; 31061 for (const line of lines) { 31062 output.push("> " + line); 31063 } 31064 return output.join("\n"); 31065 }, 31066 regExp: QUOTE_REGEX, 31067 replace: (parentNode, children, _match, isImport) => { 31068 if (isImport) { 31069 const previousNode = parentNode.getPreviousSibling(); 31070 if ($isQuoteNode2(previousNode)) { 31071 previousNode.splice(previousNode.getChildrenSize(), 0, [$createLineBreakNode2(), ...children]); 31072 parentNode.remove(); 31073 return; 31074 } 31075 } 31076 const node = $createQuoteNode2(); 31077 node.append(...children); 31078 parentNode.replace(node); 31079 if (!isImport) { 31080 node.select(0, 0); 31081 } 31082 }, 31083 type: "element" 31084 }; 31085 var CODE = { 31086 dependencies: [CodeNode2], 31087 export: (node) => { 31088 if (!$isCodeNode2(node)) { 31089 return null; 31090 } 31091 const textContent = node.getTextContent(); 31092 let fence = $getState2(node, codeFenceState); 31093 if (textContent.indexOf(fence) > -1) { 31094 const backticks = textContent.match(/`{3,}/g); 31095 if (backticks) { 31096 const maxLength = Math.max(...backticks.map((b3) => b3.length)); 31097 fence = "`".repeat(maxLength + 1); 31098 } 31099 } 31100 return fence + (node.getLanguage() || "") + (textContent ? "\n" + textContent : "") + "\n" + fence; 31101 }, 31102 handleImportAfterStartMatch: ({ 31103 lines, 31104 rootNode, 31105 startLineIndex, 31106 startMatch 31107 }) => { 31108 const fence = startMatch[1]; 31109 const fenceLength = fence.trim().length; 31110 const currentLine = lines[startLineIndex]; 31111 const afterFenceIndex = startMatch.index + fence.length; 31112 const afterFence = currentLine.slice(afterFenceIndex); 31113 const singleLineEndRegex = new RegExp(`\`{${fenceLength},}$`); 31114 if (singleLineEndRegex.test(afterFence)) { 31115 const endMatch = afterFence.match(singleLineEndRegex); 31116 const content = afterFence.slice(0, afterFence.lastIndexOf(endMatch[0])); 31117 const fakeStartMatch = [...startMatch]; 31118 fakeStartMatch[2] = ""; 31119 CODE.replace(rootNode, null, fakeStartMatch, endMatch, [content], true); 31120 return [true, startLineIndex]; 31121 } 31122 const multilineEndRegex = new RegExp(`^[ \\t]*\`{${fenceLength},}$`); 31123 for (let i2 = startLineIndex + 1; i2 < lines.length; i2++) { 31124 const line = lines[i2]; 31125 if (multilineEndRegex.test(line)) { 31126 const endMatch = line.match(multilineEndRegex); 31127 const linesInBetween2 = lines.slice(startLineIndex + 1, i2); 31128 const afterFullMatch2 = currentLine.slice(startMatch[0].length); 31129 if (afterFullMatch2.length > 0) { 31130 linesInBetween2.unshift(afterFullMatch2); 31131 } 31132 CODE.replace(rootNode, null, startMatch, endMatch, linesInBetween2, true); 31133 return [true, i2]; 31134 } 31135 } 31136 const linesInBetween = lines.slice(startLineIndex + 1); 31137 const afterFullMatch = currentLine.slice(startMatch[0].length); 31138 if (afterFullMatch.length > 0) { 31139 linesInBetween.unshift(afterFullMatch); 31140 } 31141 CODE.replace(rootNode, null, startMatch, null, linesInBetween, true); 31142 return [true, lines.length - 1]; 31143 }, 31144 regExpEnd: { 31145 optional: true, 31146 regExp: CODE_END_REGEX 31147 }, 31148 regExpStart: CODE_START_REGEX, 31149 replace: (rootNode, children, startMatch, endMatch, linesInBetween, isImport) => { 31150 let codeBlockNode; 31151 let code; 31152 const fence = startMatch[1] ? startMatch[1].trim() : "```"; 31153 const language = startMatch[2] || void 0; 31154 if (!children && linesInBetween) { 31155 if (linesInBetween.length === 1) { 31156 if (endMatch) { 31157 codeBlockNode = $createCodeNode2(language); 31158 code = linesInBetween[0]; 31159 } else { 31160 codeBlockNode = $createCodeNode2(language); 31161 code = linesInBetween[0].startsWith(" ") ? linesInBetween[0].slice(1) : linesInBetween[0]; 31162 } 31163 } else { 31164 codeBlockNode = $createCodeNode2(language); 31165 if (linesInBetween.length > 0) { 31166 if (linesInBetween[0].trim().length === 0) { 31167 linesInBetween.shift(); 31168 } else if (linesInBetween[0].startsWith(" ")) { 31169 linesInBetween[0] = linesInBetween[0].slice(1); 31170 } 31171 } 31172 while (linesInBetween.length > 0 && !linesInBetween[linesInBetween.length - 1].length) { 31173 linesInBetween.pop(); 31174 } 31175 code = linesInBetween.join("\n"); 31176 } 31177 $setState2(codeBlockNode, codeFenceState, fence); 31178 const textNode = $createTextNode2(code); 31179 codeBlockNode.append(textNode); 31180 rootNode.append(codeBlockNode); 31181 } else if (children) { 31182 createBlockNode((match) => { 31183 return $createCodeNode2(match ? match[2] : void 0); 31184 })(rootNode, children, startMatch, isImport); 31185 } 31186 }, 31187 type: "multiline-element" 31188 }; 31189 var UNORDERED_LIST = { 31190 dependencies: [ListNode2, ListItemNode2], 31191 export: (node, exportChildren2) => { 31192 return $isListNode2(node) ? $listExport(node, exportChildren2, 0) : null; 31193 }, 31194 regExp: UNORDERED_LIST_REGEX, 31195 replace: listReplace("bullet"), 31196 type: "element" 31197 }; 31198 var CHECK_LIST = { 31199 dependencies: [ListNode2, ListItemNode2], 31200 export: (node, exportChildren2) => { 31201 return $isListNode2(node) ? $listExport(node, exportChildren2, 0) : null; 31202 }, 31203 regExp: CHECK_LIST_REGEX, 31204 replace: listReplace("check"), 31205 type: "element" 31206 }; 31207 var ORDERED_LIST = { 31208 dependencies: [ListNode2, ListItemNode2], 31209 export: (node, exportChildren2) => { 31210 return $isListNode2(node) ? $listExport(node, exportChildren2, 0) : null; 31211 }, 31212 regExp: ORDERED_LIST_REGEX, 31213 replace: listReplace("number"), 31214 type: "element" 31215 }; 31216 var INLINE_CODE = { 31217 format: ["code"], 31218 tag: "`", 31219 type: "text-format" 31220 }; 31221 var HIGHLIGHT = { 31222 format: ["highlight"], 31223 tag: "==", 31224 type: "text-format" 31225 }; 31226 var BOLD_ITALIC_STAR = { 31227 format: ["bold", "italic"], 31228 tag: "***", 31229 type: "text-format" 31230 }; 31231 var BOLD_ITALIC_UNDERSCORE = { 31232 format: ["bold", "italic"], 31233 intraword: false, 31234 tag: "___", 31235 type: "text-format" 31236 }; 31237 var BOLD_STAR = { 31238 format: ["bold"], 31239 tag: "**", 31240 type: "text-format" 31241 }; 31242 var BOLD_UNDERSCORE = { 31243 format: ["bold"], 31244 intraword: false, 31245 tag: "__", 31246 type: "text-format" 31247 }; 31248 var STRIKETHROUGH = { 31249 format: ["strikethrough"], 31250 tag: "~~", 31251 type: "text-format" 31252 }; 31253 var ITALIC_STAR = { 31254 format: ["italic"], 31255 tag: "*", 31256 type: "text-format" 31257 }; 31258 var ITALIC_UNDERSCORE = { 31259 format: ["italic"], 31260 intraword: false, 31261 tag: "_", 31262 type: "text-format" 31263 }; 31264 var LINK = { 31265 dependencies: [LinkNode2], 31266 export: (node, exportChildren2, exportFormat) => { 31267 if (!$isLinkNode2(node) || $isAutoLinkNode2(node)) { 31268 return null; 31269 } 31270 const textContent = exportChildren2(node); 31271 let title = node.getTitle(); 31272 if (title != null) { 31273 title = title.replace(/([\\"])/g, "\\$1"); 31274 } 31275 const linkContent = title ? `[${textContent}](${node.getURL()} "${title}")` : `[${textContent}](${node.getURL()})`; 31276 return linkContent; 31277 }, 31278 importRegExp: /(?:\[(.+?)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))/, 31279 regExp: /(?:\[([^[\]]*(?:\[[^[\]]*\][^[\]]*)*)\])(?:\((?:([^()\s]+)(?:\s"((?:[^"]*\\")*[^"]*)"\s*)?)\))$/, 31280 replace: (textNode, match) => { 31281 if ($findMatchingParent2(textNode, $isLinkNode2)) { 31282 return; 31283 } 31284 const [, linkText, rawLinkUrl, rawLinkTitle] = match; 31285 const linkUrl = rawLinkUrl != null ? unescapeText(rawLinkUrl) : void 0; 31286 const linkTitle = rawLinkTitle != null ? unescapeText(rawLinkTitle) : void 0; 31287 const linkNode = $createLinkNode2(linkUrl, { 31288 title: linkTitle 31289 }); 31290 const openBracketAmount = linkText.split("[").length - 1; 31291 const closeBracketAmount = linkText.split("]").length - 1; 31292 let parsedLinkText = linkText; 31293 let outsideLinkText = ""; 31294 if (openBracketAmount < closeBracketAmount) { 31295 return; 31296 } else if (openBracketAmount > closeBracketAmount) { 31297 const linkTextParts = linkText.split("["); 31298 outsideLinkText = "[" + linkTextParts[0]; 31299 parsedLinkText = linkTextParts.slice(1).join("["); 31300 } 31301 const linkTextNode = $createTextNode2(parsedLinkText); 31302 linkTextNode.setFormat(textNode.getFormat()); 31303 linkNode.append(linkTextNode); 31304 textNode.replace(linkNode); 31305 if (outsideLinkText) { 31306 linkNode.insertBefore($createTextNode2(outsideLinkText)); 31307 } 31308 return linkTextNode; 31309 }, 31310 trigger: ")", 31311 type: "text-match" 31312 }; 31313 var ELEMENT_TRANSFORMERS = [HEADING, QUOTE, UNORDERED_LIST, ORDERED_LIST]; 31314 var MULTILINE_ELEMENT_TRANSFORMERS = [CODE]; 31315 var TEXT_FORMAT_TRANSFORMERS = [INLINE_CODE, BOLD_ITALIC_STAR, BOLD_ITALIC_UNDERSCORE, BOLD_STAR, BOLD_UNDERSCORE, HIGHLIGHT, ITALIC_STAR, ITALIC_UNDERSCORE, STRIKETHROUGH]; 31316 var TEXT_MATCH_TRANSFORMERS = [LINK]; 31317 var TRANSFORMERS = [...ELEMENT_TRANSFORMERS, ...MULTILINE_ELEMENT_TRANSFORMERS, ...TEXT_FORMAT_TRANSFORMERS, ...TEXT_MATCH_TRANSFORMERS]; 31318 function normalizeMarkdown(input, shouldMergeAdjacentLines = false) { 31319 const lines = input.split("\n"); 31320 let inCodeBlock = false; 31321 const sanitizedLines = []; 31322 for (let i2 = 0; i2 < lines.length; i2++) { 31323 const rawLine = lines[i2]; 31324 const line = rawLine.trimEnd(); 31325 const lastLine = sanitizedLines[sanitizedLines.length - 1]; 31326 if (CODE_SINGLE_LINE_REGEX.test(line)) { 31327 sanitizedLines.push(line); 31328 continue; 31329 } 31330 if (CODE_START_REGEX.test(line) || CODE_END_REGEX.test(line)) { 31331 inCodeBlock = !inCodeBlock; 31332 sanitizedLines.push(line); 31333 continue; 31334 } 31335 if (inCodeBlock) { 31336 sanitizedLines.push(rawLine); 31337 continue; 31338 } 31339 if (line === "" || lastLine === "" || !lastLine || HEADING_REGEX.test(lastLine) || HEADING_REGEX.test(line) || QUOTE_REGEX.test(line) || ORDERED_LIST_REGEX.test(line) || UNORDERED_LIST_REGEX.test(line) || CHECK_LIST_REGEX.test(line) || TABLE_ROW_REG_EXP.test(line) || TABLE_ROW_DIVIDER_REG_EXP.test(line) || !shouldMergeAdjacentLines || TAG_START_REGEX.test(line) || TAG_END_REGEX.test(line) || ENDS_WITH(TAG_END_REGEX).test(lastLine) || ENDS_WITH(TAG_START_REGEX).test(lastLine) || CODE_END_REGEX.test(lastLine)) { 31340 sanitizedLines.push(!shouldMergeAdjacentLines && line !== "" ? rawLine : line); 31341 } else { 31342 sanitizedLines[sanitizedLines.length - 1] = lastLine + " " + line.trimStart(); 31343 } 31344 } 31345 return sanitizedLines.join("\n"); 31346 } 31347 function runElementTransformers(parentNode, anchorNode, anchorOffset, elementTransformers) { 31348 const grandParentNode = parentNode.getParent(); 31349 if (!$isRootOrShadowRoot2(grandParentNode) || parentNode.getFirstChild() !== anchorNode) { 31350 return false; 31351 } 31352 const textContent = anchorNode.getTextContent(); 31353 if (textContent[anchorOffset - 1] !== " ") { 31354 return false; 31355 } 31356 for (const { 31357 regExp, 31358 replace 31359 } of elementTransformers) { 31360 const match = textContent.match(regExp); 31361 if (match && match[0].length === (match[0].endsWith(" ") ? anchorOffset : anchorOffset - 1)) { 31362 const nextSiblings = anchorNode.getNextSiblings(); 31363 const [leadingNode, remainderNode] = anchorNode.splitText(anchorOffset); 31364 const siblings = remainderNode ? [remainderNode, ...nextSiblings] : nextSiblings; 31365 if (replace(parentNode, siblings, match, false) !== false) { 31366 leadingNode.remove(); 31367 return true; 31368 } 31369 } 31370 } 31371 return false; 31372 } 31373 function runMultilineElementTransformers(parentNode, anchorNode, anchorOffset, elementTransformers, triggerOnEnter) { 31374 const grandParentNode = parentNode.getParent(); 31375 if (!$isRootOrShadowRoot2(grandParentNode) || parentNode.getFirstChild() !== anchorNode) { 31376 return false; 31377 } 31378 const textContent = anchorNode.getTextContent(); 31379 if (!triggerOnEnter) { 31380 if (textContent[anchorOffset - 1] !== " ") { 31381 return false; 31382 } 31383 } 31384 for (const { 31385 regExpStart, 31386 replace, 31387 regExpEnd 31388 } of elementTransformers) { 31389 if (regExpEnd && !("optional" in regExpEnd) || regExpEnd && "optional" in regExpEnd && !regExpEnd.optional) { 31390 continue; 31391 } 31392 const match = textContent.match(regExpStart); 31393 if (match) { 31394 const matchLength = triggerOnEnter || match[0].endsWith(" ") ? anchorOffset : anchorOffset - 1; 31395 if (match[0].length !== matchLength) { 31396 continue; 31397 } 31398 const nextSiblings = anchorNode.getNextSiblings(); 31399 const [leadingNode, remainderNode] = anchorNode.splitText(anchorOffset); 31400 const siblings = remainderNode ? [remainderNode, ...nextSiblings] : nextSiblings; 31401 if (replace(parentNode, siblings, match, null, null, false) !== false) { 31402 leadingNode.remove(); 31403 return true; 31404 } 31405 } 31406 } 31407 return false; 31408 } 31409 function runTextMatchTransformers(anchorNode, anchorOffset, transformersByTrigger) { 31410 let textContent = anchorNode.getTextContent(); 31411 const lastChar = textContent[anchorOffset - 1]; 31412 const transformers = transformersByTrigger[lastChar]; 31413 if (transformers == null) { 31414 return false; 31415 } 31416 if (anchorOffset < textContent.length) { 31417 textContent = textContent.slice(0, anchorOffset); 31418 } 31419 for (const transformer of transformers) { 31420 if (!transformer.replace || !transformer.regExp) { 31421 continue; 31422 } 31423 const match = textContent.match(transformer.regExp); 31424 if (match === null) { 31425 continue; 31426 } 31427 const startIndex = match.index || 0; 31428 const endIndex = startIndex + match[0].length; 31429 let replaceNode; 31430 if (startIndex === 0) { 31431 [replaceNode] = anchorNode.splitText(endIndex); 31432 } else { 31433 [, replaceNode] = anchorNode.splitText(startIndex, endIndex); 31434 } 31435 replaceNode.selectNext(0, 0); 31436 transformer.replace(replaceNode, match); 31437 return true; 31438 } 31439 return false; 31440 } 31441 function $runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransformers) { 31442 const textContent = anchorNode.getTextContent(); 31443 const closeTagEndIndex = anchorOffset - 1; 31444 const closeChar = textContent[closeTagEndIndex]; 31445 const matchers = textFormatTransformers[closeChar]; 31446 if (!matchers) { 31447 return false; 31448 } 31449 for (const matcher of matchers) { 31450 const { 31451 tag 31452 } = matcher; 31453 const tagLength = tag.length; 31454 const closeTagStartIndex = closeTagEndIndex - tagLength + 1; 31455 if (tagLength > 1) { 31456 if (!isEqualSubString(textContent, closeTagStartIndex, tag, 0, tagLength)) { 31457 continue; 31458 } 31459 } 31460 if (textContent[closeTagStartIndex - 1] === " ") { 31461 continue; 31462 } 31463 const afterCloseTagChar = textContent[closeTagEndIndex + 1]; 31464 if (matcher.intraword === false && afterCloseTagChar && !PUNCTUATION_OR_SPACE2.test(afterCloseTagChar)) { 31465 continue; 31466 } 31467 const closeNode = anchorNode; 31468 let openNode = closeNode; 31469 let openTagStartIndex = getOpenTagStartIndex(textContent, closeTagStartIndex, tag); 31470 let sibling = openNode; 31471 while (openTagStartIndex < 0 && (sibling = sibling.getPreviousSibling())) { 31472 if ($isLineBreakNode2(sibling)) { 31473 break; 31474 } 31475 if ($isTextNode2(sibling)) { 31476 if (sibling.hasFormat("code")) { 31477 continue; 31478 } 31479 const siblingTextContent = sibling.getTextContent(); 31480 openNode = sibling; 31481 openTagStartIndex = getOpenTagStartIndex(siblingTextContent, siblingTextContent.length, tag); 31482 } 31483 } 31484 if (openTagStartIndex < 0) { 31485 continue; 31486 } 31487 if (openNode === closeNode && openTagStartIndex + tagLength === closeTagStartIndex) { 31488 continue; 31489 } 31490 const prevOpenNodeText = openNode.getTextContent(); 31491 if (openTagStartIndex > 0 && prevOpenNodeText[openTagStartIndex - 1] === closeChar) { 31492 continue; 31493 } 31494 const beforeOpenTagChar = prevOpenNodeText[openTagStartIndex - 1]; 31495 if (matcher.intraword === false && beforeOpenTagChar && !PUNCTUATION_OR_SPACE2.test(beforeOpenTagChar)) { 31496 continue; 31497 } 31498 if (!matcher.format.includes("code") && $isInsideUnclosedCodeSpan(openNode, openTagStartIndex)) { 31499 continue; 31500 } 31501 const prevCloseNodeText = closeNode.getTextContent(); 31502 const closeNodeText = prevCloseNodeText.slice(0, closeTagStartIndex) + prevCloseNodeText.slice(closeTagEndIndex + 1); 31503 closeNode.setTextContent(closeNodeText); 31504 const openNodeText = openNode === closeNode ? closeNodeText : prevOpenNodeText; 31505 openNode.setTextContent(openNodeText.slice(0, openTagStartIndex) + openNodeText.slice(openTagStartIndex + tagLength)); 31506 const selection = $getSelection2(); 31507 const nextSelection = $createRangeSelection2(); 31508 $setSelection2(nextSelection); 31509 const newOffset = closeTagEndIndex - tagLength * (openNode === closeNode ? 2 : 1) + 1; 31510 nextSelection.anchor.set(openNode.__key, openTagStartIndex, "text"); 31511 nextSelection.focus.set(closeNode.__key, newOffset, "text"); 31512 for (const format of matcher.format) { 31513 if (!nextSelection.hasFormat(format)) { 31514 nextSelection.formatText(format); 31515 } 31516 } 31517 nextSelection.anchor.set(nextSelection.focus.key, nextSelection.focus.offset, nextSelection.focus.type); 31518 for (const format of matcher.format) { 31519 if (nextSelection.hasFormat(format)) { 31520 nextSelection.toggleFormat(format); 31521 } 31522 } 31523 if ($isRangeSelection2(selection)) { 31524 nextSelection.format = selection.format; 31525 } 31526 return true; 31527 } 31528 return false; 31529 } 31530 function $isInsideUnclosedCodeSpan(node, offset3) { 31531 let backtickCount = 0; 31532 const text2 = node.getTextContent(); 31533 for (let i2 = 0; i2 < offset3; i2++) { 31534 if (text2[i2] === "`") { 31535 backtickCount++; 31536 } 31537 } 31538 return backtickCount % 2 !== 0; 31539 } 31540 function getOpenTagStartIndex(string, maxIndex, tag) { 31541 const tagLength = tag.length; 31542 for (let i2 = maxIndex; i2 >= tagLength; i2--) { 31543 const startIndex = i2 - tagLength; 31544 if (isEqualSubString(string, startIndex, tag, 0, tagLength) && // Space after opening tag cancels transformation 31545 string[startIndex + tagLength] !== " ") { 31546 return startIndex; 31547 } 31548 } 31549 return -1; 31550 } 31551 function isEqualSubString(stringA, aStart, stringB, bStart, length) { 31552 for (let i2 = 0; i2 < length; i2++) { 31553 if (stringA[aStart + i2] !== stringB[bStart + i2]) { 31554 return false; 31555 } 31556 } 31557 return true; 31558 } 31559 function registerMarkdownShortcuts(editor, transformers = TRANSFORMERS) { 31560 const byType = transformersByType(transformers); 31561 const textFormatTransformersByTrigger = indexBy(byType.textFormat, ({ 31562 tag 31563 }) => tag[tag.length - 1]); 31564 const textMatchTransformersByTrigger = indexBy(byType.textMatch, ({ 31565 trigger 31566 }) => trigger); 31567 for (const transformer of transformers) { 31568 const type = transformer.type; 31569 if (type === "element" || type === "text-match" || type === "multiline-element") { 31570 const dependencies = transformer.dependencies; 31571 for (const node of dependencies) { 31572 if (!editor.hasNode(node)) { 31573 { 31574 formatDevErrorMessage11(`MarkdownShortcuts: missing dependency ${node.getType()} for transformer. Ensure node dependency is included in editor initial config.`); 31575 } 31576 } 31577 } 31578 } 31579 } 31580 const $transform = (parentNode, anchorNode, anchorOffset) => { 31581 if (runElementTransformers(parentNode, anchorNode, anchorOffset, byType.element)) { 31582 return true; 31583 } 31584 if (runMultilineElementTransformers(parentNode, anchorNode, anchorOffset, byType.multilineElement)) { 31585 return true; 31586 } 31587 if (runTextMatchTransformers(anchorNode, anchorOffset, textMatchTransformersByTrigger)) { 31588 return true; 31589 } 31590 if ($runTextFormatTransformers(anchorNode, anchorOffset, textFormatTransformersByTrigger)) { 31591 return true; 31592 } 31593 return false; 31594 }; 31595 return mergeRegister2(editor.registerUpdateListener(({ 31596 tags, 31597 dirtyLeaves, 31598 editorState, 31599 prevEditorState 31600 }) => { 31601 if (tags.has(COLLABORATION_TAG2) || tags.has(HISTORIC_TAG2)) { 31602 return; 31603 } 31604 if (editor.isComposing()) { 31605 return; 31606 } 31607 const selection = editorState.read($getSelection2); 31608 const prevSelection = prevEditorState.read($getSelection2); 31609 if (!$isRangeSelection2(prevSelection) || !$isRangeSelection2(selection) || !selection.isCollapsed() || selection.is(prevSelection)) { 31610 return; 31611 } 31612 const anchorKey = selection.anchor.key; 31613 const anchorOffset = selection.anchor.offset; 31614 const anchorNode = editorState._nodeMap.get(anchorKey); 31615 if (!$isTextNode2(anchorNode) || !dirtyLeaves.has(anchorKey) || anchorOffset !== 1 && anchorOffset > prevSelection.anchor.offset + 1) { 31616 return; 31617 } 31618 editor.update(() => { 31619 if (!canContainTransformableMarkdown(anchorNode)) { 31620 return; 31621 } 31622 const parentNode = anchorNode.getParent(); 31623 if (parentNode === null || $isCodeNode2(parentNode)) { 31624 return; 31625 } 31626 if ($transform(parentNode, anchorNode, selection.anchor.offset)) { 31627 $addUpdateTag2(HISTORY_PUSH_TAG2); 31628 } 31629 }); 31630 }), editor.registerCommand(KEY_ENTER_COMMAND2, (event) => { 31631 if (event !== null && event.shiftKey) { 31632 return false; 31633 } 31634 const selection = $getSelection2(); 31635 if (!$isRangeSelection2(selection) || !selection.isCollapsed()) { 31636 return false; 31637 } 31638 const anchorOffset = selection.anchor.offset; 31639 const anchorNode = selection.anchor.getNode(); 31640 if (!$isTextNode2(anchorNode) || !canContainTransformableMarkdown(anchorNode)) { 31641 return false; 31642 } 31643 const parentNode = anchorNode.getParent(); 31644 if (parentNode === null || $isCodeNode2(parentNode)) { 31645 return false; 31646 } 31647 const textContent = anchorNode.getTextContent(); 31648 if (anchorOffset !== textContent.length) { 31649 return false; 31650 } 31651 if (runMultilineElementTransformers(parentNode, anchorNode, anchorOffset, byType.multilineElement, true)) { 31652 if (event !== null) { 31653 event.preventDefault(); 31654 } 31655 return true; 31656 } 31657 return false; 31658 }, COMMAND_PRIORITY_LOW2)); 31659 } 31660 function $convertFromMarkdownString(markdown, transformers = TRANSFORMERS, node, shouldPreserveNewLines = false, shouldMergeAdjacentLines = false) { 31661 const sanitizedMarkdown = shouldPreserveNewLines ? markdown : normalizeMarkdown(markdown, shouldMergeAdjacentLines); 31662 const importMarkdown = createMarkdownImport(transformers, shouldPreserveNewLines); 31663 return importMarkdown(sanitizedMarkdown, node); 31664 } 31665 function $convertToMarkdownString(transformers = TRANSFORMERS, node, shouldPreserveNewLines = false) { 31666 const exportMarkdown = createMarkdownExport(transformers, shouldPreserveNewLines); 31667 return exportMarkdown(node); 31668 } 31669 31670
vendor: 1,296 bytes, lines 31670-31697
31670// node_modules/@lexical/markdown/LexicalMarkdown.mjs 31671 var mod16 = true ? LexicalMarkdown_dev_exports : LexicalMarkdown_prod_exports; 31672 var $convertFromMarkdownString2 = mod16.$convertFromMarkdownString; 31673 var $convertToMarkdownString2 = mod16.$convertToMarkdownString; 31674 var BOLD_ITALIC_STAR2 = mod16.BOLD_ITALIC_STAR; 31675 var BOLD_ITALIC_UNDERSCORE2 = mod16.BOLD_ITALIC_UNDERSCORE; 31676 var BOLD_STAR2 = mod16.BOLD_STAR; 31677 var BOLD_UNDERSCORE2 = mod16.BOLD_UNDERSCORE; 31678 var CHECK_LIST2 = mod16.CHECK_LIST; 31679 var CODE2 = mod16.CODE; 31680 var ELEMENT_TRANSFORMERS2 = mod16.ELEMENT_TRANSFORMERS; 31681 var HEADING2 = mod16.HEADING; 31682 var HIGHLIGHT2 = mod16.HIGHLIGHT; 31683 var INLINE_CODE2 = mod16.INLINE_CODE; 31684 var ITALIC_STAR2 = mod16.ITALIC_STAR; 31685 var ITALIC_UNDERSCORE2 = mod16.ITALIC_UNDERSCORE; 31686 var LINK2 = mod16.LINK; 31687 var MULTILINE_ELEMENT_TRANSFORMERS2 = mod16.MULTILINE_ELEMENT_TRANSFORMERS; 31688 var ORDERED_LIST2 = mod16.ORDERED_LIST; 31689 var QUOTE2 = mod16.QUOTE; 31690 var STRIKETHROUGH2 = mod16.STRIKETHROUGH; 31691 var TEXT_FORMAT_TRANSFORMERS2 = mod16.TEXT_FORMAT_TRANSFORMERS; 31692 var TEXT_MATCH_TRANSFORMERS2 = mod16.TEXT_MATCH_TRANSFORMERS; 31693 var TRANSFORMERS2 = mod16.TRANSFORMERS; 31694 var UNORDERED_LIST2 = mod16.UNORDERED_LIST; 31695 var registerMarkdownShortcuts2 = mod16.registerMarkdownShortcuts; 31696 31697
vendor: 165,474 bytes, lines 31697-35877
31697// node_modules/@lexical/table/LexicalTable.dev.mjs 31698 var LexicalTable_dev_exports = {}; 31699 __export(LexicalTable_dev_exports, { 31700 $computeTableMap: () => $computeTableMap, 31701 $computeTableMapSkipCellCheck: () => $computeTableMapSkipCellCheck, 31702 $createTableCellNode: () => $createTableCellNode, 31703 $createTableNode: () => $createTableNode, 31704 $createTableNodeWithDimensions: () => $createTableNodeWithDimensions, 31705 $createTableRowNode: () => $createTableRowNode, 31706 $createTableSelection: () => $createTableSelection, 31707 $createTableSelectionFrom: () => $createTableSelectionFrom, 31708 $deleteTableColumn: () => $deleteTableColumn, 31709 $deleteTableColumnAtSelection: () => $deleteTableColumnAtSelection, 31710 $deleteTableColumn__EXPERIMENTAL: () => $deleteTableColumn__EXPERIMENTAL, 31711 $deleteTableRowAtSelection: () => $deleteTableRowAtSelection, 31712 $deleteTableRow__EXPERIMENTAL: () => $deleteTableRow__EXPERIMENTAL, 31713 $findCellNode: () => $findCellNode, 31714 $findTableNode: () => $findTableNode, 31715 $getElementForTableNode: () => $getElementForTableNode, 31716 $getNodeTriplet: () => $getNodeTriplet, 31717 $getTableAndElementByKey: () => $getTableAndElementByKey, 31718 $getTableCellNodeFromLexicalNode: () => $getTableCellNodeFromLexicalNode, 31719 $getTableCellNodeRect: () => $getTableCellNodeRect, 31720 $getTableColumnIndexFromTableCellNode: () => $getTableColumnIndexFromTableCellNode, 31721 $getTableNodeFromLexicalNodeOrThrow: () => $getTableNodeFromLexicalNodeOrThrow, 31722 $getTableRowIndexFromTableCellNode: () => $getTableRowIndexFromTableCellNode, 31723 $getTableRowNodeFromTableCellNodeOrThrow: () => $getTableRowNodeFromTableCellNodeOrThrow, 31724 $insertTableColumn: () => $insertTableColumn, 31725 $insertTableColumnAtSelection: () => $insertTableColumnAtSelection, 31726 $insertTableColumn__EXPERIMENTAL: () => $insertTableColumn__EXPERIMENTAL, 31727 $insertTableRow: () => $insertTableRow, 31728 $insertTableRowAtSelection: () => $insertTableRowAtSelection, 31729 $insertTableRow__EXPERIMENTAL: () => $insertTableRow__EXPERIMENTAL, 31730 $isScrollableTablesActive: () => $isScrollableTablesActive, 31731 $isSimpleTable: () => $isSimpleTable, 31732 $isTableCellNode: () => $isTableCellNode, 31733 $isTableNode: () => $isTableNode, 31734 $isTableRowNode: () => $isTableRowNode, 31735 $isTableSelection: () => $isTableSelection, 31736 $mergeCells: () => $mergeCells, 31737 $moveTableColumn: () => $moveTableColumn, 31738 $removeTableRowAtIndex: () => $removeTableRowAtIndex, 31739 $unmergeCell: () => $unmergeCell, 31740 INSERT_TABLE_COMMAND: () => INSERT_TABLE_COMMAND, 31741 TableCellHeaderStates: () => TableCellHeaderStates, 31742 TableCellNode: () => TableCellNode, 31743 TableExtension: () => TableExtension, 31744 TableNode: () => TableNode, 31745 TableObserver: () => TableObserver, 31746 TableRowNode: () => TableRowNode, 31747 applyTableHandlers: () => applyTableHandlers, 31748 getDOMCellFromTarget: () => getDOMCellFromTarget, 31749 getTableElement: () => getTableElement, 31750 getTableObserverFromTableElement: () => getTableObserverFromTableElement, 31751 registerTableCellUnmergeTransform: () => registerTableCellUnmergeTransform, 31752 registerTablePlugin: () => registerTablePlugin, 31753 registerTableSelectionObserver: () => registerTableSelectionObserver, 31754 setScrollableTablesActive: () => setScrollableTablesActive 31755 }); 31756 var PIXEL_VALUE_REG_EXP = /^(\d+(?:\.\d+)?)px$/; 31757 var COLUMN_WIDTH = 75; 31758 var TableCellHeaderStates = { 31759 BOTH: 3, 31760 COLUMN: 2, 31761 NO_STATUS: 0, 31762 ROW: 1 31763 }; 31764 var TableCellNode = class _TableCellNode extends ElementNode2 { 31765 /** @internal */ 31766 __colSpan; 31767 /** @internal */ 31768 __rowSpan; 31769 /** @internal */ 31770 __headerState; 31771 /** @internal */ 31772 __width; 31773 /** @internal */ 31774 __backgroundColor; 31775 /** @internal */ 31776 __verticalAlign; 31777 static getType() { 31778 return "tablecell"; 31779 } 31780 static clone(node) { 31781 return new _TableCellNode(node.__headerState, node.__colSpan, node.__width, node.__key); 31782 } 31783 afterCloneFrom(node) { 31784 super.afterCloneFrom(node); 31785 this.__rowSpan = node.__rowSpan; 31786 this.__backgroundColor = node.__backgroundColor; 31787 this.__verticalAlign = node.__verticalAlign; 31788 this.__colSpan = node.__colSpan; 31789 this.__headerState = node.__headerState; 31790 this.__width = node.__width; 31791 } 31792 static importDOM() { 31793 return { 31794 td: (node) => ({ 31795 conversion: $convertTableCellNodeElement, 31796 priority: 0 31797 }), 31798 th: (node) => ({ 31799 conversion: $convertTableCellNodeElement, 31800 priority: 0 31801 }) 31802 }; 31803 } 31804 static importJSON(serializedNode) { 31805 return $createTableCellNode().updateFromJSON(serializedNode); 31806 } 31807 updateFromJSON(serializedNode) { 31808 return super.updateFromJSON(serializedNode).setHeaderStyles(serializedNode.headerState).setColSpan(serializedNode.colSpan || 1).setRowSpan(serializedNode.rowSpan || 1).setWidth(serializedNode.width || void 0).setBackgroundColor(serializedNode.backgroundColor || null).setVerticalAlign(serializedNode.verticalAlign || void 0); 31809 } 31810 constructor(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width, key) { 31811 super(key); 31812 this.__colSpan = colSpan; 31813 this.__rowSpan = 1; 31814 this.__headerState = headerState; 31815 this.__width = width; 31816 this.__backgroundColor = null; 31817 this.__verticalAlign = void 0; 31818 } 31819 createDOM(config) { 31820 const element = document.createElement(this.getTag()); 31821 if (this.__width) { 31822 element.style.width = `${this.__width}px`; 31823 } 31824 if (this.__colSpan > 1) { 31825 element.colSpan = this.__colSpan; 31826 } 31827 if (this.__rowSpan > 1) { 31828 element.rowSpan = this.__rowSpan; 31829 } 31830 if (this.__backgroundColor !== null) { 31831 element.style.backgroundColor = this.__backgroundColor; 31832 } 31833 if (isValidVerticalAlign(this.__verticalAlign)) { 31834 element.style.verticalAlign = this.__verticalAlign; 31835 } 31836 addClassNamesToElement3(element, config.theme.tableCell, this.hasHeader() && config.theme.tableCellHeader); 31837 return element; 31838 } 31839 exportDOM(editor) { 31840 const output = super.exportDOM(editor); 31841 if (isHTMLElement2(output.element)) { 31842 const element = output.element; 31843 element.setAttribute("data-temporary-table-cell-lexical-key", this.getKey()); 31844 element.style.border = "1px solid black"; 31845 if (this.__colSpan > 1) { 31846 element.colSpan = this.__colSpan; 31847 } 31848 if (this.__rowSpan > 1) { 31849 element.rowSpan = this.__rowSpan; 31850 } 31851 element.style.width = `${this.getWidth() || COLUMN_WIDTH}px`; 31852 element.style.verticalAlign = this.getVerticalAlign() || "top"; 31853 element.style.textAlign = "start"; 31854 if (this.__backgroundColor === null && this.hasHeader()) { 31855 element.style.backgroundColor = "#f2f3f5"; 31856 } 31857 } 31858 return output; 31859 } 31860 exportJSON() { 31861 return { 31862 ...super.exportJSON(), 31863 ...isValidVerticalAlign(this.__verticalAlign) && { 31864 verticalAlign: this.__verticalAlign 31865 }, 31866 backgroundColor: this.getBackgroundColor(), 31867 colSpan: this.__colSpan, 31868 headerState: this.__headerState, 31869 rowSpan: this.__rowSpan, 31870 width: this.getWidth() 31871 }; 31872 } 31873 getColSpan() { 31874 return this.getLatest().__colSpan; 31875 } 31876 setColSpan(colSpan) { 31877 const self2 = this.getWritable(); 31878 self2.__colSpan = colSpan; 31879 return self2; 31880 } 31881 getRowSpan() { 31882 return this.getLatest().__rowSpan; 31883 } 31884 setRowSpan(rowSpan) { 31885 const self2 = this.getWritable(); 31886 self2.__rowSpan = rowSpan; 31887 return self2; 31888 } 31889 getTag() { 31890 return this.hasHeader() ? "th" : "td"; 31891 } 31892 setHeaderStyles(headerState, mask = TableCellHeaderStates.BOTH) { 31893 const self2 = this.getWritable(); 31894 self2.__headerState = headerState & mask | self2.__headerState & ~mask; 31895 return self2; 31896 } 31897 getHeaderStyles() { 31898 return this.getLatest().__headerState; 31899 } 31900 setWidth(width) { 31901 const self2 = this.getWritable(); 31902 self2.__width = width; 31903 return self2; 31904 } 31905 getWidth() { 31906 return this.getLatest().__width; 31907 } 31908 getBackgroundColor() { 31909 return this.getLatest().__backgroundColor; 31910 } 31911 setBackgroundColor(newBackgroundColor) { 31912 const self2 = this.getWritable(); 31913 self2.__backgroundColor = newBackgroundColor; 31914 return self2; 31915 } 31916 getVerticalAlign() { 31917 return this.getLatest().__verticalAlign; 31918 } 31919 setVerticalAlign(newVerticalAlign) { 31920 const self2 = this.getWritable(); 31921 self2.__verticalAlign = newVerticalAlign || void 0; 31922 return self2; 31923 } 31924 toggleHeaderStyle(headerStateToToggle) { 31925 const self2 = this.getWritable(); 31926 if ((self2.__headerState & headerStateToToggle) === headerStateToToggle) { 31927 self2.__headerState -= headerStateToToggle; 31928 } else { 31929 self2.__headerState += headerStateToToggle; 31930 } 31931 return self2; 31932 } 31933 hasHeaderState(headerState) { 31934 return (this.getHeaderStyles() & headerState) === headerState; 31935 } 31936 hasHeader() { 31937 return this.getLatest().__headerState !== TableCellHeaderStates.NO_STATUS; 31938 } 31939 updateDOM(prevNode) { 31940 return prevNode.__headerState !== this.__headerState || prevNode.__width !== this.__width || prevNode.__colSpan !== this.__colSpan || prevNode.__rowSpan !== this.__rowSpan || prevNode.__backgroundColor !== this.__backgroundColor || prevNode.__verticalAlign !== this.__verticalAlign; 31941 } 31942 isShadowRoot() { 31943 return true; 31944 } 31945 collapseAtStart() { 31946 return true; 31947 } 31948 canBeEmpty() { 31949 return false; 31950 } 31951 canIndent() { 31952 return false; 31953 } 31954 }; 31955 function isValidVerticalAlign(verticalAlign) { 31956 return verticalAlign === "middle" || verticalAlign === "bottom"; 31957 } 31958 function $convertTableCellNodeElement(domNode) { 31959 const domNode_ = domNode; 31960 const nodeName = domNode.nodeName.toLowerCase(); 31961 let width = void 0; 31962 if (PIXEL_VALUE_REG_EXP.test(domNode_.style.width)) { 31963 width = parseFloat(domNode_.style.width); 31964 } 31965 let headerState = TableCellHeaderStates.NO_STATUS; 31966 if (nodeName === "th") { 31967 const scope = domNode_.getAttribute("scope"); 31968 if (scope === "col") { 31969 headerState = TableCellHeaderStates.COLUMN; 31970 } else if (scope === "row") { 31971 headerState = TableCellHeaderStates.ROW; 31972 } else { 31973 const parentRow = domNode_.parentElement; 31974 const isInHeaderRow = isHTMLElement2(parentRow) && parentRow.nodeName.toLowerCase() === "tr" && isHTMLElement2(parentRow.parentElement) && (parentRow.parentElement.nodeName.toLowerCase() === "thead" || parentRow.rowIndex === 0); 31975 const isFirstColumn = domNode_.cellIndex === 0; 31976 if (isInHeaderRow) { 31977 headerState |= TableCellHeaderStates.ROW; 31978 } 31979 if (isFirstColumn) { 31980 headerState |= TableCellHeaderStates.COLUMN; 31981 } 31982 if (headerState === TableCellHeaderStates.NO_STATUS) { 31983 headerState = TableCellHeaderStates.ROW; 31984 } 31985 } 31986 } 31987 const tableCellNode = $createTableCellNode(headerState, domNode_.colSpan, width); 31988 tableCellNode.__rowSpan = domNode_.rowSpan; 31989 const backgroundColor = domNode_.style.backgroundColor; 31990 if (backgroundColor !== "") { 31991 tableCellNode.__backgroundColor = backgroundColor; 31992 } 31993 const verticalAlign = domNode_.style.verticalAlign; 31994 if (isValidVerticalAlign(verticalAlign)) { 31995 tableCellNode.__verticalAlign = verticalAlign; 31996 } 31997 const style = domNode_.style; 31998 const textDecoration = (style && style.textDecoration || "").split(" "); 31999 const hasBoldFontWeight = style.fontWeight === "700" || style.fontWeight === "bold"; 32000 const hasLinethroughTextDecoration = textDecoration.includes("line-through"); 32001 const hasItalicFontStyle = style.fontStyle === "italic"; 32002 const hasUnderlineTextDecoration = textDecoration.includes("underline"); 32003 const color = style.color; 32004 return { 32005 after: (childLexicalNodes) => { 32006 const result = []; 32007 let paragraphNode = null; 32008 const removeSingleLineBreakNode = () => { 32009 if (paragraphNode) { 32010 const firstChild = paragraphNode.getFirstChild(); 32011 if ($isLineBreakNode2(firstChild) && paragraphNode.getChildrenSize() === 1) { 32012 firstChild.remove(); 32013 } 32014 } 32015 }; 32016 for (const child of childLexicalNodes) { 32017 if ($isInlineElementOrDecoratorNode2(child) || $isTextNode2(child) || $isLineBreakNode2(child)) { 32018 if ($isTextNode2(child)) { 32019 if (hasBoldFontWeight) { 32020 child.toggleFormat("bold"); 32021 } 32022 if (hasLinethroughTextDecoration) { 32023 child.toggleFormat("strikethrough"); 32024 } 32025 if (hasItalicFontStyle) { 32026 child.toggleFormat("italic"); 32027 } 32028 if (hasUnderlineTextDecoration) { 32029 child.toggleFormat("underline"); 32030 } 32031 if (color) { 32032 const existingStyle = child.getStyle(); 32033 if (!existingStyle.includes("color:")) { 32034 child.setStyle(existingStyle + `color: ${color};`); 32035 } 32036 } 32037 } 32038 if (paragraphNode) { 32039 paragraphNode.append(child); 32040 } else { 32041 paragraphNode = $createParagraphNode2().append(child); 32042 result.push(paragraphNode); 32043 } 32044 } else { 32045 result.push(child); 32046 removeSingleLineBreakNode(); 32047 paragraphNode = null; 32048 } 32049 } 32050 removeSingleLineBreakNode(); 32051 if (result.length === 0) { 32052 result.push($createParagraphNode2()); 32053 } 32054 return result; 32055 }, 32056 node: tableCellNode 32057 }; 32058 } 32059 function $createTableCellNode(headerState = TableCellHeaderStates.NO_STATUS, colSpan = 1, width) { 32060 return $applyNodeReplacement2(new TableCellNode(headerState, colSpan, width)); 32061 } 32062 function $isTableCellNode(node) { 32063 return node instanceof TableCellNode; 32064 } 32065 var INSERT_TABLE_COMMAND = createCommand2("INSERT_TABLE_COMMAND"); 32066 function formatDevErrorMessage12(message) { 32067 throw new Error(message); 32068 } 32069 var TableRowNode = class _TableRowNode extends ElementNode2 { 32070 /** @internal */ 32071 __height; 32072 static getType() { 32073 return "tablerow"; 32074 } 32075 static clone(node) { 32076 return new _TableRowNode(node.__height, node.__key); 32077 } 32078 afterCloneFrom(prevNode) { 32079 super.afterCloneFrom(prevNode); 32080 this.__height = prevNode.__height; 32081 } 32082 static importDOM() { 32083 return { 32084 tr: (node) => ({ 32085 conversion: $convertTableRowElement, 32086 priority: 0 32087 }) 32088 }; 32089 } 32090 static importJSON(serializedNode) { 32091 return $createTableRowNode().updateFromJSON(serializedNode); 32092 } 32093 updateFromJSON(serializedNode) { 32094 return super.updateFromJSON(serializedNode).setHeight(serializedNode.height); 32095 } 32096 constructor(height, key) { 32097 super(key); 32098 this.__height = height; 32099 } 32100 exportJSON() { 32101 const height = this.getHeight(); 32102 return { 32103 ...super.exportJSON(), 32104 ...height === void 0 ? void 0 : { 32105 height 32106 } 32107 }; 32108 } 32109 createDOM(config) { 32110 const element = document.createElement("tr"); 32111 if (this.__height) { 32112 element.style.height = `${this.__height}px`; 32113 } 32114 addClassNamesToElement3(element, config.theme.tableRow); 32115 return element; 32116 } 32117 extractWithChild(child, selection, destination) { 32118 return destination === "html"; 32119 } 32120 isShadowRoot() { 32121 return true; 32122 } 32123 setHeight(height) { 32124 const self2 = this.getWritable(); 32125 self2.__height = height; 32126 return self2; 32127 } 32128 getHeight() { 32129 return this.getLatest().__height; 32130 } 32131 updateDOM(prevNode) { 32132 return prevNode.__height !== this.__height; 32133 } 32134 canBeEmpty() { 32135 return false; 32136 } 32137 canIndent() { 32138 return false; 32139 } 32140 }; 32141 function $convertTableRowElement(domNode) { 32142 const domNode_ = domNode; 32143 let height = void 0; 32144 if (PIXEL_VALUE_REG_EXP.test(domNode_.style.height)) { 32145 height = parseFloat(domNode_.style.height); 32146 } 32147 return { 32148 after: (children) => $descendantsMatching2(children, $isTableCellNode), 32149 node: $createTableRowNode(height) 32150 }; 32151 } 32152 function $createTableRowNode(height) { 32153 return $applyNodeReplacement2(new TableRowNode(height)); 32154 } 32155 function $isTableRowNode(node) { 32156 return node instanceof TableRowNode; 32157 } 32158 var CAN_USE_DOM6 = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined"; 32159 var documentMode5 = CAN_USE_DOM6 && "documentMode" in document ? document.documentMode : null; 32160 var IS_FIREFOX4 = CAN_USE_DOM6 && /^(?!.*Seamonkey)(?=.*Firefox).*/i.test(navigator.userAgent); 32161 CAN_USE_DOM6 && "InputEvent" in window && !documentMode5 ? "getTargetRanges" in new window.InputEvent("input") : false; 32162 function $createTableNodeWithDimensions(rowCount, columnCount, includeHeaders = true) { 32163 const tableNode = $createTableNode(); 32164 for (let iRow = 0; iRow < rowCount; iRow++) { 32165 const tableRowNode = $createTableRowNode(); 32166 for (let iColumn = 0; iColumn < columnCount; iColumn++) { 32167 let headerState = TableCellHeaderStates.NO_STATUS; 32168 if (typeof includeHeaders === "object") { 32169 if (iRow === 0 && includeHeaders.rows) { 32170 headerState |= TableCellHeaderStates.ROW; 32171 } 32172 if (iColumn === 0 && includeHeaders.columns) { 32173 headerState |= TableCellHeaderStates.COLUMN; 32174 } 32175 } else if (includeHeaders) { 32176 if (iRow === 0) { 32177 headerState |= TableCellHeaderStates.ROW; 32178 } 32179 if (iColumn === 0) { 32180 headerState |= TableCellHeaderStates.COLUMN; 32181 } 32182 } 32183 const tableCellNode = $createTableCellNode(headerState); 32184 const paragraphNode = $createParagraphNode2(); 32185 paragraphNode.append($createTextNode2()); 32186 tableCellNode.append(paragraphNode); 32187 tableRowNode.append(tableCellNode); 32188 } 32189 tableNode.append(tableRowNode); 32190 } 32191 return tableNode; 32192 } 32193 function $getTableCellNodeFromLexicalNode(startingNode) { 32194 const node = $findMatchingParent3(startingNode, (n2) => $isTableCellNode(n2)); 32195 if ($isTableCellNode(node)) { 32196 return node; 32197 } 32198 return null; 32199 } 32200 function $getTableRowNodeFromTableCellNodeOrThrow(startingNode) { 32201 const node = $findMatchingParent3(startingNode, (n2) => $isTableRowNode(n2)); 32202 if ($isTableRowNode(node)) { 32203 return node; 32204 } 32205 throw new Error("Expected table cell to be inside of table row."); 32206 } 32207 function $getTableNodeFromLexicalNodeOrThrow(startingNode) { 32208 const node = $findMatchingParent3(startingNode, (n2) => $isTableNode(n2)); 32209 if ($isTableNode(node)) { 32210 return node; 32211 } 32212 throw new Error("Expected table cell to be inside of table."); 32213 } 32214 function $getTableRowIndexFromTableCellNode(tableCellNode) { 32215 const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode); 32216 const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableRowNode); 32217 return tableNode.getChildren().findIndex((n2) => n2.is(tableRowNode)); 32218 } 32219 function $getTableColumnIndexFromTableCellNode(tableCellNode) { 32220 const tableRowNode = $getTableRowNodeFromTableCellNodeOrThrow(tableCellNode); 32221 return tableRowNode.getChildren().findIndex((n2) => n2.is(tableCellNode)); 32222 } 32223 function $getTableCellSiblingsFromTableCellNode(tableCellNode, table) { 32224 const tableNode = $getTableNodeFromLexicalNodeOrThrow(tableCellNode); 32225 const { 32226 x: x3, 32227 y: y3 32228 } = tableNode.getCordsFromCellNode(tableCellNode, table); 32229 return { 32230 above: tableNode.getCellNodeFromCords(x3, y3 - 1, table), 32231 below: tableNode.getCellNodeFromCords(x3, y3 + 1, table), 32232 left: tableNode.getCellNodeFromCords(x3 - 1, y3, table), 32233 right: tableNode.getCellNodeFromCords(x3 + 1, y3, table) 32234 }; 32235 } 32236 function $removeTableRowAtIndex(tableNode, indexToDelete) { 32237 const tableRows = tableNode.getChildren(); 32238 if (indexToDelete >= tableRows.length || indexToDelete < 0) { 32239 throw new Error("Expected table cell to be inside of table row."); 32240 } 32241 const targetRowNode = tableRows[indexToDelete]; 32242 targetRowNode.remove(); 32243 return tableNode; 32244 } 32245 function $insertTableRow(tableNode, targetIndex, shouldInsertAfter = true, rowCount, table) { 32246 const tableRows = tableNode.getChildren(); 32247 if (targetIndex >= tableRows.length || targetIndex < 0) { 32248 throw new Error("Table row target index out of range"); 32249 } 32250 const targetRowNode = tableRows[targetIndex]; 32251 if ($isTableRowNode(targetRowNode)) { 32252 for (let r2 = 0; r2 < rowCount; r2++) { 32253 const tableRowCells = targetRowNode.getChildren(); 32254 const tableColumnCount = tableRowCells.length; 32255 const newTableRowNode = $createTableRowNode(); 32256 for (let c2 = 0; c2 < tableColumnCount; c2++) { 32257 const tableCellFromTargetRow = tableRowCells[c2]; 32258 if (!$isTableCellNode(tableCellFromTargetRow)) { 32259 formatDevErrorMessage12(`Expected table cell`); 32260 } 32261 const { 32262 above, 32263 below 32264 } = $getTableCellSiblingsFromTableCellNode(tableCellFromTargetRow, table); 32265 let headerState = TableCellHeaderStates.NO_STATUS; 32266 const width = above && above.getWidth() || below && below.getWidth() || void 0; 32267 if (above && above.hasHeaderState(TableCellHeaderStates.COLUMN) || below && below.hasHeaderState(TableCellHeaderStates.COLUMN)) { 32268 headerState |= TableCellHeaderStates.COLUMN; 32269 } 32270 const tableCellNode = $createTableCellNode(headerState, 1, width); 32271 tableCellNode.append($createParagraphNode2()); 32272 newTableRowNode.append(tableCellNode); 32273 } 32274 if (shouldInsertAfter) { 32275 targetRowNode.insertAfter(newTableRowNode); 32276 } else { 32277 targetRowNode.insertBefore(newTableRowNode); 32278 } 32279 } 32280 } else { 32281 throw new Error("Row before insertion index does not exist."); 32282 } 32283 return tableNode; 32284 } 32285 var getHeaderState = (currentState, possibleState) => { 32286 if (currentState === TableCellHeaderStates.BOTH || currentState === possibleState) { 32287 return possibleState; 32288 } 32289 return TableCellHeaderStates.NO_STATUS; 32290 }; 32291 function $insertTableRowAtSelection(insertAfter = true) { 32292 const selection = $getSelection2(); 32293 if (!($isRangeSelection2(selection) || $isTableSelection(selection))) { 32294 formatDevErrorMessage12(`Expected a RangeSelection or TableSelection`); 32295 } 32296 const anchor = selection.anchor.getNode(); 32297 const focus = selection.focus.getNode(); 32298 const [anchorCell] = $getNodeTriplet(anchor); 32299 const [focusCell, , grid] = $getNodeTriplet(focus); 32300 const [, focusCellMap, anchorCellMap] = $computeTableMap(grid, focusCell, anchorCell); 32301 const { 32302 startRow: anchorStartRow 32303 } = anchorCellMap; 32304 const { 32305 startRow: focusStartRow 32306 } = focusCellMap; 32307 if (insertAfter) { 32308 return $insertTableRowAtNode(anchorStartRow + anchorCell.__rowSpan > focusStartRow + focusCell.__rowSpan ? anchorCell : focusCell, true); 32309 } else { 32310 return $insertTableRowAtNode(focusStartRow < anchorStartRow ? focusCell : anchorCell, false); 32311 } 32312 } 32313 var $insertTableRow__EXPERIMENTAL = $insertTableRowAtSelection; 32314 function $insertTableRowAtNode(cellNode, insertAfter = true) { 32315 const [, , grid] = $getNodeTriplet(cellNode); 32316 const [gridMap, cellMap] = $computeTableMap(grid, cellNode, cellNode); 32317 const columnCount = gridMap[0].length; 32318 const { 32319 startRow: cellStartRow 32320 } = cellMap; 32321 let insertedRow = null; 32322 if (insertAfter) { 32323 const insertAfterEndRow = cellStartRow + cellNode.__rowSpan - 1; 32324 const insertAfterEndRowMap = gridMap[insertAfterEndRow]; 32325 const newRow = $createTableRowNode(); 32326 for (let i2 = 0; i2 < columnCount; i2++) { 32327 const { 32328 cell, 32329 startRow 32330 } = insertAfterEndRowMap[i2]; 32331 if (startRow + cell.__rowSpan - 1 <= insertAfterEndRow) { 32332 const currentCell = insertAfterEndRowMap[i2].cell; 32333 const currentCellHeaderState = currentCell.__headerState; 32334 const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.COLUMN); 32335 newRow.append($createTableCellNode(headerState).append($createParagraphNode2())); 32336 } else { 32337 cell.setRowSpan(cell.__rowSpan + 1); 32338 } 32339 } 32340 const insertAfterEndRowNode = grid.getChildAtIndex(insertAfterEndRow); 32341 if (!$isTableRowNode(insertAfterEndRowNode)) { 32342 formatDevErrorMessage12(`insertAfterEndRow is not a TableRowNode`); 32343 } 32344 insertAfterEndRowNode.insertAfter(newRow); 32345 insertedRow = newRow; 32346 } else { 32347 const insertBeforeStartRow = cellStartRow; 32348 const insertBeforeStartRowMap = gridMap[insertBeforeStartRow]; 32349 const newRow = $createTableRowNode(); 32350 for (let i2 = 0; i2 < columnCount; i2++) { 32351 const { 32352 cell, 32353 startRow 32354 } = insertBeforeStartRowMap[i2]; 32355 if (startRow === insertBeforeStartRow) { 32356 const currentCell = insertBeforeStartRowMap[i2].cell; 32357 const currentCellHeaderState = currentCell.__headerState; 32358 const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.COLUMN); 32359 newRow.append($createTableCellNode(headerState).append($createParagraphNode2())); 32360 } else { 32361 cell.setRowSpan(cell.__rowSpan + 1); 32362 } 32363 } 32364 const insertBeforeStartRowNode = grid.getChildAtIndex(insertBeforeStartRow); 32365 if (!$isTableRowNode(insertBeforeStartRowNode)) { 32366 formatDevErrorMessage12(`insertBeforeStartRow is not a TableRowNode`); 32367 } 32368 insertBeforeStartRowNode.insertBefore(newRow); 32369 insertedRow = newRow; 32370 } 32371 return insertedRow; 32372 } 32373 function $insertTableColumn(tableNode, targetIndex, shouldInsertAfter = true, columnCount, table) { 32374 const tableRows = tableNode.getChildren(); 32375 const tableCellsToBeInserted = []; 32376 for (let r2 = 0; r2 < tableRows.length; r2++) { 32377 const currentTableRowNode = tableRows[r2]; 32378 if ($isTableRowNode(currentTableRowNode)) { 32379 for (let c2 = 0; c2 < columnCount; c2++) { 32380 const tableRowChildren = currentTableRowNode.getChildren(); 32381 if (targetIndex >= tableRowChildren.length || targetIndex < 0) { 32382 throw new Error("Table column target index out of range"); 32383 } 32384 const targetCell = tableRowChildren[targetIndex]; 32385 if (!$isTableCellNode(targetCell)) { 32386 formatDevErrorMessage12(`Expected table cell`); 32387 } 32388 const { 32389 left, 32390 right 32391 } = $getTableCellSiblingsFromTableCellNode(targetCell, table); 32392 let headerState = TableCellHeaderStates.NO_STATUS; 32393 if (left && left.hasHeaderState(TableCellHeaderStates.ROW) || right && right.hasHeaderState(TableCellHeaderStates.ROW)) { 32394 headerState |= TableCellHeaderStates.ROW; 32395 } 32396 const newTableCell = $createTableCellNode(headerState); 32397 newTableCell.append($createParagraphNode2()); 32398 tableCellsToBeInserted.push({ 32399 newTableCell, 32400 targetCell 32401 }); 32402 } 32403 } 32404 } 32405 tableCellsToBeInserted.forEach(({ 32406 newTableCell, 32407 targetCell 32408 }) => { 32409 if (shouldInsertAfter) { 32410 targetCell.insertAfter(newTableCell); 32411 } else { 32412 targetCell.insertBefore(newTableCell); 32413 } 32414 }); 32415 return tableNode; 32416 } 32417 function $insertTableColumnAtSelection(insertAfter = true) { 32418 const selection = $getSelection2(); 32419 if (!($isRangeSelection2(selection) || $isTableSelection(selection))) { 32420 formatDevErrorMessage12(`Expected a RangeSelection or TableSelection`); 32421 } 32422 const anchor = selection.anchor.getNode(); 32423 const focus = selection.focus.getNode(); 32424 const [anchorCell] = $getNodeTriplet(anchor); 32425 const [focusCell, , grid] = $getNodeTriplet(focus); 32426 const [, focusCellMap, anchorCellMap] = $computeTableMap(grid, focusCell, anchorCell); 32427 const { 32428 startColumn: anchorStartColumn 32429 } = anchorCellMap; 32430 const { 32431 startColumn: focusStartColumn 32432 } = focusCellMap; 32433 if (insertAfter) { 32434 return $insertTableColumnAtNode(anchorStartColumn + anchorCell.__colSpan > focusStartColumn + focusCell.__colSpan ? anchorCell : focusCell, true); 32435 } else { 32436 return $insertTableColumnAtNode(focusStartColumn < anchorStartColumn ? focusCell : anchorCell, false); 32437 } 32438 } 32439 var $insertTableColumn__EXPERIMENTAL = $insertTableColumnAtSelection; 32440 function $insertTableColumnAtNode(cellNode, insertAfter = true, shouldSetSelection = true) { 32441 const [, , grid] = $getNodeTriplet(cellNode); 32442 const [gridMap, cellMap] = $computeTableMap(grid, cellNode, cellNode); 32443 const rowCount = gridMap.length; 32444 const { 32445 startColumn 32446 } = cellMap; 32447 const insertAfterColumn = insertAfter ? startColumn + cellNode.__colSpan - 1 : startColumn - 1; 32448 const gridFirstChild = grid.getFirstChild(); 32449 if (!$isTableRowNode(gridFirstChild)) { 32450 formatDevErrorMessage12(`Expected firstTable child to be a row`); 32451 } 32452 let firstInsertedCell = null; 32453 function $createTableCellNodeForInsertTableColumn(headerState = TableCellHeaderStates.NO_STATUS) { 32454 const cell = $createTableCellNode(headerState).append($createParagraphNode2()); 32455 if (firstInsertedCell === null) { 32456 firstInsertedCell = cell; 32457 } 32458 return cell; 32459 } 32460 let loopRow = gridFirstChild; 32461 rowLoop: for (let i2 = 0; i2 < rowCount; i2++) { 32462 if (i2 !== 0) { 32463 const currentRow = loopRow.getNextSibling(); 32464 if (!$isTableRowNode(currentRow)) { 32465 formatDevErrorMessage12(`Expected row nextSibling to be a row`); 32466 } 32467 loopRow = currentRow; 32468 } 32469 const rowMap = gridMap[i2]; 32470 const currentCellHeaderState = rowMap[insertAfterColumn < 0 ? 0 : insertAfterColumn].cell.__headerState; 32471 const headerState = getHeaderState(currentCellHeaderState, TableCellHeaderStates.ROW); 32472 if (insertAfterColumn < 0) { 32473 $insertFirst3(loopRow, $createTableCellNodeForInsertTableColumn(headerState)); 32474 continue; 32475 } 32476 const { 32477 cell: currentCell, 32478 startColumn: currentStartColumn, 32479 startRow: currentStartRow 32480 } = rowMap[insertAfterColumn]; 32481 if (currentStartColumn + currentCell.__colSpan - 1 <= insertAfterColumn) { 32482 let insertAfterCell = currentCell; 32483 let insertAfterCellRowStart = currentStartRow; 32484 let prevCellIndex = insertAfterColumn; 32485 while (insertAfterCellRowStart !== i2 && insertAfterCell.__rowSpan > 1) { 32486 prevCellIndex -= currentCell.__colSpan; 32487 if (prevCellIndex >= 0) { 32488 const { 32489 cell: cell_, 32490 startRow: startRow_ 32491 } = rowMap[prevCellIndex]; 32492 insertAfterCell = cell_; 32493 insertAfterCellRowStart = startRow_; 32494 } else { 32495 loopRow.append($createTableCellNodeForInsertTableColumn(headerState)); 32496 continue rowLoop; 32497 } 32498 } 32499 insertAfterCell.insertAfter($createTableCellNodeForInsertTableColumn(headerState)); 32500 } else { 32501 currentCell.setColSpan(currentCell.__colSpan + 1); 32502 } 32503 } 32504 if (firstInsertedCell !== null && shouldSetSelection) { 32505 $moveSelectionToCell(firstInsertedCell); 32506 } 32507 const colWidths = grid.getColWidths(); 32508 if (colWidths) { 32509 const newColWidths = [...colWidths]; 32510 const columnIndex = insertAfterColumn < 0 ? 0 : insertAfterColumn; 32511 const newWidth = newColWidths[columnIndex]; 32512 newColWidths.splice(columnIndex, 0, newWidth); 32513 grid.setColWidths(newColWidths); 32514 } 32515 return firstInsertedCell; 32516 } 32517 function $deleteTableColumn(tableNode, targetIndex) { 32518 const tableRows = tableNode.getChildren(); 32519 for (let i2 = 0; i2 < tableRows.length; i2++) { 32520 const currentTableRowNode = tableRows[i2]; 32521 if ($isTableRowNode(currentTableRowNode)) { 32522 const tableRowChildren = currentTableRowNode.getChildren(); 32523 if (targetIndex >= tableRowChildren.length || targetIndex < 0) { 32524 throw new Error("Table column target index out of range"); 32525 } 32526 tableRowChildren[targetIndex].remove(); 32527 } 32528 } 32529 return tableNode; 32530 } 32531 function $deleteTableRowAtSelection() { 32532 const selection = $getSelection2(); 32533 if (!($isRangeSelection2(selection) || $isTableSelection(selection))) { 32534 formatDevErrorMessage12(`Expected a RangeSelection or TableSelection`); 32535 } 32536 const [anchor, focus] = selection.isBackward() ? [selection.focus.getNode(), selection.anchor.getNode()] : [selection.anchor.getNode(), selection.focus.getNode()]; 32537 const [anchorCell, , grid] = $getNodeTriplet(anchor); 32538 const [focusCell] = $getNodeTriplet(focus); 32539 const [gridMap, anchorCellMap, focusCellMap] = $computeTableMap(grid, anchorCell, focusCell); 32540 const { 32541 startRow: anchorStartRow 32542 } = anchorCellMap; 32543 const { 32544 startRow: focusStartRow 32545 } = focusCellMap; 32546 const focusEndRow = focusStartRow + focusCell.__rowSpan - 1; 32547 if (gridMap.length === focusEndRow - anchorStartRow + 1) { 32548 grid.remove(); 32549 return; 32550 } 32551 const columnCount = gridMap[0].length; 32552 const nextRow = gridMap[focusEndRow + 1]; 32553 const nextRowNode = grid.getChildAtIndex(focusEndRow + 1); 32554 for (let row = focusEndRow; row >= anchorStartRow; row--) { 32555 for (let column = columnCount - 1; column >= 0; column--) { 32556 const { 32557 cell, 32558 startRow: cellStartRow, 32559 startColumn: cellStartColumn 32560 } = gridMap[row][column]; 32561 if (cellStartColumn !== column) { 32562 continue; 32563 } 32564 if (cellStartRow < anchorStartRow || cellStartRow + cell.__rowSpan - 1 > focusEndRow) { 32565 const intersectionStart = Math.max(cellStartRow, anchorStartRow); 32566 const intersectionEnd = Math.min(cell.__rowSpan + cellStartRow - 1, focusEndRow); 32567 const overflowRowsCount = intersectionStart <= intersectionEnd ? intersectionEnd - intersectionStart + 1 : 0; 32568 cell.setRowSpan(cell.__rowSpan - overflowRowsCount); 32569 } 32570 if (cellStartRow >= anchorStartRow && cellStartRow + cell.__rowSpan - 1 > focusEndRow && // Handle overflow only once 32571 row === focusEndRow) { 32572 if (!(nextRowNode !== null)) { 32573 formatDevErrorMessage12(`Expected nextRowNode not to be null`); 32574 } 32575 let insertAfterCell = null; 32576 for (let columnIndex = 0; columnIndex < column; columnIndex++) { 32577 const currentCellMap = nextRow[columnIndex]; 32578 const currentCell = currentCellMap.cell; 32579 if (currentCellMap.startRow === row + 1) { 32580 insertAfterCell = currentCell; 32581 } 32582 if (currentCell.__colSpan > 1) { 32583 columnIndex += currentCell.__colSpan - 1; 32584 } 32585 } 32586 if (insertAfterCell === null) { 32587 $insertFirst3(nextRowNode, cell); 32588 } else { 32589 insertAfterCell.insertAfter(cell); 32590 } 32591 } 32592 } 32593 const rowNode = grid.getChildAtIndex(row); 32594 if (!$isTableRowNode(rowNode)) { 32595 formatDevErrorMessage12(`Expected TableNode childAtIndex(${String(row)}) to be RowNode`); 32596 } 32597 rowNode.remove(); 32598 } 32599 if (nextRow !== void 0) { 32600 const { 32601 cell 32602 } = nextRow[0]; 32603 $moveSelectionToCell(cell); 32604 } else { 32605 const previousRow = gridMap[anchorStartRow - 1]; 32606 const { 32607 cell 32608 } = previousRow[0]; 32609 $moveSelectionToCell(cell); 32610 } 32611 } 32612 var $deleteTableRow__EXPERIMENTAL = $deleteTableRowAtSelection; 32613 function $deleteTableColumnAtSelection() { 32614 const selection = $getSelection2(); 32615 if (!($isRangeSelection2(selection) || $isTableSelection(selection))) { 32616 formatDevErrorMessage12(`Expected a RangeSelection or TableSelection`); 32617 } 32618 const anchor = selection.anchor.getNode(); 32619 const focus = selection.focus.getNode(); 32620 const [anchorCell, , grid] = $getNodeTriplet(anchor); 32621 const [focusCell] = $getNodeTriplet(focus); 32622 const [gridMap, anchorCellMap, focusCellMap] = $computeTableMap(grid, anchorCell, focusCell); 32623 const { 32624 startColumn: anchorStartColumn 32625 } = anchorCellMap; 32626 const { 32627 startRow: focusStartRow, 32628 startColumn: focusStartColumn 32629 } = focusCellMap; 32630 const startColumn = Math.min(anchorStartColumn, focusStartColumn); 32631 const endColumn = Math.max(anchorStartColumn + anchorCell.__colSpan - 1, focusStartColumn + focusCell.__colSpan - 1); 32632 const selectedColumnCount = endColumn - startColumn + 1; 32633 const columnCount = gridMap[0].length; 32634 if (columnCount === endColumn - startColumn + 1) { 32635 grid.selectPrevious(); 32636 grid.remove(); 32637 return; 32638 } 32639 const rowCount = gridMap.length; 32640 for (let row = 0; row < rowCount; row++) { 32641 for (let column = startColumn; column <= endColumn; column++) { 32642 const { 32643 cell, 32644 startColumn: cellStartColumn 32645 } = gridMap[row][column]; 32646 if (cellStartColumn < startColumn) { 32647 if (column === startColumn) { 32648 const overflowLeft = startColumn - cellStartColumn; 32649 cell.setColSpan(cell.__colSpan - // Possible overflow right too 32650 Math.min(selectedColumnCount, cell.__colSpan - overflowLeft)); 32651 } 32652 } else if (cellStartColumn + cell.__colSpan - 1 > endColumn) { 32653 if (column === endColumn) { 32654 const inSelectedArea = endColumn - cellStartColumn + 1; 32655 cell.setColSpan(cell.__colSpan - inSelectedArea); 32656 } 32657 } else { 32658 cell.remove(); 32659 } 32660 } 32661 } 32662 const focusRowMap = gridMap[focusStartRow]; 32663 const nextColumn = anchorStartColumn > focusStartColumn ? focusRowMap[anchorStartColumn + anchorCell.__colSpan] : focusRowMap[focusStartColumn + focusCell.__colSpan]; 32664 if (nextColumn !== void 0) { 32665 const { 32666 cell 32667 } = nextColumn; 32668 $moveSelectionToCell(cell); 32669 } else { 32670 const previousRow = focusStartColumn < anchorStartColumn ? focusRowMap[focusStartColumn - 1] : focusRowMap[anchorStartColumn - 1]; 32671 const { 32672 cell 32673 } = previousRow; 32674 $moveSelectionToCell(cell); 32675 } 32676 const colWidths = grid.getColWidths(); 32677 if (colWidths) { 32678 const newColWidths = [...colWidths]; 32679 newColWidths.splice(startColumn, selectedColumnCount); 32680 grid.setColWidths(newColWidths); 32681 } 32682 } 32683 var $deleteTableColumn__EXPERIMENTAL = $deleteTableColumnAtSelection; 32684 function $moveSelectionToCell(cell) { 32685 const firstDescendant = cell.getFirstDescendant(); 32686 if (firstDescendant == null) { 32687 cell.selectStart(); 32688 } else { 32689 firstDescendant.getParentOrThrow().selectStart(); 32690 } 32691 } 32692 function $insertFirst3(parent, node) { 32693 const firstChild = parent.getFirstChild(); 32694 if (firstChild !== null) { 32695 firstChild.insertBefore(node); 32696 } else { 32697 parent.append(node); 32698 } 32699 } 32700 function $mergeCells(cellNodes) { 32701 if (cellNodes.length === 0) { 32702 return null; 32703 } 32704 const tableNode = $getTableNodeFromLexicalNodeOrThrow(cellNodes[0]); 32705 const [gridMap] = $computeTableMapSkipCellCheck(tableNode, null, null); 32706 let minRow = Infinity; 32707 let maxRow = -Infinity; 32708 let minCol = Infinity; 32709 let maxCol = -Infinity; 32710 const processedCells = /* @__PURE__ */ new Set(); 32711 for (const row of gridMap) { 32712 for (const mapCell of row) { 32713 if (!mapCell || !mapCell.cell) { 32714 continue; 32715 } 32716 const cellKey = mapCell.cell.getKey(); 32717 if (processedCells.has(cellKey)) { 32718 continue; 32719 } 32720 if (cellNodes.some((cell) => cell.is(mapCell.cell))) { 32721 processedCells.add(cellKey); 32722 const cellStartRow = mapCell.startRow; 32723 const cellStartCol = mapCell.startColumn; 32724 const cellRowSpan = mapCell.cell.__rowSpan || 1; 32725 const cellColSpan = mapCell.cell.__colSpan || 1; 32726 minRow = Math.min(minRow, cellStartRow); 32727 maxRow = Math.max(maxRow, cellStartRow + cellRowSpan - 1); 32728 minCol = Math.min(minCol, cellStartCol); 32729 maxCol = Math.max(maxCol, cellStartCol + cellColSpan - 1); 32730 } 32731 } 32732 } 32733 if (minRow === Infinity || minCol === Infinity) { 32734 return null; 32735 } 32736 const totalRowSpan = maxRow - minRow + 1; 32737 const totalColSpan = maxCol - minCol + 1; 32738 const targetCellMap = gridMap[minRow][minCol]; 32739 if (!targetCellMap.cell) { 32740 return null; 32741 } 32742 const targetCell = targetCellMap.cell; 32743 targetCell.setColSpan(totalColSpan); 32744 targetCell.setRowSpan(totalRowSpan); 32745 const seenCells = /* @__PURE__ */ new Set([targetCell.getKey()]); 32746 for (let row = minRow; row <= maxRow; row++) { 32747 for (let col = minCol; col <= maxCol; col++) { 32748 const mapCell = gridMap[row][col]; 32749 if (!mapCell.cell) { 32750 continue; 32751 } 32752 const currentCell = mapCell.cell; 32753 const key = currentCell.getKey(); 32754 if (!seenCells.has(key)) { 32755 seenCells.add(key); 32756 const isEmpty = $cellContainsEmptyParagraph(currentCell); 32757 if (!isEmpty) { 32758 targetCell.append(...currentCell.getChildren()); 32759 } 32760 currentCell.remove(); 32761 } 32762 } 32763 } 32764 if (targetCell.getChildrenSize() === 0) { 32765 targetCell.append($createParagraphNode2()); 32766 } 32767 return targetCell; 32768 } 32769 function $cellContainsEmptyParagraph(cell) { 32770 if (cell.getChildrenSize() !== 1) { 32771 return false; 32772 } 32773 const firstChild = cell.getFirstChildOrThrow(); 32774 if (!$isParagraphNode2(firstChild) || !firstChild.isEmpty()) { 32775 return false; 32776 } 32777 return true; 32778 } 32779 function $unmergeCell() { 32780 const selection = $getSelection2(); 32781 if (!($isRangeSelection2(selection) || $isTableSelection(selection))) { 32782 formatDevErrorMessage12(`Expected a RangeSelection or TableSelection`); 32783 } 32784 const anchor = selection.anchor.getNode(); 32785 const cellNode = $findMatchingParent3(anchor, $isTableCellNode); 32786 if (!$isTableCellNode(cellNode)) { 32787 formatDevErrorMessage12(`Expected to find a parent TableCellNode`); 32788 } 32789 return $unmergeCellNode(cellNode); 32790 } 32791 function $unmergeCellNode(cellNode) { 32792 const [cell, row, grid] = $getNodeTriplet(cellNode); 32793 const colSpan = cell.__colSpan; 32794 const rowSpan = cell.__rowSpan; 32795 if (colSpan === 1 && rowSpan === 1) { 32796 return; 32797 } 32798 const [map, cellMap] = $computeTableMap(grid, cell, cell); 32799 const { 32800 startColumn, 32801 startRow 32802 } = cellMap; 32803 const baseColStyle = cell.__headerState & TableCellHeaderStates.COLUMN; 32804 const colStyles = Array.from({ 32805 length: colSpan 32806 }, (_v, i2) => { 32807 let colStyle = baseColStyle; 32808 for (let rowIdx = 0; colStyle !== 0 && rowIdx < map.length; rowIdx++) { 32809 colStyle &= map[rowIdx][i2 + startColumn].cell.__headerState; 32810 } 32811 return colStyle; 32812 }); 32813 const baseRowStyle = cell.__headerState & TableCellHeaderStates.ROW; 32814 const rowStyles = Array.from({ 32815 length: rowSpan 32816 }, (_v, i2) => { 32817 let rowStyle = baseRowStyle; 32818 for (let colIdx = 0; rowStyle !== 0 && colIdx < map[0].length; colIdx++) { 32819 rowStyle &= map[i2 + startRow][colIdx].cell.__headerState; 32820 } 32821 return rowStyle; 32822 }); 32823 if (colSpan > 1) { 32824 for (let i2 = 1; i2 < colSpan; i2++) { 32825 cell.insertAfter($createTableCellNode(colStyles[i2] | rowStyles[0]).append($createParagraphNode2())); 32826 } 32827 cell.setColSpan(1); 32828 } 32829 if (rowSpan > 1) { 32830 let currentRowNode; 32831 for (let i2 = 1; i2 < rowSpan; i2++) { 32832 const currentRow = startRow + i2; 32833 const currentRowMap = map[currentRow]; 32834 currentRowNode = (currentRowNode || row).getNextSibling(); 32835 if (!$isTableRowNode(currentRowNode)) { 32836 formatDevErrorMessage12(`Expected row next sibling to be a row`); 32837 } 32838 let insertAfterCell = null; 32839 for (let column = 0; column < startColumn; column++) { 32840 const currentCellMap = currentRowMap[column]; 32841 const currentCell = currentCellMap.cell; 32842 if (currentCellMap.startRow === currentRow) { 32843 insertAfterCell = currentCell; 32844 } 32845 if (currentCell.__colSpan > 1) { 32846 column += currentCell.__colSpan - 1; 32847 } 32848 } 32849 if (insertAfterCell === null) { 32850 for (let j3 = colSpan - 1; j3 >= 0; j3--) { 32851 $insertFirst3(currentRowNode, $createTableCellNode(colStyles[j3] | rowStyles[i2]).append($createParagraphNode2())); 32852 } 32853 } else { 32854 for (let j3 = colSpan - 1; j3 >= 0; j3--) { 32855 insertAfterCell.insertAfter($createTableCellNode(colStyles[j3] | rowStyles[i2]).append($createParagraphNode2())); 32856 } 32857 } 32858 } 32859 cell.setRowSpan(1); 32860 } 32861 } 32862 function $computeTableMap(tableNode, cellA, cellB) { 32863 const [tableMap, cellAValue, cellBValue] = $computeTableMapSkipCellCheck(tableNode, cellA, cellB); 32864 if (!(cellAValue !== null)) { 32865 formatDevErrorMessage12(`Anchor not found in Table`); 32866 } 32867 if (!(cellBValue !== null)) { 32868 formatDevErrorMessage12(`Focus not found in Table`); 32869 } 32870 return [tableMap, cellAValue, cellBValue]; 32871 } 32872 function $computeTableMapSkipCellCheck(tableNode, cellA, cellB) { 32873 const tableMap = []; 32874 let cellAValue = null; 32875 let cellBValue = null; 32876 function getMapRow(i2) { 32877 let row = tableMap[i2]; 32878 if (row === void 0) { 32879 tableMap[i2] = row = []; 32880 } 32881 return row; 32882 } 32883 const gridChildren = tableNode.getChildren(); 32884 for (let rowIdx = 0; rowIdx < gridChildren.length; rowIdx++) { 32885 const row = gridChildren[rowIdx]; 32886 if (!$isTableRowNode(row)) { 32887 formatDevErrorMessage12(`Expected TableNode children to be TableRowNode`); 32888 } 32889 const startMapRow = getMapRow(rowIdx); 32890 for (let cell = row.getFirstChild(), colIdx = 0; cell != null; cell = cell.getNextSibling()) { 32891 if (!$isTableCellNode(cell)) { 32892 formatDevErrorMessage12(`Expected TableRowNode children to be TableCellNode`); 32893 } 32894 while (startMapRow[colIdx] !== void 0) { 32895 colIdx++; 32896 } 32897 const value = { 32898 cell, 32899 startColumn: colIdx, 32900 startRow: rowIdx 32901 }; 32902 const { 32903 __rowSpan: rowSpan, 32904 __colSpan: colSpan 32905 } = cell; 32906 for (let j3 = 0; j3 < rowSpan; j3++) { 32907 if (rowIdx + j3 >= gridChildren.length) { 32908 break; 32909 } 32910 const mapRow = getMapRow(rowIdx + j3); 32911 for (let i2 = 0; i2 < colSpan; i2++) { 32912 mapRow[colIdx + i2] = value; 32913 } 32914 } 32915 if (cellA !== null && cellAValue === null && cellA.is(cell)) { 32916 cellAValue = value; 32917 } 32918 if (cellB !== null && cellBValue === null && cellB.is(cell)) { 32919 cellBValue = value; 32920 } 32921 } 32922 } 32923 return [tableMap, cellAValue, cellBValue]; 32924 } 32925 function $getNodeTriplet(source) { 32926 let cell; 32927 if (source instanceof TableCellNode) { 32928 cell = source; 32929 } else if ("__type" in source) { 32930 const cell_ = $findMatchingParent3(source, $isTableCellNode); 32931 if (!$isTableCellNode(cell_)) { 32932 formatDevErrorMessage12(`Expected to find a parent TableCellNode`); 32933 } 32934 cell = cell_; 32935 } else { 32936 const cell_ = $findMatchingParent3(source.getNode(), $isTableCellNode); 32937 if (!$isTableCellNode(cell_)) { 32938 formatDevErrorMessage12(`Expected to find a parent TableCellNode`); 32939 } 32940 cell = cell_; 32941 } 32942 const row = cell.getParent(); 32943 if (!$isTableRowNode(row)) { 32944 formatDevErrorMessage12(`Expected TableCellNode to have a parent TableRowNode`); 32945 } 32946 const grid = row.getParent(); 32947 if (!$isTableNode(grid)) { 32948 formatDevErrorMessage12(`Expected TableRowNode to have a parent TableNode`); 32949 } 32950 return [cell, row, grid]; 32951 } 32952 function $computeTableCellRectSpans(map, boundary) { 32953 const { 32954 minColumn, 32955 maxColumn, 32956 minRow, 32957 maxRow 32958 } = boundary; 32959 let topSpan = 1; 32960 let leftSpan = 1; 32961 let rightSpan = 1; 32962 let bottomSpan = 1; 32963 const topRow = map[minRow]; 32964 const bottomRow = map[maxRow]; 32965 for (let col = minColumn; col <= maxColumn; col++) { 32966 topSpan = Math.max(topSpan, topRow[col].cell.__rowSpan); 32967 bottomSpan = Math.max(bottomSpan, bottomRow[col].cell.__rowSpan); 32968 } 32969 for (let row = minRow; row <= maxRow; row++) { 32970 leftSpan = Math.max(leftSpan, map[row][minColumn].cell.__colSpan); 32971 rightSpan = Math.max(rightSpan, map[row][maxColumn].cell.__colSpan); 32972 } 32973 return { 32974 bottomSpan, 32975 leftSpan, 32976 rightSpan, 32977 topSpan 32978 }; 32979 } 32980 function $computeTableCellRectBoundary(map, cellAMap, cellBMap) { 32981 let minColumn = Math.min(cellAMap.startColumn, cellBMap.startColumn); 32982 let minRow = Math.min(cellAMap.startRow, cellBMap.startRow); 32983 let maxColumn = Math.max(cellAMap.startColumn + cellAMap.cell.__colSpan - 1, cellBMap.startColumn + cellBMap.cell.__colSpan - 1); 32984 let maxRow = Math.max(cellAMap.startRow + cellAMap.cell.__rowSpan - 1, cellBMap.startRow + cellBMap.cell.__rowSpan - 1); 32985 let hasChanges; 32986 do { 32987 hasChanges = false; 32988 for (let row = 0; row < map.length; row++) { 32989 for (let col = 0; col < map[0].length; col++) { 32990 const cell = map[row][col]; 32991 if (!cell) { 32992 continue; 32993 } 32994 const cellEndCol = cell.startColumn + cell.cell.__colSpan - 1; 32995 const cellEndRow = cell.startRow + cell.cell.__rowSpan - 1; 32996 const intersectsHorizontally = cell.startColumn <= maxColumn && cellEndCol >= minColumn; 32997 const intersectsVertically = cell.startRow <= maxRow && cellEndRow >= minRow; 32998 if (intersectsHorizontally && intersectsVertically) { 32999 const newMinColumn = Math.min(minColumn, cell.startColumn); 33000 const newMaxColumn = Math.max(maxColumn, cellEndCol); 33001 const newMinRow = Math.min(minRow, cell.startRow); 33002 const newMaxRow = Math.max(maxRow, cellEndRow); 33003 if (newMinColumn !== minColumn || newMaxColumn !== maxColumn || newMinRow !== minRow || newMaxRow !== maxRow) { 33004 minColumn = newMinColumn; 33005 maxColumn = newMaxColumn; 33006 minRow = newMinRow; 33007 maxRow = newMaxRow; 33008 hasChanges = true; 33009 } 33010 } 33011 } 33012 } 33013 } while (hasChanges); 33014 return { 33015 maxColumn, 33016 maxRow, 33017 minColumn, 33018 minRow 33019 }; 33020 } 33021 function $isSimpleTable(table) { 33022 const rows = table.getChildren(); 33023 let columns = null; 33024 for (const row of rows) { 33025 if (!$isTableRowNode(row)) { 33026 return false; 33027 } 33028 if (columns === null) { 33029 columns = row.getChildrenSize(); 33030 } 33031 if (row.getChildrenSize() !== columns) { 33032 return false; 33033 } 33034 const cells = row.getChildren(); 33035 for (const cell of cells) { 33036 if (!$isTableCellNode(cell) || cell.getRowSpan() !== 1 || cell.getColSpan() !== 1) { 33037 return false; 33038 } 33039 } 33040 } 33041 return (columns || 0) > 0; 33042 } 33043 function $moveTableColumn(tableNode, originColumn, targetColumn) { 33044 if (originColumn === targetColumn) { 33045 return; 33046 } 33047 const columnCount = tableNode.getColumnCount(); 33048 if (originColumn < 0 || originColumn >= columnCount || targetColumn < 0 || targetColumn >= columnCount) { 33049 return; 33050 } 33051 if (!$isSimpleTable(tableNode)) { 33052 return; 33053 } 33054 const rows = tableNode.getChildren().filter($isTableRowNode); 33055 rows.forEach((row) => { 33056 const cells = row.getChildren(); 33057 const [moved] = cells.splice(originColumn, 1); 33058 cells.splice(targetColumn, 0, moved); 33059 row.splice(0, cells.length, cells); 33060 }); 33061 const colWidths = tableNode.getColWidths(); 33062 if (colWidths && colWidths.length === columnCount) { 33063 const newWidths = [...colWidths]; 33064 const [movedWidth] = newWidths.splice(originColumn, 1); 33065 newWidths.splice(targetColumn, 0, movedWidth); 33066 tableNode.setColWidths(newWidths); 33067 } 33068 } 33069 function $getTableCellNodeRect(tableCellNode) { 33070 const [cellNode, , gridNode] = $getNodeTriplet(tableCellNode); 33071 const rows = gridNode.getChildren(); 33072 const rowCount = rows.length; 33073 const columnCount = rows[0].getChildren().length; 33074 const cellMatrix = new Array(rowCount); 33075 for (let i2 = 0; i2 < rowCount; i2++) { 33076 cellMatrix[i2] = new Array(columnCount); 33077 } 33078 for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) { 33079 const row = rows[rowIndex]; 33080 const cells = row.getChildren(); 33081 let columnIndex = 0; 33082 for (let cellIndex = 0; cellIndex < cells.length; cellIndex++) { 33083 while (cellMatrix[rowIndex][columnIndex]) { 33084 columnIndex++; 33085 } 33086 const cell = cells[cellIndex]; 33087 const rowSpan = cell.__rowSpan || 1; 33088 const colSpan = cell.__colSpan || 1; 33089 for (let i2 = 0; i2 < rowSpan; i2++) { 33090 for (let j3 = 0; j3 < colSpan; j3++) { 33091 cellMatrix[rowIndex + i2][columnIndex + j3] = cell; 33092 } 33093 } 33094 if (cellNode === cell) { 33095 return { 33096 colSpan, 33097 columnIndex, 33098 rowIndex, 33099 rowSpan 33100 }; 33101 } 33102 columnIndex += colSpan; 33103 } 33104 } 33105 return null; 33106 } 33107 function $getCellNodes(tableSelection) { 33108 const [[anchorNode, anchorCell, anchorRow, anchorTable], [focusNode, focusCell, focusRow, focusTable]] = ["anchor", "focus"].map((k2) => { 33109 const node = tableSelection[k2].getNode(); 33110 const cellNode = $findMatchingParent3(node, $isTableCellNode); 33111 if (!$isTableCellNode(cellNode)) { 33112 formatDevErrorMessage12(`Expected TableSelection ${k2} to be (or a child of) TableCellNode, got key ${node.getKey()} of type ${node.getType()}`); 33113 } 33114 const rowNode = cellNode.getParent(); 33115 if (!$isTableRowNode(rowNode)) { 33116 formatDevErrorMessage12(`Expected TableSelection ${k2} cell parent to be a TableRowNode`); 33117 } 33118 const tableNode = rowNode.getParent(); 33119 if (!$isTableNode(tableNode)) { 33120 formatDevErrorMessage12(`Expected TableSelection ${k2} row parent to be a TableNode`); 33121 } 33122 return [node, cellNode, rowNode, tableNode]; 33123 }); 33124 if (!anchorTable.is(focusTable)) { 33125 formatDevErrorMessage12(`Expected TableSelection anchor and focus to be in the same table`); 33126 } 33127 return { 33128 anchorCell, 33129 anchorNode, 33130 anchorRow, 33131 anchorTable, 33132 focusCell, 33133 focusNode, 33134 focusRow, 33135 focusTable 33136 }; 33137 } 33138 var TableSelection = class _TableSelection { 33139 tableKey; 33140 anchor; 33141 focus; 33142 _cachedNodes; 33143 dirty; 33144 constructor(tableKey, anchor, focus) { 33145 this.anchor = anchor; 33146 this.focus = focus; 33147 anchor._selection = this; 33148 focus._selection = this; 33149 this._cachedNodes = null; 33150 this.dirty = false; 33151 this.tableKey = tableKey; 33152 } 33153 getStartEndPoints() { 33154 return [this.anchor, this.focus]; 33155 } 33156 /** 33157 * {@link $createTableSelection} unfortunately makes it very easy to create 33158 * nonsense selections, so we have a method to see if the selection probably 33159 * makes sense. 33160 * 33161 * @returns true if the TableSelection is (probably) valid 33162 */ 33163 isValid() { 33164 if (this.tableKey === "root" || this.anchor.key === "root" || this.anchor.type !== "element" || this.focus.key === "root" || this.focus.type !== "element") { 33165 return false; 33166 } 33167 const tableNode = $getNodeByKey2(this.tableKey); 33168 const anchorNode = $getNodeByKey2(this.anchor.key); 33169 const focusNode = $getNodeByKey2(this.focus.key); 33170 return tableNode !== null && anchorNode !== null && focusNode !== null; 33171 } 33172 /** 33173 * Returns whether the Selection is "backwards", meaning the focus 33174 * logically precedes the anchor in the EditorState. 33175 * @returns true if the Selection is backwards, false otherwise. 33176 */ 33177 isBackward() { 33178 return this.focus.isBefore(this.anchor); 33179 } 33180 getCachedNodes() { 33181 return this._cachedNodes; 33182 } 33183 setCachedNodes(nodes) { 33184 this._cachedNodes = nodes; 33185 } 33186 is(selection) { 33187 return $isTableSelection(selection) && this.tableKey === selection.tableKey && this.anchor.is(selection.anchor) && this.focus.is(selection.focus); 33188 } 33189 set(tableKey, anchorCellKey, focusCellKey) { 33190 this.dirty = this.dirty || tableKey !== this.tableKey || anchorCellKey !== this.anchor.key || focusCellKey !== this.focus.key; 33191 this.tableKey = tableKey; 33192 this.anchor.key = anchorCellKey; 33193 this.focus.key = focusCellKey; 33194 this._cachedNodes = null; 33195 } 33196 clone() { 33197 return new _TableSelection(this.tableKey, $createPoint2(this.anchor.key, this.anchor.offset, this.anchor.type), $createPoint2(this.focus.key, this.focus.offset, this.focus.type)); 33198 } 33199 isCollapsed() { 33200 return false; 33201 } 33202 extract() { 33203 return this.getNodes(); 33204 } 33205 insertRawText(text2) { 33206 } 33207 insertText() { 33208 } 33209 /** 33210 * Returns whether the provided TextFormatType is present on the Selection. 33211 * This will be true if any paragraph in table cells has the specified format. 33212 * 33213 * @param type the TextFormatType to check for. 33214 * @returns true if the provided format is currently toggled on on the Selection, false otherwise. 33215 */ 33216 hasFormat(type) { 33217 let format = 0; 33218 const cellNodes = this.getNodes().filter($isTableCellNode); 33219 cellNodes.forEach((cellNode) => { 33220 const paragraph = cellNode.getFirstChild(); 33221 if ($isParagraphNode2(paragraph)) { 33222 format |= paragraph.getTextFormat(); 33223 } 33224 }); 33225 const formatFlag = TEXT_TYPE_TO_FORMAT2[type]; 33226 return (format & formatFlag) !== 0; 33227 } 33228 insertNodes(nodes) { 33229 const focusNode = this.focus.getNode(); 33230 if (!$isElementNode2(focusNode)) { 33231 formatDevErrorMessage12(`Expected TableSelection focus to be an ElementNode`); 33232 } 33233 const selection = $normalizeSelection__EXPERIMENTAL(focusNode.select(0, focusNode.getChildrenSize())); 33234 selection.insertNodes(nodes); 33235 } 33236 // TODO Deprecate this method. It's confusing when used with colspan|rowspan 33237 getShape() { 33238 const { 33239 anchorCell, 33240 focusCell 33241 } = $getCellNodes(this); 33242 const anchorCellNodeRect = $getTableCellNodeRect(anchorCell); 33243 if (!(anchorCellNodeRect !== null)) { 33244 formatDevErrorMessage12(`getCellRect: expected to find AnchorNode`); 33245 } 33246 const focusCellNodeRect = $getTableCellNodeRect(focusCell); 33247 if (!(focusCellNodeRect !== null)) { 33248 formatDevErrorMessage12(`getCellRect: expected to find focusCellNode`); 33249 } 33250 const startX = Math.min(anchorCellNodeRect.columnIndex, focusCellNodeRect.columnIndex); 33251 const stopX = Math.max(anchorCellNodeRect.columnIndex + anchorCellNodeRect.colSpan - 1, focusCellNodeRect.columnIndex + focusCellNodeRect.colSpan - 1); 33252 const startY = Math.min(anchorCellNodeRect.rowIndex, focusCellNodeRect.rowIndex); 33253 const stopY = Math.max(anchorCellNodeRect.rowIndex + anchorCellNodeRect.rowSpan - 1, focusCellNodeRect.rowIndex + focusCellNodeRect.rowSpan - 1); 33254 return { 33255 fromX: Math.min(startX, stopX), 33256 fromY: Math.min(startY, stopY), 33257 toX: Math.max(startX, stopX), 33258 toY: Math.max(startY, stopY) 33259 }; 33260 } 33261 getNodes() { 33262 if (!this.isValid()) { 33263 return []; 33264 } 33265 const cachedNodes = this._cachedNodes; 33266 if (cachedNodes !== null) { 33267 return cachedNodes; 33268 } 33269 const { 33270 anchorTable: tableNode, 33271 anchorCell, 33272 focusCell 33273 } = $getCellNodes(this); 33274 const focusCellGrid = focusCell.getParents()[1]; 33275 if (focusCellGrid !== tableNode) { 33276 if (!tableNode.isParentOf(focusCell)) { 33277 const gridParent = tableNode.getParent(); 33278 if (!(gridParent != null)) { 33279 formatDevErrorMessage12(`Expected gridParent to have a parent`); 33280 } 33281 this.set(this.tableKey, gridParent.getKey(), focusCell.getKey()); 33282 } else { 33283 const focusCellParent = focusCellGrid.getParent(); 33284 if (!(focusCellParent != null)) { 33285 formatDevErrorMessage12(`Expected focusCellParent to have a parent`); 33286 } 33287 this.set(this.tableKey, focusCell.getKey(), focusCellParent.getKey()); 33288 } 33289 return this.getNodes(); 33290 } 33291 const [map, cellAMap, cellBMap] = $computeTableMap(tableNode, anchorCell, focusCell); 33292 const { 33293 minColumn, 33294 maxColumn, 33295 minRow, 33296 maxRow 33297 } = $computeTableCellRectBoundary(map, cellAMap, cellBMap); 33298 const nodeMap = /* @__PURE__ */ new Map([[tableNode.getKey(), tableNode]]); 33299 let lastRow = null; 33300 for (let i2 = minRow; i2 <= maxRow; i2++) { 33301 for (let j3 = minColumn; j3 <= maxColumn; j3++) { 33302 const { 33303 cell 33304 } = map[i2][j3]; 33305 const currentRow = cell.getParent(); 33306 if (!$isTableRowNode(currentRow)) { 33307 formatDevErrorMessage12(`Expected TableCellNode parent to be a TableRowNode`); 33308 } 33309 if (currentRow !== lastRow) { 33310 nodeMap.set(currentRow.getKey(), currentRow); 33311 lastRow = currentRow; 33312 } 33313 if (!nodeMap.has(cell.getKey())) { 33314 $visitRecursively(cell, (childNode) => { 33315 nodeMap.set(childNode.getKey(), childNode); 33316 }); 33317 } 33318 } 33319 } 33320 const nodes = Array.from(nodeMap.values()); 33321 if (!isCurrentlyReadOnlyMode2()) { 33322 this._cachedNodes = nodes; 33323 } 33324 return nodes; 33325 } 33326 getTextContent() { 33327 const nodes = this.getNodes().filter((node) => $isTableCellNode(node)); 33328 let textContent = ""; 33329 for (let i2 = 0; i2 < nodes.length; i2++) { 33330 const node = nodes[i2]; 33331 const row = node.__parent; 33332 const nextRow = (nodes[i2 + 1] || {}).__parent; 33333 textContent += node.getTextContent() + (nextRow !== row ? "\n" : " "); 33334 } 33335 return textContent; 33336 } 33337 }; 33338 function $isTableSelection(x3) { 33339 return x3 instanceof TableSelection; 33340 } 33341 function $createTableSelection() { 33342 const anchor = $createPoint2("root", 0, "element"); 33343 const focus = $createPoint2("root", 0, "element"); 33344 return new TableSelection("root", anchor, focus); 33345 } 33346 function $createTableSelectionFrom(tableNode, anchorCell, focusCell) { 33347 const tableNodeKey = tableNode.getKey(); 33348 const anchorCellKey = anchorCell.getKey(); 33349 const focusCellKey = focusCell.getKey(); 33350 { 33351 if (!tableNode.isAttached()) { 33352 formatDevErrorMessage12(`$createTableSelectionFrom: tableNode ${tableNodeKey} is not attached`); 33353 } 33354 if (!tableNode.is($findTableNode(anchorCell))) { 33355 formatDevErrorMessage12(`$createTableSelectionFrom: anchorCell ${anchorCellKey} is not in table ${tableNodeKey}`); 33356 } 33357 if (!tableNode.is($findTableNode(focusCell))) { 33358 formatDevErrorMessage12(`$createTableSelectionFrom: focusCell ${focusCellKey} is not in table ${tableNodeKey}`); 33359 } 33360 } 33361 const prevSelection = $getSelection2(); 33362 const nextSelection = $isTableSelection(prevSelection) ? prevSelection.clone() : $createTableSelection(); 33363 nextSelection.set(tableNode.getKey(), anchorCell.getKey(), focusCell.getKey()); 33364 return nextSelection; 33365 } 33366 function $visitRecursively(node, $visit) { 33367 const stack = [[node]]; 33368 for (let currentArray = stack.at(-1); currentArray !== void 0 && stack.length > 0; currentArray = stack.at(-1)) { 33369 const currentNode = currentArray.pop(); 33370 if (currentNode === void 0) { 33371 stack.pop(); 33372 } else if ($visit(currentNode) !== false && $isElementNode2(currentNode)) { 33373 stack.push(currentNode.getChildren()); 33374 } 33375 } 33376 } 33377 function $getTableAndElementByKey(tableNodeKey, editor = $getEditor2()) { 33378 const tableNode = $getNodeByKey2(tableNodeKey); 33379 if (!$isTableNode(tableNode)) { 33380 formatDevErrorMessage12(`TableObserver: Expected tableNodeKey ${tableNodeKey} to be a TableNode`); 33381 } 33382 const tableElement = getTableElement(tableNode, editor.getElementByKey(tableNodeKey)); 33383 if (!(tableElement !== null)) { 33384 formatDevErrorMessage12(`TableObserver: Expected to find TableElement in DOM for key ${tableNodeKey}`); 33385 } 33386 return { 33387 tableElement, 33388 tableNode 33389 }; 33390 } 33391 var TableObservers = class { 33392 observers; 33393 nextFocus; 33394 shouldCheckSelectionForTable; 33395 constructor() { 33396 this.observers = /* @__PURE__ */ new Map(); 33397 this.nextFocus = null; 33398 this.shouldCheckSelectionForTable = null; 33399 } 33400 /** 33401 * @internal 33402 * When handling mousemove events we track what the focus cell should be, but 33403 * the DOM selection may end up somewhere else entirely. We don't have an elegant 33404 * way to handle this after the DOM selection has been resolved in a 33405 * SELECTION_CHANGE_COMMAND callback. 33406 */ 33407 setNextFocus(nextFocus) { 33408 this.nextFocus = nextFocus; 33409 } 33410 /** @internal */ 33411 getAndClearNextFocus() { 33412 const { 33413 nextFocus 33414 } = this; 33415 if (nextFocus !== null) { 33416 this.nextFocus = null; 33417 } 33418 return nextFocus; 33419 } 33420 /** 33421 * @internal 33422 * Firefox has a strange behavior where pressing the down arrow key from 33423 * above the table will move the caret after the table and then lexical 33424 * will select the last cell instead of the first. 33425 * We do still want to let the browser handle caret movement but we will 33426 * use this property to "tag" the update so that we can recheck the 33427 * selection after the event is processed. 33428 */ 33429 setShouldCheckSelectionForTable(tableKey) { 33430 this.shouldCheckSelectionForTable = tableKey; 33431 } 33432 /** 33433 * @internal 33434 */ 33435 getAndClearShouldCheckSelectionForTable() { 33436 const { 33437 shouldCheckSelectionForTable 33438 } = this; 33439 if (shouldCheckSelectionForTable) { 33440 this.shouldCheckSelectionForTable = null; 33441 return shouldCheckSelectionForTable; 33442 } 33443 return null; 33444 } 33445 }; 33446 var TableObserver = class { 33447 focusX; 33448 focusY; 33449 listenersToRemove; 33450 table; 33451 isHighlightingCells; 33452 anchorX; 33453 anchorY; 33454 tableNodeKey; 33455 anchorCell; 33456 focusCell; 33457 anchorCellNodeKey; 33458 focusCellNodeKey; 33459 editor; 33460 tableSelection; 33461 hasHijackedSelectionStyles; 33462 isSelecting; 33463 pointerType; 33464 abortController; 33465 listenerOptions; 33466 constructor(editor, tableNodeKey) { 33467 this.isHighlightingCells = false; 33468 this.anchorX = -1; 33469 this.anchorY = -1; 33470 this.focusX = -1; 33471 this.focusY = -1; 33472 this.listenersToRemove = /* @__PURE__ */ new Set(); 33473 this.tableNodeKey = tableNodeKey; 33474 this.editor = editor; 33475 this.table = { 33476 columns: 0, 33477 domRows: [], 33478 rows: 0 33479 }; 33480 this.tableSelection = null; 33481 this.anchorCellNodeKey = null; 33482 this.focusCellNodeKey = null; 33483 this.anchorCell = null; 33484 this.focusCell = null; 33485 this.hasHijackedSelectionStyles = false; 33486 this.isSelecting = false; 33487 this.pointerType = null; 33488 this.abortController = new AbortController(); 33489 this.listenerOptions = { 33490 signal: this.abortController.signal 33491 }; 33492 this.trackTable(); 33493 } 33494 getTable() { 33495 return this.table; 33496 } 33497 removeListeners() { 33498 this.abortController.abort("removeListeners"); 33499 Array.from(this.listenersToRemove).forEach((removeListener) => removeListener()); 33500 this.listenersToRemove.clear(); 33501 } 33502 $lookup() { 33503 return $getTableAndElementByKey(this.tableNodeKey, this.editor); 33504 } 33505 trackTable() { 33506 const observer = new MutationObserver((records) => { 33507 this.editor.getEditorState().read(() => { 33508 let gridNeedsRedraw = false; 33509 for (let i2 = 0; i2 < records.length; i2++) { 33510 const record = records[i2]; 33511 const target = record.target; 33512 const nodeName = target.nodeName; 33513 if (nodeName === "TABLE" || nodeName === "TBODY" || nodeName === "THEAD" || nodeName === "TR") { 33514 gridNeedsRedraw = true; 33515 break; 33516 } 33517 } 33518 if (!gridNeedsRedraw) { 33519 return; 33520 } 33521 const { 33522 tableNode, 33523 tableElement 33524 } = this.$lookup(); 33525 this.table = getTable(tableNode, tableElement); 33526 }, { 33527 editor: this.editor 33528 }); 33529 }); 33530 this.editor.getEditorState().read(() => { 33531 const { 33532 tableNode, 33533 tableElement 33534 } = this.$lookup(); 33535 this.table = getTable(tableNode, tableElement); 33536 observer.observe(tableElement, { 33537 attributes: true, 33538 childList: true, 33539 subtree: true 33540 }); 33541 }, { 33542 editor: this.editor 33543 }); 33544 } 33545 $clearHighlight(setEmptySelection = true) { 33546 const editor = this.editor; 33547 this.isHighlightingCells = false; 33548 this.anchorX = -1; 33549 this.anchorY = -1; 33550 this.focusX = -1; 33551 this.focusY = -1; 33552 this.tableSelection = null; 33553 this.anchorCellNodeKey = null; 33554 this.focusCellNodeKey = null; 33555 this.anchorCell = null; 33556 this.focusCell = null; 33557 this.hasHijackedSelectionStyles = false; 33558 this.$enableHighlightStyle(); 33559 const { 33560 tableNode, 33561 tableElement 33562 } = this.$lookup(); 33563 const grid = getTable(tableNode, tableElement); 33564 $updateDOMForSelection(editor, grid, null); 33565 if (setEmptySelection && $getSelection2() !== null) { 33566 $setSelection2(null); 33567 editor.dispatchCommand(SELECTION_CHANGE_COMMAND2, void 0); 33568 } 33569 } 33570 $enableHighlightStyle() { 33571 const editor = this.editor; 33572 const { 33573 tableElement 33574 } = this.$lookup(); 33575 removeClassNamesFromElement3(tableElement, editor._config.theme.tableSelection); 33576 tableElement.classList.remove("disable-selection"); 33577 this.hasHijackedSelectionStyles = false; 33578 } 33579 $disableHighlightStyle() { 33580 const { 33581 tableElement 33582 } = this.$lookup(); 33583 addClassNamesToElement3(tableElement, this.editor._config.theme.tableSelection); 33584 this.hasHijackedSelectionStyles = true; 33585 } 33586 $updateTableTableSelection(selection) { 33587 if (selection !== null) { 33588 if (!(selection.tableKey === this.tableNodeKey)) { 33589 formatDevErrorMessage12(`TableObserver.$updateTableTableSelection: selection.tableKey !== this.tableNodeKey ('${selection.tableKey}' !== '${this.tableNodeKey}')`); 33590 } 33591 const editor = this.editor; 33592 this.tableSelection = selection; 33593 this.isHighlightingCells = true; 33594 this.$disableHighlightStyle(); 33595 this.updateDOMSelection(); 33596 $updateDOMForSelection(editor, this.table, this.tableSelection); 33597 } else { 33598 this.$clearHighlight(); 33599 } 33600 } 33601 /** @internal */ 33602 updateDOMSelection() { 33603 if (this.anchorCell !== null && this.focusCell !== null) { 33604 const domSelection = getDOMSelection2(this.editor._window); 33605 if (domSelection && domSelection.rangeCount > 0) { 33606 domSelection.removeAllRanges(); 33607 } 33608 } 33609 } 33610 $setFocusCellForSelection(cell, ignoreStart = false) { 33611 const editor = this.editor; 33612 const { 33613 tableNode 33614 } = this.$lookup(); 33615 const cellX = cell.x; 33616 const cellY = cell.y; 33617 this.focusCell = cell; 33618 if (!this.isHighlightingCells) { 33619 const shouldEnable = ignoreStart || this.anchorX !== cellX || this.anchorY !== cellY || this.tableSelection != null && this.anchorCellNodeKey != null; 33620 if (shouldEnable) { 33621 this.isHighlightingCells = true; 33622 this.$disableHighlightStyle(); 33623 } 33624 } 33625 if (this.focusX !== -1 && this.focusY !== -1 && cellX === this.focusX && cellY === this.focusY) { 33626 return false; 33627 } 33628 this.focusX = cellX; 33629 this.focusY = cellY; 33630 if (this.isHighlightingCells) { 33631 const focusTableCellNode = $getNearestTableCellInTableFromDOMNode(tableNode, cell.elem); 33632 if (this.tableSelection != null && this.anchorCellNodeKey != null) { 33633 let targetCellNode = focusTableCellNode; 33634 if (targetCellNode === null && ignoreStart) { 33635 targetCellNode = tableNode.getCellNodeFromCords(cellX, cellY, this.table); 33636 } 33637 if (targetCellNode !== null) { 33638 const anchorTableCell = this.$getAnchorTableCellOrThrow(); 33639 this.focusCellNodeKey = targetCellNode.getKey(); 33640 this.tableSelection = $createTableSelectionFrom(tableNode, anchorTableCell, targetCellNode); 33641 $setSelection2(this.tableSelection); 33642 editor.dispatchCommand(SELECTION_CHANGE_COMMAND2, void 0); 33643 $updateDOMForSelection(editor, this.table, this.tableSelection); 33644 return true; 33645 } 33646 } 33647 } 33648 return false; 33649 } 33650 $getAnchorTableCell() { 33651 return this.anchorCellNodeKey ? $getNodeByKey2(this.anchorCellNodeKey) : null; 33652 } 33653 $getAnchorTableCellOrThrow() { 33654 const anchorTableCell = this.$getAnchorTableCell(); 33655 if (!(anchorTableCell !== null)) { 33656 formatDevErrorMessage12(`TableObserver anchorTableCell is null`); 33657 } 33658 return anchorTableCell; 33659 } 33660 $getFocusTableCell() { 33661 return this.focusCellNodeKey ? $getNodeByKey2(this.focusCellNodeKey) : null; 33662 } 33663 $getFocusTableCellOrThrow() { 33664 const focusTableCell = this.$getFocusTableCell(); 33665 if (!(focusTableCell !== null)) { 33666 formatDevErrorMessage12(`TableObserver focusTableCell is null`); 33667 } 33668 return focusTableCell; 33669 } 33670 $setAnchorCellForSelection(cell) { 33671 this.isHighlightingCells = false; 33672 this.anchorCell = cell; 33673 this.anchorX = cell.x; 33674 this.anchorY = cell.y; 33675 this.focusX = -1; 33676 this.focusY = -1; 33677 this.focusCell = null; 33678 this.focusCellNodeKey = null; 33679 const { 33680 tableNode 33681 } = this.$lookup(); 33682 const anchorTableCellNode = $getNearestTableCellInTableFromDOMNode(tableNode, cell.elem); 33683 if (anchorTableCellNode !== null) { 33684 const anchorNodeKey = anchorTableCellNode.getKey(); 33685 if (this.tableSelection != null) { 33686 this.tableSelection = this.tableSelection.clone(); 33687 this.tableSelection.set(tableNode.getKey(), anchorNodeKey, anchorNodeKey); 33688 } else { 33689 this.tableSelection = $createTableSelectionFrom(tableNode, anchorTableCellNode, anchorTableCellNode); 33690 } 33691 this.anchorCellNodeKey = anchorNodeKey; 33692 } 33693 } 33694 $formatCells(type) { 33695 const selection = $getSelection2(); 33696 if (!$isTableSelection(selection)) { 33697 formatDevErrorMessage12(`Expected Table selection`); 33698 } 33699 const formatSelection = $createRangeSelection2(); 33700 const anchor = formatSelection.anchor; 33701 const focus = formatSelection.focus; 33702 const cellNodes = selection.getNodes().filter($isTableCellNode); 33703 if (!(cellNodes.length > 0)) { 33704 formatDevErrorMessage12(`No table cells present`); 33705 } 33706 const paragraph = cellNodes[0].getFirstChild(); 33707 const alignFormatWith = $isParagraphNode2(paragraph) ? paragraph.getFormatFlags(type, null) : null; 33708 cellNodes.forEach((cellNode) => { 33709 anchor.set(cellNode.getKey(), 0, "element"); 33710 focus.set(cellNode.getKey(), cellNode.getChildrenSize(), "element"); 33711 formatSelection.formatText(type, alignFormatWith); 33712 }); 33713 $setSelection2(selection); 33714 this.editor.dispatchCommand(SELECTION_CHANGE_COMMAND2, void 0); 33715 } 33716 $clearText() { 33717 const { 33718 editor 33719 } = this; 33720 const tableNode = $getNodeByKey2(this.tableNodeKey); 33721 if (!$isTableNode(tableNode)) { 33722 throw new Error("Expected TableNode."); 33723 } 33724 const selection = $getSelection2(); 33725 if (!$isTableSelection(selection)) { 33726 formatDevErrorMessage12(`Expected TableSelection`); 33727 } 33728 const selectedNodes = selection.getNodes().filter($isTableCellNode); 33729 const firstRow = tableNode.getFirstChild(); 33730 const lastRow = tableNode.getLastChild(); 33731 const isEntireTableSelected = selectedNodes.length > 0 && firstRow !== null && lastRow !== null && $isTableRowNode(firstRow) && $isTableRowNode(lastRow) && selectedNodes[0] === firstRow.getFirstChild() && selectedNodes[selectedNodes.length - 1] === lastRow.getLastChild(); 33732 if (isEntireTableSelected) { 33733 tableNode.selectPrevious(); 33734 const parent = tableNode.getParent(); 33735 tableNode.remove(); 33736 if ($isRootNode2(parent) && parent.isEmpty()) { 33737 editor.dispatchCommand(INSERT_PARAGRAPH_COMMAND2, void 0); 33738 } 33739 return; 33740 } 33741 selectedNodes.forEach((cellNode) => { 33742 if ($isElementNode2(cellNode)) { 33743 const paragraphNode = $createParagraphNode2(); 33744 const textNode = $createTextNode2(); 33745 paragraphNode.append(textNode); 33746 cellNode.append(paragraphNode); 33747 cellNode.getChildren().forEach((child) => { 33748 if (child !== paragraphNode) { 33749 child.remove(); 33750 } 33751 }); 33752 } 33753 }); 33754 $updateDOMForSelection(editor, this.table, null); 33755 $setSelection2(null); 33756 editor.dispatchCommand(SELECTION_CHANGE_COMMAND2, void 0); 33757 } 33758 }; 33759 var LEXICAL_ELEMENT_KEY = "__lexicalTableSelection"; 33760 var isPointerDownOnEvent = (event) => { 33761 return (event.buttons & 1) === 1; 33762 }; 33763 function isHTMLTableElement(el) { 33764 return isHTMLElement2(el) && el.nodeName === "TABLE"; 33765 } 33766 function getTableElement(tableNode, dom) { 33767 if (!dom) { 33768 return dom; 33769 } 33770 const element = isHTMLTableElement(dom) ? dom : dom.querySelector("table"); 33771 if (!isHTMLTableElement(element)) { 33772 formatDevErrorMessage12(`getTableElement: Expecting table in DOM node for ${tableNode.constructor.name} of type ${tableNode.getType()} with key ${tableNode.getKey()}, not ${dom.nodeName}`); 33773 } 33774 return element; 33775 } 33776 function getEditorWindow(editor) { 33777 return editor._window; 33778 } 33779 function $findParentTableCellNodeInTable(tableNode, node) { 33780 for (let currentNode = node, lastTableCellNode = null; currentNode !== null; currentNode = currentNode.getParent()) { 33781 if (tableNode.is(currentNode)) { 33782 return lastTableCellNode; 33783 } else if ($isTableCellNode(currentNode)) { 33784 lastTableCellNode = currentNode; 33785 } 33786 } 33787 return null; 33788 } 33789 var ARROW_KEY_COMMANDS_WITH_DIRECTION = [[KEY_ARROW_DOWN_COMMAND2, "down"], [KEY_ARROW_UP_COMMAND2, "up"], [KEY_ARROW_LEFT_COMMAND2, "backward"], [KEY_ARROW_RIGHT_COMMAND2, "forward"]]; 33790 var DELETE_TEXT_COMMANDS = [DELETE_WORD_COMMAND2, DELETE_LINE_COMMAND2, DELETE_CHARACTER_COMMAND2]; 33791 var DELETE_KEY_COMMANDS = [KEY_BACKSPACE_COMMAND2, KEY_DELETE_COMMAND2]; 33792 function registerTableWindowHandlers(editor, tableObservers) { 33793 const rootElement = editor.getRootElement(); 33794 const editorWindow = editor._window; 33795 if (!rootElement || !editorWindow) { 33796 return () => { 33797 }; 33798 } 33799 const pointerDownCallback = (event) => { 33800 const target = event.target; 33801 if (event.button !== 0 || !isDOMNode2(target) || !rootElement.contains(target)) { 33802 return; 33803 } 33804 const selectionInfo = getTableObserverFromCellNode(target); 33805 editor.update(() => { 33806 const selection = $getSelection2(); 33807 if ($isTableSelection(selection)) { 33808 for (const [observer] of tableObservers.observers.values()) { 33809 observer.$clearHighlight(false); 33810 } 33811 $setSelection2(null); 33812 editor.dispatchCommand(SELECTION_CHANGE_COMMAND2, void 0); 33813 } 33814 if (!selectionInfo) { 33815 return; 33816 } 33817 const { 33818 tableObserver, 33819 tableElement, 33820 cellElement 33821 } = selectionInfo; 33822 $handleTableClick(editor, event, cellElement, tableElement, tableObserver, tableObservers); 33823 }); 33824 }; 33825 editorWindow.addEventListener("pointerdown", pointerDownCallback); 33826 return () => { 33827 editorWindow.removeEventListener("pointerdown", pointerDownCallback); 33828 }; 33829 } 33830 function $handleTableClick(editor, event, selectedDOMCell, tableElement, tableObserver, tableObservers) { 33831 const editorWindow = editor._window; 33832 if (!editorWindow) { 33833 return; 33834 } 33835 const createPointerHandlers = (startingCell) => { 33836 if (tableObserver.isSelecting) { 33837 return; 33838 } 33839 tableObserver.isSelecting = true; 33840 if (startingCell !== null && tableObserver.anchorCell === null) { 33841 editor.update(() => { 33842 tableObserver.$setAnchorCellForSelection(startingCell); 33843 }); 33844 } 33845 const onPointerUp = () => { 33846 tableObserver.isSelecting = false; 33847 editorWindow.removeEventListener("pointerup", onPointerUp); 33848 editorWindow.removeEventListener("pointermove", onPointerMove); 33849 }; 33850 const onPointerMove = (moveEvent) => { 33851 if (!isPointerDownOnEvent(moveEvent) && tableObserver.isSelecting) { 33852 tableObserver.isSelecting = false; 33853 editorWindow.removeEventListener("pointerup", onPointerUp); 33854 editorWindow.removeEventListener("pointermove", onPointerMove); 33855 return; 33856 } 33857 if (!isDOMNode2(moveEvent.target)) { 33858 return; 33859 } 33860 let focusCell = null; 33861 const override = !(IS_FIREFOX4 || tableElement.contains(moveEvent.target)); 33862 if (override) { 33863 focusCell = getDOMCellInTableFromTarget(tableElement, moveEvent.target); 33864 } else { 33865 for (const el of document.elementsFromPoint(moveEvent.clientX, moveEvent.clientY)) { 33866 focusCell = getDOMCellInTableFromTarget(tableElement, el); 33867 if (focusCell) { 33868 break; 33869 } 33870 } 33871 } 33872 if (focusCell) { 33873 const anchorCell = focusCell; 33874 if (tableObserver.anchorCell === null) { 33875 editor.update(() => { 33876 tableObserver.$setAnchorCellForSelection(anchorCell); 33877 }); 33878 } 33879 if (tableObserver.focusCell === null || focusCell.elem !== tableObserver.focusCell.elem) { 33880 tableObservers.setNextFocus({ 33881 focusCell, 33882 override, 33883 tableKey: tableObserver.tableNodeKey 33884 }); 33885 editor.dispatchCommand(SELECTION_CHANGE_COMMAND2, void 0); 33886 } 33887 } 33888 }; 33889 editorWindow.addEventListener("pointerup", onPointerUp, tableObserver.listenerOptions); 33890 editorWindow.addEventListener("pointermove", onPointerMove, tableObserver.listenerOptions); 33891 }; 33892 tableObserver.pointerType = event.pointerType; 33893 const tableNode = $getNodeByKeyOrThrow2(tableObserver.tableNodeKey); 33894 const prevSelection = $getPreviousSelection2(); 33895 if (IS_FIREFOX4 && event.shiftKey && $isSelectionInTable(prevSelection, tableNode) && ($isRangeSelection2(prevSelection) || $isTableSelection(prevSelection))) { 33896 const prevAnchorNode = prevSelection.anchor.getNode(); 33897 const prevAnchorCell = $findParentTableCellNodeInTable(tableNode, prevSelection.anchor.getNode()); 33898 if (prevAnchorCell) { 33899 tableObserver.$setAnchorCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, prevAnchorCell)); 33900 tableObserver.$setFocusCellForSelection(selectedDOMCell); 33901 stopEvent(event); 33902 } else { 33903 const newSelection = tableNode.isBefore(prevAnchorNode) ? tableNode.selectStart() : tableNode.selectEnd(); 33904 newSelection.anchor.set(prevSelection.anchor.key, prevSelection.anchor.offset, prevSelection.anchor.type); 33905 } 33906 } else { 33907 if (event.pointerType !== "touch") { 33908 tableObserver.$setAnchorCellForSelection(selectedDOMCell); 33909 } 33910 } 33911 createPointerHandlers(selectedDOMCell); 33912 } 33913 function applyTableHandlers(tableNode, element, editor, hasTabHandler, tableObservers) { 33914 const rootElement = editor.getRootElement(); 33915 const editorWindow = getEditorWindow(editor); 33916 if (!(rootElement !== null && editorWindow !== null)) { 33917 formatDevErrorMessage12(`applyTableHandlers: editor has no root element set`); 33918 } 33919 const tableObserver = new TableObserver(editor, tableNode.getKey()); 33920 const tableElement = getTableElement(tableNode, element); 33921 attachTableObserverToTableElement(tableElement, tableObserver); 33922 tableObserver.listenersToRemove.add(() => detachTableObserverFromTableElement(tableElement, tableObserver)); 33923 const onTripleClick = (event) => { 33924 if (event.detail >= 3 && isDOMNode2(event.target)) { 33925 const targetCell = getDOMCellFromTarget(event.target); 33926 if (targetCell !== null) { 33927 event.preventDefault(); 33928 } 33929 } 33930 }; 33931 tableElement.addEventListener("mousedown", onTripleClick, tableObserver.listenerOptions); 33932 tableObserver.listenersToRemove.add(() => { 33933 tableElement.removeEventListener("mousedown", onTripleClick); 33934 }); 33935 for (const [command, direction] of ARROW_KEY_COMMANDS_WITH_DIRECTION) { 33936 tableObserver.listenersToRemove.add(editor.registerCommand(command, (event) => $handleArrowKey(editor, event, direction, tableNode, tableObserver, tableObservers), COMMAND_PRIORITY_HIGH2)); 33937 } 33938 tableObserver.listenersToRemove.add(editor.registerCommand(KEY_ESCAPE_COMMAND2, (event) => { 33939 const selection = $getSelection2(); 33940 if ($isTableSelection(selection)) { 33941 const focusCellNode = $findParentTableCellNodeInTable(tableNode, selection.focus.getNode()); 33942 if (focusCellNode !== null) { 33943 stopEvent(event); 33944 focusCellNode.selectEnd(); 33945 return true; 33946 } 33947 } 33948 return false; 33949 }, COMMAND_PRIORITY_HIGH2)); 33950 const deleteTextHandler = (command) => () => { 33951 const selection = $getSelection2(); 33952 if (!$isSelectionInTable(selection, tableNode)) { 33953 return false; 33954 } 33955 if ($isTableSelection(selection)) { 33956 tableObserver.$clearText(); 33957 return true; 33958 } else if ($isRangeSelection2(selection)) { 33959 const tableCellNode = $findParentTableCellNodeInTable(tableNode, selection.anchor.getNode()); 33960 if (!$isTableCellNode(tableCellNode)) { 33961 return false; 33962 } 33963 const anchorNode = selection.anchor.getNode(); 33964 const focusNode = selection.focus.getNode(); 33965 const isAnchorInside = tableNode.isParentOf(anchorNode); 33966 const isFocusInside = tableNode.isParentOf(focusNode); 33967 const selectionContainsPartialTable = isAnchorInside && !isFocusInside || isFocusInside && !isAnchorInside; 33968 if (selectionContainsPartialTable) { 33969 tableObserver.$clearText(); 33970 return true; 33971 } 33972 const nearestElementNode = $findMatchingParent3(selection.anchor.getNode(), (n2) => $isElementNode2(n2)); 33973 const topLevelCellElementNode = nearestElementNode && $findMatchingParent3(nearestElementNode, (n2) => $isElementNode2(n2) && $isTableCellNode(n2.getParent())); 33974 if (!$isElementNode2(topLevelCellElementNode) || !$isElementNode2(nearestElementNode)) { 33975 return false; 33976 } 33977 if (command === DELETE_LINE_COMMAND2 && topLevelCellElementNode.getPreviousSibling() === null) { 33978 return true; 33979 } 33980 } 33981 return false; 33982 }; 33983 for (const command of DELETE_TEXT_COMMANDS) { 33984 tableObserver.listenersToRemove.add(editor.registerCommand(command, deleteTextHandler(command), COMMAND_PRIORITY_HIGH2)); 33985 } 33986 const $deleteCellHandler = (event) => { 33987 const selection = $getSelection2(); 33988 if (!($isTableSelection(selection) || $isRangeSelection2(selection))) { 33989 return false; 33990 } 33991 const isAnchorInside = tableNode.isParentOf(selection.anchor.getNode()); 33992 const isFocusInside = tableNode.isParentOf(selection.focus.getNode()); 33993 if (isAnchorInside !== isFocusInside) { 33994 const tablePoint = isAnchorInside ? "anchor" : "focus"; 33995 const outerPoint = isAnchorInside ? "focus" : "anchor"; 33996 const { 33997 key, 33998 offset: offset3, 33999 type 34000 } = selection[outerPoint]; 34001 const newSelection = tableNode[selection[tablePoint].isBefore(selection[outerPoint]) ? "selectPrevious" : "selectNext"](); 34002 newSelection[outerPoint].set(key, offset3, type); 34003 return false; 34004 } 34005 if (!$isSelectionInTable(selection, tableNode)) { 34006 return false; 34007 } 34008 if ($isTableSelection(selection)) { 34009 if (event) { 34010 event.preventDefault(); 34011 event.stopPropagation(); 34012 } 34013 tableObserver.$clearText(); 34014 return true; 34015 } 34016 return false; 34017 }; 34018 for (const command of DELETE_KEY_COMMANDS) { 34019 tableObserver.listenersToRemove.add(editor.registerCommand(command, $deleteCellHandler, COMMAND_PRIORITY_HIGH2)); 34020 } 34021 tableObserver.listenersToRemove.add(editor.registerCommand(CUT_COMMAND2, (event) => { 34022 const selection = $getSelection2(); 34023 if (selection) { 34024 if (!($isTableSelection(selection) || $isRangeSelection2(selection))) { 34025 return false; 34026 } 34027 void copyToClipboard2(editor, objectKlassEquals2(event, ClipboardEvent) ? event : null, $getClipboardDataFromSelection2(selection)); 34028 const intercepted = $deleteCellHandler(event); 34029 if ($isRangeSelection2(selection)) { 34030 selection.removeText(); 34031 return true; 34032 } 34033 return intercepted; 34034 } 34035 return false; 34036 }, COMMAND_PRIORITY_HIGH2)); 34037 tableObserver.listenersToRemove.add(editor.registerCommand(FORMAT_TEXT_COMMAND2, (payload) => { 34038 const selection = $getSelection2(); 34039 if (!$isSelectionInTable(selection, tableNode)) { 34040 return false; 34041 } 34042 if ($isTableSelection(selection)) { 34043 tableObserver.$formatCells(payload); 34044 return true; 34045 } else if ($isRangeSelection2(selection)) { 34046 const tableCellNode = $findMatchingParent3(selection.anchor.getNode(), (n2) => $isTableCellNode(n2)); 34047 if (!$isTableCellNode(tableCellNode)) { 34048 return false; 34049 } 34050 } 34051 return false; 34052 }, COMMAND_PRIORITY_HIGH2)); 34053 tableObserver.listenersToRemove.add(editor.registerCommand(FORMAT_ELEMENT_COMMAND2, (formatType) => { 34054 const selection = $getSelection2(); 34055 if (!$isTableSelection(selection) || !$isSelectionInTable(selection, tableNode)) { 34056 return false; 34057 } 34058 const anchorNode = selection.anchor.getNode(); 34059 const focusNode = selection.focus.getNode(); 34060 if (!$isTableCellNode(anchorNode) || !$isTableCellNode(focusNode)) { 34061 return false; 34062 } 34063 if ($isFullTableSelection(selection, tableNode)) { 34064 tableNode.setFormat(formatType); 34065 return true; 34066 } 34067 const [tableMap, anchorCell, focusCell] = $computeTableMap(tableNode, anchorNode, focusNode); 34068 const maxRow = Math.max(anchorCell.startRow + anchorCell.cell.__rowSpan - 1, focusCell.startRow + focusCell.cell.__rowSpan - 1); 34069 const maxColumn = Math.max(anchorCell.startColumn + anchorCell.cell.__colSpan - 1, focusCell.startColumn + focusCell.cell.__colSpan - 1); 34070 const minRow = Math.min(anchorCell.startRow, focusCell.startRow); 34071 const minColumn = Math.min(anchorCell.startColumn, focusCell.startColumn); 34072 const visited = /* @__PURE__ */ new Set(); 34073 for (let i2 = minRow; i2 <= maxRow; i2++) { 34074 for (let j3 = minColumn; j3 <= maxColumn; j3++) { 34075 const cell = tableMap[i2][j3].cell; 34076 if (visited.has(cell)) { 34077 continue; 34078 } 34079 visited.add(cell); 34080 cell.setFormat(formatType); 34081 const cellChildren = cell.getChildren(); 34082 for (let k2 = 0; k2 < cellChildren.length; k2++) { 34083 const child = cellChildren[k2]; 34084 if ($isElementNode2(child) && !child.isInline()) { 34085 child.setFormat(formatType); 34086 } 34087 } 34088 } 34089 } 34090 return true; 34091 }, COMMAND_PRIORITY_HIGH2)); 34092 tableObserver.listenersToRemove.add(editor.registerCommand(CONTROLLED_TEXT_INSERTION_COMMAND2, (payload) => { 34093 const selection = $getSelection2(); 34094 if (!$isSelectionInTable(selection, tableNode)) { 34095 return false; 34096 } 34097 if ($isTableSelection(selection)) { 34098 tableObserver.$clearHighlight(); 34099 return false; 34100 } else if ($isRangeSelection2(selection)) { 34101 const tableCellNode = $findMatchingParent3(selection.anchor.getNode(), (n2) => $isTableCellNode(n2)); 34102 if (!$isTableCellNode(tableCellNode)) { 34103 return false; 34104 } 34105 if (typeof payload === "string") { 34106 const edgePosition = $getTableEdgeCursorPosition(editor, selection, tableNode); 34107 if (edgePosition) { 34108 $insertParagraphAtTableEdge(edgePosition, tableNode, [$createTextNode2(payload)]); 34109 return true; 34110 } 34111 } 34112 } 34113 return false; 34114 }, COMMAND_PRIORITY_HIGH2)); 34115 if (hasTabHandler) { 34116 tableObserver.listenersToRemove.add(editor.registerCommand(KEY_TAB_COMMAND2, (event) => { 34117 const selection = $getSelection2(); 34118 if (!$isRangeSelection2(selection) || !selection.isCollapsed() || !$isSelectionInTable(selection, tableNode)) { 34119 return false; 34120 } 34121 const tableCellNode = $findCellNode(selection.anchor.getNode()); 34122 if (tableCellNode === null || !tableNode.is($findTableNode(tableCellNode))) { 34123 return false; 34124 } 34125 stopEvent(event); 34126 $selectAdjacentCell(tableCellNode, event.shiftKey ? "previous" : "next"); 34127 return true; 34128 }, COMMAND_PRIORITY_HIGH2)); 34129 } 34130 tableObserver.listenersToRemove.add(editor.registerCommand(FOCUS_COMMAND2, (payload) => { 34131 return tableNode.isSelected(); 34132 }, COMMAND_PRIORITY_HIGH2)); 34133 tableObserver.listenersToRemove.add(editor.registerCommand(INSERT_PARAGRAPH_COMMAND2, () => { 34134 const selection = $getSelection2(); 34135 if (!$isRangeSelection2(selection) || !selection.isCollapsed() || !$isSelectionInTable(selection, tableNode)) { 34136 return false; 34137 } 34138 const edgePosition = $getTableEdgeCursorPosition(editor, selection, tableNode); 34139 if (edgePosition) { 34140 $insertParagraphAtTableEdge(edgePosition, tableNode); 34141 return true; 34142 } 34143 return false; 34144 }, COMMAND_PRIORITY_HIGH2)); 34145 return tableObserver; 34146 } 34147 function $handleTableSelectionChangeCommand(tableObservers, editor) { 34148 const selection = $getSelection2(); 34149 const prevSelection = $getPreviousSelection2(); 34150 const nextFocus = tableObservers.getAndClearNextFocus(); 34151 if (nextFocus !== null) { 34152 const { 34153 tableKey, 34154 focusCell 34155 } = nextFocus; 34156 const observerAndTable = tableObservers.observers.get(tableKey); 34157 if (!!!observerAndTable) { 34158 formatDevErrorMessage12(`tableObserver not found for tableKey: ${tableKey}`); 34159 } 34160 const [tableObserver] = observerAndTable; 34161 if ($isTableSelection(selection) && selection.tableKey === tableObserver.tableNodeKey) { 34162 if (focusCell.x === tableObserver.focusX && focusCell.y === tableObserver.focusY) { 34163 return false; 34164 } else { 34165 tableObserver.$setFocusCellForSelection(focusCell); 34166 return true; 34167 } 34168 } else if (tableObserver.anchorCell !== null && tableObserver.anchorCellNodeKey !== null && focusCell.elem !== tableObserver.anchorCell.elem && tableObserver.tableSelection !== null) { 34169 tableObserver.$setFocusCellForSelection(focusCell, true); 34170 return true; 34171 } 34172 } 34173 const shouldCheckSelectionForTable = tableObservers.getAndClearShouldCheckSelectionForTable(); 34174 if (!!shouldCheckSelectionForTable && $isRangeSelection2(prevSelection) && $isRangeSelection2(selection) && selection.isCollapsed()) { 34175 const tableNode = $getNodeByKeyOrThrow2(shouldCheckSelectionForTable); 34176 const anchor = selection.anchor.getNode(); 34177 const firstRow = tableNode.getFirstChild(); 34178 const anchorCell = $findCellNode(anchor); 34179 if (anchorCell !== null && $isTableRowNode(firstRow)) { 34180 const firstCell = firstRow.getFirstChild(); 34181 if ($isTableCellNode(firstCell) && tableNode.is($findMatchingParent3(anchorCell, (node) => node.is(tableNode) || node.is(firstCell)))) { 34182 firstCell.selectStart(); 34183 return true; 34184 } 34185 } 34186 } 34187 if ($isTableSelection(selection)) { 34188 $fixTableSelectionForSelectedTable(editor, selection); 34189 } 34190 if ($isRangeSelection2(selection)) { 34191 $fixRangeSelectionForSelectedTable(selection, tableObservers); 34192 } 34193 const tableNodesAndObservers = Array.from(tableObservers.observers.entries()).map(([tableKey, [tableObserver]]) => ({ 34194 tableNode: $getNodeByKeyOrThrow2(tableKey), 34195 tableObserver 34196 })); 34197 for (const { 34198 tableNode, 34199 tableObserver 34200 } of tableNodesAndObservers) { 34201 $syncTableSelectionState(editor, tableNode, tableObserver); 34202 } 34203 return false; 34204 } 34205 function $fixRangeSelectionForSelectedTable(selection, tableObservers) { 34206 const prevSelection = $getPreviousSelection2(); 34207 const { 34208 anchor, 34209 focus 34210 } = selection; 34211 const anchorNode = anchor.getNode(); 34212 const focusNode = focus.getNode(); 34213 const anchorCellNode = $findCellNode(anchorNode); 34214 const focusCellNode = $findCellNode(focusNode); 34215 const anchorCellTable = anchorCellNode ? $findTableNode(anchorCellNode) : null; 34216 const focusCellTable = focusCellNode ? $findTableNode(focusCellNode) : null; 34217 const isBackward = selection.isBackward(); 34218 const isSameTable = anchorCellNode && focusCellNode && anchorCellTable && focusCellTable && anchorCellTable.is(focusCellTable); 34219 const shouldMoveFocus = focusCellTable && (!anchorCellTable || anchorCellTable.isParentOf(focusCellTable)); 34220 const shouldMoveAnchor = anchorCellTable && (!focusCellTable || focusCellTable.isParentOf(anchorCellTable)); 34221 if (shouldMoveFocus) { 34222 const newSelection = selection.clone(); 34223 const [tableMap] = $computeTableMap(focusCellTable, focusCellNode, focusCellNode); 34224 const firstCell = tableMap[0][0].cell; 34225 const lastCell = tableMap[tableMap.length - 1].at(-1).cell; 34226 newSelection.focus.set(isBackward ? firstCell.getKey() : lastCell.getKey(), isBackward ? 0 : lastCell.getChildrenSize(), "element"); 34227 $setSelection2(newSelection); 34228 } else if (shouldMoveAnchor) { 34229 const newSelection = selection.clone(); 34230 const [tableMap] = $computeTableMap(anchorCellTable, anchorCellNode, anchorCellNode); 34231 const firstCell = tableMap[0][0].cell; 34232 const lastCell = tableMap[tableMap.length - 1].at(-1).cell; 34233 newSelection.anchor.set(isBackward ? lastCell.getKey() : firstCell.getKey(), isBackward ? lastCell.getChildrenSize() : 0, "element"); 34234 $setSelection2(newSelection); 34235 } else if (isSameTable) { 34236 const observerInfo = tableObservers.observers.get(anchorCellTable.getKey()); 34237 if (!!!observerInfo) { 34238 formatDevErrorMessage12(`tableObserver not found for tableKey: ${anchorCellTable.getKey()}`); 34239 } 34240 const [tableObserver] = observerInfo; 34241 if (!anchorCellNode.is(focusCellNode)) { 34242 tableObserver.$setAnchorCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, anchorCellNode)); 34243 tableObserver.$setFocusCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, focusCellNode), true); 34244 } 34245 if (tableObserver.pointerType === "touch" && tableObserver.isSelecting && selection.isCollapsed() && $isRangeSelection2(prevSelection) && prevSelection.isCollapsed()) { 34246 const prevAnchorCellNode = $findCellNode(prevSelection.anchor.getNode()); 34247 if (prevAnchorCellNode && !prevAnchorCellNode.is(focusCellNode)) { 34248 tableObserver.$setAnchorCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, prevAnchorCellNode)); 34249 tableObserver.$setFocusCellForSelection($getObserverCellFromCellNodeOrThrow(tableObserver, focusCellNode), true); 34250 tableObserver.pointerType = null; 34251 } 34252 } 34253 } 34254 } 34255 function $fixTableSelectionForSelectedTable(editor, selection) { 34256 const editorWindow = getEditorWindow(editor); 34257 const prevSelection = $getPreviousSelection2(); 34258 if (!selection.is(prevSelection)) { 34259 return; 34260 } 34261 const tableNode = $getNodeByKeyOrThrow2(selection.tableKey); 34262 const domSelection = getDOMSelection2(editorWindow); 34263 if (domSelection && domSelection.anchorNode && domSelection.focusNode) { 34264 const focusNode = $getNearestNodeFromDOMNode2(domSelection.focusNode); 34265 const isFocusOutside = focusNode && !tableNode.isParentOf(focusNode); 34266 const anchorNode = $getNearestNodeFromDOMNode2(domSelection.anchorNode); 34267 const isAnchorInside = anchorNode && tableNode.isParentOf(anchorNode); 34268 if (isFocusOutside && isAnchorInside && domSelection.rangeCount > 0) { 34269 const newSelection = $createRangeSelectionFromDom2(domSelection, editor); 34270 if (newSelection) { 34271 newSelection.anchor.set(tableNode.getKey(), selection.isBackward() ? tableNode.getChildrenSize() : 0, "element"); 34272 domSelection.removeAllRanges(); 34273 $setSelection2(newSelection); 34274 } 34275 } 34276 } 34277 } 34278 function $syncTableSelectionState(editor, tableNode, tableObserver) { 34279 const selection = $getSelection2(); 34280 const prevSelection = $getPreviousSelection2(); 34281 if (selection && !selection.is(prevSelection) && ($isTableSelection(selection) || $isTableSelection(prevSelection)) && tableObserver.tableSelection && !tableObserver.tableSelection.is(prevSelection)) { 34282 if ($isTableSelection(selection) && selection.tableKey === tableObserver.tableNodeKey) { 34283 tableObserver.$updateTableTableSelection(selection); 34284 } else if (!$isTableSelection(selection) && $isTableSelection(prevSelection) && prevSelection.tableKey === tableObserver.tableNodeKey) { 34285 tableObserver.$updateTableTableSelection(null); 34286 } 34287 } 34288 if (tableObserver.hasHijackedSelectionStyles && !tableNode.isSelected()) { 34289 $removeHighlightStyleToTable(editor, tableObserver); 34290 } else if (!tableObserver.hasHijackedSelectionStyles && tableNode.isSelected()) { 34291 $addHighlightStyleToTable(editor, tableObserver); 34292 } 34293 } 34294 function detachTableObserverFromTableElement(tableElement, tableObserver) { 34295 if (getTableObserverFromTableElement(tableElement) === tableObserver) { 34296 delete tableElement[LEXICAL_ELEMENT_KEY]; 34297 } 34298 } 34299 function attachTableObserverToTableElement(tableElement, tableObserver) { 34300 if (!(getTableObserverFromTableElement(tableElement) === null)) { 34301 formatDevErrorMessage12(`tableElement already has an attached TableObserver`); 34302 } 34303 tableElement[LEXICAL_ELEMENT_KEY] = tableObserver; 34304 } 34305 function getTableObserverFromTableElement(tableElement) { 34306 return tableElement[LEXICAL_ELEMENT_KEY] || null; 34307 } 34308 function getTableObserverFromCellNode(node) { 34309 const cellNode = getDOMCellFromTarget(node); 34310 if (cellNode === null) { 34311 return null; 34312 } 34313 let currentNode = cellNode.elem; 34314 while (currentNode != null) { 34315 const nodeName = currentNode.nodeName; 34316 if (nodeName === "TABLE" && LEXICAL_ELEMENT_KEY in currentNode && !!currentNode[LEXICAL_ELEMENT_KEY]) { 34317 return { 34318 cellElement: cellNode, 34319 tableElement: currentNode, 34320 tableObserver: currentNode[LEXICAL_ELEMENT_KEY] 34321 }; 34322 } 34323 currentNode = currentNode.parentNode; 34324 } 34325 return null; 34326 } 34327 function getDOMCellFromTarget(node) { 34328 let currentNode = node; 34329 while (currentNode != null) { 34330 const nodeName = currentNode.nodeName; 34331 if (nodeName === "TD" || nodeName === "TH") { 34332 const cell = currentNode._cell; 34333 if (cell === void 0) { 34334 return null; 34335 } 34336 return cell; 34337 } 34338 currentNode = currentNode.parentNode; 34339 } 34340 return null; 34341 } 34342 function getDOMCellInTableFromTarget(table, node) { 34343 if (!table.contains(node)) { 34344 return null; 34345 } 34346 let cell = null; 34347 for (let currentNode = node; currentNode != null; currentNode = currentNode.parentNode) { 34348 if (currentNode === table) { 34349 return cell; 34350 } 34351 const nodeName = currentNode.nodeName; 34352 if (nodeName === "TD" || nodeName === "TH") { 34353 cell = currentNode._cell || null; 34354 } 34355 } 34356 return null; 34357 } 34358 function getTable(tableNode, dom) { 34359 const tableElement = getTableElement(tableNode, dom); 34360 const domRows = []; 34361 const grid = { 34362 columns: 0, 34363 domRows, 34364 rows: 0 34365 }; 34366 let currentNode = tableElement.querySelector("tr"); 34367 let x3 = 0; 34368 let y3 = 0; 34369 domRows.length = 0; 34370 while (currentNode != null) { 34371 const nodeMame = currentNode.nodeName; 34372 if (nodeMame === "TD" || nodeMame === "TH") { 34373 const elem = currentNode; 34374 const cell = { 34375 elem, 34376 hasBackgroundColor: elem.style.backgroundColor !== "", 34377 highlighted: false, 34378 x: x3, 34379 y: y3 34380 }; 34381 currentNode._cell = cell; 34382 let row = domRows[y3]; 34383 if (row === void 0) { 34384 row = domRows[y3] = []; 34385 } 34386 row[x3] = cell; 34387 } else { 34388 const child = currentNode.firstChild; 34389 if (child != null) { 34390 currentNode = child; 34391 continue; 34392 } 34393 } 34394 const sibling = currentNode.nextSibling; 34395 if (sibling != null) { 34396 x3++; 34397 currentNode = sibling; 34398 continue; 34399 } 34400 const parent = currentNode.parentNode; 34401 if (parent != null) { 34402 const parentSibling = parent.nextSibling; 34403 if (parentSibling == null) { 34404 break; 34405 } 34406 y3++; 34407 x3 = 0; 34408 currentNode = parentSibling; 34409 } 34410 } 34411 grid.columns = x3 + 1; 34412 grid.rows = y3 + 1; 34413 return grid; 34414 } 34415 function $updateDOMForSelection(editor, table, selection) { 34416 const selectedCellNodes = new Set(selection ? selection.getNodes() : []); 34417 $forEachTableCell(table, (cell, lexicalNode) => { 34418 const elem = cell.elem; 34419 if (selectedCellNodes.has(lexicalNode)) { 34420 cell.highlighted = true; 34421 $addHighlightToDOM(editor, cell); 34422 } else { 34423 cell.highlighted = false; 34424 $removeHighlightFromDOM(editor, cell); 34425 if (!elem.getAttribute("style")) { 34426 elem.removeAttribute("style"); 34427 } 34428 } 34429 }); 34430 } 34431 function $forEachTableCell(grid, cb) { 34432 const { 34433 domRows 34434 } = grid; 34435 for (let y3 = 0; y3 < domRows.length; y3++) { 34436 const row = domRows[y3]; 34437 if (!row) { 34438 continue; 34439 } 34440 for (let x3 = 0; x3 < row.length; x3++) { 34441 const cell = row[x3]; 34442 if (!cell) { 34443 continue; 34444 } 34445 const lexicalNode = $getNearestNodeFromDOMNode2(cell.elem); 34446 if (lexicalNode !== null) { 34447 cb(cell, lexicalNode, { 34448 x: x3, 34449 y: y3 34450 }); 34451 } 34452 } 34453 } 34454 } 34455 function $addHighlightStyleToTable(editor, tableSelection) { 34456 tableSelection.$disableHighlightStyle(); 34457 $forEachTableCell(tableSelection.table, (cell) => { 34458 cell.highlighted = true; 34459 $addHighlightToDOM(editor, cell); 34460 }); 34461 } 34462 function $removeHighlightStyleToTable(editor, tableObserver) { 34463 tableObserver.$enableHighlightStyle(); 34464 $forEachTableCell(tableObserver.table, (cell) => { 34465 const elem = cell.elem; 34466 cell.highlighted = false; 34467 $removeHighlightFromDOM(editor, cell); 34468 if (!elem.getAttribute("style")) { 34469 elem.removeAttribute("style"); 34470 } 34471 }); 34472 } 34473 function $selectAdjacentCell(tableCellNode, direction) { 34474 const siblingMethod = direction === "next" ? "getNextSibling" : "getPreviousSibling"; 34475 const childMethod = direction === "next" ? "getFirstChild" : "getLastChild"; 34476 const sibling = tableCellNode[siblingMethod](); 34477 if ($isElementNode2(sibling)) { 34478 return sibling.selectEnd(); 34479 } 34480 const parentRow = $findMatchingParent3(tableCellNode, $isTableRowNode); 34481 if (!(parentRow !== null)) { 34482 formatDevErrorMessage12(`selectAdjacentCell: Cell not in table row`); 34483 } 34484 for (let nextRow = parentRow[siblingMethod](); $isTableRowNode(nextRow); nextRow = nextRow[siblingMethod]()) { 34485 const child = nextRow[childMethod](); 34486 if ($isElementNode2(child)) { 34487 return child.selectEnd(); 34488 } 34489 } 34490 const parentTable = $findMatchingParent3(parentRow, $isTableNode); 34491 if (!(parentTable !== null)) { 34492 formatDevErrorMessage12(`selectAdjacentCell: Row not in table`); 34493 } 34494 return direction === "next" ? parentTable.selectNext() : parentTable.selectPrevious(); 34495 } 34496 var selectTableNodeInDirection = (tableObserver, tableNode, x3, y3, direction) => { 34497 const isForward = direction === "forward"; 34498 switch (direction) { 34499 case "backward": 34500 case "forward": 34501 if (x3 !== (isForward ? tableObserver.table.columns - 1 : 0)) { 34502 selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x3 + (isForward ? 1 : -1), y3, tableObserver.table), isForward); 34503 } else { 34504 if (y3 !== (isForward ? tableObserver.table.rows - 1 : 0)) { 34505 selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(isForward ? 0 : tableObserver.table.columns - 1, y3 + (isForward ? 1 : -1), tableObserver.table), isForward); 34506 } else if (!isForward) { 34507 tableNode.selectPrevious(); 34508 } else { 34509 tableNode.selectNext(); 34510 } 34511 } 34512 return true; 34513 case "up": 34514 if (y3 !== 0) { 34515 selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x3, y3 - 1, tableObserver.table), false); 34516 } else { 34517 tableNode.selectPrevious(); 34518 } 34519 return true; 34520 case "down": 34521 if (y3 !== tableObserver.table.rows - 1) { 34522 selectTableCellNode(tableNode.getCellNodeFromCordsOrThrow(x3, y3 + 1, tableObserver.table), true); 34523 } else { 34524 tableNode.selectNext(); 34525 } 34526 return true; 34527 default: 34528 return false; 34529 } 34530 }; 34531 function getCorner(rect, cellValue) { 34532 let colName; 34533 let rowName; 34534 if (cellValue.startColumn === rect.minColumn) { 34535 colName = "minColumn"; 34536 } else if (cellValue.startColumn + cellValue.cell.__colSpan - 1 === rect.maxColumn) { 34537 colName = "maxColumn"; 34538 } else { 34539 return null; 34540 } 34541 if (cellValue.startRow === rect.minRow) { 34542 rowName = "minRow"; 34543 } else if (cellValue.startRow + cellValue.cell.__rowSpan - 1 === rect.maxRow) { 34544 rowName = "maxRow"; 34545 } else { 34546 return null; 34547 } 34548 return [colName, rowName]; 34549 } 34550 function getCornerOrThrow(rect, cellValue) { 34551 const corner = getCorner(rect, cellValue); 34552 if (!(corner !== null)) { 34553 formatDevErrorMessage12(`getCornerOrThrow: cell ${cellValue.cell.getKey()} is not at a corner of rect`); 34554 } 34555 return corner; 34556 } 34557 function oppositeCorner([colName, rowName]) { 34558 return [colName === "minColumn" ? "maxColumn" : "minColumn", rowName === "minRow" ? "maxRow" : "minRow"]; 34559 } 34560 function cellAtCornerOrThrow(tableMap, rect, [colName, rowName]) { 34561 const rowNum = rect[rowName]; 34562 const rowMap = tableMap[rowNum]; 34563 if (!(rowMap !== void 0)) { 34564 formatDevErrorMessage12(`cellAtCornerOrThrow: ${rowName} = ${String(rowNum)} missing in tableMap`); 34565 } 34566 const colNum = rect[colName]; 34567 const cell = rowMap[colNum]; 34568 if (!(cell !== void 0)) { 34569 formatDevErrorMessage12(`cellAtCornerOrThrow: ${colName} = ${String(colNum)} missing in tableMap`); 34570 } 34571 return cell; 34572 } 34573 function $extractRectCorners(tableMap, anchorCellValue, newFocusCellValue) { 34574 const rect = $computeTableCellRectBoundary(tableMap, anchorCellValue, newFocusCellValue); 34575 const anchorCorner = getCorner(rect, anchorCellValue); 34576 if (anchorCorner) { 34577 return [cellAtCornerOrThrow(tableMap, rect, anchorCorner), cellAtCornerOrThrow(tableMap, rect, oppositeCorner(anchorCorner))]; 34578 } 34579 const newFocusCorner = getCorner(rect, newFocusCellValue); 34580 if (newFocusCorner) { 34581 return [cellAtCornerOrThrow(tableMap, rect, oppositeCorner(newFocusCorner)), cellAtCornerOrThrow(tableMap, rect, newFocusCorner)]; 34582 } 34583 const newAnchorCorner = ["minColumn", "minRow"]; 34584 return [cellAtCornerOrThrow(tableMap, rect, newAnchorCorner), cellAtCornerOrThrow(tableMap, rect, oppositeCorner(newAnchorCorner))]; 34585 } 34586 function $adjustFocusInDirection(tableObserver, tableMap, anchorCellValue, focusCellValue, direction) { 34587 const rect = $computeTableCellRectBoundary(tableMap, anchorCellValue, focusCellValue); 34588 const spans = $computeTableCellRectSpans(tableMap, rect); 34589 const { 34590 topSpan, 34591 leftSpan, 34592 bottomSpan, 34593 rightSpan 34594 } = spans; 34595 const anchorCorner = getCornerOrThrow(rect, anchorCellValue); 34596 const [focusColumn, focusRow] = oppositeCorner(anchorCorner); 34597 let fCol = rect[focusColumn]; 34598 let fRow = rect[focusRow]; 34599 if (direction === "forward") { 34600 fCol += focusColumn === "maxColumn" ? 1 : leftSpan; 34601 } else if (direction === "backward") { 34602 fCol -= focusColumn === "minColumn" ? 1 : rightSpan; 34603 } else if (direction === "down") { 34604 fRow += focusRow === "maxRow" ? 1 : topSpan; 34605 } else if (direction === "up") { 34606 fRow -= focusRow === "minRow" ? 1 : bottomSpan; 34607 } 34608 const targetRowMap = tableMap[fRow]; 34609 if (targetRowMap === void 0) { 34610 return false; 34611 } 34612 const newFocusCellValue = targetRowMap[fCol]; 34613 if (newFocusCellValue === void 0) { 34614 return false; 34615 } 34616 const [finalAnchorCell, finalFocusCell] = $extractRectCorners(tableMap, anchorCellValue, newFocusCellValue); 34617 const anchorDOM = $getObserverCellFromCellNodeOrThrow(tableObserver, finalAnchorCell.cell); 34618 const focusDOM = $getObserverCellFromCellNodeOrThrow(tableObserver, finalFocusCell.cell); 34619 tableObserver.$setAnchorCellForSelection(anchorDOM); 34620 tableObserver.$setFocusCellForSelection(focusDOM, true); 34621 return true; 34622 } 34623 function $isSelectionInTable(selection, tableNode) { 34624 if ($isRangeSelection2(selection) || $isTableSelection(selection)) { 34625 const isAnchorInside = tableNode.isParentOf(selection.anchor.getNode()); 34626 const isFocusInside = tableNode.isParentOf(selection.focus.getNode()); 34627 return isAnchorInside && isFocusInside; 34628 } 34629 return false; 34630 } 34631 function $isFullTableSelection(selection, tableNode) { 34632 if ($isTableSelection(selection)) { 34633 const anchorNode = selection.anchor.getNode(); 34634 const focusNode = selection.focus.getNode(); 34635 if (tableNode && anchorNode && focusNode) { 34636 const [map] = $computeTableMap(tableNode, anchorNode, focusNode); 34637 return anchorNode.getKey() === map[0][0].cell.getKey() && focusNode.getKey() === map[map.length - 1].at(-1).cell.getKey(); 34638 } 34639 } 34640 return false; 34641 } 34642 function selectTableCellNode(tableCell, fromStart) { 34643 if (fromStart) { 34644 tableCell.selectStart(); 34645 } else { 34646 tableCell.selectEnd(); 34647 } 34648 } 34649 function $addHighlightToDOM(editor, cell) { 34650 const element = cell.elem; 34651 const editorThemeClasses = editor._config.theme; 34652 const node = $getNearestNodeFromDOMNode2(element); 34653 if (!$isTableCellNode(node)) { 34654 formatDevErrorMessage12(`Expected to find LexicalNode from Table Cell DOMNode`); 34655 } 34656 addClassNamesToElement3(element, editorThemeClasses.tableCellSelected); 34657 } 34658 function $removeHighlightFromDOM(editor, cell) { 34659 const element = cell.elem; 34660 const node = $getNearestNodeFromDOMNode2(element); 34661 if (!$isTableCellNode(node)) { 34662 formatDevErrorMessage12(`Expected to find LexicalNode from Table Cell DOMNode`); 34663 } 34664 const editorThemeClasses = editor._config.theme; 34665 removeClassNamesFromElement3(element, editorThemeClasses.tableCellSelected); 34666 } 34667 function $findCellNode(node) { 34668 const cellNode = $findMatchingParent3(node, $isTableCellNode); 34669 return $isTableCellNode(cellNode) ? cellNode : null; 34670 } 34671 function $findTableNode(node) { 34672 const tableNode = $findMatchingParent3(node, $isTableNode); 34673 return $isTableNode(tableNode) ? tableNode : null; 34674 } 34675 function $getBlockParentIfFirstNode(node) { 34676 for (let prevNode = node, currentNode = node; currentNode !== null; prevNode = currentNode, currentNode = currentNode.getParent()) { 34677 if ($isElementNode2(currentNode)) { 34678 if (currentNode !== prevNode && currentNode.getFirstChild() !== prevNode) { 34679 return null; 34680 } else if (!currentNode.isInline()) { 34681 return currentNode; 34682 } 34683 } 34684 } 34685 return null; 34686 } 34687 function $handleHorizontalArrowKeyRangeSelection(editor, event, selection, alter, isBackward, tableNode, tableObserver) { 34688 const initialFocus = $caretFromPoint2(selection.focus, isBackward ? "previous" : "next"); 34689 if ($isExtendableTextPointCaret2(initialFocus)) { 34690 return false; 34691 } 34692 let lastCaret = initialFocus; 34693 for (const nextCaret of $extendCaretToRange2(initialFocus).iterNodeCarets("shadowRoot")) { 34694 if (!($isSiblingCaret2(nextCaret) && $isElementNode2(nextCaret.origin))) { 34695 return false; 34696 } 34697 lastCaret = nextCaret; 34698 } 34699 const lastCaretParent = lastCaret.getParentAtCaret(); 34700 if (!$isTableCellNode(lastCaretParent)) { 34701 return false; 34702 } 34703 const anchorCell = lastCaretParent; 34704 const focusCaret = $findNextTableCell($getSiblingCaret2(anchorCell, lastCaret.direction)); 34705 const anchorCellTable = $findMatchingParent3(anchorCell, $isTableNode); 34706 if (!(anchorCellTable && anchorCellTable.is(tableNode))) { 34707 return false; 34708 } 34709 const anchorCellDOM = editor.getElementByKey(anchorCell.getKey()); 34710 const anchorDOMCell = getDOMCellFromTarget(anchorCellDOM); 34711 if (!anchorCellDOM || !anchorDOMCell) { 34712 return false; 34713 } 34714 const anchorCellTableElement = $getElementForTableNode(editor, anchorCellTable); 34715 tableObserver.table = anchorCellTableElement; 34716 if (!focusCaret) { 34717 if (alter === "extend") { 34718 tableObserver.$setAnchorCellForSelection(anchorDOMCell); 34719 tableObserver.$setFocusCellForSelection(anchorDOMCell, true); 34720 } else { 34721 const outerFocusCaret = $getTableExitCaret($getSiblingCaret2(anchorCellTable, initialFocus.direction)); 34722 $setPointFromCaret2(selection.anchor, outerFocusCaret); 34723 $setPointFromCaret2(selection.focus, outerFocusCaret); 34724 } 34725 } else if (alter === "extend") { 34726 const focusDOMCell = getDOMCellFromTarget(editor.getElementByKey(focusCaret.origin.getKey())); 34727 if (!focusDOMCell) { 34728 return false; 34729 } 34730 tableObserver.$setAnchorCellForSelection(anchorDOMCell); 34731 tableObserver.$setFocusCellForSelection(focusDOMCell, true); 34732 } else { 34733 const innerFocusCaret = $normalizeCaret2(focusCaret); 34734 $setPointFromCaret2(selection.anchor, innerFocusCaret); 34735 $setPointFromCaret2(selection.focus, innerFocusCaret); 34736 } 34737 stopEvent(event); 34738 return true; 34739 } 34740 function $getTableExitCaret(initialCaret) { 34741 const adjacent = $getAdjacentChildCaret2(initialCaret); 34742 return $isChildCaret2(adjacent) ? $normalizeCaret2(adjacent) : initialCaret; 34743 } 34744 function $findNextTableCell(initialCaret) { 34745 for (const nextCaret of $extendCaretToRange2(initialCaret).iterNodeCarets("root")) { 34746 const { 34747 origin 34748 } = nextCaret; 34749 if ($isTableCellNode(origin)) { 34750 if ($isChildCaret2(nextCaret)) { 34751 return $getChildCaret2(origin, initialCaret.direction); 34752 } 34753 } else if (!$isTableRowNode(origin)) { 34754 break; 34755 } 34756 } 34757 return null; 34758 } 34759 function $handleArrowKey(editor, event, direction, tableNode, tableObserver, tableObservers) { 34760 if ((direction === "up" || direction === "down") && isTypeaheadMenuInView(editor)) { 34761 return false; 34762 } 34763 const selection = $getSelection2(); 34764 if (!$isSelectionInTable(selection, tableNode)) { 34765 if ($isRangeSelection2(selection)) { 34766 if (direction === "backward") { 34767 if (selection.focus.offset > 0) { 34768 return false; 34769 } 34770 const parentNode = $getBlockParentIfFirstNode(selection.focus.getNode()); 34771 if (!parentNode) { 34772 return false; 34773 } 34774 const siblingNode = parentNode.getPreviousSibling(); 34775 if (!$isTableNode(siblingNode)) { 34776 return false; 34777 } 34778 stopEvent(event); 34779 if (event.shiftKey) { 34780 selection.focus.set(siblingNode.getParentOrThrow().getKey(), siblingNode.getIndexWithinParent(), "element"); 34781 } else { 34782 siblingNode.selectEnd(); 34783 } 34784 return true; 34785 } else if (event.shiftKey && (direction === "up" || direction === "down")) { 34786 const focusNode = selection.focus.getNode(); 34787 const isTableUnselect = !selection.isCollapsed() && (direction === "up" && !selection.isBackward() || direction === "down" && selection.isBackward()); 34788 if (isTableUnselect) { 34789 let focusParentNode = $findMatchingParent3(focusNode, (n2) => $isTableNode(n2)); 34790 if ($isTableCellNode(focusParentNode)) { 34791 focusParentNode = $findMatchingParent3(focusParentNode, $isTableNode); 34792 } 34793 if (focusParentNode !== tableNode) { 34794 return false; 34795 } 34796 if (!focusParentNode) { 34797 return false; 34798 } 34799 const sibling = direction === "down" ? focusParentNode.getNextSibling() : focusParentNode.getPreviousSibling(); 34800 if (!sibling) { 34801 return false; 34802 } 34803 let newOffset = 0; 34804 if (direction === "up") { 34805 if ($isElementNode2(sibling)) { 34806 newOffset = sibling.getChildrenSize(); 34807 } 34808 } 34809 let newFocusNode = sibling; 34810 if (direction === "up") { 34811 if ($isElementNode2(sibling)) { 34812 const lastCell = sibling.getLastChild(); 34813 newFocusNode = lastCell ? lastCell : sibling; 34814 newOffset = $isTextNode2(newFocusNode) ? newFocusNode.getTextContentSize() : 0; 34815 } 34816 } 34817 const newSelection = selection.clone(); 34818 newSelection.focus.set(newFocusNode.getKey(), newOffset, $isTextNode2(newFocusNode) ? "text" : "element"); 34819 $setSelection2(newSelection); 34820 stopEvent(event); 34821 return true; 34822 } else if ($isRootOrShadowRoot2(focusNode)) { 34823 const selectedNode = direction === "up" ? selection.getNodes()[selection.getNodes().length - 1] : selection.getNodes()[0]; 34824 if (selectedNode) { 34825 const tableCellNode = $findParentTableCellNodeInTable(tableNode, selectedNode); 34826 if (tableCellNode !== null) { 34827 const firstDescendant = tableNode.getFirstDescendant(); 34828 const lastDescendant = tableNode.getLastDescendant(); 34829 if (!firstDescendant || !lastDescendant) { 34830 return false; 34831 } 34832 const [firstCellNode] = $getNodeTriplet(firstDescendant); 34833 const [lastCellNode] = $getNodeTriplet(lastDescendant); 34834 const firstCellCoords = tableNode.getCordsFromCellNode(firstCellNode, tableObserver.table); 34835 const lastCellCoords = tableNode.getCordsFromCellNode(lastCellNode, tableObserver.table); 34836 const firstCellDOM = tableNode.getDOMCellFromCordsOrThrow(firstCellCoords.x, firstCellCoords.y, tableObserver.table); 34837 const lastCellDOM = tableNode.getDOMCellFromCordsOrThrow(lastCellCoords.x, lastCellCoords.y, tableObserver.table); 34838 tableObserver.$setAnchorCellForSelection(firstCellDOM); 34839 tableObserver.$setFocusCellForSelection(lastCellDOM, true); 34840 return true; 34841 } 34842 } 34843 return false; 34844 } else { 34845 let focusParentNode = $findMatchingParent3(focusNode, (n2) => $isElementNode2(n2) && !n2.isInline()); 34846 if ($isTableCellNode(focusParentNode)) { 34847 focusParentNode = $findMatchingParent3(focusParentNode, $isTableNode); 34848 } 34849 if (!focusParentNode) { 34850 return false; 34851 } 34852 const sibling = direction === "down" ? focusParentNode.getNextSibling() : focusParentNode.getPreviousSibling(); 34853 if ($isTableNode(sibling) && tableObserver.tableNodeKey === sibling.getKey()) { 34854 const firstDescendant = sibling.getFirstDescendant(); 34855 const lastDescendant = sibling.getLastDescendant(); 34856 if (!firstDescendant || !lastDescendant) { 34857 return false; 34858 } 34859 const [firstCellNode] = $getNodeTriplet(firstDescendant); 34860 const [lastCellNode] = $getNodeTriplet(lastDescendant); 34861 const newSelection = selection.clone(); 34862 newSelection.focus.set((direction === "up" ? firstCellNode : lastCellNode).getKey(), direction === "up" ? 0 : lastCellNode.getChildrenSize(), "element"); 34863 stopEvent(event); 34864 $setSelection2(newSelection); 34865 return true; 34866 } 34867 } 34868 } 34869 } 34870 if (direction === "down" && $isScrollableTablesActive(editor)) { 34871 tableObservers.setShouldCheckSelectionForTable(tableNode.getKey()); 34872 } 34873 return false; 34874 } 34875 if ($isRangeSelection2(selection)) { 34876 if (direction === "backward" || direction === "forward") { 34877 const alter = event.shiftKey ? "extend" : "move"; 34878 return $handleHorizontalArrowKeyRangeSelection(editor, event, selection, alter, direction === "backward", tableNode, tableObserver); 34879 } 34880 if (selection.isCollapsed()) { 34881 const { 34882 anchor, 34883 focus 34884 } = selection; 34885 const anchorCellNode = $findMatchingParent3(anchor.getNode(), $isTableCellNode); 34886 const focusCellNode = $findMatchingParent3(focus.getNode(), $isTableCellNode); 34887 if (!$isTableCellNode(anchorCellNode) || !anchorCellNode.is(focusCellNode)) { 34888 return false; 34889 } 34890 const anchorCellTable = $findTableNode(anchorCellNode); 34891 if (anchorCellTable !== tableNode && anchorCellTable != null) { 34892 const anchorCellTableElement = getTableElement(anchorCellTable, editor.getElementByKey(anchorCellTable.getKey())); 34893 if (anchorCellTableElement != null) { 34894 tableObserver.table = getTable(anchorCellTable, anchorCellTableElement); 34895 return $handleArrowKey(editor, event, direction, anchorCellTable, tableObserver, tableObservers); 34896 } 34897 } 34898 const anchorCellDom = editor.getElementByKey(anchorCellNode.__key); 34899 const anchorDOM = editor.getElementByKey(anchor.key); 34900 if (anchorDOM == null || anchorCellDom == null) { 34901 return false; 34902 } 34903 let edgeSelectionRect; 34904 if (anchor.type === "element") { 34905 edgeSelectionRect = anchorDOM.getBoundingClientRect(); 34906 } else { 34907 const domSelection = getDOMSelection2(getEditorWindow(editor)); 34908 if (domSelection === null || domSelection.rangeCount === 0) { 34909 return false; 34910 } 34911 const range2 = domSelection.getRangeAt(0); 34912 edgeSelectionRect = range2.getBoundingClientRect(); 34913 } 34914 const edgeChild = direction === "up" ? anchorCellNode.getFirstChild() : anchorCellNode.getLastChild(); 34915 if (edgeChild == null) { 34916 return false; 34917 } 34918 const edgeChildDOM = editor.getElementByKey(edgeChild.__key); 34919 if (edgeChildDOM == null) { 34920 return false; 34921 } 34922 const edgeRect = edgeChildDOM.getBoundingClientRect(); 34923 const isExiting = direction === "up" ? edgeRect.top > edgeSelectionRect.top - edgeSelectionRect.height : edgeSelectionRect.bottom + edgeSelectionRect.height > edgeRect.bottom; 34924 if (isExiting) { 34925 stopEvent(event); 34926 const cords = tableNode.getCordsFromCellNode(anchorCellNode, tableObserver.table); 34927 if (event.shiftKey) { 34928 const cell = tableNode.getDOMCellFromCordsOrThrow(cords.x, cords.y, tableObserver.table); 34929 tableObserver.$setAnchorCellForSelection(cell); 34930 tableObserver.$setFocusCellForSelection(cell, true); 34931 } else { 34932 return selectTableNodeInDirection(tableObserver, tableNode, cords.x, cords.y, direction); 34933 } 34934 return true; 34935 } 34936 } 34937 } else if ($isTableSelection(selection)) { 34938 const { 34939 anchor, 34940 focus 34941 } = selection; 34942 const anchorCellNode = $findMatchingParent3(anchor.getNode(), $isTableCellNode); 34943 const focusCellNode = $findMatchingParent3(focus.getNode(), $isTableCellNode); 34944 const [tableNodeFromSelection] = selection.getNodes(); 34945 if (!$isTableNode(tableNodeFromSelection)) { 34946 formatDevErrorMessage12(`$handleArrowKey: TableSelection.getNodes()[0] expected to be TableNode`); 34947 } 34948 const tableElement = getTableElement(tableNodeFromSelection, editor.getElementByKey(tableNodeFromSelection.getKey())); 34949 if (!$isTableCellNode(anchorCellNode) || !$isTableCellNode(focusCellNode) || !$isTableNode(tableNodeFromSelection) || tableElement == null) { 34950 return false; 34951 } 34952 tableObserver.$updateTableTableSelection(selection); 34953 const grid = getTable(tableNodeFromSelection, tableElement); 34954 const cordsAnchor = tableNode.getCordsFromCellNode(anchorCellNode, grid); 34955 const anchorCell = tableNode.getDOMCellFromCordsOrThrow(cordsAnchor.x, cordsAnchor.y, grid); 34956 tableObserver.$setAnchorCellForSelection(anchorCell); 34957 stopEvent(event); 34958 if (event.shiftKey) { 34959 const [tableMap, anchorValue, focusValue] = $computeTableMap(tableNode, anchorCellNode, focusCellNode); 34960 return $adjustFocusInDirection(tableObserver, tableMap, anchorValue, focusValue, direction); 34961 } else { 34962 focusCellNode.selectEnd(); 34963 } 34964 return true; 34965 } 34966 return false; 34967 } 34968 function stopEvent(event) { 34969 event.preventDefault(); 34970 event.stopImmediatePropagation(); 34971 event.stopPropagation(); 34972 } 34973 function isTypeaheadMenuInView(editor) { 34974 const root = editor.getRootElement(); 34975 if (!root) { 34976 return false; 34977 } 34978 return root.hasAttribute("aria-controls") && root.getAttribute("aria-controls") === "typeahead-menu"; 34979 } 34980 function $insertParagraphAtTableEdge(edgePosition, tableNode, children) { 34981 const paragraphNode = $createParagraphNode2(); 34982 if (edgePosition === "first") { 34983 tableNode.insertBefore(paragraphNode); 34984 } else { 34985 tableNode.insertAfter(paragraphNode); 34986 } 34987 paragraphNode.append(...children || []); 34988 paragraphNode.selectEnd(); 34989 } 34990 function $getTableEdgeCursorPosition(editor, selection, tableNode) { 34991 const tableNodeParent = tableNode.getParent(); 34992 if (!tableNodeParent) { 34993 return void 0; 34994 } 34995 const domSelection = getDOMSelection2(getEditorWindow(editor)); 34996 if (!domSelection) { 34997 return void 0; 34998 } 34999 const domAnchorNode = domSelection.anchorNode; 35000 const tableNodeParentDOM = editor.getElementByKey(tableNodeParent.getKey()); 35001 const tableElement = getTableElement(tableNode, editor.getElementByKey(tableNode.getKey())); 35002 if (!domAnchorNode || !tableNodeParentDOM || !tableElement || !tableNodeParentDOM.contains(domAnchorNode) || tableElement.contains(domAnchorNode)) { 35003 return void 0; 35004 } 35005 const anchorCellNode = $findMatchingParent3(selection.anchor.getNode(), (n2) => $isTableCellNode(n2)); 35006 if (!anchorCellNode) { 35007 return void 0; 35008 } 35009 const parentTable = $findMatchingParent3(anchorCellNode, (n2) => $isTableNode(n2)); 35010 if (!$isTableNode(parentTable) || !parentTable.is(tableNode)) { 35011 return void 0; 35012 } 35013 const [tableMap, cellValue] = $computeTableMap(tableNode, anchorCellNode, anchorCellNode); 35014 const firstCell = tableMap[0][0]; 35015 const lastCell = tableMap[tableMap.length - 1][tableMap[0].length - 1]; 35016 const { 35017 startRow, 35018 startColumn 35019 } = cellValue; 35020 const isAtFirstCell = startRow === firstCell.startRow && startColumn === firstCell.startColumn; 35021 const isAtLastCell = startRow === lastCell.startRow && startColumn === lastCell.startColumn; 35022 if (isAtFirstCell) { 35023 return "first"; 35024 } else if (isAtLastCell) { 35025 return "last"; 35026 } else { 35027 return void 0; 35028 } 35029 } 35030 function $getObserverCellFromCellNodeOrThrow(tableObserver, tableCellNode) { 35031 const { 35032 tableNode 35033 } = tableObserver.$lookup(); 35034 const currentCords = tableNode.getCordsFromCellNode(tableCellNode, tableObserver.table); 35035 return tableNode.getDOMCellFromCordsOrThrow(currentCords.x, currentCords.y, tableObserver.table); 35036 } 35037 function $getNearestTableCellInTableFromDOMNode(tableNode, startingDOM, editorState) { 35038 return $findParentTableCellNodeInTable(tableNode, $getNearestNodeFromDOMNode2(startingDOM, editorState)); 35039 } 35040 function isHTMLDivElement(element) { 35041 return isHTMLElement3(element) && element.nodeName === "DIV"; 35042 } 35043 function updateColgroup(dom, colCount, colWidths) { 35044 const colGroup = dom.querySelector("colgroup"); 35045 if (!colGroup) { 35046 return; 35047 } 35048 const cols = []; 35049 for (let i2 = 0; i2 < colCount; i2++) { 35050 const col = document.createElement("col"); 35051 const width = colWidths && colWidths[i2]; 35052 if (width) { 35053 col.style.width = `${width}px`; 35054 } 35055 cols.push(col); 35056 } 35057 colGroup.replaceChildren(...cols); 35058 } 35059 function setRowStriping(dom, config, rowStriping) { 35060 if (rowStriping) { 35061 addClassNamesToElement3(dom, config.theme.tableRowStriping); 35062 dom.setAttribute("data-lexical-row-striping", "true"); 35063 } else { 35064 removeClassNamesFromElement3(dom, config.theme.tableRowStriping); 35065 dom.removeAttribute("data-lexical-row-striping"); 35066 } 35067 } 35068 function setFrozenColumns(dom, tableElement, config, frozenColumnCount) { 35069 if (frozenColumnCount > 0) { 35070 addClassNamesToElement3(dom, config.theme.tableFrozenColumn); 35071 tableElement.setAttribute("data-lexical-frozen-column", "true"); 35072 } else { 35073 removeClassNamesFromElement3(dom, config.theme.tableFrozenColumn); 35074 tableElement.removeAttribute("data-lexical-frozen-column"); 35075 } 35076 } 35077 function setFrozenRows(dom, tableElement, config, frozenRowCount) { 35078 if (frozenRowCount > 0) { 35079 addClassNamesToElement3(dom, config.theme.tableFrozenRow); 35080 tableElement.setAttribute("data-lexical-frozen-row", "true"); 35081 } else { 35082 removeClassNamesFromElement3(dom, config.theme.tableFrozenRow); 35083 tableElement.removeAttribute("data-lexical-frozen-row"); 35084 } 35085 } 35086 function alignTableElement(dom, config, formatType) { 35087 if (!config.theme.tableAlignment) { 35088 return; 35089 } 35090 const removeClasses = []; 35091 const addClasses = []; 35092 for (const format of ["center", "right"]) { 35093 const classes = config.theme.tableAlignment[format]; 35094 if (!classes) { 35095 continue; 35096 } 35097 (format === formatType ? addClasses : removeClasses).push(classes); 35098 } 35099 removeClassNamesFromElement3(dom, ...removeClasses); 35100 addClassNamesToElement3(dom, ...addClasses); 35101 } 35102 var scrollableEditors = /* @__PURE__ */ new WeakSet(); 35103 function $isScrollableTablesActive(editor = $getEditor2()) { 35104 return scrollableEditors.has(editor); 35105 } 35106 function setScrollableTablesActive(editor, active) { 35107 if (active) { 35108 if (!editor._config.theme.tableScrollableWrapper) { 35109 console.warn("TableNode: hasHorizontalScroll is active but theme.tableScrollableWrapper is not defined."); 35110 } 35111 scrollableEditors.add(editor); 35112 } else { 35113 scrollableEditors.delete(editor); 35114 } 35115 } 35116 var TableNode = class _TableNode extends ElementNode2 { 35117 /** @internal */ 35118 __rowStriping; 35119 __frozenColumnCount; 35120 __frozenRowCount; 35121 __colWidths; 35122 static getType() { 35123 return "table"; 35124 } 35125 getColWidths() { 35126 const self2 = this.getLatest(); 35127 return self2.__colWidths; 35128 } 35129 setColWidths(colWidths) { 35130 const self2 = this.getWritable(); 35131 self2.__colWidths = colWidths !== void 0 && true ? Object.freeze(colWidths) : colWidths; 35132 return self2; 35133 } 35134 static clone(node) { 35135 return new _TableNode(node.__key); 35136 } 35137 afterCloneFrom(prevNode) { 35138 super.afterCloneFrom(prevNode); 35139 this.__colWidths = prevNode.__colWidths; 35140 this.__rowStriping = prevNode.__rowStriping; 35141 this.__frozenColumnCount = prevNode.__frozenColumnCount; 35142 this.__frozenRowCount = prevNode.__frozenRowCount; 35143 } 35144 static importDOM() { 35145 return { 35146 table: (_node) => ({ 35147 conversion: $convertTableElement2, 35148 priority: 1 35149 }) 35150 }; 35151 } 35152 static importJSON(serializedNode) { 35153 return $createTableNode().updateFromJSON(serializedNode); 35154 } 35155 updateFromJSON(serializedNode) { 35156 return super.updateFromJSON(serializedNode).setRowStriping(serializedNode.rowStriping || false).setFrozenColumns(serializedNode.frozenColumnCount || 0).setFrozenRows(serializedNode.frozenRowCount || 0).setColWidths(serializedNode.colWidths); 35157 } 35158 constructor(key) { 35159 super(key); 35160 this.__rowStriping = false; 35161 this.__frozenColumnCount = 0; 35162 this.__frozenRowCount = 0; 35163 this.__colWidths = void 0; 35164 } 35165 exportJSON() { 35166 return { 35167 ...super.exportJSON(), 35168 colWidths: this.getColWidths(), 35169 frozenColumnCount: this.__frozenColumnCount ? this.__frozenColumnCount : void 0, 35170 frozenRowCount: this.__frozenRowCount ? this.__frozenRowCount : void 0, 35171 rowStriping: this.__rowStriping ? this.__rowStriping : void 0 35172 }; 35173 } 35174 extractWithChild(child, selection, destination) { 35175 return destination === "html"; 35176 } 35177 getDOMSlot(element) { 35178 const tableElement = !isHTMLTableElement(element) ? element.querySelector("table") : element; 35179 if (!isHTMLTableElement(tableElement)) { 35180 formatDevErrorMessage12(`TableNode.getDOMSlot: createDOM() did not return a table`); 35181 } 35182 return super.getDOMSlot(element).withElement(tableElement).withAfter(tableElement.querySelector("colgroup")); 35183 } 35184 createDOM(config, editor) { 35185 const tableElement = document.createElement("table"); 35186 if (this.__style) { 35187 setDOMStyleFromCSS2(tableElement.style, this.__style); 35188 } 35189 const colGroup = document.createElement("colgroup"); 35190 tableElement.appendChild(colGroup); 35191 setDOMUnmanaged2(colGroup); 35192 addClassNamesToElement3(tableElement, config.theme.table); 35193 this.updateTableElement(null, tableElement, config); 35194 if ($isScrollableTablesActive(editor)) { 35195 const wrapperElement = document.createElement("div"); 35196 const classes = config.theme.tableScrollableWrapper; 35197 if (classes) { 35198 addClassNamesToElement3(wrapperElement, classes); 35199 } else { 35200 wrapperElement.style.overflowX = "auto"; 35201 } 35202 wrapperElement.appendChild(tableElement); 35203 this.updateTableWrapper(null, wrapperElement, tableElement, config); 35204 return wrapperElement; 35205 } 35206 return tableElement; 35207 } 35208 updateTableWrapper(prevNode, tableWrapper, tableElement, config) { 35209 if (this.__frozenColumnCount !== (prevNode ? prevNode.__frozenColumnCount : 0)) { 35210 setFrozenColumns(tableWrapper, tableElement, config, this.__frozenColumnCount); 35211 } 35212 if (this.__frozenRowCount !== (prevNode ? prevNode.__frozenRowCount : 0)) { 35213 setFrozenRows(tableWrapper, tableElement, config, this.__frozenRowCount); 35214 } 35215 } 35216 updateTableElement(prevNode, tableElement, config) { 35217 if (this.__style !== (prevNode ? prevNode.__style : "")) { 35218 setDOMStyleFromCSS2(tableElement.style, this.__style, prevNode ? prevNode.__style : ""); 35219 } 35220 if (this.__rowStriping !== (prevNode ? prevNode.__rowStriping : false)) { 35221 setRowStriping(tableElement, config, this.__rowStriping); 35222 } 35223 const prevColCount = prevNode ? prevNode.getColumnCount() : 0; 35224 const prevColWidths = prevNode ? prevNode.__colWidths : void 0; 35225 if (this.getColumnCount() !== prevColCount || this.getColWidths() !== prevColWidths) { 35226 updateColgroup(tableElement, this.getColumnCount(), this.getColWidths()); 35227 } 35228 alignTableElement(tableElement, config, this.getFormatType()); 35229 } 35230 updateDOM(prevNode, dom, config) { 35231 const tableElement = getTableElement(this, dom); 35232 if (dom === tableElement === $isScrollableTablesActive()) { 35233 return true; 35234 } 35235 if (isHTMLDivElement(dom)) { 35236 this.updateTableWrapper(prevNode, dom, tableElement, config); 35237 } 35238 this.updateTableElement(prevNode, tableElement, config); 35239 return false; 35240 } 35241 scaleDOMColWidths(dom, scale) { 35242 const colWidths = this.getColWidths(); 35243 if (!colWidths) { 35244 return; 35245 } 35246 const tableElement = getTableElement(this, dom); 35247 updateColgroup(tableElement, this.getColumnCount(), colWidths.map((width) => width * scale)); 35248 } 35249 exportDOM(editor) { 35250 const superExport = super.exportDOM(editor); 35251 const { 35252 element 35253 } = superExport; 35254 return { 35255 after: (tableElement) => { 35256 if (superExport.after) { 35257 tableElement = superExport.after(tableElement); 35258 } 35259 if (!isHTMLTableElement(tableElement) && isHTMLElement3(tableElement)) { 35260 tableElement = tableElement.querySelector("table"); 35261 } 35262 if (!isHTMLTableElement(tableElement)) { 35263 return null; 35264 } 35265 alignTableElement(tableElement, editor._config, this.getFormatType()); 35266 const [tableMap] = $computeTableMapSkipCellCheck(this, null, null); 35267 const cellValues = /* @__PURE__ */ new Map(); 35268 for (const mapRow of tableMap) { 35269 for (const mapValue of mapRow) { 35270 const key = mapValue.cell.getKey(); 35271 if (!cellValues.has(key)) { 35272 cellValues.set(key, { 35273 colSpan: mapValue.cell.getColSpan(), 35274 startColumn: mapValue.startColumn 35275 }); 35276 } 35277 } 35278 } 35279 const knownColumns = /* @__PURE__ */ new Set(); 35280 for (const cellDOM of tableElement.querySelectorAll(":scope > tr > [data-temporary-table-cell-lexical-key]")) { 35281 const key = cellDOM.getAttribute("data-temporary-table-cell-lexical-key"); 35282 if (key) { 35283 const cellSpan = cellValues.get(key); 35284 cellDOM.removeAttribute("data-temporary-table-cell-lexical-key"); 35285 if (cellSpan) { 35286 cellValues.delete(key); 35287 for (let i2 = 0; i2 < cellSpan.colSpan; i2++) { 35288 knownColumns.add(i2 + cellSpan.startColumn); 35289 } 35290 } 35291 } 35292 } 35293 const colGroup = tableElement.querySelector(":scope > colgroup"); 35294 if (colGroup) { 35295 const cols = Array.from(tableElement.querySelectorAll(":scope > colgroup > col")).filter((dom, i2) => knownColumns.has(i2)); 35296 colGroup.replaceChildren(...cols); 35297 } 35298 const rows = tableElement.querySelectorAll(":scope > tr"); 35299 if (rows.length > 0) { 35300 const tBody = document.createElement("tbody"); 35301 for (const row of rows) { 35302 tBody.appendChild(row); 35303 } 35304 tableElement.append(tBody); 35305 } 35306 return tableElement; 35307 }, 35308 element: !isHTMLTableElement(element) && isHTMLElement3(element) ? element.querySelector("table") : element 35309 }; 35310 } 35311 canBeEmpty() { 35312 return false; 35313 } 35314 isShadowRoot() { 35315 return true; 35316 } 35317 getCordsFromCellNode(tableCellNode, table) { 35318 const { 35319 rows, 35320 domRows 35321 } = table; 35322 for (let y3 = 0; y3 < rows; y3++) { 35323 const row = domRows[y3]; 35324 if (row == null) { 35325 continue; 35326 } 35327 for (let x3 = 0; x3 < row.length; x3++) { 35328 const cell = row[x3]; 35329 if (cell == null) { 35330 continue; 35331 } 35332 const { 35333 elem 35334 } = cell; 35335 const cellNode = $getNearestTableCellInTableFromDOMNode(this, elem); 35336 if (cellNode !== null && tableCellNode.is(cellNode)) { 35337 return { 35338 x: x3, 35339 y: y3 35340 }; 35341 } 35342 } 35343 } 35344 throw new Error("Cell not found in table."); 35345 } 35346 getDOMCellFromCords(x3, y3, table) { 35347 const { 35348 domRows 35349 } = table; 35350 const row = domRows[y3]; 35351 if (row == null) { 35352 return null; 35353 } 35354 const index = x3 < row.length ? x3 : row.length - 1; 35355 const cell = row[index]; 35356 if (cell == null) { 35357 return null; 35358 } 35359 return cell; 35360 } 35361 getDOMCellFromCordsOrThrow(x3, y3, table) { 35362 const cell = this.getDOMCellFromCords(x3, y3, table); 35363 if (!cell) { 35364 throw new Error("Cell not found at cords."); 35365 } 35366 return cell; 35367 } 35368 getCellNodeFromCords(x3, y3, table) { 35369 const cell = this.getDOMCellFromCords(x3, y3, table); 35370 if (cell == null) { 35371 return null; 35372 } 35373 const node = $getNearestNodeFromDOMNode2(cell.elem); 35374 if ($isTableCellNode(node)) { 35375 return node; 35376 } 35377 return null; 35378 } 35379 getCellNodeFromCordsOrThrow(x3, y3, table) { 35380 const node = this.getCellNodeFromCords(x3, y3, table); 35381 if (!node) { 35382 throw new Error("Node at cords not TableCellNode."); 35383 } 35384 return node; 35385 } 35386 getRowStriping() { 35387 return Boolean(this.getLatest().__rowStriping); 35388 } 35389 setRowStriping(newRowStriping) { 35390 const self2 = this.getWritable(); 35391 self2.__rowStriping = newRowStriping; 35392 return self2; 35393 } 35394 setFrozenColumns(columnCount) { 35395 const self2 = this.getWritable(); 35396 self2.__frozenColumnCount = columnCount; 35397 return self2; 35398 } 35399 getFrozenColumns() { 35400 return this.getLatest().__frozenColumnCount; 35401 } 35402 setFrozenRows(rowCount) { 35403 const self2 = this.getWritable(); 35404 self2.__frozenRowCount = rowCount; 35405 return self2; 35406 } 35407 getFrozenRows() { 35408 return this.getLatest().__frozenRowCount; 35409 } 35410 canSelectBefore() { 35411 return true; 35412 } 35413 canIndent() { 35414 return false; 35415 } 35416 getColumnCount() { 35417 const firstRow = this.getFirstChild(); 35418 if (!firstRow) { 35419 return 0; 35420 } 35421 let columnCount = 0; 35422 firstRow.getChildren().forEach((cell) => { 35423 if ($isTableCellNode(cell)) { 35424 columnCount += cell.getColSpan(); 35425 } 35426 }); 35427 return columnCount; 35428 } 35429 }; 35430 function $getElementForTableNode(editor, tableNode) { 35431 const tableElement = editor.getElementByKey(tableNode.getKey()); 35432 if (!(tableElement !== null)) { 35433 formatDevErrorMessage12(`$getElementForTableNode: Table Element Not Found`); 35434 } 35435 return getTable(tableNode, tableElement); 35436 } 35437 function $convertTableElement2(domNode) { 35438 const tableNode = $createTableNode(); 35439 if (domNode.hasAttribute("data-lexical-row-striping")) { 35440 tableNode.setRowStriping(true); 35441 } 35442 if (domNode.hasAttribute("data-lexical-frozen-column")) { 35443 tableNode.setFrozenColumns(1); 35444 } 35445 if (domNode.hasAttribute("data-lexical-frozen-row")) { 35446 tableNode.setFrozenRows(1); 35447 } 35448 const colGroup = domNode.querySelector(":scope > colgroup"); 35449 if (colGroup) { 35450 let columns = []; 35451 for (const col of colGroup.querySelectorAll(":scope > col")) { 35452 let width = col.style.width || ""; 35453 if (!PIXEL_VALUE_REG_EXP.test(width)) { 35454 width = col.getAttribute("width") || ""; 35455 if (!/^\d+$/.test(width)) { 35456 columns = void 0; 35457 break; 35458 } 35459 } 35460 columns.push(parseFloat(width)); 35461 } 35462 if (columns) { 35463 tableNode.setColWidths(columns); 35464 } 35465 } 35466 return { 35467 after: (children) => $descendantsMatching2(children, $isTableRowNode), 35468 node: tableNode 35469 }; 35470 } 35471 function $createTableNode() { 35472 return $applyNodeReplacement2(new TableNode()); 35473 } 35474 function $isTableNode(node) { 35475 return node instanceof TableNode; 35476 } 35477 function $insertTable({ 35478 rows, 35479 columns, 35480 includeHeaders 35481 }, hasNestedTables) { 35482 const selection = $getSelection2() || $getPreviousSelection2(); 35483 if (!selection || !$isRangeSelection2(selection)) { 35484 return false; 35485 } 35486 if (!hasNestedTables && $findTableNode(selection.anchor.getNode())) { 35487 return false; 35488 } 35489 const tableNode = $createTableNodeWithDimensions(Number(rows), Number(columns), includeHeaders); 35490 $insertNodeToNearestRoot2(tableNode); 35491 const firstDescendant = tableNode.getFirstDescendant(); 35492 if ($isTextNode2(firstDescendant)) { 35493 firstDescendant.select(); 35494 } 35495 return true; 35496 } 35497 function $tableCellTransform(node) { 35498 if (!$isTableRowNode(node.getParent())) { 35499 node.remove(); 35500 } else if (node.isEmpty()) { 35501 node.append($createParagraphNode2()); 35502 } 35503 } 35504 function $tableRowTransform(node) { 35505 if (!$isTableNode(node.getParent())) { 35506 node.remove(); 35507 } else { 35508 $unwrapAndFilterDescendants2(node, $isTableCellNode); 35509 } 35510 } 35511 function $tableTransform(node) { 35512 $unwrapAndFilterDescendants2(node, $isTableRowNode); 35513 const [gridMap] = $computeTableMapSkipCellCheck(node, null, null); 35514 const maxRowLength = gridMap.reduce((curLength, row) => { 35515 return Math.max(curLength, row.length); 35516 }, 0); 35517 const rowNodes = node.getChildren(); 35518 for (let i2 = 0; i2 < gridMap.length; ++i2) { 35519 const rowNode = rowNodes[i2]; 35520 if (!rowNode) { 35521 continue; 35522 } 35523 if (!$isTableRowNode(rowNode)) { 35524 formatDevErrorMessage12(`TablePlugin: Expecting all children of TableNode to be TableRowNode, found ${rowNode.constructor.name} (type ${rowNode.getType()})`); 35525 } 35526 const rowLength = gridMap[i2].reduce((acc, cell) => cell ? 1 + acc : acc, 0); 35527 if (rowLength === maxRowLength) { 35528 continue; 35529 } 35530 for (let j3 = rowLength; j3 < maxRowLength; ++j3) { 35531 const newCell = $createTableCellNode(); 35532 newCell.append($createParagraphNode2()); 35533 rowNode.append(newCell); 35534 } 35535 } 35536 const colWidths = node.getColWidths(); 35537 const columnCount = node.getColumnCount(); 35538 if (colWidths && colWidths.length !== columnCount) { 35539 let newColWidths = void 0; 35540 if (columnCount < colWidths.length) { 35541 newColWidths = colWidths.slice(0, columnCount); 35542 } else if (colWidths.length > 0) { 35543 const fillWidth = colWidths[colWidths.length - 1]; 35544 newColWidths = [...colWidths, ...Array(columnCount - colWidths.length).fill(fillWidth)]; 35545 } 35546 node.setColWidths(newColWidths); 35547 } 35548 } 35549 function $tableClickCommand(event) { 35550 if (event.detail < 3 || !isDOMNode2(event.target)) { 35551 return false; 35552 } 35553 const startNode = $getNearestNodeFromDOMNode2(event.target); 35554 if (startNode === null) { 35555 return false; 35556 } 35557 const blockNode = $findMatchingParent3(startNode, (node) => $isElementNode2(node) && !node.isInline()); 35558 if (blockNode === null) { 35559 return false; 35560 } 35561 const rootNode = blockNode.getParent(); 35562 if (!$isTableCellNode(rootNode)) { 35563 return false; 35564 } 35565 blockNode.select(0); 35566 return true; 35567 } 35568 function $tableSelectAllCommand() { 35569 const selection = $getSelection2(); 35570 if (!$isRangeSelection2(selection)) { 35571 return false; 35572 } 35573 const anchorNode = selection.anchor.getNode(); 35574 const tableNode = $findTableNode(anchorNode); 35575 if (tableNode === null) { 35576 return false; 35577 } 35578 const root = $getRoot2(); 35579 if (!root.is(tableNode.getParent()) || root.getChildrenSize() !== 1) { 35580 return false; 35581 } 35582 const [tableMap] = $computeTableMapSkipCellCheck(tableNode, null, null); 35583 if (tableMap.length === 0 || tableMap[0].length === 0) { 35584 return false; 35585 } 35586 const firstCellMap = tableMap[0][0]; 35587 if (!firstCellMap || !firstCellMap.cell) { 35588 return false; 35589 } 35590 const lastRow = tableMap[tableMap.length - 1]; 35591 const lastCellMap = lastRow[lastRow.length - 1]; 35592 if (!lastCellMap || !lastCellMap.cell) { 35593 return false; 35594 } 35595 const tableSelection = $createTableSelectionFrom(tableNode, firstCellMap.cell, lastCellMap.cell); 35596 $setSelection2(tableSelection); 35597 return true; 35598 } 35599 function registerTableCellUnmergeTransform(editor) { 35600 return editor.registerNodeTransform(TableCellNode, (node) => { 35601 if (node.getColSpan() > 1 || node.getRowSpan() > 1) { 35602 const [, , gridNode] = $getNodeTriplet(node); 35603 const [gridMap] = $computeTableMap(gridNode, node, node); 35604 const rowsCount = gridMap.length; 35605 const columnsCount = gridMap[0].length; 35606 let row = gridNode.getFirstChild(); 35607 if (!$isTableRowNode(row)) { 35608 formatDevErrorMessage12(`Expected TableNode first child to be a RowNode`); 35609 } 35610 const unmerged = []; 35611 for (let i2 = 0; i2 < rowsCount; i2++) { 35612 if (i2 !== 0) { 35613 row = row.getNextSibling(); 35614 if (!$isTableRowNode(row)) { 35615 formatDevErrorMessage12(`Expected TableNode first child to be a RowNode`); 35616 } 35617 } 35618 let lastRowCell = null; 35619 for (let j3 = 0; j3 < columnsCount; j3++) { 35620 const cellMap = gridMap[i2][j3]; 35621 const cell = cellMap.cell; 35622 if (cellMap.startRow === i2 && cellMap.startColumn === j3) { 35623 lastRowCell = cell; 35624 unmerged.push(cell); 35625 } else if (cell.getColSpan() > 1 || cell.getRowSpan() > 1) { 35626 if (!$isTableCellNode(cell)) { 35627 formatDevErrorMessage12(`Expected TableNode cell to be a TableCellNode`); 35628 } 35629 const newCell = $createTableCellNode(cell.__headerState); 35630 if (lastRowCell !== null) { 35631 lastRowCell.insertAfter(newCell); 35632 } else { 35633 $insertFirst2(row, newCell); 35634 } 35635 } 35636 } 35637 } 35638 for (const cell of unmerged) { 35639 cell.setColSpan(1); 35640 cell.setRowSpan(1); 35641 } 35642 } 35643 }); 35644 } 35645 function registerTableSelectionObserver(editor, hasTabHandler = true) { 35646 const tableObservers = new TableObservers(); 35647 const initializeTableNode = (tableNode, nodeKey, dom) => { 35648 const tableElement = getTableElement(tableNode, dom); 35649 const tableSelection = applyTableHandlers(tableNode, tableElement, editor, hasTabHandler, tableObservers); 35650 tableObservers.observers.set(nodeKey, [tableSelection, tableElement]); 35651 }; 35652 return mergeRegister3(registerTableWindowHandlers(editor, tableObservers), editor.registerCommand(SELECTION_CHANGE_COMMAND2, () => { 35653 return $handleTableSelectionChangeCommand(tableObservers, editor); 35654 }, COMMAND_PRIORITY_HIGH2), editor.registerMutationListener(TableNode, (nodeMutations) => { 35655 editor.getEditorState().read(() => { 35656 for (const [nodeKey, mutation] of nodeMutations) { 35657 const tableSelection = tableObservers.observers.get(nodeKey); 35658 if (mutation === "created" || mutation === "updated") { 35659 const { 35660 tableNode, 35661 tableElement 35662 } = $getTableAndElementByKey(nodeKey); 35663 if (tableSelection === void 0) { 35664 initializeTableNode(tableNode, nodeKey, tableElement); 35665 } else if (tableElement !== tableSelection[1]) { 35666 tableSelection[0].removeListeners(); 35667 tableObservers.observers.delete(nodeKey); 35668 initializeTableNode(tableNode, nodeKey, tableElement); 35669 } 35670 } else if (mutation === "destroyed") { 35671 if (tableSelection !== void 0) { 35672 tableSelection[0].removeListeners(); 35673 tableObservers.observers.delete(nodeKey); 35674 } 35675 } 35676 } 35677 }, { 35678 editor 35679 }); 35680 }, { 35681 skipInitialization: false 35682 }), () => { 35683 for (const [, [tableSelection]] of tableObservers.observers) { 35684 tableSelection.removeListeners(); 35685 } 35686 }); 35687 } 35688 function registerTablePlugin(editor, options) { 35689 if (!editor.hasNodes([TableNode])) { 35690 { 35691 formatDevErrorMessage12(`TablePlugin: TableNode is not registered on editor`); 35692 } 35693 } 35694 const { 35695 hasNestedTables = signal(false) 35696 } = options ?? {}; 35697 return mergeRegister3(editor.registerCommand(INSERT_TABLE_COMMAND, (payload) => { 35698 return $insertTable(payload, hasNestedTables.peek()); 35699 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(SELECTION_INSERT_CLIPBOARD_NODES_COMMAND2, (payload, dispatchEditor) => { 35700 if (editor !== dispatchEditor) { 35701 return false; 35702 } 35703 return $tableSelectionInsertClipboardNodesCommand(payload, hasNestedTables); 35704 }, COMMAND_PRIORITY_EDITOR2), editor.registerCommand(SELECT_ALL_COMMAND2, $tableSelectAllCommand, COMMAND_PRIORITY_LOW2), editor.registerCommand(CLICK_COMMAND2, $tableClickCommand, COMMAND_PRIORITY_EDITOR2), editor.registerNodeTransform(TableNode, $tableTransform), editor.registerNodeTransform(TableRowNode, $tableRowTransform), editor.registerNodeTransform(TableCellNode, $tableCellTransform)); 35705 } 35706 function $tableSelectionInsertClipboardNodesCommand(selectionPayload, hasNestedTables) { 35707 const { 35708 nodes, 35709 selection 35710 } = selectionPayload; 35711 const hasTables = nodes.some((n2) => $isTableNode(n2) || $dfs2(n2).some((d3) => $isTableNode(d3.node))); 35712 if (!hasTables) { 35713 return false; 35714 } 35715 const isTableSelection = $isTableSelection(selection); 35716 const isRangeSelection = $isRangeSelection2(selection); 35717 const isSelectionInsideOfGrid = isRangeSelection && $findMatchingParent3(selection.anchor.getNode(), (n2) => $isTableCellNode(n2)) !== null && $findMatchingParent3(selection.focus.getNode(), (n2) => $isTableCellNode(n2)) !== null || isTableSelection; 35718 if (!isSelectionInsideOfGrid) { 35719 return false; 35720 } 35721 if (nodes.length === 1 && $isTableNode(nodes[0])) { 35722 return $insertTableIntoGrid(nodes[0], selection); 35723 } 35724 if (isRangeSelection && hasNestedTables.peek() && !$isMultiCellTableSelection(selection)) { 35725 return false; 35726 } 35727 return true; 35728 } 35729 function $insertTableIntoGrid(tableNode, selection) { 35730 const anchorAndFocus = selection.getStartEndPoints(); 35731 const isTableSelection = $isTableSelection(selection); 35732 if (anchorAndFocus === null) { 35733 return false; 35734 } 35735 const [anchor, focus] = anchorAndFocus; 35736 const [anchorCellNode, anchorRowNode, gridNode] = $getNodeTriplet(anchor); 35737 const focusCellNode = $findMatchingParent3(focus.getNode(), (n2) => $isTableCellNode(n2)); 35738 if (!$isTableCellNode(anchorCellNode) || !$isTableCellNode(focusCellNode) || !$isTableRowNode(anchorRowNode) || !$isTableNode(gridNode)) { 35739 return false; 35740 } 35741 const [initialGridMap, anchorCellMap, focusCellMap] = $computeTableMap(gridNode, anchorCellNode, focusCellNode); 35742 const [templateGridMap] = $computeTableMapSkipCellCheck(tableNode, null, null); 35743 const initialRowCount = initialGridMap.length; 35744 const initialColCount = initialRowCount > 0 ? initialGridMap[0].length : 0; 35745 let startRow = anchorCellMap.startRow; 35746 let startCol = anchorCellMap.startColumn; 35747 let affectedRowCount = templateGridMap.length; 35748 let affectedColCount = affectedRowCount > 0 ? templateGridMap[0].length : 0; 35749 if (isTableSelection) { 35750 const selectionBoundary = $computeTableCellRectBoundary(initialGridMap, anchorCellMap, focusCellMap); 35751 const selectionRowCount = selectionBoundary.maxRow - selectionBoundary.minRow + 1; 35752 const selectionColCount = selectionBoundary.maxColumn - selectionBoundary.minColumn + 1; 35753 startRow = selectionBoundary.minRow; 35754 startCol = selectionBoundary.minColumn; 35755 affectedRowCount = Math.min(affectedRowCount, selectionRowCount); 35756 affectedColCount = Math.min(affectedColCount, selectionColCount); 35757 } 35758 let didPerformMergeOperations = false; 35759 const lastRowForUnmerge = Math.min(initialRowCount, startRow + affectedRowCount) - 1; 35760 const lastColForUnmerge = Math.min(initialColCount, startCol + affectedColCount) - 1; 35761 const unmergedKeys = /* @__PURE__ */ new Set(); 35762 for (let row = startRow; row <= lastRowForUnmerge; row++) { 35763 for (let col = startCol; col <= lastColForUnmerge; col++) { 35764 const cellMap = initialGridMap[row][col]; 35765 if (unmergedKeys.has(cellMap.cell.getKey())) { 35766 continue; 35767 } 35768 if (cellMap.cell.__rowSpan === 1 && cellMap.cell.__colSpan === 1) { 35769 continue; 35770 } 35771 $unmergeCellNode(cellMap.cell); 35772 unmergedKeys.add(cellMap.cell.getKey()); 35773 didPerformMergeOperations = true; 35774 } 35775 } 35776 let [interimGridMap] = $computeTableMapSkipCellCheck(gridNode.getWritable(), null, null); 35777 const rowsToInsert = affectedRowCount - initialRowCount + startRow; 35778 for (let i2 = 0; i2 < rowsToInsert; i2++) { 35779 const cellMap = interimGridMap[initialRowCount - 1][0]; 35780 $insertTableRowAtNode(cellMap.cell); 35781 } 35782 const colsToInsert = affectedColCount - initialColCount + startCol; 35783 for (let i2 = 0; i2 < colsToInsert; i2++) { 35784 const cellMap = interimGridMap[0][initialColCount - 1]; 35785 $insertTableColumnAtNode(cellMap.cell, true, false); 35786 } 35787 [interimGridMap] = $computeTableMapSkipCellCheck(gridNode.getWritable(), null, null); 35788 for (let row = startRow; row < startRow + affectedRowCount; row++) { 35789 for (let col = startCol; col < startCol + affectedColCount; col++) { 35790 const templateRow = row - startRow; 35791 const templateCol = col - startCol; 35792 const templateCellMap = templateGridMap[templateRow][templateCol]; 35793 if (templateCellMap.startRow !== templateRow || templateCellMap.startColumn !== templateCol) { 35794 continue; 35795 } 35796 const templateCell = templateCellMap.cell; 35797 if (templateCell.__rowSpan !== 1 || templateCell.__colSpan !== 1) { 35798 const cellsToMerge = []; 35799 const lastRowForMerge = Math.min(row + templateCell.__rowSpan, startRow + affectedRowCount) - 1; 35800 const lastColForMerge = Math.min(col + templateCell.__colSpan, startCol + affectedColCount) - 1; 35801 for (let r2 = row; r2 <= lastRowForMerge; r2++) { 35802 for (let c2 = col; c2 <= lastColForMerge; c2++) { 35803 const cellMap = interimGridMap[r2][c2]; 35804 cellsToMerge.push(cellMap.cell); 35805 } 35806 } 35807 $mergeCells(cellsToMerge); 35808 didPerformMergeOperations = true; 35809 } 35810 const { 35811 cell 35812 } = interimGridMap[row][col]; 35813 const backgroundColor = templateCell.getBackgroundColor(); 35814 if (backgroundColor !== null && backgroundColor !== void 0) { 35815 cell.setBackgroundColor(backgroundColor); 35816 } 35817 const originalChildren = cell.getChildren(); 35818 templateCell.getChildren().forEach((child) => { 35819 if ($isTextNode2(child)) { 35820 const paragraphNode = $createParagraphNode2(); 35821 paragraphNode.append(child); 35822 cell.append(child); 35823 } else { 35824 cell.append(child); 35825 } 35826 }); 35827 originalChildren.forEach((n2) => n2.remove()); 35828 } 35829 } 35830 if (isTableSelection && didPerformMergeOperations) { 35831 const [finalGridMap] = $computeTableMapSkipCellCheck(gridNode.getWritable(), null, null); 35832 const newAnchorCellMap = finalGridMap[anchorCellMap.startRow][anchorCellMap.startColumn]; 35833 newAnchorCellMap.cell.selectEnd(); 35834 } 35835 return true; 35836 } 35837 function $isMultiCellTableSelection(selection) { 35838 if ($isTableSelection(selection) && !selection.focus.getNode().is(selection.anchor.getNode())) { 35839 return true; 35840 } 35841 if ($isRangeSelection2(selection) && $isTableCellNode(selection.anchor.getNode()) && !selection.anchor.getNode().is(selection.focus.getNode())) { 35842 return true; 35843 } 35844 return false; 35845 } 35846 var TableExtension = defineExtension2({ 35847 build(editor, config, state) { 35848 return namedSignals2(config); 35849 }, 35850 config: safeCast2({ 35851 hasCellBackgroundColor: true, 35852 hasCellMerge: true, 35853 hasHorizontalScroll: true, 35854 hasNestedTables: false, 35855 hasTabHandler: true 35856 }), 35857 name: "@lexical/table/Table", 35858 nodes: () => [TableNode, TableRowNode, TableCellNode], 35859 register(editor, config, state) { 35860 const stores = state.getOutput(); 35861 return mergeRegister3(effect(() => { 35862 const hasHorizontalScroll = stores.hasHorizontalScroll.value; 35863 const hadHorizontalScroll = $isScrollableTablesActive(editor); 35864 if (hadHorizontalScroll !== hasHorizontalScroll) { 35865 setScrollableTablesActive(editor, hasHorizontalScroll); 35866 editor.registerNodeTransform(TableNode, () => { 35867 })(); 35868 } 35869 }), registerTablePlugin(editor, stores), effect(() => registerTableSelectionObserver(editor, stores.hasTabHandler.value)), effect(() => stores.hasCellMerge.value ? void 0 : registerTableCellUnmergeTransform(editor)), effect(() => stores.hasCellBackgroundColor.value ? void 0 : editor.registerNodeTransform(TableCellNode, (node) => { 35870 if (node.getBackgroundColor() !== null) { 35871 node.setBackgroundColor(null); 35872 } 35873 }))); 35874 } 35875 }); 35876 35877
vendor: 3,518 bytes, lines 35877-35935
35877// node_modules/@lexical/table/LexicalTable.mjs 35878 var mod17 = true ? LexicalTable_dev_exports : LexicalTable_prod_exports; 35879 var $computeTableMap2 = mod17.$computeTableMap; 35880 var $computeTableMapSkipCellCheck2 = mod17.$computeTableMapSkipCellCheck; 35881 var $createTableCellNode2 = mod17.$createTableCellNode; 35882 var $createTableNode2 = mod17.$createTableNode; 35883 var $createTableNodeWithDimensions2 = mod17.$createTableNodeWithDimensions; 35884 var $createTableRowNode2 = mod17.$createTableRowNode; 35885 var $createTableSelection2 = mod17.$createTableSelection; 35886 var $createTableSelectionFrom2 = mod17.$createTableSelectionFrom; 35887 var $deleteTableColumn2 = mod17.$deleteTableColumn; 35888 var $deleteTableColumnAtSelection2 = mod17.$deleteTableColumnAtSelection; 35889 var $deleteTableColumn__EXPERIMENTAL2 = mod17.$deleteTableColumn__EXPERIMENTAL; 35890 var $deleteTableRowAtSelection2 = mod17.$deleteTableRowAtSelection; 35891 var $deleteTableRow__EXPERIMENTAL2 = mod17.$deleteTableRow__EXPERIMENTAL; 35892 var $findCellNode2 = mod17.$findCellNode; 35893 var $findTableNode2 = mod17.$findTableNode; 35894 var $getElementForTableNode2 = mod17.$getElementForTableNode; 35895 var $getNodeTriplet2 = mod17.$getNodeTriplet; 35896 var $getTableAndElementByKey2 = mod17.$getTableAndElementByKey; 35897 var $getTableCellNodeFromLexicalNode2 = mod17.$getTableCellNodeFromLexicalNode; 35898 var $getTableCellNodeRect2 = mod17.$getTableCellNodeRect; 35899 var $getTableColumnIndexFromTableCellNode2 = mod17.$getTableColumnIndexFromTableCellNode; 35900 var $getTableNodeFromLexicalNodeOrThrow2 = mod17.$getTableNodeFromLexicalNodeOrThrow; 35901 var $getTableRowIndexFromTableCellNode2 = mod17.$getTableRowIndexFromTableCellNode; 35902 var $getTableRowNodeFromTableCellNodeOrThrow2 = mod17.$getTableRowNodeFromTableCellNodeOrThrow; 35903 var $insertTableColumn2 = mod17.$insertTableColumn; 35904 var $insertTableColumnAtSelection2 = mod17.$insertTableColumnAtSelection; 35905 var $insertTableColumn__EXPERIMENTAL2 = mod17.$insertTableColumn__EXPERIMENTAL; 35906 var $insertTableRow2 = mod17.$insertTableRow; 35907 var $insertTableRowAtSelection2 = mod17.$insertTableRowAtSelection; 35908 var $insertTableRow__EXPERIMENTAL2 = mod17.$insertTableRow__EXPERIMENTAL; 35909 var $isScrollableTablesActive2 = mod17.$isScrollableTablesActive; 35910 var $isSimpleTable2 = mod17.$isSimpleTable; 35911 var $isTableCellNode2 = mod17.$isTableCellNode; 35912 var $isTableNode2 = mod17.$isTableNode; 35913 var $isTableRowNode2 = mod17.$isTableRowNode; 35914 var $isTableSelection2 = mod17.$isTableSelection; 35915 var $mergeCells2 = mod17.$mergeCells; 35916 var $moveTableColumn2 = mod17.$moveTableColumn; 35917 var $removeTableRowAtIndex2 = mod17.$removeTableRowAtIndex; 35918 var $unmergeCell2 = mod17.$unmergeCell; 35919 var INSERT_TABLE_COMMAND2 = mod17.INSERT_TABLE_COMMAND; 35920 var TableCellHeaderStates2 = mod17.TableCellHeaderStates; 35921 var TableCellNode2 = mod17.TableCellNode; 35922 var TableExtension2 = mod17.TableExtension; 35923 var TableNode2 = mod17.TableNode; 35924 var TableObserver2 = mod17.TableObserver; 35925 var TableRowNode2 = mod17.TableRowNode; 35926 var applyTableHandlers2 = mod17.applyTableHandlers; 35927 var getDOMCellFromTarget2 = mod17.getDOMCellFromTarget; 35928 var getTableElement2 = mod17.getTableElement; 35929 var getTableObserverFromTableElement2 = mod17.getTableObserverFromTableElement; 35930 var registerTableCellUnmergeTransform2 = mod17.registerTableCellUnmergeTransform; 35931 var registerTablePlugin2 = mod17.registerTablePlugin; 35932 var registerTableSelectionObserver2 = mod17.registerTableSelectionObserver; 35933 var setScrollableTablesActive2 = mod17.setScrollableTablesActive; 35934 35935
vendor: 55,601 bytes, lines 35935-37092
35935// node_modules/marked/lib/marked.esm.js 35936 function L() { 35937 return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null }; 35938 } 35939 var T = L(); 35940 function G(l4) { 35941 T = l4; 35942 } 35943 var E2 = { exec: () => null }; 35944 function d2(l4, e2 = "") { 35945 let t2 = typeof l4 == "string" ? l4 : l4.source, n2 = { replace: (r2, i2) => { 35946 let s2 = typeof i2 == "string" ? i2 : i2.source; 35947 return s2 = s2.replace(m2.caret, "$1"), t2 = t2.replace(r2, s2), n2; 35948 }, getRegex: () => new RegExp(t2, e2) }; 35949 return n2; 35950 } 35951 var be = (() => { 35952 try { 35953 return !!new RegExp("(?<=1)(?<!1)"); 35954 } catch { 35955 return false; 35956 } 35957 })(); 35958 var m2 = { codeRemoveIndent: /^(?: {1,4}| {0,3}\t)/gm, outputLinkReplace: /\\([\[\]])/g, indentCodeCompensation: /^(\s+)(?:```)/, beginningSpace: /^\s+/, endingHash: /#$/, startingSpaceChar: /^ /, endingSpaceChar: / $/, nonSpaceChar: /[^ ]/, newLineCharGlobal: /\n/g, tabCharGlobal: /\t/g, multipleSpaceGlobal: /\s+/g, blankLine: /^[ \t]*$/, doubleBlankLine: /\n[ \t]*\n[ \t]*$/, blockquoteStart: /^ {0,3}>/, blockquoteSetextReplace: /\n {0,3}((?:=+|-+) *)(?=\n|$)/g, blockquoteSetextReplace2: /^ {0,3}>[ \t]?/gm, listReplaceTabs: /^\t+/, listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g, listIsTask: /^\[[ xX]\] /, listReplaceTask: /^\[[ xX]\] +/, anyLine: /\n.*\n/, hrefBrackets: /^<(.*)>$/, tableDelimiter: /[:|]/, tableAlignChars: /^\||\| *$/g, tableRowBlankLine: /\n[ \t]*$/, tableAlignRight: /^ *-+: *$/, tableAlignCenter: /^ *:-+: *$/, tableAlignLeft: /^ *:-+ *$/, startATag: /^<a /i, endATag: /^<\/a>/i, startPreScriptTag: /^<(pre|code|kbd|script)(\s|>)/i, endPreScriptTag: /^<\/(pre|code|kbd|script)(\s|>)/i, startAngleBracket: /^</, endAngleBracket: />$/, pedanticHrefTitle: /^([^'"]*[^\s])\s+(['"])(.*)\2/, unicodeAlphaNumeric: /[\p{L}\p{N}]/u, escapeTest: /[&<>"']/, escapeReplace: /[&<>"']/g, escapeTestNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/, escapeReplaceNoEncode: /[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g, unescapeTest: /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, caret: /(^|[^\[])\^/g, percentDecode: /%25/g, findPipe: /\|/g, splitPipe: / \|/, slashPipe: /\\\|/g, carriageReturn: /\r\n|\r/g, spaceLine: /^ +$/gm, notSpaceStart: /^\S*/, endingNewline: /\n$/, listItemRegex: (l4) => new RegExp(`^( {0,3}${l4})((?:[ ][^\\n]*)?(?:\\n|$))`), nextBulletRegex: (l4) => new RegExp(`^ {0,${Math.min(3, l4 - 1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`), hrRegex: (l4) => new RegExp(`^ {0,${Math.min(3, l4 - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`), fencesBeginRegex: (l4) => new RegExp(`^ {0,${Math.min(3, l4 - 1)}}(?:\`\`\`|~~~)`), headingBeginRegex: (l4) => new RegExp(`^ {0,${Math.min(3, l4 - 1)}}#`), htmlBeginRegex: (l4) => new RegExp(`^ {0,${Math.min(3, l4 - 1)}}<(?:[a-z].*>|!--)`, "i") }; 35959 var Re = /^(?:[ \t]*(?:\n|$))+/; 35960 var Te = /^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/; 35961 var Oe = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/; 35962 var I = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/; 35963 var we = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/; 35964 var F = /(?:[*+-]|\d{1,9}[.)])/; 35965 var ie2 = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/; 35966 var oe2 = d2(ie2).replace(/bull/g, F).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/\|table/g, "").getRegex(); 35967 var ye2 = d2(ie2).replace(/bull/g, F).replace(/blockCode/g, /(?: {4}| {0,3}\t)/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).replace(/table/g, / {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(); 35968 var j2 = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/; 35969 var Pe = /^[^\n]+/; 35970 var Q = /(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/; 35971 var Se = d2(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label", Q).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(); 35972 var $e = d2(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g, F).getRegex(); 35973 var v2 = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul"; 35974 var U2 = /<!--(?:-?>|[\s\S]*?(?:-->|$))/; 35975 var _e = d2("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))", "i").replace("comment", U2).replace("tag", v2).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(); 35976 var ae2 = d2(j2).replace("hr", I).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", v2).getRegex(); 35977 var Le = d2(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", ae2).getRegex(); 35978 var K = { blockquote: Le, code: Te, def: Se, fences: Oe, heading: we, hr: I, html: _e, lheading: oe2, list: $e, newline: Re, paragraph: ae2, table: E2, text: Pe }; 35979 var re2 = d2("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr", I).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("blockquote", " {0,3}>").replace("code", "(?: {4}| {0,3} )[^\\n]").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", v2).getRegex(); 35980 var Me = { ...K, lheading: ye2, table: re2, paragraph: d2(j2).replace("hr", I).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("table", re2).replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", v2).getRegex() }; 35981 var ze = { ...K, html: d2(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment", U2).replace(/tag/g, "(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(), def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, heading: /^(#{1,6})(.*)(?:\n+|$)/, fences: E2, lheading: /^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/, paragraph: d2(j2).replace("hr", I).replace("heading", ` *#{1,6} *[^ 35982]`).replace("lheading", oe2).replace("|table", "").replace("blockquote", " {0,3}>").replace("|fences", "").replace("|list", "").replace("|html", "").replace("|tag", "").getRegex() }; 35983 var Ae = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/; 35984 var Ee = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/; 35985 var le2 = /^( {2,}|\\)\n(?!\s*$)/; 35986 var Ie = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/; 35987 var D = /[\p{P}\p{S}]/u; 35988 var W = /[\s\p{P}\p{S}]/u; 35989 var ue2 = /[^\s\p{P}\p{S}]/u; 35990 var Ce = d2(/^((?![*_])punctSpace)/, "u").replace(/punctSpace/g, W).getRegex(); 35991 var pe2 = /(?!~)[\p{P}\p{S}]/u; 35992 var Be = /(?!~)[\s\p{P}\p{S}]/u; 35993 var qe = /(?:[^\s\p{P}\p{S}]|~)/u; 35994 var ve = d2(/link|precode-code|html/, "g").replace("link", /\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-", be ? "(?<!`)()" : "(^^|[^`])").replace("code", /(?<b>`+)[^`]+\k<b>(?!`)/).replace("html", /<(?! )[^<>]*?>/).getRegex(); 35995 var ce2 = /^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/; 35996 var De = d2(ce2, "u").replace(/punct/g, D).getRegex(); 35997 var He = d2(ce2, "u").replace(/punct/g, pe2).getRegex(); 35998 var he2 = "^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)"; 35999 var Ze = d2(he2, "gu").replace(/notPunctSpace/g, ue2).replace(/punctSpace/g, W).replace(/punct/g, D).getRegex(); 36000 var Ge = d2(he2, "gu").replace(/notPunctSpace/g, qe).replace(/punctSpace/g, Be).replace(/punct/g, pe2).getRegex(); 36001 var Ne = d2("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)", "gu").replace(/notPunctSpace/g, ue2).replace(/punctSpace/g, W).replace(/punct/g, D).getRegex(); 36002 var Fe = d2(/\\(punct)/, "gu").replace(/punct/g, D).getRegex(); 36003 var je = d2(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme", /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email", /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(); 36004 var Qe = d2(U2).replace("(?:-->|$)", "-->").getRegex(); 36005 var Ue = d2("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment", Qe).replace("attribute", /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(); 36006 var q = /(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+[^`]*?`+(?!`)|[^\[\]\\`])*?/; 36007 var Ke = d2(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]*(?:\n[ \t]*)?)(title))?\s*\)/).replace("label", q).replace("href", /<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title", /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(); 36008 var de2 = d2(/^!?\[(label)\]\[(ref)\]/).replace("label", q).replace("ref", Q).getRegex(); 36009 var ke = d2(/^!?\[(ref)\](?:\[\])?/).replace("ref", Q).getRegex(); 36010 var We = d2("reflink|nolink(?!\\()", "g").replace("reflink", de2).replace("nolink", ke).getRegex(); 36011 var se2 = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/; 36012 var X = { _backpedal: E2, anyPunctuation: Fe, autolink: je, blockSkip: ve, br: le2, code: Ee, del: E2, emStrongLDelim: De, emStrongRDelimAst: Ze, emStrongRDelimUnd: Ne, escape: Ae, link: Ke, nolink: ke, punctuation: Ce, reflink: de2, reflinkSearch: We, tag: Ue, text: Ie, url: E2 }; 36013 var Xe = { ...X, link: d2(/^!?\[(label)\]\((.*?)\)/).replace("label", q).getRegex(), reflink: d2(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label", q).getRegex() }; 36014 var N = { ...X, emStrongRDelimAst: Ge, emStrongLDelim: He, url: d2(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol", se2).replace("email", /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(), _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/, del: /^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/, text: d2(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol", se2).getRegex() }; 36015 var Je = { ...N, br: d2(le2).replace("{2,}", "*").getRegex(), text: d2(N.text).replace("\\b_", "\\b_| {2,}\\n").replace(/\{2,\}/g, "*").getRegex() }; 36016 var C = { normal: K, gfm: Me, pedantic: ze }; 36017 var M = { normal: X, gfm: N, breaks: Je, pedantic: Xe }; 36018 var Ve = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }; 36019 var ge2 = (l4) => Ve[l4]; 36020 function w2(l4, e2) { 36021 if (e2) { 36022 if (m2.escapeTest.test(l4)) return l4.replace(m2.escapeReplace, ge2); 36023 } else if (m2.escapeTestNoEncode.test(l4)) return l4.replace(m2.escapeReplaceNoEncode, ge2); 36024 return l4; 36025 } 36026 function J2(l4) { 36027 try { 36028 l4 = encodeURI(l4).replace(m2.percentDecode, "%"); 36029 } catch { 36030 return null; 36031 } 36032 return l4; 36033 } 36034 function V(l4, e2) { 36035 let t2 = l4.replace(m2.findPipe, (i2, s2, a2) => { 36036 let o2 = false, p2 = s2; 36037 for (; --p2 >= 0 && a2[p2] === "\\"; ) o2 = !o2; 36038 return o2 ? "|" : " |"; 36039 }), n2 = t2.split(m2.splitPipe), r2 = 0; 36040 if (n2[0].trim() || n2.shift(), n2.length > 0 && !n2.at(-1)?.trim() && n2.pop(), e2) if (n2.length > e2) n2.splice(e2); 36041 else for (; n2.length < e2; ) n2.push(""); 36042 for (; r2 < n2.length; r2++) n2[r2] = n2[r2].trim().replace(m2.slashPipe, "|"); 36043 return n2; 36044 } 36045 function z(l4, e2, t2) { 36046 let n2 = l4.length; 36047 if (n2 === 0) return ""; 36048 let r2 = 0; 36049 for (; r2 < n2; ) { 36050 let i2 = l4.charAt(n2 - r2 - 1); 36051 if (i2 === e2 && !t2) r2++; 36052 else if (i2 !== e2 && t2) r2++; 36053 else break; 36054 } 36055 return l4.slice(0, n2 - r2); 36056 } 36057 function fe2(l4, e2) { 36058 if (l4.indexOf(e2[1]) === -1) return -1; 36059 let t2 = 0; 36060 for (let n2 = 0; n2 < l4.length; n2++) if (l4[n2] === "\\") n2++; 36061 else if (l4[n2] === e2[0]) t2++; 36062 else if (l4[n2] === e2[1] && (t2--, t2 < 0)) return n2; 36063 return t2 > 0 ? -2 : -1; 36064 } 36065 function me2(l4, e2, t2, n2, r2) { 36066 let i2 = e2.href, s2 = e2.title || null, a2 = l4[1].replace(r2.other.outputLinkReplace, "$1"); 36067 n2.state.inLink = true; 36068 let o2 = { type: l4[0].charAt(0) === "!" ? "image" : "link", raw: t2, href: i2, title: s2, text: a2, tokens: n2.inlineTokens(a2) }; 36069 return n2.state.inLink = false, o2; 36070 } 36071 function Ye(l4, e2, t2) { 36072 let n2 = l4.match(t2.other.indentCodeCompensation); 36073 if (n2 === null) return e2; 36074 let r2 = n2[1]; 36075 return e2.split(` 36076`).map((i2) => { 36077 let s2 = i2.match(t2.other.beginningSpace); 36078 if (s2 === null) return i2; 36079 let [a2] = s2; 36080 return a2.length >= r2.length ? i2.slice(r2.length) : i2; 36081 }).join(` 36082`); 36083 } 36084 var y2 = class { 36085 options; 36086 rules; 36087 lexer; 36088 constructor(e2) { 36089 this.options = e2 || T; 36090 } 36091 space(e2) { 36092 let t2 = this.rules.block.newline.exec(e2); 36093 if (t2 && t2[0].length > 0) return { type: "space", raw: t2[0] }; 36094 } 36095 code(e2) { 36096 let t2 = this.rules.block.code.exec(e2); 36097 if (t2) { 36098 let n2 = t2[0].replace(this.rules.other.codeRemoveIndent, ""); 36099 return { type: "code", raw: t2[0], codeBlockStyle: "indented", text: this.options.pedantic ? n2 : z(n2, ` 36100`) }; 36101 } 36102 } 36103 fences(e2) { 36104 let t2 = this.rules.block.fences.exec(e2); 36105 if (t2) { 36106 let n2 = t2[0], r2 = Ye(n2, t2[3] || "", this.rules); 36107 return { type: "code", raw: n2, lang: t2[2] ? t2[2].trim().replace(this.rules.inline.anyPunctuation, "$1") : t2[2], text: r2 }; 36108 } 36109 } 36110 heading(e2) { 36111 let t2 = this.rules.block.heading.exec(e2); 36112 if (t2) { 36113 let n2 = t2[2].trim(); 36114 if (this.rules.other.endingHash.test(n2)) { 36115 let r2 = z(n2, "#"); 36116 (this.options.pedantic || !r2 || this.rules.other.endingSpaceChar.test(r2)) && (n2 = r2.trim()); 36117 } 36118 return { type: "heading", raw: t2[0], depth: t2[1].length, text: n2, tokens: this.lexer.inline(n2) }; 36119 } 36120 } 36121 hr(e2) { 36122 let t2 = this.rules.block.hr.exec(e2); 36123 if (t2) return { type: "hr", raw: z(t2[0], ` 36124`) }; 36125 } 36126 blockquote(e2) { 36127 let t2 = this.rules.block.blockquote.exec(e2); 36128 if (t2) { 36129 let n2 = z(t2[0], ` 36130`).split(` 36131`), r2 = "", i2 = "", s2 = []; 36132 for (; n2.length > 0; ) { 36133 let a2 = false, o2 = [], p2; 36134 for (p2 = 0; p2 < n2.length; p2++) if (this.rules.other.blockquoteStart.test(n2[p2])) o2.push(n2[p2]), a2 = true; 36135 else if (!a2) o2.push(n2[p2]); 36136 else break; 36137 n2 = n2.slice(p2); 36138 let u2 = o2.join(` 36139`), c2 = u2.replace(this.rules.other.blockquoteSetextReplace, ` 36140 $1`).replace(this.rules.other.blockquoteSetextReplace2, ""); 36141 r2 = r2 ? `${r2} 36142${u2}` : u2, i2 = i2 ? `${i2} 36143${c2}` : c2; 36144 let g2 = this.lexer.state.top; 36145 if (this.lexer.state.top = true, this.lexer.blockTokens(c2, s2, true), this.lexer.state.top = g2, n2.length === 0) break; 36146 let h2 = s2.at(-1); 36147 if (h2?.type === "code") break; 36148 if (h2?.type === "blockquote") { 36149 let R = h2, f = R.raw + ` 36150` + n2.join(` 36151`), O = this.blockquote(f); 36152 s2[s2.length - 1] = O, r2 = r2.substring(0, r2.length - R.raw.length) + O.raw, i2 = i2.substring(0, i2.length - R.text.length) + O.text; 36153 break; 36154 } else if (h2?.type === "list") { 36155 let R = h2, f = R.raw + ` 36156` + n2.join(` 36157`), O = this.list(f); 36158 s2[s2.length - 1] = O, r2 = r2.substring(0, r2.length - h2.raw.length) + O.raw, i2 = i2.substring(0, i2.length - R.raw.length) + O.raw, n2 = f.substring(s2.at(-1).raw.length).split(` 36159`); 36160 continue; 36161 } 36162 } 36163 return { type: "blockquote", raw: r2, tokens: s2, text: i2 }; 36164 } 36165 } 36166 list(e2) { 36167 let t2 = this.rules.block.list.exec(e2); 36168 if (t2) { 36169 let n2 = t2[1].trim(), r2 = n2.length > 1, i2 = { type: "list", raw: "", ordered: r2, start: r2 ? +n2.slice(0, -1) : "", loose: false, items: [] }; 36170 n2 = r2 ? `\\d{1,9}\\${n2.slice(-1)}` : `\\${n2}`, this.options.pedantic && (n2 = r2 ? n2 : "[*+-]"); 36171 let s2 = this.rules.other.listItemRegex(n2), a2 = false; 36172 for (; e2; ) { 36173 let p2 = false, u2 = "", c2 = ""; 36174 if (!(t2 = s2.exec(e2)) || this.rules.block.hr.test(e2)) break; 36175 u2 = t2[0], e2 = e2.substring(u2.length); 36176 let g2 = t2[2].split(` 36177`, 1)[0].replace(this.rules.other.listReplaceTabs, (H) => " ".repeat(3 * H.length)), h2 = e2.split(` 36178`, 1)[0], R = !g2.trim(), f = 0; 36179 if (this.options.pedantic ? (f = 2, c2 = g2.trimStart()) : R ? f = t2[1].length + 1 : (f = t2[2].search(this.rules.other.nonSpaceChar), f = f > 4 ? 1 : f, c2 = g2.slice(f), f += t2[1].length), R && this.rules.other.blankLine.test(h2) && (u2 += h2 + ` 36180`, e2 = e2.substring(h2.length + 1), p2 = true), !p2) { 36181 let H = this.rules.other.nextBulletRegex(f), ee = this.rules.other.hrRegex(f), te2 = this.rules.other.fencesBeginRegex(f), ne2 = this.rules.other.headingBeginRegex(f), xe = this.rules.other.htmlBeginRegex(f); 36182 for (; e2; ) { 36183 let Z = e2.split(` 36184`, 1)[0], A; 36185 if (h2 = Z, this.options.pedantic ? (h2 = h2.replace(this.rules.other.listReplaceNesting, " "), A = h2) : A = h2.replace(this.rules.other.tabCharGlobal, " "), te2.test(h2) || ne2.test(h2) || xe.test(h2) || H.test(h2) || ee.test(h2)) break; 36186 if (A.search(this.rules.other.nonSpaceChar) >= f || !h2.trim()) c2 += ` 36187` + A.slice(f); 36188 else { 36189 if (R || g2.replace(this.rules.other.tabCharGlobal, " ").search(this.rules.other.nonSpaceChar) >= 4 || te2.test(g2) || ne2.test(g2) || ee.test(g2)) break; 36190 c2 += ` 36191` + h2; 36192 } 36193 !R && !h2.trim() && (R = true), u2 += Z + ` 36194`, e2 = e2.substring(Z.length + 1), g2 = A.slice(f); 36195 } 36196 } 36197 i2.loose || (a2 ? i2.loose = true : this.rules.other.doubleBlankLine.test(u2) && (a2 = true)); 36198 let O = null, Y; 36199 this.options.gfm && (O = this.rules.other.listIsTask.exec(c2), O && (Y = O[0] !== "[ ] ", c2 = c2.replace(this.rules.other.listReplaceTask, ""))), i2.items.push({ type: "list_item", raw: u2, task: !!O, checked: Y, loose: false, text: c2, tokens: [] }), i2.raw += u2; 36200 } 36201 let o2 = i2.items.at(-1); 36202 if (o2) o2.raw = o2.raw.trimEnd(), o2.text = o2.text.trimEnd(); 36203 else return; 36204 i2.raw = i2.raw.trimEnd(); 36205 for (let p2 = 0; p2 < i2.items.length; p2++) if (this.lexer.state.top = false, i2.items[p2].tokens = this.lexer.blockTokens(i2.items[p2].text, []), !i2.loose) { 36206 let u2 = i2.items[p2].tokens.filter((g2) => g2.type === "space"), c2 = u2.length > 0 && u2.some((g2) => this.rules.other.anyLine.test(g2.raw)); 36207 i2.loose = c2; 36208 } 36209 if (i2.loose) for (let p2 = 0; p2 < i2.items.length; p2++) i2.items[p2].loose = true; 36210 return i2; 36211 } 36212 } 36213 html(e2) { 36214 let t2 = this.rules.block.html.exec(e2); 36215 if (t2) return { type: "html", block: true, raw: t2[0], pre: t2[1] === "pre" || t2[1] === "script" || t2[1] === "style", text: t2[0] }; 36216 } 36217 def(e2) { 36218 let t2 = this.rules.block.def.exec(e2); 36219 if (t2) { 36220 let n2 = t2[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal, " "), r2 = t2[2] ? t2[2].replace(this.rules.other.hrefBrackets, "$1").replace(this.rules.inline.anyPunctuation, "$1") : "", i2 = t2[3] ? t2[3].substring(1, t2[3].length - 1).replace(this.rules.inline.anyPunctuation, "$1") : t2[3]; 36221 return { type: "def", tag: n2, raw: t2[0], href: r2, title: i2 }; 36222 } 36223 } 36224 table(e2) { 36225 let t2 = this.rules.block.table.exec(e2); 36226 if (!t2 || !this.rules.other.tableDelimiter.test(t2[2])) return; 36227 let n2 = V(t2[1]), r2 = t2[2].replace(this.rules.other.tableAlignChars, "").split("|"), i2 = t2[3]?.trim() ? t2[3].replace(this.rules.other.tableRowBlankLine, "").split(` 36228`) : [], s2 = { type: "table", raw: t2[0], header: [], align: [], rows: [] }; 36229 if (n2.length === r2.length) { 36230 for (let a2 of r2) this.rules.other.tableAlignRight.test(a2) ? s2.align.push("right") : this.rules.other.tableAlignCenter.test(a2) ? s2.align.push("center") : this.rules.other.tableAlignLeft.test(a2) ? s2.align.push("left") : s2.align.push(null); 36231 for (let a2 = 0; a2 < n2.length; a2++) s2.header.push({ text: n2[a2], tokens: this.lexer.inline(n2[a2]), header: true, align: s2.align[a2] }); 36232 for (let a2 of i2) s2.rows.push(V(a2, s2.header.length).map((o2, p2) => ({ text: o2, tokens: this.lexer.inline(o2), header: false, align: s2.align[p2] }))); 36233 return s2; 36234 } 36235 } 36236 lheading(e2) { 36237 let t2 = this.rules.block.lheading.exec(e2); 36238 if (t2) return { type: "heading", raw: t2[0], depth: t2[2].charAt(0) === "=" ? 1 : 2, text: t2[1], tokens: this.lexer.inline(t2[1]) }; 36239 } 36240 paragraph(e2) { 36241 let t2 = this.rules.block.paragraph.exec(e2); 36242 if (t2) { 36243 let n2 = t2[1].charAt(t2[1].length - 1) === ` 36244` ? t2[1].slice(0, -1) : t2[1]; 36245 return { type: "paragraph", raw: t2[0], text: n2, tokens: this.lexer.inline(n2) }; 36246 } 36247 } 36248 text(e2) { 36249 let t2 = this.rules.block.text.exec(e2); 36250 if (t2) return { type: "text", raw: t2[0], text: t2[0], tokens: this.lexer.inline(t2[0]) }; 36251 } 36252 escape(e2) { 36253 let t2 = this.rules.inline.escape.exec(e2); 36254 if (t2) return { type: "escape", raw: t2[0], text: t2[1] }; 36255 } 36256 tag(e2) { 36257 let t2 = this.rules.inline.tag.exec(e2); 36258 if (t2) return !this.lexer.state.inLink && this.rules.other.startATag.test(t2[0]) ? this.lexer.state.inLink = true : this.lexer.state.inLink && this.rules.other.endATag.test(t2[0]) && (this.lexer.state.inLink = false), !this.lexer.state.inRawBlock && this.rules.other.startPreScriptTag.test(t2[0]) ? this.lexer.state.inRawBlock = true : this.lexer.state.inRawBlock && this.rules.other.endPreScriptTag.test(t2[0]) && (this.lexer.state.inRawBlock = false), { type: "html", raw: t2[0], inLink: this.lexer.state.inLink, inRawBlock: this.lexer.state.inRawBlock, block: false, text: t2[0] }; 36259 } 36260 link(e2) { 36261 let t2 = this.rules.inline.link.exec(e2); 36262 if (t2) { 36263 let n2 = t2[2].trim(); 36264 if (!this.options.pedantic && this.rules.other.startAngleBracket.test(n2)) { 36265 if (!this.rules.other.endAngleBracket.test(n2)) return; 36266 let s2 = z(n2.slice(0, -1), "\\"); 36267 if ((n2.length - s2.length) % 2 === 0) return; 36268 } else { 36269 let s2 = fe2(t2[2], "()"); 36270 if (s2 === -2) return; 36271 if (s2 > -1) { 36272 let o2 = (t2[0].indexOf("!") === 0 ? 5 : 4) + t2[1].length + s2; 36273 t2[2] = t2[2].substring(0, s2), t2[0] = t2[0].substring(0, o2).trim(), t2[3] = ""; 36274 } 36275 } 36276 let r2 = t2[2], i2 = ""; 36277 if (this.options.pedantic) { 36278 let s2 = this.rules.other.pedanticHrefTitle.exec(r2); 36279 s2 && (r2 = s2[1], i2 = s2[3]); 36280 } else i2 = t2[3] ? t2[3].slice(1, -1) : ""; 36281 return r2 = r2.trim(), this.rules.other.startAngleBracket.test(r2) && (this.options.pedantic && !this.rules.other.endAngleBracket.test(n2) ? r2 = r2.slice(1) : r2 = r2.slice(1, -1)), me2(t2, { href: r2 && r2.replace(this.rules.inline.anyPunctuation, "$1"), title: i2 && i2.replace(this.rules.inline.anyPunctuation, "$1") }, t2[0], this.lexer, this.rules); 36282 } 36283 } 36284 reflink(e2, t2) { 36285 let n2; 36286 if ((n2 = this.rules.inline.reflink.exec(e2)) || (n2 = this.rules.inline.nolink.exec(e2))) { 36287 let r2 = (n2[2] || n2[1]).replace(this.rules.other.multipleSpaceGlobal, " "), i2 = t2[r2.toLowerCase()]; 36288 if (!i2) { 36289 let s2 = n2[0].charAt(0); 36290 return { type: "text", raw: s2, text: s2 }; 36291 } 36292 return me2(n2, i2, n2[0], this.lexer, this.rules); 36293 } 36294 } 36295 emStrong(e2, t2, n2 = "") { 36296 let r2 = this.rules.inline.emStrongLDelim.exec(e2); 36297 if (!r2 || r2[3] && n2.match(this.rules.other.unicodeAlphaNumeric)) return; 36298 if (!(r2[1] || r2[2] || "") || !n2 || this.rules.inline.punctuation.exec(n2)) { 36299 let s2 = [...r2[0]].length - 1, a2, o2, p2 = s2, u2 = 0, c2 = r2[0][0] === "*" ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd; 36300 for (c2.lastIndex = 0, t2 = t2.slice(-1 * e2.length + s2); (r2 = c2.exec(t2)) != null; ) { 36301 if (a2 = r2[1] || r2[2] || r2[3] || r2[4] || r2[5] || r2[6], !a2) continue; 36302 if (o2 = [...a2].length, r2[3] || r2[4]) { 36303 p2 += o2; 36304 continue; 36305 } else if ((r2[5] || r2[6]) && s2 % 3 && !((s2 + o2) % 3)) { 36306 u2 += o2; 36307 continue; 36308 } 36309 if (p2 -= o2, p2 > 0) continue; 36310 o2 = Math.min(o2, o2 + p2 + u2); 36311 let g2 = [...r2[0]][0].length, h2 = e2.slice(0, s2 + r2.index + g2 + o2); 36312 if (Math.min(s2, o2) % 2) { 36313 let f = h2.slice(1, -1); 36314 return { type: "em", raw: h2, text: f, tokens: this.lexer.inlineTokens(f) }; 36315 } 36316 let R = h2.slice(2, -2); 36317 return { type: "strong", raw: h2, text: R, tokens: this.lexer.inlineTokens(R) }; 36318 } 36319 } 36320 } 36321 codespan(e2) { 36322 let t2 = this.rules.inline.code.exec(e2); 36323 if (t2) { 36324 let n2 = t2[2].replace(this.rules.other.newLineCharGlobal, " "), r2 = this.rules.other.nonSpaceChar.test(n2), i2 = this.rules.other.startingSpaceChar.test(n2) && this.rules.other.endingSpaceChar.test(n2); 36325 return r2 && i2 && (n2 = n2.substring(1, n2.length - 1)), { type: "codespan", raw: t2[0], text: n2 }; 36326 } 36327 } 36328 br(e2) { 36329 let t2 = this.rules.inline.br.exec(e2); 36330 if (t2) return { type: "br", raw: t2[0] }; 36331 } 36332 del(e2) { 36333 let t2 = this.rules.inline.del.exec(e2); 36334 if (t2) return { type: "del", raw: t2[0], text: t2[2], tokens: this.lexer.inlineTokens(t2[2]) }; 36335 } 36336 autolink(e2) { 36337 let t2 = this.rules.inline.autolink.exec(e2); 36338 if (t2) { 36339 let n2, r2; 36340 return t2[2] === "@" ? (n2 = t2[1], r2 = "mailto:" + n2) : (n2 = t2[1], r2 = n2), { type: "link", raw: t2[0], text: n2, href: r2, tokens: [{ type: "text", raw: n2, text: n2 }] }; 36341 } 36342 } 36343 url(e2) { 36344 let t2; 36345 if (t2 = this.rules.inline.url.exec(e2)) { 36346 let n2, r2; 36347 if (t2[2] === "@") n2 = t2[0], r2 = "mailto:" + n2; 36348 else { 36349 let i2; 36350 do 36351 i2 = t2[0], t2[0] = this.rules.inline._backpedal.exec(t2[0])?.[0] ?? ""; 36352 while (i2 !== t2[0]); 36353 n2 = t2[0], t2[1] === "www." ? r2 = "http://" + t2[0] : r2 = t2[0]; 36354 } 36355 return { type: "link", raw: t2[0], text: n2, href: r2, tokens: [{ type: "text", raw: n2, text: n2 }] }; 36356 } 36357 } 36358 inlineText(e2) { 36359 let t2 = this.rules.inline.text.exec(e2); 36360 if (t2) { 36361 let n2 = this.lexer.state.inRawBlock; 36362 return { type: "text", raw: t2[0], text: t2[0], escaped: n2 }; 36363 } 36364 } 36365 }; 36366 var x2 = class l2 { 36367 tokens; 36368 options; 36369 state; 36370 tokenizer; 36371 inlineQueue; 36372 constructor(e2) { 36373 this.tokens = [], this.tokens.links = /* @__PURE__ */ Object.create(null), this.options = e2 || T, this.options.tokenizer = this.options.tokenizer || new y2(), this.tokenizer = this.options.tokenizer, this.tokenizer.options = this.options, this.tokenizer.lexer = this, this.inlineQueue = [], this.state = { inLink: false, inRawBlock: false, top: true }; 36374 let t2 = { other: m2, block: C.normal, inline: M.normal }; 36375 this.options.pedantic ? (t2.block = C.pedantic, t2.inline = M.pedantic) : this.options.gfm && (t2.block = C.gfm, this.options.breaks ? t2.inline = M.breaks : t2.inline = M.gfm), this.tokenizer.rules = t2; 36376 } 36377 static get rules() { 36378 return { block: C, inline: M }; 36379 } 36380 static lex(e2, t2) { 36381 return new l2(t2).lex(e2); 36382 } 36383 static lexInline(e2, t2) { 36384 return new l2(t2).inlineTokens(e2); 36385 } 36386 lex(e2) { 36387 e2 = e2.replace(m2.carriageReturn, ` 36388`), this.blockTokens(e2, this.tokens); 36389 for (let t2 = 0; t2 < this.inlineQueue.length; t2++) { 36390 let n2 = this.inlineQueue[t2]; 36391 this.inlineTokens(n2.src, n2.tokens); 36392 } 36393 return this.inlineQueue = [], this.tokens; 36394 } 36395 blockTokens(e2, t2 = [], n2 = false) { 36396 for (this.options.pedantic && (e2 = e2.replace(m2.tabCharGlobal, " ").replace(m2.spaceLine, "")); e2; ) { 36397 let r2; 36398 if (this.options.extensions?.block?.some((s2) => (r2 = s2.call({ lexer: this }, e2, t2)) ? (e2 = e2.substring(r2.raw.length), t2.push(r2), true) : false)) continue; 36399 if (r2 = this.tokenizer.space(e2)) { 36400 e2 = e2.substring(r2.raw.length); 36401 let s2 = t2.at(-1); 36402 r2.raw.length === 1 && s2 !== void 0 ? s2.raw += ` 36403` : t2.push(r2); 36404 continue; 36405 } 36406 if (r2 = this.tokenizer.code(e2)) { 36407 e2 = e2.substring(r2.raw.length); 36408 let s2 = t2.at(-1); 36409 s2?.type === "paragraph" || s2?.type === "text" ? (s2.raw += (s2.raw.endsWith(` 36410`) ? "" : ` 36411`) + r2.raw, s2.text += ` 36412` + r2.text, this.inlineQueue.at(-1).src = s2.text) : t2.push(r2); 36413 continue; 36414 } 36415 if (r2 = this.tokenizer.fences(e2)) { 36416 e2 = e2.substring(r2.raw.length), t2.push(r2); 36417 continue; 36418 } 36419 if (r2 = this.tokenizer.heading(e2)) { 36420 e2 = e2.substring(r2.raw.length), t2.push(r2); 36421 continue; 36422 } 36423 if (r2 = this.tokenizer.hr(e2)) { 36424 e2 = e2.substring(r2.raw.length), t2.push(r2); 36425 continue; 36426 } 36427 if (r2 = this.tokenizer.blockquote(e2)) { 36428 e2 = e2.substring(r2.raw.length), t2.push(r2); 36429 continue; 36430 } 36431 if (r2 = this.tokenizer.list(e2)) { 36432 e2 = e2.substring(r2.raw.length), t2.push(r2); 36433 continue; 36434 } 36435 if (r2 = this.tokenizer.html(e2)) { 36436 e2 = e2.substring(r2.raw.length), t2.push(r2); 36437 continue; 36438 } 36439 if (r2 = this.tokenizer.def(e2)) { 36440 e2 = e2.substring(r2.raw.length); 36441 let s2 = t2.at(-1); 36442 s2?.type === "paragraph" || s2?.type === "text" ? (s2.raw += (s2.raw.endsWith(` 36443`) ? "" : ` 36444`) + r2.raw, s2.text += ` 36445` + r2.raw, this.inlineQueue.at(-1).src = s2.text) : this.tokens.links[r2.tag] || (this.tokens.links[r2.tag] = { href: r2.href, title: r2.title }, t2.push(r2)); 36446 continue; 36447 } 36448 if (r2 = this.tokenizer.table(e2)) { 36449 e2 = e2.substring(r2.raw.length), t2.push(r2); 36450 continue; 36451 } 36452 if (r2 = this.tokenizer.lheading(e2)) { 36453 e2 = e2.substring(r2.raw.length), t2.push(r2); 36454 continue; 36455 } 36456 let i2 = e2; 36457 if (this.options.extensions?.startBlock) { 36458 let s2 = 1 / 0, a2 = e2.slice(1), o2; 36459 this.options.extensions.startBlock.forEach((p2) => { 36460 o2 = p2.call({ lexer: this }, a2), typeof o2 == "number" && o2 >= 0 && (s2 = Math.min(s2, o2)); 36461 }), s2 < 1 / 0 && s2 >= 0 && (i2 = e2.substring(0, s2 + 1)); 36462 } 36463 if (this.state.top && (r2 = this.tokenizer.paragraph(i2))) { 36464 let s2 = t2.at(-1); 36465 n2 && s2?.type === "paragraph" ? (s2.raw += (s2.raw.endsWith(` 36466`) ? "" : ` 36467`) + r2.raw, s2.text += ` 36468` + r2.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = s2.text) : t2.push(r2), n2 = i2.length !== e2.length, e2 = e2.substring(r2.raw.length); 36469 continue; 36470 } 36471 if (r2 = this.tokenizer.text(e2)) { 36472 e2 = e2.substring(r2.raw.length); 36473 let s2 = t2.at(-1); 36474 s2?.type === "text" ? (s2.raw += (s2.raw.endsWith(` 36475`) ? "" : ` 36476`) + r2.raw, s2.text += ` 36477` + r2.text, this.inlineQueue.pop(), this.inlineQueue.at(-1).src = s2.text) : t2.push(r2); 36478 continue; 36479 } 36480 if (e2) { 36481 let s2 = "Infinite loop on byte: " + e2.charCodeAt(0); 36482 if (this.options.silent) { 36483 console.error(s2); 36484 break; 36485 } else throw new Error(s2); 36486 } 36487 } 36488 return this.state.top = true, t2; 36489 } 36490 inline(e2, t2 = []) { 36491 return this.inlineQueue.push({ src: e2, tokens: t2 }), t2; 36492 } 36493 inlineTokens(e2, t2 = []) { 36494 let n2 = e2, r2 = null; 36495 if (this.tokens.links) { 36496 let o2 = Object.keys(this.tokens.links); 36497 if (o2.length > 0) for (; (r2 = this.tokenizer.rules.inline.reflinkSearch.exec(n2)) != null; ) o2.includes(r2[0].slice(r2[0].lastIndexOf("[") + 1, -1)) && (n2 = n2.slice(0, r2.index) + "[" + "a".repeat(r2[0].length - 2) + "]" + n2.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex)); 36498 } 36499 for (; (r2 = this.tokenizer.rules.inline.anyPunctuation.exec(n2)) != null; ) n2 = n2.slice(0, r2.index) + "++" + n2.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex); 36500 let i2; 36501 for (; (r2 = this.tokenizer.rules.inline.blockSkip.exec(n2)) != null; ) i2 = r2[2] ? r2[2].length : 0, n2 = n2.slice(0, r2.index + i2) + "[" + "a".repeat(r2[0].length - i2 - 2) + "]" + n2.slice(this.tokenizer.rules.inline.blockSkip.lastIndex); 36502 n2 = this.options.hooks?.emStrongMask?.call({ lexer: this }, n2) ?? n2; 36503 let s2 = false, a2 = ""; 36504 for (; e2; ) { 36505 s2 || (a2 = ""), s2 = false; 36506 let o2; 36507 if (this.options.extensions?.inline?.some((u2) => (o2 = u2.call({ lexer: this }, e2, t2)) ? (e2 = e2.substring(o2.raw.length), t2.push(o2), true) : false)) continue; 36508 if (o2 = this.tokenizer.escape(e2)) { 36509 e2 = e2.substring(o2.raw.length), t2.push(o2); 36510 continue; 36511 } 36512 if (o2 = this.tokenizer.tag(e2)) { 36513 e2 = e2.substring(o2.raw.length), t2.push(o2); 36514 continue; 36515 } 36516 if (o2 = this.tokenizer.link(e2)) { 36517 e2 = e2.substring(o2.raw.length), t2.push(o2); 36518 continue; 36519 } 36520 if (o2 = this.tokenizer.reflink(e2, this.tokens.links)) { 36521 e2 = e2.substring(o2.raw.length); 36522 let u2 = t2.at(-1); 36523 o2.type === "text" && u2?.type === "text" ? (u2.raw += o2.raw, u2.text += o2.text) : t2.push(o2); 36524 continue; 36525 } 36526 if (o2 = this.tokenizer.emStrong(e2, n2, a2)) { 36527 e2 = e2.substring(o2.raw.length), t2.push(o2); 36528 continue; 36529 } 36530 if (o2 = this.tokenizer.codespan(e2)) { 36531 e2 = e2.substring(o2.raw.length), t2.push(o2); 36532 continue; 36533 } 36534 if (o2 = this.tokenizer.br(e2)) { 36535 e2 = e2.substring(o2.raw.length), t2.push(o2); 36536 continue; 36537 } 36538 if (o2 = this.tokenizer.del(e2)) { 36539 e2 = e2.substring(o2.raw.length), t2.push(o2); 36540 continue; 36541 } 36542 if (o2 = this.tokenizer.autolink(e2)) { 36543 e2 = e2.substring(o2.raw.length), t2.push(o2); 36544 continue; 36545 } 36546 if (!this.state.inLink && (o2 = this.tokenizer.url(e2))) { 36547 e2 = e2.substring(o2.raw.length), t2.push(o2); 36548 continue; 36549 } 36550 let p2 = e2; 36551 if (this.options.extensions?.startInline) { 36552 let u2 = 1 / 0, c2 = e2.slice(1), g2; 36553 this.options.extensions.startInline.forEach((h2) => { 36554 g2 = h2.call({ lexer: this }, c2), typeof g2 == "number" && g2 >= 0 && (u2 = Math.min(u2, g2)); 36555 }), u2 < 1 / 0 && u2 >= 0 && (p2 = e2.substring(0, u2 + 1)); 36556 } 36557 if (o2 = this.tokenizer.inlineText(p2)) { 36558 e2 = e2.substring(o2.raw.length), o2.raw.slice(-1) !== "_" && (a2 = o2.raw.slice(-1)), s2 = true; 36559 let u2 = t2.at(-1); 36560 u2?.type === "text" ? (u2.raw += o2.raw, u2.text += o2.text) : t2.push(o2); 36561 continue; 36562 } 36563 if (e2) { 36564 let u2 = "Infinite loop on byte: " + e2.charCodeAt(0); 36565 if (this.options.silent) { 36566 console.error(u2); 36567 break; 36568 } else throw new Error(u2); 36569 } 36570 } 36571 return t2; 36572 } 36573 }; 36574 var P = class { 36575 options; 36576 parser; 36577 constructor(e2) { 36578 this.options = e2 || T; 36579 } 36580 space(e2) { 36581 return ""; 36582 } 36583 code({ text: e2, lang: t2, escaped: n2 }) { 36584 let r2 = (t2 || "").match(m2.notSpaceStart)?.[0], i2 = e2.replace(m2.endingNewline, "") + ` 36585`; 36586 return r2 ? '<pre><code class="language-' + w2(r2) + '">' + (n2 ? i2 : w2(i2, true)) + `</code></pre> 36587` : "<pre><code>" + (n2 ? i2 : w2(i2, true)) + `</code></pre> 36588`; 36589 } 36590 blockquote({ tokens: e2 }) { 36591 return `<blockquote> 36592${this.parser.parse(e2)}</blockquote> 36593`; 36594 } 36595 html({ text: e2 }) { 36596 return e2; 36597 } 36598 def(e2) { 36599 return ""; 36600 } 36601 heading({ tokens: e2, depth: t2 }) { 36602 return `<h${t2}>${this.parser.parseInline(e2)}</h${t2}> 36603`; 36604 } 36605 hr(e2) { 36606 return `<hr> 36607`; 36608 } 36609 list(e2) { 36610 let t2 = e2.ordered, n2 = e2.start, r2 = ""; 36611 for (let a2 = 0; a2 < e2.items.length; a2++) { 36612 let o2 = e2.items[a2]; 36613 r2 += this.listitem(o2); 36614 } 36615 let i2 = t2 ? "ol" : "ul", s2 = t2 && n2 !== 1 ? ' start="' + n2 + '"' : ""; 36616 return "<" + i2 + s2 + `> 36617` + r2 + "</" + i2 + `> 36618`; 36619 } 36620 listitem(e2) { 36621 let t2 = ""; 36622 if (e2.task) { 36623 let n2 = this.checkbox({ checked: !!e2.checked }); 36624 e2.loose ? e2.tokens[0]?.type === "paragraph" ? (e2.tokens[0].text = n2 + " " + e2.tokens[0].text, e2.tokens[0].tokens && e2.tokens[0].tokens.length > 0 && e2.tokens[0].tokens[0].type === "text" && (e2.tokens[0].tokens[0].text = n2 + " " + w2(e2.tokens[0].tokens[0].text), e2.tokens[0].tokens[0].escaped = true)) : e2.tokens.unshift({ type: "text", raw: n2 + " ", text: n2 + " ", escaped: true }) : t2 += n2 + " "; 36625 } 36626 return t2 += this.parser.parse(e2.tokens, !!e2.loose), `<li>${t2}</li> 36627`; 36628 } 36629 checkbox({ checked: e2 }) { 36630 return "<input " + (e2 ? 'checked="" ' : "") + 'disabled="" type="checkbox">'; 36631 } 36632 paragraph({ tokens: e2 }) { 36633 return `<p>${this.parser.parseInline(e2)}</p> 36634`; 36635 } 36636 table(e2) { 36637 let t2 = "", n2 = ""; 36638 for (let i2 = 0; i2 < e2.header.length; i2++) n2 += this.tablecell(e2.header[i2]); 36639 t2 += this.tablerow({ text: n2 }); 36640 let r2 = ""; 36641 for (let i2 = 0; i2 < e2.rows.length; i2++) { 36642 let s2 = e2.rows[i2]; 36643 n2 = ""; 36644 for (let a2 = 0; a2 < s2.length; a2++) n2 += this.tablecell(s2[a2]); 36645 r2 += this.tablerow({ text: n2 }); 36646 } 36647 return r2 && (r2 = `<tbody>${r2}</tbody>`), `<table> 36648<thead> 36649` + t2 + `</thead> 36650` + r2 + `</table> 36651`; 36652 } 36653 tablerow({ text: e2 }) { 36654 return `<tr> 36655${e2}</tr> 36656`; 36657 } 36658 tablecell(e2) { 36659 let t2 = this.parser.parseInline(e2.tokens), n2 = e2.header ? "th" : "td"; 36660 return (e2.align ? `<${n2} align="${e2.align}">` : `<${n2}>`) + t2 + `</${n2}> 36661`; 36662 } 36663 strong({ tokens: e2 }) { 36664 return `<strong>${this.parser.parseInline(e2)}</strong>`; 36665 } 36666 em({ tokens: e2 }) { 36667 return `<em>${this.parser.parseInline(e2)}</em>`; 36668 } 36669 codespan({ text: e2 }) { 36670 return `<code>${w2(e2, true)}</code>`; 36671 } 36672 br(e2) { 36673 return "<br>"; 36674 } 36675 del({ tokens: e2 }) { 36676 return `<del>${this.parser.parseInline(e2)}</del>`; 36677 } 36678 link({ href: e2, title: t2, tokens: n2 }) { 36679 let r2 = this.parser.parseInline(n2), i2 = J2(e2); 36680 if (i2 === null) return r2; 36681 e2 = i2; 36682 let s2 = '<a href="' + e2 + '"'; 36683 return t2 && (s2 += ' title="' + w2(t2) + '"'), s2 += ">" + r2 + "</a>", s2; 36684 } 36685 image({ href: e2, title: t2, text: n2, tokens: r2 }) { 36686 r2 && (n2 = this.parser.parseInline(r2, this.parser.textRenderer)); 36687 let i2 = J2(e2); 36688 if (i2 === null) return w2(n2); 36689 e2 = i2; 36690 let s2 = `<img src="${e2}" alt="${n2}"`; 36691 return t2 && (s2 += ` title="${w2(t2)}"`), s2 += ">", s2; 36692 } 36693 text(e2) { 36694 return "tokens" in e2 && e2.tokens ? this.parser.parseInline(e2.tokens) : "escaped" in e2 && e2.escaped ? e2.text : w2(e2.text); 36695 } 36696 }; 36697 var $ = class { 36698 strong({ text: e2 }) { 36699 return e2; 36700 } 36701 em({ text: e2 }) { 36702 return e2; 36703 } 36704 codespan({ text: e2 }) { 36705 return e2; 36706 } 36707 del({ text: e2 }) { 36708 return e2; 36709 } 36710 html({ text: e2 }) { 36711 return e2; 36712 } 36713 text({ text: e2 }) { 36714 return e2; 36715 } 36716 link({ text: e2 }) { 36717 return "" + e2; 36718 } 36719 image({ text: e2 }) { 36720 return "" + e2; 36721 } 36722 br() { 36723 return ""; 36724 } 36725 }; 36726 var b2 = class l3 { 36727 options; 36728 renderer; 36729 textRenderer; 36730 constructor(e2) { 36731 this.options = e2 || T, this.options.renderer = this.options.renderer || new P(), this.renderer = this.options.renderer, this.renderer.options = this.options, this.renderer.parser = this, this.textRenderer = new $(); 36732 } 36733 static parse(e2, t2) { 36734 return new l3(t2).parse(e2); 36735 } 36736 static parseInline(e2, t2) { 36737 return new l3(t2).parseInline(e2); 36738 } 36739 parse(e2, t2 = true) { 36740 let n2 = ""; 36741 for (let r2 = 0; r2 < e2.length; r2++) { 36742 let i2 = e2[r2]; 36743 if (this.options.extensions?.renderers?.[i2.type]) { 36744 let a2 = i2, o2 = this.options.extensions.renderers[a2.type].call({ parser: this }, a2); 36745 if (o2 !== false || !["space", "hr", "heading", "code", "table", "blockquote", "list", "html", "def", "paragraph", "text"].includes(a2.type)) { 36746 n2 += o2 || ""; 36747 continue; 36748 } 36749 } 36750 let s2 = i2; 36751 switch (s2.type) { 36752 case "space": { 36753 n2 += this.renderer.space(s2); 36754 continue; 36755 } 36756 case "hr": { 36757 n2 += this.renderer.hr(s2); 36758 continue; 36759 } 36760 case "heading": { 36761 n2 += this.renderer.heading(s2); 36762 continue; 36763 } 36764 case "code": { 36765 n2 += this.renderer.code(s2); 36766 continue; 36767 } 36768 case "table": { 36769 n2 += this.renderer.table(s2); 36770 continue; 36771 } 36772 case "blockquote": { 36773 n2 += this.renderer.blockquote(s2); 36774 continue; 36775 } 36776 case "list": { 36777 n2 += this.renderer.list(s2); 36778 continue; 36779 } 36780 case "html": { 36781 n2 += this.renderer.html(s2); 36782 continue; 36783 } 36784 case "def": { 36785 n2 += this.renderer.def(s2); 36786 continue; 36787 } 36788 case "paragraph": { 36789 n2 += this.renderer.paragraph(s2); 36790 continue; 36791 } 36792 case "text": { 36793 let a2 = s2, o2 = this.renderer.text(a2); 36794 for (; r2 + 1 < e2.length && e2[r2 + 1].type === "text"; ) a2 = e2[++r2], o2 += ` 36795` + this.renderer.text(a2); 36796 t2 ? n2 += this.renderer.paragraph({ type: "paragraph", raw: o2, text: o2, tokens: [{ type: "text", raw: o2, text: o2, escaped: true }] }) : n2 += o2; 36797 continue; 36798 } 36799 default: { 36800 let a2 = 'Token with "' + s2.type + '" type was not found.'; 36801 if (this.options.silent) return console.error(a2), ""; 36802 throw new Error(a2); 36803 } 36804 } 36805 } 36806 return n2; 36807 } 36808 parseInline(e2, t2 = this.renderer) { 36809 let n2 = ""; 36810 for (let r2 = 0; r2 < e2.length; r2++) { 36811 let i2 = e2[r2]; 36812 if (this.options.extensions?.renderers?.[i2.type]) { 36813 let a2 = this.options.extensions.renderers[i2.type].call({ parser: this }, i2); 36814 if (a2 !== false || !["escape", "html", "link", "image", "strong", "em", "codespan", "br", "del", "text"].includes(i2.type)) { 36815 n2 += a2 || ""; 36816 continue; 36817 } 36818 } 36819 let s2 = i2; 36820 switch (s2.type) { 36821 case "escape": { 36822 n2 += t2.text(s2); 36823 break; 36824 } 36825 case "html": { 36826 n2 += t2.html(s2); 36827 break; 36828 } 36829 case "link": { 36830 n2 += t2.link(s2); 36831 break; 36832 } 36833 case "image": { 36834 n2 += t2.image(s2); 36835 break; 36836 } 36837 case "strong": { 36838 n2 += t2.strong(s2); 36839 break; 36840 } 36841 case "em": { 36842 n2 += t2.em(s2); 36843 break; 36844 } 36845 case "codespan": { 36846 n2 += t2.codespan(s2); 36847 break; 36848 } 36849 case "br": { 36850 n2 += t2.br(s2); 36851 break; 36852 } 36853 case "del": { 36854 n2 += t2.del(s2); 36855 break; 36856 } 36857 case "text": { 36858 n2 += t2.text(s2); 36859 break; 36860 } 36861 default: { 36862 let a2 = 'Token with "' + s2.type + '" type was not found.'; 36863 if (this.options.silent) return console.error(a2), ""; 36864 throw new Error(a2); 36865 } 36866 } 36867 } 36868 return n2; 36869 } 36870 }; 36871 var S2 = class { 36872 options; 36873 block; 36874 constructor(e2) { 36875 this.options = e2 || T; 36876 } 36877 static passThroughHooks = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens", "emStrongMask"]); 36878 static passThroughHooksRespectAsync = /* @__PURE__ */ new Set(["preprocess", "postprocess", "processAllTokens"]); 36879 preprocess(e2) { 36880 return e2; 36881 } 36882 postprocess(e2) { 36883 return e2; 36884 } 36885 processAllTokens(e2) { 36886 return e2; 36887 } 36888 emStrongMask(e2) { 36889 return e2; 36890 } 36891 provideLexer() { 36892 return this.block ? x2.lex : x2.lexInline; 36893 } 36894 provideParser() { 36895 return this.block ? b2.parse : b2.parseInline; 36896 } 36897 }; 36898 var B = class { 36899 defaults = L(); 36900 options = this.setOptions; 36901 parse = this.parseMarkdown(true); 36902 parseInline = this.parseMarkdown(false); 36903 Parser = b2; 36904 Renderer = P; 36905 TextRenderer = $; 36906 Lexer = x2; 36907 Tokenizer = y2; 36908 Hooks = S2; 36909 constructor(...e2) { 36910 this.use(...e2); 36911 } 36912 walkTokens(e2, t2) { 36913 let n2 = []; 36914 for (let r2 of e2) switch (n2 = n2.concat(t2.call(this, r2)), r2.type) { 36915 case "table": { 36916 let i2 = r2; 36917 for (let s2 of i2.header) n2 = n2.concat(this.walkTokens(s2.tokens, t2)); 36918 for (let s2 of i2.rows) for (let a2 of s2) n2 = n2.concat(this.walkTokens(a2.tokens, t2)); 36919 break; 36920 } 36921 case "list": { 36922 let i2 = r2; 36923 n2 = n2.concat(this.walkTokens(i2.items, t2)); 36924 break; 36925 } 36926 default: { 36927 let i2 = r2; 36928 this.defaults.extensions?.childTokens?.[i2.type] ? this.defaults.extensions.childTokens[i2.type].forEach((s2) => { 36929 let a2 = i2[s2].flat(1 / 0); 36930 n2 = n2.concat(this.walkTokens(a2, t2)); 36931 }) : i2.tokens && (n2 = n2.concat(this.walkTokens(i2.tokens, t2))); 36932 } 36933 } 36934 return n2; 36935 } 36936 use(...e2) { 36937 let t2 = this.defaults.extensions || { renderers: {}, childTokens: {} }; 36938 return e2.forEach((n2) => { 36939 let r2 = { ...n2 }; 36940 if (r2.async = this.defaults.async || r2.async || false, n2.extensions && (n2.extensions.forEach((i2) => { 36941 if (!i2.name) throw new Error("extension name required"); 36942 if ("renderer" in i2) { 36943 let s2 = t2.renderers[i2.name]; 36944 s2 ? t2.renderers[i2.name] = function(...a2) { 36945 let o2 = i2.renderer.apply(this, a2); 36946 return o2 === false && (o2 = s2.apply(this, a2)), o2; 36947 } : t2.renderers[i2.name] = i2.renderer; 36948 } 36949 if ("tokenizer" in i2) { 36950 if (!i2.level || i2.level !== "block" && i2.level !== "inline") throw new Error("extension level must be 'block' or 'inline'"); 36951 let s2 = t2[i2.level]; 36952 s2 ? s2.unshift(i2.tokenizer) : t2[i2.level] = [i2.tokenizer], i2.start && (i2.level === "block" ? t2.startBlock ? t2.startBlock.push(i2.start) : t2.startBlock = [i2.start] : i2.level === "inline" && (t2.startInline ? t2.startInline.push(i2.start) : t2.startInline = [i2.start])); 36953 } 36954 "childTokens" in i2 && i2.childTokens && (t2.childTokens[i2.name] = i2.childTokens); 36955 }), r2.extensions = t2), n2.renderer) { 36956 let i2 = this.defaults.renderer || new P(this.defaults); 36957 for (let s2 in n2.renderer) { 36958 if (!(s2 in i2)) throw new Error(`renderer '${s2}' does not exist`); 36959 if (["options", "parser"].includes(s2)) continue; 36960 let a2 = s2, o2 = n2.renderer[a2], p2 = i2[a2]; 36961 i2[a2] = (...u2) => { 36962 let c2 = o2.apply(i2, u2); 36963 return c2 === false && (c2 = p2.apply(i2, u2)), c2 || ""; 36964 }; 36965 } 36966 r2.renderer = i2; 36967 } 36968 if (n2.tokenizer) { 36969 let i2 = this.defaults.tokenizer || new y2(this.defaults); 36970 for (let s2 in n2.tokenizer) { 36971 if (!(s2 in i2)) throw new Error(`tokenizer '${s2}' does not exist`); 36972 if (["options", "rules", "lexer"].includes(s2)) continue; 36973 let a2 = s2, o2 = n2.tokenizer[a2], p2 = i2[a2]; 36974 i2[a2] = (...u2) => { 36975 let c2 = o2.apply(i2, u2); 36976 return c2 === false && (c2 = p2.apply(i2, u2)), c2; 36977 }; 36978 } 36979 r2.tokenizer = i2; 36980 } 36981 if (n2.hooks) { 36982 let i2 = this.defaults.hooks || new S2(); 36983 for (let s2 in n2.hooks) { 36984 if (!(s2 in i2)) throw new Error(`hook '${s2}' does not exist`); 36985 if (["options", "block"].includes(s2)) continue; 36986 let a2 = s2, o2 = n2.hooks[a2], p2 = i2[a2]; 36987 S2.passThroughHooks.has(s2) ? i2[a2] = (u2) => { 36988 if (this.defaults.async && S2.passThroughHooksRespectAsync.has(s2)) return (async () => { 36989 let g2 = await o2.call(i2, u2); 36990 return p2.call(i2, g2); 36991 })(); 36992 let c2 = o2.call(i2, u2); 36993 return p2.call(i2, c2); 36994 } : i2[a2] = (...u2) => { 36995 if (this.defaults.async) return (async () => { 36996 let g2 = await o2.apply(i2, u2); 36997 return g2 === false && (g2 = await p2.apply(i2, u2)), g2; 36998 })(); 36999 let c2 = o2.apply(i2, u2); 37000 return c2 === false && (c2 = p2.apply(i2, u2)), c2; 37001 }; 37002 } 37003 r2.hooks = i2; 37004 } 37005 if (n2.walkTokens) { 37006 let i2 = this.defaults.walkTokens, s2 = n2.walkTokens; 37007 r2.walkTokens = function(a2) { 37008 let o2 = []; 37009 return o2.push(s2.call(this, a2)), i2 && (o2 = o2.concat(i2.call(this, a2))), o2; 37010 }; 37011 } 37012 this.defaults = { ...this.defaults, ...r2 }; 37013 }), this; 37014 } 37015 setOptions(e2) { 37016 return this.defaults = { ...this.defaults, ...e2 }, this; 37017 } 37018 lexer(e2, t2) { 37019 return x2.lex(e2, t2 ?? this.defaults); 37020 } 37021 parser(e2, t2) { 37022 return b2.parse(e2, t2 ?? this.defaults); 37023 } 37024 parseMarkdown(e2) { 37025 return (n2, r2) => { 37026 let i2 = { ...r2 }, s2 = { ...this.defaults, ...i2 }, a2 = this.onError(!!s2.silent, !!s2.async); 37027 if (this.defaults.async === true && i2.async === false) return a2(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise.")); 37028 if (typeof n2 > "u" || n2 === null) return a2(new Error("marked(): input parameter is undefined or null")); 37029 if (typeof n2 != "string") return a2(new Error("marked(): input parameter is of type " + Object.prototype.toString.call(n2) + ", string expected")); 37030 if (s2.hooks && (s2.hooks.options = s2, s2.hooks.block = e2), s2.async) return (async () => { 37031 let o2 = s2.hooks ? await s2.hooks.preprocess(n2) : n2, u2 = await (s2.hooks ? await s2.hooks.provideLexer() : e2 ? x2.lex : x2.lexInline)(o2, s2), c2 = s2.hooks ? await s2.hooks.processAllTokens(u2) : u2; 37032 s2.walkTokens && await Promise.all(this.walkTokens(c2, s2.walkTokens)); 37033 let h2 = await (s2.hooks ? await s2.hooks.provideParser() : e2 ? b2.parse : b2.parseInline)(c2, s2); 37034 return s2.hooks ? await s2.hooks.postprocess(h2) : h2; 37035 })().catch(a2); 37036 try { 37037 s2.hooks && (n2 = s2.hooks.preprocess(n2)); 37038 let p2 = (s2.hooks ? s2.hooks.provideLexer() : e2 ? x2.lex : x2.lexInline)(n2, s2); 37039 s2.hooks && (p2 = s2.hooks.processAllTokens(p2)), s2.walkTokens && this.walkTokens(p2, s2.walkTokens); 37040 let c2 = (s2.hooks ? s2.hooks.provideParser() : e2 ? b2.parse : b2.parseInline)(p2, s2); 37041 return s2.hooks && (c2 = s2.hooks.postprocess(c2)), c2; 37042 } catch (o2) { 37043 return a2(o2); 37044 } 37045 }; 37046 } 37047 onError(e2, t2) { 37048 return (n2) => { 37049 if (n2.message += ` 37050Please report this to https://github.com/markedjs/marked.`, e2) { 37051 let r2 = "<p>An error occurred:</p><pre>" + w2(n2.message + "", true) + "</pre>"; 37052 return t2 ? Promise.resolve(r2) : r2; 37053 } 37054 if (t2) return Promise.reject(n2); 37055 throw n2; 37056 }; 37057 } 37058 }; 37059 var _2 = new B(); 37060 function k(l4, e2) { 37061 return _2.parse(l4, e2); 37062 } 37063 k.options = k.setOptions = function(l4) { 37064 return _2.setOptions(l4), k.defaults = _2.defaults, G(k.defaults), k; 37065 }; 37066 k.getDefaults = L; 37067 k.defaults = T; 37068 k.use = function(...l4) { 37069 return _2.use(...l4), k.defaults = _2.defaults, G(k.defaults), k; 37070 }; 37071 k.walkTokens = function(l4, e2) { 37072 return _2.walkTokens(l4, e2); 37073 }; 37074 k.parseInline = _2.parseInline; 37075 k.Parser = b2; 37076 k.parser = b2.parse; 37077 k.Renderer = P; 37078 k.TextRenderer = $; 37079 k.Lexer = x2; 37080 k.lexer = x2.lex; 37081 k.Tokenizer = y2; 37082 k.Hooks = S2; 37083 k.parse = k; 37084 var Zt = k.options; 37085 var Gt = k.setOptions; 37086 var Nt = k.use; 37087 var Ft = k.walkTokens; 37088 var jt = k.parseInline; 37089 var Ut = b2.parse; 37090 var Kt = x2.lex; 37091 37092
vendor: 378,521 bytes, lines 37092-46195
37092// node_modules/@37signals/lexxy/dist/lexxy.esm.js 37093 var import_prismjs4 = __toESM(require_prism(), 1); 37094 var ALLOWED_HTML_ATTRIBUTES = ["class", "contenteditable", "href", "src", "style", "title"]; 37095 var ALLOWED_STYLE_PROPERTIES = ["color", "background-color"]; 37096 function styleFilterHook(_currentNode, hookEvent) { 37097 if (hookEvent.attrName === "style" && hookEvent.attrValue) { 37098 const styles = { ...getStyleObjectFromCSS4(hookEvent.attrValue) }; 37099 const sanitizedStyles = {}; 37100 for (const property in styles) { 37101 if (ALLOWED_STYLE_PROPERTIES.includes(property)) { 37102 sanitizedStyles[property] = styles[property]; 37103 } 37104 } 37105 if (Object.keys(sanitizedStyles).length) { 37106 hookEvent.attrValue = getCSSFromStyleObject2(sanitizedStyles); 37107 } else { 37108 hookEvent.keepAttr = false; 37109 } 37110 } 37111 } 37112 purify.addHook("uponSanitizeAttribute", styleFilterHook); 37113 purify.addHook("uponSanitizeElement", (node, data) => { 37114 if (data.tagName === "strong" || data.tagName === "em") { 37115 node.removeAttribute("class"); 37116 } 37117 }); 37118 function buildConfig(allowedElements) { 37119 const tagAttributes = {}; 37120 for (const element of allowedElements) { 37121 if (typeof element === "string") { 37122 tagAttributes[element] ||= []; 37123 } else { 37124 tagAttributes[element.tag] ||= []; 37125 tagAttributes[element.tag].push(...element.attributes); 37126 } 37127 } 37128 return { 37129 ALLOWED_TAGS: Object.keys(tagAttributes), 37130 ALLOWED_ATTR: ALLOWED_HTML_ATTRIBUTES, 37131 ADD_ATTR: (attribute, tag) => tagAttributes[tag]?.includes(attribute), 37132 ADD_URI_SAFE_ATTR: ["caption", "filename"], 37133 SAFE_FOR_XML: false 37134 // So that it does not strip attributes that contains serialized HTML (like content) 37135 }; 37136 } 37137 function getNonce() { 37138 const element = document.head.querySelector("meta[name=csp-nonce]"); 37139 return element?.content; 37140 } 37141 function registerEventListener(element, type, listener, options) { 37142 element.addEventListener(type, listener, options); 37143 const elementRef = new WeakRef(element); 37144 const listenerRef = new WeakRef(listener); 37145 return function deregisterListener() { 37146 const listener2 = listenerRef.deref(); 37147 if (listener2) elementRef.deref()?.removeEventListener(type, listener2, options); 37148 }; 37149 } 37150 var ListenerBin = class { 37151 #listeners = []; 37152 track(...listeners) { 37153 this.#listeners.push(...listeners); 37154 } 37155 dispose() { 37156 while (this.#listeners.length) { 37157 const teardown = this.#listeners.pop(); 37158 teardown(); 37159 } 37160 } 37161 }; 37162 function handlingDefault(handler) { 37163 return (event) => { 37164 const handled = handler(event); 37165 if (handled) event.preventDefault(); 37166 return handled; 37167 }; 37168 } 37169 function createElement(name, properties, content = "") { 37170 const element = document.createElement(name); 37171 for (const [key, value] of Object.entries(properties || {})) { 37172 if (key === "dataset") { 37173 Object.entries(value).forEach(([key2, value2]) => element.dataset[key2] = value2); 37174 } else if (key in element) { 37175 element[key] = value; 37176 } else if (value !== null && value !== void 0) { 37177 element.setAttribute(key, value); 37178 } 37179 } 37180 if (content) { 37181 element.innerHTML = content; 37182 } 37183 return element; 37184 } 37185 function parseHtml(html2) { 37186 const parser = new DOMParser(); 37187 return parser.parseFromString(html2, "text/html"); 37188 } 37189 function createAttachmentFigure(contentType, isPreviewable, fileName) { 37190 const extension = fileName ? fileName.split(".").pop().toLowerCase() : "unknown"; 37191 return createElement("figure", { 37192 className: `attachment attachment--${isPreviewable ? "preview" : "file"} attachment--${extension}`, 37193 "data-content-type": contentType 37194 }); 37195 } 37196 function isPreviewableImage(contentType, fileName = "") { 37197 return contentType.startsWith("image/") && !contentType.includes("svg") || fileName.toLowerCase().endsWith(".avif"); 37198 } 37199 function isLexxyImageLayoutContent(content) { 37200 return content != null && typeof content === "object" && !Array.isArray(content) && "lexxyImage" in content; 37201 } 37202 function isLexxyImageLayoutString(content) { 37203 if (!content) return false; 37204 try { 37205 const parsed = typeof content === "string" ? JSON.parse(content) : content; 37206 return isLexxyImageLayoutContent(parsed); 37207 } catch { 37208 return false; 37209 } 37210 } 37211 function parseLexxyImageLayout(content) { 37212 if (!content) return {}; 37213 try { 37214 const parsed = typeof content === "string" ? JSON.parse(content) : content; 37215 return parsed?.lexxyImage || {}; 37216 } catch { 37217 return {}; 37218 } 37219 } 37220 var LEXXY_IMAGE_SIZE_CLASSES = ["attachment--image-small", "attachment--image-medium", "attachment--image-full"]; 37221 var LEXXY_IMAGE_ALIGN_CLASSES = ["attachment--align-left", "attachment--align-center", "attachment--align-right"]; 37222 var CAPTION_ALLOWED_TAGS = ["a", "b", "strong", "i", "em", "s", "strike", "u", "br"]; 37223 var CAPTION_ALLOWED_ATTRIBUTES = ["href", "title"]; 37224 var CAPTION_EXEC_COMMANDS = { 37225 bold: "bold", 37226 italic: "italic", 37227 underline: "underline" 37228 }; 37229 var CAPTION_TOOLBAR_ICONS = { 37230 bold: `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"><g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"><path d="M6.75 2.25H10C11.795 2.25 13.25 3.71 13.25 5.5C13.25 7.29 11.795 8.75 10 8.75H6.75"></path><path d="M6.75 8.75H10.75C12.683 8.75 14.25 10.3199 14.25 12.25C14.25 14.1801 12.683 15.75 10.75 15.75H6.75"></path><path d="M6.75 15.75H4.75C4.198 15.75 3.75 15.3 3.75 14.75V3.25C3.75 2.7 4.198 2.25 4.75 2.25H6.75V15.75Z"></path></g></svg>`, 37231 italic: `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="1.75" fill="none" stroke="currentColor"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M11 5l6 0"></path><path d="M7 19l6 0"></path><path d="M14 5l-4 14"></path></g></svg>`, 37232 underline: `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"><g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"><path d="M12.75,2.75v5.75c0,2.071-1.679,3.75-3.75,3.75h0c-2.071,0-3.75-1.679-3.75-3.75V2.75"></path><line id="color" x1="2.75" y1="15.25" x2="15.25" y2="15.25"></line></g></svg>`, 37233 link: `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"><g fill="currentColor"><path fill-rule="evenodd" clip-rule="evenodd" d="M9.03166 6.54197C9.22575 6.9079 9.08644 7.36188 8.72052 7.55597C8.47184 7.68787 8.24717 7.85851 8.04832 8.05733C6.96021 9.14544 6.96021 10.9086 8.04832 11.9967L10.2233 14.1717C11.3114 15.2598 13.0746 15.2598 14.1627 14.1717C15.2507 13.0836 15.2608 11.3104 14.1727 10.2223L13.4103 9.45993C13.1174 9.16703 13.1174 8.69216 13.4103 8.39927C13.7032 8.10638 14.178 8.10638 14.4709 8.39927L15.2333 9.16167C16.9072 10.8356 16.9072 13.5484 15.2333 15.2223C13.5594 16.8962 10.8365 16.9062 9.16266 15.2323L6.98766 13.0573C5.31377 11.3834 5.31377 8.67056 6.98766 6.99667C7.29576 6.68747 7.64975 6.42597 8.01766 6.23083C8.38359 6.03674 8.83757 6.17604 9.03166 6.54197Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M2.77868 2.76766C4.45257 1.09376 7.16544 1.09376 8.83934 2.76766L11.0143 4.94266C12.6882 6.61655 12.6882 9.32942 11.0143 11.0033C10.7101 11.3075 10.3647 11.5674 9.98433 11.7692C9.6184 11.9633 9.16442 11.824 8.97033 11.458C8.77624 11.0921 8.91554 10.6381 9.28147 10.444C9.53006 10.3122 9.7549 10.1414 9.95368 9.94267C11.0418 8.85455 11.0418 7.09142 9.95368 6.00332L7.77868 3.82832C6.69057 2.74021 4.92744 2.74021 3.83934 3.82832C2.76193 4.90573 2.74775 6.69607 3.82934 7.77766L4.59174 8.54006C4.88463 8.83295 4.88463 9.30782 4.59174 9.60072C4.29884 9.89361 3.82397 9.89361 3.53108 9.60072L2.76868 8.83832C1.10903 7.17867 1.1232 4.42314 2.77868 2.76766Z"></path></g></svg>` 37234 }; 37235 function applyLexxyImageLayout(figure, content) { 37236 const { size: size2, align: storedAlign } = parseLexxyImageLayout(content); 37237 let align = storedAlign; 37238 if (["small", "medium", "full"].includes(size2)) { 37239 figure.classList.add(`attachment--image-${size2}`); 37240 } 37241 if (["small", "medium"].includes(size2) && !align) { 37242 align = "center"; 37243 } 37244 if (["left", "center", "right"].includes(align)) { 37245 figure.classList.add(`attachment--align-${align}`); 37246 } 37247 } 37248 function syncLexxyImageLayoutClasses(figure, content) { 37249 figure.classList.remove(...LEXXY_IMAGE_SIZE_CLASSES, ...LEXXY_IMAGE_ALIGN_CLASSES); 37250 applyLexxyImageLayout(figure, content); 37251 } 37252 function sanitizeCaptionHtml(caption) { 37253 return purify.sanitize(caption || "", { 37254 ALLOWED_TAGS: CAPTION_ALLOWED_TAGS, 37255 ALLOWED_ATTR: CAPTION_ALLOWED_ATTRIBUTES, 37256 ALLOW_DATA_ATTR: false 37257 }).trim(); 37258 } 37259 function captionTextContent(caption) { 37260 const container = document.createElement("div"); 37261 container.innerHTML = sanitizeCaptionHtml(caption); 37262 return container.textContent || ""; 37263 } 37264 function syncCaptionEditorEmptyState(input) { 37265 if (!input) return; 37266 if (!captionTextContent(input.innerHTML).trim()) { 37267 input.dataset.captionEmpty = "true"; 37268 } else { 37269 delete input.dataset.captionEmpty; 37270 } 37271 } 37272 function normalizeCaptionHtml(html2) { 37273 const caption = sanitizeCaptionHtml(html2); 37274 if (!captionTextContent(caption).trim()) return ""; 37275 return caption; 37276 } 37277 function escapeCaptionText(text2) { 37278 const container = document.createElement("div"); 37279 container.textContent = text2; 37280 return container.innerHTML; 37281 } 37282 function normalizedCaptionUrl(url) { 37283 const value = url?.trim(); 37284 if (!value) return null; 37285 const urlWithScheme = /^[a-z][a-z\d+.-]*:/i.test(value) ? value : `https://${value}`; 37286 try { 37287 const parsed = new URL(urlWithScheme); 37288 return ["http:", "https:"].includes(parsed.protocol) ? parsed.href : null; 37289 } catch { 37290 return null; 37291 } 37292 } 37293 function dispatch(element, eventName, detail = null, cancelable = false) { 37294 return element.dispatchEvent(new CustomEvent(eventName, { bubbles: true, detail, cancelable })); 37295 } 37296 function addBlockSpacing(doc) { 37297 const selector = "body > :not(h1, h2, h3, h4, h5, h6) + *, blockquote > :not(h1, h2, h3, h4, h5, h6) + *"; 37298 for (const block of doc.querySelectorAll(selector)) { 37299 const spacer = doc.createElement("p"); 37300 spacer.appendChild(doc.createElement("br")); 37301 block.before(spacer); 37302 } 37303 } 37304 function generateDomId(prefix) { 37305 const randomPart = Math.random().toString(36).slice(2, 10); 37306 return `${prefix}-${randomPart}`; 37307 } 37308 function extractPlainTextFromHtml(innerHtml = "") { 37309 return parseHtml(innerHtml).body.textContent.trim(); 37310 } 37311 function isActiveAndVisible(element) { 37312 return element && !element.disabled && checkVisibility(element); 37313 } 37314 function checkVisibility(element, options) { 37315 if (element.checkVisibility) { 37316 return element.checkVisibility(options); 37317 } else { 37318 return Boolean(element.offsetParent); 37319 } 37320 } 37321 function handleRollingTabIndex(elements, event) { 37322 const previousActiveElement = document.activeElement; 37323 if (elements.includes(previousActiveElement)) { 37324 const finder = new NextElementFinder(elements, event.key); 37325 if (finder.selectNext(previousActiveElement)) { 37326 event.preventDefault(); 37327 } 37328 } 37329 } 37330 var NextElementFinder = class { 37331 constructor(elements, key) { 37332 this.elements = elements; 37333 this.key = key; 37334 } 37335 selectNext(fromElement) { 37336 const nextElement = this.#findNextElement(fromElement); 37337 if (nextElement) { 37338 const inactiveElements = this.elements.filter((element) => element !== nextElement); 37339 this.#unsetTabIndex(inactiveElements); 37340 this.#focusWithActiveTabIndex(nextElement); 37341 return true; 37342 } 37343 return false; 37344 } 37345 #findNextElement(fromElement) { 37346 switch (this.key) { 37347 case "ArrowRight": 37348 case "ArrowDown": 37349 return this.#findNextSibling(fromElement); 37350 case "ArrowLeft": 37351 case "ArrowUp": 37352 return this.#findPreviousSibling(fromElement); 37353 case "Home": 37354 return this.#findFirst(); 37355 case "End": 37356 return this.#findLast(); 37357 } 37358 } 37359 #findFirst(elements = this.elements) { 37360 return elements.find(isActiveAndVisible); 37361 } 37362 #findLast(elements = this.elements) { 37363 return elements.findLast(isActiveAndVisible); 37364 } 37365 #findNextSibling(element) { 37366 const afterElements = this.elements.slice(this.#indexOf(element) + 1); 37367 return this.#findFirst(afterElements); 37368 } 37369 #findPreviousSibling(element) { 37370 const beforeElements = this.elements.slice(0, this.#indexOf(element)); 37371 return this.#findLast(beforeElements); 37372 } 37373 #indexOf(element) { 37374 return this.elements.indexOf(element); 37375 } 37376 #focusWithActiveTabIndex(element) { 37377 if (isActiveAndVisible(element)) { 37378 element.tabIndex = 0; 37379 element.focus(); 37380 } 37381 } 37382 #unsetTabIndex(elements) { 37383 elements.forEach((element) => element.tabIndex = -1); 37384 } 37385 }; 37386 var ToolbarIcons = { 37387 "bold": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37388 <path fill-rule="evenodd" clip-rule="evenodd" d="M9.05273 1.88232C10.6866 1.88237 12.0033 2.20353 12.9529 2.89673L13.1272 3.0293C13.974 3.70864 14.4008 4.63245 14.4009 5.76562C14.4008 6.49354 14.2316 7.15281 13.8845 7.73145C13.6683 8.09188 13.3997 8.40162 13.0818 8.66016C13.5902 8.92606 14.0196 9.28599 14.3635 9.74121C14.8586 10.3834 15.0945 11.1743 15.0945 12.0879C15.0944 13.3698 14.5922 14.3931 13.5879 15.1106L13.5857 15.1128C12.5967 15.805 11.196 16.125 9.43799 16.125H3.10547V1.88232L9.05273 1.88232ZM6.36108 13.4084H9.28418C10.224 13.4084 10.8634 13.2491 11.2581 12.9851C11.6259 12.7389 11.8198 12.3768 11.8198 11.8367C11.8197 11.2968 11.6259 10.9351 11.2581 10.689C10.8634 10.425 10.2241 10.2649 9.28418 10.2649H6.36108V13.4084ZM6.36108 7.56812H8.78247C9.5163 7.56809 10.0547 7.45371 10.429 7.25757L10.5791 7.16895C10.9438 6.92178 11.1255 6.57934 11.1255 6.09302C11.1254 5.59017 10.9414 5.25227 10.5835 5.02002L10.5784 5.01636L10.5732 5.01343C10.1994 4.75387 9.61878 4.59818 8.78247 4.59814H6.36108V7.56812Z"/> 37389 </svg>`, 37390 "italic": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37391 <path d="M14.1379 3.91187L14.1086 4.06421H11.4668L9.49805 13.9431H12.0981L11.7473 15.7852L11.7188 15.9375H4.16675L4.51758 14.0955L4.54614 13.9431H7.18799L9.17505 4.06421H6.55664L6.90747 2.22217L6.93677 2.06982H14.4888L14.1379 3.91187Z"/> 37392 </svg>`, 37393 "strikethrough": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37394 <path d="M14.3723 11.8015C14.3771 11.8858 14.3811 11.9756 14.3811 12.0681C14.3811 12.811 14.1777 13.4959 13.7725 14.1174L13.7717 14.1189C13.3624 14.7329 12.7463 15.2162 11.9377 15.5742L11.9348 15.5757C11.1214 15.9223 10.1306 16.092 8.96997 16.092C7.9356 16.092 6.93308 15.9348 5.96338 15.6204L5.96045 15.6189C5.00593 15.292 4.24112 14.8699 3.67676 14.3459L3.57568 14.2522L3.63501 14.1277L4.45605 12.397L4.64282 12.5654C5.13492 13.0083 5.76733 13.3759 6.54492 13.6648C7.33475 13.9406 8.14322 14.0786 8.96997 14.0786C10.0731 14.0786 10.8638 13.8932 11.3708 13.5513C11.8757 13.1982 12.1172 12.7464 12.1172 12.1838C12.1172 12.0662 12.1049 11.9556 12.0828 11.8513L12.0344 11.625H14.3621L14.3723 11.8015Z"/> 37395 <path d="M9.2981 1.91602C10.111 1.91604 10.9109 2.02122 11.6975 2.23096C12.4855 2.44111 13.1683 2.74431 13.7417 3.14429L13.8655 3.23071L13.8083 3.36987L13.1726 4.91235L13.0869 5.1189L12.8987 4.99878C12.3487 4.64881 11.761 4.38633 11.1365 4.21143L11.1328 4.20996C10.585 4.04564 10.0484 3.95419 9.52295 3.93384L9.2981 3.92944C8.22329 3.92944 7.44693 4.12611 6.94043 4.49121C6.44619 4.85665 6.20874 5.31616 6.20874 5.88135L6.21533 6.03296C6.24495 6.37662 6.37751 6.65526 6.61011 6.87964L6.72144 6.97632C6.98746 7.19529 7.30625 7.37584 7.68018 7.51538L8.05151 7.63184C8.45325 7.75061 8.94669 7.87679 9.53247 8.01123L9.53467 8.01196C10.1213 8.15305 10.6426 8.29569 11.0991 8.4375H15C15.5178 8.4375 15.9375 8.85723 15.9375 9.375C15.9375 9.89277 15.5178 10.3125 15 10.3125H3C2.48223 10.3125 2.0625 9.89277 2.0625 9.375C2.0625 8.85723 2.48223 8.4375 3 8.4375H4.93726C4.83783 8.34526 4.74036 8.24896 4.64795 8.146L4.64502 8.14233C4.1721 7.58596 3.94482 6.85113 3.94482 5.95825C3.94483 5.20441 4.14059 4.51965 4.53369 3.90967L4.53516 3.90747C4.94397 3.29427 5.55262 2.81114 6.34863 2.45288C7.15081 2.0919 8.13683 1.91602 9.2981 1.91602Z"/> 37396 </svg>`, 37397 "underline": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37398 <path d="M14 14C14.5523 14 15 14.4477 15 15C15 15.5523 14.5523 16 14 16H4C3.44772 16 3 15.5523 3 15C3 14.4477 3.44772 14 4 14H14Z"/> 37399 <path d="M12.625 1.59375C13.25 1.59375 13.625 1.97656 13.625 2.64062V9.02344C13.625 11.4844 11.8516 13.1875 8.99219 13.1875C6.14062 13.1875 4.35938 11.4844 4.35938 9.02344V2.64062C4.35938 1.97656 4.74219 1.59375 5.36719 1.59375C6 1.59375 6.375 1.97656 6.375 2.64062V8.84375C6.375 10.3828 7.32031 11.4297 8.99219 11.4297C10.6641 11.4297 11.6172 10.3828 11.6172 8.84375V2.64062C11.6172 1.97656 11.9922 1.59375 12.625 1.59375Z"/> 37400 </svg>`, 37401 "heading": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37402 <path d="M11.5 2C12.0523 2 12.5 2.44772 12.5 3V3.5C12.5 4.05228 12.0523 4.5 11.5 4.5H8V15C8 15.5523 7.55228 16 7 16H6.5C5.94772 16 5.5 15.5523 5.5 15V4.5H2C1.44772 4.5 1 4.05228 1 3.5V3C1 2.44772 1.44772 2 2 2H11.5ZM16 7C16.5523 7 17 7.44772 17 8V8.5C17 9.05228 16.5523 9.5 16 9.5H15V15C15 15.5523 14.5523 16 14 16H13.5C12.9477 16 12.5 15.5523 12.5 15V9.5H11.5C10.9477 9.5 10.5 9.05228 10.5 8.5V8C10.5 7.44772 10.9477 7 11.5 7H16Z"/> 37403 </svg>`, 37404 "h1": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37405 <path d="M8.12207 4.30078C8.84668 4.30078 9.25684 4.74512 9.25684 5.51758V12.5518C9.25677 13.3241 8.84662 13.7686 8.12207 13.7686C7.39752 13.7686 6.9942 13.3309 6.99414 12.5518V9.87207H3.56934V12.5518C3.56927 13.3241 3.15912 13.7686 2.43457 13.7686C1.71002 13.7686 1.3067 13.3309 1.30664 12.5518V5.51758C1.30664 4.73828 1.70996 4.30078 2.43457 4.30078C3.15918 4.30078 3.56934 4.74512 3.56934 5.51758V8.07422H6.99414V5.51758C6.99414 4.73828 7.39746 4.30078 8.12207 4.30078ZM13.8418 4.125H14.8271C15.543 4.125 16.0449 4.56934 16.0449 5.23828V12.7207C16.0449 13.4111 15.6348 13.8486 14.9854 13.8486C14.336 13.8486 13.9395 13.418 13.9395 12.7207V6.11133H13.8887L12.9541 6.74219C12.7354 6.88574 12.5303 6.95312 12.3047 6.95312C11.7646 6.95312 11.3955 6.58398 11.3955 6.06445C11.3955 5.69531 11.5801 5.42578 11.9766 5.15625L13.4023 4.32031C13.5459 4.23633 13.6826 4.17578 13.8418 4.125Z"/> 37406 </svg>`, 37407 "h2": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37408 <path d="M8.12207 4.30078C8.84668 4.30078 9.25684 4.74512 9.25684 5.51758V12.5518C9.25677 13.3241 8.84662 13.7686 8.12207 13.7686C7.39752 13.7686 6.9942 13.3309 6.99414 12.5518V9.87207H3.56934V12.5518C3.56927 13.3241 3.15912 13.7686 2.43457 13.7686C1.71002 13.7686 1.3067 13.3309 1.30664 12.5518V5.51758C1.30664 4.73828 1.70996 4.30078 2.43457 4.30078C3.15918 4.30078 3.56934 4.74512 3.56934 5.51758V8.07422H6.99414V5.51758C6.99414 4.73828 7.39746 4.30078 8.12207 4.30078ZM13.6445 4.19824C15.5244 4.19824 16.8984 5.34668 16.8984 6.91211C16.8984 7.8759 16.4335 8.7237 15.292 9.84473L13.3438 11.8135V11.9092H16.1875C16.8232 11.9092 17.2197 12.251 17.2197 12.8115C17.2196 13.3651 16.83 13.7002 16.1875 13.7002H11.5117C10.8487 13.7002 10.4112 13.3241 10.4111 12.75C10.4111 12.3399 10.6368 11.9843 11.3203 11.3145L13.6855 8.88086C14.4169 8.13583 14.7245 7.64349 14.7246 7.12402C14.7246 6.4541 14.2393 6.00293 13.5215 6.00293C12.9404 6.00293 12.5166 6.29688 12.2158 6.90527C11.9151 7.37002 11.6552 7.54785 11.2588 7.54785C10.7188 7.54785 10.3429 7.17861 10.3428 6.65918C10.3428 5.3877 11.7783 4.19824 13.6445 4.19824Z"/> 37409 </svg>`, 37410 "h3": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37411 <path d="M13.5967 4.19824C15.5928 4.19824 16.9873 5.23047 16.9873 6.7002C16.9872 7.705 16.2421 8.60059 15.2988 8.7168V8.86719C16.4199 8.94923 17.2607 9.89942 17.2607 11.0889C17.2606 12.7362 15.7362 13.9053 13.583 13.9053C11.6827 13.9053 10.1925 12.873 10.1924 11.7041C10.1924 11.1846 10.5547 10.8154 11.0537 10.8154C11.3818 10.8154 11.6553 10.9727 11.9629 11.3555C12.3799 11.9159 12.92 12.2031 13.583 12.2031C14.4853 12.2031 15.0731 11.7313 15.0732 11C15.0732 10.2754 14.4785 9.7832 13.5898 9.7832H13.0361C12.5645 9.7832 12.2159 9.4208 12.2158 8.92188C12.2158 8.44336 12.5576 8.07422 13.0361 8.07422H13.5693C14.3075 8.07422 14.8544 7.60928 14.8545 6.97363C14.8545 6.33789 14.3213 5.90039 13.5557 5.90039C12.9678 5.90039 12.5029 6.16016 12.0859 6.71387C11.8399 7.03508 11.5527 7.17871 11.1973 7.17871C10.671 7.17871 10.295 6.82314 10.2949 6.31738C10.2949 5.18945 11.751 4.19824 13.5967 4.19824ZM8.0332 4.30078C8.75781 4.30078 9.16797 4.74512 9.16797 5.51758V12.5518C9.1679 13.3241 8.75776 13.7686 8.0332 13.7686C7.30865 13.7686 6.90534 13.3309 6.90527 12.5518V9.87207H3.48047V12.5518C3.4804 13.3241 3.07026 13.7686 2.3457 13.7686C1.62115 13.7686 1.21784 13.3309 1.21777 12.5518V5.51758C1.21777 4.73828 1.62109 4.30078 2.3457 4.30078C3.07031 4.30078 3.48047 4.74512 3.48047 5.51758V8.07422H6.90527V5.51758C6.90527 4.73828 7.30859 4.30078 8.0332 4.30078Z"/> 37412 </svg>`, 37413 "h4": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37414 <path d="M14.6357 4.22559C15.7432 4.22559 16.4336 4.80664 16.4336 5.73633V10.3164H16.7275C17.2881 10.3164 17.6436 10.6787 17.6436 11.2256C17.6435 11.7655 17.3017 12.1006 16.7275 12.1006H16.4336V12.6611C16.4335 13.3515 16.0234 13.7891 15.374 13.7891C14.7247 13.7891 14.3282 13.3583 14.3281 12.6611V12.1006H11.04C10.2335 12.1006 9.76863 11.6766 9.76855 10.918C9.76855 10.5762 9.85064 10.3026 10.1104 9.74219C10.7666 8.42289 11.5733 7.0146 12.5713 5.54492C13.2549 4.56738 13.7812 4.22559 14.6357 4.22559ZM7.88965 4.30078C8.61426 4.30078 9.02441 4.74512 9.02441 5.51758V12.5518C9.02435 13.3241 8.6142 13.7686 7.88965 13.7686C7.1651 13.7686 6.76178 13.3309 6.76172 12.5518V9.87207H3.33691V12.5518C3.33685 13.3241 2.9267 13.7686 2.20215 13.7686C1.4776 13.7686 1.07428 13.3309 1.07422 12.5518V5.51758C1.07422 4.73828 1.47754 4.30078 2.20215 4.30078C2.92676 4.30078 3.33691 4.74512 3.33691 5.51758V8.07422H6.76172V5.51758C6.76172 4.73828 7.16504 4.30078 7.88965 4.30078ZM14.2188 6.07812C13.6035 7.02841 12.2158 9.48929 11.7988 10.2686V10.3164H14.3281V6.07812H14.2188Z"/> 37415 </svg>`, 37416 "h5": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37417 <path d="M8.12207 4.30078C8.84668 4.30078 9.25684 4.74512 9.25684 5.51758V12.5518C9.25677 13.3241 8.84662 13.7686 8.12207 13.7686C7.39752 13.7686 6.9942 13.3309 6.99414 12.5518V9.87207H3.56934V12.5518C3.56927 13.3241 3.15912 13.7686 2.43457 13.7686C1.71002 13.7686 1.3067 13.3309 1.30664 12.5518V5.51758C1.30664 4.73828 1.70996 4.30078 2.43457 4.30078C3.15918 4.30078 3.56934 4.74512 3.56934 5.51758V8.07422H6.99414V5.51758C6.99414 4.73828 7.39746 4.30078 8.12207 4.30078ZM16.1191 4.30078C16.6934 4.30078 17.0762 4.63672 17.0762 5.16602C17.0762 5.69531 16.6934 6.03125 16.1191 6.03125H13.3457L12.9219 8.25586H13.0176C13.248 8.03711 13.6855 7.84375 14.2871 7.84375C15.9277 7.84375 17.1445 9.07422 17.1445 10.7832C17.1445 12.5605 15.8184 13.9053 13.7695 13.9053C11.9512 13.9053 10.6934 12.9277 10.5566 11.7178C10.5566 11.2021 10.9121 10.8193 11.4277 10.8193C11.8379 10.8193 12.1328 11.0244 12.3516 11.4893C12.625 12.0361 13.1133 12.2549 13.7285 12.2549C14.5488 12.2549 15.1367 11.6533 15.1367 10.7695C15.1367 9.92188 14.5625 9.31348 13.7559 9.31348C13.1953 9.31348 12.7578 9.56055 12.4629 10.0254C12.2168 10.3887 11.9355 10.5527 11.5527 10.5527C10.9648 10.5527 10.5684 10.1699 10.5684 9.55469C10.5684 9.42773 10.582 9.30762 10.6094 9.17383L11.2383 5.55273C11.3516 4.88379 11.7207 4.30078 12.6797 4.30078H16.1191Z"/> 37418 </svg>`, 37419 "h6": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37420 <path d="M8.12207 4.30078C8.84668 4.30078 9.25684 4.74512 9.25684 5.51758V12.5518C9.25677 13.3241 8.84662 13.7686 8.12207 13.7686C7.39752 13.7686 6.9942 13.3309 6.99414 12.5518V9.87207H3.56934V12.5518C3.56927 13.3241 3.15912 13.7686 2.43457 13.7686C1.71002 13.7686 1.3067 13.3309 1.30664 12.5518V5.51758C1.30664 4.73828 1.70996 4.30078 2.43457 4.30078C3.15918 4.30078 3.56934 4.74512 3.56934 5.51758V8.07422H6.99414V5.51758C6.99414 4.73828 7.39746 4.30078 8.12207 4.30078ZM13.6719 13.9258C15.5518 13.9258 17.1445 12.37306 17.1445 10.35451V10.05763C17.1445 8.10744 16.6016 6.59574 15.5928 5.58694C14.8613 4.85544 13.8975 4.42384 12.7285 4.25294C12.4199 4.21194 12.1592 4.19824 11.8643 4.19824C11.2627 4.19824 10.8389 4.59474 10.8389 5.14164C10.8389 5.65724 11.2354 6.02054 11.7783 6.04784C12.1758 6.06834 12.4844 6.10944 12.7656 6.19144C13.5176 6.42384 14.0742 6.95314 14.3965 7.75974L14.4922 8.00584H14.3828C14.0605 7.56834 13.4863 7.25974 12.6523 7.25974C11.1406 7.25974 10.0674 8.42384 10.0674 10.02345V10.27736C10.0674 12.2549 11.4668 13.9258 13.6719 13.9258ZM13.5215 12.24123C12.6797 12.24123 12.0918 11.48244 12.0918 10.4131V10.1592C12.0918 9.26174 12.6523 8.71291 13.5352 8.71291C14.3965 8.71291 14.9844 9.27638 14.9844 10.1592V10.4131C14.9844 11.48244 14.3828 12.24123 13.5215 12.24123Z"/> 37421 </svg>`, 37422 "paragraph": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37423 <path d="M9 12C9.55228 12 10 12.4477 10 13C10 13.5523 9.55228 14 9 14H3C2.44772 14 2 13.5523 2 13C2 12.4477 2.44772 12 3 12H9ZM15 8C15.5523 8 16 8.44772 16 9C16 9.55228 15.5523 10 15 10H3C2.44772 10 2 9.55228 2 9C2 8.44772 2.44772 8 3 8H15ZM15 4C15.5523 4 16 4.44772 16 5C16 5.55228 15.5523 6 15 6H3C2.44772 6 2 5.55228 2 5C2 4.44772 2.44772 4 3 4H15Z"/> 37424 </svg>`, 37425 "clearFormatting": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37426 <path d="M10.0607 2.07533C10.8417 1.29432 12.1078 1.2943 12.8888 2.07533L16.424 5.61049C17.205 6.39154 17.205 7.65854 16.424 8.43959L9.44937 15.4142C9.07435 15.7891 8.5656 16.0001 8.03531 16.0001H5.0148C4.55074 16.0001 4.10309 15.8385 3.74722 15.547L3.60074 15.4142L1.57534 13.3888C0.79431 12.6078 0.794336 11.3417 1.57534 10.5607L10.0607 2.07533ZM2.98941 11.9747L5.0148 14.0001H8.03531L9.71792 12.3165L6.18179 8.78139L2.98941 11.9747Z"/> 37427 </svg>`, 37428 "highlight": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37429 <path d="M16.4564 14.4272C17.1356 15.5592 16.3204 17.0002 15.0003 17.0004C13.68 17.0004 12.864 15.5593 13.5433 14.4272L15.0003 12.0004L16.4564 14.4272ZM5.1214 1.70746C5.51192 1.31693 6.14494 1.31693 6.53546 1.70746L9.7171 4.8891L13.2532 8.42426C14.2295 9.40056 14.2295 10.9841 13.2532 11.9604L9.7171 15.4955C8.74078 16.4718 7.15822 16.4718 6.18195 15.4955L2.64679 11.9604C1.67048 10.9841 1.67048 9.40057 2.64679 8.42426L6.18195 4.8891C6.30299 4.76805 6.43323 4.66177 6.57062 4.57074L5.1214 3.12152C4.73091 2.73104 4.73099 2.09799 5.1214 1.70746ZM8.30304 6.30316C8.10776 6.10815 7.79119 6.10799 7.59601 6.30316L4.06085 9.83929L3.9964 9.91742C3.88661 10.0838 3.88645 10.3019 3.9964 10.4682L4.02277 10.5004H11.8763C12.0312 10.3043 12.02 10.0205 11.8392 9.83929L8.30304 6.30316Z"/> 37430 </svg>`, 37431 "link": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37432 <path d="M12.8885 7.23091L13.9479 6.17155C14.5337 5.58576 14.5337 4.63602 13.9479 4.05023C13.3621 3.46444 12.4124 3.46444 11.8266 4.05023L8.29235 7.58446C7.9263 7.95051 7.90312 8.52994 8.2233 8.92271L8.36141 9.07463C8.68158 9.4674 8.65841 10.0468 8.29235 10.4129C7.90183 10.8034 7.26866 10.8034 6.87814 10.4129C5.70657 9.24131 5.70657 7.34182 6.87814 6.17025L10.4124 2.63602C11.7792 1.26918 13.9953 1.26918 15.3621 2.63602C16.729 4.00285 16.729 6.21893 15.3621 7.58576L14.3028 8.64512C13.9122 9.03564 13.2791 9.03564 12.8885 8.64512C12.498 8.2546 12.498 7.62143 12.8885 7.23091Z"/> 37433 <path d="M5.11038 10.7664L4.04843 11.8284C3.46264 12.4142 3.46264 13.3639 4.04842 13.9497C4.63421 14.5355 5.58396 14.5355 6.16975 13.9497L9.70657 10.4129C10.0726 10.0468 10.0958 9.46741 9.77563 9.07464L9.63752 8.92272C9.31734 8.52995 9.34052 7.95052 9.70657 7.58446C10.0971 7.19394 10.7303 7.19394 11.1208 7.58446C12.2924 8.75604 12.2924 10.6555 11.1208 11.8271L7.58396 15.3639C6.21712 16.7308 4.00105 16.7308 2.63421 15.3639C1.26738 13.9971 1.26738 11.781 2.63421 10.4142L3.69617 9.35223C4.08669 8.96171 4.71986 8.96171 5.11038 9.35223C5.5009 9.74275 5.5009 10.3759 5.11038 10.7664Z"/> 37434 </svg>`, 37435 "quote": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37436 <path d="M4.96387 4.23438C6.8769 4.23438 8.42767 5.78522 8.42773 7.69824C8.42773 8.32925 8.25769 8.92015 7.96289 9.42969L7.96387 9.43066L5.11816 14.3584C4.77659 14.95 4.02038 15.153 3.42871 14.8115C2.83701 14.4699 2.63397 13.7128 2.97559 13.1211L4.16113 11.0674C2.63532 10.7052 1.5 9.33485 1.5 7.69824C1.50006 5.78524 3.05086 4.2344 4.96387 4.23438ZM13.0361 4.23438C14.9491 4.23449 16.4999 5.7853 16.5 7.69824C16.5 8.32921 16.3299 8.92017 16.0352 9.42969L16.0361 9.43066L13.1904 14.3584C12.8488 14.9501 12.0917 15.1531 11.5 14.8115C10.9085 14.4698 10.7063 13.7127 11.0479 13.1211L12.2324 11.0674C10.7069 10.7049 9.57227 9.33461 9.57227 7.69824C9.57233 5.78522 11.1231 4.23438 13.0361 4.23438Z"/> 37437 </svg>`, 37438 "code": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37439 <path d="M6.29289 3.79295C6.68342 3.40243 7.31643 3.40243 7.70696 3.79295C8.09748 4.18348 8.09748 4.81649 7.70696 5.20702L3.91399 8.99999L7.70696 12.793C8.09748 13.1835 8.09748 13.8165 7.70696 14.207C7.31643 14.5975 6.68342 14.5975 6.29289 14.207L1.79289 9.70702C1.40237 9.31649 1.40237 8.68348 1.79289 8.29295L6.29289 3.79295Z"/> 37440 <path d="M11.707 3.79295C11.3164 3.40243 10.6834 3.40243 10.2929 3.79295C9.90237 4.18348 9.90237 4.81649 10.2929 5.20702L14.0859 8.99999L10.2929 12.793C9.90237 13.1835 9.90237 13.8165 10.2929 14.207C10.6834 14.5975 11.3164 14.5975 11.707 14.207L16.207 9.70702C16.5975 9.31649 16.5975 8.68348 16.207 8.29295L11.707 3.79295Z"/> 37441 </svg>`, 37442 "ul": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37443 <path d="M3 12.5C3.82843 12.5 4.5 13.1716 4.5 14C4.5 14.8284 3.82843 15.5 3 15.5C2.17157 15.5 1.5 14.8284 1.5 14C1.5 13.1716 2.17157 12.5 3 12.5ZM15.5 13C16.0523 13 16.5 13.4477 16.5 14C16.5 14.5523 16.0523 15 15.5 15H7C6.44772 15 6 14.5523 6 14C6 13.4477 6.44772 13 7 13H15.5ZM3 7.5C3.82843 7.5 4.5 8.17157 4.5 9C4.5 9.82843 3.82843 10.5 3 10.5C2.17157 10.5 1.5 9.82843 1.5 9C1.5 8.17157 2.17157 7.5 3 7.5ZM15.5 8C16.0523 8 16.5 8.44772 16.5 9C16.5 9.55228 16.0523 10 15.5 10H7C6.44772 10 6 9.55228 6 9C6 8.44772 6.44772 8 7 8H15.5ZM3 2.5C3.82843 2.5 4.5 3.17157 4.5 4C4.5 4.82843 3.82843 5.5 3 5.5C2.17157 5.5 1.5 4.82843 1.5 4C1.5 3.17157 2.17157 2.5 3 2.5ZM15.5 3C16.0523 3 16.5 3.44772 16.5 4C16.5 4.55228 16.0523 5 15.5 5H7C6.44772 5 6 4.55228 6 4C6 3.44772 6.44772 3 7 3H15.5Z"/> 37444 </svg>`, 37445 "ol": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37446 <path d="M15.5 13C16.0523 13 16.5 13.4477 16.5 14C16.5 14.5523 16.0523 15 15.5 15H7C6.44772 15 6 14.5523 6 14C6 13.4477 6.44772 13 7 13H15.5ZM15.5 8C16.0523 8 16.5 8.44772 16.5 9C16.5 9.55228 16.0523 10 15.5 10H7C6.44772 10 6 9.55228 6 9C6 8.44772 6.44772 8 7 8H15.5ZM15.5 3C16.0523 3 16.5 3.44772 16.5 4C16.5 4.55228 16.0523 5 15.5 5H7C6.44772 5 6 4.55228 6 4C6 3.44772 6.44772 3 7 3H15.5Z"/> 37447 <path d="M2.98657 16.0967C2.68042 16.0967 2.41187 16.0465 2.18091 15.9463C1.95174 15.846 1.77002 15.7046 1.63574 15.522C1.50146 15.3376 1.42448 15.1227 1.40479 14.8774L1.4021 14.8452H2.34204L2.34741 14.8748C2.35815 14.9589 2.39038 15.035 2.44409 15.103C2.49959 15.1711 2.5721 15.2248 2.66162 15.2642C2.75293 15.3035 2.86035 15.3232 2.98389 15.3232C3.10563 15.3232 3.21037 15.3027 3.2981 15.2615C3.38761 15.2185 3.45654 15.1603 3.50488 15.0869C3.55322 15.0135 3.57739 14.9294 3.57739 14.8345V14.8291C3.57739 14.6715 3.51921 14.5516 3.40283 14.4692C3.28646 14.3869 3.12085 14.3457 2.90601 14.3457H2.48706V13.677H2.90063C3.02775 13.677 3.13607 13.6582 3.22559 13.6206C3.31689 13.583 3.38672 13.5302 3.43506 13.4622C3.48519 13.3941 3.51025 13.3153 3.51025 13.2258V13.2205C3.51025 13.1256 3.48877 13.0441 3.4458 12.9761C3.40462 12.9062 3.34375 12.8534 3.26318 12.8176C3.18441 12.78 3.08952 12.7612 2.97852 12.7612C2.86572 12.7612 2.76636 12.7809 2.68042 12.8203C2.59627 12.8579 2.52913 12.9125 2.479 12.9841C2.43066 13.054 2.40112 13.1363 2.39038 13.2312L2.3877 13.2581H1.49341L1.49609 13.2205C1.514 12.977 1.58561 12.7666 1.71094 12.5894C1.83805 12.4103 2.00903 12.2725 2.22388 12.1758C2.44051 12.0773 2.69206 12.0281 2.97852 12.0281C3.27393 12.0281 3.52995 12.0728 3.74658 12.1624C3.96322 12.2501 4.13062 12.3727 4.24878 12.5303C4.36694 12.6878 4.42603 12.8722 4.42603 13.0835V13.0889C4.42603 13.2518 4.38932 13.3941 4.31592 13.5159C4.2443 13.6358 4.14762 13.7343 4.02588 13.8113C3.90592 13.8883 3.77254 13.942 3.62573 13.9724V13.9912C3.91756 14.0199 4.14941 14.1121 4.32129 14.2678C4.49316 14.4236 4.5791 14.6295 4.5791 14.8855V14.8909C4.5791 15.1344 4.51375 15.3474 4.38306 15.53C4.25236 15.7109 4.06795 15.8505 3.82983 15.949C3.59172 16.0474 3.31063 16.0967 2.98657 16.0967Z"/> 37448 <path d="M1.54443 11V10.342L2.76099 9.20874C2.95076 9.03507 3.09757 8.89274 3.20142 8.78174C3.30705 8.66895 3.37956 8.57316 3.41895 8.49438C3.46012 8.41382 3.48071 8.33415 3.48071 8.25537V8.24463C3.48071 8.14795 3.46012 8.0638 3.41895 7.99219C3.37777 7.92057 3.31779 7.86507 3.23901 7.82568C3.16024 7.7863 3.06714 7.7666 2.95972 7.7666C2.84692 7.7666 2.74756 7.78988 2.66162 7.83643C2.57747 7.88298 2.51123 7.94743 2.46289 8.02979C2.41455 8.11035 2.39038 8.20345 2.39038 8.30908V8.33057L1.48804 8.32788V8.31177C1.48804 8.05396 1.5507 7.82837 1.67603 7.63501C1.80314 7.44165 1.97949 7.29126 2.20508 7.18384C2.43245 7.07463 2.69653 7.02002 2.99731 7.02002C3.28556 7.02002 3.53711 7.06836 3.75195 7.16504C3.96859 7.25993 4.13688 7.39331 4.25684 7.56519C4.37858 7.73706 4.43945 7.93758 4.43945 8.16675V8.18018C4.43945 8.3252 4.40902 8.46932 4.34814 8.61255C4.28727 8.75578 4.18701 8.90885 4.04736 9.07178C3.90771 9.23291 3.71883 9.41642 3.48071 9.62231L2.58374 10.4092L2.85498 9.98486V10.4092L2.58374 10.2319H4.49048V11H1.54443Z"/> 37449 <path d="M2.84155 6V3.01367H2.79053L1.85596 3.64478V2.79614L2.84155 2.12476H3.82715V6H2.84155Z"/> 37450 </svg>`, 37451 "image": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37452 <path d="M14 2C15.6569 2 17 3.34315 17 5V13C17 14.6569 15.6569 16 14 16H4C2.34315 16 1 14.6569 1 13V5C1 3.34315 2.34315 2 4 2H14ZM3.06348 13.3496C3.2053 13.7294 3.57078 14 4 14H13.5859L11 11.4141L9.70703 12.707C9.31651 13.0976 8.68349 13.0976 8.29297 12.707C7.90244 12.3165 7.90244 11.6835 8.29297 11.293L8.58594 11L7 9.41406L3.06348 13.3496ZM4 4C3.44772 4 3 4.44772 3 5V10.5859L6.29297 7.29297L6.36914 7.22461C6.76191 6.90427 7.34092 6.92686 7.70703 7.29297L10 9.58594L10.293 9.29297L10.3691 9.22461C10.7619 8.90427 11.3409 8.92686 11.707 9.29297L15 12.5859V5C15 4.44772 14.5523 4 14 4H4ZM12.5 5C13.3284 5 14 5.67157 14 6.5C14 7.32843 13.3284 8 12.5 8C11.6716 8 11 7.32843 11 6.5C11 5.67157 11.6716 5 12.5 5Z"/> 37453 </svg>`, 37454 "attachment": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37455 <path d="M13 13.5V6C13 4.067 11.433 2.5 9.5 2.5C7.567 2.5 6 4.067 6 6V13.5C6 14.6046 6.89543 15.5 8 15.5H8.23047C9.20759 15.5 10 14.7076 10 13.7305V7C10 6.72386 9.77614 6.5 9.5 6.5C9.22386 6.5 9 6.72386 9 7V12.5C9 13.0523 8.55228 13.5 8 13.5C7.44772 13.5 7 13.0523 7 12.5V7C7 5.61929 8.11929 4.5 9.5 4.5C10.8807 4.5 12 5.61929 12 7V13.7305C12 15.8122 10.3122 17.5 8.23047 17.5H8C5.79086 17.5 4 15.7091 4 13.5V6C4 2.96243 6.46243 0.5 9.5 0.5C12.5376 0.5 15 2.96243 15 6V13.5C15 14.0523 14.5523 14.5 14 14.5C13.4477 14.5 13 14.0523 13 13.5Z"/> 37456 </svg>`, 37457 "table": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37458 <path d="M15 1C16.1046 1 17 1.89543 17 3V15C17 16.1046 16.1046 17 15 17H3C1.89543 17 1 16.1046 1 15V3C1 1.89543 1.89543 1 3 1H15ZM3 15H8V10H3V15ZM10 10V15H15V10H10ZM10 8H15V3H10V8ZM3 8H8V3H3V8Z"/> 37459 </svg>`, 37460 "hr": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37461 <path d="M12.75 12C13.1642 12 13.5 12.3358 13.5 12.75V14.25C13.5 14.6642 13.1642 15 12.75 15H5.25C4.83579 15 4.5 14.6642 4.5 14.25V12.75C4.5 12.3358 4.83579 12 5.25 12H12.75ZM15.4863 8C16.0461 8 16.5 8.44771 16.5 9C16.5 9.55229 16.0461 10 15.4863 10H2.51367C1.95392 10 1.5 9.55229 1.5 9C1.5 8.44771 1.95392 8 2.51367 8H15.4863ZM12.75 3C13.1642 3 13.5 3.33579 13.5 3.75V5.25C13.5 5.66421 13.1642 6 12.75 6H5.25C4.83579 6 4.5 5.66421 4.5 5.25V3.75C4.5 3.33579 4.83579 3 5.25 3H12.75Z"/> 37462 </svg>`, 37463 "undo": `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> 37464 <path d="M8.36612 5.36612C8.85427 4.87796 9.64554 4.87796 10.1337 5.36612C10.6218 5.85428 10.6218 6.64557 10.1337 7.13369L7.26748 9.9999H15.2499C18.1494 9.99996 20.4999 12.3504 20.4999 15.2499V19.2499C20.4999 19.9402 19.9402 20.4999 19.2499 20.4999C18.5596 20.4999 18 19.9402 17.9999 19.2499V15.2499C17.9999 13.7312 16.7686 12.5 15.2499 12.4999H7.26748L10.1337 15.3661C10.6218 15.8543 10.6218 16.6456 10.1337 17.1337C9.64557 17.6218 8.85428 17.6218 8.36612 17.1337L3.36612 12.1337C2.87796 11.6455 2.87796 10.8543 3.36612 10.3661L8.36612 5.36612Z"/> 37465 </svg>`, 37466 "redo": `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> 37467 <path d="M15.6338 5.1163C15.1456 4.62814 14.3543 4.62814 13.8662 5.1163C13.3781 5.60446 13.3781 6.39575 13.8662 6.88388L16.7324 9.75009H8.74997C5.85052 9.75014 3.49997 12.1006 3.49997 15.0001V19.0001C3.50002 19.6904 4.05969 20.25 4.74997 20.2501C5.4403 20.2501 5.99992 19.6904 5.99997 19.0001V15.0001C5.99997 13.4813 7.23123 12.2501 8.74997 12.2501H16.7324L13.8662 15.1163C13.3781 15.6045 13.3781 16.3958 13.8662 16.8839C14.3543 17.372 15.1456 17.3719 15.6338 16.8839L20.6338 11.8839C21.1219 11.3957 21.1219 10.6045 20.6338 10.1163L15.6338 5.1163Z" /> 37468 </svg>`, 37469 "overflow": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 37470 <path d="M3 6.75C4.24264 6.75 5.25 7.75736 5.25 9C5.25 10.2426 4.24264 11.25 3 11.25C1.75736 11.25 0.75 10.2426 0.75 9C0.75 7.75736 1.75736 6.75 3 6.75ZM9 6.75C10.2426 6.75 11.25 7.75736 11.25 9C11.25 10.2426 10.2426 11.25 9 11.25C7.75736 11.25 6.75 10.2426 6.75 9C6.75 7.75736 7.75736 6.75 9 6.75ZM15 6.75C16.2426 6.75 17.25 7.75736 17.25 9C17.25 10.2426 16.2426 11.25 15 11.25C13.7574 11.25 12.75 10.2426 12.75 9C12.75 7.75736 13.7574 6.75 15 6.75Z"/> 37471 </svg>` 37472 }; 37473 var LexicalToolbarElement = class extends HTMLElement { 37474 static observedAttributes = ["connected"]; 37475 #listeners = new ListenerBin(); 37476 #refreshToolbarAF = null; 37477 constructor() { 37478 super(); 37479 this.internals = this.attachInternals(); 37480 this.internals.role = "toolbar"; 37481 this.#createEditorPromise(); 37482 } 37483 connectedCallback() { 37484 this.requestOverflowRefresh(); 37485 this.setAttribute("role", "toolbar"); 37486 this.#installResizeObserver(); 37487 } 37488 disconnectedCallback() { 37489 this.dispose(); 37490 } 37491 dispose() { 37492 this.#listeners.dispose(); 37493 cancelAnimationFrame(this.#refreshToolbarAF); 37494 this.editorElement = null; 37495 this.editor = null; 37496 this.selection = null; 37497 this.#refreshToolbarAF = null; 37498 this.#createEditorPromise(); 37499 } 37500 attributeChangedCallback(name, oldValue, newValue) { 37501 if (name === "connected" && this.isConnected && oldValue != null && oldValue !== newValue) { 37502 requestAnimationFrame(() => this.#reconnect()); 37503 } 37504 } 37505 configure(config) { 37506 if (typeof config === "object" && config !== null) { 37507 for (const [button, value] of Object.entries(config)) { 37508 this.setAttribute(`data-${button}`, value); 37509 } 37510 } 37511 } 37512 setEditor(editorElement) { 37513 this.editorElement = editorElement; 37514 this.editor = editorElement.editor; 37515 this.selection = editorElement.selection; 37516 this.#bindButtons(); 37517 this.#bindHotkeys(); 37518 this.#resetTabIndexValues(); 37519 this.#monitorSelectionChanges(); 37520 this.#monitorHistoryChanges(); 37521 this.requestOverflowRefresh(); 37522 this.#bindFocusListeners(); 37523 this.resolveEditorPromise(editorElement); 37524 this.toggleAttribute("connected", true); 37525 } 37526 async getEditorElement() { 37527 return this.editorElement || await this.editorPromise; 37528 } 37529 requestOverflowRefresh() { 37530 if (this.#refreshToolbarAF != null) return; 37531 this.#refreshToolbarAF = requestAnimationFrame(() => { 37532 this.#refreshOverflow(); 37533 this.#refreshToolbarAF = null; 37534 }); 37535 } 37536 closeDropdowns({ except } = {}) { 37537 this.#dropdowns.forEach((dropdown) => { 37538 if (dropdown !== except) { 37539 dropdown.close({ focusEditor: false }); 37540 } 37541 }); 37542 } 37543 #reconnect() { 37544 this.disconnectedCallback(); 37545 this.connectedCallback(); 37546 } 37547 async #createEditorPromise() { 37548 this.editorPromise = new Promise((resolve) => { 37549 this.resolveEditorPromise = resolve; 37550 }); 37551 this.editorElement = await this.editorPromise; 37552 } 37553 #installResizeObserver() { 37554 const resizeObserver = new ResizeObserver(() => this.requestOverflowRefresh()); 37555 resizeObserver.observe(this); 37556 this.#listeners.track(() => resizeObserver.disconnect()); 37557 } 37558 #bindButtons() { 37559 this.#listeners.track(registerEventListener(this, "click", this.#handleButtonClicked)); 37560 } 37561 #handleButtonClicked = (event) => { 37562 this.#handleTargetClicked(event, "[data-command]", this.#dispatchButtonCommand.bind(this)); 37563 }; 37564 #handleTargetClicked(event, selector, callback) { 37565 const button = event.target.closest(selector); 37566 if (button) { 37567 callback(event, button); 37568 } 37569 } 37570 #dispatchButtonCommand(event, { dataset: { command, payload } }) { 37571 const isKeyboard = event instanceof PointerEvent && event.pointerId === -1; 37572 this.editor.update(() => { 37573 this.editor.dispatchCommand(command, payload); 37574 }, { tag: isKeyboard ? SKIP_DOM_SELECTION_TAG2 : void 0 }); 37575 if (!isKeyboard) this.editor.focus(); 37576 } 37577 #bindHotkeys() { 37578 this.#listeners.track(registerEventListener(this.editorElement, "keydown", this.#handleHotkey)); 37579 } 37580 #handleHotkey = (event) => { 37581 const buttons = this.querySelectorAll("[data-hotkey]"); 37582 buttons.forEach((button) => { 37583 const hotkeys = button.dataset.hotkey.toLowerCase().split(/\s+/); 37584 if (hotkeys.includes(this.#keyCombinationFor(event))) { 37585 event.preventDefault(); 37586 event.stopPropagation(); 37587 button.click(); 37588 } 37589 }); 37590 }; 37591 #keyCombinationFor(event) { 37592 const pressedKey = event.key.toLowerCase(); 37593 const modifiers = [ 37594 event.ctrlKey ? "ctrl" : null, 37595 event.metaKey ? "cmd" : null, 37596 event.altKey ? "alt" : null, 37597 event.shiftKey ? "shift" : null 37598 ].filter(Boolean); 37599 return [...modifiers, pressedKey].join("+"); 37600 } 37601 #bindFocusListeners() { 37602 this.#listeners.track( 37603 registerEventListener(this.editorElement, "lexxy:focus", this.#handleEditorFocus), 37604 registerEventListener(this.editorElement, "lexxy:blur", this.#handleEditorBlur), 37605 registerEventListener(this, "keydown", this.#handleKeydown) 37606 ); 37607 } 37608 #handleEditorFocus = () => { 37609 const firstVisible = this.#buttons.find(isActiveAndVisible); 37610 if (firstVisible) firstVisible.tabIndex = 0; 37611 }; 37612 #handleEditorBlur = () => { 37613 this.#resetTabIndexValues(); 37614 }; 37615 #handleKeydown = (event) => { 37616 handleRollingTabIndex(this.#buttons, event); 37617 }; 37618 #resetTabIndexValues() { 37619 this.#buttons.forEach((button) => { 37620 button.tabIndex = -1; 37621 }); 37622 } 37623 #monitorSelectionChanges() { 37624 this.#listeners.track(this.editor.registerUpdateListener(({ editorState }) => { 37625 editorState.read(() => { 37626 this.#updateButtonStates(); 37627 this.closeDropdowns(); 37628 }); 37629 })); 37630 } 37631 #monitorHistoryChanges() { 37632 this.#listeners.track( 37633 this.editor.registerCommand(CAN_UNDO_COMMAND2, (enabled) => { 37634 this.#setButtonDisabled("undo", !enabled); 37635 }, COMMAND_PRIORITY_LOW2), 37636 this.editor.registerCommand(CAN_REDO_COMMAND2, (enabled) => { 37637 this.#setButtonDisabled("redo", !enabled); 37638 }, COMMAND_PRIORITY_LOW2) 37639 ); 37640 } 37641 #updateButtonStates() { 37642 const selection = $getSelection2(); 37643 if (!$isRangeSelection2(selection)) return; 37644 const anchorNode = selection.anchor.getNode(); 37645 if (!anchorNode.getParent()) { 37646 return; 37647 } 37648 const { 37649 isBold: isBold2, 37650 isItalic: isItalic2, 37651 isStrikethrough, 37652 isUnderline: isUnderline2, 37653 isHighlight, 37654 isInLink, 37655 isInQuote, 37656 isInHeading, 37657 headingTag, 37658 isInCode, 37659 isInList, 37660 listType, 37661 isInTable 37662 } = this.selection.getFormat(); 37663 this.#setButtonPressed("bold", isBold2); 37664 this.#setButtonPressed("italic", isItalic2); 37665 this.#setButtonPressed("strikethrough", isStrikethrough); 37666 this.#setButtonPressed("underline", isUnderline2); 37667 this.#setButtonPressed("format", isInHeading); 37668 this.#setButtonPressed("paragraph", !isInHeading); 37669 this.querySelector("lexxy-heading-dropdown")?.updateActiveHeading(headingTag); 37670 this.#setButtonPressed("lists", isInList); 37671 this.#setButtonPressed("unordered-list", isInList && listType === "bullet"); 37672 this.#setButtonPressed("ordered-list", isInList && listType === "number"); 37673 this.#setButtonPressed("highlight", isHighlight); 37674 this.#setButtonPressed("link", isInLink); 37675 this.#setButtonPressed("quote", isInQuote); 37676 this.#setButtonPressed("code", isInCode); 37677 this.#setButtonPressed("table", isInTable); 37678 } 37679 #setButtonPressed(name, isPressed) { 37680 const button = this.querySelector(`[name="${name}"]`); 37681 if (button) { 37682 const next = isPressed.toString(); 37683 if (button.getAttribute("aria-pressed") !== next) { 37684 button.setAttribute("aria-pressed", next); 37685 } 37686 } 37687 } 37688 #setButtonDisabled(name, isDisabled) { 37689 const button = this.querySelector(`[name="${name}"]`); 37690 if (button) { 37691 if (button.disabled !== isDisabled) { 37692 button.disabled = isDisabled; 37693 } 37694 const next = isDisabled.toString(); 37695 if (button.getAttribute("aria-disabled") !== next) { 37696 button.setAttribute("aria-disabled", next); 37697 } 37698 } 37699 } 37700 #refreshOverflow() { 37701 this.#hideOverflowMenuButton(); 37702 this.#resetToolbarOverflow(); 37703 this.#reindexToolbarItems(); 37704 this.#compactMenu(); 37705 const isOverflowing = this.#overflowMenuDropdown.children.length > 0; 37706 this.toggleAttribute("overflowing", isOverflowing); 37707 this.#setOverflowMenuNonce(); 37708 this.#showOverflowMenuButton(isOverflowing); 37709 } 37710 #resetToolbarOverflow() { 37711 const items = Array.from(this.#overflowMenuDropdown.children); 37712 items.sort((a2, b3) => this.#itemPosition(b3) - this.#itemPosition(a2)); 37713 for (const item of items) { 37714 const nextItem = this.querySelector(`[data-position="${this.#itemPosition(item) + 1}"]`) ?? this.#overflowMenuButton; 37715 item.removeAttribute("role"); 37716 this.insertBefore(item, nextItem); 37717 } 37718 } 37719 #showOverflowMenuButton(show = true) { 37720 this.#overflowMenuDropdown.toggleAttribute("disabled", !show); 37721 this.#overflowMenuButton.style.display = show ? "block" : "none"; 37722 } 37723 #hideOverflowMenuButton() { 37724 this.#showOverflowMenuButton(false); 37725 } 37726 #itemPosition(item) { 37727 return parseInt(item.dataset.position ?? "999"); 37728 } 37729 #reindexToolbarItems() { 37730 this.#toolbarItems.forEach((item, index) => { 37731 item.dataset.position = index; 37732 }); 37733 } 37734 #compactMenu() { 37735 const overflowWidth = this.#getOverflowWidth(); 37736 if (overflowWidth > 0) { 37737 this.#showOverflowMenuButton(); 37738 const gap = this.#getToolbarGap(); 37739 const spaceForOverflow = gap + this.#overflowMenuButton.offsetWidth; 37740 this.#reclaimWidth(overflowWidth + spaceForOverflow, { gap }); 37741 } 37742 } 37743 #getOverflowWidth() { 37744 return this.scrollWidth - this.clientWidth; 37745 } 37746 #reclaimWidth(overflowWidth, { gap }) { 37747 const buttons = this.#overflowableButtons; 37748 const overflowButtons = []; 37749 let recoveredWidth = 0; 37750 while (recoveredWidth < overflowWidth && buttons.length) { 37751 const button = buttons.pop(); 37752 overflowButtons.push(button); 37753 button.role = "menuitem"; 37754 recoveredWidth += button.offsetWidth + gap; 37755 } 37756 this.#overflowMenuDropdown.append(...overflowButtons.reverse()); 37757 } 37758 #setOverflowMenuNonce() { 37759 this.#overflowMenuButton.setAttribute("nonce", getNonce()); 37760 } 37761 #getToolbarGap() { 37762 return parseFloat(window.getComputedStyle(this).columnGap) || 0; 37763 } 37764 get #dropdowns() { 37765 return this.querySelectorAll(":scope .lexxy-editor__toolbar-dropdown"); 37766 } 37767 get #overflowMenuButton() { 37768 return this.querySelector(".lexxy-editor__toolbar-overflow"); 37769 } 37770 get #overflowMenuDropdown() { 37771 return this.#overflowMenuButton?.querySelector(":scope > [data-dropdown-panel]"); 37772 } 37773 get #overflowableButtons() { 37774 return Array.from(this.querySelectorAll(":scope > button:not([data-prevent-overflow])")); 37775 } 37776 get #buttons() { 37777 return Array.from(this.querySelectorAll(":scope button")); 37778 } 37779 get #toolbarItems() { 37780 return Array.from(this.querySelectorAll(":scope > *:not(.lexxy-editor__toolbar-overflow)")); 37781 } 37782 static get defaultTemplate() { 37783 const linkInputId = generateDomId("lexxy-link-url"); 37784 return ` 37785 <button class="lexxy-editor__toolbar-button" type="button" name="image" data-command="uploadImage" data-prevent-overflow="true" title="Add images and video"> 37786 ${ToolbarIcons.image} 37787 </button> 37788 37789 <button class="lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end" type="button" name="file" data-command="uploadFile" title="Upload files"> 37790 ${ToolbarIcons.attachment} 37791 </button> 37792 37793 <button class="lexxy-editor__toolbar-button" type="button" name="bold" data-command="bold" title="Bold"> 37794 ${ToolbarIcons.bold} 37795 </button> 37796 37797 <button class="lexxy-editor__toolbar-button" type="button" name="italic" data-command="italic" title="Italic"> 37798 ${ToolbarIcons.italic} 37799 </button> 37800 37801 <button class="lexxy-editor__toolbar-button" type="button" name="strikethrough" data-command="strikethrough" title="Strikethrough"> 37802 ${ToolbarIcons.strikethrough} 37803 </button> 37804 37805 <button class="lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end" type="button" name="underline" data-command="underline" title="Underline"> 37806 ${ToolbarIcons.underline} 37807 </button> 37808 37809 <lexxy-toolbar-dropdown class="lexxy-editor__toolbar-dropdown"> 37810 <button data-dropdown-trigger class="lexxy-editor__toolbar-button lexxy-editor__toolbar-button--chevron" type="button" name="format" title="Text formatting" aria-haspopup="menu" aria-expanded="false"> 37811 ${ToolbarIcons.heading} 37812 </button> 37813 <div data-dropdown-panel role="menu" class="lexxy-editor__toolbar-dropdown-list" hidden> 37814 <button type="button" name="paragraph" data-command="setFormatParagraph" title="Paragraph" role="menuitem"> 37815 ${ToolbarIcons.paragraph} <span>Normal</span> 37816 </button> 37817 <lexxy-heading-dropdown> 37818 <div class="lexxy-heading-options"></div> 37819 </lexxy-heading-dropdown> 37820 <div class="lexxy-editor__toolbar-separator" role="separator"></div> 37821 <button type="button" name="clear-formatting" data-command="clearFormatting" title="Clear formatting" role="menuitem"> 37822 ${ToolbarIcons.clearFormatting} <span>Clear formatting</span> 37823 </button> 37824 </div> 37825 </lexxy-toolbar-dropdown> 37826 37827 <lexxy-highlight-dropdown class="lexxy-editor__toolbar-dropdown lexxy-editor__toolbar-dropdown--highlight"> 37828 <button data-dropdown-trigger class="lexxy-editor__toolbar-button lexxy-editor__toolbar-button--chevron" type="button" name="highlight" title="Color highlight" aria-haspopup="menu" aria-expanded="false"> 37829 ${ToolbarIcons.highlight} 37830 </button> 37831 <div data-dropdown-panel role="menu" hidden> 37832 <div class="lexxy-highlight-colors"></div> 37833 <button data-command="removeHighlight" type="button" class="lexxy-editor__toolbar-button lexxy-editor__toolbar-dropdown-reset" role="menuitem">Remove all coloring</button> 37834 </div> 37835 </lexxy-highlight-dropdown> 37836 37837 <lexxy-link-dropdown class="lexxy-editor__toolbar-dropdown lexxy-editor__toolbar-dropdown--link"> 37838 <button data-dropdown-trigger class="lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end" type="button" name="link" title="Link" data-hotkey="cmd+k ctrl+k" aria-haspopup="dialog" aria-expanded="false"> 37839 ${ToolbarIcons.link} 37840 </button> 37841 <div data-dropdown-panel role="dialog" aria-label="Link" hidden> 37842 <input type="url" placeholder="Enter a URL\u2026" class="input" id="${linkInputId}"> 37843 <div class="lexxy-editor__toolbar-dropdown-actions"> 37844 <button type="button" class="lexxy-editor__toolbar-button" value="link">Link</button> 37845 <button type="button" class="lexxy-editor__toolbar-button" value="unlink">Unlink</button> 37846 </div> 37847 </div> 37848 </lexxy-link-dropdown> 37849 37850 <button class="lexxy-editor__toolbar-button" type="button" name="quote" data-command="insertQuoteBlock" title="Quote"> 37851 ${ToolbarIcons.quote} 37852 </button> 37853 37854 <button class="lexxy-editor__toolbar-button" type="button" name="code" data-command="insertCodeBlock" title="Code"> 37855 ${ToolbarIcons.code} 37856 </button> 37857 37858 <button class="lexxy-editor__toolbar-button" type="button" name="unordered-list" data-command="insertUnorderedList" title="Bullet list"> 37859 ${ToolbarIcons.ul} 37860 </button> 37861 <button class="lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end" type="button" name="ordered-list" data-command="insertOrderedList" title="Numbered list"> 37862 ${ToolbarIcons.ol} 37863 </button> 37864 37865 <button class="lexxy-editor__toolbar-button" type="button" name="table" data-command="insertTable" title="Insert a table"> 37866 ${ToolbarIcons.table} 37867 </button> 37868 37869 <button class="lexxy-editor__toolbar-button" type="button" name="divider" data-command="insertHorizontalDivider" title="Insert a divider"> 37870 ${ToolbarIcons.hr} 37871 </button> 37872 37873 <button class="lexxy-editor__toolbar-button lexxy-editor__toolbar-button--push-right" type="button" name="undo" data-command="undo" title="Undo" disabled aria-disabled="true"> 37874 ${ToolbarIcons.undo} 37875 </button> 37876 37877 <button class="lexxy-editor__toolbar-button" type="button" name="redo" data-command="redo" title="Redo" disabled aria-disabled="true"> 37878 ${ToolbarIcons.redo} 37879 </button> 37880 37881 <lexxy-toolbar-dropdown class="lexxy-editor__toolbar-dropdown lexxy-editor__toolbar-button--push-right lexxy-editor__toolbar-overflow"> 37882 <button data-dropdown-trigger class="lexxy-editor__toolbar-button" type="button" aria-haspopup="menu" aria-expanded="false" aria-label="Show more toolbar buttons"> 37883 ${ToolbarIcons.overflow} 37884 </button> 37885 <div data-dropdown-panel role="menu" class="lexxy-editor__toolbar-overflow-menu" aria-label="More toolbar buttons" hidden></div> 37886 </lexxy-toolbar-dropdown> 37887 `; 37888 } 37889 }; 37890 function debounce(fn, wait) { 37891 let timeout; 37892 return (...args) => { 37893 clearTimeout(timeout); 37894 timeout = setTimeout(() => fn(...args), wait); 37895 }; 37896 } 37897 function debounceAsync(fn, wait) { 37898 let timeout; 37899 return (...args) => { 37900 clearTimeout(timeout); 37901 return new Promise((resolve, reject) => { 37902 timeout = setTimeout(async () => { 37903 try { 37904 const result = await fn(...args); 37905 resolve(result); 37906 } catch (err) { 37907 reject(err); 37908 } 37909 }, wait); 37910 }); 37911 }; 37912 } 37913 function delay(ms) { 37914 return new Promise((resolve) => setTimeout(resolve, ms)); 37915 } 37916 function nextFrame() { 37917 return new Promise(requestAnimationFrame); 37918 } 37919 var ToolbarDropdown = class extends HTMLElement { 37920 #listeners = new ListenerBin(); 37921 connectedCallback() { 37922 this.#onToolbarEditor(() => { 37923 this.#registerListeners(); 37924 this.editorReady(); 37925 }); 37926 } 37927 disconnectedCallback() { 37928 this.#listeners.dispose(); 37929 } 37930 editorReady() { 37931 } 37932 onOpen() { 37933 } 37934 onClose() { 37935 } 37936 get trigger() { 37937 return this.querySelector(":scope > [data-dropdown-trigger]"); 37938 } 37939 get panel() { 37940 return this.querySelector(":scope > [data-dropdown-panel]"); 37941 } 37942 get toolbar() { 37943 return this.closest("lexxy-toolbar"); 37944 } 37945 get editorElement() { 37946 return this.toolbar?.editorElement; 37947 } 37948 get editor() { 37949 return this.toolbar?.editor; 37950 } 37951 get isOpen() { 37952 return this.panel.hidden === false; 37953 } 37954 get isClosed() { 37955 return !this.isOpen; 37956 } 37957 track(...listeners) { 37958 this.#listeners.track(...listeners); 37959 } 37960 open() { 37961 if (this.isOpen) return; 37962 this.trigger.setAttribute("aria-expanded", "true"); 37963 this.panel.hidden = false; 37964 this.onOpen(); 37965 this.#focusFirstInteractive(); 37966 } 37967 close({ focusEditor = true } = {}) { 37968 if (focusEditor) this.editor?.focus(); 37969 if (this.isClosed) return; 37970 this.trigger.setAttribute("aria-expanded", "false"); 37971 this.panel.hidden = true; 37972 this.onClose(); 37973 } 37974 #registerListeners() { 37975 this.#listeners.track( 37976 registerEventListener(this, "keydown", this.#handleKeyDown), 37977 registerEventListener(this.trigger, "click", this.#handleTriggerClick) 37978 ); 37979 } 37980 #handleTriggerClick = () => { 37981 if (this.isOpen) { 37982 this.close({ focusEditor: false }); 37983 } else { 37984 this.toolbar?.closeDropdowns({ except: this }); 37985 this.open(); 37986 } 37987 }; 37988 async #onToolbarEditor(callback) { 37989 if (!this.toolbar) return; 37990 await this.toolbar.getEditorElement(); 37991 if (this.isConnected && this.toolbar) callback(); 37992 } 37993 #handleKeyDown = (event) => { 37994 if (event.key === "Escape") { 37995 event.stopPropagation(); 37996 this.close(); 37997 } 37998 }; 37999 async #focusFirstInteractive() { 38000 this.#interactiveElements[0]?.focus(); 38001 await this.#resetTabIndexValues(); 38002 } 38003 async #resetTabIndexValues() { 38004 await nextFrame(); 38005 this.#buttons.forEach((element, index) => { 38006 element.setAttribute("tabindex", index === 0 ? 0 : "-1"); 38007 }); 38008 } 38009 get #interactiveElements() { 38010 return Array.from(this.panel.querySelectorAll("button, input")); 38011 } 38012 get #buttons() { 38013 return Array.from(this.panel.querySelectorAll("button")); 38014 } 38015 }; 38016 var HEADING_BUTTON_SELECTOR = "button.lexxy-heading-button"; 38017 var HEADING_PRESETS = [ 38018 { label: "Large Heading", name: "heading-large", command: "setFormatHeadingLarge" }, 38019 { label: "Medium Heading", name: "heading-medium", command: "setFormatHeadingMedium" }, 38020 { label: "Small Heading", name: "heading-small", command: "setFormatHeadingSmall" } 38021 ]; 38022 var HeadingDropdown = class _HeadingDropdown extends HTMLElement { 38023 static labelFor(tag, index) { 38024 if (index < HEADING_PRESETS.length) { 38025 return HEADING_PRESETS[index].label; 38026 } else { 38027 const level = tag.match(/^h(\d+)$/)?.[1]; 38028 if (level) { 38029 return `Heading ${level}`; 38030 } else { 38031 return tag.toUpperCase(); 38032 } 38033 } 38034 } 38035 static nameFor(tag, index) { 38036 if (index < HEADING_PRESETS.length) { 38037 return HEADING_PRESETS[index].name; 38038 } else { 38039 const level = tag.match(/^h(\d+)$/)?.[1]; 38040 if (level) { 38041 return `heading-${level}`; 38042 } else { 38043 return `heading-${tag}`; 38044 } 38045 } 38046 } 38047 static commandFor(index) { 38048 if (index < HEADING_PRESETS.length) { 38049 return HEADING_PRESETS[index].command; 38050 } else { 38051 return "applyHeadingFormat"; 38052 } 38053 } 38054 #listeners = new ListenerBin(); 38055 connectedCallback() { 38056 this.style.display = "contents"; 38057 this.#onToolbarEditor(() => { 38058 this.#buttonContainer.style.display = "contents"; 38059 this.#setUpButtons(); 38060 this.#registerButtonHandlers(); 38061 this.#syncActiveHeading(); 38062 }); 38063 } 38064 disconnectedCallback() { 38065 this.#listeners.dispose(); 38066 } 38067 updateActiveHeading(tag) { 38068 this.#headingButtons.forEach((button) => { 38069 const next = (button.dataset.heading === tag).toString(); 38070 if (button.getAttribute("aria-pressed") !== next) { 38071 button.setAttribute("aria-pressed", next); 38072 } 38073 }); 38074 } 38075 get #toolbar() { 38076 return this.closest("lexxy-toolbar"); 38077 } 38078 get #editorElement() { 38079 return this.#toolbar?.editorElement; 38080 } 38081 get #editor() { 38082 return this.#toolbar?.editor; 38083 } 38084 async #onToolbarEditor(callback) { 38085 const toolbar = this.#toolbar; 38086 if (!toolbar) return; 38087 await toolbar.getEditorElement(); 38088 if (this.isConnected && this.#toolbar) callback(); 38089 } 38090 #setUpButtons() { 38091 this.#buttonContainer.innerHTML = ""; 38092 this.#configuredHeadings.forEach((tag, index) => { 38093 this.#buttonContainer.appendChild(this.#createButton(tag, index)); 38094 }); 38095 } 38096 #createButton(tag, index) { 38097 const label = _HeadingDropdown.labelFor(tag, index); 38098 const name = _HeadingDropdown.nameFor(tag, index); 38099 const icon = ToolbarIcons[tag] || ""; 38100 const button = document.createElement("button"); 38101 button.type = "button"; 38102 button.dataset.heading = tag; 38103 button.dataset.command = _HeadingDropdown.commandFor(index); 38104 button.classList.add("lexxy-heading-button"); 38105 button.name = name; 38106 button.title = label; 38107 button.setAttribute("role", "menuitem"); 38108 button.innerHTML = `${icon} <span>${label}</span>`; 38109 return button; 38110 } 38111 #registerButtonHandlers() { 38112 this.#headingButtons.forEach((button) => { 38113 this.#listeners.track(registerEventListener(button, "click", (event) => { 38114 if (!this.#editor) return; 38115 event.preventDefault(); 38116 this.#editor.dispatchCommand(button.dataset.command, button.dataset.heading); 38117 this.#editor.focus(); 38118 })); 38119 }); 38120 } 38121 #syncActiveHeading() { 38122 const { headingTag } = this.#editor.read(() => this.#editorElement.selection.getFormat()); 38123 this.updateActiveHeading(headingTag ?? null); 38124 } 38125 get #configuredHeadings() { 38126 return this.#editorElement.config.get("headings"); 38127 } 38128 get #buttonContainer() { 38129 return this.querySelector(".lexxy-heading-options"); 38130 } 38131 get #headingButtons() { 38132 return Array.from(this.querySelectorAll(HEADING_BUTTON_SELECTOR)); 38133 } 38134 }; 38135 var APPLY_HIGHLIGHT_SELECTOR = "button.lexxy-highlight-button"; 38136 var REMOVE_HIGHLIGHT_SELECTOR = "[data-command='removeHighlight']"; 38137 var NO_STYLE = Symbol("no_style"); 38138 var HighlightDropdown = class extends ToolbarDropdown { 38139 editorReady() { 38140 this.#setUpButtons(); 38141 this.#registerButtonHandlers(); 38142 } 38143 onOpen() { 38144 this.editor.getEditorState().read(() => { 38145 this.#updateColorButtonStates($getSelection2()); 38146 }); 38147 } 38148 #registerButtonHandlers() { 38149 this.#colorButtons.forEach((button) => { 38150 this.track(registerEventListener(button, "click", this.#handleColorButtonClick)); 38151 }); 38152 } 38153 #setUpButtons() { 38154 this.#buttonContainer.innerHTML = ""; 38155 const colorGroups = this.editorElement.config.get("highlight.buttons"); 38156 this.#populateButtonGroup("color", colorGroups.color); 38157 this.#populateButtonGroup("background-color", colorGroups["background-color"]); 38158 const maxNumberOfColors = Math.max(colorGroups.color.length, colorGroups["background-color"].length); 38159 this.panel.style.setProperty("--max-colors", maxNumberOfColors); 38160 } 38161 #populateButtonGroup(attribute, values) { 38162 values.forEach((value, index) => { 38163 this.#buttonContainer.appendChild(this.#createButton(attribute, value, index)); 38164 }); 38165 } 38166 #createButton(attribute, value, index) { 38167 return createElement("button", { 38168 type: "button", 38169 dataset: { value, style: attribute }, 38170 style: `${attribute}: ${value}`, 38171 class: "lexxy-editor__toolbar-button lexxy-highlight-button", 38172 name: `${attribute}-${index}`, 38173 role: "menuitem" 38174 }); 38175 } 38176 #handleColorButtonClick = (event) => { 38177 event.preventDefault(); 38178 const button = event.target.closest(APPLY_HIGHLIGHT_SELECTOR); 38179 if (!button) return; 38180 const { style, value } = button.dataset; 38181 this.editor.dispatchCommand("toggleHighlight", { [style]: value }); 38182 this.close(); 38183 }; 38184 #updateColorButtonStates(selection) { 38185 if (!$isRangeSelection2(selection)) { 38186 return; 38187 } 38188 const textColor = $getSelectionStyleValueForProperty2(selection, "color", NO_STYLE); 38189 const backgroundColor = $getSelectionStyleValueForProperty2(selection, "background-color", NO_STYLE); 38190 this.#colorButtons.forEach((button) => { 38191 const matchesSelection = button.dataset.value === textColor || button.dataset.value === backgroundColor; 38192 const next = matchesSelection.toString(); 38193 if (button.getAttribute("aria-pressed") !== next) { 38194 button.setAttribute("aria-pressed", next); 38195 } 38196 }); 38197 const hasHighlight = textColor !== NO_STYLE || backgroundColor !== NO_STYLE; 38198 this.panel.querySelector(REMOVE_HIGHLIGHT_SELECTOR).disabled = !hasHighlight; 38199 } 38200 get #buttonContainer() { 38201 return this.panel.querySelector(".lexxy-highlight-colors"); 38202 } 38203 get #colorButtons() { 38204 return Array.from(this.panel.querySelectorAll(APPLY_HIGHLIGHT_SELECTOR)); 38205 } 38206 }; 38207 var LinkDropdown = class extends ToolbarDropdown { 38208 editorReady() { 38209 this.input = this.panel.querySelector("input"); 38210 this.track( 38211 registerEventListener(this.input, "keydown", this.#handleEnter), 38212 registerEventListener(this.linkButton, "click", this.#handleLink), 38213 registerEventListener(this.unlinkButton, "click", this.#handleUnlink) 38214 ); 38215 } 38216 onOpen() { 38217 this.input.value = this.#selectedLinkUrl; 38218 this.input.required = true; 38219 } 38220 onClose() { 38221 this.input.required = false; 38222 } 38223 get linkButton() { 38224 return this.panel.querySelector("[value='link']"); 38225 } 38226 get unlinkButton() { 38227 return this.panel.querySelector("[value='unlink']"); 38228 } 38229 #handleEnter = (event) => { 38230 if (event.key === "Enter") { 38231 event.preventDefault(); 38232 event.stopPropagation(); 38233 this.#handleLink(event); 38234 } 38235 }; 38236 #handleLink = () => { 38237 if (!this.input.checkValidity()) { 38238 this.input.reportValidity(); 38239 return; 38240 } 38241 this.editor.dispatchCommand("link", this.input.value); 38242 this.close(); 38243 }; 38244 #handleUnlink = () => { 38245 this.editor.dispatchCommand("unlink"); 38246 this.close(); 38247 }; 38248 get #selectedLinkUrl() { 38249 return this.editor.getEditorState().read(() => { 38250 const linkNode = this.editorElement.selection.nearestNodeOfType(LinkNode2); 38251 return linkNode?.getURL() ?? ""; 38252 }); 38253 } 38254 }; 38255 function deepMerge(target, source) { 38256 const result = { ...target, ...source }; 38257 for (const [key, value] of Object.entries(source)) { 38258 if (arePlainHashes(target[key], value)) { 38259 result[key] = deepMerge(target[key], value); 38260 } 38261 } 38262 return result; 38263 } 38264 function arePlainHashes(...values) { 38265 return values.every((value) => value && value.constructor == Object); 38266 } 38267 var Configuration = class { 38268 #tree = {}; 38269 constructor(...configs) { 38270 this.merge(...configs); 38271 } 38272 merge(...configs) { 38273 return this.#tree = configs.reduce(deepMerge, this.#tree); 38274 } 38275 get(path) { 38276 const keys = path.split("."); 38277 return keys.reduce((node, key) => node[key], this.#tree); 38278 } 38279 }; 38280 function range(from, to) { 38281 return [...Array(1 + to - from).keys()].map((i2) => i2 + from); 38282 } 38283 var global2 = new Configuration({ 38284 attachmentTagName: "action-text-attachment", 38285 attachmentContentTypeNamespace: "actiontext", 38286 authenticatedUploads: false, 38287 extensions: [] 38288 }); 38289 var presets = new Configuration({ 38290 default: { 38291 attachments: true, 38292 markdown: true, 38293 multiLine: true, 38294 permittedAttachmentTypes: null, 38295 richText: true, 38296 toolbar: { 38297 upload: "both" 38298 }, 38299 headings: ["h2", "h3", "h4"], 38300 highlight: { 38301 buttons: { 38302 color: range(1, 9).map((n2) => `var(--highlight-${n2})`), 38303 "background-color": range(1, 9).map((n2) => `var(--highlight-bg-${n2})`) 38304 }, 38305 permit: { 38306 color: [], 38307 "background-color": [] 38308 } 38309 } 38310 } 38311 }); 38312 var Lexxy = { 38313 global: global2, 38314 presets, 38315 configure({ global: newGlobal, ...newPresets }) { 38316 if (newGlobal) { 38317 global2.merge(newGlobal); 38318 } 38319 presets.merge(newPresets); 38320 } 38321 }; 38322 function setSanitizerConfig(allowedTags) { 38323 purify.clearConfig(); 38324 purify.setConfig(buildConfig(allowedTags)); 38325 } 38326 function sanitize(html2) { 38327 return purify.sanitize(html2); 38328 } 38329 function bytesToHumanSize(bytes) { 38330 if (bytes === 0) return "0 B"; 38331 const sizes = ["B", "KB", "MB", "GB", "TB", "PB"]; 38332 const i2 = Math.floor(Math.log(bytes) / Math.log(1024)); 38333 const value = bytes / Math.pow(1024, i2); 38334 return `${value.toFixed(2)} ${sizes[i2]}`; 38335 } 38336 function extractFileName(string) { 38337 return string.split("/").pop(); 38338 } 38339 function parseAttachmentContent(content) { 38340 try { 38341 return JSON.parse(content); 38342 } catch { 38343 return content; 38344 } 38345 } 38346 function mimeTypeToExtension(mimeType) { 38347 if (!mimeType) return null; 38348 const extension = mimeType.split("/")[1]; 38349 return extension; 38350 } 38351 var CustomActionTextAttachmentNode = class _CustomActionTextAttachmentNode extends DecoratorNode2 { 38352 static getType() { 38353 return "custom_action_text_attachment"; 38354 } 38355 static clone(node) { 38356 return new _CustomActionTextAttachmentNode({ ...node }, node.__key); 38357 } 38358 static importJSON(serializedNode) { 38359 return new _CustomActionTextAttachmentNode({ ...serializedNode }); 38360 } 38361 static importDOM() { 38362 return { 38363 [this.TAG_NAME]: (element) => { 38364 const content = element.getAttribute("content"); 38365 if (!content) { 38366 return null; 38367 } 38368 if (isLexxyImageLayoutString(content)) { 38369 return null; 38370 } 38371 return { 38372 conversion: (attachment) => { 38373 const nodes = []; 38374 const previousSibling = attachment.previousSibling; 38375 if (previousSibling && previousSibling.nodeType === Node.TEXT_NODE && /\s$/.test(previousSibling.textContent)) { 38376 nodes.push($createTextNode2(" ")); 38377 } 38378 const innerHtml = parseAttachmentContent(attachment.getAttribute("content")); 38379 nodes.push(new _CustomActionTextAttachmentNode({ 38380 sgid: attachment.getAttribute("sgid"), 38381 innerHtml, 38382 plainText: attachment.textContent.trim() || extractPlainTextFromHtml(innerHtml), 38383 contentType: attachment.getAttribute("content-type") 38384 })); 38385 const nextSibling = attachment.nextSibling; 38386 if (nextSibling && nextSibling.nodeType === Node.TEXT_NODE && /^\s/.test(nextSibling.textContent)) { 38387 nodes.push($createTextNode2(" ")); 38388 } 38389 return { node: nodes }; 38390 }, 38391 priority: 2 38392 }; 38393 } 38394 }; 38395 } 38396 static get TAG_NAME() { 38397 return Lexxy.global.get("attachmentTagName"); 38398 } 38399 constructor({ tagName, sgid, contentType, innerHtml, plainText }, key) { 38400 super(key); 38401 const contentTypeNamespace = Lexxy.global.get("attachmentContentTypeNamespace"); 38402 this.tagName = tagName || _CustomActionTextAttachmentNode.TAG_NAME; 38403 this.sgid = sgid; 38404 this.contentType = contentType || `application/vnd.${contentTypeNamespace}.unknown`; 38405 this.innerHtml = innerHtml; 38406 this.plainText = plainText ?? extractPlainTextFromHtml(innerHtml); 38407 } 38408 createDOM() { 38409 const figure = createElement(this.tagName, { "content-type": this.contentType, "data-lexxy-decorator": true, draggable: true }); 38410 figure.dataset.lexicalNodeKey = this.__key; 38411 figure.insertAdjacentHTML("beforeend", sanitize(this.innerHtml)); 38412 const deleteButton = createElement("lexxy-node-delete-button"); 38413 figure.appendChild(deleteButton); 38414 return figure; 38415 } 38416 updateDOM() { 38417 return false; 38418 } 38419 getTextContent() { 38420 return "\uFEFF"; 38421 } 38422 getReadableTextContent() { 38423 return this.plainText || `[${this.contentType}]`; 38424 } 38425 isInline() { 38426 return true; 38427 } 38428 exportDOM() { 38429 const attachment = createElement(this.tagName, { 38430 sgid: this.sgid, 38431 content: this.innerHtml, 38432 "content-type": this.contentType 38433 }); 38434 return { element: attachment }; 38435 } 38436 exportJSON() { 38437 return { 38438 type: "custom_action_text_attachment", 38439 version: 1, 38440 tagName: this.tagName, 38441 sgid: this.sgid, 38442 contentType: this.contentType, 38443 innerHtml: this.innerHtml, 38444 plainText: this.plainText 38445 }; 38446 } 38447 decorate() { 38448 return null; 38449 } 38450 }; 38451 function $isCustomActionTextAttachmentNode(node) { 38452 return node instanceof CustomActionTextAttachmentNode; 38453 } 38454 function dasherize(value) { 38455 return value.replace(/([A-Z])/g, (_3, char) => `-${char.toLowerCase()}`); 38456 } 38457 function isAutolinkableURL(string) { 38458 return /^(?:[a-z0-9]+:\/\/|www\.)[^\s]+$/i.test(string.trim()); 38459 } 38460 function normalizeFilteredText(string) { 38461 return string.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, ""); 38462 } 38463 function filterMatchPosition(text2, potentialMatch) { 38464 const normalizedText = normalizeFilteredText(text2); 38465 const normalizedMatch = normalizeFilteredText(potentialMatch); 38466 if (!normalizedMatch) return 0; 38467 const match = normalizedText.match(new RegExp(`(?<![\\p{L}\\p{N}])${escapeForRegExp(normalizedMatch)}`, "u")); 38468 return match ? match.index : -1; 38469 } 38470 function upcaseFirst(string) { 38471 return string.charAt(0).toUpperCase() + string.slice(1); 38472 } 38473 function escapeForRegExp(string) { 38474 return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); 38475 } 38476 function parseBoolean(value) { 38477 if (typeof value === "string") return value === "true"; 38478 return Boolean(value); 38479 } 38480 var LexxyExtension = class { 38481 #editorElement; 38482 constructor(editorElement) { 38483 this.#editorElement = editorElement; 38484 } 38485 get editorElement() { 38486 return this.#editorElement; 38487 } 38488 get editorConfig() { 38489 return this.#editorElement.config; 38490 } 38491 // optional: defaults to true 38492 get enabled() { 38493 return true; 38494 } 38495 get lexicalExtension() { 38496 return null; 38497 } 38498 get allowedElements() { 38499 return []; 38500 } 38501 defineExtension(...args) { 38502 return defineExtension2(...args); 38503 } 38504 initializeToolbar(_lexxyToolbar) { 38505 } 38506 setEditorValidity(flags, message) { 38507 this.editorElement.setElementValidity(this, flags, message); 38508 } 38509 dispose() { 38510 } 38511 }; 38512 function $containsRangeSelection(node, selection = $getSelection2()) { 38513 if ($isRangeSelection2(selection)) { 38514 const { commonAncestor } = $getCommonAncestor2(selection.focus.getNode(), selection.anchor.getNode()); 38515 return $findMatchingParent2(commonAncestor, (parent) => parent.is(node)); 38516 } else { 38517 return false; 38518 } 38519 } 38520 function $createNodeSelectionWith(...nodes) { 38521 const selection = $createNodeSelection2(); 38522 nodes.forEach((node) => selection.add(node.getKey())); 38523 return selection; 38524 } 38525 function $isShadowRoot(node) { 38526 return $isElementNode2(node) && $isRootOrShadowRoot2(node) && !$isRootNode2(node); 38527 } 38528 function $isSafeForRoot(node) { 38529 return ($isElementNode2(node) || $isDecoratorNode2(node)) && !node.isParentRequired(); 38530 } 38531 function $makeSafeForRoot(node) { 38532 if ($isSafeForRoot(node)) { 38533 return node; 38534 } else if (node.getParent()) { 38535 return $wrapNodeInElement2(node, () => node.createParentElementNode()); 38536 } else { 38537 return node.createParentElementNode().append(node); 38538 } 38539 } 38540 function getListType(node) { 38541 const list = $getNearestNodeOfType2(node, ListNode2); 38542 return list?.getListType() ?? null; 38543 } 38544 function isEditorFocused(editor) { 38545 const rootElement = editor.getRootElement(); 38546 return rootElement !== null && rootElement.contains(document.activeElement); 38547 } 38548 function $isAtNodeEdge(point, atStart = null) { 38549 if (atStart === null) { 38550 return $isAtNodeEdge(point, true) || $isAtNodeEdge(point, false); 38551 } else { 38552 return atStart ? $isAtNodeStart(point) : $isAtNodeEnd2(point); 38553 } 38554 } 38555 function $isAtNodeStart(point) { 38556 return point.offset === 0; 38557 } 38558 function extendTextNodeConversion(conversionName, ...callbacks) { 38559 return extendConversion(TextNode2, conversionName, (conversionOutput, element) => ({ 38560 ...conversionOutput, 38561 forChild: (lexicalNode, parentNode) => { 38562 const originalForChild = conversionOutput?.forChild ?? ((x3) => x3); 38563 let childNode = originalForChild(lexicalNode, parentNode); 38564 if ($isTextNode2(childNode)) { 38565 childNode = callbacks.reduce( 38566 (childNode2, callback) => callback(childNode2, element) ?? childNode2, 38567 childNode 38568 ); 38569 return childNode; 38570 } 38571 } 38572 })); 38573 } 38574 function extendConversion(nodeKlass, conversionName, callback = (output) => output) { 38575 return (element) => { 38576 const converter = nodeKlass.importDOM()?.[conversionName]?.(element); 38577 if (!converter) return null; 38578 const conversionOutput = converter.conversion(element); 38579 if (!conversionOutput) return conversionOutput; 38580 return callback(conversionOutput, element) ?? conversionOutput; 38581 }; 38582 } 38583 function $isCursorOnLastLine(selection) { 38584 const anchorNode = selection.anchor.getNode(); 38585 const elementNode = $isElementNode2(anchorNode) ? anchorNode : anchorNode.getParentOrThrow(); 38586 const children = elementNode.getChildren(); 38587 if (children.length === 0) return true; 38588 const lastChild = children[children.length - 1]; 38589 if (anchorNode === elementNode.getLatest() && selection.anchor.offset === children.length) return true; 38590 if (anchorNode === lastChild) return true; 38591 const lastLineBreakIndex = children.findLastIndex((child) => $isLineBreakNode2(child)); 38592 if (lastLineBreakIndex === -1) return true; 38593 const anchorIndex = children.indexOf(anchorNode); 38594 return anchorIndex > lastLineBreakIndex; 38595 } 38596 function $isBlankNode(node) { 38597 if (node.getTextContent().trim() !== "") return false; 38598 const children = node.getChildren?.(); 38599 if (!children || children.length === 0) return true; 38600 return children.every((child) => { 38601 if ($isLineBreakNode2(child)) return true; 38602 return $isBlankNode(child); 38603 }); 38604 } 38605 function $trimTrailingBlankNodes(parent) { 38606 for (const child of $lastToFirstIterator2(parent)) { 38607 if ($isBlankNode(child)) { 38608 child.remove(); 38609 } else { 38610 break; 38611 } 38612 } 38613 } 38614 function $isListItemStructurallyEmpty(listItem) { 38615 const children = listItem.getChildren(); 38616 for (const child of children) { 38617 if ($isDecoratorNode2(child)) return false; 38618 if ($isLineBreakNode2(child)) continue; 38619 if ($isTextNode2(child)) { 38620 if (child.getTextContent().trim() !== "") return false; 38621 } else if ($isElementNode2(child)) { 38622 if (child.getTextContent().trim() !== "") return false; 38623 } 38624 } 38625 return true; 38626 } 38627 function $textBeforeOffset(targetNode, offset3) { 38628 const parts = []; 38629 let done = false; 38630 function visit(node) { 38631 if (done) return; 38632 if (node === targetNode) { 38633 parts.push(node.getTextContent().slice(0, offset3)); 38634 done = true; 38635 return; 38636 } 38637 if ($isElementNode2(node)) { 38638 const children = node.getChildren(); 38639 for (let i2 = 0; i2 < children.length; i2++) { 38640 visit(children[i2]); 38641 if (done) return; 38642 const child = children[i2]; 38643 if ($isElementNode2(child) && !child.isInline() && i2 < children.length - 1) { 38644 parts.push("\n\n"); 38645 } 38646 } 38647 } else { 38648 parts.push(node.getTextContent()); 38649 } 38650 } 38651 visit($getRoot2()); 38652 return parts.join(""); 38653 } 38654 function isAttachmentSpacerTextNode(node, previousNode, index, childCount) { 38655 return $isTextNode2(node) && node.getTextContent() === " " && index === childCount - 1 && previousNode instanceof CustomActionTextAttachmentNode; 38656 } 38657 function $splitSelectedParagraphsAtInnerLineBreaks(selection) { 38658 const topLevelElements = /* @__PURE__ */ new Set(); 38659 for (const node of selection.getNodes()) { 38660 const topLevel = node.getTopLevelElement(); 38661 if (topLevel) topLevelElements.add(topLevel); 38662 } 38663 for (const element of topLevelElements) { 38664 if (!$isParagraphNode2(element)) continue; 38665 const children = element.getChildren(); 38666 if (!children.some($isLineBreakNode2)) continue; 38667 const groups = [[]]; 38668 for (const child of children) { 38669 if ($isLineBreakNode2(child)) { 38670 groups.push([]); 38671 child.remove(); 38672 } else { 38673 groups[groups.length - 1].push(child); 38674 } 38675 } 38676 for (const group of groups) { 38677 if (group.length === 0) continue; 38678 const paragraph = $createParagraphNode2(); 38679 group.forEach((child) => paragraph.append(child)); 38680 element.insertBefore(paragraph); 38681 } 38682 if (groups.some((group) => group.length > 0)) element.remove(); 38683 } 38684 } 38685 function $expandSelectionToLineBreaksAndSplitAtEdges(selection, fallbackAncestor = (node) => node.getTopLevelElement()) { 38686 $ensureForwardRangeSelection2(selection); 38687 $shrinkSelectionPastBlockEdges(selection); 38688 const focusCaret = $caretFromPoint2(selection.focus, "next"); 38689 const anchorCaret = $caretFromPoint2(selection.anchor, "previous"); 38690 const skipInwardEdge = selection.isCollapsed(); 38691 const focusBrCaret = $getCaretAtLineBreakBoundary(focusCaret, skipInwardEdge); 38692 let anchorBrCaret = $getCaretAtLineBreakBoundary(anchorCaret, skipInwardEdge); 38693 if (focusBrCaret?.origin.is(anchorBrCaret?.origin)) { 38694 anchorBrCaret = null; 38695 } 38696 const focusOuter = focusBrCaret && $splitAroundLineBreak(focusBrCaret); 38697 const anchorOuter = anchorBrCaret && $splitAroundLineBreak(anchorBrCaret); 38698 const innerStart = anchorOuter?.getNextSibling() ?? fallbackAncestor(selection.anchor.getNode()); 38699 const innerEnd = focusOuter?.getPreviousSibling() ?? fallbackAncestor(selection.focus.getNode()); 38700 if (!innerStart || !innerEnd) return; 38701 $setSelectionFromCaretRange2($getCaretRange2( 38702 $normalizeCaret2($getChildCaret2(innerStart, "next")), 38703 $getCaretInDirection2( 38704 $normalizeCaret2($getChildCaret2(innerEnd, "previous")), 38705 "next" 38706 ) 38707 )); 38708 } 38709 function $shrinkSelectionPastBlockEdges(selection) { 38710 if (selection.isCollapsed()) return; 38711 const anchorBlock = selection.anchor.getNode().getTopLevelElement(); 38712 const focusBlock = selection.focus.getNode().getTopLevelElement(); 38713 if (!anchorBlock || !focusBlock || anchorBlock.is(focusBlock)) return; 38714 if ($isAtBlockEnd(selection.anchor, anchorBlock)) { 38715 const nextBlock = $nearestElementSibling(anchorBlock, "next"); 38716 if (nextBlock) selection.anchor.set(nextBlock.getKey(), 0, "element"); 38717 } 38718 if ($isAtBlockStart(selection.focus, focusBlock)) { 38719 const previousBlock = $nearestElementSibling(focusBlock, "previous"); 38720 if (previousBlock) selection.focus.set(previousBlock.getKey(), previousBlock.getChildrenSize(), "element"); 38721 } 38722 $ensureForwardRangeSelection2(selection); 38723 } 38724 function $nearestElementSibling(block, direction) { 38725 let sibling = block; 38726 do { 38727 sibling = direction === "next" ? sibling.getNextSibling() : sibling.getPreviousSibling(); 38728 } while (sibling && !$isElementNode2(sibling)); 38729 return sibling; 38730 } 38731 function $isAtBlockEnd(point, block) { 38732 return $isAtBlockBoundary($caretFromPoint2(point, "next"), block); 38733 } 38734 function $isAtBlockStart(point, block) { 38735 return $isAtBlockBoundary($caretFromPoint2(point, "previous"), block); 38736 } 38737 function $isAtBlockBoundary(caret, block) { 38738 if ($isTextPointCaret2(caret) && $isExtendableTextPointCaret2(caret)) return false; 38739 let cursor = $normalizeCaret2(caret); 38740 while (cursor && block.isParentOf(cursor.origin)) { 38741 if (cursor.getNodeAtCaret()) return false; 38742 cursor = cursor.getParentCaret(); 38743 } 38744 return true; 38745 } 38746 function $getCaretAtLineBreakBoundary(caret, skipInwardEdge = false) { 38747 const paragraph = caret.origin.getTopLevelElement(); 38748 if (!paragraph || !$isParagraphNode2(paragraph)) return null; 38749 const lineBreak = (skipInwardEdge ? null : $inwardEdgeLineBreak(caret, paragraph)) ?? $outwardLineBreak(caret, paragraph); 38750 return lineBreak ? $getSiblingCaret2(lineBreak, caret.direction) : null; 38751 } 38752 function $inwardEdgeLineBreak(caret, paragraph) { 38753 let candidateCaret; 38754 if ($isChildCaret2(caret) && caret.origin.is(paragraph) || $isTextPointCaret2(caret) && $isExtendableTextPointCaret2(caret.getFlipped())) { 38755 candidateCaret = null; 38756 } else if ($isSiblingCaret2(caret) && caret.getParentAtCaret().is(paragraph)) { 38757 candidateCaret = caret; 38758 } else { 38759 const childCaret = $paragraphChildCaretAtInwardEdge(caret, paragraph); 38760 candidateCaret = childCaret ? $rewindSiblingCaret2(childCaret) : null; 38761 } 38762 if (candidateCaret && $isLineBreakNode2(candidateCaret.origin)) { 38763 return $candidateUnlessShadowed(candidateCaret); 38764 } else { 38765 return null; 38766 } 38767 } 38768 function $candidateUnlessShadowed(candidateCaret) { 38769 const outward = candidateCaret.getNodeAtCaret(); 38770 return $isLineBreakNode2(outward) ? null : candidateCaret.origin; 38771 } 38772 function $outwardLineBreak(caret, paragraph) { 38773 const startCaret = $outwardWalkStartCaret(caret, paragraph); 38774 if (!startCaret) return null; 38775 for (const { origin } of startCaret) { 38776 if (!origin.getParent().is(paragraph)) break; 38777 if ($isLineBreakNode2(origin)) return origin; 38778 } 38779 return null; 38780 } 38781 function $outwardWalkStartCaret(caret, paragraph) { 38782 if (caret.getParentAtCaret().is(paragraph)) { 38783 return caret; 38784 } else { 38785 return $paragraphChildCaretContaining(caret, paragraph); 38786 } 38787 } 38788 function $paragraphChildCaretContaining(caret, paragraph) { 38789 let cursor = caret.getSiblingCaret(); 38790 while (cursor && !cursor.origin.getParent()?.is(paragraph)) { 38791 cursor = cursor.getParentCaret(); 38792 } 38793 return cursor?.origin.getParent()?.is(paragraph) ? cursor : null; 38794 } 38795 function $paragraphChildCaretAtInwardEdge(caret, paragraph) { 38796 let cursor = caret.getSiblingCaret(); 38797 while (cursor && !cursor.origin.getParent()?.is(paragraph)) { 38798 if (cursor.getNodeAtCaret()) return null; 38799 cursor = cursor.getParentCaret(); 38800 } 38801 return cursor?.origin.getParent()?.is(paragraph) ? cursor : null; 38802 } 38803 function $splitAroundLineBreak(lineBreakCaret) { 38804 let outer = null; 38805 if (lineBreakCaret.getNodeAtCaret() === null) { 38806 lineBreakCaret.origin.remove(); 38807 } else { 38808 const lineBreak = lineBreakCaret.origin; 38809 const splitCaret = $getCaretInDirection2($rewindSiblingCaret2(lineBreakCaret), "next"); 38810 $splitAtPointCaretNext2(splitCaret); 38811 outer = lineBreak.getTopLevelElement(); 38812 lineBreak.remove(); 38813 } 38814 return outer; 38815 } 38816 function $isPointOnBlockContainer(point) { 38817 if (point.type !== "element") return false; 38818 const firstChild = point.getNode().getFirstChild(); 38819 return ($isElementNode2(firstChild) || $isDecoratorNode2(firstChild)) && !firstChild.isInline(); 38820 } 38821 function $hasPointOnBlockContainer(selection) { 38822 return $isRangeSelection2(selection) && [selection.anchor, selection.focus].some($isPointOnBlockContainer); 38823 } 38824 function $normalizeBlockContainerSelection(selection = $getSelection2()) { 38825 if (!$hasPointOnBlockContainer(selection)) return false; 38826 $normalizeSelection__EXPERIMENTAL(selection); 38827 return true; 38828 } 38829 function $consecutiveSiblingGroups(blocks) { 38830 const ordered = [...blocks].sort((a2, b3) => a2.getIndexWithinParent() - b3.getIndexWithinParent()); 38831 const groups = []; 38832 for (const block of ordered) { 38833 const lastGroup = groups.at(-1); 38834 const previous = lastGroup?.at(-1); 38835 if (previous && previous.getParent().is(block.getParent()) && previous.getNextSibling()?.is(block)) { 38836 lastGroup.push(block); 38837 } else { 38838 groups.push([block]); 38839 } 38840 } 38841 return groups; 38842 } 38843 var REWRITE_HISTORY_COMMAND = createCommand2("REWRITE_HISTORY_COMMAND"); 38844 var RewritableHistoryExtension = class extends LexxyExtension { 38845 #historyState = null; 38846 get lexicalExtension() { 38847 return defineExtension2({ 38848 name: "lexxy/rewritable-history", 38849 dependencies: [HistoryExtension2], 38850 register: (editor, _config, state) => { 38851 const historyOutput = state.getDependency(HistoryExtension2).output; 38852 this.#historyState = historyOutput.historyState.value; 38853 return editor.registerCommand( 38854 REWRITE_HISTORY_COMMAND, 38855 (rewrites) => this.#rewriteHistory(rewrites), 38856 COMMAND_PRIORITY_EDITOR2 38857 ); 38858 } 38859 }); 38860 } 38861 get historyState() { 38862 return this.#historyState; 38863 } 38864 get #allHistoryEntries() { 38865 const entries2 = Array.from(this.#historyState.undoStack); 38866 if (this.#historyState.current) entries2.push(this.#historyState.current); 38867 return entries2.concat(this.#historyState.redoStack); 38868 } 38869 #rewriteHistory(rewrites) { 38870 this.#applyRewritesImmediatelyToCurrentState(rewrites); 38871 this.#applyRewritesToHistory(rewrites); 38872 return true; 38873 } 38874 #applyRewritesImmediatelyToCurrentState(rewrites) { 38875 $getEditor2().update(() => { 38876 for (const [nodeKey, { patch: patch2, replace }] of Object.entries(rewrites)) { 38877 const node = $getNodeByKey2(nodeKey); 38878 if (!node) continue; 38879 if (patch2) Object.assign(node.getWritable(), patch2); 38880 if (replace) node.replace(replace); 38881 } 38882 }, { discrete: true, tag: this.#getBackgroundUpdateTags() }); 38883 } 38884 #applyRewritesToHistory(rewrites) { 38885 const nodeKeys = Object.keys(rewrites); 38886 for (const entry of this.#allHistoryEntries) { 38887 if (!this.#entryHasSomeKeys(entry, nodeKeys)) continue; 38888 const editorState = entry.editorState = safeCloneEditorState(entry.editorState); 38889 for (const [nodeKey, { patch: patch2, replace }] of Object.entries(rewrites)) { 38890 const node = editorState._nodeMap.get(nodeKey); 38891 if (!node) continue; 38892 if (patch2) { 38893 this.#patchNodeInEditorState(editorState, node, patch2); 38894 } else if (replace) { 38895 this.#replaceNodeInEditorState(editorState, node, replace); 38896 } 38897 } 38898 } 38899 } 38900 #entryHasSomeKeys(entry, nodeKeys) { 38901 return nodeKeys.some((key) => entry.editorState._nodeMap.has(key)); 38902 } 38903 #getBackgroundUpdateTags() { 38904 const tags = [HISTORY_MERGE_TAG2, SKIP_SCROLL_INTO_VIEW_TAG2]; 38905 if (!isEditorFocused(this.editorElement.editor)) { 38906 tags.push(SKIP_DOM_SELECTION_TAG2); 38907 } 38908 return tags; 38909 } 38910 #patchNodeInEditorState(editorState, node, patch2) { 38911 editorState._nodeMap.set(node.__key, $cloneNodeWithPatch(node, patch2)); 38912 } 38913 #replaceNodeInEditorState(editorState, node, replaceWith) { 38914 editorState._nodeMap.set(node.__key, $cloneNodeAdoptingKeys(replaceWith, node)); 38915 } 38916 }; 38917 function $cloneNodeWithPatch(node, patch2) { 38918 const clone2 = $cloneWithProperties2(node); 38919 Object.assign(clone2, patch2); 38920 return clone2; 38921 } 38922 function $cloneNodeAdoptingKeys(node, previousNode) { 38923 const clone2 = $cloneWithProperties2(node); 38924 clone2.__key = previousNode.__key; 38925 clone2.__parent = previousNode.__parent; 38926 clone2.__prev = previousNode.__prev; 38927 clone2.__next = previousNode.__next; 38928 return clone2; 38929 } 38930 function safeCloneEditorState(editorState) { 38931 const clone2 = editorState.clone(); 38932 clone2._nodeMap = new Map(editorState._nodeMap); 38933 return clone2; 38934 } 38935 var INITIAL_PREVIEW_POLL_DELAY_MS = 3e3; 38936 var MAX_PREVIEW_POLL_DELAY_MS = 12e4; 38937 var MAX_PREVIEW_POLL_ATTEMPTS = 20; 38938 var ActionTextAttachmentNode = class _ActionTextAttachmentNode extends DecoratorNode2 { 38939 static getType() { 38940 return "action_text_attachment"; 38941 } 38942 static clone(node) { 38943 return new _ActionTextAttachmentNode({ ...node }, node.__key); 38944 } 38945 static importJSON(serializedNode) { 38946 return new _ActionTextAttachmentNode({ ...serializedNode }); 38947 } 38948 static importDOM() { 38949 return { 38950 [this.TAG_NAME]: () => { 38951 return { 38952 conversion: (attachment) => ({ 38953 node: new _ActionTextAttachmentNode({ 38954 sgid: attachment.getAttribute("sgid"), 38955 src: attachment.getAttribute("url"), 38956 previewable: attachment.getAttribute("previewable"), 38957 altText: attachment.getAttribute("alt"), 38958 caption: attachment.getAttribute("caption"), 38959 contentType: attachment.getAttribute("content-type"), 38960 fileName: attachment.getAttribute("filename"), 38961 fileSize: attachment.getAttribute("filesize"), 38962 width: attachment.getAttribute("width"), 38963 height: attachment.getAttribute("height"), 38964 content: attachment.getAttribute("content") || attachment.getAttribute("data-lexxy-image"), 38965 blobSrc: attachment.getAttribute("data-blob-url") 38966 }) 38967 }), 38968 priority: 1 38969 }; 38970 }, 38971 "img": () => { 38972 return { 38973 conversion: (img) => { 38974 const fileName = extractFileName(img.getAttribute("src") ?? ""); 38975 return { 38976 node: new _ActionTextAttachmentNode({ 38977 src: img.getAttribute("src"), 38978 fileName, 38979 caption: img.getAttribute("alt") || "", 38980 contentType: "image/*", 38981 width: img.getAttribute("width"), 38982 height: img.getAttribute("height") 38983 }) 38984 }; 38985 }, 38986 priority: 1 38987 }; 38988 }, 38989 "video": () => { 38990 return { 38991 conversion: (video) => { 38992 const videoSource = video.getAttribute("src") || video.querySelector("source")?.src; 38993 const fileName = videoSource?.split("/")?.pop(); 38994 const contentType = video.querySelector("source")?.getAttribute("content-type") || "video/*"; 38995 return { 38996 node: new _ActionTextAttachmentNode({ 38997 src: videoSource, 38998 fileName, 38999 contentType 39000 }) 39001 }; 39002 }, 39003 priority: 1 39004 }; 39005 }, 39006 "audio": () => { 39007 return { 39008 conversion: (audio) => { 39009 const audioSource = audio.getAttribute("src") || audio.querySelector("source")?.src; 39010 const fileName = audioSource?.split("/")?.pop(); 39011 const contentType = audio.querySelector("source")?.getAttribute("content-type") || "audio/*"; 39012 return { 39013 node: new _ActionTextAttachmentNode({ 39014 src: audioSource, 39015 fileName, 39016 contentType 39017 }) 39018 }; 39019 }, 39020 priority: 1 39021 }; 39022 } 39023 }; 39024 } 39025 static get TAG_NAME() { 39026 return Lexxy.global.get("attachmentTagName"); 39027 } 39028 constructor({ tagName, sgid, src, previewSrc, previewable, previewStatusUrl, pendingPreview, altText, caption, contentType, fileName, fileSize, width, height, content, blobSrc, uploadError }, key) { 39029 super(key); 39030 this.tagName = tagName || _ActionTextAttachmentNode.TAG_NAME; 39031 this.sgid = sgid; 39032 this.src = src; 39033 this.previewSrc = previewSrc; 39034 this.previewable = parseBoolean(previewable); 39035 this.previewStatusUrl = previewStatusUrl; 39036 this.pendingPreview = pendingPreview; 39037 this.altText = altText || ""; 39038 this.caption = sanitizeCaptionHtml(caption || ""); 39039 this.contentType = contentType || ""; 39040 this.fileName = fileName || ""; 39041 this.fileSize = fileSize; 39042 this.width = width; 39043 this.height = height; 39044 this.content = content; 39045 this.blobSrc = blobSrc; 39046 this.uploadError = uploadError; 39047 this.editor = $getEditor2(); 39048 } 39049 createDOM() { 39050 if (this.uploadError) return this.createDOMForError(); 39051 if (this.pendingPreview && !this.isPdf) return this.#createDOMForPendingPreview(); 39052 const figure = this.createAttachmentFigure(this.isAudio || this.isPdf || this.isPreviewableAttachment); 39053 if (this.isPdf) { 39054 figure.appendChild(this.#createDOMForPdf()); 39055 figure.appendChild(this.#createEditableCaption()); 39056 } else if (this.isPreviewableAttachment) { 39057 figure.appendChild(this.#createDOMForImage()); 39058 figure.appendChild(this.#createEditableCaption()); 39059 } else if (this.isAudio) { 39060 figure.appendChild(this.#createDOMForAudio()); 39061 figure.appendChild(this.#createEditableCaption()); 39062 } else if (this.isVideo) { 39063 figure.appendChild(this.#createDOMForFile()); 39064 figure.appendChild(this.#createEditableCaption()); 39065 } else { 39066 figure.appendChild(this.#createDOMForFile()); 39067 figure.appendChild(this.#createDOMForNotImage()); 39068 } 39069 return figure; 39070 } 39071 updateDOM(prevNode, dom) { 39072 if (this.uploadError !== prevNode.uploadError) return true; 39073 if (this.isPreviewableImage) syncLexxyImageLayoutClasses(dom, this.content); 39074 const image = dom.querySelector("img"); 39075 if (image && image.alt !== this.altText) image.alt = this.altText; 39076 const caption = dom.querySelector("figcaption [data-lexxy-caption-editor]"); 39077 if (caption && !caption.contains(document.activeElement) && sanitizeCaptionHtml(caption.innerHTML) !== this.caption) { 39078 caption.innerHTML = this.caption; 39079 } 39080 return false; 39081 } 39082 getTextContent() { 39083 return `[${captionTextContent(this.caption) || this.fileName}] 39084 39085`; 39086 } 39087 isInline() { 39088 return this.isAttached() && !this.getParent().is($getNearestRootOrShadowRoot2(this)); 39089 } 39090 exportDOM() { 39091 const attachment = createElement(this.tagName, { 39092 sgid: this.sgid, 39093 previewable: this.previewable || null, 39094 url: this.src, 39095 alt: this.altText, 39096 caption: this.caption, 39097 "content-type": this.contentType, 39098 filename: this.fileName, 39099 filesize: this.fileSize, 39100 width: this.width, 39101 height: this.height, 39102 presentation: "gallery" 39103 }); 39104 if (this.content) { 39105 if (isLexxyImageLayoutString(this.content)) { 39106 attachment.setAttribute("data-lexxy-image", this.content); 39107 } else { 39108 attachment.setAttribute("content", this.content); 39109 } 39110 } 39111 if (this.isPdf && this.blobSrc) { 39112 attachment.setAttribute("data-blob-url", this.blobSrc); 39113 } 39114 return { element: attachment }; 39115 } 39116 exportJSON() { 39117 return { 39118 type: "action_text_attachment", 39119 version: 1, 39120 tagName: this.tagName, 39121 sgid: this.sgid, 39122 src: this.src, 39123 previewable: this.previewable, 39124 previewStatusUrl: this.previewStatusUrl, 39125 pendingPreview: this.pendingPreview, 39126 altText: this.altText, 39127 caption: this.caption, 39128 contentType: this.contentType, 39129 fileName: this.fileName, 39130 fileSize: this.fileSize, 39131 width: this.width, 39132 height: this.height, 39133 content: this.content, 39134 blobSrc: this.blobSrc 39135 }; 39136 } 39137 decorate() { 39138 return null; 39139 } 39140 createDOMForError() { 39141 const figure = this.createAttachmentFigure(); 39142 figure.classList.add("attachment--error"); 39143 figure.appendChild(createElement("div", { innerText: `Error uploading ${this.fileName || "file"}` })); 39144 return figure; 39145 } 39146 createAttachmentFigure(previewable = this.isPreviewableAttachment) { 39147 const figure = createAttachmentFigure(this.contentType, previewable, this.fileName); 39148 figure.draggable = true; 39149 figure.dataset.lexicalNodeKey = this.__key; 39150 if (this.isPreviewableImage) applyLexxyImageLayout(figure, this.content); 39151 if (this.isPreviewableImage) { 39152 figure.appendChild(this.#createImageAltButton()); 39153 } 39154 const deleteButton = createElement("lexxy-node-delete-button"); 39155 figure.appendChild(deleteButton); 39156 return figure; 39157 } 39158 get isPreviewableAttachment() { 39159 return this.isPreviewableImage || this.previewable; 39160 } 39161 get isPreviewableImage() { 39162 return isPreviewableImage(this.contentType, this.fileName); 39163 } 39164 get isVideo() { 39165 return this.contentType.startsWith("video/"); 39166 } 39167 get isAudio() { 39168 return this.contentType.startsWith("audio/"); 39169 } 39170 get isPdf() { 39171 return this.contentType === "application/pdf" || this.fileName.toLowerCase().endsWith(".pdf"); 39172 } 39173 get #pdfSrc() { 39174 return this.blobSrc || this.src; 39175 } 39176 #createDOMForPdf(src = this.#pdfSrc) { 39177 const iframe = createElement("iframe", { 39178 src, 39179 title: this.fileName || "PDF", 39180 loading: "lazy" 39181 }); 39182 const container = createElement("div", { className: "attachment__container attachment__pdf-frame" }); 39183 container.appendChild(iframe); 39184 return container; 39185 } 39186 #createDOMForAudio(src = this.src) { 39187 const audio = createElement("audio", { src, controls: true, preload: "metadata" }); 39188 const container = createElement("div", { className: "attachment__container" }); 39189 container.appendChild(audio); 39190 return container; 39191 } 39192 #createDOMForPendingPreview() { 39193 const figure = this.createAttachmentFigure(false); 39194 figure.appendChild(this.#createDOMForFile()); 39195 figure.appendChild(this.#createDOMForNotImage()); 39196 this.#pollForPreview(figure); 39197 return figure; 39198 } 39199 patchAndRewriteHistory(patch2) { 39200 this.editor.dispatchCommand(REWRITE_HISTORY_COMMAND, { 39201 [this.getKey()]: { patch: patch2 } 39202 }); 39203 } 39204 replaceAndRewriteHistory(node) { 39205 this.editor.dispatchCommand(REWRITE_HISTORY_COMMAND, { 39206 [this.getKey()]: { replace: node } 39207 }); 39208 } 39209 #createDOMForImage(options = {}) { 39210 const initialSrc = this.previewSrc || this.src; 39211 const img = createElement("img", { src: initialSrc, draggable: false, alt: this.altText, ...this.#imageDimensions, ...options }); 39212 if (this.previewable && !this.isPreviewableImage) { 39213 img.onerror = () => this.#swapPreviewToFileDOM(img); 39214 } 39215 if (this.previewSrc) { 39216 this.#preloadAndSwapSrc(img); 39217 } 39218 const container = createElement("div", { className: "attachment__container" }); 39219 container.appendChild(img); 39220 return container; 39221 } 39222 #createImageAltButton() { 39223 const control = createElement("lexxy-image-alt-button", { className: "lexxy-floating-controls" }); 39224 const group = createElement("div", { className: "lexxy-floating-controls__group" }); 39225 const button = createElement("button", { 39226 className: "lexxy-image-alt", 39227 type: "button", 39228 ariaLabel: "Edit alt text", 39229 title: "Edit alt text", 39230 tabIndex: -1 39231 }); 39232 button.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"><g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"><path d="M9 16.25C13.004 16.25 16.25 13.004 16.25 9C16.25 4.996 13.004 1.75 9 1.75C4.996 1.75 1.75 4.996 1.75 9C1.75 13.004 4.996 16.25 9 16.25Z"></path><path d="M9 12.75V9.25C9 8.9739 8.7761 8.75 8.5 8.75H7.75"></path><path d="M9 6.75C8.448 6.75 8 6.301 8 5.75C8 5.199 8.448 4.75 9 4.75C9.552 4.75 10 5.199 10 5.75C10 6.301 9.552 6.75 9 6.75Z" fill="currentColor" data-stroke="none" stroke="none"></path></g></svg>`; 39233 button.addEventListener("mousedown", (event) => event.preventDefault()); 39234 button.addEventListener("click", (event) => this.#handleImageAltButtonClicked(event)); 39235 group.appendChild(button); 39236 control.appendChild(group); 39237 return control; 39238 } 39239 #handleImageAltButtonClicked(event) { 39240 event.preventDefault(); 39241 event.stopPropagation(); 39242 const altText = window.prompt("Image alt text", this.altText); 39243 if (altText === null) return; 39244 this.editor.update(() => { 39245 this.getWritable().altText = altText.trim(); 39246 }); 39247 } 39248 #preloadAndSwapSrc(img) { 39249 const previewSrc = this.previewSrc; 39250 const serverImage = new Image(); 39251 serverImage.onload = () => this.#handleImageLoaded(img, previewSrc); 39252 serverImage.onerror = () => this.#handleImageLoadError(previewSrc); 39253 serverImage.src = this.src; 39254 } 39255 #handleImageLoaded(img, previewSrc) { 39256 img.src = this.src; 39257 this.patchAndRewriteHistory({ previewSrc: null }); 39258 this.#revokePreviewSrc(previewSrc); 39259 } 39260 #handleImageLoadError(previewSrc) { 39261 this.patchAndRewriteHistory({ 39262 previewSrc: null, 39263 uploadError: true 39264 }); 39265 this.#revokePreviewSrc(previewSrc); 39266 } 39267 #revokePreviewSrc(previewSrc) { 39268 if (previewSrc?.startsWith("blob:")) URL.revokeObjectURL(previewSrc); 39269 } 39270 #swapPreviewToFileDOM(img) { 39271 const figure = img.closest("figure.attachment"); 39272 if (!figure) return; 39273 this.#swapFigureContent(figure, "attachment--preview", "attachment--file", () => { 39274 figure.appendChild(this.#createDOMForFile()); 39275 figure.appendChild(this.#createDOMForNotImage()); 39276 }); 39277 } 39278 // While the file-icon is shown, watch for the preview to become ready. 39279 // With a status URL, poll it (2xx = processing, anything else = ready). 39280 // Without one, preload the preview URL once and swap on load. 39281 #pollForPreview(figure) { 39282 if (this.previewStatusUrl) { 39283 this.#waitForPreviewByPollingStatus(figure); 39284 } else { 39285 this.#waitForPreviewByPreloadingImage(figure); 39286 } 39287 } 39288 #waitForPreviewByPollingStatus(figure) { 39289 let attempt = 0; 39290 const tryStatus = async () => { 39291 if (!this.editor.read(() => this.isAttached())) return; 39292 try { 39293 const response = await fetch(this.previewStatusUrl, { credentials: "include", redirect: "manual" }); 39294 if (!this.editor.read(() => this.isAttached())) return; 39295 if (response.ok) { 39296 retry(); 39297 } else { 39298 this.#swapToPreviewDOM(figure, this.src); 39299 } 39300 } catch { 39301 retry(); 39302 } 39303 }; 39304 const retry = () => { 39305 attempt++; 39306 if (attempt < MAX_PREVIEW_POLL_ATTEMPTS && this.editor.read(() => this.isAttached())) { 39307 const delay2 = Math.min(2e3 * Math.pow(1.5, attempt), MAX_PREVIEW_POLL_DELAY_MS); 39308 setTimeout(tryStatus, delay2); 39309 } 39310 }; 39311 setTimeout(tryStatus, INITIAL_PREVIEW_POLL_DELAY_MS); 39312 } 39313 #waitForPreviewByPreloadingImage(figure) { 39314 const img = new Image(); 39315 img.onload = () => { 39316 if (!this.editor.read(() => this.isAttached())) return; 39317 this.#swapToPreviewDOM(figure, this.src); 39318 }; 39319 img.onerror = () => { 39320 if (!this.editor.read(() => this.isAttached())) return; 39321 this.patchAndRewriteHistory({ pendingPreview: false }); 39322 }; 39323 img.src = this.src; 39324 } 39325 #swapToPreviewDOM(figure, previewSrc) { 39326 this.#swapFigureContent(figure, "attachment--file", "attachment--preview", () => { 39327 const img = createElement("img", { src: previewSrc, draggable: false, alt: this.altText }); 39328 img.onerror = () => this.#swapPreviewToFileDOM(img); 39329 const container = createElement("div", { className: "attachment__container" }); 39330 container.appendChild(img); 39331 figure.appendChild(container); 39332 figure.appendChild(this.#createEditableCaption()); 39333 }); 39334 this.patchAndRewriteHistory({ pendingPreview: false }); 39335 } 39336 #swapFigureContent(figure, fromClass, toClass, renderContent) { 39337 figure.className = figure.className.replace(fromClass, toClass); 39338 for (const child of [...figure.querySelectorAll(".attachment__container, .attachment__icon, figcaption")]) { 39339 child.remove(); 39340 } 39341 renderContent(); 39342 } 39343 get #imageDimensions() { 39344 if (this.width && this.height) { 39345 return { width: this.width, height: this.height }; 39346 } else { 39347 return {}; 39348 } 39349 } 39350 #createDOMForFile() { 39351 const extension = this.fileName ? this.fileName.split(".").pop().toLowerCase() : "unknown"; 39352 return createElement("span", { className: "attachment__icon", textContent: `${extension}` }); 39353 } 39354 #createDOMForNotImage() { 39355 const figcaption = createElement("figcaption", { className: "attachment__caption" }); 39356 const nameTag = createElement("strong", { className: "attachment__name" }); 39357 if (this.caption) { 39358 nameTag.innerHTML = this.caption; 39359 } else { 39360 nameTag.textContent = this.fileName; 39361 } 39362 figcaption.appendChild(nameTag); 39363 if (this.fileSize) { 39364 const sizeSpan = createElement("span", { className: "attachment__size", textContent: bytesToHumanSize(this.fileSize) }); 39365 figcaption.appendChild(sizeSpan); 39366 } 39367 return figcaption; 39368 } 39369 #createEditableCaption() { 39370 const caption = createElement("figcaption", { className: "attachment__caption" }); 39371 const input = createElement("div", { 39372 className: "attachment__caption-editor", 39373 contentEditable: "true", 39374 role: "textbox", 39375 ariaLabel: "Caption", 39376 spellcheck: true, 39377 dataset: { 39378 lexxyCaptionEditor: "true", 39379 placeholder: this.fileName 39380 } 39381 }); 39382 input.innerHTML = this.caption; 39383 syncCaptionEditorEmptyState(input); 39384 input.addEventListener("focusin", () => { 39385 input.dataset.placeholder = "Add caption..."; 39386 this.#ensureCaptionToolbar(caption, input); 39387 }); 39388 input.addEventListener("blur", (event) => this.#handleCaptionInputBlurred(event)); 39389 input.addEventListener("input", (event) => this.#handleCaptionInputChanged(event)); 39390 input.addEventListener("keydown", (event) => this.#handleCaptionInputKeydown(event)); 39391 input.addEventListener("copy", (event) => event.stopPropagation()); 39392 input.addEventListener("cut", (event) => event.stopPropagation()); 39393 input.addEventListener("paste", (event) => this.#handleCaptionInputPaste(event)); 39394 caption.appendChild(input); 39395 return caption; 39396 } 39397 #ensureCaptionToolbar(caption, input) { 39398 if (!caption.querySelector(".lexxy-caption-tools")) { 39399 caption.insertBefore(this.#createCaptionToolbar(input), input); 39400 } 39401 } 39402 #createCaptionToolbar(input) { 39403 const toolbar = createElement("div", { 39404 className: "lexxy-floating-controls lexxy-caption-tools", 39405 role: "toolbar", 39406 ariaLabel: "Caption formatting" 39407 }); 39408 toolbar.innerHTML = ` 39409 <div class="lexxy-floating-controls__group lexxy-caption-tools__bar"> 39410 ${this.#captionToolbarButton("bold", "Bold", ToolbarIcons.bold)} 39411 ${this.#captionToolbarButton("italic", "Italic", ToolbarIcons.italic)} 39412 ${this.#captionToolbarButton("underline", "Underline", ToolbarIcons.underline)} 39413 ${this.#captionToolbarButton("link", "Link", ToolbarIcons.link)} 39414 </div> 39415 `; 39416 toolbar.addEventListener("mousedown", (event) => event.preventDefault()); 39417 toolbar.addEventListener("click", (event) => this.#handleCaptionToolbarClick(event, input)); 39418 return toolbar; 39419 } 39420 #captionToolbarButton(command, label, icon) { 39421 const toolbarIcon = CAPTION_TOOLBAR_ICONS[command] || icon; 39422 return ` 39423 <button type="button" data-caption-command="${command}" data-lexxy-icon="${command}" title="${label}" aria-label="${label}"> 39424 ${toolbarIcon} 39425 <span>${label}</span> 39426 </button> 39427 `; 39428 } 39429 #handleCaptionToolbarClick(event, input) { 39430 const button = event.target.closest("[data-caption-command]"); 39431 if (!button) return; 39432 event.preventDefault(); 39433 input.focus(); 39434 if (button.dataset.captionCommand === "link") { 39435 this.#toggleCaptionLink(input); 39436 } else { 39437 document.execCommand(CAPTION_EXEC_COMMANDS[button.dataset.captionCommand], false); 39438 } 39439 this.#updateCaptionValueFromInput(input); 39440 } 39441 #toggleCaptionLink(input) { 39442 const selection = document.getSelection(); 39443 if (!selection || !selection.rangeCount || !input.contains(selection.anchorNode)) return; 39444 const range2 = selection.getRangeAt(0).cloneRange(); 39445 const existingLink = selection.anchorNode?.parentElement?.closest?.("a"); 39446 const initialValue = existingLink?.getAttribute("href") || selection.toString(); 39447 const url = window.prompt("Enter a URL", initialValue || ""); 39448 if (url === null) return; 39449 selection.removeAllRanges(); 39450 selection.addRange(range2); 39451 if (url.trim() === "") { 39452 document.execCommand("unlink", false); 39453 return; 39454 } 39455 const href = normalizedCaptionUrl(url); 39456 if (!href) return; 39457 if (selection.isCollapsed) { 39458 document.execCommand("insertHTML", false, `<a href="${escapeCaptionText(href)}">${escapeCaptionText(href)}</a>`); 39459 } else { 39460 document.execCommand("createLink", false, href); 39461 const link = selection.anchorNode?.parentElement?.closest?.("a"); 39462 if (link) link.setAttribute("href", href); 39463 } 39464 } 39465 #handleCaptionInputBlurred(event) { 39466 this.#updateCaptionValueFromInput(event.target); 39467 } 39468 #handleCaptionInputChanged(event) { 39469 this.editor.update(() => { 39470 this.getWritable().caption = normalizeCaptionHtml(event.target.innerHTML); 39471 }); 39472 } 39473 #updateCaptionValueFromInput(input) { 39474 input.dataset.placeholder = this.fileName; 39475 const caption = normalizeCaptionHtml(input.innerHTML); 39476 if (caption !== input.innerHTML) { 39477 input.innerHTML = caption; 39478 } 39479 this.editor.update(() => { 39480 this.getWritable().caption = caption; 39481 }); 39482 } 39483 #handleCaptionInputPaste(event) { 39484 event.preventDefault(); 39485 event.stopPropagation(); 39486 const html2 = event.clipboardData?.getData("text/html"); 39487 const text2 = event.clipboardData?.getData("text/plain") || ""; 39488 const pastedHtml = sanitizeCaptionHtml(html2) || escapeCaptionText(text2); 39489 document.execCommand("insertHTML", false, pastedHtml); 39490 this.#updateCaptionValueFromInput(event.target); 39491 } 39492 #handleCaptionInputKeydown(event) { 39493 if (event.key === "Enter") { 39494 event.preventDefault(); 39495 event.target.blur(); 39496 this.editor.update(() => { 39497 this.selectNext(0, 0); 39498 }, { 39499 tag: HISTORY_MERGE_TAG2 39500 }); 39501 } 39502 event.stopPropagation(); 39503 } 39504 }; 39505 function $isActionTextAttachmentNode(node) { 39506 return node instanceof ActionTextAttachmentNode; 39507 } 39508 function filterDisallowedAttachmentNodes(nodes, editorElement) { 39509 return nodes.filter((node) => !isDisallowedAttachment(node, editorElement)).map((node) => { 39510 $descendantsMatching2([node], (descendant) => isDisallowedAttachment(descendant, editorElement)).forEach((descendant) => descendant.remove()); 39511 return node; 39512 }); 39513 } 39514 function isDisallowedAttachment(node, editorElement) { 39515 const isAttachmentNode = node instanceof CustomActionTextAttachmentNode || node instanceof ActionTextAttachmentNode; 39516 return isAttachmentNode && !editorElement.permitsAttachmentContentType(node.contentType); 39517 } 39518 function $convertInlineImageDataURIs(nodes, editorElement) { 39519 const topLevel = nodes.map((node) => isInlineImageDataURIAttachment(node) ? $tryCreateUploadFromDataURI(node, editorElement) : node).filter((node) => node !== null); 39520 for (const node of topLevel) { 39521 for (const desc of $descendantsMatching2([node], isInlineImageDataURIAttachment)) { 39522 const upload = $tryCreateUploadFromDataURI(desc, editorElement); 39523 if (upload) { 39524 desc.replace(upload); 39525 } else { 39526 desc.remove(); 39527 } 39528 } 39529 } 39530 return topLevel; 39531 } 39532 function isInlineImageDataURIAttachment(node) { 39533 return node instanceof ActionTextAttachmentNode && /^data:image\/[^,]*;base64,/i.test(node.src ?? ""); 39534 } 39535 function $tryCreateUploadFromDataURI(node, editorElement) { 39536 const file = dataURIToFile(node.src); 39537 if (file && editorElement.acceptsFile(file)) { 39538 return editorElement.contents.$createUploadNode(file); 39539 } 39540 return null; 39541 } 39542 function dataURIToFile(dataURI) { 39543 try { 39544 const [header, data] = dataURI.split(","); 39545 const mimeType = header.match(/^data:(image\/[A-Za-z0-9][A-Za-z0-9!#$&\-^_.+]*)/)?.[1]; 39546 if (mimeType) { 39547 const bytes = Uint8Array.from(atob(data), (c2) => c2.charCodeAt(0)); 39548 const extension = mimeTypeToExtension(mimeType) ?? "png"; 39549 return new File([bytes], `pasted-image-${Date.now()}.${extension}`, { type: mimeType }); 39550 } else { 39551 return null; 39552 } 39553 } catch { 39554 return null; 39555 } 39556 } 39557 var HorizontalDividerNode = class _HorizontalDividerNode extends DecoratorNode2 { 39558 static getType() { 39559 return "horizontal_divider"; 39560 } 39561 static clone(node) { 39562 return new _HorizontalDividerNode(node.__key); 39563 } 39564 static importJSON(serializedNode) { 39565 return new _HorizontalDividerNode(); 39566 } 39567 static importDOM() { 39568 return { 39569 "hr": (hr) => { 39570 return { 39571 conversion: () => ({ 39572 node: new _HorizontalDividerNode() 39573 }), 39574 priority: 1 39575 }; 39576 } 39577 }; 39578 } 39579 constructor(key) { 39580 super(key); 39581 } 39582 createDOM() { 39583 const figure = createElement("figure", { className: "horizontal-divider" }); 39584 const hr = createElement("hr"); 39585 figure.appendChild(hr); 39586 const deleteButton = createElement("lexxy-node-delete-button"); 39587 figure.appendChild(deleteButton); 39588 return figure; 39589 } 39590 updateDOM() { 39591 return true; 39592 } 39593 getTextContent() { 39594 return "\u2504\n\n"; 39595 } 39596 isInline() { 39597 return false; 39598 } 39599 exportDOM() { 39600 const hr = createElement("hr"); 39601 return { element: hr }; 39602 } 39603 exportJSON() { 39604 return { 39605 type: "horizontal_divider", 39606 version: 1 39607 }; 39608 } 39609 decorate() { 39610 return null; 39611 } 39612 }; 39613 var HORIZONTAL_DIVIDER = { 39614 dependencies: [HorizontalDividerNode], 39615 export: (node) => { 39616 return node instanceof HorizontalDividerNode ? "---" : null; 39617 }, 39618 regExpStart: /^-{3,}\s?$/, 39619 replace: (parentNode, children, match, endMatch, linesInBetween, isImport) => { 39620 const hrNode = new HorizontalDividerNode(); 39621 parentNode.replace(hrNode); 39622 if (!isImport) { 39623 const paragraph = $createParagraphNode2(); 39624 hrNode.insertAfter(paragraph); 39625 paragraph.select(); 39626 } 39627 }, 39628 type: "multiline-element" 39629 }; 39630 var DOUBLE_QUOTE = { 39631 ...QUOTE2, 39632 regExp: /^"\s/ 39633 }; 39634 var PUNCTUATION_OR_SPACE3 = /[^\w]/; 39635 function registerMarkdownLeadingTagHandler(editor, transformers) { 39636 const textFormatTransformers = transformers.filter((t2) => t2.type === "text-format").sort((a2, b3) => b3.tag.length - a2.tag.length); 39637 return editor.registerUpdateListener(({ tags, dirtyLeaves, editorState, prevEditorState }) => { 39638 if (tags.has("historic") || tags.has("collaboration")) return; 39639 if (editor.isComposing()) return; 39640 const selection = editorState.read($getSelection2); 39641 const prevSelection = prevEditorState.read($getSelection2); 39642 if (!$isRangeSelection2(prevSelection) || !$isRangeSelection2(selection) || !selection.isCollapsed()) return; 39643 const anchorKey = selection.anchor.key; 39644 const anchorOffset = selection.anchor.offset; 39645 if (!dirtyLeaves.has(anchorKey)) return; 39646 const anchorNode = editorState.read(() => $getNodeByKey2(anchorKey)); 39647 if (!$isTextNode2(anchorNode)) return; 39648 const prevOffset = prevSelection.anchor.key === anchorKey ? prevSelection.anchor.offset : 0; 39649 if (anchorOffset <= prevOffset) return; 39650 const textContent = editorState.read(() => anchorNode.getTextContent()); 39651 for (const transformer of textFormatTransformers) { 39652 const tag = transformer.tag; 39653 const tagLen = tag.length; 39654 const openTagStart = anchorOffset - tagLen; 39655 if (openTagStart < 0) continue; 39656 const candidateOpenTag = textContent.slice(openTagStart, anchorOffset); 39657 if (candidateOpenTag !== tag) continue; 39658 const tagChar = tag[0]; 39659 if (openTagStart > 0 && textContent[openTagStart - 1] === tagChar) continue; 39660 if (transformer.intraword === false && openTagStart > 0) { 39661 const beforeChar = textContent[openTagStart - 1]; 39662 if (beforeChar && !PUNCTUATION_OR_SPACE3.test(beforeChar)) continue; 39663 } 39664 const searchStart = anchorOffset; 39665 const closeTagIndex = textContent.indexOf(tag, searchStart); 39666 if (closeTagIndex < 0) continue; 39667 if (textContent[closeTagIndex + tagLen] === tagChar) continue; 39668 if (closeTagIndex > 0 && textContent[closeTagIndex - 1] === tagChar) continue; 39669 const innerStart = anchorOffset; 39670 const innerEnd = closeTagIndex; 39671 if (innerEnd <= innerStart) continue; 39672 if (textContent[innerStart] === " ") continue; 39673 if (textContent[innerEnd - 1] === " ") continue; 39674 if (transformer.intraword === false) { 39675 const afterCloseChar = textContent[closeTagIndex + tagLen]; 39676 if (afterCloseChar && !PUNCTUATION_OR_SPACE3.test(afterCloseChar)) continue; 39677 } 39678 editor.update(() => { 39679 const node = $getNodeByKey2(anchorKey); 39680 if (!node || !$isTextNode2(node)) return; 39681 const parent = node.getParent(); 39682 if (parent === null || $isCodeNode3(parent)) return; 39683 $applyFormatFromLeadingTag(node, openTagStart, transformer); 39684 }); 39685 break; 39686 } 39687 }); 39688 } 39689 function $applyFormatFromLeadingTag(anchorNode, openTagStart, transformer) { 39690 const tag = transformer.tag; 39691 const tagLen = tag.length; 39692 const textContent = anchorNode.getTextContent(); 39693 const innerStart = openTagStart + tagLen; 39694 const closeTagIndex = textContent.indexOf(tag, innerStart); 39695 if (closeTagIndex < 0) return; 39696 const inner = textContent.slice(innerStart, closeTagIndex); 39697 if (inner.length === 0) return; 39698 const before = textContent.slice(0, openTagStart); 39699 const after = textContent.slice(closeTagIndex + tagLen); 39700 anchorNode.setTextContent(before + inner + after); 39701 const nextSelection = $createRangeSelection2(); 39702 $setSelection2(nextSelection); 39703 nextSelection.anchor.set(anchorNode.getKey(), openTagStart, "text"); 39704 nextSelection.focus.set(anchorNode.getKey(), openTagStart + inner.length, "text"); 39705 for (const format of transformer.format) { 39706 if (!nextSelection.hasFormat(format)) { 39707 nextSelection.formatText(format); 39708 } 39709 } 39710 nextSelection.anchor.set(nextSelection.focus.key, nextSelection.focus.offset, nextSelection.focus.type); 39711 for (const format of transformer.format) { 39712 if (nextSelection.hasFormat(format)) { 39713 nextSelection.toggleFormat(format); 39714 } 39715 } 39716 } 39717 var theme = { 39718 text: { 39719 bold: "lexxy-content__bold", 39720 italic: "lexxy-content__italic", 39721 strikethrough: "lexxy-content__strikethrough", 39722 underline: "lexxy-content__underline", 39723 highlight: "lexxy-content__highlight" 39724 }, 39725 tableCellHeader: "lexxy-content__table-cell--header", 39726 tableCellSelected: "lexxy-content__table-cell--selected", 39727 tableSelection: "lexxy-content__table--selection", 39728 tableScrollableWrapper: "lexxy-content__table-wrapper", 39729 tableCellHighlight: "lexxy-content__table-cell--highlight", 39730 tableCellFocus: "lexxy-content__table-cell--focus", 39731 list: { 39732 nested: { 39733 listitem: "lexxy-nested-listitem" 39734 } 39735 }, 39736 codeHighlight: { 39737 addition: "code-token__selector", 39738 atrule: "code-token__attr", 39739 attr: "code-token__attr", 39740 "attr-name": "code-token__attr", 39741 "attr-value": "code-token__selector", 39742 boolean: "code-token__property", 39743 bold: "code-token__variable", 39744 builtin: "code-token__selector", 39745 cdata: "code-token__comment", 39746 char: "code-token__selector", 39747 class: "code-token__function", 39748 "class-name": "code-token__function", 39749 color: "code-token__property", 39750 comment: "code-token__comment", 39751 constant: "code-token__property", 39752 coord: "code-token__comment", 39753 decorator: "code-token__function", 39754 deleted: "code-token__operator", 39755 deletion: "code-token__operator", 39756 directive: "code-token__attr", 39757 "directive-hash": "code-token__property", 39758 doctype: "code-token__comment", 39759 entity: "code-token__operator", 39760 function: "code-token__function", 39761 hexcode: "code-token__property", 39762 important: "code-token__function", 39763 inserted: "code-token__selector", 39764 italic: "code-token__comment", 39765 keyword: "code-token__attr", 39766 line: "code-token__selector", 39767 namespace: "code-token__variable", 39768 number: "code-token__property", 39769 macro: "code-token__function", 39770 operator: "code-token__operator", 39771 parameter: "code-token__variable", 39772 prolog: "code-token__comment", 39773 property: "code-token__property", 39774 punctuation: "code-token__punctuation", 39775 "raw-string": "code-token__operator", 39776 regex: "code-token__variable", 39777 script: "code-token__function", 39778 selector: "code-token__selector", 39779 string: "code-token__selector", 39780 style: "code-token__function", 39781 symbol: "code-token__property", 39782 tag: "code-token__property", 39783 title: "code-token__function", 39784 "type-definition": "code-token__function", 39785 url: "code-token__operator", 39786 variable: "code-token__variable" 39787 } 39788 }; 39789 var UploadRequests = class { 39790 #requestsByKey = /* @__PURE__ */ new Map(); 39791 track(key, request) { 39792 this.#requestsByKey.set(key, request); 39793 } 39794 forget(key) { 39795 this.#requestsByKey.delete(key); 39796 } 39797 abort(key) { 39798 const request = this.#requestsByKey.get(key); 39799 if (request) { 39800 this.#requestsByKey.delete(key); 39801 request.abort(); 39802 } 39803 } 39804 clear() { 39805 this.#requestsByKey.clear(); 39806 } 39807 }; 39808 var resolverRoot = null; 39809 function styleResolverRoot() { 39810 if (resolverRoot && resolverRoot.isConnected) return resolverRoot; 39811 resolverRoot = document.createElement("div"); 39812 resolverRoot.setAttribute("aria-hidden", "true"); 39813 resolverRoot.setAttribute("data-lexxy-style-resolver", ""); 39814 resolverRoot.style.cssText = "contain: strict; position: fixed; top: 0; left: 0; visibility: hidden; pointer-events: none; width: 0; height: 0;"; 39815 document.body.appendChild(resolverRoot); 39816 return resolverRoot; 39817 } 39818 function isSelectionHighlighted(selection) { 39819 if (!$isRangeSelection2(selection)) return false; 39820 if (selection.isCollapsed()) { 39821 return hasHighlightStyles(selection.style); 39822 } else { 39823 return selection.hasFormat("highlight"); 39824 } 39825 } 39826 function getHighlightStyles(selection) { 39827 if (!$isRangeSelection2(selection)) return null; 39828 let styles = getStyleObjectFromCSS4(selection.style); 39829 if (!styles.color && !styles["background-color"]) { 39830 const anchorNode = selection.anchor.getNode(); 39831 if ($isTextNode2(anchorNode)) { 39832 styles = getStyleObjectFromCSS4(anchorNode.getStyle()); 39833 } 39834 } 39835 const color = styles.color || null; 39836 const backgroundColor = styles["background-color"] || null; 39837 if (!color && !backgroundColor) return null; 39838 return { color, backgroundColor }; 39839 } 39840 function hasHighlightStyles(cssOrStyles) { 39841 const styles = typeof cssOrStyles === "string" ? getStyleObjectFromCSS4(cssOrStyles) : cssOrStyles; 39842 return !!(styles.color || styles["background-color"]); 39843 } 39844 function applyCanonicalizers(styles, canonicalizers = []) { 39845 return canonicalizers.reduce((css, canonicalizer) => { 39846 return canonicalizer.applyCanonicalization(css); 39847 }, styles); 39848 } 39849 var StyleCanonicalizer = class { 39850 constructor(property, allowedValues = []) { 39851 this._property = property; 39852 this._allowedValues = allowedValues; 39853 this._canonicalValues = this.#allowedValuesIdentityObject; 39854 } 39855 applyCanonicalization(css) { 39856 const styles = { ...getStyleObjectFromCSS4(css) }; 39857 styles[this._property] = this.getCanonicalAllowedValue(styles[this._property]); 39858 if (!styles[this._property]) { 39859 delete styles[this._property]; 39860 } 39861 return getCSSFromStyleObject2(styles); 39862 } 39863 getCanonicalAllowedValue(value) { 39864 return this._canonicalValues[value] ||= this.#resolveCannonicalValue(value); 39865 } 39866 // Private 39867 get #allowedValuesIdentityObject() { 39868 return this._allowedValues.reduce((object, value) => ({ ...object, [value]: value }), {}); 39869 } 39870 #resolveCannonicalValue(value) { 39871 let index = this.#computedAllowedValues.indexOf(value); 39872 if (index === -1) { 39873 index = this.#computedAllowedValues.indexOf(computeStyleValues(this._property, [value])[0]); 39874 } 39875 return index === -1 ? null : this._allowedValues[index]; 39876 } 39877 get #computedAllowedValues() { 39878 return this._computedAllowedValues ||= computeStyleValues(this._property, this._allowedValues); 39879 } 39880 }; 39881 function computeStyleValues(property, values) { 39882 const fragment = document.createDocumentFragment(); 39883 const elements = values.map((value) => { 39884 const element = createElement("span", { style: `display: none; ${property}: ${value};` }); 39885 fragment.appendChild(element); 39886 return element; 39887 }); 39888 styleResolverRoot().appendChild(fragment); 39889 const computed2 = elements.map( 39890 (element) => window.getComputedStyle(element).getPropertyValue(property) 39891 ); 39892 elements.forEach((element) => element.remove()); 39893 return computed2; 39894 } 39895 var TOGGLE_HIGHLIGHT_COMMAND = createCommand2(); 39896 var REMOVE_HIGHLIGHT_COMMAND = createCommand2(); 39897 var BLANK_STYLES = { "color": null, "background-color": null }; 39898 var hasPastedStylesState = createState2("hasPastedStyles", { 39899 parse: (value) => value || false 39900 }); 39901 var pendingCodeHighlights = /* @__PURE__ */ new WeakMap(); 39902 var HighlightExtension = class extends LexxyExtension { 39903 get enabled() { 39904 return this.editorElement.supportsRichText; 39905 } 39906 get lexicalExtension() { 39907 const extension = defineExtension2({ 39908 dependencies: [RichTextExtension2], 39909 name: "lexxy/highlight", 39910 config: { 39911 color: { buttons: [], permit: [] }, 39912 "background-color": { buttons: [], permit: [] } 39913 }, 39914 html: { 39915 import: { 39916 mark: $markConversion 39917 } 39918 }, 39919 register(editor, config) { 39920 const canonicalizers = buildCanonicalizers(config); 39921 $registerPreConversion(editor); 39922 return mergeRegister3( 39923 editor.registerCommand(TOGGLE_HIGHLIGHT_COMMAND, (styles) => $toggleSelectionStyles(editor, styles), COMMAND_PRIORITY_NORMAL2), 39924 editor.registerCommand(REMOVE_HIGHLIGHT_COMMAND, () => $toggleSelectionStyles(editor, BLANK_STYLES), COMMAND_PRIORITY_NORMAL2), 39925 editor.registerNodeTransform(TextNode2, $syncHighlightWithStyle), 39926 editor.registerNodeTransform(CodeHighlightNode3, $syncHighlightWithCodeHighlightNode), 39927 editor.registerNodeTransform(TextNode2, (textNode) => $canonicalizePastedStyles(textNode, canonicalizers)) 39928 ); 39929 } 39930 }); 39931 return [extension, this.editorConfig.get("highlight")]; 39932 } 39933 }; 39934 function $applyHighlightStyle(textNode, element) { 39935 const elementStyles = { 39936 color: element.style?.color, 39937 "background-color": element.style?.backgroundColor 39938 }; 39939 if ($hasUpdateTag2(PASTE_TAG2)) { 39940 $setPastedStyles(textNode); 39941 } 39942 const highlightStyle = getCSSFromStyleObject2(elementStyles); 39943 if (highlightStyle.length) { 39944 return textNode.setStyle(textNode.getStyle() + highlightStyle); 39945 } 39946 } 39947 function $markConversion() { 39948 return { 39949 conversion: extendTextNodeConversion("mark", $applyHighlightStyle), 39950 priority: 1 39951 }; 39952 } 39953 function $registerPreConversion(editor) { 39954 if (!editor._htmlConversions) return; 39955 let preEntries = editor._htmlConversions.get("pre"); 39956 if (!preEntries) { 39957 preEntries = []; 39958 editor._htmlConversions.set("pre", preEntries); 39959 } 39960 preEntries.push($preConversionWithHighlightsFactory(editor)); 39961 } 39962 function $preConversionWithHighlightsFactory(editor) { 39963 return function $preConversionWithHighlights(domNode) { 39964 const highlights = extractHighlightRanges(domNode); 39965 if (highlights.length === 0) return null; 39966 return { 39967 conversion: (domNode2) => { 39968 const language = domNode2.getAttribute("data-language"); 39969 const codeNode = $createCodeNode3(language); 39970 $getPendingHighlights(editor).set(codeNode.getKey(), highlights); 39971 return { node: codeNode }; 39972 }, 39973 priority: 2 39974 }; 39975 }; 39976 } 39977 function extractHighlightRanges(preElement) { 39978 const ranges = []; 39979 const codeElement = preElement.querySelector("code") || preElement; 39980 let offset3 = 0; 39981 function walk(node) { 39982 if (node.nodeType === Node.TEXT_NODE) { 39983 offset3 += node.textContent.length; 39984 } else if (node.nodeType === Node.ELEMENT_NODE) { 39985 if (node.tagName === "BR") { 39986 offset3 += 1; 39987 return; 39988 } 39989 const isMark = node.tagName === "MARK"; 39990 const start3 = offset3; 39991 for (const child of node.childNodes) { 39992 walk(child); 39993 } 39994 if (isMark) { 39995 const style = extractHighlightStyleFromElement(node); 39996 if (style) { 39997 ranges.push({ start: start3, end: offset3, style }); 39998 } 39999 } 40000 } 40001 } 40002 for (const child of codeElement.childNodes) { 40003 walk(child); 40004 } 40005 return ranges; 40006 } 40007 function $getPendingHighlights(editor) { 40008 let map = pendingCodeHighlights.get(editor); 40009 if (!map) { 40010 map = /* @__PURE__ */ new Map(); 40011 pendingCodeHighlights.set(editor, map); 40012 } 40013 return map; 40014 } 40015 function extractHighlightStyleFromElement(element) { 40016 const styles = {}; 40017 if (element.style?.color) styles.color = element.style.color; 40018 if (element.style?.backgroundColor) styles["background-color"] = element.style.backgroundColor; 40019 const css = getCSSFromStyleObject2(styles); 40020 return css.length > 0 ? css : null; 40021 } 40022 function buildHighlightPreservingTokenizer(editor) { 40023 return { 40024 defaultLanguage: PrismTokenizer4.defaultLanguage, 40025 tokenize(code, language) { 40026 return PrismTokenizer4.tokenize(code, language); 40027 }, 40028 $tokenize(codeNode, language) { 40029 const tokens = PrismTokenizer4.$tokenize(codeNode, language); 40030 const highlights = $takeHighlightRanges(editor, codeNode); 40031 return $applyHighlightRangesToTokens(tokens, highlights); 40032 } 40033 }; 40034 } 40035 function $takeHighlightRanges(editor, codeNode) { 40036 const pending = $getPendingHighlights(editor); 40037 const key = codeNode.getKey(); 40038 if (pending.has(key)) { 40039 const highlights = pending.get(key); 40040 pending.delete(key); 40041 return highlights; 40042 } else if (codeNode.getChildren().some($isCodeHighlightNode3)) { 40043 return $extractHighlightRangesFromCodeNode(codeNode); 40044 } else { 40045 return []; 40046 } 40047 } 40048 function $applyHighlightRangesToTokens(tokens, highlights) { 40049 if (highlights.length === 0) return tokens; 40050 const styledTokens = []; 40051 let offset3 = 0; 40052 for (const token of tokens) { 40053 if ($isCodeHighlightNode3(token)) { 40054 styledTokens.push(...$splitTokenAtHighlightBoundaries(token, offset3, highlights)); 40055 } else { 40056 styledTokens.push(token); 40057 } 40058 offset3 += token.getTextContentSize(); 40059 } 40060 return styledTokens; 40061 } 40062 function $splitTokenAtHighlightBoundaries(token, tokenStart, highlights) { 40063 const text2 = token.getTextContent(); 40064 const segments = segmentTextByHighlights(text2, tokenStart, highlights); 40065 if (segments.length === 1) { 40066 const [segment] = segments; 40067 if (segment.style) { 40068 $applyHighlightStyleToToken(token, segment.style); 40069 } 40070 return [token]; 40071 } else { 40072 return segments.map((segment) => { 40073 const segmentToken = $createCodeHighlightNode3(text2.slice(segment.start, segment.end), token.getHighlightType()); 40074 if (segment.style) { 40075 $applyHighlightStyleToToken(segmentToken, segment.style); 40076 } 40077 return segmentToken; 40078 }); 40079 } 40080 } 40081 function segmentTextByHighlights(text2, tokenStart, highlights) { 40082 const segments = []; 40083 let cursor = 0; 40084 for (const { start: start3, end, style } of highlights) { 40085 const from = Math.max(start3 - tokenStart, cursor); 40086 const to = Math.min(end - tokenStart, text2.length); 40087 if (from < to) { 40088 if (from > cursor) { 40089 segments.push({ start: cursor, end: from, style: null }); 40090 } 40091 segments.push({ start: from, end: to, style }); 40092 cursor = to; 40093 } 40094 } 40095 if (cursor < text2.length) { 40096 segments.push({ start: cursor, end: text2.length, style: null }); 40097 } 40098 return segments; 40099 } 40100 function $applyHighlightStyleToToken(token, style) { 40101 token.setStyle(style); 40102 $setCodeHighlightFormat(token, true); 40103 } 40104 function $buildChildRanges(codeNode) { 40105 const childRanges = []; 40106 let charOffset = 0; 40107 for (const child of codeNode.getChildren()) { 40108 if ($isCodeHighlightNode3(child) || $isTextNode2(child)) { 40109 const text2 = child.getTextContent(); 40110 childRanges.push({ node: child, start: charOffset, end: charOffset + text2.length }); 40111 charOffset += text2.length; 40112 } else { 40113 charOffset += 1; 40114 } 40115 } 40116 return childRanges; 40117 } 40118 function $extractHighlightRangesFromCodeNode(codeNode) { 40119 const ranges = []; 40120 const childRanges = $buildChildRanges(codeNode); 40121 for (const { node, start: start3, end } of childRanges) { 40122 const style = node.getStyle(); 40123 if (style && hasHighlightStyles(style)) { 40124 ranges.push({ start: start3, end, style }); 40125 } 40126 } 40127 return ranges; 40128 } 40129 function buildCanonicalizers(config) { 40130 return [ 40131 new StyleCanonicalizer("color", [...config.buttons.color, ...config.permit.color]), 40132 new StyleCanonicalizer("background-color", [...config.buttons["background-color"], ...config.permit["background-color"]]) 40133 ]; 40134 } 40135 function $toggleSelectionStyles(editor, styles) { 40136 const selection = $getSelection2(); 40137 if (!$isRangeSelection2(selection)) return; 40138 const patch2 = {}; 40139 for (const property in styles) { 40140 const oldValue = $getSelectionStyleValueForProperty2(selection, property); 40141 patch2[property] = toggleOrReplace(oldValue, styles[property]); 40142 } 40143 if ($selectionIsInCodeBlock(selection)) { 40144 $patchCodeHighlightStyles(editor, selection, patch2); 40145 } else { 40146 $patchStyleText2(selection, patch2); 40147 } 40148 } 40149 function $selectionIsInCodeBlock(selection) { 40150 const nodes = selection.getNodes(); 40151 return nodes.some((node) => { 40152 if ($isCodeHighlightNode3(node) || $isTextNode2(node)) { 40153 return $isCodeNode3(node.getParent()); 40154 } 40155 return $isCodeNode3(node); 40156 }); 40157 } 40158 function $patchCodeHighlightStyles(editor, selection, patch2) { 40159 const nodeKeys = selection.getNodes().filter((node) => ($isCodeHighlightNode3(node) || $isTextNode2(node)) && $isCodeNode3(node.getParent())).map((node) => ({ 40160 key: node.getKey(), 40161 startOffset: $getNodeSelectionOffsets(node, selection)[0], 40162 endOffset: $getNodeSelectionOffsets(node, selection)[1], 40163 textSize: node.getTextContentSize() 40164 })); 40165 editor.update(() => { 40166 for (const { key, startOffset, endOffset, textSize } of nodeKeys) { 40167 const node = $getNodeByKey2(key); 40168 if (!node) continue; 40169 const parent = node.getParent(); 40170 if (!$isCodeNode3(parent)) continue; 40171 if (startOffset === endOffset) continue; 40172 if (startOffset === 0 && endOffset === textSize) { 40173 $applyStylePatchToNode(node, patch2); 40174 } else { 40175 const splitNodes = node.splitText(startOffset, endOffset); 40176 const targetNode = splitNodes[startOffset === 0 ? 0 : 1]; 40177 $applyStylePatchToNode(targetNode, patch2); 40178 } 40179 } 40180 }, { skipTransforms: true, discrete: true }); 40181 } 40182 function $getNodeSelectionOffsets(node, selection) { 40183 const nodeKey = node.getKey(); 40184 const anchorKey = selection.anchor.key; 40185 const focusKey = selection.focus.key; 40186 const textSize = node.getTextContentSize(); 40187 const isAnchor = nodeKey === anchorKey; 40188 const isFocus = nodeKey === focusKey; 40189 const isForward = selection.isBackward() === false; 40190 let start3 = 0; 40191 let end = textSize; 40192 if (isForward) { 40193 if (isAnchor) start3 = selection.anchor.offset; 40194 if (isFocus) end = selection.focus.offset; 40195 } else { 40196 if (isFocus) start3 = selection.focus.offset; 40197 if (isAnchor) end = selection.anchor.offset; 40198 } 40199 return [start3, end]; 40200 } 40201 function $applyStylePatchToNode(node, patch2) { 40202 const prevStyles = getStyleObjectFromCSS4(node.getStyle()); 40203 const newStyles = { ...prevStyles }; 40204 for (const [key, value] of Object.entries(patch2)) { 40205 if (value === null) { 40206 delete newStyles[key]; 40207 } else { 40208 newStyles[key] = value; 40209 } 40210 } 40211 const newCSSText = getCSSFromStyleObject2(newStyles); 40212 node.setStyle(newCSSText); 40213 const shouldHaveHighlight = hasHighlightStyles(newCSSText); 40214 const hasHighlight = node.hasFormat("highlight"); 40215 if (shouldHaveHighlight !== hasHighlight) { 40216 $setCodeHighlightFormat(node, shouldHaveHighlight); 40217 } 40218 } 40219 function $setCodeHighlightFormat(node, shouldHaveHighlight) { 40220 const writable = node.getWritable(); 40221 const IS_HIGHLIGHT3 = 1 << 7; 40222 if (shouldHaveHighlight) { 40223 writable.__format |= IS_HIGHLIGHT3; 40224 } else { 40225 writable.__format &= ~IS_HIGHLIGHT3; 40226 } 40227 } 40228 function toggleOrReplace(oldValue, newValue) { 40229 return oldValue === newValue ? null : newValue; 40230 } 40231 function $syncHighlightWithStyle(textNode) { 40232 if (hasHighlightStyles(textNode.getStyle()) !== textNode.hasFormat("highlight")) { 40233 textNode.toggleFormat("highlight"); 40234 } 40235 } 40236 function $syncHighlightWithCodeHighlightNode(node) { 40237 const parent = node.getParent(); 40238 if (!$isCodeNode3(parent)) return; 40239 const shouldHaveHighlight = hasHighlightStyles(node.getStyle()); 40240 const hasHighlight = node.hasFormat("highlight"); 40241 if (shouldHaveHighlight !== hasHighlight) { 40242 $setCodeHighlightFormat(node, shouldHaveHighlight); 40243 } 40244 } 40245 function $canonicalizePastedStyles(textNode, canonicalizers = []) { 40246 if ($hasPastedStyles(textNode)) { 40247 $setPastedStyles(textNode, false); 40248 const canonicalizedCSS = applyCanonicalizers(textNode.getStyle(), canonicalizers); 40249 textNode.setStyle(canonicalizedCSS); 40250 const selection = $getSelection2(); 40251 if (textNode.isSelected(selection)) { 40252 selection.setStyle(textNode.getStyle()); 40253 selection.setFormat(textNode.getFormat()); 40254 } 40255 } 40256 } 40257 function $setPastedStyles(textNode, value = true) { 40258 $setState2(textNode, hasPastedStylesState, value); 40259 } 40260 function $hasPastedStyles(textNode) { 40261 return $getState2(textNode, hasPastedStylesState); 40262 } 40263 var COMMANDS = [ 40264 "bold", 40265 "italic", 40266 "strikethrough", 40267 "underline", 40268 "link", 40269 "unlink", 40270 "toggleHighlight", 40271 "removeHighlight", 40272 "setFormatHeadingLarge", 40273 "setFormatHeadingMedium", 40274 "setFormatHeadingSmall", 40275 "setFormatParagraph", 40276 "applyHeadingFormat", 40277 "clearFormatting", 40278 "insertUnorderedList", 40279 "insertOrderedList", 40280 "insertQuoteBlock", 40281 "insertCodeBlock", 40282 "setCodeLanguage", 40283 "insertHorizontalDivider", 40284 "uploadImage", 40285 "uploadFile", 40286 "insertTable", 40287 "undo", 40288 "redo" 40289 ]; 40290 var CommandDispatcher = class _CommandDispatcher { 40291 #selectionBeforeDrag = null; 40292 #listeners = new ListenerBin(); 40293 static configureFor(editorElement) { 40294 return new _CommandDispatcher(editorElement); 40295 } 40296 constructor(editorElement) { 40297 this.editorElement = editorElement; 40298 this.editor = editorElement.editor; 40299 this.selection = editorElement.selection; 40300 this.contents = editorElement.contents; 40301 this.#registerCommands(); 40302 this.#registerKeyboardCommands(); 40303 this.#registerDragAndDropHandlers(); 40304 } 40305 dispatchBold() { 40306 this.editor.dispatchCommand(FORMAT_TEXT_COMMAND2, "bold"); 40307 } 40308 dispatchItalic() { 40309 this.editor.dispatchCommand(FORMAT_TEXT_COMMAND2, "italic"); 40310 } 40311 dispatchStrikethrough() { 40312 this.editor.dispatchCommand(FORMAT_TEXT_COMMAND2, "strikethrough"); 40313 } 40314 dispatchUnderline() { 40315 this.editor.dispatchCommand(FORMAT_TEXT_COMMAND2, "underline"); 40316 } 40317 dispatchToggleHighlight(styles) { 40318 this.editor.dispatchCommand(TOGGLE_HIGHLIGHT_COMMAND, styles); 40319 } 40320 dispatchRemoveHighlight() { 40321 this.editor.dispatchCommand(REMOVE_HIGHLIGHT_COMMAND); 40322 } 40323 dispatchLink(url) { 40324 this.editor.update(() => { 40325 const selection = $getSelection2(); 40326 if (!$isRangeSelection2(selection)) return; 40327 const anchorNode = selection.anchor.getNode(); 40328 if (selection.isCollapsed() && !$getNearestNodeOfType2(anchorNode, LinkNode2)) { 40329 const autoLinkNode = $createAutoLinkNode2(url); 40330 const textNode = $createTextNode2(url); 40331 autoLinkNode.append(textNode); 40332 selection.insertNodes([autoLinkNode]); 40333 } else { 40334 $toggleLink2(url); 40335 } 40336 }); 40337 } 40338 dispatchUnlink() { 40339 this.editor.update(() => { 40340 if (this.editorElement.adapter.unlinkFrozenNode?.()) { 40341 return; 40342 } 40343 $toggleLink2(null); 40344 }); 40345 } 40346 dispatchInsertUnorderedList() { 40347 const selection = $getSelection2(); 40348 if (!$isRangeSelection2(selection)) return; 40349 const anchorNode = selection.anchor.getNode(); 40350 if (this.selection.isInsideList && anchorNode && getListType(anchorNode) === "bullet") { 40351 this.contents.applyParagraphFormat(); 40352 } else { 40353 this.contents.applyUnorderedListFormat(); 40354 } 40355 } 40356 dispatchInsertOrderedList() { 40357 const selection = $getSelection2(); 40358 if (!$isRangeSelection2(selection)) return; 40359 const anchorNode = selection.anchor.getNode(); 40360 if (this.selection.isInsideList && anchorNode && getListType(anchorNode) === "number") { 40361 this.contents.applyParagraphFormat(); 40362 } else { 40363 this.contents.applyOrderedListFormat(); 40364 } 40365 } 40366 dispatchInsertQuoteBlock() { 40367 this.contents.toggleBlockquote(); 40368 } 40369 dispatchInsertCodeBlock() { 40370 if (this.selection.hasSelectedWordsInSingleLine) { 40371 this.#toggleInlineCode(); 40372 } else { 40373 this.contents.toggleCodeBlock(); 40374 } 40375 } 40376 #toggleInlineCode() { 40377 const selection = $getSelection2(); 40378 if (!$isRangeSelection2(selection)) return; 40379 if (!selection.isCollapsed()) { 40380 const textNodes = selection.getNodes().filter($isTextNode2); 40381 const applyingCode = !textNodes.every((node) => node.hasFormat("code")); 40382 if (applyingCode) { 40383 this.#stripInlineFormattingFromSelection(selection, textNodes); 40384 } 40385 } 40386 this.editor.dispatchCommand(FORMAT_TEXT_COMMAND2, "code"); 40387 } 40388 // Strip all inline formatting (bold, italic, etc.) from the selected text 40389 // nodes so that applying code produces a single merged <code> element instead 40390 // of one per differently-formatted span. 40391 #stripInlineFormattingFromSelection(selection, textNodes) { 40392 const isBackward = selection.isBackward(); 40393 const startPoint = isBackward ? selection.focus : selection.anchor; 40394 const endPoint = isBackward ? selection.anchor : selection.focus; 40395 for (let i2 = 0; i2 < textNodes.length; i2++) { 40396 const node = textNodes[i2]; 40397 if (node.getFormat() === 0) continue; 40398 const isFirst = i2 === 0; 40399 const isLast = i2 === textNodes.length - 1; 40400 const startOffset = isFirst && startPoint.type === "text" ? startPoint.offset : 0; 40401 const endOffset = isLast && endPoint.type === "text" ? endPoint.offset : node.getTextContentSize(); 40402 if (startOffset === 0 && endOffset === node.getTextContentSize()) { 40403 node.setFormat(0); 40404 } else { 40405 const splits = node.splitText(startOffset, endOffset); 40406 const target = startOffset === 0 ? splits[0] : splits[1]; 40407 target.setFormat(0); 40408 if (isFirst && startPoint.type === "text") { 40409 startPoint.set(target.getKey(), 0, "text"); 40410 } 40411 if (isLast && endPoint.type === "text") { 40412 endPoint.set(target.getKey(), endOffset - startOffset, "text"); 40413 } 40414 } 40415 } 40416 } 40417 dispatchSetCodeLanguage(language) { 40418 this.editor.update(() => { 40419 if (!this.selection.isInsideCodeBlock) return; 40420 const codeNode = this.selection.nearestNodeOfType(CodeNode3); 40421 if (!codeNode) return; 40422 codeNode.setLanguage(language); 40423 }); 40424 } 40425 dispatchInsertHorizontalDivider() { 40426 $insertNodeToNearestRoot2(new HorizontalDividerNode()); 40427 } 40428 dispatchSetFormatHeadingLarge() { 40429 this.#applyConfiguredHeadingFormat(0); 40430 } 40431 dispatchSetFormatHeadingMedium() { 40432 this.#applyConfiguredHeadingFormat(1); 40433 } 40434 dispatchSetFormatHeadingSmall() { 40435 this.#applyConfiguredHeadingFormat(2); 40436 } 40437 dispatchSetFormatParagraph() { 40438 this.contents.applyParagraphFormat(); 40439 } 40440 dispatchApplyHeadingFormat(tag) { 40441 this.contents.applyHeadingFormat(tag); 40442 } 40443 dispatchClearFormatting() { 40444 this.contents.clearFormatting(); 40445 } 40446 dispatchUploadImage() { 40447 this.#dispatchUploadAttachment("image/*,video/*,audio/*"); 40448 } 40449 dispatchUploadFile() { 40450 this.#dispatchUploadAttachment(); 40451 } 40452 #dispatchUploadAttachment(accept = null) { 40453 const attributes = { 40454 type: "file", 40455 multiple: true, 40456 style: "display: none;", 40457 onchange: ({ target: { files } }) => { 40458 this.contents.uploadFiles(files, { selectLast: true }); 40459 } 40460 }; 40461 if (accept) attributes.accept = accept; 40462 const input = createElement("input", attributes); 40463 this.editorElement.appendChild(input); 40464 input.click(); 40465 setTimeout(() => input.remove(), 1e3); 40466 } 40467 dispatchInsertTable() { 40468 this.editor.dispatchCommand(INSERT_TABLE_COMMAND2, { "rows": 3, "columns": 3, "includeHeaders": true }); 40469 } 40470 dispatchUndo() { 40471 this.editor.dispatchCommand(UNDO_COMMAND2, void 0); 40472 } 40473 dispatchRedo() { 40474 this.editor.dispatchCommand(REDO_COMMAND2, void 0); 40475 } 40476 dispose() { 40477 this.#listeners.dispose(); 40478 } 40479 #applyConfiguredHeadingFormat(index) { 40480 const tag = this.editorElement.config.get("headings")[index]; 40481 if (tag) this.contents.applyHeadingFormat(tag); 40482 } 40483 #registerCommands() { 40484 for (const command of COMMANDS) { 40485 const methodName = `dispatch${capitalize(command)}`; 40486 this.#registerCommandHandler(command, 0, this[methodName].bind(this)); 40487 } 40488 } 40489 #registerCommandHandler(command, priority, handler) { 40490 this.#listeners.track(this.editor.registerCommand(command, handler, priority)); 40491 } 40492 #registerKeyboardCommands() { 40493 this.#registerCommandHandler(KEY_ARROW_RIGHT_COMMAND2, COMMAND_PRIORITY_NORMAL2, this.#handleArrowRightKey.bind(this)); 40494 this.#registerCommandHandler(KEY_TAB_COMMAND2, COMMAND_PRIORITY_NORMAL2, this.#handleTabKey.bind(this)); 40495 this.#registerCommandHandler(INSERT_LINE_BREAK_COMMAND2, COMMAND_PRIORITY_HIGH2, this.#normalizeBlockContainerSelection.bind(this)); 40496 this.#registerCommandHandler(INSERT_PARAGRAPH_COMMAND2, COMMAND_PRIORITY_HIGH2, this.#normalizeBlockContainerSelection.bind(this)); 40497 } 40498 #normalizeBlockContainerSelection() { 40499 $normalizeBlockContainerSelection(); 40500 return false; 40501 } 40502 #handleArrowRightKey(event) { 40503 const selection = $getSelection2(); 40504 if (!$isRangeSelection2(selection) || !selection.isCollapsed()) return false; 40505 if (this.selection.isInsideCodeBlock || !selection.hasFormat("code")) return false; 40506 const anchorNode = selection.anchor.getNode(); 40507 if (!$isTextNode2(anchorNode) || selection.anchor.offset !== anchorNode.getTextContentSize()) return false; 40508 if (anchorNode.getNextSibling() !== null) return false; 40509 event.preventDefault(); 40510 selection.toggleFormat("code"); 40511 return true; 40512 } 40513 #registerDragAndDropHandlers() { 40514 if (this.editorElement.supportsAttachments) { 40515 this.dragCounter = 0; 40516 this.#listeners.track( 40517 this.editor.registerRootListener((rootElement) => { 40518 if (rootElement) { 40519 const teardowns = [ 40520 registerEventListener(rootElement, "dragover", this.#handleDragOver.bind(this)), 40521 registerEventListener(rootElement, "drop", this.#handleDrop.bind(this)), 40522 registerEventListener(rootElement, "dragenter", this.#handleDragEnter.bind(this)), 40523 registerEventListener(rootElement, "dragleave", this.#handleDragLeave.bind(this)) 40524 ]; 40525 return () => teardowns.forEach((teardown) => teardown()); 40526 } 40527 }) 40528 ); 40529 } 40530 } 40531 #handleDragEnter(event) { 40532 if (this.#isInternalDrag(event)) return; 40533 this.dragCounter++; 40534 if (this.dragCounter === 1) { 40535 this.#saveSelectionBeforeDrag(); 40536 this.editor.getRootElement().classList.add("lexxy-editor--drag-over"); 40537 } 40538 } 40539 #handleDragLeave(event) { 40540 if (this.#isInternalDrag(event)) return; 40541 this.dragCounter--; 40542 if (this.dragCounter === 0) { 40543 this.#selectionBeforeDrag = null; 40544 this.editor.getRootElement().classList.remove("lexxy-editor--drag-over"); 40545 } 40546 } 40547 #handleDragOver(event) { 40548 if (this.#isInternalDrag(event)) return; 40549 event.preventDefault(); 40550 } 40551 #handleDrop(event) { 40552 if (this.#isInternalDrag(event)) return; 40553 event.preventDefault(); 40554 this.dragCounter = 0; 40555 this.editor.getRootElement().classList.remove("lexxy-editor--drag-over"); 40556 const dataTransfer = event.dataTransfer; 40557 if (!dataTransfer) return; 40558 const files = Array.from(dataTransfer.files); 40559 if (!files.length) return; 40560 this.#restoreSelectionBeforeDrag(); 40561 this.contents.uploadFiles(files, { selectLast: true }); 40562 this.editor.focus(); 40563 } 40564 #saveSelectionBeforeDrag() { 40565 this.editor.getEditorState().read(() => { 40566 this.#selectionBeforeDrag = $getSelection2()?.clone(); 40567 }); 40568 } 40569 #restoreSelectionBeforeDrag() { 40570 if (!this.#selectionBeforeDrag) return; 40571 this.editor.update(() => { 40572 $setSelection2(this.#selectionBeforeDrag); 40573 }); 40574 this.#selectionBeforeDrag = null; 40575 } 40576 #isInternalDrag(event) { 40577 return event.dataTransfer?.types.some((type) => type.startsWith("application/x-lexxy-")); 40578 } 40579 #handleTabKey(event) { 40580 if (this.selection.isInsideList) { 40581 return this.#handleTabForList(event); 40582 } else if (this.selection.isInsideCodeBlock) { 40583 return this.#handleTabForCode(); 40584 } 40585 return false; 40586 } 40587 #handleTabForList(event) { 40588 if (event.shiftKey && !this.selection.isIndentedList) return false; 40589 event.preventDefault(); 40590 const command = event.shiftKey ? OUTDENT_CONTENT_COMMAND2 : INDENT_CONTENT_COMMAND2; 40591 return this.editor.dispatchCommand(command); 40592 } 40593 #handleTabForCode() { 40594 const selection = $getSelection2(); 40595 return $isRangeSelection2(selection) && selection.isCollapsed(); 40596 } 40597 }; 40598 function capitalize(str) { 40599 return str.charAt(0).toUpperCase() + str.slice(1); 40600 } 40601 var Selection = class { 40602 #listeners = new ListenerBin(); 40603 constructor(editorElement) { 40604 this.editorElement = editorElement; 40605 this.editorContentElement = editorElement.editorContentElement; 40606 this.editor = this.editorElement.editor; 40607 this.previouslySelectedKeys = /* @__PURE__ */ new Set(); 40608 this.#listenForNodeSelections(); 40609 this.#processSelectionChangeCommands(); 40610 this.#containEditorFocus(); 40611 this.#clearStaleInlineCodeFormat(); 40612 } 40613 get hasNodeSelection() { 40614 return this.editor.getEditorState().read(() => { 40615 const selection = $getSelection2(); 40616 return selection !== null && $isNodeSelection2(selection); 40617 }); 40618 } 40619 get cursorPosition() { 40620 let position = null; 40621 this.editor.getEditorState().read(() => { 40622 const range2 = this.#getValidSelectionRange(); 40623 if (!range2) return; 40624 const rect = this.#getReliableRectFromRange(range2); 40625 if (this.#isRectUnreliable(rect)) return; 40626 position = this.#calculateCursorPosition(rect, range2); 40627 }); 40628 return position; 40629 } 40630 placeCursorAtTheEnd() { 40631 this.editor.update(() => { 40632 const root = $getRoot2(); 40633 const lastDescendant = root.getLastDescendant(); 40634 if (lastDescendant && $isTextNode2(lastDescendant)) { 40635 lastDescendant.selectEnd(); 40636 } else { 40637 root.selectEnd(); 40638 } 40639 }); 40640 } 40641 selectedNodeWithOffset() { 40642 const selection = $getSelection2(); 40643 if (!selection) return { node: null, offset: 0 }; 40644 if ($isRangeSelection2(selection)) { 40645 return { 40646 node: selection.anchor.getNode(), 40647 offset: selection.anchor.offset 40648 }; 40649 } else if ($isNodeSelection2(selection)) { 40650 const [node] = selection.getNodes(); 40651 return { 40652 node, 40653 offset: 0 40654 }; 40655 } 40656 return { node: null, offset: 0 }; 40657 } 40658 getFormat() { 40659 const selection = $getSelection2(); 40660 if (!$isRangeSelection2(selection)) return {}; 40661 const anchorNode = selection.anchor.getNode(); 40662 if (!anchorNode.getParent()) return {}; 40663 const topLevelElement = anchorNode.getTopLevelElementOrThrow(); 40664 const listType = getListType(anchorNode); 40665 const headingNode = this.#getNearestHeadingNode(anchorNode); 40666 return { 40667 isBold: selection.hasFormat("bold"), 40668 isItalic: selection.hasFormat("italic"), 40669 isStrikethrough: selection.hasFormat("strikethrough"), 40670 isUnderline: selection.hasFormat("underline"), 40671 isHighlight: isSelectionHighlighted(selection), 40672 isInLink: $getNearestNodeOfType2(anchorNode, LinkNode2) !== null, 40673 isInQuote: $isQuoteNode2(topLevelElement), 40674 isInHeading: headingNode !== null, 40675 isInCode: this.#isInCode(selection, anchorNode), 40676 headingTag: headingNode?.getTag() ?? null, 40677 isInList: listType !== null, 40678 listType, 40679 isInTable: $getTableCellNodeFromLexicalNode2(anchorNode) !== null 40680 }; 40681 } 40682 nearestNodeOfType(nodeType) { 40683 const anchorNode = $getSelection2()?.anchor?.getNode(); 40684 return $getNearestNodeOfType2(anchorNode, nodeType); 40685 } 40686 get hasSelectedWordsInSingleLine() { 40687 const selection = $getSelection2(); 40688 if (!$isRangeSelection2(selection)) return false; 40689 if (selection.isCollapsed()) return false; 40690 const anchorNode = selection.anchor.getNode(); 40691 const focusNode = selection.focus.getNode(); 40692 if (anchorNode.getTopLevelElement() !== focusNode.getTopLevelElement()) { 40693 return false; 40694 } 40695 const anchorElement = anchorNode.getTopLevelElement(); 40696 if (!anchorElement) return false; 40697 const anchorBlock = $isElementNode2(anchorNode) ? anchorNode : anchorNode.getParent(); 40698 const focusBlock = $isElementNode2(focusNode) ? focusNode : focusNode.getParent(); 40699 if (anchorBlock !== focusBlock && anchorBlock !== anchorElement) { 40700 return false; 40701 } 40702 const nodes = selection.getNodes(); 40703 for (const node of nodes) { 40704 if ($isLineBreakNode2(node)) { 40705 return false; 40706 } 40707 } 40708 return true; 40709 } 40710 get isInsideList() { 40711 return this.nearestNodeOfType(ListItemNode2); 40712 } 40713 get isInsideBlockQuote() { 40714 return this.nearestNodeOfType(QuoteNode2); 40715 } 40716 get isIndentedList() { 40717 const closestListNode = this.nearestNodeOfType(ListNode2); 40718 return closestListNode && $getListDepth2(closestListNode) > 1; 40719 } 40720 get isInsideCodeBlock() { 40721 return this.nearestNodeOfType(CodeNode3) !== null; 40722 } 40723 get isTableCellSelected() { 40724 const selection = $getSelection2(); 40725 const { anchor, focus } = selection; 40726 if (!$isRangeSelection2(selection) || anchor.key !== focus.key) return false; 40727 return this.nearestNodeOfType(TableCellNode2) !== null; 40728 } 40729 get isOnPreviewableImage() { 40730 return this.previewableImageNode != null; 40731 } 40732 get previewableImageNode() { 40733 const firstNode = $getSelection2()?.getNodes().at(0); 40734 return $isActionTextAttachmentNode(firstNode) && firstNode.isPreviewableImage ? firstNode : null; 40735 } 40736 get isAtNodeStart() { 40737 const { anchorNode, offset: offset3 } = this.#getCollapsedSelectionData(); 40738 return anchorNode && offset3 === 0; 40739 } 40740 get nodeAfterCursor() { 40741 const { anchorNode, offset: offset3 } = this.#getCollapsedSelectionData(); 40742 if (!anchorNode) return null; 40743 if ($isTextNode2(anchorNode)) { 40744 return this.#getNodeAfterTextNode(anchorNode, offset3); 40745 } 40746 if ($isElementNode2(anchorNode)) { 40747 return this.#getNodeAfterElementNode(anchorNode, offset3); 40748 } 40749 return this.#findNextSiblingUp(anchorNode); 40750 } 40751 get topLevelNodeAfterCursor() { 40752 const { anchorNode, offset: offset3 } = this.#getCollapsedSelectionData(); 40753 if (!anchorNode) return null; 40754 if ($isTextNode2(anchorNode)) { 40755 if (offset3 === anchorNode.getTextContentSize()) return this.#getNextNodeFromTextEnd(anchorNode); 40756 if (this.#isCursorOnLastVisualLineOfBlock(anchorNode)) { 40757 const topLevelElement = anchorNode.getTopLevelElement(); 40758 return topLevelElement ? topLevelElement.getNextSibling() : null; 40759 } 40760 return null; 40761 } 40762 if ($isElementNode2(anchorNode)) { 40763 return this.#getNodeAfterElementNode(anchorNode, offset3); 40764 } 40765 return this.#findNextSiblingUp(anchorNode); 40766 } 40767 get nodeBeforeCursor() { 40768 const { anchorNode, offset: offset3 } = this.#getCollapsedSelectionData(); 40769 if (!anchorNode) return null; 40770 if ($isTextNode2(anchorNode)) { 40771 return this.#getNodeBeforeTextNode(anchorNode, offset3); 40772 } 40773 if ($isElementNode2(anchorNode)) { 40774 return this.#getNodeBeforeElementNode(anchorNode, offset3); 40775 } 40776 return this.#findPreviousSiblingUp(anchorNode); 40777 } 40778 get topLevelNodeBeforeCursor() { 40779 const { anchorNode, offset: offset3 } = this.#getCollapsedSelectionData(); 40780 if (!anchorNode) return null; 40781 if ($isTextNode2(anchorNode)) { 40782 if (offset3 === 0) return this.#getPreviousNodeFromTextStart(anchorNode); 40783 if (this.#isCursorOnFirstVisualLineOfBlock(anchorNode)) { 40784 const topLevelElement = anchorNode.getTopLevelElement(); 40785 return topLevelElement ? topLevelElement.getPreviousSibling() : null; 40786 } 40787 return null; 40788 } 40789 if ($isElementNode2(anchorNode)) { 40790 return this.#getNodeBeforeElementNode(anchorNode, offset3); 40791 } 40792 return this.#findPreviousSiblingUp(anchorNode); 40793 } 40794 dispose() { 40795 this.editorElement = null; 40796 this.editorContentElement = null; 40797 this.editor = null; 40798 this.previouslySelectedKeys = null; 40799 this.#listeners.dispose(); 40800 } 40801 // When all inline code text is deleted, Lexical's selection retains the stale 40802 // code format flag. Verify the flag is backed by actual code-formatted content: 40803 // a code block ancestor or a text node that carries the code format. 40804 #isInCode(selection, anchorNode) { 40805 if ($getNearestNodeOfType2(anchorNode, CodeNode3) !== null) return true; 40806 if (!selection.hasFormat("code")) return false; 40807 return $isTextNode2(anchorNode) && anchorNode.hasFormat("code"); 40808 } 40809 // After deleting all inline code text, Lexical preserves the code format on 40810 // the selection even though no code-formatted content remains. This listener 40811 // detects that stale state and clears it so newly typed text won't be 40812 // code-formatted. 40813 #clearStaleInlineCodeFormat() { 40814 this.#listeners.track(this.editor.registerUpdateListener(({ editorState, tags }) => { 40815 if (tags.has("history-merge") || tags.has("skip-dom-selection")) return; 40816 let isStale = false; 40817 editorState.read(() => { 40818 const selection = $getSelection2(); 40819 if (!$isRangeSelection2(selection) || !selection.isCollapsed()) return; 40820 if (!selection.hasFormat("code")) return; 40821 const anchorNode = selection.anchor.getNode(); 40822 if (this.#isInCode(selection, anchorNode)) return; 40823 isStale = true; 40824 }); 40825 if (isStale) { 40826 setTimeout(() => { 40827 this.editor.update(() => { 40828 const selection = $getSelection2(); 40829 if (!$isRangeSelection2(selection) || !selection.hasFormat("code")) return; 40830 const anchorNode = selection.anchor.getNode(); 40831 if (this.#isInCode(selection, anchorNode)) return; 40832 selection.toggleFormat("code"); 40833 }); 40834 }, 0); 40835 } 40836 })); 40837 } 40838 get #currentlySelectedKeys() { 40839 if (this.currentlySelectedKeys) { 40840 return this.currentlySelectedKeys; 40841 } 40842 this.currentlySelectedKeys = /* @__PURE__ */ new Set(); 40843 const selection = $getSelection2(); 40844 if (selection && $isNodeSelection2(selection)) { 40845 for (const node of selection.getNodes()) { 40846 this.currentlySelectedKeys.add(node.getKey()); 40847 } 40848 } 40849 return this.currentlySelectedKeys; 40850 } 40851 #processSelectionChangeCommands() { 40852 this.#listeners.track( 40853 this.editor.registerCommand(KEY_ARROW_LEFT_COMMAND2, handlingDefault(this.#selectPreviousNode.bind(this)), COMMAND_PRIORITY_LOW2), 40854 this.editor.registerCommand(KEY_ARROW_RIGHT_COMMAND2, handlingDefault(this.#selectNextNode.bind(this)), COMMAND_PRIORITY_LOW2), 40855 this.editor.registerCommand(KEY_ARROW_UP_COMMAND2, handlingDefault(this.#selectPreviousTopLevelNode.bind(this)), COMMAND_PRIORITY_LOW2), 40856 this.editor.registerCommand(KEY_ARROW_DOWN_COMMAND2, handlingDefault(this.#selectNextTopLevelNode.bind(this)), COMMAND_PRIORITY_LOW2), 40857 this.editor.registerCommand(DELETE_CHARACTER_COMMAND2, this.#selectDecoratorNodeBeforeDeletion.bind(this), COMMAND_PRIORITY_LOW2), 40858 this.editor.registerCommand(SELECTION_CHANGE_COMMAND2, () => { 40859 this.#syncSelectedClasses(); 40860 }, COMMAND_PRIORITY_LOW2) 40861 ); 40862 } 40863 #listenForNodeSelections() { 40864 this.#listeners.track(this.editor.registerCommand(CLICK_COMMAND2, ({ target }) => { 40865 if (!isDOMNode2(target)) return false; 40866 const targetNode = $getNearestNodeFromDOMNode2(target); 40867 return $isDecoratorNode2(targetNode) && this.#selectInLexical(targetNode); 40868 }, COMMAND_PRIORITY_LOW2)); 40869 this.#listeners.track( 40870 this.editor.registerRootListener((rootElement) => { 40871 if (rootElement) { 40872 return registerEventListener(rootElement, "lexxy:internal:move-to-next-line", () => this.#selectOrAppendNextLine()); 40873 } 40874 }) 40875 ); 40876 } 40877 #containEditorFocus() { 40878 this.#listeners.track( 40879 this.editor.registerRootListener((rootElement) => { 40880 if (rootElement) { 40881 const handler = (event) => this.#handleArrowKeyOnLexicalCursor(event); 40882 rootElement.addEventListener("keydown", handler, true); 40883 return () => rootElement.removeEventListener("keydown", handler, true); 40884 } 40885 }) 40886 ); 40887 } 40888 #handleArrowKeyOnLexicalCursor(event) { 40889 if (event.key === "ArrowUp") { 40890 const lexicalCursor = this.editor.getRootElement().querySelector("[data-lexical-cursor]"); 40891 if (lexicalCursor) { 40892 let currentElement = lexicalCursor.previousElementSibling; 40893 while (currentElement && currentElement.hasAttribute("data-lexical-cursor")) { 40894 currentElement = currentElement.previousElementSibling; 40895 } 40896 if (!currentElement) { 40897 event.preventDefault(); 40898 } 40899 } 40900 } 40901 if (event.key === "ArrowDown") { 40902 const lexicalCursor = this.editor.getRootElement().querySelector("[data-lexical-cursor]"); 40903 if (lexicalCursor) { 40904 let currentElement = lexicalCursor.nextElementSibling; 40905 while (currentElement && currentElement.hasAttribute("data-lexical-cursor")) { 40906 currentElement = currentElement.nextElementSibling; 40907 } 40908 if (!currentElement) { 40909 event.preventDefault(); 40910 } 40911 } 40912 } 40913 } 40914 #syncSelectedClasses() { 40915 this.#clearPreviouslyHighlightedItems(); 40916 this.#highlightNewItems(); 40917 this.previouslySelectedKeys = this.#currentlySelectedKeys; 40918 this.currentlySelectedKeys = null; 40919 } 40920 #clearPreviouslyHighlightedItems() { 40921 for (const key of this.previouslySelectedKeys) { 40922 if (!this.#currentlySelectedKeys.has(key)) { 40923 const dom = this.editor.getElementByKey(key); 40924 if (dom) dom.classList.remove("node--selected"); 40925 } 40926 } 40927 } 40928 #highlightNewItems() { 40929 for (const key of this.#currentlySelectedKeys) { 40930 if (!this.previouslySelectedKeys.has(key)) { 40931 const nodeElement = this.editor.getElementByKey(key); 40932 if (nodeElement) nodeElement.classList.add("node--selected"); 40933 } 40934 } 40935 } 40936 #selectPreviousNode(event) { 40937 if (event.shiftKey) { 40938 return this.#withCurrentNodeSelectionNode((currentNode) => { 40939 const selection = this.#rangeSelectDecorator(currentNode, "forward"); 40940 selection.modify("extend", true, "character"); 40941 return true; 40942 }); 40943 } else { 40944 return this.#withCurrentNodeSelectionNode((currentNode) => currentNode.selectPrevious()) || this.#selectInLexical(this.nodeBeforeCursor); 40945 } 40946 } 40947 #selectNextNode(event) { 40948 if (event.shiftKey) { 40949 return this.#withCurrentNodeSelectionNode((currentNode) => { 40950 const selection = this.#rangeSelectDecorator(currentNode, "forward"); 40951 selection.modify("extend", false, "character"); 40952 return true; 40953 }); 40954 } else { 40955 return this.#withCurrentNodeSelectionNode((currentNode) => currentNode.selectNext(0, 0)) || this.#selectInLexical(this.nodeAfterCursor); 40956 } 40957 } 40958 #selectPreviousTopLevelNode() { 40959 return this.#withCurrentNodeSelectionNode((currentNode) => currentNode.getTopLevelElement().selectPrevious()) || this.#selectInLexical(this.topLevelNodeBeforeCursor); 40960 } 40961 #selectNextTopLevelNode() { 40962 return this.#withCurrentNodeSelectionNode((currentNode) => currentNode.getTopLevelElement().selectNext(0, 0)) || this.#selectInLexical(this.topLevelNodeAfterCursor); 40963 } 40964 #withCurrentNodeSelectionNode(fn) { 40965 if (this.hasNodeSelection) { 40966 return fn($getSelection2().getNodes()[0]); 40967 } 40968 } 40969 #rangeSelectDecorator(node, direction = "forward") { 40970 if ($isDecoratorNode2(node)) { 40971 const [anchorOffset, focusOffset] = direction === "forward" ? [0, 1] : [1, 0]; 40972 const indexAtNode = node.getIndexWithinParent(); 40973 return node.getParent().select(indexAtNode + anchorOffset, indexAtNode + focusOffset); 40974 } 40975 } 40976 async #selectOrAppendNextLine() { 40977 this.editor.update(() => { 40978 const topLevelElement = this.#getTopLevelElementFromSelection(); 40979 if (!topLevelElement) return; 40980 this.#moveToOrCreateNextLine(topLevelElement); 40981 }); 40982 } 40983 #getTopLevelElementFromSelection() { 40984 const selection = $getSelection2(); 40985 if (!selection) return null; 40986 if ($isNodeSelection2(selection)) { 40987 return this.#getTopLevelFromNodeSelection(selection); 40988 } 40989 if ($isRangeSelection2(selection)) { 40990 return this.#getTopLevelFromRangeSelection(selection); 40991 } 40992 return null; 40993 } 40994 #getTopLevelFromNodeSelection(selection) { 40995 const nodes = selection.getNodes(); 40996 return nodes.length > 0 ? nodes[0].getTopLevelElement() : null; 40997 } 40998 #getTopLevelFromRangeSelection(selection) { 40999 const anchorNode = selection.anchor.getNode(); 41000 return anchorNode.getTopLevelElement(); 41001 } 41002 #getNearestHeadingNode(anchorNode) { 41003 const topLevelElement = anchorNode.getTopLevelElementOrThrow(); 41004 let headingNode = $isHeadingNode2(topLevelElement) ? topLevelElement : null; 41005 if (!headingNode) { 41006 let current = anchorNode.getParent(); 41007 while (current) { 41008 if ($isHeadingNode2(current)) { 41009 headingNode = current; 41010 break; 41011 } 41012 current = current.getParent(); 41013 } 41014 } 41015 return headingNode; 41016 } 41017 #moveToOrCreateNextLine(topLevelElement) { 41018 const nextSibling = topLevelElement.getNextSibling(); 41019 if (nextSibling) { 41020 nextSibling.selectStart(); 41021 } else { 41022 this.#createAndSelectNewParagraph(); 41023 } 41024 } 41025 #createAndSelectNewParagraph() { 41026 const root = $getRoot2(); 41027 const newParagraph = $createParagraphNode2(); 41028 root.append(newParagraph); 41029 newParagraph.selectStart(); 41030 } 41031 #selectInLexical(node) { 41032 if ($isDecoratorNode2(node)) { 41033 $addUpdateTag2(HISTORY_MERGE_TAG2); 41034 const selection = $createNodeSelectionWith(node); 41035 $setSelection2(selection); 41036 return selection; 41037 } else { 41038 return false; 41039 } 41040 } 41041 #selectDecoratorNodeBeforeDeletion(backwards) { 41042 if (backwards && this.#removeEmptyListItem()) return true; 41043 const node = backwards ? this.nodeBeforeCursor : this.nodeAfterCursor; 41044 if (!$isDecoratorNode2(node)) return false; 41045 if (this.#collapseListItemToParagraph(node)) return true; 41046 this.#removeEmptyElementAnchorNode(); 41047 const selection = this.#selectInLexical(node); 41048 return Boolean(selection); 41049 } 41050 // When backspace is pressed on an empty list item that has siblings, 41051 // handle the deletion appropriately: 41052 // 41053 // - Middle/end items (has previous sibling): remove the empty item and 41054 // place the cursor at the end of the previous sibling. Without this, 41055 // Lexical's default collapseAtStart converts the empty item into a 41056 // paragraph above the list, causing the cursor to jump away. 41057 // 41058 // - First item (no previous sibling): convert to a paragraph above the 41059 // list, matching the standard "unwrap list formatting" behavior that 41060 // users expect from pressing backspace at the start of a list item. 41061 // Inside a blockquote we instead just remove the empty item and move 41062 // the cursor into the next one â stranding a paragraph there would 41063 // leave the blank line the user is trying to close. 41064 // 41065 // When the empty item is the last/only one in the list, we return false 41066 // and let Lexical's default (convert to paragraph) provide the standard 41067 // "exit list" behavior. 41068 #removeEmptyListItem() { 41069 const selection = $getSelection2(); 41070 if (!$isRangeSelection2(selection) || !selection.isCollapsed()) return false; 41071 const anchorNode = selection.anchor.getNode(); 41072 const listItem = $getNearestNodeOfType2(anchorNode, ListItemNode2); 41073 if (!listItem) return false; 41074 if (!$isListItemStructurallyEmpty(listItem)) return false; 41075 const nextSibling = listItem.getNextSibling(); 41076 if (!nextSibling) return false; 41077 const previousSibling = listItem.getPreviousSibling(); 41078 const listNode = $getNearestNodeOfType2(listItem, ListNode2); 41079 if (!listNode) return false; 41080 if (previousSibling) { 41081 previousSibling.selectEnd(); 41082 listItem.remove(); 41083 } else if ($isQuoteNode2(listNode.getParent())) { 41084 nextSibling.selectStart(); 41085 listItem.remove(); 41086 } else { 41087 const paragraph = $createParagraphNode2(); 41088 listNode.insertBefore(paragraph); 41089 listItem.remove(); 41090 paragraph.selectStart(); 41091 } 41092 return true; 41093 } 41094 // When the cursor is inside a list item, collapse the list item into a 41095 // paragraph instead of selecting the decorator. This lets the user 41096 // delete a list that immediately follows an attachment without the 41097 // attachment becoming selected. Only applies when the decorator is 41098 // outside the list item (e.g. a block attachment before the list), 41099 // not when it's an inline mention inside the list item. 41100 #collapseListItemToParagraph(decoratorNode) { 41101 const anchorNode = $getSelection2()?.anchor?.getNode(); 41102 const listItem = anchorNode && $getNearestNodeOfType2(anchorNode, ListItemNode2); 41103 if (!listItem) return false; 41104 if (listItem.isParentOf(decoratorNode)) return false; 41105 const listNode = $getNearestNodeOfType2(listItem, ListNode2); 41106 if (!listNode) return false; 41107 const paragraph = $createParagraphNode2(); 41108 const children = listItem.getChildren(); 41109 children.forEach((child) => paragraph.append(child)); 41110 if (listNode.getChildrenSize() === 1) { 41111 listNode.insertBefore(paragraph); 41112 listNode.remove(); 41113 } else { 41114 listNode.insertBefore(paragraph); 41115 listItem.remove(); 41116 } 41117 paragraph.selectStart(); 41118 return true; 41119 } 41120 #removeEmptyElementAnchorNode(anchor = $getSelection2()?.anchor) { 41121 const anchorNode = anchor?.getNode(); 41122 if ($isElementNode2(anchorNode) && anchorNode?.isEmpty()) anchorNode.remove(); 41123 } 41124 #getValidSelectionRange() { 41125 const lexicalSelection = $getSelection2(); 41126 if (!lexicalSelection || !lexicalSelection.isCollapsed()) return null; 41127 const nativeSelection = window.getSelection(); 41128 if (!nativeSelection || nativeSelection.rangeCount === 0) return null; 41129 return nativeSelection.getRangeAt(0); 41130 } 41131 #getReliableRectFromRange(range2) { 41132 let rect = range2.getBoundingClientRect(); 41133 if (this.#isRectUnreliable(rect)) { 41134 const marker = this.#createAndInsertMarker(range2); 41135 rect = marker.getBoundingClientRect(); 41136 this.#restoreSelectionAfterMarker(marker); 41137 marker.remove(); 41138 } 41139 return rect; 41140 } 41141 #isRectUnreliable(rect) { 41142 return rect.width === 0 && rect.height === 0 || rect.top === 0 && rect.left === 0; 41143 } 41144 #createAndInsertMarker(range2) { 41145 const marker = this.#createMarker(); 41146 range2.insertNode(marker); 41147 return marker; 41148 } 41149 #createMarker() { 41150 const marker = document.createElement("span"); 41151 marker.textContent = "\u200B"; 41152 marker.style.display = "inline-block"; 41153 marker.style.width = "1px"; 41154 marker.style.height = "1em"; 41155 marker.style.lineHeight = "normal"; 41156 marker.setAttribute("nonce", getNonce()); 41157 return marker; 41158 } 41159 #restoreSelectionAfterMarker(marker) { 41160 const nativeSelection = window.getSelection(); 41161 nativeSelection.removeAllRanges(); 41162 const newRange = document.createRange(); 41163 newRange.setStartAfter(marker); 41164 newRange.collapse(true); 41165 nativeSelection.addRange(newRange); 41166 } 41167 #calculateCursorPosition(rect, range2) { 41168 const rootRect = this.editor.getRootElement().getBoundingClientRect(); 41169 const x3 = rect.left - rootRect.left; 41170 let y3 = rect.top - rootRect.top; 41171 const fontSize = this.#getFontSizeForCursor(range2); 41172 if (!isNaN(fontSize)) { 41173 y3 += fontSize; 41174 } 41175 return { x: x3, y: y3, fontSize }; 41176 } 41177 #getFontSizeForCursor(range2) { 41178 const nativeSelection = window.getSelection(); 41179 const anchorNode = nativeSelection.anchorNode; 41180 const parentElement = this.#getElementFromNode(anchorNode); 41181 if (parentElement instanceof HTMLElement) { 41182 const computed2 = window.getComputedStyle(parentElement); 41183 return parseFloat(computed2.fontSize); 41184 } 41185 return 0; 41186 } 41187 #getElementFromNode(node) { 41188 return node?.nodeType === Node.TEXT_NODE ? node.parentElement : node; 41189 } 41190 #getCollapsedSelectionData() { 41191 const selection = $getSelection2(); 41192 if (!$isRangeSelection2(selection) || !selection.isCollapsed()) { 41193 return { anchorNode: null, offset: 0 }; 41194 } 41195 const { anchor } = selection; 41196 return { anchorNode: anchor.getNode(), offset: anchor.offset }; 41197 } 41198 #getNodeAfterTextNode(anchorNode, offset3) { 41199 if (offset3 === anchorNode.getTextContentSize()) { 41200 return this.#getNextNodeFromTextEnd(anchorNode); 41201 } 41202 return null; 41203 } 41204 #getNextNodeFromTextEnd(anchorNode) { 41205 const nextSibling = anchorNode.getNextSibling(); 41206 if ($isDecoratorNode2(nextSibling)) { 41207 return nextSibling; 41208 } 41209 if (nextSibling != null) { 41210 return null; 41211 } 41212 const parent = anchorNode.getParent(); 41213 return parent ? parent.getNextSibling() : null; 41214 } 41215 #getNodeAfterElementNode(anchorNode, offset3) { 41216 if (offset3 < anchorNode.getChildrenSize()) { 41217 return anchorNode.getChildAtIndex(offset3); 41218 } 41219 return this.#findNextSiblingUp(anchorNode); 41220 } 41221 #getNodeBeforeTextNode(anchorNode, offset3) { 41222 if (offset3 === 0) { 41223 return this.#getPreviousNodeFromTextStart(anchorNode); 41224 } 41225 return null; 41226 } 41227 #getPreviousNodeFromTextStart(anchorNode) { 41228 const previousSibling = anchorNode.getPreviousSibling(); 41229 if ($isDecoratorNode2(previousSibling)) { 41230 return previousSibling; 41231 } 41232 if (previousSibling != null) { 41233 return null; 41234 } 41235 const parent = anchorNode.getParent(); 41236 return parent ? parent.getPreviousSibling() : null; 41237 } 41238 #getNodeBeforeElementNode(anchorNode, offset3) { 41239 if (offset3 > 0) { 41240 return anchorNode.getChildAtIndex(offset3 - 1); 41241 } 41242 return this.#findPreviousSiblingUp(anchorNode); 41243 } 41244 #findNextSiblingUp(node) { 41245 let current = node; 41246 while (current && current.getNextSibling() == null) { 41247 current = current.getParent(); 41248 } 41249 return current ? current.getNextSibling() : null; 41250 } 41251 #findPreviousSiblingUp(node) { 41252 let current = node; 41253 while (current && current.getPreviousSibling() == null) { 41254 current = current.getParent(); 41255 } 41256 return current ? current.getPreviousSibling() : null; 41257 } 41258 #isCursorOnFirstVisualLineOfBlock(anchorNode) { 41259 return this.#isCursorOnEdgeLineOfBlock(anchorNode, "first"); 41260 } 41261 #isCursorOnLastVisualLineOfBlock(anchorNode) { 41262 return this.#isCursorOnEdgeLineOfBlock(anchorNode, "last"); 41263 } 41264 // Check whether the cursor sits on the first or last visual line of its 41265 // top-level block by comparing the Y position of the cursor with the Y 41266 // position of the block's start (first line) or end (last line). 41267 #isCursorOnEdgeLineOfBlock(anchorNode, edge) { 41268 const topLevelElement = anchorNode.getTopLevelElement(); 41269 if (!topLevelElement) return false; 41270 const domElement = this.editor.getElementByKey(topLevelElement.getKey()); 41271 if (!domElement) return false; 41272 const nativeSelection = window.getSelection(); 41273 if (!nativeSelection?.rangeCount) return false; 41274 const cursorRect = this.#getReliableRectFromRange(nativeSelection.getRangeAt(0)); 41275 if (!cursorRect || this.#isRectUnreliable(cursorRect)) return false; 41276 const edgeRect = this.#getEdgeCharRect(domElement, edge); 41277 if (!edgeRect || this.#isRectUnreliable(edgeRect)) return false; 41278 const tolerance = edgeRect.height > 0 ? edgeRect.height * 0.5 : 5; 41279 return Math.abs(cursorRect.top - edgeRect.top) < tolerance; 41280 } 41281 // Get a reliable bounding rect for the first or last character in a DOM 41282 // element by creating a non-collapsed range around it. 41283 #getEdgeCharRect(element, edge) { 41284 const walker = document.createTreeWalker( 41285 element, 41286 4 41287 /* NodeFilter.SHOW_TEXT */ 41288 ); 41289 let textNode; 41290 if (edge === "first") { 41291 textNode = walker.nextNode(); 41292 } else { 41293 while (walker.nextNode()) textNode = walker.currentNode; 41294 } 41295 if (!textNode || textNode.length === 0) return null; 41296 const range2 = document.createRange(); 41297 if (edge === "first") { 41298 range2.setStart(textNode, 0); 41299 range2.setEnd(textNode, 1); 41300 } else { 41301 range2.setStart(textNode, textNode.length - 1); 41302 range2.setEnd(textNode, textNode.length); 41303 } 41304 return range2.getBoundingClientRect(); 41305 } 41306 }; 41307 var EditorConfiguration = class { 41308 #editorElement; 41309 #config; 41310 constructor(editorElement) { 41311 this.#editorElement = editorElement; 41312 this.#config = new Configuration( 41313 Lexxy.presets.get("default"), 41314 Lexxy.presets.get(editorElement.preset), 41315 this.#overrides 41316 ); 41317 } 41318 get(path) { 41319 return this.#config.get(path); 41320 } 41321 get #overrides() { 41322 const overrides = {}; 41323 for (const option of this.#defaultOptions) { 41324 const attribute = dasherize(option); 41325 if (this.#editorElement.hasAttribute(attribute)) { 41326 overrides[option] = this.#parseAttribute(attribute); 41327 } 41328 } 41329 return overrides; 41330 } 41331 get #defaultOptions() { 41332 return Object.keys(Lexxy.presets.get("default")); 41333 } 41334 #parseAttribute(attribute) { 41335 const value = this.#editorElement.getAttribute(attribute); 41336 try { 41337 return JSON.parse(value); 41338 } catch { 41339 return value; 41340 } 41341 } 41342 }; 41343 var ImageGalleryNode = class _ImageGalleryNode extends ElementNode2 { 41344 $config() { 41345 return this.config("image_gallery", { 41346 extends: ElementNode2 41347 }); 41348 } 41349 static transform() { 41350 return (gallery) => { 41351 gallery.unwrapEmptyNode() || gallery.replaceWithSingularChild() || gallery.splitAroundInvalidChild(); 41352 }; 41353 } 41354 static importDOM() { 41355 return { 41356 div: (element) => { 41357 if (!this.#isGalleryElement(element)) return null; 41358 return { 41359 conversion: () => { 41360 return { 41361 node: $createImageGalleryNode() 41362 }; 41363 }, 41364 priority: 2 41365 }; 41366 } 41367 }; 41368 } 41369 static canCollapseWith(node) { 41370 return $isImageGalleryNode(node) || this.isValidChild(node); 41371 } 41372 static isValidChild(node) { 41373 return $isActionTextAttachmentNode(node) && node.isPreviewableImage; 41374 } 41375 static #isGalleryElement(element) { 41376 const attachmentChildren = element.querySelectorAll(`:scope > :is(${this.#attachmentTags.join()})`); 41377 return element.textContent.trim() === "" && attachmentChildren.length > 0 && element.children.length === attachmentChildren.length; 41378 } 41379 static get #attachmentTags() { 41380 return Object.keys(ActionTextAttachmentNode.importDOM()); 41381 } 41382 createDOM() { 41383 const div = document.createElement("div"); 41384 div.className = this.#galleryClassNames; 41385 return div; 41386 } 41387 updateDOM(_prevNode, dom) { 41388 dom.className = this.#galleryClassNames; 41389 return false; 41390 } 41391 canBeEmpty() { 41392 return true; 41393 } 41394 collapseAtStart(_selection) { 41395 return true; 41396 } 41397 insertNewAfter(selection, restoreSelection) { 41398 const selectionBeforeLastChild = selection.anchor.getNode().is(this) && selection.anchor.offset == this.getChildrenSize() - 1; 41399 if (selectionBeforeLastChild) { 41400 const paragraph = $createParagraphNode2(); 41401 this.insertAfter(paragraph, false); 41402 paragraph.insertAfter(this.getLastChild(), false); 41403 paragraph.selectEnd(); 41404 return null; 41405 } 41406 const newNode = $createImageGalleryNode(); 41407 this.insertAfter(newNode, restoreSelection); 41408 return newNode; 41409 } 41410 getImageAttachments() { 41411 const children = this.getChildren(); 41412 return children.filter($isActionTextAttachmentNode); 41413 } 41414 exportDOM() { 41415 const div = document.createElement("div"); 41416 div.className = this.#galleryClassNames; 41417 return { element: div }; 41418 } 41419 collapseWith(node, backwards) { 41420 if (!_ImageGalleryNode.canCollapseWith(node)) return false; 41421 if (backwards) { 41422 $insertFirst2(this, node); 41423 } else { 41424 this.append(node); 41425 } 41426 $unwrapAndFilterDescendants2(this, _ImageGalleryNode.isValidChild); 41427 return true; 41428 } 41429 unwrapEmptyNode() { 41430 if (this.isEmpty()) { 41431 const paragraph = $createParagraphNode2(); 41432 return this.replace(paragraph); 41433 } 41434 } 41435 replaceWithSingularChild() { 41436 if (this.#hasSingularChild) { 41437 const child = this.getFirstChild(); 41438 return this.replace($makeSafeForRoot(child)); 41439 } 41440 } 41441 splitAroundInvalidChild() { 41442 for (const child of $firstToLastIterator2(this)) { 41443 if (_ImageGalleryNode.isValidChild(child)) continue; 41444 const poppedNode = $makeSafeForRoot(child); 41445 const [topGallery, secondGallery] = this.splitAtIndex(poppedNode.getIndexWithinParent()); 41446 topGallery.insertAfter(poppedNode); 41447 poppedNode.selectEnd(); 41448 if (secondGallery.isEmpty()) secondGallery.remove(); 41449 break; 41450 } 41451 } 41452 splitAtIndex(index) { 41453 return $splitNode2(this, index); 41454 } 41455 get #hasSingularChild() { 41456 return this.getChildrenSize() === 1; 41457 } 41458 get #galleryClassNames() { 41459 return `attachment-gallery attachment-gallery--${this.getChildrenSize()}`; 41460 } 41461 }; 41462 function $createImageGalleryNode() { 41463 return new ImageGalleryNode(); 41464 } 41465 function $isImageGalleryNode(node) { 41466 return node instanceof ImageGalleryNode; 41467 } 41468 function $findOrCreateGalleryForImage(node) { 41469 if (!ImageGalleryNode.canCollapseWith(node)) return null; 41470 const existingGallery = $getNearestNodeOfType2(node, ImageGalleryNode); 41471 return existingGallery ?? $wrapNodeInElement2(node, $createImageGalleryNode); 41472 } 41473 var Uploader = class _Uploader { 41474 #files; 41475 static for(editorElement, files, options = {}) { 41476 const UploaderKlass = GalleryUploader.handle(editorElement, files) ? GalleryUploader : _Uploader; 41477 return new UploaderKlass(editorElement, files, options); 41478 } 41479 constructor(editorElement, files, options = {}) { 41480 this.#files = files; 41481 this.options = options; 41482 this.editorElement = editorElement; 41483 this.contents = editorElement.contents; 41484 this.selection = editorElement.selection; 41485 } 41486 get files() { 41487 return Array.from(this.#files); 41488 } 41489 $uploadFiles() { 41490 this.$createUploadNodes(); 41491 this.$insertUploadNodes(); 41492 } 41493 $createUploadNodes() { 41494 this.nodes = this.files.map((file) => this.#createUploadNode(file)); 41495 } 41496 #createUploadNode(file) { 41497 return this.options.pending ? this.contents.$createPendingUploadNode(file) : this.contents.$createUploadNode(file); 41498 } 41499 $insertUploadNodes() { 41500 this.contents.insertAtCursor(...this.nodes); 41501 } 41502 }; 41503 var GalleryUploader = class extends Uploader { 41504 #gallery; 41505 static handle(editorElement, files) { 41506 return this.isMultipleImageUpload(files) || this.gallerySelection(editorElement.selection); 41507 } 41508 static isMultipleImageUpload(files) { 41509 let imageFileCount = 0; 41510 for (const file of files) { 41511 if (isPreviewableImage(file.type)) imageFileCount++; 41512 if (imageFileCount > 1) return true; 41513 } 41514 return false; 41515 } 41516 static gallerySelection(selection) { 41517 return selection.isOnPreviewableImage || this.selectionIsAfterGalleryEdge(selection); 41518 } 41519 static selectionIsAfterGalleryEdge(selection) { 41520 return selection.isAtNodeStart && ImageGalleryNode.canCollapseWith(selection.nodeBeforeCursor); 41521 } 41522 $insertUploadNodes() { 41523 this.#findOrCreateGallery(); 41524 this.#insertImagesInGallery(); 41525 this.#insertNonImagesAfterGallery(); 41526 } 41527 #findOrCreateGallery() { 41528 if (this.selection.isOnPreviewableImage) { 41529 this.#gallery = $findOrCreateGalleryForImage(this.selection.previewableImageNode); 41530 } else if (this.#selectionIsAfterGalleryEdge) { 41531 this.#gallery = $findOrCreateGalleryForImage(this.selection.nodeBeforeCursor); 41532 } else { 41533 this.#gallery = $createImageGalleryNode(); 41534 this.contents.insertAtCursor(this.#gallery); 41535 } 41536 } 41537 get #selectionIsAfterGalleryEdge() { 41538 return this.constructor.selectionIsAfterGalleryEdge(this.selection); 41539 } 41540 get #selectedNode() { 41541 const { node } = this.selection.selectedNodeWithOffset(); 41542 return node; 41543 } 41544 get #galleryInsertPosition() { 41545 if (this.#selectionIsAfterGalleryEdge) return this.#gallery.getChildrenSize(); 41546 const anchor = $getSelection2()?.anchor; 41547 const galleryHasElementSelection = anchor?.getNode().is(this.#gallery); 41548 if (galleryHasElementSelection) return anchor.offset; 41549 const selectedNode = this.#selectedNode; 41550 const childIndex = this.#gallery.isParentOf(selectedNode) && selectedNode.getIndexWithinParent(); 41551 return childIndex !== false ? childIndex + 1 : 0; 41552 } 41553 get #imageNodes() { 41554 return this.nodes.filter((node) => ImageGalleryNode.isValidChild(node)); 41555 } 41556 get #nonImageNodes() { 41557 return this.nodes.filter((node) => !ImageGalleryNode.isValidChild(node)); 41558 } 41559 #insertImagesInGallery() { 41560 this.#gallery.splice(this.#galleryInsertPosition, 0, this.#imageNodes); 41561 } 41562 #insertNonImagesAfterGallery() { 41563 let beforeNode = this.#gallery; 41564 for (const node of this.#nonImageNodes) { 41565 beforeNode.insertAfter(node); 41566 beforeNode = node; 41567 } 41568 } 41569 }; 41570 async function loadFileIntoImage(file, image) { 41571 return new Promise((resolve) => { 41572 const reader = new FileReader(); 41573 image.addEventListener("load", () => { 41574 resolve(image); 41575 }); 41576 reader.onload = (event) => { 41577 image.src = event.target.result || null; 41578 }; 41579 reader.readAsDataURL(file); 41580 }); 41581 } 41582 var ActionTextAttachmentUploadNode = class _ActionTextAttachmentUploadNode extends ActionTextAttachmentNode { 41583 static getType() { 41584 return "action_text_attachment_upload"; 41585 } 41586 static clone(node) { 41587 return new _ActionTextAttachmentUploadNode({ ...node }, node.__key); 41588 } 41589 static importJSON(serializedNode) { 41590 return new _ActionTextAttachmentUploadNode({ ...serializedNode }); 41591 } 41592 // Should never run since this is a transient node. Defined to remove console warning. 41593 static importDOM() { 41594 return null; 41595 } 41596 constructor(node, key) { 41597 const { file, uploadUrl, blobUrlTemplate, progress, width, height, uploadError, fileName, contentType } = node; 41598 super({ ...node, contentType: file?.type ?? contentType }, key); 41599 this.file = file ?? null; 41600 this.fileName = file?.name ?? fileName; 41601 this.uploadUrl = uploadUrl; 41602 this.blobUrlTemplate = blobUrlTemplate; 41603 this.progress = progress ?? null; 41604 this.width = width; 41605 this.height = height; 41606 this.uploadError = uploadError; 41607 } 41608 createDOM() { 41609 if (this.uploadError) return this.createDOMForError(); 41610 this.#startUploadIfNeeded(); 41611 const canPreviewFile = this.isPreviewableAttachment && !this.isPdf && this.uploadUrl != null; 41612 const canPreviewAudio = this.isAudio && this.file && this.uploadUrl != null; 41613 const canPreviewPdf = this.isPdf && this.file && this.uploadUrl != null; 41614 const figure = this.createAttachmentFigure(canPreviewFile || canPreviewAudio || canPreviewPdf); 41615 if (canPreviewFile) { 41616 const img = figure.appendChild(this.#createDOMForImage()); 41617 loadFileIntoImage(this.file, img).then((img2) => this.#setDimensionsFromImage(img2)); 41618 } else if (canPreviewAudio) { 41619 figure.appendChild(this.#createDOMForAudio(URL.createObjectURL(this.file))); 41620 } else if (canPreviewPdf) { 41621 figure.appendChild(this.#createDOMForPdf(URL.createObjectURL(this.file))); 41622 } else { 41623 figure.appendChild(this.#createDOMForFile()); 41624 } 41625 figure.appendChild(this.#createCaption()); 41626 figure.appendChild(this.#createProgressBar()); 41627 return figure; 41628 } 41629 updateDOM(prevNode, dom) { 41630 if (this.uploadError !== prevNode.uploadError) return true; 41631 if (prevNode.progress !== this.progress) { 41632 const progress = dom.querySelector("progress"); 41633 progress.value = this.progress ?? 0; 41634 } 41635 return false; 41636 } 41637 exportDOM() { 41638 return { element: null }; 41639 } 41640 exportJSON() { 41641 return { 41642 ...super.exportJSON(), 41643 type: "action_text_attachment_upload", 41644 version: 1, 41645 fileName: this.fileName, 41646 contentType: this.contentType, 41647 uploadUrl: this.uploadUrl, 41648 blobUrlTemplate: this.blobUrlTemplate, 41649 progress: this.progress, 41650 width: this.width, 41651 height: this.height, 41652 uploadError: this.uploadError 41653 }; 41654 } 41655 get #uploadStarted() { 41656 return this.progress !== null; 41657 } 41658 #createDOMForImage() { 41659 return createElement("img"); 41660 } 41661 #createDOMForFile() { 41662 const extension = this.#getFileExtension(); 41663 const span = createElement("span", { className: "attachment__icon", textContent: extension }); 41664 return span; 41665 } 41666 #createDOMForAudio(src = this.src) { 41667 const audio = createElement("audio", { src, controls: true, preload: "metadata" }); 41668 const container = createElement("div", { className: "attachment__container" }); 41669 container.appendChild(audio); 41670 return container; 41671 } 41672 #createDOMForPdf(src) { 41673 const iframe = createElement("iframe", { 41674 src, 41675 title: this.fileName || "PDF", 41676 loading: "lazy" 41677 }); 41678 const container = createElement("div", { className: "attachment__container attachment__pdf-frame" }); 41679 container.appendChild(iframe); 41680 return container; 41681 } 41682 #getFileExtension() { 41683 return (this.fileName || "").split(".").pop().toLowerCase(); 41684 } 41685 #createCaption() { 41686 const figcaption = createElement("figcaption", { className: "attachment__caption" }); 41687 const nameSpan = createElement("span", { className: "attachment__name", textContent: this.caption || this.fileName || "" }); 41688 const sizeSpan = createElement("span", { className: "attachment__size", textContent: bytesToHumanSize(this.file?.size) }); 41689 figcaption.appendChild(nameSpan); 41690 figcaption.appendChild(sizeSpan); 41691 return figcaption; 41692 } 41693 #createProgressBar() { 41694 return createElement("progress", { value: this.progress ?? 0, max: 100 }); 41695 } 41696 #setDimensionsFromImage({ width, height }) { 41697 if (this.#hasDimensions) return; 41698 this.patchAndRewriteHistory({ width, height }); 41699 } 41700 get #hasDimensions() { 41701 return Boolean(this.width && this.height); 41702 } 41703 async #startUploadIfNeeded() { 41704 if (this.#uploadStarted) return; 41705 if (!this.uploadUrl) return; 41706 this.#setUploadStarted(); 41707 const { DirectUpload: DirectUpload3 } = await Promise.resolve().then(() => (init_activestorage_esm(), activestorage_esm_exports)); 41708 const upload = new DirectUpload3(this.file, this.uploadUrl, this); 41709 upload.delegate = this.#createUploadDelegate(); 41710 this.#dispatchEvent("lexxy:upload-start", { file: this.file }); 41711 upload.create((error, blob) => { 41712 this.#forgetUploadRequest(); 41713 if (error) { 41714 this.#dispatchEvent("lexxy:upload-end", { file: this.file, error }); 41715 this.#handleUploadError(error); 41716 } else { 41717 this.#dispatchEvent("lexxy:upload-end", { file: this.file, error: null }); 41718 this.editor.update(() => { 41719 this.$showUploadedAttachment(blob); 41720 }); 41721 } 41722 }); 41723 } 41724 #createUploadDelegate() { 41725 const shouldAuthenticateUploads = Lexxy.global.get("authenticatedUploads"); 41726 return { 41727 directUploadWillCreateBlobWithXHR: (request) => { 41728 if (shouldAuthenticateUploads) request.withCredentials = true; 41729 }, 41730 directUploadWillStoreFileWithXHR: (request) => { 41731 if (shouldAuthenticateUploads) request.withCredentials = true; 41732 this.#rememberUploadRequest(request); 41733 const uploadProgressHandler = (event) => this.#handleUploadProgress(event, request); 41734 request.upload.addEventListener("progress", uploadProgressHandler); 41735 } 41736 }; 41737 } 41738 #forgetUploadRequest() { 41739 this.#editorElement?.uploadRequests.forget(this.getKey()); 41740 } 41741 #rememberUploadRequest(request) { 41742 this.#editorElement?.uploadRequests.track(this.getKey(), request); 41743 } 41744 get #editorElement() { 41745 return this.editor.getRootElement()?.closest("lexxy-editor"); 41746 } 41747 #setUploadStarted() { 41748 this.#setProgress(1); 41749 } 41750 #handleUploadProgress(event, request) { 41751 const progress = Math.round(event.loaded / event.total * 100); 41752 try { 41753 this.#setProgress(progress); 41754 this.#dispatchEvent("lexxy:upload-progress", { file: this.file, progress }); 41755 } catch { 41756 request.abort(); 41757 } 41758 } 41759 #setProgress(progress) { 41760 this.patchAndRewriteHistory({ progress }); 41761 } 41762 #handleUploadError(error) { 41763 console.warn(`Upload error for ${this.file?.name ?? "file"}: ${error}`); 41764 this.patchAndRewriteHistory({ uploadError: true }); 41765 } 41766 $showUploadedAttachment(blob) { 41767 const previewSrc = this.isPreviewableImage && this.file ? URL.createObjectURL(this.file) : null; 41768 const replacementNode = this.#toActionTextAttachmentNodeWith(blob, previewSrc); 41769 this.replaceAndRewriteHistory(replacementNode); 41770 return replacementNode.getKey(); 41771 } 41772 #toActionTextAttachmentNodeWith(blob, previewSrc) { 41773 const conversion = new AttachmentNodeConversion(this, blob, previewSrc); 41774 return conversion.toAttachmentNode(); 41775 } 41776 #dispatchEvent(name, detail) { 41777 const figure = this.editor.getElementByKey(this.getKey()); 41778 if (figure) dispatch(figure, name, detail); 41779 } 41780 }; 41781 var AttachmentNodeConversion = class { 41782 constructor(uploadNode, blob, previewSrc) { 41783 this.uploadNode = uploadNode; 41784 this.blob = blob; 41785 this.previewSrc = previewSrc; 41786 } 41787 toAttachmentNode() { 41788 return new ActionTextAttachmentNode({ 41789 ...this.uploadNode, 41790 ...this.#propertiesFromBlob, 41791 src: this.#src, 41792 blobSrc: this.#pdfBlob ? this.#blobSrc : null, 41793 previewSrc: this.previewSrc, 41794 pendingPreview: this.blob.previewable && !this.uploadNode.isPreviewableImage && !this.#pdfBlob 41795 }); 41796 } 41797 get #propertiesFromBlob() { 41798 const { blob } = this; 41799 return { 41800 sgid: blob.attachable_sgid, 41801 altText: blob.filename, 41802 contentType: blob.content_type, 41803 fileName: blob.filename, 41804 fileSize: blob.byte_size, 41805 previewable: blob.previewable, 41806 previewStatusUrl: blob.preview_status_url 41807 }; 41808 } 41809 get #src() { 41810 return this.blob.previewable ? this.blob.url : this.#blobSrc; 41811 } 41812 get #blobSrc() { 41813 return this.uploadNode.blobUrlTemplate.replace(":signed_id", this.blob.signed_id).replace(":filename", encodeURIComponent(this.blob.filename)); 41814 } 41815 get #pdfBlob() { 41816 const contentType = this.blob.content_type || this.uploadNode.contentType || ""; 41817 const fileName = this.blob.filename || this.uploadNode.fileName || ""; 41818 return contentType === "application/pdf" || fileName.toLowerCase().endsWith(".pdf"); 41819 } 41820 }; 41821 function $createActionTextAttachmentUploadNode(...args) { 41822 return new ActionTextAttachmentUploadNode(...args); 41823 } 41824 var BaseNodeInserter = class { 41825 constructor(selection) { 41826 this.selection = selection; 41827 } 41828 }; 41829 var CodeNodeInserter = class extends BaseNodeInserter { 41830 static handles(selection) { 41831 return $getNearestNodeOfType2(selection.anchor?.getNode(), CodeNode3); 41832 } 41833 insertNodes(nodes) { 41834 if (!this.selection.isCollapsed()) { 41835 this.selection.removeText(); 41836 } 41837 $ensureForwardRangeSelection2(this.selection); 41838 const focusNode = this.selection.focus.getNode(); 41839 const codeNode = $getNearestNodeOfType2(focusNode, CodeNode3); 41840 const insertionIndex = focusNode.is(codeNode) ? 0 : focusNode.getIndexWithinParent(); 41841 const caret = $getChildCaretAtIndex2(codeNode, insertionIndex + 1, "previous"); 41842 const existingNodes = new Set(nodes.filter((node) => node.isAttached())); 41843 const trailingNodes = []; 41844 for (const node of nodes) { 41845 if (existingNodes.has(node)) { 41846 if (!node.isAttached()) continue; 41847 } else if (!this.#canJoinCodeBlock(node)) { 41848 trailingNodes.push(node); 41849 continue; 41850 } 41851 if (caret.getNodeAtCaret() && $isElementNode2(node)) { 41852 caret.insert($createLineBreakNode2()); 41853 } 41854 caret.insert(this.#convertNodeToCodeChild(node)); 41855 } 41856 const lastTrailingNode = this.#insertAfterCodeBlock(codeNode, trailingNodes); 41857 const nodeToSelect = lastTrailingNode ?? caret.getNodeAtCaret(); 41858 nodeToSelect?.selectEnd(); 41859 } 41860 #canJoinCodeBlock(node) { 41861 return $isTextNode2(node) || $isLineBreakNode2(node); 41862 } 41863 #insertAfterCodeBlock(codeNode, nodes) { 41864 let previousNode = codeNode; 41865 for (const node of nodes) { 41866 previousNode.insertAfter(node); 41867 previousNode = node; 41868 } 41869 return nodes.at(-1); 41870 } 41871 #convertNodeToCodeChild(node) { 41872 if ($isLineBreakNode2(node)) { 41873 return node; 41874 } else { 41875 node.remove(); 41876 return $createTextNode2(node.getTextContent()); 41877 } 41878 } 41879 }; 41880 var ShadowRootNodeInserter = class extends BaseNodeInserter { 41881 static handles(selection) { 41882 return $isShadowRoot(selection?.anchor?.getNode()); 41883 } 41884 insertNodes(nodes) { 41885 const anchorNode = this.selection.anchor.getNode(); 41886 const paragraph = $createParagraphNode2(); 41887 anchorNode.append(paragraph); 41888 paragraph.selectStart().insertNodes(nodes); 41889 } 41890 }; 41891 var NodeSelectionNodeInserter = class extends BaseNodeInserter { 41892 static handles(selection) { 41893 return $isNodeSelection2(selection) && selection.getNodes().length > 0; 41894 } 41895 insertNodes(nodes) { 41896 let lastNode = this.selection.getNodes().at(-1); 41897 for (const node of nodes) { 41898 const nodeToInsert = this.#insertsIntoRoot(lastNode) ? $makeSafeForRoot(node) : node; 41899 lastNode = lastNode.insertAfter(nodeToInsert); 41900 } 41901 } 41902 #insertsIntoRoot(node) { 41903 return node.is(node.getTopLevelElement()); 41904 } 41905 }; 41906 var ListItemNodeInserter = class extends BaseNodeInserter { 41907 static handles(selection) { 41908 return $isRangeSelection2(selection) && $getNearestNodeOfType2(selection.anchor.getNode(), ListItemNode2); 41909 } 41910 insertNodes(nodes) { 41911 if (nodes.some((node) => this.#isBlockDecorator(node))) { 41912 this.#insertAroundList(nodes); 41913 } else { 41914 this.selection.insertNodes(nodes); 41915 } 41916 } 41917 #insertAroundList(nodes) { 41918 if (!this.selection.isCollapsed()) { 41919 this.selection.removeText(); 41920 } 41921 const anchorNode = this.selection.anchor.getNode(); 41922 const outerList = this.#outermostList(anchorNode); 41923 const topItem = this.#topLevelItemFor(anchorNode, outerList); 41924 const splitAfterItem = $isBlankNode(topItem) ? topItem.getPreviousSibling() : topItem; 41925 const splitIndex = splitAfterItem ? splitAfterItem.getIndexWithinParent() + 1 : 0; 41926 const [listBefore, listAfter] = $splitNode2(outerList, splitIndex); 41927 if ($isBlankNode(topItem)) { 41928 topItem.remove(); 41929 } 41930 let anchor = listBefore ?? listAfter; 41931 for (const node of nodes) { 41932 anchor.insertAfter(node); 41933 anchor = node; 41934 } 41935 this.#removeEmptyList(listBefore); 41936 this.#removeEmptyList(listAfter); 41937 nodes.at(-1).selectNext(); 41938 } 41939 #outermostList(node) { 41940 return [node, ...node.getParents()].reverse().find($isListNode2); 41941 } 41942 #topLevelItemFor(node, outerList) { 41943 return [node, ...node.getParents()].find( 41944 (ancestor) => $isListItemNode2(ancestor) && ancestor.getParent()?.is(outerList) 41945 ); 41946 } 41947 #removeEmptyList(list) { 41948 if ($isListNode2(list) && list.isEmpty()) list.remove(); 41949 } 41950 // Only block decorator nodes (image/file attachments) are intercepted. A list 41951 // item cannot hold them, so they must break out. Pasted element blocks 41952 // (paragraphs, quotes) keep Lexical's own list-escape semantics. 41953 #isBlockDecorator(node) { 41954 return $isDecoratorNode2(node) && !node.isInline(); 41955 } 41956 }; 41957 var BlockContainerNodeInserter = class extends BaseNodeInserter { 41958 static handles(selection) { 41959 return $hasPointOnBlockContainer(selection); 41960 } 41961 insertNodes(nodes) { 41962 $normalizeSelection__EXPERIMENTAL(this.selection); 41963 this.selection.insertNodes(nodes); 41964 } 41965 }; 41966 var INSERTERS = [ 41967 CodeNodeInserter, 41968 ShadowRootNodeInserter, 41969 NodeSelectionNodeInserter, 41970 ListItemNodeInserter, 41971 BlockContainerNodeInserter 41972 ]; 41973 BaseNodeInserter.for = (selection) => { 41974 const inserterClass = INSERTERS.find((inserter) => inserter.handles(selection)); 41975 return inserterClass ? new inserterClass(selection) : selection; 41976 }; 41977 var PastedContentFormatter = class { 41978 constructor(doc) { 41979 this.doc = doc; 41980 } 41981 format() { 41982 this.#stripStyleElements(); 41983 this.#unwrapPlaceholderAnchors(); 41984 this.#stripTableCellColorStyles(); 41985 this.#nestStrayListChildren(); 41986 this.#stripStrayListChildren(); 41987 return this.doc; 41988 } 41989 // Spreadsheets (e.g. Excel) copy a <style> block whose rules (td { color: 41990 // black }, .xlNN { ... }) cascade onto the imported text. That color rides 41991 // in through the cascade rather than an inline style, so it slips past both 41992 // the cell-level stripping below and the paste style canonicalizer, leaving 41993 // pasted tables with foreign text colors that don't adapt to the theme. Drop 41994 // foreign style sheets so nothing cascades into imported content. 41995 #stripStyleElements() { 41996 for (const style of this.doc.querySelectorAll("style")) { 41997 style.remove(); 41998 } 41999 } 42000 // Anchors with non-meaningful hrefs (e.g. "#", "") appear in content copied 42001 // from rendered views where mentions and interactive elements are wrapped in 42002 // <a href="#"> tags. Unwrap them so their text content pastes as plain text 42003 // and real links are preserved. 42004 #unwrapPlaceholderAnchors() { 42005 for (const anchor of this.doc.querySelectorAll("a")) { 42006 const href = anchor.getAttribute("href") || ""; 42007 if (href === "" || href === "#") { 42008 anchor.replaceWith(...anchor.childNodes); 42009 } 42010 } 42011 } 42012 // Table cells copied from a page inherit the source theme's inline color 42013 // styles (e.g. dark-mode backgrounds). Strip them so pasted tables adopt 42014 // the current theme instead of carrying stale colors. 42015 #stripTableCellColorStyles() { 42016 for (const cell of this.doc.querySelectorAll("td, th")) { 42017 cell.style.removeProperty("background-color"); 42018 cell.style.removeProperty("background"); 42019 cell.style.removeProperty("color"); 42020 } 42021 } 42022 // Some sources (e.g. Gmail) nest a sublist as a direct child of the parent 42023 // <ol>/<ul> instead of inside a <li>. Move each nested list into its 42024 // preceding <li> so the import preserves the nesting instead of dropping it. 42025 #nestStrayListChildren() { 42026 for (const list of this.doc.querySelectorAll("ol, ul")) { 42027 for (const child of Array.from(list.children)) { 42028 if (child.tagName !== "OL" && child.tagName !== "UL") continue; 42029 const previousItem = child.previousElementSibling; 42030 if (previousItem && previousItem.tagName === "LI") { 42031 previousItem.appendChild(child); 42032 } 42033 } 42034 } 42035 } 42036 // Only <li> is a valid child of a list; drop stray <br>/whitespace so the 42037 // import doesn't wrap them into an empty leading item. 42038 #stripStrayListChildren() { 42039 for (const list of this.doc.querySelectorAll("ol, ul")) { 42040 for (const child of Array.from(list.childNodes)) { 42041 if (child.nodeType === Node.ELEMENT_NODE && child.tagName === "LI") continue; 42042 list.removeChild(child); 42043 } 42044 } 42045 } 42046 }; 42047 var Contents = class { 42048 constructor(editorElement) { 42049 this.editorElement = editorElement; 42050 this.editor = editorElement.editor; 42051 } 42052 dispose() { 42053 this.editorElement = null; 42054 this.editor = null; 42055 } 42056 get selection() { 42057 return this.editorElement.selection; 42058 } 42059 insertHtml(html2, { tag } = {}) { 42060 this.insertDOM(parseHtml(html2), { tag }); 42061 } 42062 insertDOM(doc, { tag } = {}) { 42063 this.editor.update(() => { 42064 if ($hasUpdateTag2(PASTE_TAG2)) this.#formatPastedDOM(doc); 42065 const nodes = this.editorElement.$generateNodesFromDOM(doc); 42066 if (!$hasUpdateTag2(PASTE_TAG2) || !this.#dispatchPastedNodesCommand(nodes)) { 42067 this.#insertUploadNodes(nodes) || this.insertAtCursor(...nodes); 42068 } 42069 }, { tag }); 42070 } 42071 insertText(text2, { tag } = {}) { 42072 this.editor.update(() => { 42073 const paragraph = $createParagraphNode2(); 42074 text2.split("\n").forEach((line, index) => { 42075 if (index > 0) paragraph.append($createLineBreakNode2()); 42076 paragraph.append($createTextNode2(line)); 42077 }); 42078 this.insertAtCursor(paragraph); 42079 }, { tag }); 42080 } 42081 insertAtCursor(...nodes) { 42082 const selection = this.#insertableSelection(); 42083 const inserter = BaseNodeInserter.for(selection); 42084 inserter.insertNodes(nodes); 42085 } 42086 applyParagraphFormat() { 42087 const selection = $getSelection2(); 42088 if (!$isRangeSelection2(selection)) return; 42089 $expandSelectionToLineBreaksAndSplitAtEdges(selection, (node) => $getNearestBlockElementAncestorOrThrow2(node)); 42090 $setBlocksType2(selection, () => $createParagraphNode2()); 42091 } 42092 applyHeadingFormat(tag) { 42093 const selection = $getSelection2(); 42094 if (!$isRangeSelection2(selection)) return; 42095 $expandSelectionToLineBreaksAndSplitAtEdges(selection, (node) => $getNearestBlockElementAncestorOrThrow2(node)); 42096 $setBlocksType2(selection, () => $createHeadingNode2(tag)); 42097 } 42098 applyUnorderedListFormat() { 42099 this.#applyListFormat("bullet", INSERT_UNORDERED_LIST_COMMAND2); 42100 } 42101 applyOrderedListFormat() { 42102 this.#applyListFormat("number", INSERT_ORDERED_LIST_COMMAND2); 42103 } 42104 clearFormatting() { 42105 const selection = $getSelection2(); 42106 if (!$isRangeSelection2(selection)) return; 42107 $forEachSelectedTextNode2((node) => { 42108 node.setFormat(0); 42109 node.setStyle(""); 42110 }); 42111 $toggleLink2(null); 42112 this.#topLevelElementsInSelection(selection).filter($isQuoteNode2).forEach((node) => this.#unwrap(node)); 42113 $setBlocksType2(selection, () => $createParagraphNode2()); 42114 } 42115 toggleCodeBlock() { 42116 const selection = $getSelection2(); 42117 if (!$isRangeSelection2(selection)) return; 42118 if (this.#insertNodeIfRoot($createCodeNode3("plain"))) return; 42119 const blockElements = this.#blockLevelElementsInSelection(selection); 42120 const allCode = blockElements.every($isCodeNode3); 42121 if (allCode) { 42122 blockElements.forEach((node) => this.#unwrapCodeBlock(node)); 42123 } else { 42124 $expandSelectionToLineBreaksAndSplitAtEdges(selection); 42125 const elements = this.#outermostElements(this.#blockLevelElementsInSelection(selection)); 42126 if (elements.length === 0) return; 42127 const codeNode = $createCodeNode3("plain"); 42128 elements.at(-1).insertAfter(codeNode); 42129 codeNode.selectEnd(); 42130 this.insertAtCursor(...elements); 42131 } 42132 } 42133 toggleBlockquote() { 42134 const selection = $getSelection2(); 42135 if (!$isRangeSelection2(selection)) return; 42136 if (this.#insertNodeIfRoot($createQuoteNode2())) return; 42137 const topLevelElements = this.#topLevelElementsInSelection(selection); 42138 const allQuoted = topLevelElements.length > 0 && topLevelElements.every($isQuoteNode2); 42139 if (allQuoted) { 42140 topLevelElements.forEach((node) => this.#unwrap(node)); 42141 } else { 42142 topLevelElements.filter($isQuoteNode2).forEach((node) => this.#unwrap(node)); 42143 $expandSelectionToLineBreaksAndSplitAtEdges(selection); 42144 const elements = this.#topLevelElementsInSelection(selection); 42145 if (elements.length === 0) return; 42146 const blockquote = $createQuoteNode2(); 42147 elements[0].insertBefore(blockquote); 42148 elements.forEach((element) => blockquote.append(element)); 42149 } 42150 } 42151 hasSelectedText() { 42152 let result = false; 42153 this.editor.read(() => { 42154 const selection = $getSelection2(); 42155 result = $isRangeSelection2(selection) && !selection.isCollapsed(); 42156 }); 42157 return result; 42158 } 42159 createLink(url) { 42160 let linkNodeKey = null; 42161 this.editor.update(() => { 42162 const textNode = $createTextNode2(url); 42163 const linkNode = $createLinkNode2(url); 42164 linkNode.append(textNode); 42165 const selection = $getSelection2(); 42166 if ($isRangeSelection2(selection)) { 42167 BaseNodeInserter.for(selection).insertNodes([linkNode]); 42168 linkNodeKey = linkNode.getKey(); 42169 } 42170 }); 42171 return linkNodeKey; 42172 } 42173 createLinkWithSelectedText(url) { 42174 if (!this.hasSelectedText()) return; 42175 this.editor.update(() => { 42176 $toggleLink2(null); 42177 $toggleLink2(url); 42178 }); 42179 } 42180 textBackUntil(string) { 42181 let result = ""; 42182 this.editor.getEditorState().read(() => { 42183 const selection = $getSelection2(); 42184 if (!selection || !selection.isCollapsed()) return; 42185 const anchor = selection.anchor; 42186 const anchorNode = anchor.getNode(); 42187 if (!$isTextNode2(anchorNode)) return; 42188 const fullText = anchorNode.getTextContent(); 42189 const offset3 = anchor.offset; 42190 const lastIndex = fullText.slice(0, offset3).lastIndexOf(string); 42191 if (lastIndex !== -1) { 42192 result = fullText.slice(lastIndex + string.length, this.#endOffsetAt(fullText, offset3)); 42193 } 42194 }); 42195 return result; 42196 } 42197 // The query runs from the trigger up to the next boundary, even when the 42198 // cursor sits inside an existing word â inserting "@" before "Jack" must 42199 // filter by "Jack" rather than treating the prompt as empty. 42200 #endOffsetAt(fullText, cursorOffset) { 42201 for (let offset3 = cursorOffset; offset3 < fullText.length; offset3++) { 42202 if (this.#isQueryBoundary(fullText, offset3)) { 42203 return offset3; 42204 } 42205 } 42206 return fullText.length; 42207 } 42208 // Whitespace always ends the query. Punctuation ends it too: with "@" typed 42209 // right before a period, extending across it would glue "." onto everything 42210 // typed ("B" would query "B."), matching the wrong names or nothing at all. 42211 // But punctuation joining two word characters is part of a name â "@" before 42212 // "Anne-Marie" or "O'Connor" must keep the whole name as the query. 42213 #isQueryBoundary(fullText, offset3) { 42214 const character = fullText[offset3]; 42215 if (/\s/.test(character)) return true; 42216 if (!/\p{P}/u.test(character)) return false; 42217 return !(this.#isWordCharacter(fullText[offset3 - 1]) && this.#isWordCharacter(fullText[offset3 + 1])); 42218 } 42219 #isWordCharacter(character) { 42220 return character != null && /[\p{L}\p{N}]/u.test(character); 42221 } 42222 containsTextBackUntil(string) { 42223 let result = false; 42224 this.editor.getEditorState().read(() => { 42225 const selection = $getSelection2(); 42226 if (!selection || !selection.isCollapsed()) return; 42227 const anchor = selection.anchor; 42228 const anchorNode = anchor.getNode(); 42229 if (!$isTextNode2(anchorNode)) return; 42230 const fullText = anchorNode.getTextContent(); 42231 const offset3 = anchor.offset; 42232 const textBeforeCursor = fullText.slice(0, offset3); 42233 result = textBeforeCursor.includes(string); 42234 }); 42235 return result; 42236 } 42237 replaceTextBackUntil(stringToReplace, replacementNodes) { 42238 replacementNodes = Array.isArray(replacementNodes) ? replacementNodes : [replacementNodes]; 42239 const { anchorNode, offset: offset3 } = this.#getTextAnchorData(); 42240 if (!anchorNode) return; 42241 const lastIndex = this.#findReplacementStart(anchorNode, offset3, stringToReplace); 42242 if (lastIndex === -1) return; 42243 this.#performTextReplacement(anchorNode, lastIndex, stringToReplace, replacementNodes); 42244 } 42245 uploadFiles(files, { selectLast } = {}) { 42246 if (!this.editorElement) return; 42247 if (!this.editorElement.supportsAttachments) { 42248 console.warn("This editor does not supports attachments (it's configured with [attachments=false])"); 42249 return; 42250 } 42251 const validFiles = Array.from(files).filter((file) => this.editorElement.acceptsFile(file)); 42252 this.editor.update(() => { 42253 const uploader = Uploader.for(this.editorElement, validFiles); 42254 uploader.$uploadFiles(); 42255 if (selectLast && uploader.nodes?.length) { 42256 const lastNode = uploader.nodes.at(-1); 42257 lastNode.selectEnd(); 42258 this.#normalizeSelectionInShadowRoot(); 42259 } 42260 }); 42261 } 42262 $createUploadNode(file) { 42263 return $createActionTextAttachmentUploadNode({ 42264 file, 42265 uploadUrl: this.editorElement.directUploadUrl, 42266 blobUrlTemplate: this.editorElement.blobUrlTemplate, 42267 contentType: file.type 42268 }); 42269 } 42270 $createPendingUploadNode(file) { 42271 return $createActionTextAttachmentUploadNode({ 42272 file, 42273 uploadUrl: null, 42274 blobUrlTemplate: this.editorElement.blobUrlTemplate, 42275 contentType: file.type 42276 }); 42277 } 42278 insertPendingAttachment(file) { 42279 if (!this.editorElement.supportsAttachments) return null; 42280 let nodeKey = null; 42281 this.editor.update(() => { 42282 const uploadNode = this.$createPendingUploadNode(file); 42283 this.insertAtCursor(uploadNode); 42284 nodeKey = uploadNode.getKey(); 42285 }); 42286 return nodeKey ? this.#pendingAttachmentHandle(nodeKey) : null; 42287 } 42288 insertPendingAttachments(files) { 42289 const fileList = Array.from(files); 42290 if (!this.editorElement.supportsAttachments || fileList.length === 0) return []; 42291 let nodeKeys = []; 42292 this.editor.update(() => { 42293 const uploader = Uploader.for(this.editorElement, fileList, { pending: true }); 42294 uploader.$uploadFiles(); 42295 nodeKeys = (uploader.nodes ?? []).map((node) => node.getKey()); 42296 }); 42297 return nodeKeys.map((nodeKey) => this.#pendingAttachmentHandle(nodeKey)); 42298 } 42299 #pendingAttachmentHandle(initialNodeKey) { 42300 const editor = this.editor; 42301 let nodeKey = initialNodeKey; 42302 return { 42303 setAttributes(blob) { 42304 editor.update(() => { 42305 const node = $getNodeByKey2(nodeKey); 42306 if (!(node instanceof ActionTextAttachmentUploadNode)) return; 42307 const replacementNodeKey = node.$showUploadedAttachment(blob); 42308 if (replacementNodeKey) { 42309 nodeKey = replacementNodeKey; 42310 } 42311 }, { tag: HISTORY_MERGE_TAG2 }); 42312 }, 42313 setUploadProgress(progress) { 42314 editor.update(() => { 42315 const node = $getNodeByKey2(nodeKey); 42316 if (!(node instanceof ActionTextAttachmentUploadNode)) return; 42317 node.getWritable().progress = progress; 42318 }, { tag: HISTORY_MERGE_TAG2 }); 42319 }, 42320 remove() { 42321 editor.update(() => { 42322 const node = $getNodeByKey2(nodeKey); 42323 if (node) node.remove(); 42324 }); 42325 } 42326 }; 42327 } 42328 replaceNodeWithHTML(nodeKey, html2, options = {}) { 42329 this.editor.update(() => { 42330 const node = $getNodeByKey2(nodeKey); 42331 if (!node) return; 42332 const selection = $getSelection2(); 42333 let wasSelected = false; 42334 if ($isRangeSelection2(selection)) { 42335 const selectedNodes = selection.getNodes(); 42336 wasSelected = selectedNodes.includes(node) || selectedNodes.some((n2) => n2.getParent() === node); 42337 if (wasSelected) { 42338 $setSelection2(null); 42339 } 42340 } 42341 const replacementNode = options.attachment ? this.#createCustomAttachmentNodeWithHtml(html2, options.attachment) : this.#createHtmlNodeWith(html2); 42342 node.replace(replacementNode); 42343 if (wasSelected) { 42344 replacementNode.selectEnd(); 42345 } 42346 }); 42347 } 42348 insertHTMLBelowNode(nodeKey, html2, options = {}) { 42349 this.editor.update(() => { 42350 const node = $getNodeByKey2(nodeKey); 42351 if (!node) return; 42352 const previousNode = node.getTopLevelElement() || node; 42353 const newNode = options.attachment ? this.#createCustomAttachmentNodeWithHtml(html2, options.attachment) : this.#createHtmlNodeWith(html2); 42354 previousNode.insertAfter(newNode); 42355 }); 42356 } 42357 #insertableSelection() { 42358 const selection = $getSelection2(); 42359 if ($isNodeSelection2(selection) && selection.getNodes().length === 0) { 42360 return $getRoot2().selectEnd(); 42361 } 42362 return selection ?? $getRoot2().selectEnd(); 42363 } 42364 #formatPastedDOM(doc) { 42365 new PastedContentFormatter(doc).format(); 42366 } 42367 #dispatchPastedNodesCommand(nodes) { 42368 return this.editor.dispatchCommand(SELECTION_INSERT_CLIPBOARD_NODES_COMMAND2, { 42369 nodes, 42370 selection: $getSelection2() 42371 }); 42372 } 42373 #insertNodeIfRoot(node) { 42374 const selection = $getSelection2(); 42375 if (!$isRangeSelection2(selection)) return false; 42376 const anchorNode = selection.anchor.getNode(); 42377 if ($isRootOrShadowRoot2(anchorNode)) { 42378 anchorNode.append(node); 42379 node.selectEnd(); 42380 return true; 42381 } 42382 return false; 42383 } 42384 #unwrapCodeBlock(codeNode) { 42385 const children = codeNode.getChildren(); 42386 const groups = [[]]; 42387 for (const child of children) { 42388 if ($isLineBreakNode2(child)) { 42389 groups.push([]); 42390 } else { 42391 groups[groups.length - 1].push(child.getTextContent()); 42392 } 42393 } 42394 for (const group of groups) { 42395 const paragraph = $createParagraphNode2(); 42396 const text2 = group.join(""); 42397 if (text2) { 42398 paragraph.append($createTextNode2(text2)); 42399 } 42400 codeNode.insertBefore(paragraph); 42401 } 42402 codeNode.remove(); 42403 } 42404 #applyListFormat(listType, command) { 42405 if (this.selection.isInsideBlockQuote) { 42406 this.#insertListInsideQuote(listType); 42407 } else { 42408 this.#splitParagraphsAtLineBreaksUnlessInsideList(); 42409 this.editor.dispatchCommand(command); 42410 } 42411 } 42412 #insertListInsideQuote(listType) { 42413 for (const group of $consecutiveSiblingGroups(this.#quotedBlocksInSelection())) { 42414 this.#wrapBlocksInList(group, listType); 42415 } 42416 } 42417 #quotedBlocksInSelection() { 42418 const selection = $getSelection2(); 42419 if (!$isRangeSelection2(selection)) return []; 42420 const blocks = this.#outermostElements(this.#blockLevelElementsInSelection(selection)); 42421 return blocks.filter((block) => $isQuoteNode2(block.getParent())); 42422 } 42423 #wrapBlocksInList(blocks, listType) { 42424 const list = $createListNode2(listType); 42425 blocks[0].insertBefore(list); 42426 for (const block of blocks) { 42427 const listItem = $createListItemNode2(); 42428 if ($isListNode2(block)) { 42429 listItem.append(...block.getChildren().flatMap((item) => item.getChildren())); 42430 } else { 42431 listItem.append(...block.getChildren()); 42432 } 42433 list.append(listItem); 42434 block.remove(); 42435 } 42436 } 42437 #splitParagraphsAtLineBreaksUnlessInsideList() { 42438 if (this.selection.isInsideList) return; 42439 const selection = $getSelection2(); 42440 if (!$isRangeSelection2(selection)) return; 42441 $expandSelectionToLineBreaksAndSplitAtEdges(selection); 42442 $splitSelectedParagraphsAtInnerLineBreaks(selection); 42443 } 42444 #blockLevelElementsInSelection(selection) { 42445 const blocks = /* @__PURE__ */ new Set(); 42446 for (const node of selection.getNodes()) { 42447 blocks.add($getNearestBlockElementAncestorOrThrow2(node)); 42448 } 42449 return Array.from(blocks); 42450 } 42451 #topLevelElementsInSelection(selection) { 42452 const elements = /* @__PURE__ */ new Set(); 42453 for (const node of selection.getNodes()) { 42454 const topLevel = node.getTopLevelElement(); 42455 if (topLevel) elements.add(topLevel); 42456 } 42457 return Array.from(elements); 42458 } 42459 // Selections spanning nested structures (a quote and its inner paragraphs, 42460 // nested list items) yield both an element and its ancestor. Converting the 42461 // ancestor detaches its whole subtree â including a node freshly inserted 42462 // inside it â which can leave the selection on removed nodes (Lexical 42463 // invariant #19). The outermost elements already cover their descendants' 42464 // text content, so keep only those. 42465 #outermostElements(elements) { 42466 return elements.filter((element) => { 42467 return elements.every((other) => other === element || !element.getParents().includes(other)); 42468 }); 42469 } 42470 #insertUploadNodes(nodes) { 42471 if (nodes.every($isActionTextAttachmentNode)) { 42472 const uploader = Uploader.for(this.editorElement, []); 42473 uploader.nodes = nodes; 42474 uploader.$insertUploadNodes(); 42475 return true; 42476 } 42477 } 42478 #unwrap(node) { 42479 const children = node.getChildren(); 42480 if (children.length == 0) { 42481 node.insertBefore($createParagraphNode2()); 42482 } else { 42483 children.forEach((child) => { 42484 if ($isTextNode2(child) && child.getTextContent().trim() !== "") { 42485 const newParagraph = $createParagraphNode2(); 42486 newParagraph.append(child); 42487 node.insertBefore(newParagraph); 42488 } else if (!$isLineBreakNode2(child)) { 42489 node.insertBefore(child); 42490 } 42491 }); 42492 } 42493 node.remove(); 42494 } 42495 #getTextAnchorData() { 42496 const selection = $getSelection2(); 42497 if (!selection || !selection.isCollapsed()) return { anchorNode: null, offset: 0 }; 42498 const anchor = selection.anchor; 42499 const anchorNode = anchor.getNode(); 42500 if (!$isTextNode2(anchorNode)) return { anchorNode: null, offset: 0 }; 42501 return { anchorNode, offset: anchor.offset }; 42502 } 42503 // The replaced span must start before the cursor but can extend past it 42504 // (e.g. "@Jack" when "@" was just inserted before "Jack"), so we bound the 42505 // match's start with lastIndexOf's fromIndex rather than slicing the text. 42506 #findReplacementStart(anchorNode, offset3, stringToReplace) { 42507 if (offset3 === 0) { 42508 return -1; 42509 } else { 42510 return anchorNode.getTextContent().lastIndexOf(stringToReplace, offset3 - 1); 42511 } 42512 } 42513 #performTextReplacement(anchorNode, startIndex, stringToReplace, replacementNodes) { 42514 const fullText = anchorNode.getTextContent(); 42515 const textBeforeString = fullText.slice(0, startIndex); 42516 const textAfterString = fullText.slice(startIndex + stringToReplace.length); 42517 const textNodeBefore = this.#cloneTextNodeFormatting(anchorNode, textBeforeString); 42518 const textNodeAfter = this.#cloneTextNodeFormatting(anchorNode, textAfterString || " "); 42519 anchorNode.replace(textNodeBefore); 42520 const lastInsertedNode = this.#insertReplacementNodes(textNodeBefore, replacementNodes); 42521 lastInsertedNode.insertAfter(textNodeAfter); 42522 this.#appendLineBreakIfNeeded(textNodeAfter.getParentOrThrow()); 42523 const cursorOffset = textAfterString ? 0 : 1; 42524 textNodeAfter.select(cursorOffset, cursorOffset); 42525 } 42526 #cloneTextNodeFormatting(anchorNode, text2) { 42527 return $createTextNode2(text2).setFormat(anchorNode.getFormat()).setDetail(anchorNode.getDetail()).setMode(anchorNode.getMode()).setStyle(anchorNode.getStyle()); 42528 } 42529 #insertReplacementNodes(startNode, replacementNodes) { 42530 let previousNode = startNode; 42531 for (const node of replacementNodes) { 42532 previousNode.insertAfter(node); 42533 previousNode = node; 42534 } 42535 return previousNode; 42536 } 42537 #appendLineBreakIfNeeded(paragraph) { 42538 if ($isParagraphNode2(paragraph) && this.editorElement.supportsMultiLine) { 42539 const children = paragraph.getChildren(); 42540 const last = children[children.length - 1]; 42541 const beforeLast = children[children.length - 2]; 42542 if ($isTextNode2(last) && last.getTextContent() === "" && (beforeLast && !$isTextNode2(beforeLast))) { 42543 paragraph.append($createLineBreakNode2()); 42544 } 42545 } 42546 } 42547 #createCustomAttachmentNodeWithHtml(html2, options = {}) { 42548 const attachmentConfig = typeof options === "object" ? options : {}; 42549 const contentType = attachmentConfig.contentType || "text/html"; 42550 if (!this.editorElement.permitsAttachmentContentType(contentType)) { 42551 return this.#createHtmlNodeWith(html2); 42552 } 42553 return new CustomActionTextAttachmentNode({ 42554 sgid: attachmentConfig.sgid || null, 42555 contentType, 42556 innerHtml: html2 42557 }); 42558 } 42559 #createHtmlNodeWith(html2) { 42560 const htmlNodes = this.editorElement.$generateNodesFromDOM(parseHtml(html2)); 42561 return htmlNodes[0] || $createParagraphNode2(); 42562 } 42563 // When the selection anchor is on a shadow root (e.g. a table cell), Lexical's 42564 // insertNodes can't find a block parent and fails silently. Normalize the 42565 // selection to point inside the shadow root's content instead. 42566 #normalizeSelectionInShadowRoot() { 42567 const selection = $getSelection2(); 42568 if (!$isRangeSelection2(selection)) return; 42569 const anchorNode = selection.anchor.getNode(); 42570 if (!$isShadowRoot(anchorNode)) return; 42571 const paragraph = $createParagraphNode2(); 42572 anchorNode.append(paragraph); 42573 paragraph.selectStart(); 42574 } 42575 }; 42576 var Clipboard = class { 42577 #listeners = new ListenerBin(); 42578 constructor(editorElement) { 42579 this.editorElement = editorElement; 42580 this.editor = editorElement.editor; 42581 this.contents = editorElement.contents; 42582 this.#registerPasteCommands(); 42583 } 42584 dispose() { 42585 this.editorElement = null; 42586 this.editor = null; 42587 this.contents = null; 42588 this.#listeners.dispose(); 42589 } 42590 paste(event) { 42591 const clipboardData = event.clipboardData; 42592 if (!clipboardData) return false; 42593 if (this.#isPastingIntoCodeBlock()) { 42594 this.#pastePlainTextIntoCodeBlock(clipboardData); 42595 event.preventDefault(); 42596 return true; 42597 } 42598 if (this.#isPlainTextOrURLPasted(clipboardData)) { 42599 this.#pastePlainTextOrURL(clipboardData); 42600 event.preventDefault(); 42601 return true; 42602 } 42603 const handled = this.#handlePastedFiles(clipboardData); 42604 if (handled) event.preventDefault(); 42605 return handled; 42606 } 42607 #registerPasteCommands() { 42608 this.#listeners.track( 42609 this.editor.registerCommand(PASTE_COMMAND2, this.paste.bind(this), COMMAND_PRIORITY_NORMAL2), 42610 this.editor.registerCommand( 42611 SELECTION_INSERT_CLIPBOARD_NODES_COMMAND2, 42612 (payload) => this.#handleParsedClipboardNodes(payload), 42613 COMMAND_PRIORITY_NORMAL2 42614 ) 42615 ); 42616 } 42617 #handleParsedClipboardNodes({ nodes, selection }) { 42618 const url = $bareUrlFromSingleLink(nodes); 42619 if (url && $isRangeSelection2(selection)) { 42620 this.#insertSingleLinkAt(selection, url); 42621 return true; 42622 } 42623 } 42624 #isPlainTextOrURLPasted(clipboardData) { 42625 return this.#isOnlyPlainTextPasted(clipboardData) || this.#isOnlyURLPasted(clipboardData) || this.#isSoloUrlWithHtml(clipboardData); 42626 } 42627 #isSoloUrlWithHtml(clipboardData) { 42628 if (!Array.from(clipboardData.types).includes("text/html")) return false; 42629 const text2 = clipboardData.getData("text/plain").trim(); 42630 return isAutolinkableURL(text2); 42631 } 42632 #isOnlyPlainTextPasted(clipboardData) { 42633 const types = Array.from(clipboardData.types); 42634 return types.length === 1 && types[0] === "text/plain"; 42635 } 42636 // Browsers expose a copied URL in several shapes: 42637 // Safari [ text/plain, text/uri-list ] 42638 // App ShareSheet [ text/uri-list ] 42639 // Chromium macOS [ text/plain, text/html, (?:text/link-preview) ] 42640 #isOnlyURLPasted(clipboardData) { 42641 if (this.#isLexicalClipboardData(clipboardData)) return false; 42642 const types = Array.from(clipboardData.types); 42643 if (types.includes("text/uri-list")) { 42644 return types.every((type) => type === "text/plain" || type === "text/uri-list"); 42645 } 42646 if (clipboardData.files.length) return false; 42647 const text2 = clipboardData.getData("text/plain").trim(); 42648 if (!isAutolinkableURL(text2)) return false; 42649 const html2 = clipboardData.getData("text/html"); 42650 return !html2 || this.#htmlIsBareLinkToURL(html2, text2); 42651 } 42652 #htmlIsBareLinkToURL(html2, url) { 42653 const doc = parseHtml(html2); 42654 if (doc.body.textContent.trim() !== url) return false; 42655 const links = doc.body.querySelectorAll("a"); 42656 if (links.length === 0) return true; 42657 return links.length === 1 && links[0].getAttribute("href") === url; 42658 } 42659 #isPastingIntoCodeBlock() { 42660 let result = false; 42661 this.editor.getEditorState().read(() => { 42662 const selection = $getSelection2(); 42663 if (!$isRangeSelection2(selection)) return; 42664 let currentNode = selection.anchor.getNode(); 42665 while (currentNode) { 42666 if ($isCodeNode3(currentNode)) { 42667 result = true; 42668 return; 42669 } 42670 currentNode = currentNode.getParent(); 42671 } 42672 }); 42673 return result; 42674 } 42675 #pastePlainTextIntoCodeBlock(clipboardData) { 42676 const text2 = clipboardData.getData("text/plain"); 42677 if (!text2) return; 42678 this.editor.update(() => { 42679 const selection = $getSelection2(); 42680 if ($isRangeSelection2(selection)) selection.insertRawText(text2); 42681 }, { tag: PASTE_TAG2 }); 42682 } 42683 #pastePlainTextOrURL(clipboardData) { 42684 const item = this.#plainTextOrURLItem(clipboardData); 42685 item.getAsString((text2) => { 42686 const url = text2.trim(); 42687 if (isAutolinkableURL(url)) { 42688 this.#pasteURL(url); 42689 } else if (this.editorElement.supportsMarkdown) { 42690 this.#pasteMarkdown(text2); 42691 } else { 42692 this.#pasteRichText(clipboardData); 42693 } 42694 }); 42695 } 42696 #plainTextOrURLItem(clipboardData) { 42697 const items = Array.from(clipboardData.items); 42698 return items.find((item) => item.type === "text/plain") || items.find((item) => item.type === "text/uri-list"); 42699 } 42700 #pasteURL(url) { 42701 if (this.contents.hasSelectedText()) { 42702 this.contents.createLinkWithSelectedText(url); 42703 } else { 42704 const nodeKey = this.contents.createLink(url); 42705 this.#dispatchLinkInsertEvent(nodeKey, { url }); 42706 } 42707 } 42708 #insertSingleLinkAt(selection, url) { 42709 if (!$isRangeSelection2(selection)) return; 42710 if (!selection.isCollapsed()) { 42711 $toggleLink2(null); 42712 $toggleLink2(url); 42713 return; 42714 } 42715 const linkNode = $createLinkNode2(url).append($createTextNode2(url)); 42716 BaseNodeInserter.for(selection).insertNodes([linkNode]); 42717 $onUpdate2(() => this.#dispatchLinkInsertEvent(linkNode.getKey(), { url })); 42718 } 42719 #dispatchLinkInsertEvent(nodeKey, payload) { 42720 const linkManipulationMethods = { 42721 replaceLinkWith: (html2, options) => this.contents.replaceNodeWithHTML(nodeKey, html2, options), 42722 insertBelowLink: (html2, options) => this.contents.insertHTMLBelowNode(nodeKey, html2, options) 42723 }; 42724 dispatch(this.editorElement, "lexxy:insert-link", { 42725 ...payload, 42726 ...linkManipulationMethods 42727 }); 42728 } 42729 #pasteMarkdown(text2) { 42730 const html2 = k(text2, { breaks: true }); 42731 const doc = parseHtml(html2); 42732 if (this.#isPlainTextWithoutMarkdown(doc)) { 42733 this.contents.insertText(text2, { tag: PASTE_TAG2 }); 42734 } else { 42735 const detail = Object.freeze({ 42736 markdown: text2, 42737 document: doc, 42738 addBlockSpacing: () => addBlockSpacing(doc) 42739 }); 42740 dispatch(this.editorElement, "lexxy:insert-markdown", detail); 42741 this.contents.insertDOM(doc, { tag: PASTE_TAG2 }); 42742 } 42743 } 42744 // Markdown conversion collapses runs of whitespace and unescapes backslashes, 42745 // silently corrupting plain text such as Windows/UNC file paths. When the text 42746 // carries no Markdown structure, paste it verbatim instead. A path that wrapped 42747 // across lines renders as a single paragraph with <br> line breaks (marked runs 42748 // with breaks: true), which is still plain text we should preserve untouched. 42749 #isPlainTextWithoutMarkdown(doc) { 42750 const elements = Array.from(doc.body.children); 42751 if (elements.length !== 1) return false; 42752 const paragraph = elements[0]; 42753 return paragraph.nodeName === "P" && Array.from(paragraph.childNodes).every((node) => node.nodeType === Node.TEXT_NODE || node.nodeName === "BR"); 42754 } 42755 #pasteRichText(clipboardData) { 42756 this.editor.update(() => { 42757 const selection = $getSelection2(); 42758 $insertDataTransferForRichText2(clipboardData, selection, this.editor); 42759 }, { tag: PASTE_TAG2 }); 42760 } 42761 #handlePastedFiles(clipboardData) { 42762 if (!this.editorElement.supportsAttachments) return false; 42763 const html2 = clipboardData.getData("text/html"); 42764 const files = clipboardData.files; 42765 if (files.length && this.#isCopiedImageHTML(html2)) { 42766 this.#uploadFilesPreservingScroll(files); 42767 return true; 42768 } 42769 if (html2 && !this.#isLexicalClipboardData(clipboardData)) { 42770 this.contents.insertHtml(html2, { tag: PASTE_TAG2 }); 42771 return true; 42772 } 42773 if (files.length) { 42774 this.#uploadFilesPreservingScroll(files); 42775 return true; 42776 } 42777 return false; 42778 } 42779 #isLexicalClipboardData(clipboardData) { 42780 return Array.from(clipboardData.types).includes("application/x-lexical-editor"); 42781 } 42782 #isCopiedImageHTML(html2) { 42783 if (!html2) return false; 42784 const doc = parseHtml(html2); 42785 const elementChildren = Array.from(doc.body.children); 42786 return elementChildren.length === 1 && elementChildren[0].tagName === "IMG"; 42787 } 42788 #uploadFilesPreservingScroll(files) { 42789 this.#preservingScrollPosition(() => { 42790 if (files.length) { 42791 this.contents.uploadFiles(files, { selectLast: true }); 42792 } 42793 }); 42794 } 42795 // Deals with an issue in Safari where it scrolls to the tops after pasting attachments 42796 async #preservingScrollPosition(callback) { 42797 const scrollY = window.scrollY; 42798 const scrollX = window.scrollX; 42799 callback(); 42800 await nextFrame(); 42801 window.scrollTo(scrollX, scrollY); 42802 this.editor.focus(); 42803 } 42804 }; 42805 function $bareUrlFromSingleLink(nodes) { 42806 if (nodes.length !== 1) return null; 42807 const node = nodes[0]; 42808 if ($isLinkNode2(node)) return $bareUrlFromLink(node); 42809 if ($isParagraphNode2(node)) { 42810 const children = node.getChildren(); 42811 if (children.length === 1 && $isLinkNode2(children[0])) { 42812 return $bareUrlFromLink(children[0]); 42813 } 42814 } 42815 return null; 42816 } 42817 function $bareUrlFromLink(linkNode) { 42818 const url = linkNode.getURL(); 42819 if (!url) return null; 42820 return linkNode.getTextContent() === url ? url : null; 42821 } 42822 var Extensions = class { 42823 constructor(lexxyElement) { 42824 this.lexxyElement = lexxyElement; 42825 this.enabledExtensions = this.#initializeExtensions(); 42826 } 42827 get lexicalExtensions() { 42828 return this.enabledExtensions.map((ext) => ext.lexicalExtension).filter(Boolean); 42829 } 42830 initializeToolbars() { 42831 const toolbar = this.#lexxyToolbar; 42832 if (!toolbar) return; 42833 this.#clearPreviousExtensionToolbarButtons(toolbar); 42834 this.#addExtensionToolbarButtons(toolbar); 42835 toolbar.requestOverflowRefresh(); 42836 } 42837 dispose() { 42838 while (this.enabledExtensions.length) { 42839 this.enabledExtensions.pop().dispose(); 42840 } 42841 } 42842 #clearPreviousExtensionToolbarButtons(toolbar) { 42843 toolbar.querySelectorAll("[data-lexxy-extension]").forEach((el) => el.remove()); 42844 } 42845 #addExtensionToolbarButtons(toolbar) { 42846 this.enabledExtensions.forEach((ext) => { 42847 const childrenBefore = new Set(toolbar.children); 42848 ext.initializeToolbar(toolbar); 42849 for (const child of toolbar.children) { 42850 if (!childrenBefore.has(child)) { 42851 child.setAttribute("data-lexxy-extension", ""); 42852 } 42853 } 42854 }); 42855 } 42856 get allowedElements() { 42857 return this.enabledExtensions.flatMap((ext) => ext.allowedElements); 42858 } 42859 get #lexxyToolbar() { 42860 return this.lexxyElement.toolbar; 42861 } 42862 get #baseExtensions() { 42863 return this.lexxyElement.baseExtensions; 42864 } 42865 get #configuredExtensions() { 42866 return Lexxy.global.get("extensions"); 42867 } 42868 #initializeExtensions() { 42869 const extensionDefinitions = this.#baseExtensions.concat(this.#configuredExtensions); 42870 return extensionDefinitions.map( 42871 (extension) => new extension(this.lexxyElement) 42872 ).filter((extension) => extension.enabled); 42873 } 42874 }; 42875 var BrowserAdapter = class { 42876 frozenLinkKey = null; 42877 dispatchAttributesChange(attributes, linkHref, highlight, headingTag) { 42878 } 42879 dispatchEditorInitialized(detail) { 42880 } 42881 freeze() { 42882 } 42883 thaw() { 42884 } 42885 unlinkFrozenNode() { 42886 return false; 42887 } 42888 }; 42889 function exportTextNodeDOM(editor, textNode) { 42890 const element = textNode.createDOM(editor._config, editor); 42891 element.style.whiteSpace = "pre-wrap"; 42892 if (textNode.hasFormat("lowercase")) { 42893 element.style.textTransform = "lowercase"; 42894 } else if (textNode.hasFormat("uppercase")) { 42895 element.style.textTransform = "uppercase"; 42896 } else if (textNode.hasFormat("capitalize")) { 42897 element.style.textTransform = "capitalize"; 42898 } 42899 let result = element; 42900 if (textNode.hasFormat("bold") && !containsTag(element, "strong")) { 42901 result = wrapWith(result, "b"); 42902 } 42903 if (textNode.hasFormat("italic") && !containsTag(element, "em")) { 42904 result = wrapWith(result, "i"); 42905 } 42906 if (textNode.hasFormat("strikethrough")) { 42907 result = wrapWith(result, "s"); 42908 } 42909 if (textNode.hasFormat("underline")) { 42910 result = wrapWith(result, "u"); 42911 } 42912 return { element: unwrapSpans(result) }; 42913 } 42914 function containsTag(element, tagName) { 42915 const upperTag = tagName.toUpperCase(); 42916 if (element.tagName === upperTag) return true; 42917 return element.querySelector(tagName) !== null; 42918 } 42919 function wrapWith(element, tag) { 42920 const wrapper = document.createElement(tag); 42921 wrapper.appendChild(element); 42922 return wrapper; 42923 } 42924 function unwrapSpans(element) { 42925 if (element.tagName === "SPAN") return element.firstChild; 42926 for (const span of element.querySelectorAll("span")) { 42927 span.replaceWith(...span.childNodes); 42928 } 42929 return element; 42930 } 42931 var ProvisionalParagraphNode = class _ProvisionalParagraphNode extends ParagraphNode2 { 42932 $config() { 42933 return this.config("provisonal_paragraph", { 42934 extends: ParagraphNode2, 42935 importDOM: () => null, 42936 $transform: (node) => { 42937 node.concretizeIfEdited(node); 42938 node.removeUnlessRequired(node); 42939 } 42940 }); 42941 } 42942 static neededBetween(nodeBefore, nodeAfter) { 42943 return !$isSelectableElement(nodeBefore, "next") && !$isSelectableElement(nodeAfter, "previous"); 42944 } 42945 createDOM(editor) { 42946 const p2 = super.createDOM(editor); 42947 const selected = this.isSelected($getSelection2()); 42948 p2.classList.add("provisional-paragraph"); 42949 p2.classList.toggle("hidden", !selected); 42950 return p2; 42951 } 42952 updateDOM(_prevNode, dom) { 42953 const selected = this.isSelected($getSelection2()); 42954 dom.classList.toggle("hidden", !selected); 42955 return false; 42956 } 42957 getTextContent() { 42958 return ""; 42959 } 42960 exportDOM() { 42961 return { 42962 element: null 42963 }; 42964 } 42965 // override as Lexical has an interesting view of collapsed selection in ElementNodes 42966 // https://github.com/facebook/lexical/blob/f1e4f66014377b1f2595aec2b0ee17f5b7ef4dfc/packages/lexical/src/LexicalNode.ts#L646 42967 isSelected(selection = null) { 42968 const targetSelection = selection || $getSelection2(); 42969 if (!targetSelection) return false; 42970 if (targetSelection.getNodes().some((node) => node.is(this) || this.isParentOf(node))) return true; 42971 if ($isRangeSelection2(targetSelection) && targetSelection.isCollapsed()) { 42972 const { anchor } = targetSelection; 42973 const parent = this.getParent(); 42974 if (parent && anchor.getNode().is(parent) && anchor.type === "element") { 42975 const index = this.getIndexWithinParent(); 42976 return anchor.offset === index || anchor.offset === index + 1; 42977 } 42978 } 42979 return false; 42980 } 42981 removeUnlessRequired(self2 = this.getLatest()) { 42982 if (!self2.required) self2.remove(); 42983 } 42984 concretizeIfEdited(self2 = this.getLatest()) { 42985 if (self2.getTextContentSize() > 0) { 42986 self2.replace($createParagraphNode2(), true); 42987 } 42988 } 42989 get required() { 42990 return this.isDirectRootChild && _ProvisionalParagraphNode.neededBetween(...this.immediateSiblings); 42991 } 42992 get isDirectRootChild() { 42993 const parent = this.getParent(); 42994 return $isRootOrShadowRoot2(parent); 42995 } 42996 get immediateSiblings() { 42997 return [this.getPreviousSibling(), this.getNextSibling()]; 42998 } 42999 }; 43000 function $isProvisionalParagraphNode(node) { 43001 return node instanceof ProvisionalParagraphNode; 43002 } 43003 function $isSelectableElement(node, direction) { 43004 return $isElementNode2(node) && (direction === "next" ? node.canInsertTextBefore() : node.canInsertTextAfter()); 43005 } 43006 var ProvisionalParagraphExtension = class extends LexxyExtension { 43007 get lexicalExtension() { 43008 return defineExtension2({ 43009 name: "lexxy/provisional-paragraph", 43010 nodes: [ 43011 ProvisionalParagraphNode 43012 ], 43013 register(editor) { 43014 return mergeRegister3( 43015 // Process Provisional Paragraph Nodes on RootNode changes as sibling status influences whether 43016 // they are required and their visible/hidden status 43017 editor.registerNodeTransform(RootNode2, $insertRequiredProvisionalParagraphs), 43018 editor.registerNodeTransform(RootNode2, $removeUnneededProvisionalParagraphs), 43019 editor.registerCommand(SELECTION_CHANGE_COMMAND2, $markAllProvisionalParagraphsDirty, COMMAND_PRIORITY_HIGH2) 43020 ); 43021 } 43022 }); 43023 } 43024 }; 43025 function $insertRequiredProvisionalParagraphs(rootNode) { 43026 const nodeBeforeRootSelection = $nodeBeforeRootSelection(rootNode); 43027 const firstNode = rootNode.getFirstChild(); 43028 if (ProvisionalParagraphNode.neededBetween(null, firstNode)) { 43029 $insertFirst2(rootNode, new ProvisionalParagraphNode()); 43030 } 43031 for (const node of $firstToLastIterator2(rootNode)) { 43032 const nextNode = node.getNextSibling(); 43033 if (ProvisionalParagraphNode.neededBetween(node, nextNode)) { 43034 node.insertAfter(new ProvisionalParagraphNode()); 43035 if (node.is(nodeBeforeRootSelection)) node.selectNext(); 43036 } 43037 } 43038 } 43039 function $nodeBeforeRootSelection(rootNode) { 43040 const selection = $getSelection2(); 43041 if (!$isRootOrShadowRoot2(selection?.anchor?.getNode())) return null; 43042 return rootNode.getChildAtIndex(selection.anchor.offset - 1); 43043 } 43044 function $removeUnneededProvisionalParagraphs(rootNode) { 43045 for (const provisionalParagraph of $getAllProvisionalParagraphs(rootNode)) { 43046 provisionalParagraph.removeUnlessRequired(); 43047 } 43048 } 43049 function $markAllProvisionalParagraphsDirty() { 43050 $addUpdateTag2(HISTORY_MERGE_TAG2); 43051 for (const provisionalParagraph of $getAllProvisionalParagraphs()) { 43052 provisionalParagraph.markDirty(); 43053 } 43054 } 43055 function $getAllProvisionalParagraphs(rootNode = $getRoot2()) { 43056 return $descendantsMatching2(rootNode.getChildren(), $isProvisionalParagraphNode); 43057 } 43058 var CodeHighlightingExtension = class extends LexxyExtension { 43059 get enabled() { 43060 return this.editorElement.supportsRichText; 43061 } 43062 get lexicalExtension() { 43063 return defineExtension2({ 43064 name: "lexxy/code-highlighting", 43065 register(editor) { 43066 return registerCodeHighlighting4(editor, buildHighlightPreservingTokenizer(editor)); 43067 } 43068 }); 43069 } 43070 }; 43071 var TRIX_LANGUAGE_ATTR = "language"; 43072 var TrixContentExtension = class extends LexxyExtension { 43073 get enabled() { 43074 return this.editorElement.supportsRichText; 43075 } 43076 get lexicalExtension() { 43077 return defineExtension2({ 43078 name: "lexxy/trix-content", 43079 html: { 43080 import: { 43081 em: (element) => onlyStyledElements(element, { 43082 conversion: extendTextNodeConversion("i", $applyHighlightStyle), 43083 priority: 1 43084 }), 43085 span: (element) => onlyStyledElements(element, { 43086 conversion: extendTextNodeConversion("mark", $applyHighlightStyle), 43087 priority: 1 43088 }), 43089 strong: (element) => onlyStyledElements(element, { 43090 conversion: extendTextNodeConversion("b", $applyHighlightStyle), 43091 priority: 1 43092 }), 43093 del: () => ({ 43094 conversion: extendTextNodeConversion("s", $applyStrikethrough, $applyHighlightStyle), 43095 priority: 1 43096 }), 43097 pre: (element) => onlyPreLanguageElements(element, { 43098 conversion: extendConversion(CodeNode3, "pre", $applyLanguage), 43099 priority: 1 43100 }) 43101 } 43102 } 43103 }); 43104 } 43105 }; 43106 function onlyStyledElements(element, conversion) { 43107 const elementHighlighted = element.style.color !== "" || element.style.backgroundColor !== ""; 43108 return elementHighlighted ? conversion : null; 43109 } 43110 function $applyStrikethrough(textNode) { 43111 if (!textNode.hasFormat("strikethrough")) textNode.toggleFormat("strikethrough"); 43112 return textNode; 43113 } 43114 function onlyPreLanguageElements(element, conversion) { 43115 return element.hasAttribute(TRIX_LANGUAGE_ATTR) ? conversion : null; 43116 } 43117 function $applyLanguage(conversionOutput, element) { 43118 const language = normalizeCodeLang2(element.getAttribute(TRIX_LANGUAGE_ATTR)); 43119 conversionOutput.node.setLanguage(language); 43120 } 43121 var WrappedTableNode = class extends TableNode2 { 43122 $config() { 43123 return this.config("wrapped_table_node", { extends: TableNode2 }); 43124 } 43125 static importDOM() { 43126 return super.importDOM(); 43127 } 43128 canInsertTextBefore() { 43129 return false; 43130 } 43131 canInsertTextAfter() { 43132 return false; 43133 } 43134 exportDOM(editor) { 43135 const superExport = super.exportDOM(editor); 43136 return { 43137 ...superExport, 43138 after: (tableElement) => { 43139 if (superExport.after) { 43140 tableElement = superExport.after(tableElement); 43141 const clonedTable = tableElement.cloneNode(true); 43142 const wrappedTable = createElement("figure", { className: "lexxy-content__table-wrapper" }, clonedTable.outerHTML); 43143 return wrappedTable; 43144 } 43145 return tableElement; 43146 } 43147 }; 43148 } 43149 }; 43150 var TablesExtension = class extends LexxyExtension { 43151 get enabled() { 43152 return this.editorElement.supportsRichText; 43153 } 43154 get allowedElements() { 43155 return ["figure", "tbody"]; 43156 } 43157 get lexicalExtension() { 43158 return defineExtension2({ 43159 name: "lexxy/tables", 43160 nodes: [ 43161 WrappedTableNode, 43162 { 43163 replace: TableNode2, 43164 with: () => new WrappedTableNode(), 43165 withKlass: WrappedTableNode 43166 }, 43167 TableCellNode2, 43168 TableRowNode2 43169 ], 43170 register(editor) { 43171 setScrollableTablesActive2(editor, true); 43172 return mergeRegister3( 43173 registerTablePlugin2(editor), 43174 // Lexxy registers extensions before setRootElement(), but table 43175 // drag-selection needs a root before wiring its pointer handlers. 43176 editor.registerRootListener((rootElement) => { 43177 if (rootElement) { 43178 return registerTableSelectionObserver2(editor, true); 43179 } 43180 }), 43181 // A table in Lexxy is a Lexxy table: cell shading can't be set in the 43182 // editor, so any cell background only ever comes from foreign content 43183 // (pasted spreadsheets, loaded documents). Normalize every cell to no 43184 // background so it adopts the current theme. This also clears 43185 // Lexical's hardcoded default header background (Lexical #8089). 43186 editor.registerNodeTransform(TableCellNode2, (node) => { 43187 if (node.getBackgroundColor() !== "") { 43188 node.setBackgroundColor(""); 43189 } 43190 }), 43191 // Bug fix: Fix column header states (Lexical #8090) 43192 editor.registerNodeTransform(TableCellNode2, (node) => { 43193 const headerState = node.getHeaderStyles(); 43194 if (headerState !== TableCellHeaderStates2.ROW) return; 43195 const rowParent = node.getParent(); 43196 const tableNode = rowParent?.getParent(); 43197 if (!tableNode) return; 43198 const rows = tableNode.getChildren(); 43199 const cellIndex = rowParent.getChildren().indexOf(node); 43200 const cellsInRow = rowParent.getChildren(); 43201 const isHeaderRow = cellsInRow.every( 43202 (cell) => cell.getHeaderStyles() !== TableCellHeaderStates2.NO_STATUS 43203 ); 43204 const isHeaderColumn = rows.every((row) => { 43205 const cell = row.getChildren()[cellIndex]; 43206 return cell && cell.getHeaderStyles() !== TableCellHeaderStates2.NO_STATUS; 43207 }); 43208 let newHeaderState = TableCellHeaderStates2.NO_STATUS; 43209 if (isHeaderRow) newHeaderState |= TableCellHeaderStates2.ROW; 43210 if (isHeaderColumn) newHeaderState |= TableCellHeaderStates2.COLUMN; 43211 if (newHeaderState !== headerState) { 43212 node.setHeaderStyles(newHeaderState, TableCellHeaderStates2.BOTH); 43213 } 43214 }), 43215 editor.registerCommand("insertTableRowAfter", () => { 43216 $insertTableRowAtSelection2(true); 43217 }, COMMAND_PRIORITY_NORMAL2), 43218 editor.registerCommand("insertTableRowBefore", () => { 43219 $insertTableRowAtSelection2(false); 43220 }, COMMAND_PRIORITY_NORMAL2), 43221 editor.registerCommand("insertTableColumnAfter", () => { 43222 $insertTableColumnAtSelection2(true); 43223 }, COMMAND_PRIORITY_NORMAL2), 43224 editor.registerCommand("insertTableColumnBefore", () => { 43225 $insertTableColumnAtSelection2(false); 43226 }, COMMAND_PRIORITY_NORMAL2), 43227 editor.registerCommand("deleteTableRow", () => { 43228 $deleteTableRowAtSelection2(); 43229 }, COMMAND_PRIORITY_NORMAL2), 43230 editor.registerCommand("deleteTableColumn", () => { 43231 $deleteTableColumnAtSelection2(); 43232 }, COMMAND_PRIORITY_NORMAL2), 43233 editor.registerCommand("deleteTable", () => { 43234 const selection = $getSelection2(); 43235 if (!$isRangeSelection2(selection)) return false; 43236 $findTableNode2(selection.anchor.getNode())?.remove(); 43237 }, COMMAND_PRIORITY_NORMAL2) 43238 ); 43239 } 43240 }); 43241 } 43242 }; 43243 var MIME_TYPE$1 = "application/x-lexxy-node-key"; 43244 var AttachmentDragAndDrop = class _AttachmentDragAndDrop { 43245 #editor; 43246 #draggedNodeKey = null; 43247 #rafId = null; 43248 #draggingRafId = null; 43249 #listeners = new ListenerBin(); 43250 constructor(editor) { 43251 this.#editor = editor; 43252 this.#listeners.track( 43253 editor.registerCommand(DRAGSTART_COMMAND2, (event) => this.#handleDragStart(event), COMMAND_PRIORITY_HIGH2), 43254 editor.registerCommand(DROP_COMMAND2, (event) => this.#handleDrop(event), COMMAND_PRIORITY_HIGH2) 43255 ); 43256 this.#listeners.track(editor.registerRootListener((root, prevRoot) => { 43257 if (prevRoot) { 43258 prevRoot.removeEventListener("dragover", this.#onDragOver); 43259 prevRoot.removeEventListener("dragend", this.#onDragEnd); 43260 } 43261 if (root) { 43262 root.addEventListener("dragover", this.#onDragOver); 43263 root.addEventListener("dragend", this.#onDragEnd); 43264 } 43265 })); 43266 } 43267 destroy() { 43268 this.#cleanup(); 43269 this.#listeners.dispose(); 43270 } 43271 // -- Event handlers -------------------------------------------------------- 43272 #handleDragStart(event) { 43273 if (event.target.closest?.("textarea, [data-lexxy-caption-editor]")) return false; 43274 const figure = event.target.closest?.("figure.attachment[data-lexical-node-key]"); 43275 if (!figure) return false; 43276 this.#draggedNodeKey = figure.dataset.lexicalNodeKey; 43277 event.dataTransfer.setData(MIME_TYPE$1, this.#draggedNodeKey); 43278 event.dataTransfer.effectAllowed = "move"; 43279 this.#draggingRafId = requestAnimationFrame(() => { 43280 this.#draggingRafId = null; 43281 figure.classList.add("lexxy-dragging"); 43282 }); 43283 return true; 43284 } 43285 #onDragOver = (event) => { 43286 if (!this.#draggedNodeKey) return; 43287 event.preventDefault(); 43288 event.dataTransfer.dropEffect = "move"; 43289 if (!this.#rafId) { 43290 this.#rafId = requestAnimationFrame(() => { 43291 this.#rafId = null; 43292 this.#updateDropTarget(event); 43293 }); 43294 } 43295 }; 43296 #handleDrop(event) { 43297 if (!this.#draggedNodeKey) return false; 43298 event.preventDefault(); 43299 const target = this.#resolveDropTarget(event); 43300 const draggedKey = this.#draggedNodeKey; 43301 this.#cleanup(); 43302 if (target) { 43303 this.#performDrop(draggedKey, target); 43304 } 43305 return true; 43306 } 43307 #onDragEnd = () => { 43308 this.#cleanup(); 43309 }; 43310 // -- Drop target resolution ----------------------------------------------- 43311 #updateDropTarget(event) { 43312 this.#clearDropIndicators(); 43313 const target = this.#resolveDropTarget(event); 43314 if (!target) return; 43315 if (target.type === "gallery" || target.type === "gallery-reorder") { 43316 target.element.classList.add(`lexxy-drop-target--gallery-${target.position}`); 43317 } else if (target.type === "list-item") { 43318 target.element.classList.add(`lexxy-drop-target--list-${target.position}`); 43319 } else { 43320 target.element.classList.add(`lexxy-drop-target--block-${target.position}`); 43321 } 43322 } 43323 #resolveDropTarget(event) { 43324 const element = document.elementFromPoint(event.clientX, event.clientY); 43325 if (!element) return null; 43326 const rootElement = this.#editor.getRootElement(); 43327 if (!rootElement || !rootElement.contains(element)) return null; 43328 const draggedNode = this.#draggedNodeKey ? $getNodeByKey2(this.#draggedNodeKey) : null; 43329 const targetFigure = element.closest("figure.attachment[data-lexical-node-key]"); 43330 if (targetFigure && targetFigure.dataset.lexicalNodeKey !== this.#draggedNodeKey) { 43331 const targetNode = this.#attachmentNodeForFigure(targetFigure); 43332 if (targetNode && draggedNode && this.#isGalleryImage(targetNode) && this.#isGalleryImage(draggedNode)) { 43333 const targetGallery2 = targetFigure.closest(".attachment-gallery"); 43334 if (targetGallery2) { 43335 const draggedFigure = rootElement.querySelector(`[data-lexical-node-key="${this.#draggedNodeKey}"]`); 43336 if (draggedFigure && targetGallery2.contains(draggedFigure)) { 43337 const position3 = this.#computeHorizontalPosition(targetFigure, event.clientX); 43338 return { type: "gallery-reorder", element: targetFigure, nodeKey: targetFigure.dataset.lexicalNodeKey, position: position3 }; 43339 } 43340 } 43341 const position2 = this.#computeHorizontalPosition(targetFigure, event.clientX); 43342 return { type: "gallery", element: targetFigure, nodeKey: targetFigure.dataset.lexicalNodeKey, position: position2 }; 43343 } 43344 if (targetNode && draggedNode && $isActionTextAttachmentNode(targetNode) && $isActionTextAttachmentNode(draggedNode) && !this.#isGalleryImage(targetNode) && !this.#isGalleryImage(draggedNode) && !this.#isVerticalEdgeIntent(targetFigure, event.clientY)) { 43345 return null; 43346 } 43347 } 43348 if (targetFigure?.dataset.lexicalNodeKey === this.#draggedNodeKey && targetFigure.closest(".attachment-gallery")) return null; 43349 const targetGallery = element.closest(".attachment-gallery"); 43350 if (targetGallery) { 43351 let galleryFigure = element.closest("figure.attachment[data-lexical-node-key]"); 43352 if (!galleryFigure) { 43353 galleryFigure = this.#findNearestFigureInGallery(targetGallery, event.clientX); 43354 } 43355 if (galleryFigure && galleryFigure.dataset.lexicalNodeKey !== this.#draggedNodeKey) { 43356 const position2 = this.#computeHorizontalPosition(galleryFigure, event.clientX); 43357 return { type: "gallery-reorder", element: galleryFigure, nodeKey: galleryFigure.dataset.lexicalNodeKey, position: position2 }; 43358 } 43359 if (galleryFigure) return null; 43360 } 43361 const listItem = element.closest("li"); 43362 if (listItem && rootElement.contains(listItem)) { 43363 const position2 = this.#computeVerticalPosition(listItem, event.clientY); 43364 return { type: "list-item", element: listItem, position: position2 }; 43365 } 43366 const block = this.#findNearestBlock(element, rootElement, event.clientY); 43367 if (!block) return null; 43368 const position = this.#computeVerticalPosition(block, event.clientY); 43369 if (position === "before" && block.previousElementSibling) { 43370 return { type: "block", element: block.previousElementSibling, position: "after" }; 43371 } 43372 return { type: "block", element: block, position }; 43373 } 43374 #findNearestBlock(element, rootElement, clientY) { 43375 let current = element; 43376 while (current && current !== rootElement) { 43377 if (current.parentElement === rootElement) return current; 43378 current = current.parentElement; 43379 } 43380 let nearest = null; 43381 let minDistance = Infinity; 43382 for (const child of rootElement.children) { 43383 const rect = child.getBoundingClientRect(); 43384 const distance = Math.min(Math.abs(clientY - rect.top), Math.abs(clientY - rect.bottom)); 43385 if (distance < minDistance) { 43386 minDistance = distance; 43387 nearest = child; 43388 } 43389 } 43390 return nearest; 43391 } 43392 #computeVerticalPosition(element, clientY) { 43393 const rect = element.getBoundingClientRect(); 43394 return clientY < rect.top + rect.height / 2 ? "before" : "after"; 43395 } 43396 #computeHorizontalPosition(element, clientX) { 43397 const rect = element.getBoundingClientRect(); 43398 return clientX < rect.left + rect.width / 2 ? "before" : "after"; 43399 } 43400 #isGalleryImage(node) { 43401 return $isActionTextAttachmentNode(node) && node.isPreviewableImage; 43402 } 43403 #attachmentNodeForFigure(figure) { 43404 if (!figure?.dataset?.lexicalNodeKey) return null; 43405 const node = $getNodeByKey2(figure.dataset.lexicalNodeKey); 43406 return $isActionTextAttachmentNode(node) ? node : null; 43407 } 43408 #isVerticalEdgeIntent(figure, clientY) { 43409 const rect = figure.getBoundingClientRect(); 43410 const edgeZone = Math.min(24, rect.height * 0.15); 43411 return clientY < rect.top + edgeZone || clientY > rect.bottom - edgeZone; 43412 } 43413 #findNearestFigureInGallery(gallery, clientX) { 43414 const figures = gallery.querySelectorAll("figure.attachment[data-lexical-node-key]"); 43415 let nearest = null; 43416 let minDistance = Infinity; 43417 for (const figure of figures) { 43418 const rect = figure.getBoundingClientRect(); 43419 const center = rect.left + rect.width / 2; 43420 const distance = Math.abs(clientX - center); 43421 if (distance < minDistance) { 43422 minDistance = distance; 43423 nearest = figure; 43424 } 43425 } 43426 return nearest; 43427 } 43428 // -- Drop indicator -------------------------------------------------------- 43429 static #DROP_CLASSES = [ 43430 "lexxy-drop-target--gallery-before", 43431 "lexxy-drop-target--gallery-after", 43432 "lexxy-drop-target--list-before", 43433 "lexxy-drop-target--list-after", 43434 "lexxy-drop-target--block-before", 43435 "lexxy-drop-target--block-after" 43436 ]; 43437 #clearDropIndicators() { 43438 const rootElement = this.#editor.getRootElement(); 43439 if (!rootElement) return; 43440 for (const el of rootElement.querySelectorAll("[class*='lexxy-drop-target--']")) { 43441 el.classList.remove(..._AttachmentDragAndDrop.#DROP_CLASSES); 43442 } 43443 } 43444 // -- Node operations ------------------------------------------------------- 43445 #performDrop(draggedKey, target) { 43446 const draggedNode = $getNodeByKey2(draggedKey); 43447 if (!draggedNode || !$isActionTextAttachmentNode(draggedNode)) return; 43448 if (target.type === "gallery") { 43449 this.#dropOntoImage(draggedNode, target.nodeKey, target.position); 43450 } else if (target.type === "gallery-reorder") { 43451 this.#reorderInGallery(draggedNode, target.nodeKey, target.position); 43452 } else if (target.type === "list-item") { 43453 this.#dropIntoList(draggedNode, target); 43454 } else { 43455 this.#dropBetweenBlocks(draggedNode, target); 43456 } 43457 $setSelection2(null); 43458 } 43459 #dropOntoImage(draggedNode, targetKey, position) { 43460 const targetNode = $getNodeByKey2(targetKey); 43461 if (!targetNode || !$isActionTextAttachmentNode(targetNode)) return; 43462 if (draggedNode.is(targetNode)) return; 43463 if (!draggedNode.isPreviewableImage || !targetNode.isPreviewableImage) return; 43464 const gallery = $findOrCreateGalleryForImage(targetNode); 43465 if (!gallery) return; 43466 draggedNode.remove(); 43467 if (position === "before") { 43468 targetNode.insertBefore(draggedNode); 43469 } else { 43470 targetNode.insertAfter(draggedNode); 43471 } 43472 } 43473 #reorderInGallery(draggedNode, targetKey, position) { 43474 const targetNode = $getNodeByKey2(targetKey); 43475 if (!targetNode || draggedNode.is(targetNode)) return; 43476 if (!draggedNode.isPreviewableImage || !targetNode.isPreviewableImage) return; 43477 draggedNode.remove(); 43478 if (position === "before") { 43479 targetNode.insertBefore(draggedNode); 43480 } else { 43481 targetNode.insertAfter(draggedNode); 43482 } 43483 } 43484 #dropIntoList(draggedNode, target) { 43485 const listItemNode = $getNearestNodeFromDOMNode2(target.element); 43486 if (!listItemNode || !$isListItemNode2(listItemNode)) return; 43487 const listNode = listItemNode.getParent(); 43488 if (!listNode || !$isListNode2(listNode)) return; 43489 const children = listNode.getChildren(); 43490 const index = children.indexOf(listItemNode); 43491 if (index === -1) return; 43492 const splitIndex = target.position === "before" ? index : index + 1; 43493 draggedNode.remove(); 43494 if (splitIndex === 0) { 43495 listNode.insertBefore(draggedNode); 43496 } else if (splitIndex >= children.length) { 43497 listNode.insertAfter(draggedNode); 43498 } else { 43499 const [, listAfter] = $splitNode2(listNode, splitIndex); 43500 listAfter.insertBefore(draggedNode); 43501 } 43502 } 43503 #dropBetweenBlocks(draggedNode, target) { 43504 const targetNode = $getNearestNodeFromDOMNode2(target.element); 43505 if (!targetNode) return; 43506 const topLevelTarget = targetNode.getTopLevelElement?.() || targetNode; 43507 if (draggedNode.is(topLevelTarget)) return; 43508 draggedNode.remove(); 43509 if (target.position === "before") { 43510 topLevelTarget.insertBefore(draggedNode); 43511 } else { 43512 topLevelTarget.insertAfter(draggedNode); 43513 } 43514 } 43515 // -- Lifecycle helpers ----------------------------------------------------- 43516 #cleanup() { 43517 this.#clearDropIndicators(); 43518 if (this.#draggedNodeKey) { 43519 const rootElement = this.#editor.getRootElement(); 43520 if (rootElement) { 43521 const figure = rootElement.querySelector(`[data-lexical-node-key="${this.#draggedNodeKey}"]`); 43522 figure?.classList.remove("lexxy-dragging"); 43523 } 43524 } 43525 this.#draggedNodeKey = null; 43526 if (this.#rafId) { 43527 cancelAnimationFrame(this.#rafId); 43528 this.#rafId = null; 43529 } 43530 if (this.#draggingRafId) { 43531 cancelAnimationFrame(this.#draggingRafId); 43532 this.#draggingRafId = null; 43533 } 43534 } 43535 }; 43536 var ATTACHMENT_ATTRIBUTES = [ 43537 "alt", 43538 "caption", 43539 "content", 43540 "content-type", 43541 "data-blob-url", 43542 "data-direct-upload-id", 43543 "data-lexxy-image", 43544 "data-sgid", 43545 "filename", 43546 "filesize", 43547 "height", 43548 "presentation", 43549 "previewable", 43550 "sgid", 43551 "url", 43552 "width" 43553 ]; 43554 var UPLOADS_BUSY_MESSAGE = "Please wait for all files to upload"; 43555 var AttachmentsExtension = class extends LexxyExtension { 43556 #uploadsCount = 0; 43557 get enabled() { 43558 return this.editorElement.supportsAttachments; 43559 } 43560 get allowedElements() { 43561 return [{ tag: ActionTextAttachmentNode.TAG_NAME, attributes: ATTACHMENT_ATTRIBUTES }]; 43562 } 43563 get lexicalExtension() { 43564 return defineExtension2({ 43565 name: "lexxy/action-text-attachments", 43566 nodes: [ 43567 ActionTextAttachmentNode, 43568 ActionTextAttachmentUploadNode, 43569 ImageGalleryNode 43570 ], 43571 register: (editor) => { 43572 const dragAndDrop = new AttachmentDragAndDrop(editor); 43573 return mergeRegister3( 43574 editor.registerNodeTransform(ActionTextAttachmentNode, $extractAttachmentFromParagraph), 43575 editor.registerCommand(DELETE_CHARACTER_COMMAND2, $collapseIntoGallery, COMMAND_PRIORITY_NORMAL2), 43576 editor.registerMutationListener(ActionTextAttachmentUploadNode, this.#handleUploadMutations.bind(this)), 43577 () => dragAndDrop.destroy() 43578 ); 43579 } 43580 }); 43581 } 43582 #handleUploadMutations(mutations) { 43583 const previousUploadsCount = this.#uploadsCount; 43584 for (const [key, mutation] of mutations) { 43585 if (mutation === "created") { 43586 this.#uploadsCount++; 43587 } else if (mutation === "destroyed") { 43588 this.#uploadsCount--; 43589 this.editorElement.uploadRequests.abort(key); 43590 } 43591 } 43592 if (this.#uploadsCount !== previousUploadsCount) { 43593 this.#setUploadsValidity(); 43594 } 43595 } 43596 #setUploadsValidity() { 43597 if (this.#uploadsCount) { 43598 this.setEditorValidity({ customError: true }, UPLOADS_BUSY_MESSAGE); 43599 } else { 43600 this.setEditorValidity({}); 43601 } 43602 } 43603 }; 43604 function $extractAttachmentFromParagraph(attachmentNode) { 43605 const parentNode = attachmentNode.getParent(); 43606 if (!$isParagraphNode2(parentNode)) return; 43607 if (parentNode.getChildrenSize() === 1) { 43608 parentNode.replace(attachmentNode); 43609 } else { 43610 const index = attachmentNode.getIndexWithinParent(); 43611 const [topParagraph, bottomParagraph] = $splitNode2(parentNode, index); 43612 topParagraph.insertAfter(attachmentNode); 43613 for (const p2 of [topParagraph, bottomParagraph]) { 43614 if (p2.isEmpty()) p2.remove(); 43615 } 43616 } 43617 } 43618 function $collapseIntoGallery(backwards) { 43619 const anchor = $getSelection2()?.anchor; 43620 if (!anchor) return false; 43621 if ($collapseAtGalleryEdge(anchor, backwards)) { 43622 return true; 43623 } else if (backwards) { 43624 return $collapseAroundEmptyParagraph(anchor) || $moveSelectionBeforeGallery(anchor); 43625 } 43626 return false; 43627 } 43628 function $collapseAroundEmptyParagraph(anchor) { 43629 const anchorNode = anchor.getNode(); 43630 if (!anchorNode) return false; 43631 const isWithinEmptyParagraph = $isParagraphNode2(anchorNode) && anchorNode.isEmpty(); 43632 const previousSibling = anchorNode.getPreviousSibling(); 43633 const topGallery = $findOrCreateGalleryForImage(previousSibling); 43634 const selectionIndex = topGallery?.getChildrenSize(); 43635 if (isWithinEmptyParagraph && topGallery?.collapseWith(anchorNode.getNextSibling())) { 43636 topGallery.select(selectionIndex, selectionIndex); 43637 anchorNode.remove(); 43638 return true; 43639 } else { 43640 return false; 43641 } 43642 } 43643 function $collapseAtGalleryEdge(anchor, backwards) { 43644 const anchorNode = anchor.getNode(); 43645 if (!$isImageGalleryNode(anchorNode)) return false; 43646 const isAtGalleryEdge = $isAtNodeEdge(anchor, backwards); 43647 const sibling = backwards ? anchorNode.getPreviousSibling() : anchorNode.getNextSibling(); 43648 if (isAtGalleryEdge && anchorNode.collapseWith(sibling, backwards)) { 43649 const selectionOffset = backwards ? 1 : anchorNode.getChildrenSize() - 1; 43650 anchorNode.select(selectionOffset, selectionOffset); 43651 return true; 43652 } else { 43653 return false; 43654 } 43655 } 43656 function $moveSelectionBeforeGallery(anchor) { 43657 const previousNode = anchor.getNode().getPreviousSibling(); 43658 if (!$isImageGalleryNode(anchor.getNode()) || !$isAtNodeEdge(anchor, true) || !previousNode) return false; 43659 if ($isDecoratorNode2(previousNode)) { 43660 return false; 43661 } else if (previousNode.isEmpty()) { 43662 previousNode.remove(); 43663 } else { 43664 previousNode.selectEnd(); 43665 } 43666 return true; 43667 } 43668 var EarlyEscapeCodeNode = class _EarlyEscapeCodeNode extends CodeNode3 { 43669 $config() { 43670 return this.config("early_escape_code", { extends: CodeNode3 }); 43671 } 43672 static $fromSelection(selection) { 43673 const anchorNode = selection.anchor.getNode(); 43674 return $getNearestNodeOfType2(anchorNode, _EarlyEscapeCodeNode) || (anchorNode instanceof _EarlyEscapeCodeNode ? anchorNode : null); 43675 } 43676 insertNewAfter(selection, restoreSelection) { 43677 if ($hasUpdateTag2(PASTE_TAG2) || !selection.isCollapsed()) { 43678 return super.insertNewAfter(selection, restoreSelection); 43679 } else if (this.#isCursorAtStart(selection)) { 43680 return this.#insertParagraphBefore(); 43681 } else if (this.#isCursorOnWhitespaceOnlyLastLine(selection)) { 43682 return this.#insertBlankLineBelow(selection, restoreSelection); 43683 } else if (this.#isCursorOnEmptyLastLine(selection)) { 43684 return this.#escapeToNewParagraphAfter(); 43685 } else { 43686 return super.insertNewAfter(selection, restoreSelection); 43687 } 43688 } 43689 #isCursorAtStart(selection) { 43690 const { anchor } = selection; 43691 if (!$isAtNodeStart(anchor)) return false; 43692 const anchorNode = anchor.getNode(); 43693 return this.is(anchorNode) || this.getFirstChild()?.is(anchorNode); 43694 } 43695 #isCursorOnEmptyLastLine(selection) { 43696 if (!$isCursorOnLastLine(selection)) return false; 43697 const textContent = this.getTextContent(); 43698 return textContent === "" || textContent.endsWith("\n"); 43699 } 43700 #isCursorOnWhitespaceOnlyLastLine(selection) { 43701 if (!$isCursorOnLastLine(selection)) return false; 43702 const textContent = this.getTextContent(); 43703 const lastNewlineIndex = textContent.lastIndexOf("\n"); 43704 const lastLine = lastNewlineIndex === -1 ? textContent : textContent.slice(lastNewlineIndex + 1); 43705 return lastLine.length > 0 && lastLine.trim() === ""; 43706 } 43707 #insertParagraphBefore() { 43708 this.insertBefore($createParagraphNode2()); 43709 return null; 43710 } 43711 #insertBlankLineBelow(selection, restoreSelection) { 43712 super.insertNewAfter(selection, restoreSelection); 43713 this.getLastChild().remove(); 43714 return null; 43715 } 43716 #escapeToNewParagraphAfter() { 43717 $trimTrailingBlankNodes(this); 43718 const paragraph = $createParagraphNode2(); 43719 this.insertAfter(paragraph); 43720 return paragraph; 43721 } 43722 }; 43723 var EarlyEscapeListItemNode = class extends ListItemNode2 { 43724 $config() { 43725 return this.config("early_escape_listitem", { extends: ListItemNode2 }); 43726 } 43727 insertNewAfter(selection, restoreSelection) { 43728 if (this.#shouldEscape(selection)) { 43729 return this.#escapeFromList(); 43730 } 43731 return super.insertNewAfter(selection, restoreSelection); 43732 } 43733 get #isInBlockquote() { 43734 return Boolean($getNearestNodeOfType2(this, QuoteNode2)); 43735 } 43736 #shouldEscape(selection) { 43737 if (this.#isInPasteOperation() || !this.#isInBlockquote) { 43738 return false; 43739 } else if ($isBlankNode(this)) { 43740 return true; 43741 } else { 43742 const paragraph = $getNearestNodeOfType2(selection.anchor.getNode(), ParagraphNode2); 43743 return paragraph && $isBlankNode(paragraph) && $isListItemNode2(paragraph.getParent()); 43744 } 43745 } 43746 #isInPasteOperation() { 43747 return $hasUpdateTag2(PASTE_TAG2); 43748 } 43749 #escapeFromList() { 43750 const parentList = this.getParent(); 43751 if (!parentList || !$isListNode2(parentList)) return; 43752 const blockquote = parentList.getParent(); 43753 const isInBlockquote = blockquote && $isQuoteNode2(blockquote); 43754 if (isInBlockquote) { 43755 const hasNonEmptyListItems = this.getNextSiblings().some( 43756 (sibling) => $isListItemNode2(sibling) && !$isBlankNode(sibling) 43757 ); 43758 if (hasNonEmptyListItems) { 43759 return this.#splitBlockquoteWithList(); 43760 } 43761 } 43762 const paragraph = $createParagraphNode2(); 43763 parentList.insertAfter(paragraph); 43764 this.remove(); 43765 return paragraph; 43766 } 43767 #splitBlockquoteWithList() { 43768 const splitQuotes = $splitNode2(this.getParent(), this.getIndexWithinParent()); 43769 this.remove(); 43770 const middleParagraph = $createParagraphNode2(); 43771 splitQuotes[0].insertAfter(middleParagraph); 43772 splitQuotes.forEach($trimTrailingBlankNodes); 43773 return middleParagraph; 43774 } 43775 }; 43776 var FormatEscapeExtension = class extends LexxyExtension { 43777 get enabled() { 43778 return this.editorElement.supportsRichText; 43779 } 43780 get allowedElements() { 43781 return [{ tag: "ol", attributes: ["start"] }, { tag: "li", attributes: ["value"] }]; 43782 } 43783 get lexicalExtension() { 43784 return defineExtension2({ 43785 name: "lexxy/format-escape", 43786 nodes: [ 43787 EarlyEscapeCodeNode, 43788 { replace: CodeNode3, with: (node) => new EarlyEscapeCodeNode(node.getLanguage()), withKlass: EarlyEscapeCodeNode }, 43789 EarlyEscapeListItemNode, 43790 { replace: ListItemNode2, with: () => new EarlyEscapeListItemNode(), withKlass: EarlyEscapeListItemNode } 43791 ], 43792 register(editor) { 43793 return mergeRegister3( 43794 editor.registerCommand( 43795 INSERT_PARAGRAPH_COMMAND2, 43796 () => $escapeFromBlockquote(), 43797 COMMAND_PRIORITY_HIGH2 43798 ), 43799 editor.registerCommand( 43800 KEY_ARROW_DOWN_COMMAND2, 43801 (event) => $handleArrowDownInCodeBlock(event), 43802 COMMAND_PRIORITY_NORMAL2 43803 ), 43804 editor.registerNodeTransform(QuoteNode2, $ensureQuoteHasParagraphChild) 43805 ); 43806 } 43807 }); 43808 } 43809 }; 43810 function $escapeFromBlockquote() { 43811 return $escapeBeforeBlockquoteStart() || $escapeFromBlankBlockquoteParagraph(); 43812 } 43813 function $escapeBeforeBlockquoteStart() { 43814 const selection = $getSelection2(); 43815 if (!$isRangeSelection2(selection) || !selection.isCollapsed() || selection.anchor.offset !== 0) return false; 43816 const paragraph = $getNearestNodeOfType2(selection.anchor.getNode(), ParagraphNode2); 43817 if (paragraph && !$isBlankNode(paragraph) && !paragraph.getPreviousSibling()) { 43818 const blockquote = paragraph.getParent(); 43819 if ($isQuoteNode2(blockquote)) { 43820 blockquote.insertBefore($createParagraphNode2()); 43821 return true; 43822 } 43823 } 43824 return false; 43825 } 43826 function $escapeFromBlankBlockquoteParagraph() { 43827 const anchorNode = $getSelection2().anchor.getNode(); 43828 const paragraph = $getNearestNodeOfType2(anchorNode, ParagraphNode2); 43829 if (!paragraph || !$isBlankNode(paragraph)) return false; 43830 const blockquote = paragraph.getParent(); 43831 if ($isQuoteNode2(blockquote)) { 43832 const nonEmptySiblings = paragraph.getNextSiblings().filter((sibling) => !$isBlankNode(sibling)); 43833 if (nonEmptySiblings.length > 0) { 43834 $splitQuoteNode(blockquote, paragraph); 43835 } else { 43836 blockquote.insertAfter(paragraph); 43837 paragraph.selectStart(); 43838 } 43839 return true; 43840 } 43841 return false; 43842 } 43843 function $splitQuoteNode(node, paragraph) { 43844 const splitQuotes = $splitNode2(node, paragraph.getIndexWithinParent()); 43845 splitQuotes[0].insertAfter(paragraph); 43846 splitQuotes.forEach($trimTrailingBlankNodes); 43847 paragraph.selectEnd(); 43848 } 43849 function $handleArrowDownInCodeBlock(event) { 43850 const selection = $getSelection2(); 43851 if (!$isRangeSelection2(selection) || !selection.isCollapsed()) return false; 43852 const codeNode = EarlyEscapeCodeNode.$fromSelection(selection); 43853 if (!codeNode) return false; 43854 if ($isCursorOnLastLine(selection) && !codeNode.getNextSibling()) { 43855 event?.preventDefault(); 43856 const paragraph = $createParagraphNode2(); 43857 codeNode.insertAfter(paragraph); 43858 paragraph.selectEnd(); 43859 return true; 43860 } 43861 return false; 43862 } 43863 function $ensureQuoteHasParagraphChild(quoteNode) { 43864 if (!quoteNode.isEmpty()) return; 43865 quoteNode.append($createParagraphNode2()); 43866 if ($containsRangeSelection(quoteNode)) quoteNode.getFirstChild().select(); 43867 } 43868 var LinkOpenerExtension = class extends LexxyExtension { 43869 get enabled() { 43870 return this.editorElement.supportsRichText; 43871 } 43872 get lexicalExtension() { 43873 return defineExtension2({ 43874 name: "lexxy/link-opener", 43875 register: (editor) => mergeRegister2( 43876 editor.registerCommand(CLICK_COMMAND2, this.#handleClick.bind(this), COMMAND_PRIORITY_NORMAL2), 43877 registerEventListener(this.editorElement.editorContentElement, "auxclick", this.#handleAuxClick.bind(this)), 43878 registerEventListener(window, "keydown", this.#handleKey.bind(this)), 43879 registerEventListener(window, "keyup", this.#handleKey.bind(this)), 43880 registerEventListener(window, "focus", this.#handleFocus.bind(this)) 43881 ) 43882 }); 43883 } 43884 #handleClick(event) { 43885 if (this.#isModified(event)) { 43886 return $openLink(event.target); 43887 } else { 43888 return false; 43889 } 43890 } 43891 #handleAuxClick(event) { 43892 if (event.button === 1) { 43893 this.editorElement.editor.read(() => $openLink(event.target)); 43894 } 43895 } 43896 #handleKey(event) { 43897 this.#updateOpenableAttribute(event); 43898 } 43899 // Chrome dispatches events without modifier keys *for a while* after changing tabs 43900 async #handleFocus() { 43901 await delay(200); 43902 this.editorElement.addEventListener("mousemove", this.#updateOpenableAttribute.bind(this), { once: true }); 43903 } 43904 #updateOpenableAttribute(event) { 43905 this.editorElement.toggleAttribute("data-links-openable", this.#isModified(event)); 43906 } 43907 #isModified(event) { 43908 return IS_APPLE3 ? event.metaKey : event.ctrlKey; 43909 } 43910 }; 43911 function $openLink(target) { 43912 const node = $getNearestNodeFromDOMNode2(target); 43913 const linkNode = $findMatchingParent2(node, $isLinkNode2); 43914 if (linkNode) { 43915 const url = linkNode.sanitizeUrl(linkNode.getURL()); 43916 window.open(url, "_blank", "noopener,noreferrer"); 43917 return true; 43918 } else { 43919 return false; 43920 } 43921 } 43922 var PreventLexicalTripleClickExtension = class extends LexxyExtension { 43923 get lexicalExtension() { 43924 return defineExtension2({ 43925 name: "lexxy/prevent-lexical-triple-click", 43926 register: (editor) => editor.registerRootListener((rootElement) => { 43927 if (rootElement) { 43928 return registerEventListener( 43929 rootElement, 43930 "click", 43931 this.#handleTripleClick.bind(this), 43932 { capture: true } 43933 ); 43934 } 43935 }) 43936 }); 43937 } 43938 // Stop propagation of the triple-click to prevent Lexical's handler from running. 43939 // 43940 // Lexical's onClick handler implements a triple-click handler that is trivial/anemic/naïve. The 43941 // intention of the change, made in facebook/lexical#4512, seems to be to deal with browsers' 43942 // "overselection" behavior, where a triple-click selection might end at offset 0 of the following 43943 // block, which can cause issues when transforming the selection. But the implementation breaks 43944 // many common real-world use cases and Lexxy does not demonstrate the behavior it's intended to 43945 // work around (in headers or tables). 43946 #handleTripleClick(event) { 43947 if (event.detail === 3) { 43948 event.stopPropagation(); 43949 } 43950 } 43951 }; 43952 function caretRect(node, offset3) { 43953 const range2 = document.createRange(); 43954 range2.setStart(node, offset3); 43955 range2.collapse(true); 43956 const rect = range2.getBoundingClientRect(); 43957 if (rect.height > 0) { 43958 return rect; 43959 } else { 43960 return null; 43961 } 43962 } 43963 function caretFromPoint3(clientX, clientY) { 43964 if (document.caretPositionFromPoint) { 43965 const position = document.caretPositionFromPoint(clientX, clientY); 43966 if (position) return { node: position.offsetNode, offset: position.offset }; 43967 } else if (document.caretRangeFromPoint) { 43968 const range2 = document.caretRangeFromPoint(clientX, clientY); 43969 if (range2) return { node: range2.startContainer, offset: range2.startOffset }; 43970 } 43971 return null; 43972 } 43973 var MIME_TYPE = "application/x-lexxy-custom-attachment-key"; 43974 var CustomAttachmentDragAndDrop = class { 43975 #editor; 43976 #draggedNodeKey = null; 43977 #draggingRafId = null; 43978 #dragOverRafId = null; 43979 #dropIndicator = null; 43980 #listeners = new ListenerBin(); 43981 constructor(editor) { 43982 this.#editor = editor; 43983 this.#listeners.track( 43984 editor.registerCommand(DRAGSTART_COMMAND2, (event) => this.#handleDragStart(event), COMMAND_PRIORITY_HIGH2), 43985 editor.registerCommand(DROP_COMMAND2, (event) => this.#handleDrop(event), COMMAND_PRIORITY_HIGH2) 43986 ); 43987 this.#listeners.track(editor.registerRootListener((root, prevRoot) => { 43988 if (prevRoot) { 43989 prevRoot.removeEventListener("dragover", this.#onDragOver); 43990 prevRoot.removeEventListener("dragend", this.#onDragEnd); 43991 } 43992 if (root) { 43993 root.addEventListener("dragover", this.#onDragOver); 43994 root.addEventListener("dragend", this.#onDragEnd); 43995 } 43996 })); 43997 } 43998 destroy() { 43999 this.#cleanup(); 44000 this.#dropIndicator?.remove(); 44001 this.#dropIndicator = null; 44002 this.#listeners.dispose(); 44003 } 44004 #handleDragStart(event) { 44005 const attachment = this.#customAttachmentElementFrom(event.target); 44006 if (!attachment) return false; 44007 this.#draggedNodeKey = attachment.dataset.lexicalNodeKey; 44008 event.dataTransfer.setData(MIME_TYPE, this.#draggedNodeKey); 44009 event.dataTransfer.effectAllowed = "move"; 44010 this.#draggingRafId = requestAnimationFrame(() => { 44011 this.#draggingRafId = null; 44012 attachment.classList.add("lexxy-dragging"); 44013 }); 44014 return true; 44015 } 44016 #onDragOver = (event) => { 44017 if (!this.#draggedNodeKey) return; 44018 event.preventDefault(); 44019 event.dataTransfer.dropEffect = "move"; 44020 if (!this.#dragOverRafId) { 44021 this.#dragOverRafId = requestAnimationFrame(() => { 44022 this.#dragOverRafId = null; 44023 this.#updateDropIndicator(event); 44024 }); 44025 } 44026 }; 44027 #onDragEnd = () => { 44028 this.#cleanup(); 44029 }; 44030 #handleDrop(event) { 44031 if (!this.#draggedNodeKey) return false; 44032 event.preventDefault(); 44033 const dropPoint = this.#resolveDropPoint(event); 44034 const draggedKey = this.#draggedNodeKey; 44035 this.#cleanup(); 44036 if (dropPoint) { 44037 this.#moveAttachment(draggedKey, dropPoint); 44038 } 44039 return true; 44040 } 44041 #resolveDropPoint(event) { 44042 const rootElement = this.#editor.getRootElement(); 44043 if (!rootElement) return null; 44044 const caret = caretFromPoint3(event.clientX, event.clientY); 44045 if (!caret || !rootElement.contains(caret.node)) return null; 44046 if (caret.node === rootElement) { 44047 return this.#nearestLineCaret(rootElement, event.clientY); 44048 } 44049 const decorator = this.#decoratorElementContaining(caret.node); 44050 if (decorator) { 44051 return this.#dropPointBesideDecorator(decorator, event.clientX); 44052 } else { 44053 return caret; 44054 } 44055 } 44056 #nearestLineCaret(rootElement, clientY) { 44057 let nearestLine = null; 44058 let nearestDistance = Infinity; 44059 for (const line of rootElement.children) { 44060 const rect2 = line.getBoundingClientRect(); 44061 const distance = Math.min(Math.abs(clientY - rect2.top), Math.abs(clientY - rect2.bottom)); 44062 if (distance < nearestDistance) { 44063 nearestDistance = distance; 44064 nearestLine = line; 44065 } 44066 } 44067 if (!nearestLine) return null; 44068 const rect = nearestLine.getBoundingClientRect(); 44069 if (clientY < rect.top) { 44070 return { node: nearestLine, offset: 0 }; 44071 } else { 44072 return { node: nearestLine, offset: nearestLine.childNodes.length }; 44073 } 44074 } 44075 #decoratorElementContaining(node) { 44076 const element = node.nodeType === Node.ELEMENT_NODE ? node : node.parentElement; 44077 return element?.closest("[data-lexxy-decorator][data-lexical-node-key]"); 44078 } 44079 #dropPointBesideDecorator(decorator, clientX) { 44080 const rect = decorator.getBoundingClientRect(); 44081 const placement = clientX > rect.left + rect.width / 2 ? "after" : "before"; 44082 return { decoratorKey: decorator.dataset.lexicalNodeKey, placement }; 44083 } 44084 #moveAttachment(draggedKey, dropPoint) { 44085 this.#editor.update(() => { 44086 const draggedNode = $getNodeByKey2(draggedKey); 44087 if (!$isCustomActionTextAttachmentNode(draggedNode)) return; 44088 if (dropPoint.decoratorKey) { 44089 this.#moveBesideNode(draggedNode, dropPoint); 44090 } else { 44091 this.#moveToCaret(draggedNode, dropPoint); 44092 } 44093 }); 44094 } 44095 #moveBesideNode(draggedNode, { decoratorKey, placement }) { 44096 const targetNode = $getNodeByKey2(decoratorKey); 44097 if (!targetNode || targetNode === draggedNode) return; 44098 draggedNode.remove(); 44099 if (placement === "after") { 44100 targetNode.insertAfter(draggedNode); 44101 } else { 44102 targetNode.insertBefore(draggedNode); 44103 } 44104 } 44105 #moveToCaret(draggedNode, dropPoint) { 44106 const selection = $createRangeSelectionFromDom2({ 44107 anchorNode: dropPoint.node, 44108 anchorOffset: dropPoint.offset, 44109 focusNode: dropPoint.node, 44110 focusOffset: dropPoint.offset 44111 }, this.#editor); 44112 if (!selection) return; 44113 $setSelection2(selection); 44114 draggedNode.remove(); 44115 selection.insertNodes([draggedNode]); 44116 } 44117 #updateDropIndicator(event) { 44118 this.#hideCaret(); 44119 const dropPoint = this.#resolveDropPoint(event); 44120 if (dropPoint) this.#showCaret(this.#caretRectFor(dropPoint)); 44121 } 44122 #caretRectFor(dropPoint) { 44123 if (dropPoint.decoratorKey) { 44124 return this.#decoratorEdgeRect(dropPoint); 44125 } 44126 const { node, offset: offset3 } = dropPoint; 44127 const rect = caretRect(node, offset3); 44128 if (rect) return rect; 44129 const line = node.nodeType === Node.TEXT_NODE ? node.parentElement : node; 44130 if (!line) return null; 44131 const lineRect = line.getBoundingClientRect(); 44132 return { left: lineRect.left, top: lineRect.top, height: lineRect.height }; 44133 } 44134 #decoratorEdgeRect({ decoratorKey, placement }) { 44135 const decorator = this.#editor.getRootElement()?.querySelector(`[data-lexical-node-key="${decoratorKey}"]`); 44136 if (!decorator) return null; 44137 const rect = decorator.getBoundingClientRect(); 44138 const left = placement === "after" ? rect.right : rect.left; 44139 return { left, top: rect.top, height: rect.height }; 44140 } 44141 #showCaret(rect) { 44142 if (!rect) return; 44143 const caret = this.#ensureCaretIndicator(); 44144 caret.style.blockSize = `${rect.height}px`; 44145 caret.style.insetInlineStart = `${rect.left}px`; 44146 caret.style.insetBlockStart = `${rect.top}px`; 44147 } 44148 #ensureCaretIndicator() { 44149 this.#dropIndicator ||= createElement("div", { className: "lexxy-drop-caret" }); 44150 this.#editorElement().appendChild(this.#dropIndicator); 44151 this.#dropIndicator.style.display = "block"; 44152 return this.#dropIndicator; 44153 } 44154 #editorElement() { 44155 return this.#editor.getRootElement().closest("lexxy-editor"); 44156 } 44157 #hideCaret() { 44158 if (this.#dropIndicator) this.#dropIndicator.style.display = "none"; 44159 } 44160 #customAttachmentElementFrom(target) { 44161 return target?.closest?.("[data-lexxy-decorator][data-lexical-node-key]"); 44162 } 44163 #cleanup() { 44164 if (this.#draggedNodeKey) { 44165 const rootElement = this.#editor.getRootElement(); 44166 const attachment = rootElement?.querySelector(`[data-lexical-node-key="${this.#draggedNodeKey}"]`); 44167 attachment?.classList.remove("lexxy-dragging"); 44168 } 44169 this.#hideCaret(); 44170 this.#draggedNodeKey = null; 44171 if (this.#draggingRafId) { 44172 cancelAnimationFrame(this.#draggingRafId); 44173 this.#draggingRafId = null; 44174 } 44175 if (this.#dragOverRafId) { 44176 cancelAnimationFrame(this.#dragOverRafId); 44177 this.#dragOverRafId = null; 44178 } 44179 } 44180 }; 44181 var CustomAttachmentDragAndDropExtension = class extends LexxyExtension { 44182 get enabled() { 44183 return this.editorElement.supportsRichText; 44184 } 44185 get lexicalExtension() { 44186 return defineExtension2({ 44187 name: "lexxy/custom-attachment-drag-and-drop", 44188 register: (editor) => { 44189 const dragAndDrop = new CustomAttachmentDragAndDrop(editor); 44190 return () => dragAndDrop.destroy(); 44191 } 44192 }); 44193 } 44194 }; 44195 var LexicalEditorElement = class extends HTMLElement { 44196 static formAssociated = true; 44197 static debug = false; 44198 static commands = ["bold", "italic", "strikethrough"]; 44199 static observedAttributes = ["autocapitalize", "connected", "required"]; 44200 #initialValue = ""; 44201 #previousInternalFormValue = null; 44202 #initializeEventDispatched = false; 44203 #editorInitializedDispatched = false; 44204 #listeners = new ListenerBin(); 44205 #disposables = []; 44206 #historyState = { undo: false, redo: false }; 44207 #validity = /* @__PURE__ */ new Map(); 44208 #validationTextArea = document.createElement("textarea"); 44209 #uploadRequests; 44210 constructor() { 44211 super(); 44212 this.internals = this.attachInternals(); 44213 this.internals.role = "presentation"; 44214 } 44215 get uploadRequests() { 44216 return this.#uploadRequests; 44217 } 44218 connectedCallback() { 44219 this.id ||= generateDomId("lexxy-editor"); 44220 this.config = new EditorConfiguration(this); 44221 this.extensions = new Extensions(this); 44222 this.#disposables.push(this.extensions); 44223 this.editor = this.#createEditor(); 44224 this.#disposables.push(this.editor); 44225 this.#disposables.push(this.#listeners); 44226 this.contents = new Contents(this); 44227 this.#disposables.push(this.contents); 44228 this.selection = new Selection(this); 44229 this.#disposables.push(this.selection); 44230 this.clipboard = new Clipboard(this); 44231 this.#disposables.push(this.clipboard); 44232 this.adapter = new BrowserAdapter(); 44233 this.#uploadRequests = new UploadRequests(); 44234 const commandDispatcher = CommandDispatcher.configureFor(this); 44235 this.#disposables.push(commandDispatcher); 44236 this.#initialize(); 44237 this.toggleAttribute("connected", true); 44238 requestAnimationFrame(() => { 44239 this.#mountRoot(); 44240 this.#handleAutofocus(); 44241 this.#dispatchInitialize(); 44242 }); 44243 } 44244 disconnectedCallback() { 44245 this.#initializeEventDispatched = false; 44246 this.#editorInitializedDispatched = false; 44247 this.#previousInternalFormValue = null; 44248 this.valueBeforeDisconnect = this.value; 44249 this.#clearCachedValues(); 44250 this.#reset(); 44251 } 44252 attributeChangedCallback(name, oldValue, newValue) { 44253 if (typeof this[`${name}ChangedCallback`] === "function") { 44254 this[`${name}ChangedCallback`](oldValue, newValue); 44255 } 44256 } 44257 autocapitalizeChangedCallback() { 44258 if (this.editorContentElement) { 44259 this.#transferAttributeToContentEditable(this.editorContentElement, "autocapitalize"); 44260 } 44261 } 44262 connectedChangedCallback(oldValue, newValue) { 44263 if (this.isConnected && oldValue != null && oldValue !== newValue) { 44264 requestAnimationFrame(() => this.#reconnect()); 44265 } 44266 } 44267 requiredChangedCallback() { 44268 if (this.isConnected) this.#requestValidityRefresh(); 44269 } 44270 formResetCallback() { 44271 this.value = this.#initialValue; 44272 this.editor.dispatchCommand(CLEAR_HISTORY_COMMAND2, void 0); 44273 } 44274 toString() { 44275 return this.cachedStringValue ??= this.editor?.read(() => { 44276 return $getReadableTextContent($getRoot2()); 44277 }); 44278 } 44279 get form() { 44280 return this.internals.form; 44281 } 44282 get name() { 44283 return this.getAttribute("name"); 44284 } 44285 get required() { 44286 return this.hasAttribute("required"); 44287 } 44288 get validity() { 44289 return this.internals.validity; 44290 } 44291 checkValidity() { 44292 return this.internals.checkValidity(); 44293 } 44294 reportValidity() { 44295 return this.internals.reportValidity(); 44296 } 44297 setElementValidity(key, flags, message) { 44298 this.#validity.set(key, { flags, message }); 44299 this.#requestValidityRefresh(); 44300 } 44301 get toolbarElement() { 44302 if (!this.#hasToolbar) return null; 44303 this.toolbar ??= this.#findOrCreateDefaultToolbar(); 44304 return this.toolbar; 44305 } 44306 get baseExtensions() { 44307 return [ 44308 ProvisionalParagraphExtension, 44309 CodeHighlightingExtension, 44310 HighlightExtension, 44311 TrixContentExtension, 44312 TablesExtension, 44313 RewritableHistoryExtension, 44314 AttachmentsExtension, 44315 FormatEscapeExtension, 44316 LinkOpenerExtension, 44317 PreventLexicalTripleClickExtension, 44318 CustomAttachmentDragAndDropExtension 44319 ]; 44320 } 44321 get directUploadUrl() { 44322 return this.dataset.directUploadUrl; 44323 } 44324 get blobUrlTemplate() { 44325 return this.dataset.blobUrlTemplate; 44326 } 44327 get permittedAttachmentTypes() { 44328 const raw = this.config.get("permittedAttachmentTypes"); 44329 if (raw == null) { 44330 return null; 44331 } else { 44332 const tokens = Array.isArray(raw) ? raw : String(raw).split(/\s+/); 44333 return Object.freeze(tokens.filter((t2) => t2 && t2 !== "false")); 44334 } 44335 } 44336 permitsAttachmentContentType(contentType) { 44337 if (!this.supportsAttachments) { 44338 return false; 44339 } else { 44340 const list = this.permittedAttachmentTypes; 44341 return list === null || list.includes(contentType); 44342 } 44343 } 44344 acceptsFile(file) { 44345 return dispatch(this, "lexxy:file-accept", { file }, true); 44346 } 44347 $generateNodesFromDOM(doc, { editor = this.editor } = {}) { 44348 let nodes = $generateNodesFromDOM2(editor, doc); 44349 if ($hasUpdateTag2(PASTE_TAG2)) nodes = $convertInlineImageDataURIs(nodes, this); 44350 return filterDisallowedAttachmentNodes(nodes, this); 44351 } 44352 get isEmpty() { 44353 return ["<p><br></p>", "<p></p>", ""].includes(this.value.trim()); 44354 } 44355 get isBlank() { 44356 return this.isEmpty || this.toString().match(/^\s*$/g) !== null; 44357 } 44358 get hasOpenPrompt() { 44359 return this.querySelector(".lexxy-prompt-menu.lexxy-prompt-menu--visible") !== null; 44360 } 44361 get preset() { 44362 return this.getAttribute("preset") || "default"; 44363 } 44364 get supportsAttachments() { 44365 return this.config.get("attachments"); 44366 } 44367 get supportsMarkdown() { 44368 return this.supportsRichText && this.config.get("markdown"); 44369 } 44370 get supportsMultiLine() { 44371 return this.config.get("multiLine") && !this.isSingleLineMode; 44372 } 44373 get supportsRichText() { 44374 return this.config.get("richText"); 44375 } 44376 registerAdapter(adapter) { 44377 this.adapter = adapter; 44378 if (!this.editor) return; 44379 this.#dispatchEditorInitialized(); 44380 this.#dispatchAttributesChange(); 44381 } 44382 freezeSelection() { 44383 this.adapter.freeze(); 44384 } 44385 thawSelection() { 44386 this.adapter.thaw(); 44387 } 44388 dispatchAttributesChange() { 44389 this.#dispatchAttributesChange(); 44390 } 44391 dispatchEditorInitialized() { 44392 this.#dispatchEditorInitialized(); 44393 } 44394 // TODO: Deprecate `single-line` attribute 44395 get isSingleLineMode() { 44396 return this.hasAttribute("single-line"); 44397 } 44398 get contentTabIndex() { 44399 return parseInt(this.editorContentElement?.getAttribute("tabindex") ?? "0"); 44400 } 44401 focus() { 44402 if (this.#isContentFocused) return; 44403 this.editor.focus(() => this.#onFocus()); 44404 } 44405 get #isContentFocused() { 44406 return !!this.editor && isEditorFocused(this.editor); 44407 } 44408 get value() { 44409 return this.cachedValue ??= this.#readSanitizedEditorValue(); 44410 } 44411 set value(html2) { 44412 const editorHasFocus = this.#isContentFocused; 44413 this.editor.update(() => { 44414 if (editorHasFocus) { 44415 $onUpdate2(() => this.editor.focus()); 44416 } else { 44417 $addUpdateTag2(SKIP_DOM_SELECTION_TAG2); 44418 } 44419 this.#setEditorHtml(html2); 44420 this.#toggleEmptyStatus(); 44421 }, { discrete: true }); 44422 } 44423 get canUndo() { 44424 return this.#historyState.undo; 44425 } 44426 get canRedo() { 44427 return this.#historyState.redo; 44428 } 44429 #readSanitizedEditorValue() { 44430 return this.editor?.read(() => { 44431 return sanitize($generateHtmlFromNodes2(this.editor, null)); 44432 }) ?? null; 44433 } 44434 #parseHtmlIntoLexicalNodes(html2, { editor = this.editor } = {}) { 44435 if (!html2) html2 = "<p></p>"; 44436 const nodes = this.$generateNodesFromDOM(parseHtml(`${html2}`), { editor }); 44437 return nodes.filter(this.#isNotWhitespaceOnlyNode).map(this.#wrapTextNode); 44438 } 44439 // Whitespace-only text nodes (e.g. "\n" between block elements like <div>) and stray line break 44440 // nodes are formatting artifacts from the HTML source. They can't be appended to the root node 44441 // and have no semantic meaning, so we strip them during import. 44442 #isNotWhitespaceOnlyNode(node) { 44443 if ($isLineBreakNode2(node)) return false; 44444 if ($isTextNode2(node) && node.getTextContent().trim() === "") return false; 44445 return true; 44446 } 44447 // Raw string values produce TextNodes which cannot be appended directly to the RootNode. 44448 // We wrap those in <p> 44449 #wrapTextNode(node) { 44450 if (!$isTextNode2(node)) return node; 44451 const paragraph = $createParagraphNode2(); 44452 paragraph.append(node); 44453 return paragraph; 44454 } 44455 #initialize() { 44456 this.#registerComponents(); 44457 this.#handleEnter(); 44458 this.#registerFocusEvents(); 44459 this.#registerHistoryEvents(); 44460 this.#registerFileAcceptFilter(); 44461 this.#attachDebugHooks(); 44462 this.#attachToolbar(); 44463 this.#resetBeforeTurboCaches(); 44464 this.#setInternalFormValue(this.value, { suppressEvent: true }); 44465 this.#synchronizeWithChanges(); 44466 } 44467 #registerFileAcceptFilter() { 44468 this.#listeners.track( 44469 registerEventListener(this, "lexxy:file-accept", (event) => { 44470 if (!this.permitsAttachmentContentType(event.detail.file.type)) { 44471 event.preventDefault(); 44472 } 44473 }) 44474 ); 44475 } 44476 #createEditor() { 44477 this.editorContentElement ||= this.#createEditorContentElement(); 44478 this.appendChild(this.editorContentElement); 44479 const editor = buildEditorFromExtensions2( 44480 { 44481 name: "lexxy/core", 44482 namespace: "Lexxy", 44483 theme, 44484 nodes: this.#lexicalNodes, 44485 html: { 44486 export: /* @__PURE__ */ new Map([[TextNode2, exportTextNodeDOM], [CodeHighlightNode3, exportTextNodeDOM]]) 44487 }, 44488 $initialEditorState: (editor2) => { 44489 this.#configureSanitizer(editor2); 44490 this.#loadInitialValue(editor2); 44491 } 44492 }, 44493 ...this.extensions.lexicalExtensions 44494 ); 44495 return editor; 44496 } 44497 // Toggling editable around setRootElement skips Lexical's DOM-selection sync, 44498 // which would otherwise steal focus from elsewhere on the page. 44499 #mountRoot() { 44500 this.editor.setEditable(false); 44501 this.editor.setRootElement(this.editorContentElement); 44502 this.editor.setEditable(true); 44503 } 44504 get #lexicalNodes() { 44505 const nodes = [CustomActionTextAttachmentNode]; 44506 if (this.supportsRichText) { 44507 nodes.push( 44508 QuoteNode2, 44509 HeadingNode2, 44510 ListNode2, 44511 ListItemNode2, 44512 CodeNode3, 44513 CodeHighlightNode3, 44514 LinkNode2, 44515 AutoLinkNode2, 44516 HorizontalDividerNode 44517 ); 44518 } 44519 return nodes; 44520 } 44521 #createEditorContentElement() { 44522 const editorContentElement = createElement("div", { 44523 id: `${this.id}-content`, 44524 classList: "lexxy-editor__content", 44525 contenteditable: true, 44526 role: "textbox", 44527 "aria-multiline": true, 44528 "aria-label": this.#labelText, 44529 placeholder: this.getAttribute("placeholder") 44530 }); 44531 this.#ariaAttributes.forEach((attribute) => editorContentElement.setAttribute(attribute.name, attribute.value)); 44532 this.#transferAttributeToContentEditable(editorContentElement, "autocapitalize"); 44533 this.#transferAttributeToContentEditable(editorContentElement, "tabindex", { defaultValue: 0, removeSource: true }); 44534 return editorContentElement; 44535 } 44536 #transferAttributeToContentEditable(element, qualifiedName, { defaultValue = null, removeSource = false } = {}) { 44537 if (this.hasAttribute(qualifiedName)) { 44538 element.setAttribute(qualifiedName, this.getAttribute(qualifiedName)); 44539 } else if (defaultValue !== null) { 44540 element.setAttribute(qualifiedName, defaultValue); 44541 } else { 44542 element.removeAttribute(qualifiedName); 44543 } 44544 if (removeSource) this.removeAttribute(qualifiedName); 44545 } 44546 get #labelText() { 44547 return Array.from(this.internals.labels).map((label) => label.textContent).join(" "); 44548 } 44549 get #ariaAttributes() { 44550 return Array.from(this.attributes).filter((attribute) => attribute.name.startsWith("aria-")); 44551 } 44552 #setInternalFormValue(html2, { suppressEvent = false } = {}) { 44553 const changed = html2 !== this.#previousInternalFormValue; 44554 this.internals.setFormValue(html2); 44555 this.#previousInternalFormValue = html2; 44556 if (changed && !suppressEvent) { 44557 dispatch(this, "lexxy:change"); 44558 } 44559 } 44560 #loadInitialValue(editor) { 44561 const initialHtml = this.valueBeforeDisconnect || this.getAttribute("value") || "<p><br></p>"; 44562 this.#initialValue = initialHtml; 44563 this.#setEditorHtml(initialHtml, { editor }); 44564 } 44565 #setEditorHtml(html2, { editor = this.editor } = {}) { 44566 $getRoot2().clear().selectEnd().insertNodes(this.#parseHtmlIntoLexicalNodes(html2, { editor })); 44567 } 44568 #resetBeforeTurboCaches() { 44569 this.#listeners.track( 44570 registerEventListener(document, "turbo:before-cache", this.#handleTurboBeforeCache) 44571 ); 44572 } 44573 #handleTurboBeforeCache = (event) => { 44574 if (!this.closest("[data-turbo-permanent]")) { 44575 this.#reset(); 44576 } 44577 }; 44578 #synchronizeWithChanges() { 44579 this.#listeners.track(this.editor.registerUpdateListener(({ editorState }) => { 44580 this.#clearCachedValues(); 44581 this.#setInternalFormValue(this.value); 44582 this.#toggleEmptyStatus(); 44583 this.#requestValidityRefresh(); 44584 this.#dispatchAttributesChange(); 44585 })); 44586 } 44587 async #requestValidityRefresh() { 44588 await nextFrame(); 44589 if (this.isConnected) this.#refreshValidity(); 44590 } 44591 #refreshValidity() { 44592 this.#refreshInternalValidity(); 44593 const { validity, message } = this.#calculateValidity(); 44594 this.internals.setValidity(validity, message, this.editorContentElement); 44595 } 44596 #refreshInternalValidity() { 44597 this.#validationTextArea.required = this.required && this.isBlank; 44598 const flags = this.#validationTextArea.validity; 44599 const message = this.#validationTextArea.validationMessage; 44600 this.#validity.set(this, { flags, message }); 44601 } 44602 #calculateValidity() { 44603 const validity = {}; 44604 const messages = []; 44605 for (const { flags, message } of this.#validity.values()) { 44606 if (flags.valid === true) continue; 44607 for (const flag in flags) { 44608 if (flags[flag]) { 44609 validity[flag] = true; 44610 messages.push(message); 44611 } 44612 } 44613 } 44614 return { validity, message: messages.join("\n") }; 44615 } 44616 #clearCachedValues() { 44617 this.cachedValue = null; 44618 this.cachedStringValue = null; 44619 } 44620 #registerComponents() { 44621 const registered = []; 44622 if (this.supportsRichText) { 44623 registered.push( 44624 registerRichText2(this.editor), 44625 registerList2(this.editor) 44626 ); 44627 this.#registerTableComponents(); 44628 this.#registerCodeLanguagePicker(); 44629 if (this.supportsMarkdown) { 44630 const transformers = [...TRANSFORMERS2.filter((transformer) => transformer !== QUOTE2), DOUBLE_QUOTE, HORIZONTAL_DIVIDER]; 44631 registered.push( 44632 registerMarkdownShortcuts2(this.editor, transformers), 44633 registerMarkdownLeadingTagHandler(this.editor, transformers) 44634 ); 44635 } 44636 } else { 44637 registered.push(registerPlainText2(this.editor)); 44638 } 44639 this.#listeners.track(...registered); 44640 } 44641 #registerTableComponents() { 44642 let tableTools = this.querySelector("lexxy-table-tools"); 44643 tableTools ??= createElement("lexxy-table-tools"); 44644 this.append(tableTools); 44645 this.#disposables.push(tableTools); 44646 } 44647 #registerCodeLanguagePicker() { 44648 let codeLanguagePicker = this.querySelector("lexxy-code-language-picker"); 44649 codeLanguagePicker ??= createElement("lexxy-code-language-picker"); 44650 this.append(codeLanguagePicker); 44651 this.#disposables.push(codeLanguagePicker); 44652 } 44653 #handleEnter() { 44654 this.#listeners.track(this.editor.registerCommand( 44655 KEY_ENTER_COMMAND2, 44656 (event) => { 44657 if (event.ctrlKey || event.metaKey) { 44658 event.preventDefault(); 44659 return true; 44660 } 44661 if (!this.supportsMultiLine) { 44662 event.preventDefault(); 44663 return true; 44664 } 44665 return false; 44666 }, 44667 COMMAND_PRIORITY_NORMAL2 44668 )); 44669 } 44670 #registerFocusEvents() { 44671 this.#listeners.track( 44672 registerEventListener(this, "focusin", this.#handleFocusIn), 44673 registerEventListener(this, "focusout", this.#handleFocusOut) 44674 ); 44675 } 44676 #handleFocusIn(event) { 44677 if (this.#elementInEditorOrToolbar(event.target) && !this.currentlyFocused) { 44678 this.#dispatchAttributesChange(); 44679 dispatch(this, "lexxy:focus"); 44680 this.currentlyFocused = true; 44681 } 44682 } 44683 #handleFocusOut(event) { 44684 if (!this.#elementInEditorOrToolbar(event.relatedTarget)) { 44685 dispatch(this, "lexxy:blur"); 44686 this.currentlyFocused = false; 44687 } 44688 } 44689 #elementInEditorOrToolbar(element) { 44690 return this.contains(element) || this.toolbarElement?.contains(element); 44691 } 44692 #onFocus() { 44693 if (this.isEmpty) { 44694 this.selection.placeCursorAtTheEnd(); 44695 } 44696 } 44697 #handleAutofocus() { 44698 if (!document.querySelector(":focus")) { 44699 if (this.hasAttribute("autofocus") && document.querySelector("[autofocus]") === this) { 44700 this.focus(); 44701 } 44702 } 44703 } 44704 #registerHistoryEvents() { 44705 this.#listeners.track( 44706 this.editor.registerCommand(CAN_UNDO_COMMAND2, (enabled) => { 44707 this.#historyState.undo = enabled; 44708 }, COMMAND_PRIORITY_NORMAL2), 44709 this.editor.registerCommand(CAN_REDO_COMMAND2, (enabled) => { 44710 this.#historyState.redo = enabled; 44711 }, COMMAND_PRIORITY_NORMAL2) 44712 ); 44713 } 44714 #attachDebugHooks() { 44715 return; 44716 } 44717 #attachToolbar() { 44718 if (this.#hasToolbar) { 44719 this.toolbarElement.setEditor(this); 44720 if (typeof this.toolbarElement.dispose === "function") { 44721 this.#disposables.push(this.toolbarElement); 44722 } 44723 this.extensions.initializeToolbars(); 44724 } 44725 } 44726 #findOrCreateDefaultToolbar() { 44727 const toolbarConfig = this.config.get("toolbar"); 44728 if (typeof toolbarConfig === "string") { 44729 return document.getElementById(toolbarConfig); 44730 } else { 44731 return this.querySelector("lexxy-toolbar") ?? this.#createDefaultToolbar(); 44732 } 44733 } 44734 get #hasToolbar() { 44735 return this.supportsRichText && !!this.config.get("toolbar"); 44736 } 44737 #createDefaultToolbar() { 44738 const toolbar = createElement("lexxy-toolbar"); 44739 toolbar.innerHTML = LexicalToolbarElement.defaultTemplate; 44740 toolbar.setAttribute("data-attachments", this.supportsAttachments); 44741 toolbar.configure(this.config.get("toolbar")); 44742 this.prepend(toolbar); 44743 return toolbar; 44744 } 44745 #toggleEmptyStatus() { 44746 this.classList.toggle("lexxy-editor--empty", this.isEmpty); 44747 } 44748 #configureSanitizer(editor) { 44749 setSanitizerConfig(this.#getAllowedElements(editor)); 44750 } 44751 #getAllowedElements(editor) { 44752 return this.#getImportableTags(editor).concat(this.extensions.allowedElements); 44753 } 44754 #getImportableTags(editor) { 44755 const tags = Array.from(editor._htmlConversions.keys()); 44756 return tags.filter((tag) => !tag.startsWith("#")); 44757 } 44758 #dispatchAttributesChange() { 44759 let attributes = null; 44760 let linkHref = null; 44761 let highlight = null; 44762 let headingTag = null; 44763 this.editor.getEditorState().read(() => { 44764 const selection = $getSelection2(); 44765 if (!$isRangeSelection2(selection)) return; 44766 const format = this.selection.getFormat(); 44767 if (Object.keys(format).length === 0) return; 44768 const anchorNode = selection.anchor.getNode(); 44769 const linkNode = $getNearestNodeOfType2(anchorNode, LinkNode2); 44770 attributes = { 44771 bold: { active: format.isBold, enabled: true }, 44772 italic: { active: format.isItalic, enabled: true }, 44773 strikethrough: { active: format.isStrikethrough, enabled: true }, 44774 code: { active: format.isInCode, enabled: true }, 44775 highlight: { active: format.isHighlight, enabled: true }, 44776 link: { active: format.isInLink, enabled: true }, 44777 quote: { active: format.isInQuote, enabled: true }, 44778 heading: { active: format.isInHeading, enabled: true }, 44779 "unordered-list": { active: format.isInList && format.listType === "bullet", enabled: true }, 44780 "ordered-list": { active: format.isInList && format.listType === "number", enabled: true }, 44781 undo: { active: false, enabled: this.canUndo }, 44782 redo: { active: false, enabled: this.canRedo } 44783 }; 44784 linkHref = linkNode ? linkNode.getURL() : null; 44785 highlight = format.isHighlight ? getHighlightStyles(selection) : null; 44786 headingTag = format.headingTag ?? null; 44787 }); 44788 if (attributes) { 44789 this.adapter.dispatchAttributesChange(attributes, linkHref, highlight, headingTag); 44790 } 44791 } 44792 #dispatchEditorInitialized() { 44793 if (!this.adapter) return; 44794 this.#editorInitializedDispatched = true; 44795 this.adapter.dispatchEditorInitialized({ 44796 highlightColors: this.#resolvedHighlightColors, 44797 headingFormats: this.#supportedHeadingFormats 44798 }); 44799 } 44800 #dispatchInitialize() { 44801 if (this.isConnected && this.adapter) { 44802 if (!this.#initializeEventDispatched) { 44803 this.#initializeEventDispatched = true; 44804 dispatch(this, "lexxy:initialize"); 44805 } 44806 if (!this.#editorInitializedDispatched) { 44807 this.#dispatchEditorInitialized(); 44808 } 44809 } 44810 } 44811 get #resolvedHighlightColors() { 44812 const buttons = this.config.get("highlight.buttons"); 44813 if (!buttons) return null; 44814 const colors = this.#resolveColors("color", buttons.color || []); 44815 const backgroundColors = this.#resolveColors("background-color", buttons["background-color"] || []); 44816 return { colors, backgroundColors }; 44817 } 44818 get #supportedHeadingFormats() { 44819 if (!this.supportsRichText) return []; 44820 const headings = this.config.get("headings"); 44821 return [ 44822 { label: "Normal", command: "setFormatParagraph", tag: null }, 44823 ...headings.map((tag, index) => ({ 44824 label: HeadingDropdown.labelFor(tag, index), 44825 command: HeadingDropdown.commandFor(index), 44826 tag 44827 })) 44828 ]; 44829 } 44830 // Builds one resolver element per CSS value inside a hidden container, attaches 44831 // the container in a single DOM write, then reads all computed values in one pass 44832 // â triggering at most one forced reflow. The previous implementation interleaved 44833 // setProperty/getComputedStyle/removeProperty on the same element, forcing a style 44834 // recalc on every iteration during editor initialization. 44835 #resolveColors(property, cssValues) { 44836 const container = document.createElement("span"); 44837 container.style.display = "none"; 44838 const resolvers = cssValues.map((cssValue) => { 44839 const element = document.createElement("span"); 44840 element.style.setProperty(property, cssValue); 44841 container.appendChild(element); 44842 return { element, name: cssValue }; 44843 }); 44844 styleResolverRoot().appendChild(container); 44845 const resolved = resolvers.map(({ element, name }) => ({ 44846 name, 44847 value: window.getComputedStyle(element).getPropertyValue(property) 44848 })); 44849 container.remove(); 44850 return resolved; 44851 } 44852 #reset() { 44853 this.#dispose(); 44854 this.#resetValidity(); 44855 this.#uploadRequests?.clear(); 44856 this.editorContentElement?.remove(); 44857 this.editorContentElement = null; 44858 this.toolbar = null; 44859 } 44860 #dispose() { 44861 while (this.#disposables.length) { 44862 this.#disposables.pop().dispose(); 44863 } 44864 } 44865 #reconnect() { 44866 this.disconnectedCallback(); 44867 this.valueBeforeDisconnect = null; 44868 this.connectedCallback(); 44869 } 44870 #resetValidity() { 44871 this.#validity = /* @__PURE__ */ new Map(); 44872 } 44873 }; 44874 function $getReadableTextContent(node) { 44875 if (node instanceof CustomActionTextAttachmentNode) { 44876 return node.getReadableTextContent(); 44877 } 44878 if ($isElementNode2(node)) { 44879 let text2 = ""; 44880 const children = node.getChildren(); 44881 for (let i2 = 0; i2 < children.length; i2++) { 44882 const child = children[i2]; 44883 const previousChild = children[i2 - 1]; 44884 if (isAttachmentSpacerTextNode(child, previousChild, i2, children.length)) continue; 44885 text2 += $getReadableTextContent(child); 44886 if ($isElementNode2(child) && i2 !== children.length - 1 && !child.isInline()) { 44887 text2 += "\n\n"; 44888 } 44889 } 44890 return text2; 44891 } 44892 return node.getTextContent(); 44893 } 44894 var BaseSource = class { 44895 // Template method to override 44896 async buildListItems(filter = "") { 44897 return Promise.resolve([]); 44898 } 44899 // Template method to override 44900 promptItemFor(listItem) { 44901 return null; 44902 } 44903 // Protected 44904 buildListItemElementFor(promptItemElement) { 44905 const template = promptItemElement.querySelector("template[type='menu']"); 44906 const fragment = template.content.cloneNode(true); 44907 const listItemElement = createElement("li", { role: "option", id: generateDomId("prompt-item"), tabindex: "0" }); 44908 listItemElement.classList.add("lexxy-prompt-menu__item"); 44909 listItemElement.appendChild(fragment); 44910 return listItemElement; 44911 } 44912 async loadPromptItemsFromUrl(url) { 44913 try { 44914 const response = await fetch(url); 44915 const html2 = await response.text(); 44916 const promptItems = parseHtml(html2).querySelectorAll("lexxy-prompt-item"); 44917 return Promise.resolve(Array.from(promptItems)); 44918 } catch (error) { 44919 return Promise.reject(error); 44920 } 44921 } 44922 }; 44923 var MAX_RENDERED_SUGGESTIONS$1 = 100; 44924 var LocalFilterSource = class extends BaseSource { 44925 async buildListItems(filter = "") { 44926 const promptItems = await this.fetchPromptItems(); 44927 return this.#buildListItemsFromPromptItems(promptItems, filter); 44928 } 44929 // Template method to override 44930 async fetchPromptItems(filter) { 44931 return Promise.resolve([]); 44932 } 44933 promptItemFor(listItem) { 44934 return this.promptItemByListItem.get(listItem); 44935 } 44936 #buildListItemsFromPromptItems(promptItems, filter) { 44937 this.promptItemByListItem = /* @__PURE__ */ new WeakMap(); 44938 if (!filter) { 44939 return this.#buildAllListItems(promptItems); 44940 } 44941 const matches = []; 44942 for (const promptItem of promptItems) { 44943 const searchableText = promptItem.getAttribute("search"); 44944 const position = filterMatchPosition(searchableText, filter); 44945 if (position >= 0) { 44946 matches.push({ promptItem, position }); 44947 } 44948 } 44949 matches.sort((a2, b3) => a2.position - b3.position); 44950 const listItems = []; 44951 for (const { promptItem } of matches) { 44952 if (listItems.length >= MAX_RENDERED_SUGGESTIONS$1) break; 44953 const listItem = this.buildListItemElementFor(promptItem); 44954 this.promptItemByListItem.set(listItem, promptItem); 44955 listItems.push(listItem); 44956 } 44957 return listItems; 44958 } 44959 #buildAllListItems(promptItems) { 44960 const listItems = []; 44961 for (const promptItem of promptItems) { 44962 if (listItems.length >= MAX_RENDERED_SUGGESTIONS$1) break; 44963 const listItem = this.buildListItemElementFor(promptItem); 44964 this.promptItemByListItem.set(listItem, promptItem); 44965 listItems.push(listItem); 44966 } 44967 return listItems; 44968 } 44969 }; 44970 var InlinePromptSource = class extends LocalFilterSource { 44971 constructor(inlinePromptItems) { 44972 super(); 44973 this.inlinePromptItemElements = Array.from(inlinePromptItems); 44974 } 44975 async fetchPromptItems() { 44976 return Promise.resolve(this.inlinePromptItemElements); 44977 } 44978 }; 44979 var DeferredPromptSource = class extends LocalFilterSource { 44980 constructor(url) { 44981 super(); 44982 this.url = url; 44983 this.fetchPromptItems(); 44984 } 44985 async fetchPromptItems() { 44986 this.promptItems ??= await this.loadPromptItemsFromUrl(this.url); 44987 return Promise.resolve(this.promptItems); 44988 } 44989 }; 44990 var DEBOUNCE_INTERVAL = 200; 44991 var MAX_RENDERED_SUGGESTIONS = 100; 44992 var RemoteFilterSource = class extends BaseSource { 44993 constructor(url) { 44994 super(); 44995 this.baseURL = url; 44996 this.loadAndFilterListItems = debounceAsync(this.fetchFilteredListItems.bind(this), DEBOUNCE_INTERVAL); 44997 } 44998 async buildListItems(filter = "") { 44999 return await this.loadAndFilterListItems(filter); 45000 } 45001 promptItemFor(listItem) { 45002 return this.promptItemByListItem.get(listItem); 45003 } 45004 async fetchFilteredListItems(filter) { 45005 const promptItems = await this.loadPromptItemsFromUrl(this.#urlFor(filter)); 45006 return this.#buildListItemsFromPromptItems(promptItems); 45007 } 45008 #urlFor(filter) { 45009 const url = new URL(this.baseURL, window.location.origin); 45010 url.searchParams.append("filter", filter); 45011 return url.toString(); 45012 } 45013 #buildListItemsFromPromptItems(promptItems) { 45014 const listItems = []; 45015 this.promptItemByListItem = /* @__PURE__ */ new WeakMap(); 45016 for (const promptItem of promptItems) { 45017 if (listItems.length >= MAX_RENDERED_SUGGESTIONS) break; 45018 const listItem = this.buildListItemElementFor(promptItem); 45019 this.promptItemByListItem.set(listItem, promptItem); 45020 listItems.push(listItem); 45021 } 45022 return listItems; 45023 } 45024 }; 45025 var NOTHING_FOUND_DEFAULT_MESSAGE = "Nothing found"; 45026 var FILTER_DEBOUNCE_INTERVAL = 50; 45027 var DEFAULT_ONLY_AT_PATTERN = "^|[ \\n]"; 45028 var LexicalPromptElement = class extends HTMLElement { 45029 #globalListeners = new ListenerBin(); 45030 #popoverListeners = new ListenerBin(); 45031 #debouncedFilterOptions = debounce(() => this.#filterOptions(), FILTER_DEBOUNCE_INTERVAL); 45032 constructor() { 45033 super(); 45034 this.showPopoverId = 0; 45035 } 45036 static observedAttributes = ["connected"]; 45037 connectedCallback() { 45038 this.source = this.#createSource(); 45039 this.#addTriggerListener(); 45040 this.#removePopoverBeforeTurboCaches(); 45041 this.toggleAttribute("connected", true); 45042 } 45043 disconnectedCallback() { 45044 this.#popoverListeners.dispose(); 45045 this.#globalListeners.dispose(); 45046 this.source = null; 45047 this.#removePopover(); 45048 } 45049 attributeChangedCallback(name, oldValue, newValue) { 45050 if (name === "connected" && this.isConnected && oldValue != null && oldValue !== newValue) { 45051 requestAnimationFrame(() => this.#reconnect()); 45052 } 45053 } 45054 get name() { 45055 return this.getAttribute("name"); 45056 } 45057 get trigger() { 45058 return this.getAttribute("trigger"); 45059 } 45060 get supportsSpaceInSearches() { 45061 return this.hasAttribute("supports-space-in-searches"); 45062 } 45063 get onlyAt() { 45064 return this.getAttribute("only-at"); 45065 } 45066 get verticalDirection() { 45067 return this.getAttribute("vertical-direction"); 45068 } 45069 get open() { 45070 return this.popoverElement?.classList?.contains("lexxy-prompt-menu--visible"); 45071 } 45072 get closed() { 45073 return !this.open; 45074 } 45075 get #doesSpaceSelect() { 45076 return !this.supportsSpaceInSearches; 45077 } 45078 #createSource() { 45079 const src = this.getAttribute("src"); 45080 if (src) { 45081 if (this.hasAttribute("remote-filtering")) { 45082 return new RemoteFilterSource(src); 45083 } else { 45084 return new DeferredPromptSource(src); 45085 } 45086 } else { 45087 return new InlinePromptSource(this.querySelectorAll("lexxy-prompt-item")); 45088 } 45089 } 45090 #addTriggerListener() { 45091 if (!this.#promptContentTypePermitted) return; 45092 this.#popoverListeners.track(this.#editor.registerUpdateListener(({ editorState }) => { 45093 editorState.read(() => { 45094 if (this.#selection.isInsideCodeBlock) return; 45095 const { node, offset: offset3 } = this.#selection.selectedNodeWithOffset(); 45096 if (!node) return; 45097 if ($isTextNode2(node)) { 45098 const fullText = node.getTextContent(); 45099 const triggerLength = this.trigger.length; 45100 if (offset3 >= triggerLength) { 45101 const textBeforeCursor = fullText.slice(offset3 - triggerLength, offset3); 45102 if (textBeforeCursor === this.trigger) { 45103 const textBeforeTrigger = $textBeforeOffset(node, offset3 - triggerLength); 45104 if (this.#onlyAtRegExp.test(textBeforeTrigger)) { 45105 this.#popoverListeners.dispose(); 45106 this.#showPopover(); 45107 } 45108 } 45109 } 45110 } 45111 }); 45112 })); 45113 } 45114 get #onlyAtRegExp() { 45115 return new RegExp(`(?:${this.onlyAt ?? DEFAULT_ONLY_AT_PATTERN})$`); 45116 } 45117 get #promptContentTypePermitted() { 45118 if (this.hasAttribute("insert-editable-text")) return true; 45119 const el = this.#editorElement; 45120 if (!el.supportsAttachments) { 45121 return false; 45122 } else { 45123 const templates = Array.from(this.querySelectorAll("template[type='editor']")); 45124 const types = templates.length ? templates.map((t2) => t2.getAttribute("content-type") || this.#defaultPromptContentType) : [this.#defaultPromptContentType]; 45125 return types.some((t2) => el.permitsAttachmentContentType(t2)); 45126 } 45127 } 45128 #addCursorPositionListener() { 45129 this.#popoverListeners.track(this.#editor.registerUpdateListener(({ editorState }) => { 45130 if (this.closed) return; 45131 editorState.read(() => { 45132 if (this.#selection.isInsideCodeBlock) { 45133 this.#hidePopover(); 45134 return; 45135 } 45136 const { node, offset: offset3 } = this.#selection.selectedNodeWithOffset(); 45137 if (!node) return; 45138 if (this.#cursorIsTypingSearchTerm(node, offset3)) { 45139 if (!this.popoverElement.hasAttribute("data-anchored")) { 45140 this.#positionPopover(); 45141 } 45142 } else { 45143 this.#hidePopover(); 45144 } 45145 }); 45146 })); 45147 } 45148 // The popover should stay open only while the cursor sits at the end of the 45149 // trigger and its search term. When the cursor moves away â before the 45150 // trigger, or past the token into later text â the text between the trigger 45151 // and the cursor breaks that run and we dismiss. A newline always breaks the 45152 // run; a space breaks it only for triggers that don't support spaces in 45153 // searches, since those that do (e.g. `person:`) expect multi-word terms. 45154 #cursorIsTypingSearchTerm(node, offset3) { 45155 if (!$isTextNode2(node) || offset3 === 0) return false; 45156 const textBeforeCursor = node.getTextContent().slice(0, offset3); 45157 const lastTriggerIndex = textBeforeCursor.lastIndexOf(this.trigger); 45158 if (lastTriggerIndex === -1) return false; 45159 const searchTerm = textBeforeCursor.slice(lastTriggerIndex + this.trigger.length); 45160 const breakPattern = this.supportsSpaceInSearches ? /\n/ : /[ \n]/; 45161 return !breakPattern.test(searchTerm); 45162 } 45163 get #editor() { 45164 return this.#editorElement.editor; 45165 } 45166 get #editorElement() { 45167 return this.closest("lexxy-editor"); 45168 } 45169 get #selection() { 45170 return this.#editorElement.selection; 45171 } 45172 async #showPopover() { 45173 const showId = ++this.showPopoverId; 45174 this.popoverElement ??= await this.#buildPopover(); 45175 if (this.showPopoverId !== showId) return; 45176 this.#resetPopoverPosition(); 45177 await this.#filterOptions(); 45178 if (this.showPopoverId !== showId) return; 45179 this.popoverElement.classList.toggle("lexxy-prompt-menu--visible", true); 45180 this.#selectFirstOption(); 45181 this.#popoverListeners.track( 45182 registerEventListener(this.#editorElement, "keydown", this.#handleKeydownOnPopover), 45183 registerEventListener(this.#editorElement, "lexxy:change", this.#debouncedFilterOptions) 45184 ); 45185 this.#registerKeyListeners(); 45186 this.#addCursorPositionListener(); 45187 } 45188 #registerKeyListeners() { 45189 this.#popoverListeners.track( 45190 this.#editor.registerCommand(KEY_ENTER_COMMAND2, this.#handleSelectedOption.bind(this), COMMAND_PRIORITY_CRITICAL2), 45191 this.#editor.registerCommand(KEY_TAB_COMMAND2, this.#handleSelectedOption.bind(this), COMMAND_PRIORITY_CRITICAL2) 45192 ); 45193 if (this.#doesSpaceSelect) { 45194 this.#popoverListeners.track(this.#editor.registerCommand(KEY_SPACE_COMMAND2, this.#handleSelectedOption.bind(this), COMMAND_PRIORITY_CRITICAL2)); 45195 this.#popoverListeners.track(this.#editor.registerCommand(INPUT_COMMAND2, this.#handleInputCommand.bind(this), COMMAND_PRIORITY_CRITICAL2)); 45196 } 45197 this.#popoverListeners.track( 45198 this.#editor.registerCommand(KEY_ARROW_UP_COMMAND2, this.#handleArrowUp.bind(this), COMMAND_PRIORITY_CRITICAL2), 45199 this.#editor.registerCommand(KEY_ARROW_DOWN_COMMAND2, this.#handleArrowDown.bind(this), COMMAND_PRIORITY_CRITICAL2) 45200 ); 45201 } 45202 #handleArrowUp(event) { 45203 this.#moveSelectionUp(); 45204 event.preventDefault(); 45205 return true; 45206 } 45207 #handleArrowDown(event) { 45208 this.#moveSelectionDown(); 45209 event.preventDefault(); 45210 return true; 45211 } 45212 #selectFirstOption() { 45213 const firstOption = this.#listItemElements[0]; 45214 if (firstOption) { 45215 this.#selectOption(firstOption); 45216 } 45217 } 45218 get #listItemElements() { 45219 return Array.from(this.popoverElement.querySelectorAll(".lexxy-prompt-menu__item")); 45220 } 45221 #selectOption(listItem, { scrollIntoView = false } = {}) { 45222 this.#clearListItemSelection(); 45223 listItem.toggleAttribute("aria-selected", true); 45224 if (scrollIntoView) { 45225 listItem.scrollIntoView({ block: "nearest", container: "nearest", behavior: "smooth" }); 45226 } 45227 this.#setEditorAssociationAttribute("aria-controls", this.popoverElement.id); 45228 this.#setEditorAssociationAttribute("aria-activedescendant", listItem.id); 45229 this.#setEditorAssociationAttribute("aria-haspopup", "listbox"); 45230 } 45231 #clearListItemSelection() { 45232 this.#listItemElements.forEach((item) => { 45233 item.toggleAttribute("aria-selected", false); 45234 }); 45235 } 45236 #clearSelection() { 45237 this.#clearListItemSelection(); 45238 this.#editorContentElement.removeAttribute("aria-controls"); 45239 this.#editorContentElement.removeAttribute("aria-activedescendant"); 45240 this.#editorContentElement.removeAttribute("aria-haspopup"); 45241 } 45242 #setEditorAssociationAttribute(name, value) { 45243 if (this.#editorContentElement.getAttribute(name) !== value) { 45244 this.#editorContentElement.setAttribute(name, value); 45245 } 45246 } 45247 // Right after a Turbo history restore the editor reconnects before the DOM selection 45248 // is re-established, so the cursor geometry is momentarily unavailable. Anchoring then 45249 // would pin the menu to the editor's left edge for the rest of the open cycle, so we 45250 // skip it and let a later reposition anchor it once the selection is ready. The menu 45251 // stays hidden until anchored (see the `[data-anchored]` rule in the stylesheet). 45252 #positionPopover() { 45253 const cursorPosition = this.#selection.cursorPosition; 45254 if (!cursorPosition) return; 45255 const { x: x3, y: y3, fontSize } = cursorPosition; 45256 const editorRect = this.#editorElement.getBoundingClientRect(); 45257 const contentRect = this.#editorContentElement.getBoundingClientRect(); 45258 const verticalOffset = contentRect.top - editorRect.top; 45259 if (!this.popoverElement.hasAttribute("data-anchored")) { 45260 this.#setPopoverOffsetX(x3); 45261 this.#setPopoverOffsetY(y3 + verticalOffset); 45262 this.popoverElement.toggleAttribute("data-anchored", true); 45263 } 45264 const popoverRect = this.popoverElement.getBoundingClientRect(); 45265 if (popoverRect.right > editorRect.right) { 45266 this.popoverElement.toggleAttribute("data-clipped-at-right", true); 45267 } 45268 const forceTop = this.verticalDirection === "top"; 45269 const forceBottom = this.verticalDirection === "bottom"; 45270 const overflowsWindow = popoverRect.bottom > window.innerHeight; 45271 if (!forceBottom && (forceTop || overflowsWindow)) { 45272 this.#setPopoverOffsetY(contentRect.height - y3 + fontSize); 45273 this.popoverElement.toggleAttribute("data-clipped-at-bottom", true); 45274 } 45275 } 45276 #setPopoverOffsetX(value) { 45277 this.popoverElement.style.setProperty("--lexxy-prompt-offset-x", `${value}px`); 45278 } 45279 #setPopoverOffsetY(value) { 45280 this.popoverElement.style.setProperty("--lexxy-prompt-offset-y", `${value}px`); 45281 } 45282 #resetPopoverPosition() { 45283 this.popoverElement.removeAttribute("data-clipped-at-bottom"); 45284 this.popoverElement.removeAttribute("data-clipped-at-right"); 45285 this.popoverElement.removeAttribute("data-anchored"); 45286 } 45287 async #hidePopover() { 45288 this.showPopoverId++; 45289 this.#clearSelection(); 45290 this.popoverElement.classList.toggle("lexxy-prompt-menu--visible", false); 45291 this.#popoverListeners.dispose(); 45292 await nextFrame(); 45293 this.#addTriggerListener(); 45294 } 45295 // The popover is appended to the <lexxy-editor> subtree, so Turbo serializes it 45296 // into the page cache. Removing it before caching prevents an orphaned, unmanaged 45297 // popover from being restored on history back/forward. 45298 #removePopoverBeforeTurboCaches() { 45299 this.#globalListeners.track( 45300 registerEventListener(document, "turbo:before-cache", () => this.#removePopover()) 45301 ); 45302 } 45303 #removePopover() { 45304 this.#popoverListeners.dispose(); 45305 this.popoverElement?.remove(); 45306 this.popoverElement = null; 45307 } 45308 #filterOptions = async () => { 45309 if (this.initialPrompt) { 45310 this.initialPrompt = false; 45311 return; 45312 } 45313 if (this.#editorContents.containsTextBackUntil(this.trigger)) { 45314 await this.#showFilteredOptions(); 45315 if (!this.#editorContents.containsTextBackUntil(this.trigger)) { 45316 this.#hidePopover(); 45317 return; 45318 } 45319 await nextFrame(); 45320 this.#positionPopover(); 45321 } else { 45322 this.#hidePopover(); 45323 } 45324 }; 45325 async #showFilteredOptions() { 45326 const showId = this.showPopoverId; 45327 const filter = this.#editorContents.textBackUntil(this.trigger); 45328 const filteredListItems = await this.source.buildListItems(filter); 45329 if (this.showPopoverId !== showId) return; 45330 if (!this.#editorContents.containsTextBackUntil(this.trigger)) return; 45331 this.popoverElement.innerHTML = ""; 45332 if (filteredListItems.length > 0) { 45333 this.#showResults(filteredListItems); 45334 } else { 45335 this.#showEmptyResults(); 45336 } 45337 this.#selectFirstOption(); 45338 } 45339 #showResults(filteredListItems) { 45340 this.popoverElement.classList.remove("lexxy-prompt-menu--empty"); 45341 this.popoverElement.append(...filteredListItems); 45342 } 45343 #showEmptyResults() { 45344 this.popoverElement.classList.add("lexxy-prompt-menu--empty"); 45345 const el = createElement("li", { textContent: this.#emptyResultsMessage }); 45346 el.classList.add("lexxy-prompt-menu__item--empty"); 45347 this.popoverElement.append(el); 45348 } 45349 get #emptyResultsMessage() { 45350 return this.getAttribute("empty-results") || NOTHING_FOUND_DEFAULT_MESSAGE; 45351 } 45352 #handleKeydownOnPopover = (event) => { 45353 if (event.key === "Escape") { 45354 this.#hidePopover(); 45355 this.#editorElement.focus(); 45356 event.stopPropagation(); 45357 } else if (event.key === ",") { 45358 event.preventDefault(); 45359 event.stopPropagation(); 45360 this.#optionWasSelected(); 45361 this.#editor.update(() => { 45362 const selection = $getSelection2(); 45363 if ($isRangeSelection2(selection)) { 45364 selection.insertText(","); 45365 } 45366 }); 45367 } 45368 }; 45369 // Android Mobile keyboard doesn't trigger KEY_SPACE_COMMAND 45370 #handleInputCommand(event) { 45371 if (event.inputType === "insertText" && event.data === " ") return this.#handleSelectedOption(event); 45372 } 45373 #moveSelectionDown() { 45374 const nextIndex = this.#selectedIndex + 1; 45375 if (nextIndex < this.#listItemElements.length) this.#selectOption(this.#listItemElements[nextIndex], { scrollIntoView: true }); 45376 } 45377 #moveSelectionUp() { 45378 const previousIndex = this.#selectedIndex - 1; 45379 if (previousIndex >= 0) this.#selectOption(this.#listItemElements[previousIndex], { scrollIntoView: true }); 45380 } 45381 get #selectedIndex() { 45382 return this.#listItemElements.findIndex((item) => item.hasAttribute("aria-selected")); 45383 } 45384 get #selectedListItem() { 45385 return this.#listItemElements[this.#selectedIndex]; 45386 } 45387 #handleSelectedOption(event) { 45388 event.preventDefault(); 45389 event.stopPropagation(); 45390 this.#optionWasSelected(); 45391 return true; 45392 } 45393 #optionWasSelected() { 45394 this.#replaceTriggerWithSelectedItem(); 45395 this.#hidePopover(); 45396 this.#editorElement.focus(); 45397 } 45398 #replaceTriggerWithSelectedItem() { 45399 const promptItem = this.source.promptItemFor(this.#selectedListItem); 45400 if (!promptItem) { 45401 return; 45402 } 45403 const templates = Array.from(promptItem.querySelectorAll("template[type='editor']")); 45404 const stringToReplace = `${this.trigger}${this.#editorContents.textBackUntil(this.trigger)}`; 45405 if (this.hasAttribute("insert-editable-text")) { 45406 this.#insertTemplatesAsEditableText(templates, stringToReplace); 45407 } else { 45408 this.#insertTemplatesAsAttachments(templates, stringToReplace, promptItem.getAttribute("sgid")); 45409 } 45410 } 45411 #insertTemplatesAsEditableText(templates, stringToReplace) { 45412 this.#editor.update(() => { 45413 const nodes = templates.flatMap((template) => this.#buildEditableTextNodes(template)); 45414 this.#editorContents.replaceTextBackUntil(stringToReplace, nodes); 45415 }); 45416 } 45417 #buildEditableTextNodes(template) { 45418 return this.#editorElement.$generateNodesFromDOM(parseHtml(`${template.innerHTML}`)); 45419 } 45420 #insertTemplatesAsAttachments(templates, stringToReplace, fallbackSgid = null) { 45421 this.#editor.update(() => { 45422 const attachmentNodes = this.#buildAttachmentNodes(templates, fallbackSgid); 45423 const spacedAttachmentNodes = attachmentNodes.flatMap((node) => [node, this.#getSpacerTextNode()]).slice(0, -1); 45424 this.#editorContents.replaceTextBackUntil(stringToReplace, spacedAttachmentNodes); 45425 }); 45426 } 45427 #buildAttachmentNodes(templates, fallbackSgid = null) { 45428 return templates.filter((template) => this.#editorElement.permitsAttachmentContentType( 45429 template.getAttribute("content-type") || this.#defaultPromptContentType 45430 )).map((template) => this.#buildAttachmentNode( 45431 template.innerHTML, 45432 template.getAttribute("content-type") || this.#defaultPromptContentType, 45433 template.getAttribute("sgid") || fallbackSgid 45434 )); 45435 } 45436 #getSpacerTextNode() { 45437 return $createTextNode2(" "); 45438 } 45439 get #defaultPromptContentType() { 45440 const attachmentContentTypeNamespace = Lexxy.global.get("attachmentContentTypeNamespace"); 45441 return `application/vnd.${attachmentContentTypeNamespace}.${this.name}`; 45442 } 45443 #buildAttachmentNode(innerHtml, contentType, sgid) { 45444 return new CustomActionTextAttachmentNode({ sgid, contentType, innerHtml }); 45445 } 45446 get #editorContents() { 45447 return this.#editorElement.contents; 45448 } 45449 get #editorContentElement() { 45450 return this.#editorElement.editorContentElement; 45451 } 45452 async #buildPopover() { 45453 const popoverContainer = createElement("ul", { role: "listbox", id: generateDomId("prompt-popover") }); 45454 popoverContainer.classList.add("lexxy-prompt-menu"); 45455 popoverContainer.style.position = "absolute"; 45456 popoverContainer.setAttribute("nonce", getNonce()); 45457 popoverContainer.append(...await this.source.buildListItems()); 45458 this.#globalListeners.track(registerEventListener(popoverContainer, "click", this.#handlePopoverClick)); 45459 this.#editorElement.appendChild(popoverContainer); 45460 return popoverContainer; 45461 } 45462 #handlePopoverClick = (event) => { 45463 const listItem = event.target.closest(".lexxy-prompt-menu__item"); 45464 if (listItem) { 45465 this.#selectOption(listItem); 45466 this.#optionWasSelected(); 45467 } 45468 }; 45469 #reconnect() { 45470 this.disconnectedCallback(); 45471 this.connectedCallback(); 45472 } 45473 }; 45474 var CodeLanguagePicker = class extends HTMLElement { 45475 #abortController = null; 45476 #listeners = new ListenerBin(); 45477 connectedCallback() { 45478 this.editorElement = this.closest("lexxy-editor"); 45479 this.editor = this.editorElement.editor; 45480 this.classList.add("lexxy-floating-controls"); 45481 this.#abortController = new AbortController(); 45482 this.#listeners.track(() => this.#abortController?.abort()); 45483 this.#attachLanguagePicker(); 45484 this.#hide(); 45485 this.#monitorForCodeBlockSelection(); 45486 } 45487 disconnectedCallback() { 45488 this.dispose(); 45489 } 45490 dispose() { 45491 this.#listeners.dispose(); 45492 } 45493 #attachLanguagePicker() { 45494 this.languagePickerElement = this.#findLanguagePicker() ?? this.#createLanguagePicker(); 45495 const signal2 = this.#abortController.signal; 45496 this.#listeners.track(registerEventListener(this.languagePickerElement, "change", () => { 45497 this.#updateCodeBlockLanguage(this.languagePickerElement.value); 45498 }, { signal: signal2 })); 45499 this.#listeners.track(registerEventListener(this.languagePickerElement, "mousedown", (event) => { 45500 this.#dispatchOpenEvent(event); 45501 }, { signal: signal2 })); 45502 this.languagePickerElement.setAttribute("nonce", getNonce()); 45503 this.appendChild(this.languagePickerElement); 45504 } 45505 #findLanguagePicker() { 45506 return this.querySelector("select"); 45507 } 45508 #createLanguagePicker() { 45509 const selectElement = createElement("select", { className: "lexxy-code-language-picker", "aria-label": "Pick a language\u2026", name: "lexxy-code-language" }); 45510 for (const [value, label] of Object.entries(this.#languages)) { 45511 const option = document.createElement("option"); 45512 option.value = value; 45513 option.textContent = label; 45514 selectElement.appendChild(option); 45515 } 45516 return selectElement; 45517 } 45518 get #languages() { 45519 const languages = { ...CODE_LANGUAGE_FRIENDLY_NAME_MAP4 }; 45520 languages.ruby ||= "Ruby"; 45521 languages.php ||= "PHP"; 45522 languages.go ||= "Go"; 45523 languages.bash ||= "Bash"; 45524 languages.json ||= "JSON"; 45525 languages.diff ||= "Diff"; 45526 languages.kotlin ||= "Kotlin"; 45527 delete languages.plain; 45528 const sortedEntries = Object.entries(languages).sort((a2, b3) => a2[1].localeCompare(b3[1])); 45529 return { plain: "Plain text", ...Object.fromEntries(sortedEntries) }; 45530 } 45531 #dispatchOpenEvent(event) { 45532 const handled = !dispatch(this.editorElement, "lexxy:code-language-picker-open", { 45533 languages: this.#bridgeLanguages, 45534 currentLanguage: this.languagePickerElement.value 45535 }, true); 45536 if (handled) { 45537 event.preventDefault(); 45538 } 45539 } 45540 get #bridgeLanguages() { 45541 return Object.entries(this.#languages).map(([key, name]) => ({ key, name })); 45542 } 45543 #updateCodeBlockLanguage(language) { 45544 this.editor.update(() => { 45545 const codeNode = this.#getCurrentCodeNode(); 45546 if (codeNode) { 45547 codeNode.setLanguage(language); 45548 } 45549 }); 45550 } 45551 #monitorForCodeBlockSelection() { 45552 this.#listeners.track(this.editor.registerUpdateListener(({ editorState }) => { 45553 editorState.read(() => { 45554 const codeNode = this.#getCurrentCodeNode(); 45555 if (codeNode) { 45556 this.#codeNodeWasSelected(codeNode); 45557 } else { 45558 this.#hide(); 45559 } 45560 }); 45561 })); 45562 } 45563 #getCurrentCodeNode() { 45564 return this.editorElement.selection.nearestNodeOfType(CodeNode3); 45565 } 45566 #codeNodeWasSelected(codeNode) { 45567 const language = codeNode.getLanguage(); 45568 this.#updateLanguagePickerWith(language); 45569 this.#show(); 45570 this.#positionLanguagePicker(codeNode); 45571 } 45572 #updateLanguagePickerWith(language) { 45573 if (this.languagePickerElement && language) { 45574 const normalizedLanguage = normalizeCodeLang2(language); 45575 this.languagePickerElement.value = normalizedLanguage; 45576 } 45577 } 45578 #positionLanguagePicker(codeNode) { 45579 const codeElement = this.editor.getElementByKey(codeNode.getKey()); 45580 if (!codeElement) return; 45581 const codeRect = codeElement.getBoundingClientRect(); 45582 const editorRect = this.editorElement.getBoundingClientRect(); 45583 const relativeTop = codeRect.top - editorRect.top; 45584 const relativeRight = editorRect.right - codeRect.right; 45585 this.style.top = `${relativeTop}px`; 45586 this.style.right = `${relativeRight}px`; 45587 } 45588 #show() { 45589 this.hidden = false; 45590 } 45591 #hide() { 45592 this.hidden = true; 45593 } 45594 }; 45595 var DELETE_ICON = `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 45596 <path d="M11.2041 1.01074C12.2128 1.113 13 1.96435 13 3V4H15L15.1025 4.00488C15.6067 4.05621 16 4.48232 16 5C16 5.55228 15.5523 6 15 6H14.8457L14.1416 15.1533C14.0614 16.1953 13.1925 17 12.1475 17H5.85254L5.6582 16.9902C4.76514 16.9041 4.03607 16.2296 3.88184 15.3457L3.8584 15.1533L3.1543 6H3C2.44772 6 2 5.55228 2 5C2 4.44772 2.44772 4 3 4H5V3C5 1.89543 5.89543 1 7 1H11L11.2041 1.01074ZM5.85254 15H12.1475L12.8398 6H5.16016L5.85254 15ZM7 4H11V3H7V4Z"/> 45597</svg>`; 45598 var NodeDeleteButton = class extends HTMLElement { 45599 connectedCallback() { 45600 this.editorElement = this.closest("lexxy-editor"); 45601 this.editor = this.editorElement.editor; 45602 this.classList.add("lexxy-floating-controls"); 45603 if (!this.querySelector(".lexxy-node-delete")) { 45604 this.#attachDeleteButton(); 45605 } 45606 } 45607 disconnectedCallback() { 45608 this.editor = null; 45609 this.editorElement = null; 45610 } 45611 #attachDeleteButton() { 45612 const container = createElement("div", { className: "lexxy-floating-controls__group" }); 45613 this.deleteButton = createElement("button", { 45614 className: "lexxy-node-delete", 45615 type: "button", 45616 "aria-label": "Remove" 45617 }); 45618 this.deleteButton.tabIndex = -1; 45619 this.deleteButton.innerHTML = DELETE_ICON; 45620 this.handleDeleteClick = () => this.#deleteNode(); 45621 this.deleteButton.addEventListener("click", this.handleDeleteClick); 45622 container.appendChild(this.deleteButton); 45623 this.appendChild(container); 45624 } 45625 #deleteNode() { 45626 this.editor.update(() => { 45627 const node = $getNearestNodeFromDOMNode2(this); 45628 node?.remove(); 45629 }); 45630 } 45631 }; 45632 var TableController = class { 45633 #listeners = new ListenerBin(); 45634 constructor(editorElement) { 45635 this.editor = editorElement.editor; 45636 this.contents = editorElement.contents; 45637 this.selection = editorElement.selection; 45638 this.currentTableNodeKey = null; 45639 this.currentCellKey = null; 45640 this.#registerKeyHandlers(); 45641 } 45642 destroy() { 45643 this.currentTableNodeKey = null; 45644 this.currentCellKey = null; 45645 this.#listeners.dispose(); 45646 } 45647 get currentCell() { 45648 if (!this.currentCellKey) return null; 45649 return this.editor.getEditorState().read(() => { 45650 const cell = $getNodeByKey2(this.currentCellKey); 45651 return cell instanceof TableCellNode2 ? cell : null; 45652 }); 45653 } 45654 get currentTableNode() { 45655 if (!this.currentTableNodeKey) return null; 45656 return this.editor.getEditorState().read(() => { 45657 const tableNode = $getNodeByKey2(this.currentTableNodeKey); 45658 return tableNode instanceof TableNode2 ? tableNode : null; 45659 }); 45660 } 45661 get currentRowCells() { 45662 const currentRowIndex = this.currentRowIndex; 45663 const rows = this.tableRows; 45664 if (!rows) return null; 45665 return this.editor.getEditorState().read(() => { 45666 return rows[currentRowIndex]?.getChildren() ?? null; 45667 }) ?? null; 45668 } 45669 get currentRowIndex() { 45670 const currentCell = this.currentCell; 45671 if (!currentCell) return 0; 45672 return this.editor.getEditorState().read(() => { 45673 return $getTableRowIndexFromTableCellNode2(currentCell); 45674 }) ?? 0; 45675 } 45676 get currentColumnCells() { 45677 const columnIndex = this.currentColumnIndex; 45678 const rows = this.tableRows; 45679 if (!rows) return null; 45680 return this.editor.getEditorState().read(() => { 45681 return rows.map((row) => row.getChildAtIndex(columnIndex)); 45682 }) ?? null; 45683 } 45684 get currentColumnIndex() { 45685 const currentCell = this.currentCell; 45686 if (!currentCell) return 0; 45687 return this.editor.getEditorState().read(() => { 45688 return $getTableColumnIndexFromTableCellNode2(currentCell); 45689 }) ?? 0; 45690 } 45691 get tableRows() { 45692 return this.editor.getEditorState().read(() => { 45693 return this.currentTableNode?.getChildren(); 45694 }) ?? null; 45695 } 45696 updateSelectedTable() { 45697 let cellNode = null; 45698 let tableNode = null; 45699 this.editor.getEditorState().read(() => { 45700 const selection = $getSelection2(); 45701 if (!selection || !this.selection.isTableCellSelected) return; 45702 const node = selection.getNodes()[0]; 45703 cellNode = $findCellNode2(node); 45704 tableNode = $findTableNode2(node); 45705 }); 45706 this.currentCellKey = cellNode?.getKey() ?? null; 45707 this.currentTableNodeKey = tableNode?.getKey() ?? null; 45708 return tableNode; 45709 } 45710 executeTableCommand(command, customIndex = null) { 45711 if (command.action === "delete" && command.childType === "table") { 45712 this.#deleteTable(); 45713 return; 45714 } 45715 if (command.action === "toggle") { 45716 this.#executeToggleStyle(command); 45717 return; 45718 } 45719 this.#executeCommand(command, customIndex); 45720 } 45721 #executeCommand(command, customIndex = null) { 45722 this.#selectCellAtSelection(); 45723 this.editor.dispatchCommand(this.#commandName(command)); 45724 this.#selectNextBestCell(command, customIndex); 45725 } 45726 #executeToggleStyle(command) { 45727 const childType = command.childType; 45728 let cells = null; 45729 let headerState = null; 45730 if (childType === "row") { 45731 cells = this.currentRowCells; 45732 headerState = TableCellHeaderStates2.ROW; 45733 } else if (childType === "column") { 45734 cells = this.currentColumnCells; 45735 headerState = TableCellHeaderStates2.COLUMN; 45736 } 45737 if (!cells || cells.length === 0) return; 45738 this.editor.update(() => { 45739 const firstCell = $getTableCellNodeFromLexicalNode2(cells[0]); 45740 if (!firstCell) return; 45741 const currentStyle = firstCell.getHeaderStyles(); 45742 const newStyle = currentStyle ^ headerState; 45743 cells.forEach((cell) => { 45744 this.#setHeaderStyle(cell, newStyle, headerState); 45745 }); 45746 }); 45747 } 45748 #deleteTable() { 45749 this.#selectCellAtSelection(); 45750 this.editor.dispatchCommand("deleteTable"); 45751 } 45752 #selectCellAtSelection() { 45753 this.editor.update(() => { 45754 const selection = $getSelection2(); 45755 if (!selection) return; 45756 const node = selection.getNodes()[0]; 45757 $findCellNode2(node)?.selectEnd(); 45758 }); 45759 } 45760 #commandName(command) { 45761 const { action, childType, direction } = command; 45762 const childTypeSuffix = upcaseFirst(childType); 45763 const directionSuffix = action == "insert" ? upcaseFirst(direction) : ""; 45764 return `${action}Table${childTypeSuffix}${directionSuffix}`; 45765 } 45766 #setHeaderStyle(cell, newStyle, headerState) { 45767 const tableCellNode = $getTableCellNodeFromLexicalNode2(cell); 45768 tableCellNode?.setHeaderStyles(newStyle, headerState); 45769 } 45770 async #selectCellAtIndex(rowIndex, columnIndex) { 45771 await nextFrame(); 45772 if (!this.currentTableNode) return; 45773 const rows = this.tableRows; 45774 if (!rows) return; 45775 const row = rows[rowIndex]; 45776 if (!row) return; 45777 this.editor.update(() => { 45778 const cell = $getTableCellNodeFromLexicalNode2(row.getChildAtIndex(columnIndex)); 45779 cell?.selectEnd(); 45780 }); 45781 } 45782 #selectNextBestCell(command, customIndex = null) { 45783 const { childType, direction } = command; 45784 let rowIndex = this.currentRowIndex; 45785 let columnIndex = customIndex !== null ? customIndex : this.currentColumnIndex; 45786 const deleteOffset = command.action === "delete" ? -1 : 0; 45787 const offset3 = direction === "after" ? 1 : deleteOffset; 45788 if (childType === "row") { 45789 rowIndex += offset3; 45790 } else if (childType === "column") { 45791 columnIndex += offset3; 45792 } 45793 this.#selectCellAtIndex(rowIndex, columnIndex); 45794 } 45795 #selectNextRow() { 45796 const rows = this.tableRows; 45797 if (!rows) return; 45798 const nextRow = rows.at(this.currentRowIndex + 1); 45799 if (!nextRow) return; 45800 this.editor.update(() => { 45801 nextRow.getChildAtIndex(this.currentColumnIndex)?.selectEnd(); 45802 }); 45803 } 45804 #selectPreviousCell() { 45805 const cell = this.currentCell; 45806 if (!cell) return; 45807 this.editor.update(() => { 45808 cell.selectPrevious(); 45809 }); 45810 } 45811 #insertRowAndSelectFirstCell() { 45812 this.executeTableCommand({ action: "insert", childType: "row", direction: "after" }, 0); 45813 } 45814 #deleteRowAndSelectLastCell() { 45815 this.executeTableCommand({ action: "delete", childType: "row" }, -1); 45816 } 45817 #deleteRowAndSelectNextNode() { 45818 const tableNode = this.currentTableNode; 45819 this.executeTableCommand({ action: "delete", childType: "row" }); 45820 this.editor.update(() => { 45821 const next = tableNode?.getNextSibling(); 45822 if ($isParagraphNode2(next)) { 45823 next.selectStart(); 45824 } else { 45825 const newParagraph = $createParagraphNode2(); 45826 this.currentTableNode.insertAfter(newParagraph); 45827 newParagraph.selectStart(); 45828 } 45829 }); 45830 } 45831 #isCurrentCellEmpty() { 45832 if (!this.currentTableNode) return false; 45833 const cell = this.currentCell; 45834 if (!cell) return false; 45835 return cell.getTextContent().trim() === ""; 45836 } 45837 #isCurrentRowLast() { 45838 if (!this.currentTableNode) return false; 45839 const rows = this.tableRows; 45840 if (!rows) return false; 45841 return rows.length === this.currentRowIndex + 1; 45842 } 45843 #isCurrentRowEmpty() { 45844 if (!this.currentTableNode) return false; 45845 const cells = this.currentRowCells; 45846 if (!cells) return false; 45847 return cells.every((cell) => cell.getTextContent().trim() === ""); 45848 } 45849 #isFirstCellInRow() { 45850 if (!this.currentTableNode) return false; 45851 const cells = this.currentRowCells; 45852 if (!cells) return false; 45853 return cells.indexOf(this.currentCell) === 0; 45854 } 45855 #registerKeyHandlers() { 45856 this.#listeners.track( 45857 this.editor.registerCommand(KEY_BACKSPACE_COMMAND2, (event) => this.#handleBackspaceKey(event), COMMAND_PRIORITY_HIGH2), 45858 this.editor.registerCommand(KEY_ENTER_COMMAND2, (event) => this.#handleEnterKey(event), COMMAND_PRIORITY_HIGH2) 45859 ); 45860 } 45861 #handleBackspaceKey(event) { 45862 if (!this.currentTableNode) return false; 45863 if (this.#isCurrentRowEmpty() && this.#isFirstCellInRow()) { 45864 event.preventDefault(); 45865 this.#deleteRowAndSelectLastCell(); 45866 return true; 45867 } 45868 if (this.#isCurrentCellEmpty() && !this.#isFirstCellInRow()) { 45869 event.preventDefault(); 45870 this.#selectPreviousCell(); 45871 return true; 45872 } 45873 return false; 45874 } 45875 #handleEnterKey(event) { 45876 if (event.ctrlKey || event.metaKey || event.shiftKey || !this.currentTableNode) return false; 45877 if (this.selection.isInsideList || this.selection.isInsideCodeBlock) return false; 45878 event.preventDefault(); 45879 if (this.#isCurrentRowLast() && this.#isCurrentRowEmpty()) { 45880 this.#deleteRowAndSelectNextNode(); 45881 } else if (this.#isCurrentRowLast()) { 45882 this.#insertRowAndSelectFirstCell(); 45883 } else { 45884 this.#selectNextRow(); 45885 } 45886 return true; 45887 } 45888 }; 45889 var TableIcons = { 45890 "insert-row-before": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 45891 <path fill-rule="evenodd" clip-rule="evenodd" d="M7.86804e-07 15C8.29055e-07 15.8284 0.671574 16.5 1.5 16.5H15L15.1533 16.4922C15.8593 16.4205 16.4205 15.8593 16.4922 15.1533L16.5 15V4.5L16.4922 4.34668C16.4154 3.59028 15.7767 3 15 3H13.5L13.5 4.5H15V9H1.5L1.5 4.5L3 4.5V3H1.5C0.671574 3 1.20956e-06 3.67157 1.24577e-06 4.5L7.86804e-07 15ZM15 10.5V15H1.5L1.5 10.5H15Z"/> 45892 <path d="M4.5 4.5H7.5V7.5H9V4.5H12L12 3L9 3V6.55671e-08L7.5 0V3L4.5 3V4.5Z"/> 45893 </svg>`, 45894 "insert-row-after": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 45895 <path fill-rule="evenodd" clip-rule="evenodd" d="M7.86804e-07 13.5C7.50592e-07 14.3284 0.671574 15 1.5 15H3V13.5H1.5L1.5 9L15 9V13.5H13.5V15H15C15.7767 15 16.4154 14.4097 16.4922 13.6533L16.5 13.5V3L16.4922 2.84668C16.4205 2.14069 15.8593 1.57949 15.1533 1.50781L15 1.5L1.5 1.5C0.671574 1.5 1.28803e-06 2.17157 1.24577e-06 3L7.86804e-07 13.5ZM15 3V7.5L1.5 7.5L1.5 3L15 3Z"/> 45896 <path d="M7.5 15V18H9V15H12V13.5H9V10.5H7.5V13.5H4.5V15H7.5Z"/> 45897 </svg>`, 45898 "delete-row": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 45899 <path d="M16.4922 12.1533C16.4154 12.9097 15.7767 13.5 15 13.5L12 13.5V12H15V6L1.5 6L1.5 12H4.5V13.5H1.5C0.723337 13.5 0.0846104 12.9097 0.00781328 12.1533L7.86804e-07 12L1.04907e-06 6C1.17362e-06 5.22334 0.590278 4.58461 1.34668 4.50781L1.5 4.5L15 4.5C15.8284 4.5 16.5 5.17157 16.5 6V12L16.4922 12.1533Z"/> 45900 <path d="M10.3711 15.9316L8.25 13.8096L6.12793 15.9316L5.06738 14.8711L7.18945 12.75L5.06738 10.6289L6.12793 9.56836L8.25 11.6895L10.3711 9.56836L11.4316 10.6289L9.31055 12.75L11.4316 14.8711L10.3711 15.9316Z"/> 45901 </svg>`, 45902 "toggle-row": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 45903 <path fill-rule="evenodd" clip-rule="evenodd" d="M0.00781328 13.6533C0.0846108 14.4097 0.723337 15 1.5 15L15 15L15.1533 14.9922C15.8593 14.9205 16.4205 14.3593 16.4922 13.6533L16.5 13.5V4.5L16.4922 4.34668C16.4205 3.64069 15.8593 3.07949 15.1533 3.00781L15 3L1.5 3C0.671574 3 1.24863e-06 3.67157 1.18021e-06 4.5L7.86804e-07 13.5L0.00781328 13.6533ZM15 9V13.5L1.5 13.5L1.5 9L15 9Z"/> 45904 </svg>`, 45905 "insert-column-before": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 45906 <path fill-rule="evenodd" clip-rule="evenodd" d="M4.5 0C3.67157 0 3 0.671573 3 1.5V3H4.5V1.5H9V15H4.5V13.5H3V15C3 15.7767 3.59028 16.4154 4.34668 16.4922L4.5 16.5H15L15.1533 16.4922C15.8593 16.4205 16.4205 15.8593 16.4922 15.1533L16.5 15V1.5C16.5 0.671573 15.8284 6.03989e-09 15 0H4.5ZM15 15H10.5V1.5H15V15Z"/> 45907 <path d="M3 7.5H0V9H3V12H4.5V9H7.5V7.5H4.5V4.5H3V7.5Z"/> 45908 </svg>`, 45909 "insert-column-after": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 45910 <path fill-rule="evenodd" clip-rule="evenodd" d="M13.5 0C14.3284 0 15 0.671573 15 1.5V3H13.5V1.5H9V15H13.5V13.5H15V15C15 15.7767 14.4097 16.4154 13.6533 16.4922L13.5 16.5H3L2.84668 16.4922C2.14069 16.4205 1.57949 15.8593 1.50781 15.1533L1.5 15V1.5C1.5 0.671573 2.17157 6.03989e-09 3 0H13.5ZM3 15H7.5V1.5H3V15Z"/> 45911 <path d="M15 7.5H18V9H15V12H13.5V9H10.5V7.5H13.5V4.5H15V7.5Z"/> 45912 </svg>`, 45913 "delete-column": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 45914 <path d="M12.1533 0.0078125C12.9097 0.0846097 13.5 0.723336 13.5 1.5V4.5H12V1.5H6V15H12V12H13.5V15C13.5 15.7767 12.9097 16.4154 12.1533 16.4922L12 16.5H6C5.22334 16.5 4.58461 15.9097 4.50781 15.1533L4.5 15V1.5C4.5 0.671573 5.17157 2.41596e-08 6 0H12L12.1533 0.0078125Z"/> 45915 <path d="M15.9316 6.12891L13.8105 8.24902L15.9326 10.3711L14.8711 11.4316L12.75 9.31055L10.6289 11.4316L9.56738 10.3711L11.6885 8.24902L9.56836 6.12891L10.6289 5.06836L12.75 7.18848L14.8711 5.06836L15.9316 6.12891Z"/> 45916 </svg>`, 45917 "toggle-column": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 45918 <path fill-rule="evenodd" clip-rule="evenodd" d="M13.6533 17.9922C14.4097 17.9154 15 17.2767 15 16.5L15 3L14.9922 2.84668C14.9205 2.14069 14.3593 1.57949 13.6533 1.50781L13.5 1.5L4.5 1.5L4.34668 1.50781C3.59028 1.58461 3 2.22334 3 3L3 16.5C3 17.2767 3.59028 17.9154 4.34668 17.9922L4.5 18L13.5 18L13.6533 17.9922ZM9 3L13.5 3L13.5 16.5L9 16.5L9 3Z"/> 45919 </svg>`, 45920 "delete-table": `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> 45921 <path d="M11.2041 1.01074C12.2128 1.113 13 1.96435 13 3V4H15L15.1025 4.00488C15.6067 4.05621 16 4.48232 16 5C16 5.55228 15.5523 6 15 6H14.8457L14.1416 15.1533C14.0614 16.1953 13.1925 17 12.1475 17H5.85254L5.6582 16.9902C4.76514 16.9041 4.03607 16.2296 3.88184 15.3457L3.8584 15.1533L3.1543 6H3C2.44772 6 2 5.55228 2 5C2 4.44772 2.44772 4 3 4H5V3C5 1.89543 5.89543 1 7 1H11L11.2041 1.01074ZM5.85254 15H12.1475L12.8398 6H5.16016L5.85254 15ZM7 4H11V3H7V4Z"/> 45922 </svg>` 45923 }; 45924 var TableTools = class extends HTMLElement { 45925 #listeners = new ListenerBin(); 45926 connectedCallback() { 45927 this.tableController = new TableController(this.#editorElement); 45928 this.classList.add("lexxy-floating-controls"); 45929 this.role = "toolbar"; 45930 this.#setUpButtons(); 45931 this.#hide(); 45932 this.#monitorForTableSelection(); 45933 this.#registerKeyboardShortcuts(); 45934 } 45935 disconnectedCallback() { 45936 this.dispose(); 45937 } 45938 dispose() { 45939 this.#listeners.dispose(); 45940 this.tableController?.destroy(); 45941 this.tableController = null; 45942 } 45943 get #editor() { 45944 return this.#editorElement.editor; 45945 } 45946 get #editorElement() { 45947 return this.closest("lexxy-editor"); 45948 } 45949 get #tableToolsButtons() { 45950 return Array.from(this.querySelectorAll("button, details > summary")); 45951 } 45952 #setUpButtons() { 45953 this.innerHTML = ""; 45954 this.appendChild(this.#createRowButtonsContainer()); 45955 this.appendChild(this.#createColumnButtonsContainer()); 45956 this.appendChild(this.#createDeleteTableButton()); 45957 this.#listeners.track(registerEventListener(this, "keydown", this.#handleToolsKeydown)); 45958 } 45959 #createButtonsContainer(childType, setCountProperty, moreMenu) { 45960 const container = createElement("div", { className: `lexxy-floating-controls__group lexxy-table-control lexxy-table-control--${childType}` }); 45961 const plusButton = this.#createButton(`Add ${childType}`, { action: "insert", childType, direction: "after" }, "+"); 45962 const minusButton = this.#createButton(`Remove ${childType}`, { action: "delete", childType }, "\u2212"); 45963 const dropdown = createElement("details", { className: "lexxy-table-control__more-menu" }); 45964 dropdown.setAttribute("name", "lexxy-dropdown"); 45965 dropdown.tabIndex = -1; 45966 const count = createElement("summary", {}, `_ ${childType}s`); 45967 setCountProperty(count); 45968 dropdown.appendChild(count); 45969 dropdown.appendChild(moreMenu); 45970 container.appendChild(minusButton); 45971 container.appendChild(dropdown); 45972 container.appendChild(plusButton); 45973 return container; 45974 } 45975 #createRowButtonsContainer() { 45976 return this.#createButtonsContainer( 45977 "row", 45978 (count) => { 45979 this.rowCount = count; 45980 }, 45981 this.#createMoreMenuSection("row") 45982 ); 45983 } 45984 #createColumnButtonsContainer() { 45985 return this.#createButtonsContainer( 45986 "column", 45987 (count) => { 45988 this.columnCount = count; 45989 }, 45990 this.#createMoreMenuSection("column") 45991 ); 45992 } 45993 #createMoreMenuSection(childType) { 45994 const section = createElement("div", { className: "lexxy-floating-controls__group lexxy-table-control__more-menu-details" }); 45995 const addBeforeButton = this.#createButton(`Add ${childType} before`, { action: "insert", childType, direction: "before" }); 45996 const addAfterButton = this.#createButton(`Add ${childType} after`, { action: "insert", childType, direction: "after" }); 45997 const toggleStyleButton = this.#createButton(`Toggle ${childType} style`, { action: "toggle", childType }); 45998 const deleteButton = this.#createButton(`Remove ${childType}`, { action: "delete", childType }); 45999 section.appendChild(addBeforeButton); 46000 section.appendChild(addAfterButton); 46001 section.appendChild(toggleStyleButton); 46002 section.appendChild(deleteButton); 46003 return section; 46004 } 46005 #createDeleteTableButton() { 46006 const container = createElement("div", { className: "lexxy-table-control lexxy-floating-controls__group" }); 46007 const deleteTableButton = this.#createButton("Delete this table?", { action: "delete", childType: "table" }); 46008 deleteTableButton.classList.add("lexxy-table-control__button--delete-table"); 46009 container.appendChild(deleteTableButton); 46010 this.deleteContainer = container; 46011 return container; 46012 } 46013 #createButton(label, command = {}, icon = this.#icon(command)) { 46014 const button = createElement("button", { 46015 className: "lexxy-table-control__button", 46016 "aria-label": label, 46017 type: "button" 46018 }); 46019 button.tabIndex = -1; 46020 button.innerHTML = `${icon} <span>${label}</span>`; 46021 button.dataset.action = command.action; 46022 button.dataset.childType = command.childType; 46023 button.dataset.direction = command.direction; 46024 button.addEventListener("click", () => this.#executeTableCommand(command)); 46025 button.addEventListener("mouseover", () => this.#handleCommandButtonHover()); 46026 button.addEventListener("focus", () => this.#handleCommandButtonHover()); 46027 button.addEventListener("mouseout", () => this.#handleCommandButtonHover()); 46028 return button; 46029 } 46030 #registerKeyboardShortcuts() { 46031 this.#listeners.track(this.#editor.registerCommand(KEY_DOWN_COMMAND2, this.#focusToolbarOnAltF10, COMMAND_PRIORITY_HIGH2)); 46032 } 46033 #focusToolbarOnAltF10 = (event) => { 46034 if (this.#hasSelectedTable && event.altKey && event.key === "F10") { 46035 event.preventDefault(); 46036 this.#tableToolsButtons[0]?.focus({ focusVisible: true }); 46037 return true; 46038 } else { 46039 return false; 46040 } 46041 }; 46042 get #hasSelectedTable() { 46043 return this.tableController?.currentTableNodeKey != null; 46044 } 46045 #handleToolsKeydown = (event) => { 46046 if (event.key === "Escape") { 46047 this.#handleEscapeKey(); 46048 } else { 46049 handleRollingTabIndex(this.#tableToolsButtons, event); 46050 } 46051 }; 46052 #handleEscapeKey() { 46053 const cell = this.tableController.currentCell; 46054 if (!cell) return; 46055 this.#editor.update(() => { 46056 cell.select(); 46057 this.#editor.focus(); 46058 }); 46059 this.#update(); 46060 } 46061 async #handleCommandButtonHover() { 46062 await nextFrame(); 46063 this.#clearCellStyles(); 46064 const activeElement = this.querySelector("button:hover, button:focus"); 46065 if (!activeElement) return; 46066 const command = { 46067 action: activeElement.dataset.action, 46068 childType: activeElement.dataset.childType, 46069 direction: activeElement.dataset.direction 46070 }; 46071 let cellsToHighlight = null; 46072 switch (command.childType) { 46073 case "row": 46074 cellsToHighlight = this.tableController.currentRowCells; 46075 break; 46076 case "column": 46077 cellsToHighlight = this.tableController.currentColumnCells; 46078 break; 46079 case "table": 46080 cellsToHighlight = this.tableController.tableRows; 46081 break; 46082 } 46083 if (!cellsToHighlight) return; 46084 cellsToHighlight.forEach((cell) => { 46085 const cellElement = this.#editor.getElementByKey(cell.getKey()); 46086 if (!cellElement) return; 46087 cellElement.classList.toggle(theme.tableCellHighlight, true); 46088 Object.assign(cellElement.dataset, command); 46089 }); 46090 } 46091 #monitorForTableSelection() { 46092 this.#listeners.track(this.#editor.registerUpdateListener(() => { 46093 const tableNode = this.#editor.getRootElement() && this.tableController.updateSelectedTable(); 46094 if (tableNode) { 46095 this.#show(); 46096 } else { 46097 this.#hide(); 46098 } 46099 })); 46100 } 46101 #executeTableCommand(command) { 46102 this.tableController.executeTableCommand(command); 46103 this.#update(); 46104 } 46105 #show() { 46106 this.#updateButtonsPosition(); 46107 this.style.display = "flex"; 46108 this.#updateRowColumnCount(); 46109 this.#closeMoreMenu(); 46110 this.#handleCommandButtonHover(); 46111 } 46112 #hide() { 46113 this.style.display = "none"; 46114 this.#clearCellStyles(); 46115 } 46116 #update() { 46117 this.#updateButtonsPosition(); 46118 this.#updateRowColumnCount(); 46119 this.#closeMoreMenu(); 46120 this.#handleCommandButtonHover(); 46121 } 46122 #closeMoreMenu() { 46123 this.querySelector("details[open]")?.removeAttribute("open"); 46124 } 46125 #updateButtonsPosition() { 46126 const tableNode = this.tableController.currentTableNode; 46127 if (!tableNode) return; 46128 const tableElement = this.#editor.getElementByKey(tableNode.getKey()); 46129 if (!tableElement) return; 46130 const tableRect = tableElement.getBoundingClientRect(); 46131 const editorRect = this.#editorElement.getBoundingClientRect(); 46132 const relativeTop = tableRect.top - editorRect.top; 46133 const relativeCenter = (tableRect.left + tableRect.right) / 2 - editorRect.left; 46134 this.style.top = `${relativeTop}px`; 46135 this.style.left = `${relativeCenter}px`; 46136 } 46137 #updateRowColumnCount() { 46138 const tableNode = this.tableController.currentTableNode; 46139 if (!tableNode) return; 46140 const tableElement = $getElementForTableNode2(this.#editor, tableNode); 46141 if (!tableElement) return; 46142 const rowCount = tableElement.rows; 46143 const columnCount = tableElement.columns; 46144 this.rowCount.textContent = `${rowCount} row${rowCount === 1 ? "" : "s"}`; 46145 this.columnCount.textContent = `${columnCount} column${columnCount === 1 ? "" : "s"}`; 46146 } 46147 #setTableCellFocus() { 46148 const cell = this.tableController.currentCell; 46149 if (!cell) return; 46150 const cellElement = this.#editor.getElementByKey(cell.getKey()); 46151 if (!cellElement) return; 46152 cellElement.classList.add(theme.tableCellFocus); 46153 } 46154 #clearCellStyles() { 46155 this.#editorElement.querySelectorAll(`.${theme.tableCellFocus}`)?.forEach((cell) => { 46156 cell.classList.remove(theme.tableCellFocus); 46157 }); 46158 this.#editorElement.querySelectorAll(`.${theme.tableCellHighlight}`)?.forEach((cell) => { 46159 cell.classList.remove(theme.tableCellHighlight); 46160 cell.removeAttribute("data-action"); 46161 cell.removeAttribute("data-child-type"); 46162 cell.removeAttribute("data-direction"); 46163 }); 46164 this.#setTableCellFocus(); 46165 } 46166 #icon(command) { 46167 const { action, childType } = command; 46168 const direction = action == "insert" ? command.direction : null; 46169 const iconId = [action, childType, direction].filter(Boolean).join("-"); 46170 return TableIcons[iconId]; 46171 } 46172 }; 46173 function defineElements() { 46174 const elements = { 46175 // Toolbar must be registered BEFORE Editor 46176 "lexxy-toolbar": LexicalToolbarElement, 46177 "lexxy-toolbar-dropdown": ToolbarDropdown, 46178 "lexxy-heading-dropdown": HeadingDropdown, 46179 "lexxy-highlight-dropdown": HighlightDropdown, 46180 "lexxy-link-dropdown": LinkDropdown, 46181 "lexxy-editor": LexicalEditorElement, 46182 // Prompt must be registered AFTER Editor 46183 "lexxy-prompt": LexicalPromptElement, 46184 "lexxy-code-language-picker": CodeLanguagePicker, 46185 "lexxy-node-delete-button": NodeDeleteButton, 46186 "lexxy-table-tools": TableTools 46187 }; 46188 Object.entries(elements).forEach(([name, element]) => { 46189 customElements.define(name, element); 46190 }); 46191 } 46192 var configure = Lexxy.configure; 46193 setTimeout(defineElements, 0); 46194 46195
46195// app/javascript/src/lexxy/callout_icons.js 46196 var CALLOUT_ICONS = [ 46197 { 46198 id: "lightbulb", 46199 label: "Light bulb", 46200 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 12.74V17a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-2.26A7 7 0 0 0 12 2z"/></svg>` 46201 }, 46202 { 46203 id: "info", 46204 label: "Info", 46205 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/></svg>` 46206 }, 46207 { 46208 id: "warning", 46209 label: "Warning", 46210 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>` 46211 }, 46212 { 46213 id: "check", 46214 label: "Check", 46215 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 6 9 17l-5-5"/></svg>` 46216 }, 46217 { 46218 id: "x", 46219 label: "\u{1D54F} / Twitter", 46220 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>` 46221 }, 46222 { 46223 id: "star", 46224 label: "Star", 46225 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"/></svg>` 46226 }, 46227 { 46228 id: "heart", 46229 label: "Heart", 46230 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"/></svg>` 46231 }, 46232 { 46233 id: "flag", 46234 label: "Flag", 46235 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><line x1="4" x2="4" y1="22" y2="15"/></svg>` 46236 }, 46237 { 46238 id: "bookmark", 46239 label: "Bookmark", 46240 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/></svg>` 46241 }, 46242 { 46243 id: "pin", 46244 label: "Pin", 46245 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 17v5"/><path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1h2a1 1 0 0 0 0-4H8a1 1 0 0 0 0 4h2a1 1 0 0 1 1 1z"/></svg>` 46246 }, 46247 { 46248 id: "rocket", 46249 label: "Rocket", 46250 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg>` 46251 }, 46252 { 46253 id: "message", 46254 label: "Message", 46255 svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/></svg>` 46256 } 46257 ]; 46258 function calloutIconById(id3) { 46259 return CALLOUT_ICONS.find((icon) => icon.id === id3); 46260 } 46261 function isSvgMarkup(value) { 46262 return typeof value === "string" && value.trim().startsWith("<svg"); 46263 } 46264 function iconMaskUrl(svg2) { 46265 const encoded = encodeURIComponent(svg2.replace(/currentColor/g, "#000")); 46266 return `url("data:image/svg+xml,${encoded}")`; 46267 } 46268 function sanitizedSvgElement(markup) { 46269 if (!isSvgMarkup(markup)) return null; 46270 const template = document.createElement("template"); 46271 template.innerHTML = markup.trim(); 46272 const svg2 = template.content.firstElementChild; 46273 if (!svg2 || svg2.tagName.toLowerCase() !== "svg") return null; 46274 svg2.querySelectorAll("script, foreignObject").forEach((element) => element.remove()); 46275 svg2.querySelectorAll("*").forEach((element) => {
46276 Array.from(element.attributes).forEach((attribute) => { 46277 if (/^on/i.test(attribute.name) || /javascript:/i.test(attribute.value)) { 46278 element.removeAttribute(attribute.name); 46279 } 46280 }); 46281 }); 46282 svg2.setAttribute("aria-hidden", "true"); 46283 svg2.setAttribute("focusable", "false"); 46284 svg2.classList.add("lexxy-callout__icon-svg"); 46285 if (svg2.dataset.lucide) { 46286 svg2.classList.add("lucide", `lucide-${svg2.dataset.lucide}`); 46287 } 46288 return svg2; 46289 } 46290 46291
46291// app/javascript/src/lexxy/callout_assets.js 46292 var LUCIDE_ICONS_GLOBAL = "LexxyLucideCalloutIcons"; 46293 var LUCIDE_ICONS_META_SELECTOR = 'meta[name="lucide-callout-icons-src"]'; 46294 var lucideIconsPromise = null; 46295 function lucideIconsScriptSrc() { 46296 return document.querySelector(LUCIDE_ICONS_META_SELECTOR)?.content || "/assets/lucide_callout_icons.js"; 46297 } 46298 function loadLucideCalloutIcons() { 46299 if (window[LUCIDE_ICONS_GLOBAL]) return Promise.resolve(window[LUCIDE_ICONS_GLOBAL]); 46300 if (lucideIconsPromise) return lucideIconsPromise; 46301 lucideIconsPromise = new Promise((resolve, reject) => { 46302 const script = document.createElement("script"); 46303 script.async = true; 46304 script.src = lucideIconsScriptSrc(); 46305 script.addEventListener( 46306 "load", 46307 () => { 46308 if (window[LUCIDE_ICONS_GLOBAL]) { 46309 resolve(window[LUCIDE_ICONS_GLOBAL]); 46310 } else { 46311 reject(new Error("Lucide icons loaded without exposing the callout icon registry")); 46312 } 46313 }, 46314 { once: true } 46315 ); 46316 script.addEventListener( 46317 "error", 46318 () => { 46319 lucideIconsPromise = null; 46320 reject(new Error("Could not load callout icons")); 46321 }, 46322 { once: true } 46323 ); 46324 document.head.appendChild(script); 46325 }); 46326 return lucideIconsPromise; 46327 } 46328 function safeImageUrl(value) { 46329 if (!value) return null; 46330 try { 46331 const url = new URL(value, window.location.href); 46332 if (url.protocol === "data:" && !value.startsWith("data:image/")) return null; 46333 if (!["http:", "https:", "data:", "blob:"].includes(url.protocol)) return null; 46334 return url.href; 46335 } catch (_error) { 46336 return null; 46337 } 46338 } 46339 46340
46340// app/javascript/src/lexxy/callout_content.js 46341 var CALLOUT_SELECTOR = ":where(.trix-content, .lexxy-content) .lexxy-callout[data-icon-type]:not([data-icon-type='none']):not([data-icon-type='emoji'])"; 46342 var CALLOUT_ICON_SELECTOR = ":scope > .lexxy-callout__icon"; 46343 function queryCallouts(root) { 46344 if (root === document) { 46345 return document.querySelectorAll(CALLOUT_SELECTOR); 46346 } 46347 return root.querySelectorAll(".lexxy-callout[data-icon-type]:not([data-icon-type='none']):not([data-icon-type='emoji'])"); 46348 } 46349 function hasLegacyIconStyle(callout) { 46350 return callout.style.getPropertyValue("--callout-icon-mask") || callout.style.getPropertyValue("--callout-icon-image"); 46351 } 46352 function needsHydration(callout) { 46353 if (callout.closest("lexxy-editor")) return false; 46354 if (callout.querySelector(CALLOUT_ICON_SELECTOR)) return false; 46355 if (callout.dataset.calloutHydrated === "true" && !hasLegacyIconStyle(callout)) return false; 46356 const iconType = callout.dataset.iconType; 46357 if (iconType === "symbol") { 46358 return true; 46359 } 46360 if (iconType === "image") { 46361 return true; 46362 } 46363 return false; 46364 } 46365 function resolveSymbolSvg(callout) { 46366 const iconSrc = callout.dataset.iconSrc; 46367 if (isSvgMarkup(iconSrc)) return iconSrc; 46368 const builtIn = calloutIconById(callout.dataset.iconId); 46369 return builtIn?.svg || null; 46370 } 46371 function insertCalloutIcon(callout, icon) { 46372 const wrapper = document.createElement("span"); 46373 wrapper.className = "lexxy-callout__icon"; 46374 wrapper.setAttribute("aria-hidden", "true"); 46375 wrapper.append(icon); 46376 callout.querySelector(CALLOUT_ICON_SELECTOR)?.remove(); 46377 callout.insertBefore(wrapper, callout.firstChild); 46378 } 46379 function hydrateSymbolCallout(callout, svg2) { 46380 const icon = sanitizedSvgElement(svg2); 46381 if (icon) insertCalloutIcon(callout, icon); 46382 callout.style.removeProperty("--callout-icon-mask"); 46383 callout.dataset.calloutHydrated = "true"; 46384 } 46385 function hydrateImageCallout(callout) { 46386 const imageUrl = safeImageUrl(callout.dataset.iconSrc); 46387 if (!imageUrl) return; 46388 if (!callout.isConnected || callout.querySelector(CALLOUT_ICON_SELECTOR)) { 46389 return; 46390 } 46391 const image = document.createElement("img"); 46392 image.className = "lexxy-callout__icon-image"; 46393 image.decoding = "async"; 46394 image.loading = "lazy"; 46395 image.alt = ""; 46396 image.src = imageUrl; 46397 insertCalloutIcon(callout, image); 46398 callout.style.removeProperty("--callout-icon-image"); 46399 callout.dataset.calloutHydrated = "true"; 46400 } 46401 function scheduleDecorativeHydration(callback) { 46402 if ("requestIdleCallback" in window) { 46403 window.requestIdleCallback(callback, { timeout: 1200 }); 46404 } else { 46405 setTimeout(callback, 0); 46406 } 46407 } 46408 function hydrateCallouts(root = document) { 46409 const callouts = [...queryCallouts(root)].filter(needsHydration); 46410 if (callouts.length === 0) return Promise.resolve(); 46411 const pendingLucide = []; 46412 callouts.forEach((callout) => { 46413 if (callout.dataset.iconType === "image") { 46414 hydrateImageCallout(callout); 46415 return; 46416 } 46417 if (callout.dataset.iconType !== "symbol") return; 46418 const svg2 = resolveSymbolSvg(callout); 46419 if (svg2) { 46420 hydrateSymbolCallout(callout, svg2); 46421 return; 46422 } 46423 if (callout.dataset.iconId) { 46424 pendingLucide.push(callout); 46425 } 46426 }); 46427 if (pendingLucide.length > 0) { 46428 scheduleDecorativeHydration(() => { 46429 loadLucideCalloutIcons().then((lucide) => { 46430 pendingLucide.forEach((callout) => { 46431 if (!callout.isConnected || !needsHydration(callout)) return; 46432 const svg2 = lucide.svgFor(callout.dataset.iconId); 46433 if (svg2) hydrateSymbolCallout(callout, svg2); 46434 }); 46435 }).catch(() => { 46436 }); 46437 }); 46438 } 46439 return Promise.resolve(); 46440 } 46441 function scheduleCalloutHydration(root = document) { 46442 requestAnimationFrame(() => { 46443 requestAnimationFrame(() => hydrateCallouts(root)); 46444 }); 46445 } 46446 46447
46447// app/javascript/src/lexxy/code_block_copy.js 46448 var CODE_BLOCK_SELECTOR = ":where(.trix-content, .lexxy-content) pre[data-language]"; 46449 var WRAPPER_CLASS = "lexxy-code-block"; 46450 var COPY_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 7m0 2.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667z"></path><path d="M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1"></path></svg>`; 46451 var COPIED_ICON = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12l5 5l10 -10"></path></svg>`; 46452 function queryCodeBlocks(root) { 46453 if (root === document) { 46454 return document.querySelectorAll(CODE_BLOCK_SELECTOR); 46455 } 46456 return root.querySelectorAll("pre[data-language]"); 46457 } 46458 function isReadableCodeBlock(pre) { 46459 return pre?.isConnected && !pre.closest("lexxy-editor") && !pre.closest(`.${WRAPPER_CLASS}`); 46460 } 46461 function createCopyButton(codeText) { 46462 const button = document.createElement("button"); 46463 button.type = "button"; 46464 button.className = "lexxy-code-block__copy"; 46465 button.setAttribute("aria-label", "Copy code"); 46466 button.dataset.controller = "clipboard"; 46467 button.dataset.clipboardText = codeText; 46468 button.dataset.clipboardShowTooltipValue = "false"; 46469 button.dataset.clipboardTooltipDurationValue = "1500"; 46470 const copyContent = document.createElement("span"); 46471 copyContent.dataset.clipboardTarget = "copyContent"; 46472 copyContent.innerHTML = COPY_ICON; 46473 const copiedContent = document.createElement("span"); 46474 copiedContent.dataset.clipboardTarget = "copiedContent"; 46475 copiedContent.className = "hidden"; 46476 copiedContent.innerHTML = COPIED_ICON; 46477 button.append(copyContent, copiedContent); 46478 return button; 46479 } 46480 function wrapCodeBlock(pre) { 46481 const wrapper = document.createElement("div"); 46482 wrapper.className = WRAPPER_CLASS; 46483 const parent = pre.parentNode; 46484 parent.insertBefore(wrapper, pre); 46485 wrapper.append(pre, createCopyButton(pre.textContent || "")); 46486 } 46487 function enhanceCodeBlockCopyButtons(root = document) { 46488 [...queryCodeBlocks(root)].filter(isReadableCodeBlock).forEach(wrapCodeBlock); 46489 } 46490 function scheduleCodeBlockCopyButtons(root = document) { 46491 requestAnimationFrame(() => { 46492 enhanceCodeBlockCopyButtons(root); 46493 }); 46494 } 46495 46496
46496// app/javascript/src/lexxy/hex_color_node.js 46497 var { $applyNodeReplacement: $applyNodeReplacement3, TextNode: TextNode3 } = Lexical_exports; 46498 var HEX_COLOR_CLASS = "lexxy-hex-color"; 46499 var HEX_COLOR_SWATCH_VAR = "--lexxy-hex-swatch"; 46500 var HEX_COLOR_PATTERN = /#(?:[0-9a-fA-F]{6}(?![0-9a-fA-F])|[0-9a-fA-F]{3}(?=[^0-9a-fA-F]))/; 46501 function getHexColorMatch(text2) { 46502 const match = HEX_COLOR_PATTERN.exec(text2); 46503 if (!match) return null; 46504 return { 46505 start: match.index, 46506 end: match.index + match[0].length 46507 }; 46508 } 46509 function isHexColorValue(text2) { 46510 return typeof text2 === "string" && /^#(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/.test(text2); 46511 } 46512 function colorFromStyle(style) { 46513 if (!style) return null; 46514 const swatchMatch = /(?:^|;)\s*--lexxy-hex-swatch\s*:\s*([^;]+)/i.exec(style); 46515 const backgroundMatch = /(?:^|;)\s*background-color\s*:\s*([^;]+)/i.exec(style); 46516 const colorMatch = /(?:^|;)\s*color\s*:\s*([^;]+)/i.exec(style); 46517 const value = (swatchMatch?.[1] || backgroundMatch?.[1] || colorMatch?.[1])?.trim(); 46518 return isHexColorValue(value) ? value : null; 46519 } 46520 function applyHexColorSwatch(element, color) { 46521 if (!(element instanceof HTMLElement) || !isHexColorValue(color)) return; 46522 element.classList.add(HEX_COLOR_CLASS); 46523 element.style.setProperty(HEX_COLOR_SWATCH_VAR, color); 46524 element.style.removeProperty("background-color"); 46525 element.style.removeProperty("color"); 46526 } 46527 var HexColorNode = class _HexColorNode extends TextNode3 { 46528 static getType() { 46529 return "lexxy-hex-color"; 46530 } 46531 static clone(node) { 46532 return new _HexColorNode(node.__text, node.__key); 46533 } 46534 createDOM(config, editor) { 46535 const element = super.createDOM(config, editor); 46536 applyHexColorSwatch(element, this.getTextContent()); 46537 return element; 46538 } 46539 updateDOM(prevNode, dom, config) { 46540 const updated = super.updateDOM(prevNode, dom, config); 46541 applyHexColorSwatch(dom, this.getTextContent()); 46542 return updated; 46543 } 46544 static importDOM() { 46545 return { 46546 span: (domNode) => { 46547 if (!domNode.classList.contains(HEX_COLOR_CLASS)) return null; 46548 const text2 = domNode.textContent?.trim() || ""; 46549 const color = isHexColorValue(text2) ? text2 : colorFromStyle(domNode.getAttribute("style")); 46550 if (!color) return null; 46551 return { 46552 conversion: () => ({ 46553 node: $createHexColorNode(color), 46554 forChild: () => null 46555 }), 46556 priority: 2 46557 }; 46558 } 46559 }; 46560 } 46561 exportDOM(editor) { 46562 const element = document.createElement("span"); 46563 element.textContent = this.getTextContent(); 46564 applyHexColorSwatch(element, this.getTextContent()); 46565 return { element }; 46566 } 46567 static importJSON(serializedNode) { 46568 return $createHexColorNode(serializedNode.text).updateFromJSON(serializedNode); 46569 } 46570 exportJSON() { 46571 return { 46572 ...super.exportJSON(), 46573 type: "lexxy-hex-color", 46574 version: 1 46575 }; 46576 } 46577 isTextEntity() { 46578 return true; 46579 } 46580 canInsertTextBefore() { 46581 return false; 46582 } 46583 canInsertTextAfter() { 46584 return false; 46585 } 46586 }; 46587 function $createHexColorNode(text2) { 46588 return $applyNodeReplacement3(new HexColorNode(text2)); 46589 } 46590 function $isHexColorNode(node) { 46591 return node instanceof HexColorNode; 46592 } 46593 46594
46594// app/javascript/src/lexxy/hex_color_content.js 46595 var HEX_COLOR_SELECTOR = `:where(.trix-content, .lexxy-content) .${HEX_COLOR_CLASS}`; 46596 var COPIED_CLASS = "lexxy-hex-color--copied"; 46597 var COPIED_ICON_CLASS = "lexxy-hex-color__copied-icon"; 46598 var COPIED_ICON2 = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true"><g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"><path d="M6.25,2.75h-1c-1.105,0-2,.895-2,2V14.25c0,1.105,.895,2,2,2h7.5c1.105,0,2-.895,2-2V4.75c0-1.105-.895-2-2-2h-1"></path><rect x="6.25" y="1.25" width="5.5" height="3" rx="1" ry="1"></rect><polyline points="6.25 10.25 8 12.25 11.75 7.25"></polyline></g></svg>`; 46599 var COPIED_RESET_MS = 1e3; 46600 var hydrationFrame = null; 46601 var dynamicContentObserver = null; 46602 var clickListenerAttached = false; 46603 var copiedResetTimers = /* @__PURE__ */ new WeakMap(); 46604 function queryHexColors(root) { 46605 if (root === document) { 46606 return document.querySelectorAll(HEX_COLOR_SELECTOR); 46607 } 46608 const matches = []; 46609 if (root instanceof Element && root.classList?.contains(HEX_COLOR_CLASS)) { 46610 matches.push(root); 46611 } 46612 if (root?.querySelectorAll) { 46613 matches.push(...root.querySelectorAll(`.${HEX_COLOR_CLASS}`)); 46614 } 46615 return matches; 46616 } 46617 function colorFromElement(element) { 46618 const text2 = element.textContent?.trim().replace(/\s+/g, "") || ""; 46619 const hexMatch = text2.match(/#(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})\b/); 46620 if (hexMatch && isHexColorValue(hexMatch[0])) return hexMatch[0]; 46621 const swatch = element.style.getPropertyValue("--lexxy-hex-swatch")?.trim(); 46622 if (isHexColorValue(swatch)) return swatch; 46623 const background = element.style.backgroundColor?.trim(); 46624 return isHexColorValue(background) ? background : null; 46625 } 46626 function isReadableHexColor(element) { 46627 return element?.isConnected && !element.closest("lexxy-editor"); 46628 } 46629 function ensureCopiedIcon(element) { 46630 let icon = element.querySelector(`:scope > .${COPIED_ICON_CLASS}`); 46631 if (icon) return icon; 46632 icon = document.createElement("span"); 46633 icon.className = COPIED_ICON_CLASS; 46634 icon.setAttribute("aria-hidden", "true"); 46635 icon.innerHTML = COPIED_ICON2; 46636 element.insertBefore(icon, element.firstChild); 46637 return icon; 46638 } 46639 function clearCopiedState(element) { 46640 const timer = copiedResetTimers.get(element); 46641 if (timer) { 46642 clearTimeout(timer); 46643 copiedResetTimers.delete(element); 46644 } 46645 element.classList.remove(COPIED_CLASS); 46646 element.querySelector(`:scope > .${COPIED_ICON_CLASS}`)?.remove(); 46647 } 46648 function showCopiedState(element) { 46649 clearCopiedState(element); 46650 ensureCopiedIcon(element); 46651 element.classList.add(COPIED_CLASS); 46652 const timer = setTimeout(() => { 46653 clearCopiedState(element); 46654 }, COPIED_RESET_MS); 46655 copiedResetTimers.set(element, timer); 46656 } 46657 function copyTextToClipboard(text2) { 46658 if (navigator.clipboard?.writeText) { 46659 return navigator.clipboard.writeText(text2).catch(() => copyTextWithTextarea(text2)); 46660 } 46661 return copyTextWithTextarea(text2); 46662 } 46663 function copyTextWithTextarea(text2) { 46664 return new Promise((resolve, reject) => { 46665 const textArea = document.createElement("textarea"); 46666 textArea.value = text2; 46667 textArea.setAttribute("readonly", ""); 46668 textArea.style.position = "fixed"; 46669 textArea.style.top = "0"; 46670 textArea.style.left = "0"; 46671 textArea.style.opacity = "0"; 46672 document.body.appendChild(textArea); 46673 textArea.focus(); 46674 textArea.select(); 46675 try { 46676 const successful = document.execCommand("copy"); 46677 document.body.removeChild(textArea); 46678 if (successful) resolve(); 46679 else reject(new Error("Copy command failed")); 46680 } catch (error) { 46681 document.body.removeChild(textArea); 46682 reject(error); 46683 } 46684 }); 46685 } 46686 function enhanceHexColor(element) { 46687 if (!isReadableHexColor(element)) return; 46688 const color = colorFromElement(element); 46689 if (!color) return; 46690 applyHexColorSwatch(element, color); 46691 element.dataset.lexxyHex = color; 46692 element.setAttribute("role", "button"); 46693 element.setAttribute("tabindex", "0"); 46694 element.setAttribute("aria-label", `Copy ${color}`); 46695 element.title = `Copy ${color}`; 46696 } 46697 async function handleHexColorActivation(element) { 46698 if (!isReadableHexColor(element)) return; 46699 const color = element.dataset.lexxyHex || colorFromElement(element); 46700 if (!color) return; 46701 try { 46702 await copyTextToClipboard(color); 46703 showCopiedState(element); 46704 } catch (_error) { 46705 } 46706 } 46707 function handleHexColorClick(event) { 46708 const element = event.target.closest?.(`.${HEX_COLOR_CLASS}`); 46709 if (!element || !isReadableHexColor(element)) return; 46710 event.preventDefault(); 46711 handleHexColorActivation(element); 46712 } 46713 function handleHexColorKeydown(event) { 46714 if (event.key !== "Enter" && event.key !== " ") return; 46715 const element = event.target.closest?.(`.${HEX_COLOR_CLASS}`); 46716 if (!element || event.target !== element || !isReadableHexColor(element)) return; 46717 event.preventDefault(); 46718 handleHexColorActivation(element); 46719 } 46720 function attachHexColorListeners() { 46721 if (clickListenerAttached || typeof document === "undefined") return; 46722 document.addEventListener("click", handleHexColorClick); 46723 document.addEventListener("keydown", handleHexColorKeydown); 46724 clickListenerAttached = true; 46725 } 46726 function hydrateHexColors(root = document) { 46727 queryHexColors(root).forEach(enhanceHexColor); 46728 } 46729 function scheduleHexColorHydration(root = document) { 46730 if (hydrationFrame) cancelAnimationFrame(hydrationFrame); 46731 hydrationFrame = requestAnimationFrame(() => { 46732 hydrationFrame = null; 46733 hydrateHexColors(root); 46734 }); 46735 } 46736 function nodeContainsHexColor(node) { 46737 if (!(node instanceof Element) && !(node instanceof DocumentFragment)) return false;
46738 return node instanceof Element && node.classList?.contains(HEX_COLOR_CLASS) || Boolean(node.querySelector?.(`.${HEX_COLOR_CLASS}`)); 46739 } 46740 function observeDynamicHexColors() { 46741 if (dynamicContentObserver || !document.documentElement) return; 46742 dynamicContentObserver = new MutationObserver((mutations) => { 46743 const needsHydration2 = mutations.some( 46744 (mutation) => Array.from(mutation.addedNodes).some(nodeContainsHexColor) 46745 ); 46746 if (needsHydration2) scheduleHexColorHydration(); 46747 }); 46748 dynamicContentObserver.observe(document.documentElement, { 46749 childList: true, 46750 subtree: true 46751 }); 46752 } 46753 attachHexColorListeners(); 46754 observeDynamicHexColors(); 46755 46756
46756// app/javascript/src/twitter_embeds.js 46757 var TWITTER_WIDGETS_SRC = "https://platform.twitter.com/widgets.js"; 46758 var twitterWidgetsPromise; 46759 function twitterBlockquotes(root = document) { 46760 const selectors = [ 46761 ".trix-content blockquote.twitter-tweet", 46762 ".lexxy-content blockquote.twitter-tweet", 46763 "lexxy-editor blockquote.twitter-tweet", 46764 "action-text-attachment blockquote.twitter-tweet" 46765 ]; 46766 if (root === document) { 46767 return document.querySelectorAll(selectors.join(", ")); 46768 } 46769 return root.querySelectorAll("blockquote.twitter-tweet"); 46770 } 46771 function loadTwitterWidgetsScript() { 46772 if (window.twttr?.widgets) return Promise.resolve(window.twttr); 46773 if (twitterWidgetsPromise) return twitterWidgetsPromise; 46774 twitterWidgetsPromise = new Promise((resolve, reject) => { 46775 const existing = document.getElementById("twitter-wjs"); 46776 if (existing) { 46777 if (window.twttr?.widgets) { 46778 resolve(window.twttr); 46779 return; 46780 } 46781 existing.addEventListener("load", () => resolve(window.twttr), { once: true }); 46782 return; 46783 } 46784 window.twttr = window.twttr || { _e: [], ready(callback) { 46785 window.twttr._e.push(callback); 46786 } }; 46787 const script = document.createElement("script"); 46788 script.id = "twitter-wjs"; 46789 script.async = true; 46790 script.src = TWITTER_WIDGETS_SRC; 46791 script.charset = "utf-8"; 46792 script.onload = () => resolve(window.twttr); 46793 script.onerror = () => { 46794 twitterWidgetsPromise = null; 46795 reject(new Error("Failed to load Twitter widgets")); 46796 }; 46797 document.body.appendChild(script); 46798 }); 46799 return twitterWidgetsPromise; 46800 } 46801 function renderTwitterEmbeds(root = document) { 46802 const blockquotes = twitterBlockquotes(root); 46803 if (blockquotes.length === 0) return; 46804 loadTwitterWidgetsScript().then((twttr) => { 46805 if (!twttr?.widgets) return; 46806 blockquotes.forEach((blockquote) => { 46807 if (blockquote.closest(".twitter-tweet-rendered")) return; 46808 twttr.widgets.load(blockquote); 46809 }); 46810 }).catch(() => { 46811 }); 46812 } 46813 function scheduleTwitterEmbeds(root = document) { 46814 requestAnimationFrame(() => { 46815 requestAnimationFrame(() => renderTwitterEmbeds(root)); 46816 }); 46817 } 46818 46819
46819// app/javascript/src/instagram_embeds.js 46820 var INSTAGRAM_EMBED_SRC = "https://www.instagram.com/embed.js"; 46821 var instagramEmbedPromise; 46822 function instagramBlockquotes(root = document) { 46823 const selectors = [ 46824 ".trix-content blockquote.instagram-media", 46825 ".lexxy-content blockquote.instagram-media", 46826 "lexxy-editor blockquote.instagram-media", 46827 "action-text-attachment blockquote.instagram-media" 46828 ]; 46829 if (root === document) { 46830 return document.querySelectorAll(selectors.join(", ")); 46831 } 46832 return root.querySelectorAll("blockquote.instagram-media"); 46833 } 46834 function instagramIframes(root = document) { 46835 const selectors = [ 46836 ".trix-content .embed--instagram iframe.instagram-media", 46837 ".trix-content .embed--instagram iframe.instagram-media-rendered", 46838 ".lexxy-content .embed--instagram iframe.instagram-media", 46839 ".lexxy-content .embed--instagram iframe.instagram-media-rendered", 46840 "lexxy-editor .embed--instagram iframe.instagram-media", 46841 "lexxy-editor .embed--instagram iframe.instagram-media-rendered", 46842 "action-text-attachment .embed--instagram iframe.instagram-media", 46843 "action-text-attachment .embed--instagram iframe.instagram-media-rendered" 46844 ]; 46845 if (root === document) { 46846 return document.querySelectorAll(selectors.join(", ")); 46847 } 46848 return root.querySelectorAll( 46849 ".embed--instagram iframe.instagram-media, .embed--instagram iframe.instagram-media-rendered" 46850 ); 46851 } 46852 function loadInstagramEmbedScript() { 46853 if (window.instgrm?.Embeds) return Promise.resolve(window.instgrm); 46854 if (instagramEmbedPromise) return instagramEmbedPromise; 46855 instagramEmbedPromise = new Promise((resolve, reject) => { 46856 const existing = document.getElementById("instagram-embed-js"); 46857 if (existing) { 46858 if (window.instgrm?.Embeds) { 46859 resolve(window.instgrm); 46860 return; 46861 } 46862 existing.addEventListener("load", () => resolve(window.instgrm), { once: true }); 46863 return; 46864 } 46865 const script = document.createElement("script"); 46866 script.id = "instagram-embed-js"; 46867 script.async = true; 46868 script.src = INSTAGRAM_EMBED_SRC; 46869 script.onload = () => resolve(window.instgrm); 46870 script.onerror = () => { 46871 instagramEmbedPromise = null; 46872 reject(new Error("Failed to load Instagram embed script")); 46873 }; 46874 document.body.appendChild(script); 46875 }); 46876 return instagramEmbedPromise; 46877 } 46878 function syncInstagramIframeHeight(iframe) { 46879 const height = Number.parseInt(iframe.getAttribute("height"), 10); 46880 if (!Number.isFinite(height) || height <= 0) return; 46881 iframe.style.height = `${height}px`; 46882 } 46883 function watchInstagramIframeHeight(iframe) { 46884 if (iframe.dataset.instagramHeightWatched === "true") { 46885 syncInstagramIframeHeight(iframe); 46886 return; 46887 } 46888 iframe.dataset.instagramHeightWatched = "true"; 46889 syncInstagramIframeHeight(iframe); 46890 new MutationObserver(() => syncInstagramIframeHeight(iframe)).observe(iframe, { 46891 attributes: true, 46892 attributeFilter: ["height"] 46893 }); 46894 } 46895 function syncInstagramIframeHeights(root = document) { 46896 instagramIframes(root).forEach(watchInstagramIframeHeight); 46897 } 46898 function renderInstagramEmbeds(root = document) { 46899 const blockquotes = instagramBlockquotes(root); 46900 const afterProcess = () => { 46901 requestAnimationFrame(() => { 46902 syncInstagramIframeHeights(root); 46903 }); 46904 }; 46905 if (blockquotes.length > 0) { 46906 loadInstagramEmbedScript().then((instgrm) => { 46907 if (!instgrm?.Embeds) return; 46908 instgrm.Embeds.process(root === document ? void 0 : root); 46909 afterProcess(); 46910 }).catch(() => { 46911 }); 46912 return; 46913 } 46914 syncInstagramIframeHeights(root); 46915 } 46916 function scheduleInstagramEmbeds(root = document) { 46917 requestAnimationFrame(() => { 46918 requestAnimationFrame(() => renderInstagramEmbeds(root)); 46919 }); 46920 } 46921 46922
46922// app/javascript/src/tiktok_embeds.js 46923 var TIKTOK_EMBED_SRC = "https://www.tiktok.com/embed.js"; 46924 var tiktokEmbedPromise; 46925 function tiktokBlockquotes(root = document) { 46926 const selectors = [ 46927 ".trix-content blockquote.tiktok-embed", 46928 ".lexxy-content blockquote.tiktok-embed", 46929 "lexxy-editor blockquote.tiktok-embed", 46930 "action-text-attachment blockquote.tiktok-embed" 46931 ]; 46932 if (root === document) { 46933 return document.querySelectorAll(selectors.join(", ")); 46934 } 46935 return root.querySelectorAll("blockquote.tiktok-embed"); 46936 } 46937 function loadTikTokEmbedScript() { 46938 if (window.tiktokEmbed?.lib) return Promise.resolve(window.tiktokEmbed); 46939 if (tiktokEmbedPromise) return tiktokEmbedPromise; 46940 tiktokEmbedPromise = new Promise((resolve, reject) => { 46941 const existing = document.getElementById("tiktok-embed-js"); 46942 if (existing) { 46943 if (window.tiktokEmbed?.lib) { 46944 resolve(window.tiktokEmbed); 46945 return; 46946 } 46947 existing.addEventListener("load", () => resolve(window.tiktokEmbed), { once: true }); 46948 return; 46949 } 46950 const script = document.createElement("script"); 46951 script.id = "tiktok-embed-js"; 46952 script.async = true; 46953 script.src = TIKTOK_EMBED_SRC; 46954 script.onload = () => resolve(window.tiktokEmbed); 46955 script.onerror = () => { 46956 tiktokEmbedPromise = null; 46957 reject(new Error("Failed to load TikTok embed script")); 46958 }; 46959 document.body.appendChild(script); 46960 }); 46961 return tiktokEmbedPromise; 46962 } 46963 function syncTikTokIframeHeight(iframe) { 46964 const inlineHeight = iframe.style.height?.replace("px", ""); 46965 const attributeHeight = iframe.getAttribute("height"); 46966 const height = Number.parseInt(inlineHeight || attributeHeight, 10); 46967 if (Number.isFinite(height) && height > 0) { 46968 iframe.style.height = `${height}px`; 46969 } 46970 } 46971 function renderTikTokBlockquote(blockquote, tiktokEmbed) { 46972 if (blockquote.querySelector("iframe")) { 46973 syncTikTokIframeHeight(blockquote.querySelector("iframe")); 46974 return; 46975 } 46976 if (tiktokEmbed?.lib?.render) { 46977 tiktokEmbed.lib.render(blockquote); 46978 requestAnimationFrame(() => { 46979 const iframe = blockquote.querySelector("iframe"); 46980 if (iframe) syncTikTokIframeHeight(iframe); 46981 }); 46982 } 46983 } 46984 function renderTikTokEmbeds(root = document) { 46985 const blockquotes = tiktokBlockquotes(root); 46986 if (blockquotes.length === 0) return; 46987 loadTikTokEmbedScript().then((tiktokEmbed) => { 46988 blockquotes.forEach((blockquote) => renderTikTokBlockquote(blockquote, tiktokEmbed)); 46989 }).catch(() => { 46990 }); 46991 } 46992 function scheduleTikTokEmbeds(root = document) { 46993 requestAnimationFrame(() => { 46994 requestAnimationFrame(() => renderTikTokEmbeds(root)); 46995 }); 46996 } 46997 46998
46998// app/javascript/src/facebook_embeds.js 46999 var FACEBOOK_SDK_SRC = "https://connect.facebook.net/en_US/sdk.js"; 47000 var facebookSdkPromise; 47001 function facebookEmbeds(root = document) { 47002 const selectors = [ 47003 ".trix-content .fb-video", 47004 ".trix-content .fb-post", 47005 ".lexxy-content .fb-video", 47006 ".lexxy-content .fb-post", 47007 "lexxy-editor .fb-video", 47008 "lexxy-editor .fb-post", 47009 "action-text-attachment .fb-video", 47010 "action-text-attachment .fb-post" 47011 ]; 47012 if (root === document) { 47013 return document.querySelectorAll(selectors.join(", ")); 47014 } 47015 return root.querySelectorAll(".fb-video, .fb-post"); 47016 } 47017 function ensureFbRoot() { 47018 if (document.getElementById("fb-root")) return; 47019 const root = document.createElement("div"); 47020 root.id = "fb-root"; 47021 document.body.appendChild(root); 47022 } 47023 function loadFacebookSdk() { 47024 if (window.FB?.XFBML) return Promise.resolve(window.FB); 47025 if (facebookSdkPromise) return facebookSdkPromise; 47026 facebookSdkPromise = new Promise((resolve, reject) => { 47027 const existing = document.getElementById("facebook-jssdk"); 47028 if (existing) { 47029 if (window.FB?.XFBML) { 47030 resolve(window.FB); 47031 return; 47032 } 47033 existing.addEventListener("load", () => resolve(window.FB), { once: true }); 47034 return; 47035 } 47036 window.fbAsyncInit = () => { 47037 window.FB.init({ xfbml: true, version: "v25.0" }); 47038 resolve(window.FB); 47039 }; 47040 const script = document.createElement("script"); 47041 script.id = "facebook-jssdk"; 47042 script.async = true; 47043 script.defer = true; 47044 script.crossOrigin = "anonymous"; 47045 script.src = `${FACEBOOK_SDK_SRC}#xfbml=1&version=v25.0`; 47046 script.onerror = () => { 47047 facebookSdkPromise = null; 47048 reject(new Error("Failed to load Facebook SDK")); 47049 }; 47050 document.body.appendChild(script); 47051 }); 47052 return facebookSdkPromise; 47053 } 47054 function renderFacebookEmbeds(root = document) { 47055 const embeds = facebookEmbeds(root); 47056 if (embeds.length === 0) return; 47057 ensureFbRoot(); 47058 loadFacebookSdk().then((FB) => { 47059 if (!FB?.XFBML) return; 47060 FB.XFBML.parse(root === document ? void 0 : root); 47061 }).catch(() => { 47062 }); 47063 } 47064 function scheduleFacebookEmbeds(root = document) { 47065 requestAnimationFrame(() => { 47066 requestAnimationFrame(() => renderFacebookEmbeds(root)); 47067 }); 47068 } 47069 47070
47070// app/javascript/src/airtable_embeds.js 47071 var AIRTABLE_EMBED_HEIGHT = "533px"; 47072 function airtableContainers(root = document) { 47073 const selectors = [ 47074 ".trix-content [data-airtable-embed-url]", 47075 ".lexxy-content [data-airtable-embed-url]", 47076 "lexxy-editor [data-airtable-embed-url]", 47077 "action-text-attachment [data-airtable-embed-url]" 47078 ]; 47079 if (root === document) { 47080 return document.querySelectorAll(selectors.join(", ")); 47081 } 47082 return root.querySelectorAll("[data-airtable-embed-url]"); 47083 } 47084 function hydrateAirtableEmbed(container) { 47085 if (container.querySelector("iframe")) return; 47086 const url = container.dataset.airtableEmbedUrl?.trim(); 47087 if (!url) return; 47088 container.style.left = "0"; 47089 container.style.width = "100%"; 47090 container.style.height = AIRTABLE_EMBED_HEIGHT; 47091 container.style.position = "relative"; 47092 const iframe = document.createElement("iframe"); 47093 iframe.src = url; 47094 iframe.style.top = "0"; 47095 iframe.style.left = "0"; 47096 iframe.style.width = "100%"; 47097 iframe.style.height = "100%"; 47098 iframe.style.position = "absolute"; 47099 iframe.style.border = "0"; 47100 iframe.setAttribute("allowfullscreen", ""); 47101 container.appendChild(iframe); 47102 } 47103 function renderAirtableEmbeds(root = document) { 47104 airtableContainers(root).forEach(hydrateAirtableEmbed); 47105 } 47106 function scheduleAirtableEmbeds(root = document) { 47107 requestAnimationFrame(() => { 47108 requestAnimationFrame(() => renderAirtableEmbeds(root)); 47109 }); 47110 } 47111 47112
47112// app/javascript/src/responsive_embeds.js 47113 function responsiveEmbedContainers(root = document) { 47114 const selectors = [ 47115 ".trix-content [data-responsive-embed-url]", 47116 ".lexxy-content [data-responsive-embed-url]", 47117 "lexxy-editor [data-responsive-embed-url]", 47118 "action-text-attachment [data-responsive-embed-url]" 47119 ]; 47120 if (root === document) { 47121 return document.querySelectorAll(selectors.join(", ")); 47122 } 47123 return root.querySelectorAll("[data-responsive-embed-url]"); 47124 } 47125 function hydrateResponsiveEmbed(container) { 47126 if (container.querySelector("iframe")) return; 47127 const url = container.dataset.responsiveEmbedUrl?.trim(); 47128 if (!url) return; 47129 container.style.left = "0"; 47130 container.style.width = "100%"; 47131 container.style.position = "relative"; 47132 const height = parseInt(container.dataset.responsiveEmbedHeight, 10); 47133 if (height > 0) { 47134 container.style.height = `${height}px`; 47135 container.style.paddingBottom = "0"; 47136 } else { 47137 container.style.height = "0"; 47138 container.style.paddingBottom = "56.25%"; 47139 } 47140 const iframe = document.createElement("iframe"); 47141 iframe.src = url; 47142 iframe.style.top = "0"; 47143 iframe.style.left = "0"; 47144 iframe.style.width = "100%"; 47145 iframe.style.height = "100%"; 47146 iframe.style.position = "absolute"; 47147 iframe.style.border = "0"; 47148 iframe.setAttribute("scrolling", "no"); 47149 const allow = container.dataset.responsiveEmbedAllow?.trim(); 47150 if (allow) { 47151 iframe.setAttribute("allow", allow); 47152 } else { 47153 iframe.setAttribute("allowfullscreen", ""); 47154 } 47155 container.appendChild(iframe); 47156 } 47157 function renderResponsiveEmbeds(root = document) { 47158 responsiveEmbedContainers(root).forEach(hydrateResponsiveEmbed); 47159 } 47160 function scheduleResponsiveEmbeds(root = document) { 47161 requestAnimationFrame(() => { 47162 requestAnimationFrame(() => renderResponsiveEmbeds(root)); 47163 }); 47164 } 47165 47166
47166// app/javascript/src/embed_provider_icons.data.json 47167 var embed_provider_icons_data_default = { 47168 icons: { 47169 youtube: { 47170 label: "YouTube", 47171 viewBox: "0 0 32 32", 47172 markup: '<path fill="red" d="M31.33 8.498a4.007 4.007 0 0 0-2.828-2.829C26.007 5 16 5 16 5S5.993 5 3.498 5.67A4.007 4.007 0 0 0 .67 8.497C0 10.993 0 16.201 0 16.201s0 5.207.67 7.702a4.007 4.007 0 0 0 2.828 2.829C5.993 27.4 16 27.4 16 27.4s10.007 0 12.502-.67a4.007 4.007 0 0 0 2.829-2.828C32 21.408 32 16.2 32 16.2s-.003-5.208-.67-7.703Z"/><path fill="#fff" d="m12.797 21 8.313-4.799-8.313-4.8v9.6Z"/>' 47173 }, 47174 vimeo: { 47175 label: "Vimeo", 47176 viewBox: "0 0 32 32", 47177 markup: '<path fill="#1AB7EA" d="M28.8 0H3.2A3.2 3.2 0 0 0 0 3.2v25.6A3.2 3.2 0 0 0 3.2 32h25.6a3.2 3.2 0 0 0 3.2-3.2V3.2A3.2 3.2 0 0 0 28.8 0Z"/><path fill="#fff" d="M26.925 10.627c-.104 2.25-1.674 5.333-4.717 9.245C19.064 23.957 16.403 26 14.229 26c-1.349 0-2.488-1.243-3.421-3.733-.621-2.28-1.243-4.563-1.867-6.843-.693-2.488-1.434-3.733-2.229-3.733-.173 0-.779.365-1.816 1.088l-1.088-1.4A295.481 295.481 0 0 0 7.181 8.37c1.523-1.315 2.667-2.006 3.427-2.078 1.8-.173 2.907 1.056 3.323 3.691.45 2.84.76 4.608.936 5.299.52 2.357 1.09 3.533 1.714 3.533.483 0 1.211-.765 2.182-2.293.968-1.528 1.485-2.691 1.557-3.491.139-1.32-.381-1.981-1.557-1.981-.555 0-1.126.128-1.712.378 1.136-3.722 3.309-5.53 6.512-5.426 2.376.069 3.496 1.61 3.36 4.621l.002.003Z"/>' 47178 }, 47179 spotify: { 47180 label: "Spotify",
47181 viewBox: "0 0 32 32", 47182 markup: '<path fill="#1ED760" d="M16 0C7.164 0 0 7.164 0 16c0 8.837 7.164 16 16 16 8.838 0 16-7.163 16-16 0-8.836-7.162-16-16-16Zm7.338 23.077a.997.997 0 0 1-1.372.33c-3.757-2.294-8.486-2.814-14.055-1.542a.998.998 0 0 1-.444-1.945c6.095-1.392 11.323-.793 15.54 1.785.47.288.62.902.33 1.372Zm1.958-4.357a1.248 1.248 0 0 1-1.715.411c-4.301-2.643-10.857-3.409-15.944-1.865a1.25 1.25 0 0 1-1.557-.83 1.25 1.25 0 0 1 .832-1.557c5.81-1.763 13.035-.909 17.974 2.126.586.361.771 1.13.41 1.715Zm.169-4.536c-5.157-3.063-13.665-3.345-18.589-1.85a1.496 1.496 0 1 1-.869-2.865c5.652-1.716 15.048-1.384 20.985 2.14a1.496 1.496 0 1 1-1.527 2.574Z"/>' 47183 }, 47184 soundcloud: { 47185 label: "SoundCloud", 47186 viewBox: "0 0 32 32", 47187 markup: '<path fill="#F50" fill-rule="evenodd" d="M31.997 18.07a4.48 4.48 0 0 1-4.535 4.23H16.558a.915.915 0 0 1-.905-.909V9.651a1 1 0 0 1 .603-.956S17.258 8 19.37 8a7.145 7.145 0 0 1 3.666 1.007 7.254 7.254 0 0 1 3.413 4.728 4.212 4.212 0 0 1 1.157-.158 4.365 4.365 0 0 1 4.391 4.494Zm-17.705-7.676c.33 3.982.568 7.613 0 11.582a.354.354 0 0 1-.704 0c-.529-3.935-.298-7.635 0-11.582a.353.353 0 0 1 .54-.339.354.354 0 0 1 .164.339ZM12.086 21.98a.37.37 0 0 1-.734 0 44.265 44.265 0 0 1 0-10.22.372.372 0 0 1 .739 0 39.77 39.77 0 0 1-.005 10.22Zm-2.21-10.566c.358 3.649.52 6.917-.004 10.557a.355.355 0 0 1-.709 0c-.508-3.593-.337-6.955 0-10.557a.357.357 0 0 1 .356-.319c.183 0 .337.137.356.32ZM7.66 21.984a.364.364 0 0 1-.721 0 37.382 37.382 0 0 1 0-9.542.366.366 0 1 1 .734 0 34.87 34.87 0 0 1-.013 9.543Zm-2.21-7.156c.558 2.475.306 4.66-.022 7.182a.346.346 0 0 1-.683 0c-.299-2.488-.546-4.724-.021-7.183a.363.363 0 0 1 .725.001Zm-2.207-.376c.512 2.535.346 4.682-.013 7.225-.042.376-.686.38-.72 0-.325-2.505-.479-4.716-.014-7.225a.376.376 0 0 1 .747 0Zm-2.227 1.23c.537 1.68.354 3.047-.022 4.77a.35.35 0 0 1-.696 0c-.324-1.69-.455-3.085-.029-4.77a.375.375 0 0 1 .747 0Z" clip-rule="evenodd"/>' 47188 }, 47189 x: { 47190 label: "\u{1D54F} (Twitter)",
47191 viewBox: "0 0 32 32", 47192 themeAdaptive: true, 47193 markup: '<path fill="currentColor" d="M25.2 2h4.91L19.39 14.25 32 30.92h-9.87L14.4 20.81 5.55 30.92H.63L12.1 17.81 0 2h10.13l6.99 9.24L25.2 2Zm-1.72 25.99h2.72L8.65 4.78H5.73l17.75 23.21Z"/>' 47194 }, 47195 instagram: { 47196 label: "Instagram", 47197 viewBox: "0 0 32 32", 47198 markup: '<path fill="url(#instagram-a-{id})" d="M16.008.242C9.428.242 7.504.25 7.13.28c-1.35.112-2.19.325-3.106.78a6.292 6.292 0 0 0-1.81 1.326C1.213 3.424.606 4.702.387 6.22.28 6.957.25 7.107.244 10.87c-.003 1.255 0 2.906 0 5.121 0 6.575.007 8.497.038 8.87.11 1.315.316 2.141.752 3.046a6.64 6.64 0 0 0 4.303 3.515c.65.167 1.367.26 2.288.303.39.017 4.369.029 8.35.029 3.98 0 7.96-.005 8.341-.024 1.067-.05 1.686-.134 2.371-.31a6.599 6.599 0 0 0 4.303-3.523c.428-.883.645-1.74.743-2.986.022-.271.03-4.6.03-8.924 0-4.323-.01-8.644-.03-8.916-.1-1.265-.317-2.116-.759-3.016a6.247 6.247 0 0 0-1.349-1.848C28.583 1.212 27.308.606 25.788.387c-.736-.107-.883-.138-4.65-.145h-5.13Z"/><path fill="url(#instagram-b-{id})" d="M16.008.242C9.428.242 7.504.25 7.13.28c-1.35.112-2.19.325-3.106.78a6.292 6.292 0 0 0-1.81 1.326C1.213 3.424.606 4.702.387 6.22.28 6.957.25 7.107.244 10.87c-.003 1.255 0 2.906 0 5.121 0 6.575.007 8.497.038 8.87.11 1.315.316 2.141.752 3.046a6.64 6.64 0 0 0 4.303 3.515c.65.167 1.367.26 2.288.303.39.017 4.369.029 8.35.029 3.98 0 7.96-.005 8.341-.024 1.067-.05 1.686-.134 2.371-.31a6.599 6.599 0 0 0 4.303-3.523c.428-.883.645-1.74.743-2.986.022-.271.03-4.6.03-8.924 0-4.323-.01-8.644-.03-8.916-.1-1.265-.317-2.116-.759-3.016a6.247 6.247 0 0 0-1.349-1.848C28.583 1.212 27.308.606 25.788.387c-.736-.107-.883-.138-4.65-.145h-5.13Z"/><path fill="#fff" d="M16.001 4.364c-3.16 0-3.557.013-4.798.07-1.239.057-2.084.253-2.824.54a5.698 5.698 0 0 0-2.062 1.342 5.712 5.712 0 0 0-1.343 2.061c-.288.74-.485 1.586-.54 2.825-.056 1.24-.07 1.638-.07 4.798s.014 3.556.07 4.797c.057 1.239.253 2.084.54 2.824a5.702 5.702 0 0 0 1.343 2.061 5.697 5.697 0 0 0 2.06 1.344c.74.287 1.586.483 2.825.54 1.241.057 1.637.07 4.797.07 3.161 0 3.556-.013 4.798-.07 1.238-.057 2.085-.253 2.825-.54a5.693 5.693 0 0 0 2.06-1.344 5.712 5.712 0 0 0 1.343-2.06c.286-.74.483-1.587.54-2.825.057-1.241.071-1.637.071-4.797 0-3.16-.014-3.557-.07-4.798-.058-1.239-.255-2.084-.54-2.824a5.71 5.71 0 0 0-1.344-2.062 5.688 5.688 0 0 0-2.06-1.341c-.742-.288-1.588-.484-2.827-.541-1.241-.057-1.637-.07-4.798-.07h.004ZM14.957 6.46h1.044c3.107 0 3.475.01 4.702.067 1.135.051 1.75.241 2.16.4.544.211.93.463 1.338.87.407.408.66.796.87 1.339.16.41.35 1.025.401 2.16.056 1.226.068 1.595.068 4.7 0 3.106-.012 3.474-.068 4.701-.052 1.134-.241 1.75-.4 2.16-.211.543-.464.93-.871 1.337-.407.407-.794.66-1.338.87-.41.16-1.025.35-2.16.401-1.227.056-1.595.068-4.702.068s-3.475-.012-4.702-.068c-1.135-.052-1.75-.242-2.16-.401a3.604 3.604 0 0 1-1.339-.87 3.606 3.606 0 0 1-.87-1.338c-.16-.41-.35-1.026-.402-2.16-.055-1.227-.066-1.595-.066-4.703 0-3.107.01-3.473.066-4.7.052-1.135.242-1.75.401-2.16.211-.544.464-.932.871-1.339.407-.407.795-.66 1.338-.87.41-.16 1.026-.35 2.16-.402 1.074-.048 1.49-.063 3.66-.065v.003Zm7.255 1.932a1.396 1.396 0 1 0 0 2.793 1.396 1.396 0 0 0 0-2.794Zm-6.211 1.631a5.976 5.976 0 1 0 0 11.952 5.976 5.976 0 0 0 0-11.952Zm0 2.097a3.879 3.879 0 1 1 0 7.758 3.879 3.879 0 0 1 0-7.758Z"/><defs><radialGradient id="instagram-a-{id}" cx="0" cy="0" r="1" gradientTransform="matrix(0 -31.2312 29.0554 0 8.615 34.182)" gradientUnits="userSpaceOnUse"><stop stop-color="#FD5"/><stop offset=".1" stop-color="#FD5"/><stop offset=".5" stop-color="#FF543E"/><stop offset="1" stop-color="#C837AB"/></radialGradient><radialGradient id="instagram-b-{id}" cx="0" cy="0" r="1" gradientTransform="rotate(78.678 -4.051 -1.817) scale(13.9606 57.5608)" gradientUnits="userSpaceOnUse"><stop stop-color="#3771C8"/><stop offset=".128" stop-color="#3771C8"/><stop offset="1" stop-color="#60F" stop-opacity="0"/></radialGradient></defs>' 47199 }, 47200 gumlet: { 47201 label: "Gumlet",
47202 viewBox: "0 0 32 32", 47203 markup: '<path fill="#104A70" d="m12.21 21.434-5.468 7.691c2.43 1.668 5.206 2.732 8.352 2.875v-9.535c-1.095-.121-1.998-.47-2.883-1.031Z"/><path fill="#ED7324" d="M15.094 9.468 15.031 0c-3.108.15-5.87 1.154-8.289 2.82l5.457 7.645a6.613 6.613 0 0 1 2.895-.997Z"/><path fill="#FBBC05" d="M24.553 2.647C22.104.972 19.227.094 16.06 0L16 9.456c1.088.078 2.119.365 2.998.909l5.555-7.718Z"/><path fill="#0F1E2A" d="M9.726 18.415.806 21.362c1.042 2.909 2.821 5.358 5.207 7.217l5.56-7.63a6.648 6.648 0 0 1-1.845-2.534Z"/><path fill="#DF5216" d="m11.572 10.91-5.49-7.59c-1.603 1.256-2.91 2.783-3.944 4.553a15.686 15.686 0 0 0-1.232 2.701l8.867 2.91c.402-.992 1.002-1.89 1.8-2.574Z"/><path fill="#D53C0D" d="M9.34 15.972a6.59 6.59 0 0 1 .166-1.631L.64 11.47A15.759 15.759 0 0 0 0 15.9c0 1.565.178 2.998.593 4.428L9.56 17.5a6.913 6.913 0 0 1-.22-1.528Z"/><path fill="#378A9B" d="m19.824 21.061 5.559 7.618c2.381-1.863 4.273-4.341 5.309-7.253l-8.937-2.91a6.768 6.768 0 0 1-1.931 2.545Z"/><path fill="#1D77B2" d="M16 22.493V32c3.155-.098 6.113-1.03 8.553-2.695l-5.58-7.67c-.886.535-1.889.791-2.973.858Z"/><path fill="#539E82" d="m30.924 11.371-10.698 3.293c.12.52.168.776.166 1.235-.001.459-.057.702-.166 1.224l10.736 3.305c.42-1.431.636-2.965.636-4.529 0-1.571-.235-3.066-.674-4.528Z"/>' 47204 }, 47205 tiktok: { 47206 label: "TikTok",
47207 viewBox: "0 0 32 32", 47208 themeAdaptive: true, 47209 markup: '<path fill="#FF004F" d="M22.987 11.551a12.568 12.568 0 0 0 7.331 2.345V8.638a7.426 7.426 0 0 1-1.54-.16v4.138a12.57 12.57 0 0 1-7.33-2.345v10.73c0 5.368-4.354 9.719-9.724 9.719a9.68 9.68 0 0 1-5.413-1.644A9.697 9.697 0 0 0 13.263 32c5.37 0 9.725-4.351 9.725-9.719v-10.73Zm1.9-5.304a7.328 7.328 0 0 1-1.9-4.29V1.28h-1.459a7.36 7.36 0 0 0 3.359 4.967Zm-15.18 18.71a4.447 4.447 0 0 1 4.89-6.929v-5.375c-.51-.07-1.024-.1-1.539-.089v4.184a4.447 4.447 0 0 0-3.351 8.209Z"/><path fill="currentColor" d="M21.448 10.271a12.57 12.57 0 0 0 7.33 2.345V8.477a7.36 7.36 0 0 1-3.891-2.23 7.361 7.361 0 0 1-3.359-4.967h-3.832v21a4.447 4.447 0 0 1-7.989 2.677 4.445 4.445 0 0 1 2.001-8.417c.471 0 .925.074 1.35.209v-4.184c-5.276.109-9.519 4.417-9.519 9.716a9.683 9.683 0 0 0 2.772 6.795 9.682 9.682 0 0 0 5.413 1.644c5.37 0 9.724-4.351 9.724-9.719v-10.73Z"/><path fill="#00F2EA" d="M28.779 8.477V7.358a7.333 7.333 0 0 1-3.892-1.111 7.353 7.353 0 0 0 3.892 2.23Zm-7.25-7.197a7.483 7.483 0 0 1-.081-.604V0h-5.292v21.001a4.447 4.447 0 0 1-6.449 3.956 4.447 4.447 0 0 0 7.989-2.676V1.28h3.832Zm-8.47 11.285v-1.192a9.824 9.824 0 0 0-1.335-.09C6.354 11.283 2 15.633 2 21a9.708 9.708 0 0 0 4.311 8.075 9.683 9.683 0 0 1-2.771-6.795c0-5.299 4.242-9.607 9.518-9.716Z"/>' 47210 }, 47211 facebook: { 47212 label: "Facebook",
47213 viewBox: "0 0 32 32", 47214 markup: '<path fill="#0766FF" d="M17.939 31.884C25.86 30.925 32 24.18 32 16c0-8.836-7.164-16-16-16S0 7.164 0 16c0 7.504 5.165 13.8 12.135 15.53l.31-1.308h4.888l.606 1.662Z"/><path fill="#fff" d="M12.134 31.53V20.89H8.832V16h3.302v-2.107c0-5.446 2.464-7.968 7.808-7.968 1.012 0 2.758.199 3.476.397v4.43c-.378-.04-1.038-.059-1.85-.059-2.624 0-3.636.992-3.636 3.578V16h5.23l-.896 4.889H17.94v10.995c-1.94.234-3.907.114-5.805-.354Z"/>' 47215 }, 47216 loom: { 47217 label: "Loom", 47218 viewBox: "0 0 32 32", 47219 markup: '<path fill="#625DF5" d="M32 14.325h-9.748l8.442-4.874-1.674-2.902-8.443 4.875 4.873-8.443-2.9-1.674-4.875 8.44V0h-3.35v9.748L9.45 1.307 6.549 2.98l4.873 8.44-8.44-4.872-1.676 2.902 8.442 4.874H0v3.35h9.747l-8.44 4.875 1.673 2.902 8.443-4.875L6.55 29.02l2.9 1.674 4.876-8.441V32h3.35v-9.956l4.964 8.597 2.72-1.57-4.965-8.6 8.623 4.98 1.676-2.902-8.441-4.874h9.747l.001-3.35Zm-16 6.23a4.554 4.554 0 0 1-3.221-7.777 4.552 4.552 0 0 1 7.775 3.22A4.557 4.557 0 0 1 16 20.555Z"/>' 47220 }, 47221 airtable: { 47222 label: "Airtable",
47223 viewBox: "0 0 32 32", 47224 markup: '<path fill="#FCB400" d="M14.29 3.338 2.358 8.275c-.664.274-.657 1.217.01 1.481l11.981 4.751a4.445 4.445 0 0 0 3.277 0l11.98-4.75a.8.8 0 0 0 .012-1.482l-11.93-4.937a4.446 4.446 0 0 0-3.4 0"/><path fill="#18BFFF" d="M17.052 17.101V28.97a.8.8 0 0 0 1.094.743l13.35-5.182a.799.799 0 0 0 .504-.743V11.92a.8.8 0 0 0-1.094-.743l-13.35 5.181a.8.8 0 0 0-.504.743Z"/><path fill="#F82B60" d="m13.934 17.714-3.962 1.913-.402.194-8.363 4.007c-.53.256-1.207-.13-1.207-.72V11.97c0-.213.11-.396.256-.535a.909.909 0 0 1 .202-.152c.2-.12.485-.152.727-.056l12.683 5.025c.644.256.695 1.16.066 1.463Z"/><path fill="#000" fill-opacity=".25" d="m13.934 17.714-3.962 1.913-9.716-8.193c.06-.06.128-.11.202-.152.2-.12.485-.152.727-.056l12.683 5.025c.644.256.695 1.16.066 1.463Z"/>' 47225 }, 47226 wistia: { 47227 label: "Wistia", 47228 viewBox: "0 0 32 32", 47229 markup: '<path fill="#1E64F0" d="M19.275 28.147c-4.328 1.196-14.082.62-15.644.62H0l5.968-6.72c1.616-1.827 2.446-2.204 4.251-2.204 1.805 0 5.979.177 8.248-.044 4.207-.41 7.485-1.461 9.057-2.458 3.698-2.336 4.44-3.809 4.44-3.809s1.372 10.75-12.689 14.615ZM31.587 9.259C32.262 5.129 29.937 4 29.937 4s.1 3.355-6.078 4.074C18.379 8.705 0 8.23 0 8.23l5.912 6.776c1.606 1.838 2.447 2.048 4.252 2.181 1.793.122 5.768.078 8.458-.122 2.945-.221 7.13-1.184 9.965-3.377 1.45-1.129 2.723-2.69 3-4.406V9.26Z"/>' 47230 }, 47231 genially: { 47232 label: "Genially",
47233 viewBox: "0 0 32 33", 47234 markup: '<path fill="url(#genially-a-{id})" d="M30.017 8.234C27.164 3.131 21.841.003 16.024.003v16.023l13.993-7.792Z"/><path fill="url(#genially-b-{id})" d="M29.743 24.258a16.079 16.079 0 0 0 .11-16.243l-13.829 8.011 13.719 8.232Z"/><path fill="url(#genially-c-{id})" d="M15.75 32.05a16.007 16.007 0 0 0 14.157-8.012l-13.883-8.012-.274 16.024Z"/><path fill="url(#genially-d-{id})" d="M2.031 23.764c2.799 5.103 8.176 8.23 13.993 8.286V16.026L2.031 23.764Z"/><path fill="url(#genially-e-{id})" d="M2.305 7.795a15.951 15.951 0 0 0-.164 16.243l13.883-8.012-13.719-8.23Z"/><path fill="url(#genially-f-{id})" d="M16.299.003A16.006 16.006 0 0 0 2.14 8.015l13.883 8.011.274-16.023Z"/><path fill="#000F33" d="M16.024 28.702c7.001 0 12.676-5.675 12.676-12.676 0-7-5.675-12.676-12.676-12.676-7 0-12.676 5.675-12.676 12.676s5.675 12.676 12.676 12.676Z"/><path fill="#fff" d="M24.09 15.807c-.767 0-1.371.548-1.536 1.262-.713 3.457-4.06 5.707-7.518 4.994-3.457-.714-5.707-4.061-4.993-7.518.713-3.457 4.06-5.707 7.518-4.994.274.055.548.11.823.22.658.274 1.481 0 1.81-.659l.056-.11c.439-.713.164-1.646-.55-2.085-.109-.055-.164-.11-.274-.11C14.488 5.051 9 7.63 7.244 12.624c-1.756 4.939.823 10.426 5.817 12.182 4.939 1.756 10.426-.823 12.182-5.817.165-.439.274-.878.384-1.371.165-.823-.439-1.647-1.262-1.811-.055.055-.164 0-.274 0Z"/><path fill="#fff" d="M18.603 14.874c-1.152 0-2.03.933-2.03 2.03 0 1.153.933 2.03 2.03 2.03 1.153 0 2.03-.932 2.03-2.03.056-1.097-.877-2.03-2.03-2.03Z"/><defs><linearGradient id="genially-a-{id}" x1="15.45" x2="24.164" y1="6.452" y2="11.479" gradientUnits="userSpaceOnUse"><stop stop-color="#F3B444"/><stop offset="1" stop-color="#F15480"/></linearGradient><linearGradient id="genially-b-{id}" x1="24.026" x2="24.026" y1="21.053" y2="11.428" gradientUnits="userSpaceOnUse"><stop stop-color="#B157CE"/><stop offset="1" stop-color="#F15480"/></linearGradient><linearGradient id="genially-c-{id}" x1="15.658" x2="24.246" y1="25.479" y2="20.518" gradientUnits="userSpaceOnUse"><stop stop-color="#5DA5FB"/><stop offset="1" stop-color="#B157CE"/></linearGradient><linearGradient id="genially-d-{id}" x1="7.646" x2="16.03" y1="20.437" y2="25.282" gradientUnits="userSpaceOnUse"><stop stop-color="#74E6A7"/><stop offset="1" stop-color="#5DA5FB"/></linearGradient><linearGradient id="genially-e-{id}" x1="8.003" x2="8.003" y1="11.055" y2="20.685" gradientUnits="userSpaceOnUse"><stop stop-color="#C8ED5C"/><stop offset="1" stop-color="#74E6A7"/></linearGradient><linearGradient id="genially-f-{id}" x1="8.099" x2="16.144" y1="11.343" y2="6.695" gradientUnits="userSpaceOnUse"><stop stop-color="#C8ED5C"/><stop offset="1" stop-color="#F3B444"/></linearGradient></defs>' 47235 }, 47236 excalidraw: { 47237 label: "Excalidraw",
47238 viewBox: "0 0 32 32", 47239 markup: '<path fill="#6965DB" d="M31.924 26.365a.262.262 0 0 0-.224-.045c-1.68-2.473-3.83-4.814-5.892-7.087l-.336-.378a.17.17 0 0 0-.045-.112.469.469 0 0 0-.134-.089l-.067-.067-.045-.044c-.067-.134-.225-.223-.381-.134-.628.313-1.21.78-1.77 1.226-.738.579-1.478 1.159-2.173 1.805a6.747 6.747 0 0 0-.784.825c-.112.155-.022.29.113.356-.494.49-.987.981-1.479 1.493a.253.253 0 0 0-.067.179c0 .066.045.133.089.155l.874.669v.022c1.232 1.226 3.405 2.898 5.713 4.703.335.268.694.535 1.03.802.156.179.313.38.448.558.067.088.224.111.313.044.045.045.113.089.158.134a.32.32 0 0 0 .134.045.205.205 0 0 0 .18-.09.317.317 0 0 0 .043-.133c.024 0 .023.022.045.022a.255.255 0 0 0 .18-.067l4.077-4.436a.248.248 0 0 0 0-.356Zm-11.738-1.538a.39.39 0 0 0 .089.112c.47.402.963.803 1.479 1.248l-2.062-1.56-.201-.134c-.045-.022-.09-.067-.135-.089l-.156-.134.045-.045.044-.044.09-.089c.694-.69 1.882-1.85 2.487-2.43-.65.647-1.95 2.542-1.681 3.165Zm7.034 5.528-1.703-1.293a35.927 35.927 0 0 0-2.106-2.006c.919.69 1.703 1.293 1.815 1.404.896.78.85.647 1.456 1.16l.74.534a.854.854 0 0 1-.202.201Zm.447.334-.045-.023c.068-.044.135-.089.203-.155l-.158.178ZM.785 4.59c.044.29.112.58.156.847.269 1.47.538 2.808 1.03 3.811l.203.758c.067.29.178.646.29.735a89.02 89.02 0 0 0 4.772 3.923.236.236 0 0 0 .291 0s0 .022.023.022a.205.205 0 0 0 .157.067.256.256 0 0 0 .18-.067c2.396-2.652 4.188-4.836 5.465-6.664.09-.089.113-.223.113-.334.089-.09.156-.2.246-.267.089-.09.089-.246 0-.313l-.023-.022c0-.044-.022-.112-.067-.134-.56-.534-.963-.913-1.389-1.314-.74-.692-1.5-1.404-3.114-3.009l-.022-.022c-.023-.023-.045-.045-.09-.045-.448-.156-1.366-.312-2.509-.513C4.795 1.76 2.487 1.36.404.735c0 0-.135 0-.158.022L.18.825C.157.846.135.869 0 .913c.022.134.022.223.067.38 0 .044.09.4.09.445L.785 4.59Zm12.432 2.63-.268-.268c.067.09.157.156.268.268Zm-2.845 3.744-.044.044c0-.022.022-.044.045-.044ZM8.738 2.94c.135.134.695.67.83.781-.583-.268-2.039-.936-2.712-1.16.672.135 1.591.269 1.882.38ZM1.053 1.828c.337.579.605 2.585.874 4.546-.157-.625-.269-1.248-.403-1.828-.202-1.025-.404-1.938-.673-2.74.045 0 .113 0 .202.022ZM.92 1.359c-.09 0-.18-.022-.247-.022 0-.022 0-.044-.022-.044.112 0 .179.022.269.066Zm-.874.178c0-.021 0-.021 0 0Zm31.52-.49c.023-.088-.448-.49-.291-.513.337-.021.337-.534 0-.534-.448.022-.918.133-1.344.2-.784.156-1.59.313-2.375.49-1.77.38-3.517.78-5.264 1.25-.538.155-1.143.266-1.658.534-.18.089-.157.267-.067.378-.045.023-.067.023-.112.045-.157.023-.292.045-.448.067-.135.022-.202.134-.18.268 0 .021.023.066.023.088a138.343 138.343 0 0 1-3.137 3.968c-1.12 1.292-2.307 2.652-3.495 4.056-3.786 4.413-8.064 9.427-12.791 13.84a.215.215 0 0 0 0 .312c.023.022.045.044.067.044-.067.068-.134.113-.202.178-.045.046-.067.09-.067.134a.485.485 0 0 0-.09.112c-.09.09-.09.245.023.312.09.088.247.088.313-.022.023-.023.023-.045.045-.045a.353.353 0 0 1 .494 0c.268.29.537.58.783.825l-.56-.468c-.09-.09-.246-.067-.313.022-.09.088-.068.245.022.312L6.9 31.87c.045.045.09.045.157.045a.201.201 0 0 0 .157-.067l.134-.134c.023.022.067.022.09.022a.203.203 0 0 0 .157-.067c8.065-8.067 14.562-14.152 22-19.59.066-.044.089-.133.089-.2.09 0 .157-.067.201-.156 1.367-4.168 1.636-7.868 1.725-9.695v-.022c0-.023.023-.045.023-.067.022-.045.022-.067.022-.067.06-.277.029-.567-.09-.825ZM17.138 7.6c.358-.402.717-.825 1.076-1.204-2.308 3.031-6.138 7.689-11.56 13.239 3.696-4.079 7.415-8.29 10.485-12.035ZM6.856 31.246c-.022-.023-.022-.023 0-.023v.023Zm3.338-2.875c.18-.2.36-.379.56-.58 0 0 0 .022.023.022-.202.18-.381.357-.582.558h-.001Zm.92-.891c.112-.113.223-.268.357-.402l.022-.022c1.323-1.36 2.69-2.72 4.078-4.1l.022-.023c.337-.267.74-.557 1.098-.825a304.242 304.242 0 0 0-5.578 5.372Zm8.69-22.31c-.738.959-1.567 2.229-2.262 3.232C15.346 11.566 8.29 19.3 8.132 19.434a1590.966 1590.966 0 0 1-6.452 6.129l-.134.134c-.112-.134-.112-.335.023-.446 9.968-9.339 16.017-17.116 18.46-20.526-.068.156-.113.289-.225.445Zm3.876 4.57c-.895-.514-1.32-1.316-1.075-2.095l.067-.268c.023-.067.068-.156.113-.223a2.533 2.533 0 0 1 1.008-.936c.022 0 .044 0 .067-.022-.023-.045-.023-.112-.023-.179.023-.134.113-.223.27-.223.268 0 1.097.246 1.411.513.09.067.18.156.269.245.112.134.291.357.38.535.045.022.09.245.157.357.045.178.09.379.068.557-.023.022 0 .155-.023.155a2.14 2.14 0 0 1-.29.825c-.023.023-.023.045-.046.068l-.022.021a1.628 1.628 0 0 1-.425.446c-.516.357-1.099.468-1.681.312 0 0-.157-.067-.225-.089Zm6.542-.67a31.38 31.38 0 0 1-.716 2.541c0 .023-.023.067 0 .09-.045 0-.068.022-.113.044-1.77 1.292-3.494 2.652-5.22 4.034 1.48-1.316 2.958-2.652 4.504-3.967.448-.401.761-.914.85-1.493l.225-1.338v-.044c.112-.268.538-.156.47.133Z"/>' 47240 }, 47241 tldraw: { 47242 label: "tldraw",
47243 viewBox: "0 0 24 24", 47244 themeAdaptive: true, 47245 markup: '<path fill="currentColor" d="M21.474 0H2.526C1.131 0 0 1.18 0 2.637v18.726C0 22.819 1.131 24 2.526 24h18.948C22.869 24 24 22.82 24 21.363V2.637C24 1.181 22.869 0 21.474 0zm-11.01 5.388c.397-.405.888-.607 1.474-.607.57 0 1.052.202 1.448.607.397.404.595.896.595 1.476s-.198 1.072-.595 1.476c-.396.405-.879.607-1.448.607-.586 0-1.077-.202-1.474-.607-.396-.404-.594-.896-.594-1.476s.198-1.072.594-1.476zm3.13 11.49a4.887 4.887 0 0 1-2.018 2.136c-.483.281-.879.273-1.19-.026-.292-.281-.206-.615.26-1.002.258-.193.473-.44.646-.738.172-.299.284-.607.336-.923.017-.14-.043-.21-.181-.21-.345-.018-.698-.212-1.06-.581-.362-.37-.543-.826-.543-1.37 0-.58.198-1.073.594-1.477a2.024 2.024 0 0 1 1.5-.633c.552 0 1.034.21 1.448.633.414.404.655.86.724 1.37.138.95-.034 1.89-.517 2.822z"/>' 47246 }, 47247 google_maps: { 47248 label: "Google Maps", 47249 viewBox: "0 0 32 32", 47250 markup: '<path fill="#4285F4" d="M16.166 6.888a4.27 4.27 0 0 1 4.278 4.278c0 1.04-.387 2.006-1.015 2.755 0 0 4.571-3.421 6.647-7.903A11.134 11.134 0 0 0 19.55.532L15.5 3.5l-2.62 4.91c.797-.918 1.957-1.522 3.286-1.522Z"/><path fill="#FBBC04" d="M16.166 15.42a4.27 4.27 0 0 1-4.278-4.278c0-1.04.363-2.006.991-2.731L8.5 12l-2.388 4.46c1.16 2.561 3.093 4.64 5.075 7.226L16.5 19.5l2.929-5.603a4.243 4.243 0 0 1-3.263 1.523Z"/><path fill="#34A853" d="M19.284 26.393c3.722-5.825 8.048-8.46 8.048-15.227 0-1.86-.459-3.601-1.256-5.148L11.187 23.686a44.567 44.567 0 0 1 1.91 2.73C15.369 29.923 14.74 32 16.19 32s.822-2.103 3.094-5.607Z"/><path fill="#EA4335" d="M7.61 3.988A11.154 11.154 0 0 0 5 11.142c0 2.103.41 3.795 1.112 5.317l6.767-8.048L11 5.5 7.61 3.988Z"/><path fill="#1A73E8" d="M19.55.532A11.3 11.3 0 0 0 16.142 0C12.734 0 9.665 1.547 7.61 3.988l5.27 4.423L19.55.53Z"/>' 47251 }, 47252 tella: { 47253 label: "Tella",
47254 viewBox: "0 0 32 32", 47255 markup: '<path fill="#8278FA" d="M29.702 0h-27.5C.985 0 0 .99 0 2.207v27.587C0 31.01.985 32 2.2 32h27.502c1.214 0 2.2-.99 2.2-2.206V2.207A2.2 2.2 0 0 0 29.701 0Z"/><path fill="#fff" d="M25.853 17.104c-.605-.03-7.097-.03-7.702 0a1.143 1.143 0 0 0-1.1 1.102c-.027.608-.027 7.117 0 7.724.03.608.495 1.076 1.1 1.105.607.027 7.097.027 7.702 0a1.143 1.143 0 0 0 1.1-1.105c.027-.607.027-7.117 0-7.724a1.143 1.143 0 0 0-1.1-1.102ZM4.95 17.635c0-.407.5-.663.902-.46l8.698 4.435c.401.204.401.713 0 .916l-8.698 4.437c-.4.203-.902-.051-.902-.46v-8.868ZM9.901 14.896a4.958 4.958 0 0 0 4.95-4.964A4.958 4.958 0 0 0 9.9 4.966 4.959 4.959 0 0 0 4.95 9.932 4.959 4.959 0 0 0 9.9 14.896ZM17.602 4.966c.302-.03 8.498-.03 8.8 0a.592.592 0 0 1 .55.552c.028.303.028 1.075 0 1.378a.592.592 0 0 1-.55.553c-.302.027-3.135.021-3.135.021s0 6.598-.028 6.875a.615.615 0 0 1-.55.552 11.42 11.42 0 0 1-1.374 0 .592.592 0 0 1-.55-.552c-.029-.277-.029-6.875-.029-6.875s-2.804.006-3.134-.021a.592.592 0 0 1-.55-.553c-.028-.46-.028-.92 0-1.38a.592.592 0 0 1 .55-.55Z"/>' 47256 } 47257 }, 47258 providers: [ 47259 { 47260 id: "youtube", 47261 name: "YouTube", 47262 url: "https://www.youtube.com/" 47263 }, 47264 { 47265 id: "vimeo", 47266 name: "Vimeo", 47267 url: "https://vimeo.com/" 47268 }, 47269 { 47270 id: "spotify", 47271 name: "Spotify", 47272 url: "https://open.spotify.com/" 47273 }, 47274 { 47275 id: "soundcloud", 47276 name: "SoundCloud", 47277 url: "https://soundcloud.com/" 47278 }, 47279 { 47280 id: "x", 47281 name: "\u{1D54F} / Twitter", 47282 url: "https://x.com/" 47283 }, 47284 { 47285 id: "instagram", 47286 name: "Instagram", 47287 url: "https://www.instagram.com/" 47288 }, 47289 { 47290 id: "tiktok", 47291 name: "TikTok", 47292 url: "https://www.tiktok.com/" 47293 }, 47294 { 47295 id: "facebook", 47296 name: "Facebook", 47297 url: "https://www.facebook.com/" 47298 }, 47299 { 47300 id: "loom", 47301 name: "Loom", 47302 url: "https://www.loom.com/" 47303 }, 47304 { 47305 id: "airtable", 47306 name: "Airtable", 47307 url: "https://airtable.com/" 47308 }, 47309 { 47310 id: "wistia", 47311 name: "Wistia", 47312 url: "https://wistia.com/" 47313 }, 47314 { 47315 id: "gumlet", 47316 name: "Gumlet", 47317 url: "https://www.gumlet.com/" 47318 }, 47319 { 47320 id: "genially", 47321 name: "Genially", 47322 url: "https://genially.com/" 47323 }, 47324 { 47325 id: "excalidraw", 47326 name: "Excalidraw", 47327 url: "https://excalidraw.com/" 47328 }, 47329 { 47330 id: "tldraw", 47331 name: "tldraw", 47332 url: "https://www.tldraw.com/" 47333 }, 47334 { 47335 id: "google_maps", 47336 name: "Google Maps", 47337 url: "https://www.google.com/maps" 47338 }, 47339 { 47340 id: "tella", 47341 name: "Tella", 47342 url: "https://www.tella.tv/" 47343 } 47344 ], 47345 providerNameToId: { 47346 YouTube: "youtube", 47347 Vimeo: "vimeo", 47348 Spotify: "spotify", 47349 SoundCloud: "soundcloud", 47350 "\u{1D54F} / Twitter": "x", 47351 X: "x", 47352 Twitter: "x", 47353 Instagram: "instagram", 47354 Gumlet: "gumlet", 47355 TikTok: "tiktok", 47356 Facebook: "facebook", 47357 Loom: "loom", 47358 Airtable: "airtable", 47359 "Wistia, Inc.": "wistia", 47360 Wistia: "wistia", 47361 Genially: "genially", 47362 Excalidraw: "excalidraw", 47363 tldraw: "tldraw", 47364 Tldraw: "tldraw", 47365 TLDraw: "tldraw", 47366 "Google Maps": "google_maps", 47367 GoogleMaps: "google_maps", 47368 Google: "google_maps", 47369 Tella: "tella" 47370 } 47371 }; 47372 47373
47373// app/javascript/src/embed_provider_icons.js 47374 var ICONS = embed_provider_icons_data_default.icons; 47375 var EMBED_PROVIDERS = embed_provider_icons_data_default.providers; 47376 var PROVIDER_NAME_TO_ID = embed_provider_icons_data_default.providerNameToId; 47377 var PROVIDER_DISPLAY_NAMES = { 47378 X: "\u{1D54F} / Twitter", 47379 Twitter: "\u{1D54F} / Twitter" 47380 }; 47381 function embedProviderDisplayName(providerName) { 47382 return PROVIDER_DISPLAY_NAMES[providerName] || providerName; 47383 } 47384 function embedProviderIcon(id3, { className = "link_to_embed__provider-icon" } = {}) { 47385 const icon = ICONS[id3]; 47386 if (!icon) return ""; 47387 const viewBox = icon.viewBox || "0 0 24 24"; 47388 const instanceId = `${id3}-${Math.random().toString(36).slice(2, 9)}`; 47389 if (icon.markup) { 47390 const markup = icon.markup.replace(/\{id\}/g, instanceId); 47391 const themeClass = icon.themeAdaptive ? " embed-provider-icon--theme-adaptive" : ""; 47392 return `<svg class="${className} embed-provider-icon--${id3}${themeClass}" viewBox="${viewBox}" aria-hidden="true" fill="none">${markup}</svg>`; 47393 } 47394 const color = icon.color === "currentColor" ? "currentColor" : icon.color; 47395 return `<svg class="${className}" viewBox="${viewBox}" aria-hidden="true" fill="${color}"><path d="${icon.path}"></path></svg>`; 47396 } 47397 function embedProviderIconForName(providerName, options = {}) { 47398 const displayName = embedProviderDisplayName(providerName); 47399 const id3 = PROVIDER_NAME_TO_ID[displayName] || PROVIDER_NAME_TO_ID[providerName]; 47400 return id3 ? embedProviderIcon(id3, options) : ""; 47401 } 47402 function embedProviderPill(provider) { 47403 return `<div><a class="link_to_embed__provider-pill" href="${provider.url}" target="_blank" rel="noopener noreferrer" aria-label="Open ${provider.name} in a new tab">${embedProviderIcon(provider.id)}<span>${provider.name}</span></a></div>`; 47404 } 47405 function decorateEmbedBadges(root = document) { 47406 root.querySelectorAll(".embed__badge[data-provider-name]").forEach((badge) => { 47407 if (badge.querySelector(".embed__badge-icon, .link_to_embed__provider-icon")) return; 47408 const iconMarkup = embedProviderIconForName(badge.dataset.providerName, { 47409 className: "embed__badge-icon" 47410 }); 47411 if (!iconMarkup) return; 47412 badge.insertAdjacentHTML("afterbegin", iconMarkup); 47413 }); 47414 } 47415 47416
47416// app/javascript/src/lexxy/container_content_blocks.js 47417 var { 47418 $createParagraphNode: $createParagraphNode3, 47419 $isDecoratorNode: $isDecoratorNode3, 47420 $isElementNode: $isElementNode3, 47421 $isRootOrShadowRoot: $isRootOrShadowRoot3 47422 } = Lexical_exports; 47423 function $isContainerContentBlock(node) { 47424 return $isElementNode3(node) && !node.isInline() && !$isRootOrShadowRoot3(node); 47425 } 47426 function $isBlockDecoratorNode(node) { 47427 return $isDecoratorNode3(node) && !node.isInline(); 47428 } 47429 function $isValidContainerContentNode(node) { 47430 return $isContainerContentBlock(node) || $isBlockDecoratorNode(node); 47431 } 47432 function $normalizeContainerContent(container) { 47433 const children = [...container.getLatest().getChildren()]; 47434 const needsWrap = children.some((child) => !$isValidContainerContentNode(child)); 47435 const needsParagraph = children.length === 0; 47436 if (!needsWrap && !needsParagraph) return; 47437 let inlineRun = []; 47438 const flushInlineRun = () => { 47439 if (inlineRun.length === 0) return; 47440 const paragraph = $createParagraphNode3(); 47441 inlineRun[0].insertBefore(paragraph); 47442 inlineRun.forEach((node) => paragraph.append(node)); 47443 inlineRun = []; 47444 }; 47445 for (const child of children) { 47446 if ($isValidContainerContentNode(child)) { 47447 flushInlineRun(); 47448 } else { 47449 inlineRun.push(child); 47450 } 47451 } 47452 flushInlineRun(); 47453 if (container.getLatest().getChildrenSize() === 0) { 47454 container.append($createParagraphNode3()); 47455 } 47456 } 47457 47458
47458// app/javascript/src/lexxy/highlight_palette.js 47459 var HIGHLIGHT_VARIANTS = [ 47460 { id: 1, label: "Taupe" }, 47461 { id: 2, label: "Orange" }, 47462 { id: 3, label: "Red" }, 47463 { id: 4, label: "Fuchsia" }, 47464 { id: 5, label: "Purple" }, 47465 { id: 6, label: "Blue" }, 47466 { id: 7, label: "Green" }, 47467 { id: 8, label: "Amber" }, 47468 { id: 9, label: "Gray" } 47469 ]; 47470 var CALLOUT_VARIANT_NONE = 0; 47471 var DEFAULT_CALLOUT_BORDER_VARIANT = 6; 47472 var DEFAULT_CALLOUT_BG_VARIANT = 6; 47473 function parseCalloutVariant(value, fallback) { 47474 if (value === void 0 || value === null || value === "") return fallback; 47475 const parsed = Number(value); 47476 return Number.isNaN(parsed) ? fallback : parsed; 47477 } 47478 47479
47479// app/javascript/src/lexxy/callout_node.js 47480 var { 47481 $applyNodeReplacement: $applyNodeReplacement4, 47482 $createParagraphNode: $createParagraphNode4, 47483 $findMatchingParent: $findMatchingParent4, 47484 $getSelection: $getSelection3, 47485 $isElementNode: $isElementNode4, 47486 $isParagraphNode: $isParagraphNode3, 47487 $isRangeSelection: $isRangeSelection3, 47488 ElementNode: ElementNode3, 47489 INTERNAL_$isBlock: INTERNAL_$isBlock3 47490 } = Lexical_exports; 47491 var CALLOUT_CLASS = "lexxy-callout"; 47492 var CALLOUT_ICON_TRIGGER_SELECTOR = "[data-callout-inline-icon-toggle]"; 47493 var MAX_CALLOUT_NESTING_DEPTH = 4; 47494 var CalloutNode = class _CalloutNode extends ElementNode3 { 47495 __borderVariant = DEFAULT_CALLOUT_BORDER_VARIANT; 47496 __bgVariant = DEFAULT_CALLOUT_BG_VARIANT; 47497 __icon = "\u{1F4A1}"; 47498 __iconType = "emoji"; 47499 __iconSrc = null; 47500 static getType() { 47501 return "lexxy-callout"; 47502 } 47503 static clone(node) { 47504 return new _CalloutNode( 47505 node.__borderVariant, 47506 node.__bgVariant, 47507 node.__icon, 47508 node.__iconType, 47509 node.__iconSrc, 47510 node.__key 47511 ); 47512 } 47513 constructor(borderVariant = DEFAULT_CALLOUT_BORDER_VARIANT, bgVariant = DEFAULT_CALLOUT_BG_VARIANT, icon = "\u{1F4A1}", iconType = "emoji", iconSrc = null, key) { 47514 super(key); 47515 this.__borderVariant = borderVariant; 47516 this.__bgVariant = bgVariant; 47517 this.__icon = icon; 47518 this.__iconType = iconType; 47519 this.__iconSrc = iconSrc; 47520 } 47521 createDOM() { 47522 const element = document.createElement("aside"); 47523 element.className = CALLOUT_CLASS; 47524 this.#syncDom(element); 47525 return element; 47526 } 47527 updateDOM(prevNode, dom) { 47528 if (prevNode.__borderVariant !== this.__borderVariant || prevNode.__bgVariant !== this.__bgVariant || prevNode.__icon !== this.__icon || prevNode.__iconType !== this.__iconType || prevNode.__iconSrc !== this.__iconSrc) { 47529 this.#syncDom(dom); 47530 } 47531 return false; 47532 } 47533 #syncDom(element) { 47534 element.dataset.borderVariant = String(this.__borderVariant); 47535 element.dataset.bgVariant = String(this.__bgVariant); 47536 element.dataset.iconType = this.__iconType; 47537 delete element.dataset.icon; 47538 delete element.dataset.iconId; 47539 delete element.dataset.iconSrc; 47540 element.style.removeProperty("--callout-icon-image"); 47541 element.style.removeProperty("--callout-icon-mask"); 47542 if (this.__iconType === "none") { 47543 this.#syncIconTrigger(element); 47544 return; 47545 } 47546 if (this.__iconType === "symbol") { 47547 element.dataset.iconId = this.__icon; 47548 const svg2 = isSvgMarkup(this.__iconSrc) ? this.__iconSrc : calloutIconById(this.__icon)?.svg; 47549 if (this.__iconSrc) { 47550 element.dataset.iconSrc = this.__iconSrc; 47551 } 47552 if (svg2) { 47553 element.style.setProperty("--callout-icon-mask", iconMaskUrl(svg2)); 47554 } 47555 this.#syncIconTrigger(element); 47556 return; 47557 } 47558 element.dataset.icon = this.__icon; 47559 if (this.__iconSrc) { 47560 element.dataset.iconSrc = this.__iconSrc; 47561 element.style.setProperty("--callout-icon-image", `url("${this.__iconSrc.replace(/"/g, '\\"')}")`); 47562 } 47563 this.#syncIconTrigger(element); 47564 } 47565 #syncIconTrigger(element) { 47566 const existingTrigger = element.querySelector(CALLOUT_ICON_TRIGGER_SELECTOR); 47567 if (this.__iconType === "none") { 47568 existingTrigger?.remove(); 47569 return; 47570 } 47571 const trigger = existingTrigger || (() => { 47572 const button = document.createElement("button"); 47573 button.type = "button"; 47574 button.className = "lexxy-callout__icon-trigger"; 47575 button.dataset.calloutInlineIconToggle = ""; 47576 button.setAttribute("aria-label", "Change callout icon"); 47577 element.insertBefore(button, element.firstChild); 47578 return button; 47579 })(); 47580 trigger.contentEditable = "false"; 47581 trigger.tabIndex = -1; 47582 this.#syncIconTriggerPreview(trigger); 47583 } 47584 #syncIconTriggerPreview(trigger) { 47585 trigger.replaceChildren(); 47586 if (this.__iconType === "emoji") { 47587 const emoji = document.createElement("span"); 47588 emoji.className = "lexxy-callout__icon-emoji"; 47589 emoji.setAttribute("aria-hidden", "true"); 47590 emoji.textContent = this.__icon || "\u{1F4A1}"; 47591 trigger.append(emoji); 47592 return; 47593 } 47594 if (this.__iconType === "image" && this.__iconSrc) { 47595 const image = document.createElement("img"); 47596 image.className = "lexxy-callout__icon-image"; 47597 image.alt = ""; 47598 image.decoding = "async"; 47599 image.loading = "lazy"; 47600 image.src = this.__iconSrc; 47601 trigger.append(image); 47602 return; 47603 } 47604 if (this.__iconType === "symbol") { 47605 const svgMarkup = isSvgMarkup(this.__iconSrc) ? this.__iconSrc : calloutIconById(this.__icon)?.svg; 47606 const svg2 = sanitizedSvgElement(svgMarkup); 47607 if (svg2) trigger.append(svg2); 47608 } 47609 } 47610 static importDOM() { 47611 const convert = (domNode) => { 47612 if (!domNode.classList.contains(CALLOUT_CLASS)) return null;
47613 const legacyVariant = domNode.dataset.variant; 47614 const borderVariant = parseCalloutVariant( 47615 domNode.dataset.borderVariant ?? legacyVariant, 47616 DEFAULT_CALLOUT_BORDER_VARIANT 47617 ); 47618 const bgVariant = parseCalloutVariant(domNode.dataset.bgVariant ?? legacyVariant, DEFAULT_CALLOUT_BG_VARIANT); 47619 const iconType = domNode.dataset.iconType || "emoji"; 47620 const icon = iconType === "symbol" ? domNode.dataset.iconId || "lightbulb" : domNode.dataset.icon || "\u{1F4A1}"; 47621 return { 47622 conversion: () => ({ 47623 node: $createCalloutNode(borderVariant, bgVariant, icon, iconType, domNode.dataset.iconSrc || null) 47624 }), 47625 priority: 2 47626 }; 47627 }; 47628 return { aside: convert, div: convert }; 47629 } 47630 exportDOM(editor) { 47631 const { element } = super.exportDOM(editor); 47632 if (element) { 47633 element.className = CALLOUT_CLASS; 47634 this.#syncDom(element); 47635 element.querySelector(CALLOUT_ICON_TRIGGER_SELECTOR)?.remove(); 47636 } 47637 return { element }; 47638 } 47639 static importJSON(serializedNode) { 47640 return $createCalloutNode( 47641 serializedNode.borderVariant ?? serializedNode.variant, 47642 serializedNode.bgVariant ?? serializedNode.variant, 47643 serializedNode.icon, 47644 serializedNode.iconType, 47645 serializedNode.iconSrc 47646 ); 47647 } 47648 exportJSON() { 47649 return { 47650 ...super.exportJSON(), 47651 type: "lexxy-callout", 47652 borderVariant: this.__borderVariant, 47653 bgVariant: this.__bgVariant, 47654 icon: this.__icon, 47655 iconType: this.__iconType, 47656 iconSrc: this.__iconSrc, 47657 version: 2 47658 }; 47659 } 47660 insertNewAfter(_selection, restoreSelection) { 47661 const paragraph = $createParagraphNode4(); 47662 this.insertAfter(paragraph, restoreSelection); 47663 return paragraph; 47664 } 47665 collapseAtStart() { 47666 const children = [...this.getChildren()]; 47667 const firstChild = children[0]; 47668 if (!firstChild) { 47669 const paragraph = $createParagraphNode4(); 47670 this.replace(paragraph); 47671 paragraph.selectStart(); 47672 return true; 47673 } 47674 children.forEach((child) => this.insertBefore(child)); 47675 this.remove(); 47676 firstChild.selectStart?.(); 47677 return true; 47678 } 47679 isShadowRoot() { 47680 return true; 47681 } 47682 canBeEmpty() { 47683 return false; 47684 } 47685 canIndent() { 47686 return false; 47687 } 47688 canMergeWhenEmpty() { 47689 return true; 47690 } 47691 setBorderVariant(variant) { 47692 const self2 = this.getWritable(); 47693 self2.__borderVariant = variant; 47694 return self2; 47695 } 47696 getBorderVariant() { 47697 return this.getLatest().__borderVariant; 47698 } 47699 setBgVariant(variant) { 47700 const self2 = this.getWritable(); 47701 self2.__bgVariant = variant; 47702 return self2; 47703 } 47704 getBgVariant() { 47705 return this.getLatest().__bgVariant; 47706 } 47707 setIcon(icon) { 47708 const self2 = this.getWritable(); 47709 self2.__icon = icon || "\u{1F4A1}"; 47710 return self2; 47711 } 47712 getIcon() { 47713 return this.getLatest().__icon; 47714 } 47715 setIconType(iconType) { 47716 const self2 = this.getWritable(); 47717 self2.__iconType = iconType || "emoji"; 47718 return self2; 47719 } 47720 getIconType() { 47721 return this.getLatest().__iconType; 47722 } 47723 setIconSrc(iconSrc) { 47724 const self2 = this.getWritable(); 47725 self2.__iconSrc = iconSrc || null; 47726 return self2; 47727 } 47728 getIconSrc() { 47729 return this.getLatest().__iconSrc; 47730 } 47731 }; 47732 function $createCalloutNode(borderVariant = DEFAULT_CALLOUT_BORDER_VARIANT, bgVariant = DEFAULT_CALLOUT_BG_VARIANT, icon = "\u{1F4A1}", iconType = "emoji", iconSrc = null) { 47733 return $applyNodeReplacement4(new CalloutNode(borderVariant, bgVariant, icon, iconType, iconSrc)); 47734 } 47735 function $isCalloutNode(node) { 47736 return node instanceof CalloutNode; 47737 } 47738 function $countCalloutAncestors(node) { 47739 let count = 0; 47740 let ancestor = $findMatchingParent4(node, $isCalloutNode); 47741 while ($isCalloutNode(ancestor)) { 47742 count += 1; 47743 ancestor = $findMatchingParent4(ancestor.getParent(), $isCalloutNode); 47744 } 47745 return count; 47746 }
47747 function $canNestCalloutAt(node) { 47748 return $countCalloutAncestors(node) < MAX_CALLOUT_NESTING_DEPTH; 47749 } 47750 function $getSelectedBlocks(selection) { 47751 const blockMap = /* @__PURE__ */ new Map(); 47752 const anchorAndFocus = selection.getStartEndPoints(); 47753 if (anchorAndFocus) { 47754 const [anchor, focus] = anchorAndFocus; 47755 const anchorBlock = $findMatchingParent4(anchor.getNode(), INTERNAL_$isBlock3); 47756 const focusBlock = $findMatchingParent4(focus.getNode(), INTERNAL_$isBlock3); 47757 if ($isElementNode4(anchorBlock)) blockMap.set(anchorBlock.getKey(), anchorBlock); 47758 if ($isElementNode4(focusBlock)) blockMap.set(focusBlock.getKey(), focusBlock); 47759 } 47760 for (const node of selection.getNodes()) { 47761 if ($isElementNode4(node) && INTERNAL_$isBlock3(node)) { 47762 blockMap.set(node.getKey(), node); 47763 } else if (anchorAndFocus === null) { 47764 const ancestorBlock = $findMatchingParent4(node, INTERNAL_$isBlock3); 47765 if ($isElementNode4(ancestorBlock)) blockMap.set(ancestorBlock.getKey(), ancestorBlock); 47766 } 47767 } 47768 return [...blockMap.values()]; 47769 } 47770 function $normalizeCalloutContent(callout) { 47771 $normalizeContainerContent(callout); 47772 } 47773 function $insertCallout() { 47774 const selection = $getSelection3(); 47775 if (!$isRangeSelection3(selection)) return; 47776 const blocks = $getSelectedBlocks(selection).filter((block) => !$isCalloutNode(block)); 47777 if (blocks.length === 0) return; 47778 if (!$canNestCalloutAt(blocks[0])) return; 47779 const wrapInCallout = blocks.some((block) => !$isParagraphNode3(block)); 47780 if (wrapInCallout) { 47781 const callout = $createCalloutNode(); 47782 blocks[0].insertBefore(callout); 47783 blocks.forEach((block) => callout.append(block)); 47784 return; 47785 } 47786 blocks.forEach((block) => { 47787 const callout = $createCalloutNode(); 47788 block.insertBefore(callout); 47789 callout.append(block); 47790 }); 47791 } 47792 47793
vendor: 3,782 bytes, lines 47793-47921
47793// node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs 47794 var min = Math.min; 47795 var max = Math.max; 47796 var round = Math.round; 47797 var floor = Math.floor; 47798 var createCoords = (v3) => ({ 47799 x: v3, 47800 y: v3 47801 }); 47802 var oppositeSideMap = { 47803 left: "right", 47804 right: "left", 47805 bottom: "top", 47806 top: "bottom" 47807 }; 47808 function clamp(start3, value, end) { 47809 return max(start3, min(value, end)); 47810 } 47811 function evaluate(value, param) { 47812 return typeof value === "function" ? value(param) : value; 47813 } 47814 function getSide(placement) { 47815 return placement.split("-")[0]; 47816 } 47817 function getAlignment(placement) { 47818 return placement.split("-")[1]; 47819 } 47820 function getOppositeAxis(axis) { 47821 return axis === "x" ? "y" : "x"; 47822 } 47823 function getAxisLength(axis) { 47824 return axis === "y" ? "height" : "width"; 47825 } 47826 function getSideAxis(placement) { 47827 const firstChar = placement[0]; 47828 return firstChar === "t" || firstChar === "b" ? "y" : "x"; 47829 } 47830 function getAlignmentAxis(placement) { 47831 return getOppositeAxis(getSideAxis(placement)); 47832 } 47833 function getAlignmentSides(placement, rects, rtl) { 47834 if (rtl === void 0) { 47835 rtl = false; 47836 } 47837 const alignment = getAlignment(placement); 47838 const alignmentAxis = getAlignmentAxis(placement); 47839 const length = getAxisLength(alignmentAxis); 47840 let mainAlignmentSide = alignmentAxis === "x" ? alignment === (rtl ? "end" : "start") ? "right" : "left" : alignment === "start" ? "bottom" : "top"; 47841 if (rects.reference[length] > rects.floating[length]) { 47842 mainAlignmentSide = getOppositePlacement(mainAlignmentSide); 47843 } 47844 return [mainAlignmentSide, getOppositePlacement(mainAlignmentSide)]; 47845 } 47846 function getExpandedPlacements(placement) { 47847 const oppositePlacement = getOppositePlacement(placement); 47848 return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)]; 47849 } 47850 function getOppositeAlignmentPlacement(placement) { 47851 return placement.includes("start") ? placement.replace("start", "end") : placement.replace("end", "start"); 47852 } 47853 var lrPlacement = ["left", "right"]; 47854 var rlPlacement = ["right", "left"]; 47855 var tbPlacement = ["top", "bottom"]; 47856 var btPlacement = ["bottom", "top"]; 47857 function getSideList(side, isStart, rtl) { 47858 switch (side) { 47859 case "top": 47860 case "bottom": 47861 if (rtl) return isStart ? rlPlacement : lrPlacement; 47862 return isStart ? lrPlacement : rlPlacement; 47863 case "left": 47864 case "right": 47865 return isStart ? tbPlacement : btPlacement; 47866 default: 47867 return []; 47868 } 47869 } 47870 function getOppositeAxisPlacements(placement, flipAlignment, direction, rtl) { 47871 const alignment = getAlignment(placement); 47872 let list = getSideList(getSide(placement), direction === "start", rtl); 47873 if (alignment) { 47874 list = list.map((side) => side + "-" + alignment); 47875 if (flipAlignment) { 47876 list = list.concat(list.map(getOppositeAlignmentPlacement)); 47877 } 47878 } 47879 return list; 47880 } 47881 function getOppositePlacement(placement) { 47882 const side = getSide(placement); 47883 return oppositeSideMap[side] + placement.slice(side.length); 47884 } 47885 function expandPaddingObject(padding) { 47886 return { 47887 top: 0, 47888 right: 0, 47889 bottom: 0, 47890 left: 0, 47891 ...padding 47892 }; 47893 } 47894 function getPaddingObject(padding) { 47895 return typeof padding !== "number" ? expandPaddingObject(padding) : { 47896 top: padding, 47897 right: padding, 47898 bottom: padding, 47899 left: padding 47900 }; 47901 } 47902 function rectToClientRect(rect) { 47903 const { 47904 x: x3, 47905 y: y3, 47906 width, 47907 height 47908 } = rect; 47909 return { 47910 width, 47911 height, 47912 top: y3, 47913 left: x3, 47914 right: x3 + width, 47915 bottom: y3 + height, 47916 x: x3, 47917 y: y3 47918 }; 47919 } 47920 47921
vendor: 15,448 bytes, lines 47921-48372
47921// node_modules/@floating-ui/core/dist/floating-ui.core.mjs 47922 function computeCoordsFromPlacement(_ref2, placement, rtl) { 47923 let { 47924 reference, 47925 floating 47926 } = _ref2; 47927 const sideAxis = getSideAxis(placement); 47928 const alignmentAxis = getAlignmentAxis(placement); 47929 const alignLength = getAxisLength(alignmentAxis); 47930 const side = getSide(placement); 47931 const isVertical = sideAxis === "y"; 47932 const commonX = reference.x + reference.width / 2 - floating.width / 2; 47933 const commonY = reference.y + reference.height / 2 - floating.height / 2; 47934 const commonAlign = reference[alignLength] / 2 - floating[alignLength] / 2; 47935 let coords; 47936 switch (side) { 47937 case "top": 47938 coords = { 47939 x: commonX, 47940 y: reference.y - floating.height 47941 }; 47942 break; 47943 case "bottom": 47944 coords = { 47945 x: commonX, 47946 y: reference.y + reference.height 47947 }; 47948 break; 47949 case "right": 47950 coords = { 47951 x: reference.x + reference.width, 47952 y: commonY 47953 }; 47954 break; 47955 case "left": 47956 coords = { 47957 x: reference.x - floating.width, 47958 y: commonY 47959 }; 47960 break; 47961 default: 47962 coords = { 47963 x: reference.x, 47964 y: reference.y 47965 }; 47966 } 47967 switch (getAlignment(placement)) { 47968 case "start": 47969 coords[alignmentAxis] -= commonAlign * (rtl && isVertical ? -1 : 1); 47970 break; 47971 case "end": 47972 coords[alignmentAxis] += commonAlign * (rtl && isVertical ? -1 : 1); 47973 break; 47974 } 47975 return coords; 47976 } 47977 async function detectOverflow(state, options) { 47978 var _await$platform$isEle; 47979 if (options === void 0) { 47980 options = {}; 47981 } 47982 const { 47983 x: x3, 47984 y: y3, 47985 platform: platform2, 47986 rects, 47987 elements, 47988 strategy 47989 } = state; 47990 const { 47991 boundary = "clippingAncestors", 47992 rootBoundary = "viewport", 47993 elementContext = "floating", 47994 altBoundary = false, 47995 padding = 0 47996 } = evaluate(options, state); 47997 const paddingObject = getPaddingObject(padding); 47998 const altContext = elementContext === "floating" ? "reference" : "floating"; 47999 const element = elements[altBoundary ? altContext : elementContext]; 48000 const clippingClientRect = rectToClientRect(await platform2.getClippingRect({ 48001 element: ((_await$platform$isEle = await (platform2.isElement == null ? void 0 : platform2.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || await (platform2.getDocumentElement == null ? void 0 : platform2.getDocumentElement(elements.floating)), 48002 boundary, 48003 rootBoundary, 48004 strategy 48005 })); 48006 const rect = elementContext === "floating" ? { 48007 x: x3, 48008 y: y3, 48009 width: rects.floating.width, 48010 height: rects.floating.height 48011 } : rects.reference; 48012 const offsetParent = await (platform2.getOffsetParent == null ? void 0 : platform2.getOffsetParent(elements.floating)); 48013 const offsetScale = await (platform2.isElement == null ? void 0 : platform2.isElement(offsetParent)) ? await (platform2.getScale == null ? void 0 : platform2.getScale(offsetParent)) || { 48014 x: 1, 48015 y: 1 48016 } : { 48017 x: 1, 48018 y: 1 48019 }; 48020 const elementClientRect = rectToClientRect(platform2.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform2.convertOffsetParentRelativeRectToViewportRelativeRect({ 48021 elements, 48022 rect, 48023 offsetParent, 48024 strategy 48025 }) : rect); 48026 return { 48027 top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y, 48028 bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y, 48029 left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x, 48030 right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x 48031 }; 48032 } 48033 var MAX_RESET_COUNT = 50; 48034 var computePosition = async (reference, floating, config) => { 48035 const { 48036 placement = "bottom", 48037 strategy = "absolute", 48038 middleware = [], 48039 platform: platform2 48040 } = config; 48041 const platformWithDetectOverflow = platform2.detectOverflow ? platform2 : { 48042 ...platform2, 48043 detectOverflow 48044 }; 48045 const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(floating)); 48046 let rects = await platform2.getElementRects({ 48047 reference, 48048 floating, 48049 strategy 48050 }); 48051 let { 48052 x: x3, 48053 y: y3 48054 } = computeCoordsFromPlacement(rects, placement, rtl); 48055 let statefulPlacement = placement; 48056 let resetCount = 0; 48057 const middlewareData = {}; 48058 for (let i2 = 0; i2 < middleware.length; i2++) { 48059 const currentMiddleware = middleware[i2]; 48060 if (!currentMiddleware) { 48061 continue; 48062 } 48063 const { 48064 name, 48065 fn 48066 } = currentMiddleware; 48067 const { 48068 x: nextX, 48069 y: nextY, 48070 data, 48071 reset 48072 } = await fn({ 48073 x: x3, 48074 y: y3, 48075 initialPlacement: placement, 48076 placement: statefulPlacement, 48077 strategy, 48078 middlewareData, 48079 rects, 48080 platform: platformWithDetectOverflow, 48081 elements: { 48082 reference, 48083 floating 48084 } 48085 }); 48086 x3 = nextX != null ? nextX : x3; 48087 y3 = nextY != null ? nextY : y3; 48088 middlewareData[name] = { 48089 ...middlewareData[name], 48090 ...data 48091 }; 48092 if (reset && resetCount < MAX_RESET_COUNT) { 48093 resetCount++; 48094 if (typeof reset === "object") { 48095 if (reset.placement) { 48096 statefulPlacement = reset.placement; 48097 } 48098 if (reset.rects) { 48099 rects = reset.rects === true ? await platform2.getElementRects({ 48100 reference, 48101 floating, 48102 strategy 48103 }) : reset.rects; 48104 } 48105 ({ 48106 x: x3, 48107 y: y3 48108 } = computeCoordsFromPlacement(rects, statefulPlacement, rtl)); 48109 } 48110 i2 = -1; 48111 } 48112 } 48113 return { 48114 x: x3, 48115 y: y3, 48116 placement: statefulPlacement, 48117 strategy, 48118 middlewareData 48119 }; 48120 }; 48121 var flip = function(options) { 48122 if (options === void 0) { 48123 options = {}; 48124 } 48125 return { 48126 name: "flip", 48127 options, 48128 async fn(state) { 48129 var _middlewareData$arrow, _middlewareData$flip; 48130 const { 48131 placement, 48132 middlewareData, 48133 rects, 48134 initialPlacement, 48135 platform: platform2, 48136 elements 48137 } = state; 48138 const { 48139 mainAxis: checkMainAxis = true, 48140 crossAxis: checkCrossAxis = true, 48141 fallbackPlacements: specifiedFallbackPlacements, 48142 fallbackStrategy = "bestFit", 48143 fallbackAxisSideDirection = "none", 48144 flipAlignment = true, 48145 ...detectOverflowOptions 48146 } = evaluate(options, state); 48147 if ((_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) { 48148 return {}; 48149 } 48150 const side = getSide(placement); 48151 const initialSideAxis = getSideAxis(initialPlacement); 48152 const isBasePlacement = getSide(initialPlacement) === initialPlacement; 48153 const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(elements.floating)); 48154 const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement)); 48155 const hasFallbackAxisSideDirection = fallbackAxisSideDirection !== "none"; 48156 if (!specifiedFallbackPlacements && hasFallbackAxisSideDirection) { 48157 fallbackPlacements.push(...getOppositeAxisPlacements(initialPlacement, flipAlignment, fallbackAxisSideDirection, rtl)); 48158 } 48159 const placements2 = [initialPlacement, ...fallbackPlacements]; 48160 const overflow = await platform2.detectOverflow(state, detectOverflowOptions); 48161 const overflows = []; 48162 let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || []; 48163 if (checkMainAxis) { 48164 overflows.push(overflow[side]); 48165 } 48166 if (checkCrossAxis) { 48167 const sides2 = getAlignmentSides(placement, rects, rtl); 48168 overflows.push(overflow[sides2[0]], overflow[sides2[1]]); 48169 } 48170 overflowsData = [...overflowsData, { 48171 placement, 48172 overflows 48173 }]; 48174 if (!overflows.every((side2) => side2 <= 0)) { 48175 var _middlewareData$flip2, _overflowsData$filter; 48176 const nextIndex = (((_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) || 0) + 1; 48177 const nextPlacement = placements2[nextIndex]; 48178 if (nextPlacement) { 48179 const ignoreCrossAxisOverflow = checkCrossAxis === "alignment" ? initialSideAxis !== getSideAxis(nextPlacement) : false; 48180 if (!ignoreCrossAxisOverflow || // We leave the current main axis only if every placement on that axis 48181 // overflows the main axis. 48182 overflowsData.every((d3) => getSideAxis(d3.placement) === initialSideAxis ? d3.overflows[0] > 0 : true)) { 48183 return { 48184 data: { 48185 index: nextIndex, 48186 overflows: overflowsData 48187 }, 48188 reset: { 48189 placement: nextPlacement 48190 } 48191 }; 48192 } 48193 } 48194 let resetPlacement = (_overflowsData$filter = overflowsData.filter((d3) => d3.overflows[0] <= 0).sort((a2, b3) => a2.overflows[1] - b3.overflows[1])[0]) == null ? void 0 : _overflowsData$filter.placement; 48195 if (!resetPlacement) { 48196 switch (fallbackStrategy) { 48197 case "bestFit": { 48198 var _overflowsData$filter2; 48199 const placement2 = (_overflowsData$filter2 = overflowsData.filter((d3) => { 48200 if (hasFallbackAxisSideDirection) { 48201 const currentSideAxis = getSideAxis(d3.placement); 48202 return currentSideAxis === initialSideAxis || // Create a bias to the `y` side axis due to horizontal 48203 // reading directions favoring greater width. 48204 currentSideAxis === "y"; 48205 } 48206 return true; 48207 }).map((d3) => [d3.placement, d3.overflows.filter((overflow2) => overflow2 > 0).reduce((acc, overflow2) => acc + overflow2, 0)]).sort((a2, b3) => a2[1] - b3[1])[0]) == null ? void 0 : _overflowsData$filter2[0]; 48208 if (placement2) { 48209 resetPlacement = placement2; 48210 } 48211 break; 48212 } 48213 case "initialPlacement": 48214 resetPlacement = initialPlacement; 48215 break; 48216 } 48217 } 48218 if (placement !== resetPlacement) { 48219 return { 48220 reset: { 48221 placement: resetPlacement 48222 } 48223 }; 48224 } 48225 } 48226 return {}; 48227 } 48228 }; 48229 }; 48230 var originSides = /* @__PURE__ */ new Set(["left", "top"]); 48231 async function convertValueToCoords(state, options) { 48232 const { 48233 placement, 48234 platform: platform2, 48235 elements 48236 } = state; 48237 const rtl = await (platform2.isRTL == null ? void 0 : platform2.isRTL(elements.floating)); 48238 const side = getSide(placement); 48239 const alignment = getAlignment(placement); 48240 const isVertical = getSideAxis(placement) === "y"; 48241 const mainAxisMulti = originSides.has(side) ? -1 : 1; 48242 const crossAxisMulti = rtl && isVertical ? -1 : 1; 48243 const rawValue = evaluate(options, state); 48244 let { 48245 mainAxis, 48246 crossAxis, 48247 alignmentAxis 48248 } = typeof rawValue === "number" ? { 48249 mainAxis: rawValue, 48250 crossAxis: 0, 48251 alignmentAxis: null 48252 } : { 48253 mainAxis: rawValue.mainAxis || 0, 48254 crossAxis: rawValue.crossAxis || 0, 48255 alignmentAxis: rawValue.alignmentAxis 48256 }; 48257 if (alignment && typeof alignmentAxis === "number") { 48258 crossAxis = alignment === "end" ? alignmentAxis * -1 : alignmentAxis; 48259 } 48260 return isVertical ? { 48261 x: crossAxis * crossAxisMulti, 48262 y: mainAxis * mainAxisMulti 48263 } : { 48264 x: mainAxis * mainAxisMulti, 48265 y: crossAxis * crossAxisMulti 48266 }; 48267 } 48268 var offset = function(options) { 48269 if (options === void 0) { 48270 options = 0; 48271 } 48272 return { 48273 name: "offset", 48274 options, 48275 async fn(state) { 48276 var _middlewareData$offse, _middlewareData$arrow; 48277 const { 48278 x: x3, 48279 y: y3, 48280 placement, 48281 middlewareData 48282 } = state; 48283 const diffCoords = await convertValueToCoords(state, options); 48284 if (placement === ((_middlewareData$offse = middlewareData.offset) == null ? void 0 : _middlewareData$offse.placement) && (_middlewareData$arrow = middlewareData.arrow) != null && _middlewareData$arrow.alignmentOffset) { 48285 return {}; 48286 } 48287 return { 48288 x: x3 + diffCoords.x, 48289 y: y3 + diffCoords.y, 48290 data: { 48291 ...diffCoords, 48292 placement 48293 } 48294 }; 48295 } 48296 }; 48297 }; 48298 var shift = function(options) { 48299 if (options === void 0) { 48300 options = {}; 48301 } 48302 return { 48303 name: "shift", 48304 options, 48305 async fn(state) { 48306 const { 48307 x: x3, 48308 y: y3, 48309 placement, 48310 platform: platform2 48311 } = state; 48312 const { 48313 mainAxis: checkMainAxis = true, 48314 crossAxis: checkCrossAxis = false, 48315 limiter = { 48316 fn: (_ref2) => { 48317 let { 48318 x: x4, 48319 y: y4 48320 } = _ref2; 48321 return { 48322 x: x4, 48323 y: y4 48324 }; 48325 } 48326 }, 48327 ...detectOverflowOptions 48328 } = evaluate(options, state); 48329 const coords = { 48330 x: x3, 48331 y: y3 48332 }; 48333 const overflow = await platform2.detectOverflow(state, detectOverflowOptions); 48334 const crossAxis = getSideAxis(getSide(placement)); 48335 const mainAxis = getOppositeAxis(crossAxis); 48336 let mainAxisCoord = coords[mainAxis]; 48337 let crossAxisCoord = coords[crossAxis]; 48338 if (checkMainAxis) { 48339 const minSide = mainAxis === "y" ? "top" : "left"; 48340 const maxSide = mainAxis === "y" ? "bottom" : "right"; 48341 const min2 = mainAxisCoord + overflow[minSide]; 48342 const max2 = mainAxisCoord - overflow[maxSide]; 48343 mainAxisCoord = clamp(min2, mainAxisCoord, max2); 48344 } 48345 if (checkCrossAxis) { 48346 const minSide = crossAxis === "y" ? "top" : "left"; 48347 const maxSide = crossAxis === "y" ? "bottom" : "right"; 48348 const min2 = crossAxisCoord + overflow[minSide]; 48349 const max2 = crossAxisCoord - overflow[maxSide]; 48350 crossAxisCoord = clamp(min2, crossAxisCoord, max2); 48351 } 48352 const limitedCoords = limiter.fn({ 48353 ...state, 48354 [mainAxis]: mainAxisCoord, 48355 [crossAxis]: crossAxisCoord 48356 }); 48357 return { 48358 ...limitedCoords, 48359 data: { 48360 x: limitedCoords.x - x3, 48361 y: limitedCoords.y - y3, 48362 enabled: { 48363 [mainAxis]: checkMainAxis, 48364 [crossAxis]: checkCrossAxis 48365 } 48366 } 48367 }; 48368 } 48369 }; 48370 }; 48371 48372
vendor: 5,524 bytes, lines 48372-48528
48372// node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.mjs 48373 function hasWindow() { 48374 return typeof window !== "undefined"; 48375 } 48376 function getNodeName(node) { 48377 if (isNode(node)) { 48378 return (node.nodeName || "").toLowerCase(); 48379 } 48380 return "#document"; 48381 } 48382 function getWindow2(node) { 48383 var _node$ownerDocument; 48384 return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window; 48385 } 48386 function getDocumentElement(node) { 48387 var _ref2; 48388 return (_ref2 = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref2.documentElement; 48389 } 48390 function isNode(value) { 48391 if (!hasWindow()) { 48392 return false; 48393 } 48394 return value instanceof Node || value instanceof getWindow2(value).Node; 48395 } 48396 function isElement(value) { 48397 if (!hasWindow()) { 48398 return false; 48399 } 48400 return value instanceof Element || value instanceof getWindow2(value).Element; 48401 } 48402 function isHTMLElement4(value) { 48403 if (!hasWindow()) { 48404 return false; 48405 } 48406 return value instanceof HTMLElement || value instanceof getWindow2(value).HTMLElement; 48407 } 48408 function isShadowRoot(value) { 48409 if (!hasWindow() || typeof ShadowRoot === "undefined") { 48410 return false; 48411 } 48412 return value instanceof ShadowRoot || value instanceof getWindow2(value).ShadowRoot; 48413 } 48414 function isOverflowElement(element) { 48415 const { 48416 overflow, 48417 overflowX, 48418 overflowY, 48419 display 48420 } = getComputedStyle2(element); 48421 return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && display !== "inline" && display !== "contents"; 48422 } 48423 function isTableElement(element) { 48424 return /^(table|td|th)$/.test(getNodeName(element)); 48425 } 48426 function isTopLayer(element) { 48427 try { 48428 if (element.matches(":popover-open")) { 48429 return true; 48430 } 48431 } catch (_e2) { 48432 } 48433 try { 48434 return element.matches(":modal"); 48435 } catch (_e2) { 48436 return false; 48437 } 48438 } 48439 var willChangeRe = /transform|translate|scale|rotate|perspective|filter/; 48440 var containRe = /paint|layout|strict|content/; 48441 var isNotNone = (value) => !!value && value !== "none"; 48442 var isWebKitValue; 48443 function isContainingBlock(elementOrCss) { 48444 const css = isElement(elementOrCss) ? getComputedStyle2(elementOrCss) : elementOrCss; 48445 return isNotNone(css.transform) || isNotNone(css.translate) || isNotNone(css.scale) || isNotNone(css.rotate) || isNotNone(css.perspective) || !isWebKit() && (isNotNone(css.backdropFilter) || isNotNone(css.filter)) || willChangeRe.test(css.willChange || "") || containRe.test(css.contain || ""); 48446 } 48447 function getContainingBlock(element) { 48448 let currentNode = getParentNode(element); 48449 while (isHTMLElement4(currentNode) && !isLastTraversableNode(currentNode)) { 48450 if (isContainingBlock(currentNode)) { 48451 return currentNode; 48452 } else if (isTopLayer(currentNode)) { 48453 return null; 48454 } 48455 currentNode = getParentNode(currentNode); 48456 } 48457 return null; 48458 } 48459 function isWebKit() { 48460 if (isWebKitValue == null) { 48461 isWebKitValue = typeof CSS !== "undefined" && CSS.supports && CSS.supports("-webkit-backdrop-filter", "none"); 48462 } 48463 return isWebKitValue; 48464 } 48465 function isLastTraversableNode(node) { 48466 return /^(html|body|#document)$/.test(getNodeName(node)); 48467 } 48468 function getComputedStyle2(element) { 48469 return getWindow2(element).getComputedStyle(element); 48470 } 48471 function getNodeScroll(element) { 48472 if (isElement(element)) { 48473 return { 48474 scrollLeft: element.scrollLeft, 48475 scrollTop: element.scrollTop 48476 }; 48477 } 48478 return { 48479 scrollLeft: element.scrollX, 48480 scrollTop: element.scrollY 48481 }; 48482 } 48483 function getParentNode(node) { 48484 if (getNodeName(node) === "html") { 48485 return node; 48486 } 48487 const result = ( 48488 // Step into the shadow DOM of the parent of a slotted node. 48489 node.assignedSlot || // DOM Element detected. 48490 node.parentNode || // ShadowRoot detected. 48491 isShadowRoot(node) && node.host || // Fallback. 48492 getDocumentElement(node) 48493 ); 48494 return isShadowRoot(result) ? result.host : result; 48495 } 48496 function getNearestOverflowAncestor(node) { 48497 const parentNode = getParentNode(node); 48498 if (isLastTraversableNode(parentNode)) { 48499 return node.ownerDocument ? node.ownerDocument.body : node.body; 48500 } 48501 if (isHTMLElement4(parentNode) && isOverflowElement(parentNode)) { 48502 return parentNode; 48503 } 48504 return getNearestOverflowAncestor(parentNode); 48505 } 48506 function getOverflowAncestors(node, list, traverseIframes) { 48507 var _node$ownerDocument2; 48508 if (list === void 0) { 48509 list = []; 48510 } 48511 if (traverseIframes === void 0) { 48512 traverseIframes = true; 48513 } 48514 const scrollableAncestor = getNearestOverflowAncestor(node); 48515 const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body); 48516 const win = getWindow2(scrollableAncestor); 48517 if (isBody) { 48518 const frameElement = getFrameElement(win); 48519 return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []); 48520 } else { 48521 return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes)); 48522 } 48523 } 48524 function getFrameElement(win) { 48525 return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null; 48526 } 48527 48528
vendor: 21,760 bytes, lines 48528-49139
48528// node_modules/@floating-ui/dom/dist/floating-ui.dom.mjs 48529 function getCssDimensions(element) { 48530 const css = getComputedStyle2(element); 48531 let width = parseFloat(css.width) || 0; 48532 let height = parseFloat(css.height) || 0; 48533 const hasOffset = isHTMLElement4(element); 48534 const offsetWidth = hasOffset ? element.offsetWidth : width; 48535 const offsetHeight = hasOffset ? element.offsetHeight : height; 48536 const shouldFallback = round(width) !== offsetWidth || round(height) !== offsetHeight; 48537 if (shouldFallback) { 48538 width = offsetWidth; 48539 height = offsetHeight; 48540 } 48541 return { 48542 width, 48543 height, 48544 $: shouldFallback 48545 }; 48546 } 48547 function unwrapElement(element) { 48548 return !isElement(element) ? element.contextElement : element; 48549 } 48550 function getScale(element) { 48551 const domElement = unwrapElement(element); 48552 if (!isHTMLElement4(domElement)) { 48553 return createCoords(1); 48554 } 48555 const rect = domElement.getBoundingClientRect(); 48556 const { 48557 width, 48558 height, 48559 $: $2 48560 } = getCssDimensions(domElement); 48561 let x3 = ($2 ? round(rect.width) : rect.width) / width; 48562 let y3 = ($2 ? round(rect.height) : rect.height) / height; 48563 if (!x3 || !Number.isFinite(x3)) { 48564 x3 = 1; 48565 } 48566 if (!y3 || !Number.isFinite(y3)) { 48567 y3 = 1; 48568 } 48569 return { 48570 x: x3, 48571 y: y3 48572 }; 48573 } 48574 var noOffsets = /* @__PURE__ */ createCoords(0); 48575 function getVisualOffsets(element) { 48576 const win = getWindow2(element); 48577 if (!isWebKit() || !win.visualViewport) { 48578 return noOffsets; 48579 } 48580 return { 48581 x: win.visualViewport.offsetLeft, 48582 y: win.visualViewport.offsetTop 48583 }; 48584 } 48585 function shouldAddVisualOffsets(element, isFixed, floatingOffsetParent) { 48586 if (isFixed === void 0) { 48587 isFixed = false; 48588 } 48589 if (!floatingOffsetParent || isFixed && floatingOffsetParent !== getWindow2(element)) { 48590 return false; 48591 } 48592 return isFixed; 48593 } 48594 function getBoundingClientRect(element, includeScale, isFixedStrategy, offsetParent) { 48595 if (includeScale === void 0) { 48596 includeScale = false; 48597 } 48598 if (isFixedStrategy === void 0) { 48599 isFixedStrategy = false; 48600 } 48601 const clientRect = element.getBoundingClientRect(); 48602 const domElement = unwrapElement(element); 48603 let scale = createCoords(1); 48604 if (includeScale) { 48605 if (offsetParent) { 48606 if (isElement(offsetParent)) { 48607 scale = getScale(offsetParent); 48608 } 48609 } else { 48610 scale = getScale(element); 48611 } 48612 } 48613 const visualOffsets = shouldAddVisualOffsets(domElement, isFixedStrategy, offsetParent) ? getVisualOffsets(domElement) : createCoords(0); 48614 let x3 = (clientRect.left + visualOffsets.x) / scale.x; 48615 let y3 = (clientRect.top + visualOffsets.y) / scale.y; 48616 let width = clientRect.width / scale.x; 48617 let height = clientRect.height / scale.y; 48618 if (domElement) { 48619 const win = getWindow2(domElement); 48620 const offsetWin = offsetParent && isElement(offsetParent) ? getWindow2(offsetParent) : offsetParent; 48621 let currentWin = win; 48622 let currentIFrame = getFrameElement(currentWin); 48623 while (currentIFrame && offsetParent && offsetWin !== currentWin) { 48624 const iframeScale = getScale(currentIFrame); 48625 const iframeRect = currentIFrame.getBoundingClientRect(); 48626 const css = getComputedStyle2(currentIFrame); 48627 const left = iframeRect.left + (currentIFrame.clientLeft + parseFloat(css.paddingLeft)) * iframeScale.x; 48628 const top = iframeRect.top + (currentIFrame.clientTop + parseFloat(css.paddingTop)) * iframeScale.y; 48629 x3 *= iframeScale.x; 48630 y3 *= iframeScale.y; 48631 width *= iframeScale.x; 48632 height *= iframeScale.y; 48633 x3 += left; 48634 y3 += top; 48635 currentWin = getWindow2(currentIFrame); 48636 currentIFrame = getFrameElement(currentWin); 48637 } 48638 } 48639 return rectToClientRect({ 48640 width, 48641 height, 48642 x: x3, 48643 y: y3 48644 }); 48645 } 48646 function getWindowScrollBarX(element, rect) { 48647 const leftScroll = getNodeScroll(element).scrollLeft; 48648 if (!rect) { 48649 return getBoundingClientRect(getDocumentElement(element)).left + leftScroll; 48650 } 48651 return rect.left + leftScroll; 48652 } 48653 function getHTMLOffset(documentElement, scroll) { 48654 const htmlRect = documentElement.getBoundingClientRect(); 48655 const x3 = htmlRect.left + scroll.scrollLeft - getWindowScrollBarX(documentElement, htmlRect); 48656 const y3 = htmlRect.top + scroll.scrollTop; 48657 return { 48658 x: x3, 48659 y: y3 48660 }; 48661 } 48662 function convertOffsetParentRelativeRectToViewportRelativeRect(_ref2) { 48663 let { 48664 elements, 48665 rect, 48666 offsetParent, 48667 strategy 48668 } = _ref2; 48669 const isFixed = strategy === "fixed"; 48670 const documentElement = getDocumentElement(offsetParent); 48671 const topLayer = elements ? isTopLayer(elements.floating) : false; 48672 if (offsetParent === documentElement || topLayer && isFixed) { 48673 return rect; 48674 } 48675 let scroll = { 48676 scrollLeft: 0, 48677 scrollTop: 0 48678 }; 48679 let scale = createCoords(1); 48680 const offsets = createCoords(0); 48681 const isOffsetParentAnElement = isHTMLElement4(offsetParent); 48682 if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) { 48683 if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) { 48684 scroll = getNodeScroll(offsetParent); 48685 } 48686 if (isOffsetParentAnElement) { 48687 const offsetRect = getBoundingClientRect(offsetParent); 48688 scale = getScale(offsetParent); 48689 offsets.x = offsetRect.x + offsetParent.clientLeft; 48690 offsets.y = offsetRect.y + offsetParent.clientTop; 48691 } 48692 } 48693 const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0); 48694 return { 48695 width: rect.width * scale.x, 48696 height: rect.height * scale.y, 48697 x: rect.x * scale.x - scroll.scrollLeft * scale.x + offsets.x + htmlOffset.x, 48698 y: rect.y * scale.y - scroll.scrollTop * scale.y + offsets.y + htmlOffset.y 48699 }; 48700 } 48701 function getClientRects(element) { 48702 return Array.from(element.getClientRects()); 48703 } 48704 function getDocumentRect(element) { 48705 const html2 = getDocumentElement(element); 48706 const scroll = getNodeScroll(element); 48707 const body = element.ownerDocument.body; 48708 const width = max(html2.scrollWidth, html2.clientWidth, body.scrollWidth, body.clientWidth); 48709 const height = max(html2.scrollHeight, html2.clientHeight, body.scrollHeight, body.clientHeight); 48710 let x3 = -scroll.scrollLeft + getWindowScrollBarX(element); 48711 const y3 = -scroll.scrollTop; 48712 if (getComputedStyle2(body).direction === "rtl") { 48713 x3 += max(html2.clientWidth, body.clientWidth) - width; 48714 } 48715 return { 48716 width, 48717 height, 48718 x: x3, 48719 y: y3 48720 }; 48721 } 48722 var SCROLLBAR_MAX = 25; 48723 function getViewportRect(element, strategy) { 48724 const win = getWindow2(element); 48725 const html2 = getDocumentElement(element); 48726 const visualViewport = win.visualViewport; 48727 let width = html2.clientWidth; 48728 let height = html2.clientHeight; 48729 let x3 = 0; 48730 let y3 = 0; 48731 if (visualViewport) { 48732 width = visualViewport.width; 48733 height = visualViewport.height; 48734 const visualViewportBased = isWebKit(); 48735 if (!visualViewportBased || visualViewportBased && strategy === "fixed") { 48736 x3 = visualViewport.offsetLeft; 48737 y3 = visualViewport.offsetTop; 48738 } 48739 } 48740 const windowScrollbarX = getWindowScrollBarX(html2); 48741 if (windowScrollbarX <= 0) { 48742 const doc = html2.ownerDocument; 48743 const body = doc.body; 48744 const bodyStyles = getComputedStyle(body); 48745 const bodyMarginInline = doc.compatMode === "CSS1Compat" ? parseFloat(bodyStyles.marginLeft) + parseFloat(bodyStyles.marginRight) || 0 : 0; 48746 const clippingStableScrollbarWidth = Math.abs(html2.clientWidth - body.clientWidth - bodyMarginInline); 48747 if (clippingStableScrollbarWidth <= SCROLLBAR_MAX) { 48748 width -= clippingStableScrollbarWidth; 48749 } 48750 } else if (windowScrollbarX <= SCROLLBAR_MAX) { 48751 width += windowScrollbarX; 48752 } 48753 return { 48754 width, 48755 height, 48756 x: x3, 48757 y: y3 48758 }; 48759 } 48760 function getInnerBoundingClientRect(element, strategy) { 48761 const clientRect = getBoundingClientRect(element, true, strategy === "fixed"); 48762 const top = clientRect.top + element.clientTop; 48763 const left = clientRect.left + element.clientLeft; 48764 const scale = isHTMLElement4(element) ? getScale(element) : createCoords(1); 48765 const width = element.clientWidth * scale.x; 48766 const height = element.clientHeight * scale.y; 48767 const x3 = left * scale.x; 48768 const y3 = top * scale.y; 48769 return { 48770 width, 48771 height, 48772 x: x3, 48773 y: y3 48774 }; 48775 } 48776 function getClientRectFromClippingAncestor(element, clippingAncestor, strategy) { 48777 let rect; 48778 if (clippingAncestor === "viewport") { 48779 rect = getViewportRect(element, strategy); 48780 } else if (clippingAncestor === "document") { 48781 rect = getDocumentRect(getDocumentElement(element)); 48782 } else if (isElement(clippingAncestor)) { 48783 rect = getInnerBoundingClientRect(clippingAncestor, strategy); 48784 } else { 48785 const visualOffsets = getVisualOffsets(element); 48786 rect = { 48787 x: clippingAncestor.x - visualOffsets.x, 48788 y: clippingAncestor.y - visualOffsets.y, 48789 width: clippingAncestor.width, 48790 height: clippingAncestor.height 48791 }; 48792 } 48793 return rectToClientRect(rect); 48794 } 48795 function hasFixedPositionAncestor(element, stopNode) { 48796 const parentNode = getParentNode(element); 48797 if (parentNode === stopNode || !isElement(parentNode) || isLastTraversableNode(parentNode)) { 48798 return false; 48799 } 48800 return getComputedStyle2(parentNode).position === "fixed" || hasFixedPositionAncestor(parentNode, stopNode); 48801 } 48802 function getClippingElementAncestors(element, cache) { 48803 const cachedResult = cache.get(element); 48804 if (cachedResult) { 48805 return cachedResult; 48806 } 48807 let result = getOverflowAncestors(element, [], false).filter((el) => isElement(el) && getNodeName(el) !== "body"); 48808 let currentContainingBlockComputedStyle = null; 48809 const elementIsFixed = getComputedStyle2(element).position === "fixed"; 48810 let currentNode = elementIsFixed ? getParentNode(element) : element; 48811 while (isElement(currentNode) && !isLastTraversableNode(currentNode)) { 48812 const computedStyle = getComputedStyle2(currentNode); 48813 const currentNodeIsContaining = isContainingBlock(currentNode); 48814 if (!currentNodeIsContaining && computedStyle.position === "fixed") { 48815 currentContainingBlockComputedStyle = null; 48816 } 48817 const shouldDropCurrentNode = elementIsFixed ? !currentNodeIsContaining && !currentContainingBlockComputedStyle : !currentNodeIsContaining && computedStyle.position === "static" && !!currentContainingBlockComputedStyle && (currentContainingBlockComputedStyle.position === "absolute" || currentContainingBlockComputedStyle.position === "fixed") || isOverflowElement(currentNode) && !currentNodeIsContaining && hasFixedPositionAncestor(element, currentNode); 48818 if (shouldDropCurrentNode) { 48819 result = result.filter((ancestor) => ancestor !== currentNode); 48820 } else { 48821 currentContainingBlockComputedStyle = computedStyle; 48822 } 48823 currentNode = getParentNode(currentNode); 48824 } 48825 cache.set(element, result); 48826 return result; 48827 } 48828 function getClippingRect(_ref2) { 48829 let { 48830 element, 48831 boundary, 48832 rootBoundary, 48833 strategy 48834 } = _ref2; 48835 const elementClippingAncestors = boundary === "clippingAncestors" ? isTopLayer(element) ? [] : getClippingElementAncestors(element, this._c) : [].concat(boundary); 48836 const clippingAncestors = [...elementClippingAncestors, rootBoundary]; 48837 const firstRect = getClientRectFromClippingAncestor(element, clippingAncestors[0], strategy); 48838 let top = firstRect.top; 48839 let right = firstRect.right; 48840 let bottom = firstRect.bottom; 48841 let left = firstRect.left; 48842 for (let i2 = 1; i2 < clippingAncestors.length; i2++) { 48843 const rect = getClientRectFromClippingAncestor(element, clippingAncestors[i2], strategy); 48844 top = max(rect.top, top); 48845 right = min(rect.right, right); 48846 bottom = min(rect.bottom, bottom); 48847 left = max(rect.left, left); 48848 } 48849 return { 48850 width: right - left, 48851 height: bottom - top, 48852 x: left, 48853 y: top 48854 }; 48855 } 48856 function getDimensions(element) { 48857 const { 48858 width, 48859 height 48860 } = getCssDimensions(element); 48861 return { 48862 width, 48863 height 48864 }; 48865 } 48866 function getRectRelativeToOffsetParent(element, offsetParent, strategy) { 48867 const isOffsetParentAnElement = isHTMLElement4(offsetParent); 48868 const documentElement = getDocumentElement(offsetParent); 48869 const isFixed = strategy === "fixed"; 48870 const rect = getBoundingClientRect(element, true, isFixed, offsetParent); 48871 let scroll = { 48872 scrollLeft: 0, 48873 scrollTop: 0 48874 }; 48875 const offsets = createCoords(0); 48876 function setLeftRTLScrollbarOffset() { 48877 offsets.x = getWindowScrollBarX(documentElement); 48878 } 48879 if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) { 48880 if (getNodeName(offsetParent) !== "body" || isOverflowElement(documentElement)) { 48881 scroll = getNodeScroll(offsetParent); 48882 } 48883 if (isOffsetParentAnElement) { 48884 const offsetRect = getBoundingClientRect(offsetParent, true, isFixed, offsetParent); 48885 offsets.x = offsetRect.x + offsetParent.clientLeft; 48886 offsets.y = offsetRect.y + offsetParent.clientTop; 48887 } else if (documentElement) { 48888 setLeftRTLScrollbarOffset(); 48889 } 48890 } 48891 if (isFixed && !isOffsetParentAnElement && documentElement) { 48892 setLeftRTLScrollbarOffset(); 48893 } 48894 const htmlOffset = documentElement && !isOffsetParentAnElement && !isFixed ? getHTMLOffset(documentElement, scroll) : createCoords(0); 48895 const x3 = rect.left + scroll.scrollLeft - offsets.x - htmlOffset.x; 48896 const y3 = rect.top + scroll.scrollTop - offsets.y - htmlOffset.y; 48897 return { 48898 x: x3, 48899 y: y3, 48900 width: rect.width, 48901 height: rect.height 48902 }; 48903 } 48904 function isStaticPositioned(element) { 48905 return getComputedStyle2(element).position === "static"; 48906 } 48907 function getTrueOffsetParent(element, polyfill) { 48908 if (!isHTMLElement4(element) || getComputedStyle2(element).position === "fixed") { 48909 return null; 48910 } 48911 if (polyfill) { 48912 return polyfill(element); 48913 } 48914 let rawOffsetParent = element.offsetParent; 48915 if (getDocumentElement(element) === rawOffsetParent) { 48916 rawOffsetParent = rawOffsetParent.ownerDocument.body; 48917 } 48918 return rawOffsetParent; 48919 } 48920 function getOffsetParent(element, polyfill) { 48921 const win = getWindow2(element); 48922 if (isTopLayer(element)) { 48923 return win; 48924 } 48925 if (!isHTMLElement4(element)) { 48926 let svgOffsetParent = getParentNode(element); 48927 while (svgOffsetParent && !isLastTraversableNode(svgOffsetParent)) { 48928 if (isElement(svgOffsetParent) && !isStaticPositioned(svgOffsetParent)) { 48929 return svgOffsetParent; 48930 } 48931 svgOffsetParent = getParentNode(svgOffsetParent); 48932 } 48933 return win; 48934 } 48935 let offsetParent = getTrueOffsetParent(element, polyfill); 48936 while (offsetParent && isTableElement(offsetParent) && isStaticPositioned(offsetParent)) { 48937 offsetParent = getTrueOffsetParent(offsetParent, polyfill); 48938 } 48939 if (offsetParent && isLastTraversableNode(offsetParent) && isStaticPositioned(offsetParent) && !isContainingBlock(offsetParent)) { 48940 return win; 48941 } 48942 return offsetParent || getContainingBlock(element) || win; 48943 } 48944 var getElementRects = async function(data) { 48945 const getOffsetParentFn = this.getOffsetParent || getOffsetParent; 48946 const getDimensionsFn = this.getDimensions; 48947 const floatingDimensions = await getDimensionsFn(data.floating); 48948 return { 48949 reference: getRectRelativeToOffsetParent(data.reference, await getOffsetParentFn(data.floating), data.strategy), 48950 floating: { 48951 x: 0, 48952 y: 0, 48953 width: floatingDimensions.width, 48954 height: floatingDimensions.height 48955 } 48956 }; 48957 }; 48958 function isRTL(element) { 48959 return getComputedStyle2(element).direction === "rtl"; 48960 } 48961 var platform = { 48962 convertOffsetParentRelativeRectToViewportRelativeRect, 48963 getDocumentElement, 48964 getClippingRect, 48965 getOffsetParent, 48966 getElementRects, 48967 getClientRects, 48968 getDimensions, 48969 getScale, 48970 isElement, 48971 isRTL 48972 }; 48973 function rectsAreEqual(a2, b3) { 48974 return a2.x === b3.x && a2.y === b3.y && a2.width === b3.width && a2.height === b3.height; 48975 } 48976 function observeMove(element, onMove) { 48977 let io = null; 48978 let timeoutId; 48979 const root = getDocumentElement(element); 48980 function cleanup() { 48981 var _io; 48982 clearTimeout(timeoutId); 48983 (_io = io) == null || _io.disconnect(); 48984 io = null; 48985 } 48986 function refresh(skip, threshold) { 48987 if (skip === void 0) { 48988 skip = false; 48989 } 48990 if (threshold === void 0) { 48991 threshold = 1; 48992 } 48993 cleanup(); 48994 const elementRectForRootMargin = element.getBoundingClientRect(); 48995 const { 48996 left, 48997 top, 48998 width, 48999 height 49000 } = elementRectForRootMargin; 49001 if (!skip) { 49002 onMove(); 49003 } 49004 if (!width || !height) { 49005 return; 49006 } 49007 const insetTop = floor(top); 49008 const insetRight = floor(root.clientWidth - (left + width)); 49009 const insetBottom = floor(root.clientHeight - (top + height)); 49010 const insetLeft = floor(left); 49011 const rootMargin = -insetTop + "px " + -insetRight + "px " + -insetBottom + "px " + -insetLeft + "px"; 49012 const options = { 49013 rootMargin, 49014 threshold: max(0, min(1, threshold)) || 1 49015 }; 49016 let isFirstUpdate = true; 49017 function handleObserve(entries2) { 49018 const ratio = entries2[0].intersectionRatio; 49019 if (ratio !== threshold) { 49020 if (!isFirstUpdate) { 49021 return refresh(); 49022 } 49023 if (!ratio) { 49024 timeoutId = setTimeout(() => { 49025 refresh(false, 1e-7); 49026 }, 1e3); 49027 } else { 49028 refresh(false, ratio); 49029 } 49030 } 49031 if (ratio === 1 && !rectsAreEqual(elementRectForRootMargin, element.getBoundingClientRect())) { 49032 refresh(); 49033 } 49034 isFirstUpdate = false; 49035 } 49036 try { 49037 io = new IntersectionObserver(handleObserve, { 49038 ...options, 49039 // Handle <iframe>s 49040 root: root.ownerDocument 49041 }); 49042 } catch (_e2) { 49043 io = new IntersectionObserver(handleObserve, options); 49044 } 49045 io.observe(element); 49046 } 49047 refresh(true); 49048 return cleanup; 49049 } 49050 function autoUpdate(reference, floating, update, options) { 49051 if (options === void 0) { 49052 options = {}; 49053 } 49054 const { 49055 ancestorScroll = true, 49056 ancestorResize = true, 49057 elementResize = typeof ResizeObserver === "function", 49058 layoutShift = typeof IntersectionObserver === "function", 49059 animationFrame = false 49060 } = options; 49061 const referenceEl = unwrapElement(reference); 49062 const ancestors = ancestorScroll || ancestorResize ? [...referenceEl ? getOverflowAncestors(referenceEl) : [], ...floating ? getOverflowAncestors(floating) : []] : []; 49063 ancestors.forEach((ancestor) => { 49064 ancestorScroll && ancestor.addEventListener("scroll", update, { 49065 passive: true 49066 }); 49067 ancestorResize && ancestor.addEventListener("resize", update); 49068 }); 49069 const cleanupIo = referenceEl && layoutShift ? observeMove(referenceEl, update) : null; 49070 let reobserveFrame = -1; 49071 let resizeObserver = null; 49072 if (elementResize) { 49073 resizeObserver = new ResizeObserver((_ref2) => { 49074 let [firstEntry] = _ref2; 49075 if (firstEntry && firstEntry.target === referenceEl && resizeObserver && floating) { 49076 resizeObserver.unobserve(floating); 49077 cancelAnimationFrame(reobserveFrame); 49078 reobserveFrame = requestAnimationFrame(() => { 49079 var _resizeObserver; 49080 (_resizeObserver = resizeObserver) == null || _resizeObserver.observe(floating); 49081 }); 49082 } 49083 update(); 49084 }); 49085 if (referenceEl && !animationFrame) { 49086 resizeObserver.observe(referenceEl); 49087 } 49088 if (floating) { 49089 resizeObserver.observe(floating); 49090 } 49091 } 49092 let frameId; 49093 let prevRefRect = animationFrame ? getBoundingClientRect(reference) : null; 49094 if (animationFrame) { 49095 frameLoop(); 49096 } 49097 function frameLoop() { 49098 const nextRefRect = getBoundingClientRect(reference); 49099 if (prevRefRect && !rectsAreEqual(prevRefRect, nextRefRect)) { 49100 update(); 49101 } 49102 prevRefRect = nextRefRect; 49103 frameId = requestAnimationFrame(frameLoop); 49104 } 49105 update(); 49106 return () => { 49107 var _resizeObserver2; 49108 ancestors.forEach((ancestor) => { 49109 ancestorScroll && ancestor.removeEventListener("scroll", update); 49110 ancestorResize && ancestor.removeEventListener("resize", update); 49111 }); 49112 cleanupIo == null || cleanupIo(); 49113 (_resizeObserver2 = resizeObserver) == null || _resizeObserver2.disconnect(); 49114 resizeObserver = null; 49115 if (animationFrame) { 49116 cancelAnimationFrame(frameId); 49117 } 49118 }; 49119 } 49120 var offset2 = offset; 49121 var shift2 = shift; 49122 var flip2 = flip; 49123 var computePosition2 = (reference, floating, options) => { 49124 const cache = /* @__PURE__ */ new Map(); 49125 const mergedOptions = { 49126 platform, 49127 ...options 49128 }; 49129 const platformWithCache = { 49130 ...mergedOptions.platform, 49131 _c: cache 49132 }; 49133 return computePosition(reference, floating, { 49134 ...mergedOptions, 49135 platform: platformWithCache 49136 }); 49137 }; 49138 49139
49139// app/javascript/src/lexxy/callout_image_uploader.js 49140 var CALLOUT_ICON_TYPES = ["image/jpeg", "image/png", "image/webp", "image/gif"]; 49141 var MAX_CALLOUT_ICON_BYTES = 1024 * 1024; 49142 function isCalloutIconFile(file) { 49143 return file && CALLOUT_ICON_TYPES.includes(file.type) && file.size <= MAX_CALLOUT_ICON_BYTES; 49144 } 49145 function uploadCalloutIcon(editorElement, file) { 49146 const uploadUrl = editorElement.directUploadUrl; 49147 const blobUrlTemplate = editorElement.blobUrlTemplate; 49148 if (!uploadUrl || !blobUrlTemplate) { 49149 return Promise.reject(new Error("Direct upload is not configured for this editor")); 49150 } 49151 if (!isCalloutIconFile(file)) { 49152 return Promise.reject(new Error("Please choose a PNG, JPG, WEBP, or GIF under 1MB")); 49153 } 49154 return Promise.resolve().then(() => (init_activestorage_esm(), activestorage_esm_exports)).then(({ DirectUpload: DirectUpload3 }) => { 49155 return new Promise((resolve, reject) => { 49156 const upload = new DirectUpload3(file, uploadUrl, { 49157 directUploadWillCreateBlobWithXHR(request) { 49158 request.withCredentials = true; 49159 }, 49160 directUploadWillStoreFileWithXHR(request) { 49161 request.withCredentials = true; 49162 } 49163 }); 49164 upload.create((error, blob) => { 49165 if (error) { 49166 reject(error); 49167 return; 49168 } 49169 const url = blob.previewable ? blob.url : blobUrlTemplate.replace(":signed_id", blob.signed_id).replace(":filename", encodeURIComponent(blob.filename)); 49170 resolve(url); 49171 }); 49172 }); 49173 }); 49174 } 49175 49176
vendor: 139,589 bytes, lines 49176-51762
49176// node_modules/emoji-mart/dist/module.js 49177 function $parcel$interopDefault(a2) { 49178 return a2 && a2.__esModule ? a2.default : a2; 49179 } 49180 function $c770c458706daa72$export$2e2bcd8739ae039(obj, key, value) { 49181 if (key in obj) Object.defineProperty(obj, key, { 49182 value, 49183 enumerable: true, 49184 configurable: true, 49185 writable: true 49186 }); 49187 else obj[key] = value; 49188 return obj; 49189 } 49190 var $fb96b826c0c5f37a$var$n; 49191 var $fb96b826c0c5f37a$export$41c562ebe57d11e2; 49192 var $fb96b826c0c5f37a$var$u; 49193 var $fb96b826c0c5f37a$export$a8257692ac88316c; 49194 var $fb96b826c0c5f37a$var$t; 49195 var $fb96b826c0c5f37a$var$r; 49196 var $fb96b826c0c5f37a$var$o; 49197 var $fb96b826c0c5f37a$var$f; 49198 var $fb96b826c0c5f37a$var$e = {}; 49199 var $fb96b826c0c5f37a$var$c = []; 49200 var $fb96b826c0c5f37a$var$s = /acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i; 49201 function $fb96b826c0c5f37a$var$a(n1, l1) { 49202 for (var u1 in l1) n1[u1] = l1[u1]; 49203 return n1; 49204 } 49205 function $fb96b826c0c5f37a$var$h(n2) { 49206 var l22 = n2.parentNode; 49207 l22 && l22.removeChild(n2); 49208 } 49209 function $fb96b826c0c5f37a$export$c8a8987d4410bf2d(l32, u2, i1) { 49210 var t1, r1, o1, f1 = {}; 49211 for (o1 in u2) "key" == o1 ? t1 = u2[o1] : "ref" == o1 ? r1 = u2[o1] : f1[o1] = u2[o1]; 49212 if (arguments.length > 2 && (f1.children = arguments.length > 3 ? $fb96b826c0c5f37a$var$n.call(arguments, 2) : i1), "function" == typeof l32 && null != l32.defaultProps) for (o1 in l32.defaultProps) void 0 === f1[o1] && (f1[o1] = l32.defaultProps[o1]); 49213 return $fb96b826c0c5f37a$var$y(l32, f1, t1, r1, null); 49214 } 49215 function $fb96b826c0c5f37a$var$y(n3, i2, t2, r2, o2) { 49216 var f2 = { 49217 type: n3, 49218 props: i2, 49219 key: t2, 49220 ref: r2, 49221 __k: null, 49222 __: null, 49223 __b: 0, 49224 __e: null, 49225 __d: void 0, 49226 __c: null, 49227 __h: null, 49228 constructor: void 0, 49229 __v: null == o2 ? ++$fb96b826c0c5f37a$var$u : o2 49230 }; 49231 return null == o2 && null != $fb96b826c0c5f37a$export$41c562ebe57d11e2.vnode && $fb96b826c0c5f37a$export$41c562ebe57d11e2.vnode(f2), f2; 49232 } 49233 function $fb96b826c0c5f37a$export$7d1e3a5e95ceca43() { 49234 return { 49235 current: null 49236 }; 49237 } 49238 function $fb96b826c0c5f37a$export$ffb0004e005737fa(n4) { 49239 return n4.children; 49240 } 49241 function $fb96b826c0c5f37a$export$16fa2f45be04daa8(n5, l4) { 49242 this.props = n5, this.context = l4; 49243 } 49244 function $fb96b826c0c5f37a$var$k(n6, l5) { 49245 if (null == l5) return n6.__ ? $fb96b826c0c5f37a$var$k(n6.__, n6.__.__k.indexOf(n6) + 1) : null; 49246 for (var u3; l5 < n6.__k.length; l5++) if (null != (u3 = n6.__k[l5]) && null != u3.__e) return u3.__e; 49247 return "function" == typeof n6.type ? $fb96b826c0c5f37a$var$k(n6) : null; 49248 } 49249 function $fb96b826c0c5f37a$var$b(n7) { 49250 var l6, u4; 49251 if (null != (n7 = n7.__) && null != n7.__c) { 49252 for (n7.__e = n7.__c.base = null, l6 = 0; l6 < n7.__k.length; l6++) if (null != (u4 = n7.__k[l6]) && null != u4.__e) { 49253 n7.__e = n7.__c.base = u4.__e; 49254 break; 49255 } 49256 return $fb96b826c0c5f37a$var$b(n7); 49257 } 49258 } 49259 function $fb96b826c0c5f37a$var$m(n8) { 49260 (!n8.__d && (n8.__d = true) && $fb96b826c0c5f37a$var$t.push(n8) && !$fb96b826c0c5f37a$var$g.__r++ || $fb96b826c0c5f37a$var$o !== $fb96b826c0c5f37a$export$41c562ebe57d11e2.debounceRendering) && (($fb96b826c0c5f37a$var$o = $fb96b826c0c5f37a$export$41c562ebe57d11e2.debounceRendering) || $fb96b826c0c5f37a$var$r)($fb96b826c0c5f37a$var$g); 49261 } 49262 function $fb96b826c0c5f37a$var$g() { 49263 for (var n9; $fb96b826c0c5f37a$var$g.__r = $fb96b826c0c5f37a$var$t.length; ) n9 = $fb96b826c0c5f37a$var$t.sort(function(n10, l7) { 49264 return n10.__v.__b - l7.__v.__b; 49265 }), $fb96b826c0c5f37a$var$t = [], n9.some(function(n11) { 49266 var l8, u5, i3, t3, r3, o3; 49267 n11.__d && (r3 = (t3 = (l8 = n11).__v).__e, (o3 = l8.__P) && (u5 = [], (i3 = $fb96b826c0c5f37a$var$a({}, t3)).__v = t3.__v + 1, $fb96b826c0c5f37a$var$j(o3, t3, i3, l8.__n, void 0 !== o3.ownerSVGElement, null != t3.__h ? [ 49268 r3 49269 ] : null, u5, null == r3 ? $fb96b826c0c5f37a$var$k(t3) : r3, t3.__h), $fb96b826c0c5f37a$var$z(u5, t3), t3.__e != r3 && $fb96b826c0c5f37a$var$b(t3))); 49270 }); 49271 } 49272 function $fb96b826c0c5f37a$var$w(n12, l9, u6, i4, t4, r4, o4, f3, s1, a1) { 49273 var h1, v1, p1, _1, b1, m1, g1, w1 = i4 && i4.__k || $fb96b826c0c5f37a$var$c, A1 = w1.length; 49274 for (u6.__k = [], h1 = 0; h1 < l9.length; h1++) if (null != (_1 = u6.__k[h1] = null == (_1 = l9[h1]) || "boolean" == typeof _1 ? null : "string" == typeof _1 || "number" == typeof _1 || "bigint" == typeof _1 ? $fb96b826c0c5f37a$var$y(null, _1, null, null, _1) : Array.isArray(_1) ? $fb96b826c0c5f37a$var$y($fb96b826c0c5f37a$export$ffb0004e005737fa, { 49275 children: _1 49276 }, null, null, null) : _1.__b > 0 ? $fb96b826c0c5f37a$var$y(_1.type, _1.props, _1.key, null, _1.__v) : _1)) { 49277 if (_1.__ = u6, _1.__b = u6.__b + 1, null === (p1 = w1[h1]) || p1 && _1.key == p1.key && _1.type === p1.type) w1[h1] = void 0; 49278 else for (v1 = 0; v1 < A1; v1++) { 49279 if ((p1 = w1[v1]) && _1.key == p1.key && _1.type === p1.type) { 49280 w1[v1] = void 0; 49281 break; 49282 } 49283 p1 = null; 49284 } 49285 $fb96b826c0c5f37a$var$j(n12, _1, p1 = p1 || $fb96b826c0c5f37a$var$e, t4, r4, o4, f3, s1, a1), b1 = _1.__e, (v1 = _1.ref) && p1.ref != v1 && (g1 || (g1 = []), p1.ref && g1.push(p1.ref, null, _1), g1.push(v1, _1.__c || b1, _1)), null != b1 ? (null == m1 && (m1 = b1), "function" == typeof _1.type && _1.__k === p1.__k ? _1.__d = s1 = $fb96b826c0c5f37a$var$x(_1, s1, n12) : s1 = $fb96b826c0c5f37a$var$P(n12, _1, p1, w1, b1, s1), "function" == typeof u6.type && (u6.__d = s1)) : s1 && p1.__e == s1 && s1.parentNode != n12 && (s1 = $fb96b826c0c5f37a$var$k(p1)); 49286 } 49287 for (u6.__e = m1, h1 = A1; h1--; ) null != w1[h1] && ("function" == typeof u6.type && null != w1[h1].__e && w1[h1].__e == u6.__d && (u6.__d = $fb96b826c0c5f37a$var$k(i4, h1 + 1)), $fb96b826c0c5f37a$var$N(w1[h1], w1[h1])); 49288 if (g1) for (h1 = 0; h1 < g1.length; h1++) $fb96b826c0c5f37a$var$M(g1[h1], g1[++h1], g1[++h1]); 49289 } 49290 function $fb96b826c0c5f37a$var$x(n13, l10, u7) { 49291 for (var i5, t5 = n13.__k, r5 = 0; t5 && r5 < t5.length; r5++) (i5 = t5[r5]) && (i5.__ = n13, l10 = "function" == typeof i5.type ? $fb96b826c0c5f37a$var$x(i5, l10, u7) : $fb96b826c0c5f37a$var$P(u7, i5, i5, t5, i5.__e, l10)); 49292 return l10; 49293 } 49294 function $fb96b826c0c5f37a$export$47e4c5b300681277(n14, l11) { 49295 return l11 = l11 || [], null == n14 || "boolean" == typeof n14 || (Array.isArray(n14) ? n14.some(function(n15) { 49296 $fb96b826c0c5f37a$export$47e4c5b300681277(n15, l11); 49297 }) : l11.push(n14)), l11; 49298 } 49299 function $fb96b826c0c5f37a$var$P(n16, l12, u8, i6, t6, r6) { 49300 var o5, f4, e1; 49301 if (void 0 !== l12.__d) o5 = l12.__d, l12.__d = void 0; 49302 else if (null == u8 || t6 != r6 || null == t6.parentNode) n: if (null == r6 || r6.parentNode !== n16) n16.appendChild(t6), o5 = null; 49303 else { 49304 for (f4 = r6, e1 = 0; (f4 = f4.nextSibling) && e1 < i6.length; e1 += 2) if (f4 == t6) break n; 49305 n16.insertBefore(t6, r6), o5 = r6; 49306 } 49307 return void 0 !== o5 ? o5 : t6.nextSibling; 49308 } 49309 function $fb96b826c0c5f37a$var$C(n17, l13, u9, i7, t7) { 49310 var r7; 49311 for (r7 in u9) "children" === r7 || "key" === r7 || r7 in l13 || $fb96b826c0c5f37a$var$H(n17, r7, null, u9[r7], i7); 49312 for (r7 in l13) t7 && "function" != typeof l13[r7] || "children" === r7 || "key" === r7 || "value" === r7 || "checked" === r7 || u9[r7] === l13[r7] || $fb96b826c0c5f37a$var$H(n17, r7, l13[r7], u9[r7], i7); 49313 } 49314 function $fb96b826c0c5f37a$var$$(n18, l14, u10) { 49315 "-" === l14[0] ? n18.setProperty(l14, u10) : n18[l14] = null == u10 ? "" : "number" != typeof u10 || $fb96b826c0c5f37a$var$s.test(l14) ? u10 : u10 + "px"; 49316 } 49317 function $fb96b826c0c5f37a$var$H(n19, l15, u11, i8, t8) { 49318 var r8; 49319 n: if ("style" === l15) { 49320 if ("string" == typeof u11) n19.style.cssText = u11; 49321 else { 49322 if ("string" == typeof i8 && (n19.style.cssText = i8 = ""), i8) for (l15 in i8) u11 && l15 in u11 || $fb96b826c0c5f37a$var$$(n19.style, l15, ""); 49323 if (u11) for (l15 in u11) i8 && u11[l15] === i8[l15] || $fb96b826c0c5f37a$var$$(n19.style, l15, u11[l15]); 49324 } 49325 } else if ("o" === l15[0] && "n" === l15[1]) r8 = l15 !== (l15 = l15.replace(/Capture$/, "")), l15 = l15.toLowerCase() in n19 ? l15.toLowerCase().slice(2) : l15.slice(2), n19.l || (n19.l = {}), n19.l[l15 + r8] = u11, u11 ? i8 || n19.addEventListener(l15, r8 ? $fb96b826c0c5f37a$var$T : $fb96b826c0c5f37a$var$I, r8) : n19.removeEventListener(l15, r8 ? $fb96b826c0c5f37a$var$T : $fb96b826c0c5f37a$var$I, r8); 49326 else if ("dangerouslySetInnerHTML" !== l15) { 49327 if (t8) l15 = l15.replace(/xlink[H:h]/, "h").replace(/sName$/, "s"); 49328 else if ("href" !== l15 && "list" !== l15 && "form" !== l15 && "tabIndex" !== l15 && "download" !== l15 && l15 in n19) try { 49329 n19[l15] = null == u11 ? "" : u11; 49330 break n; 49331 } catch (n2) { 49332 } 49333 "function" == typeof u11 || (null != u11 && (false !== u11 || "a" === l15[0] && "r" === l15[1]) ? n19.setAttribute(l15, u11) : n19.removeAttribute(l15)); 49334 } 49335 } 49336 function $fb96b826c0c5f37a$var$I(n20) { 49337 this.l[n20.type + false]($fb96b826c0c5f37a$export$41c562ebe57d11e2.event ? $fb96b826c0c5f37a$export$41c562ebe57d11e2.event(n20) : n20); 49338 } 49339 function $fb96b826c0c5f37a$var$T(n21) { 49340 this.l[n21.type + true]($fb96b826c0c5f37a$export$41c562ebe57d11e2.event ? $fb96b826c0c5f37a$export$41c562ebe57d11e2.event(n21) : n21); 49341 } 49342 function $fb96b826c0c5f37a$var$j(n22, u12, i9, t9, r9, o6, f5, e2, c1) { 49343 var s2, h2, v22, y1, p2, k1, b22, m22, g2, x1, A2, P1 = u12.type; 49344 if (void 0 !== u12.constructor) return null; 49345 null != i9.__h && (c1 = i9.__h, e2 = u12.__e = i9.__e, u12.__h = null, o6 = [ 49346 e2 49347 ]), (s2 = $fb96b826c0c5f37a$export$41c562ebe57d11e2.__b) && s2(u12); 49348 try { 49349 n: if ("function" == typeof P1) { 49350 if (m22 = u12.props, g2 = (s2 = P1.contextType) && t9[s2.__c], x1 = s2 ? g2 ? g2.props.value : s2.__ : t9, i9.__c ? b22 = (h2 = u12.__c = i9.__c).__ = h2.__E : ("prototype" in P1 && P1.prototype.render ? u12.__c = h2 = new P1(m22, x1) : (u12.__c = h2 = new $fb96b826c0c5f37a$export$16fa2f45be04daa8(m22, x1), h2.constructor = P1, h2.render = $fb96b826c0c5f37a$var$O), g2 && g2.sub(h2), h2.props = m22, h2.state || (h2.state = {}), h2.context = x1, h2.__n = t9, v22 = h2.__d = true, h2.__h = []), null == h2.__s && (h2.__s = h2.state), null != P1.getDerivedStateFromProps && (h2.__s == h2.state && (h2.__s = $fb96b826c0c5f37a$var$a({}, h2.__s)), $fb96b826c0c5f37a$var$a(h2.__s, P1.getDerivedStateFromProps(m22, h2.__s))), y1 = h2.props, p2 = h2.state, v22) null == P1.getDerivedStateFromProps && null != h2.componentWillMount && h2.componentWillMount(), null != h2.componentDidMount && h2.__h.push(h2.componentDidMount); 49351 else { 49352 if (null == P1.getDerivedStateFromProps && m22 !== y1 && null != h2.componentWillReceiveProps && h2.componentWillReceiveProps(m22, x1), !h2.__e && null != h2.shouldComponentUpdate && false === h2.shouldComponentUpdate(m22, h2.__s, x1) || u12.__v === i9.__v) { 49353 h2.props = m22, h2.state = h2.__s, u12.__v !== i9.__v && (h2.__d = false), h2.__v = u12, u12.__e = i9.__e, u12.__k = i9.__k, u12.__k.forEach(function(n23) { 49354 n23 && (n23.__ = u12); 49355 }), h2.__h.length && f5.push(h2); 49356 break n; 49357 } 49358 null != h2.componentWillUpdate && h2.componentWillUpdate(m22, h2.__s, x1), null != h2.componentDidUpdate && h2.__h.push(function() { 49359 h2.componentDidUpdate(y1, p2, k1); 49360 }); 49361 } 49362 h2.context = x1, h2.props = m22, h2.state = h2.__s, (s2 = $fb96b826c0c5f37a$export$41c562ebe57d11e2.__r) && s2(u12), h2.__d = false, h2.__v = u12, h2.__P = n22, s2 = h2.render(h2.props, h2.state, h2.context), h2.state = h2.__s, null != h2.getChildContext && (t9 = $fb96b826c0c5f37a$var$a($fb96b826c0c5f37a$var$a({}, t9), h2.getChildContext())), v22 || null == h2.getSnapshotBeforeUpdate || (k1 = h2.getSnapshotBeforeUpdate(y1, p2)), A2 = null != s2 && s2.type === $fb96b826c0c5f37a$export$ffb0004e005737fa && null == s2.key ? s2.props.children : s2, $fb96b826c0c5f37a$var$w(n22, Array.isArray(A2) ? A2 : [ 49363 A2 49364 ], u12, i9, t9, r9, o6, f5, e2, c1), h2.base = u12.__e, u12.__h = null, h2.__h.length && f5.push(h2), b22 && (h2.__E = h2.__ = null), h2.__e = false; 49365 } else null == o6 && u12.__v === i9.__v ? (u12.__k = i9.__k, u12.__e = i9.__e) : u12.__e = $fb96b826c0c5f37a$var$L(i9.__e, u12, i9, t9, r9, o6, f5, c1); 49366 (s2 = $fb96b826c0c5f37a$export$41c562ebe57d11e2.diffed) && s2(u12); 49367 } catch (n24) { 49368 u12.__v = null, (c1 || null != o6) && (u12.__e = e2, u12.__h = !!c1, o6[o6.indexOf(e2)] = null), $fb96b826c0c5f37a$export$41c562ebe57d11e2.__e(n24, u12, i9); 49369 } 49370 } 49371 function $fb96b826c0c5f37a$var$z(n25, u13) { 49372 $fb96b826c0c5f37a$export$41c562ebe57d11e2.__c && $fb96b826c0c5f37a$export$41c562ebe57d11e2.__c(u13, n25), n25.some(function(u14) { 49373 try { 49374 n25 = u14.__h, u14.__h = [], n25.some(function(n26) { 49375 n26.call(u14); 49376 }); 49377 } catch (n27) { 49378 $fb96b826c0c5f37a$export$41c562ebe57d11e2.__e(n27, u14.__v); 49379 } 49380 }); 49381 } 49382 function $fb96b826c0c5f37a$var$L(l16, u15, i10, t10, r10, o7, f6, c2) { 49383 var s3, a2, v3, y22 = i10.props, p3 = u15.props, d1 = u15.type, _22 = 0; 49384 if ("svg" === d1 && (r10 = true), null != o7) { 49385 for (; _22 < o7.length; _22++) if ((s3 = o7[_22]) && "setAttribute" in s3 == !!d1 && (d1 ? s3.localName === d1 : 3 === s3.nodeType)) { 49386 l16 = s3, o7[_22] = null; 49387 break; 49388 } 49389 } 49390 if (null == l16) { 49391 if (null === d1) return document.createTextNode(p3); 49392 l16 = r10 ? document.createElementNS("http://www.w3.org/2000/svg", d1) : document.createElement(d1, p3.is && p3), o7 = null, c2 = false; 49393 } 49394 if (null === d1) y22 === p3 || c2 && l16.data === p3 || (l16.data = p3); 49395 else { 49396 if (o7 = o7 && $fb96b826c0c5f37a$var$n.call(l16.childNodes), a2 = (y22 = i10.props || $fb96b826c0c5f37a$var$e).dangerouslySetInnerHTML, v3 = p3.dangerouslySetInnerHTML, !c2) { 49397 if (null != o7) for (y22 = {}, _22 = 0; _22 < l16.attributes.length; _22++) y22[l16.attributes[_22].name] = l16.attributes[_22].value; 49398 (v3 || a2) && (v3 && (a2 && v3.__html == a2.__html || v3.__html === l16.innerHTML) || (l16.innerHTML = v3 && v3.__html || "")); 49399 } 49400 if ($fb96b826c0c5f37a$var$C(l16, p3, y22, r10, c2), v3) u15.__k = []; 49401 else if (_22 = u15.props.children, $fb96b826c0c5f37a$var$w(l16, Array.isArray(_22) ? _22 : [ 49402 _22 49403 ], u15, i10, t10, r10 && "foreignObject" !== d1, o7, f6, o7 ? o7[0] : i10.__k && $fb96b826c0c5f37a$var$k(i10, 0), c2), null != o7) for (_22 = o7.length; _22--; ) null != o7[_22] && $fb96b826c0c5f37a$var$h(o7[_22]); 49404 c2 || ("value" in p3 && void 0 !== (_22 = p3.value) && (_22 !== y22.value || _22 !== l16.value || "progress" === d1 && !_22) && $fb96b826c0c5f37a$var$H(l16, "value", _22, y22.value, false), "checked" in p3 && void 0 !== (_22 = p3.checked) && _22 !== l16.checked && $fb96b826c0c5f37a$var$H(l16, "checked", _22, y22.checked, false)); 49405 } 49406 return l16; 49407 } 49408 function $fb96b826c0c5f37a$var$M(n28, u16, i11) { 49409 try { 49410 "function" == typeof n28 ? n28(u16) : n28.current = u16; 49411 } catch (n29) { 49412 $fb96b826c0c5f37a$export$41c562ebe57d11e2.__e(n29, i11); 49413 } 49414 } 49415 function $fb96b826c0c5f37a$var$N(n30, u17, i12) { 49416 var t11, r11; 49417 if ($fb96b826c0c5f37a$export$41c562ebe57d11e2.unmount && $fb96b826c0c5f37a$export$41c562ebe57d11e2.unmount(n30), (t11 = n30.ref) && (t11.current && t11.current !== n30.__e || $fb96b826c0c5f37a$var$M(t11, null, u17)), null != (t11 = n30.__c)) { 49418 if (t11.componentWillUnmount) try { 49419 t11.componentWillUnmount(); 49420 } catch (n31) { 49421 $fb96b826c0c5f37a$export$41c562ebe57d11e2.__e(n31, u17); 49422 } 49423 t11.base = t11.__P = null; 49424 } 49425 if (t11 = n30.__k) for (r11 = 0; r11 < t11.length; r11++) t11[r11] && $fb96b826c0c5f37a$var$N(t11[r11], u17, "function" != typeof n30.type); 49426 i12 || null == n30.__e || $fb96b826c0c5f37a$var$h(n30.__e), n30.__e = n30.__d = void 0; 49427 } 49428 function $fb96b826c0c5f37a$var$O(n32, l4, u18) { 49429 return this.constructor(n32, u18); 49430 } 49431 function $fb96b826c0c5f37a$export$b3890eb0ae9dca99(u19, i13, t12) { 49432 var r12, o8, f7; 49433 $fb96b826c0c5f37a$export$41c562ebe57d11e2.__ && $fb96b826c0c5f37a$export$41c562ebe57d11e2.__(u19, i13), o8 = (r12 = "function" == typeof t12) ? null : t12 && t12.__k || i13.__k, f7 = [], $fb96b826c0c5f37a$var$j(i13, u19 = (!r12 && t12 || i13).__k = $fb96b826c0c5f37a$export$c8a8987d4410bf2d($fb96b826c0c5f37a$export$ffb0004e005737fa, null, [ 49434 u19 49435 ]), o8 || $fb96b826c0c5f37a$var$e, $fb96b826c0c5f37a$var$e, void 0 !== i13.ownerSVGElement, !r12 && t12 ? [ 49436 t12 49437 ] : o8 ? null : i13.firstChild ? $fb96b826c0c5f37a$var$n.call(i13.childNodes) : null, f7, !r12 && t12 ? t12 : o8 ? o8.__e : i13.firstChild, r12), $fb96b826c0c5f37a$var$z(f7, u19); 49438 } 49439 $fb96b826c0c5f37a$var$n = $fb96b826c0c5f37a$var$c.slice, $fb96b826c0c5f37a$export$41c562ebe57d11e2 = { 49440 __e: function(n39, l22) { 49441 for (var u23, i16, t14; l22 = l22.__; ) if ((u23 = l22.__c) && !u23.__) try { 49442 if ((i16 = u23.constructor) && null != i16.getDerivedStateFromError && (u23.setState(i16.getDerivedStateFromError(n39)), t14 = u23.__d), null != u23.componentDidCatch && (u23.componentDidCatch(n39), t14 = u23.__d), t14) return u23.__E = u23; 49443 } catch (l23) { 49444 n39 = l23; 49445 } 49446 throw n39; 49447 } 49448 }, $fb96b826c0c5f37a$var$u = 0, $fb96b826c0c5f37a$export$a8257692ac88316c = function(n40) { 49449 return null != n40 && void 0 === n40.constructor; 49450 }, $fb96b826c0c5f37a$export$16fa2f45be04daa8.prototype.setState = function(n41, l24) { 49451 var u24; 49452 u24 = null != this.__s && this.__s !== this.state ? this.__s : this.__s = $fb96b826c0c5f37a$var$a({}, this.state), "function" == typeof n41 && (n41 = n41($fb96b826c0c5f37a$var$a({}, u24), this.props)), n41 && $fb96b826c0c5f37a$var$a(u24, n41), null != n41 && this.__v && (l24 && this.__h.push(l24), $fb96b826c0c5f37a$var$m(this)); 49453 }, $fb96b826c0c5f37a$export$16fa2f45be04daa8.prototype.forceUpdate = function(n42) { 49454 this.__v && (this.__e = true, n42 && this.__h.push(n42), $fb96b826c0c5f37a$var$m(this)); 49455 }, $fb96b826c0c5f37a$export$16fa2f45be04daa8.prototype.render = $fb96b826c0c5f37a$export$ffb0004e005737fa, $fb96b826c0c5f37a$var$t = [], $fb96b826c0c5f37a$var$r = "function" == typeof Promise ? Promise.prototype.then.bind(Promise.resolve()) : setTimeout, $fb96b826c0c5f37a$var$g.__r = 0, $fb96b826c0c5f37a$var$f = 0; 49456 var $bd9dd35321b03dd4$var$o = 0; 49457 function $bd9dd35321b03dd4$export$34b9dba7ce09269b(_1, e1, n2, t2, f) { 49458 var l4, s2, u2 = {}; 49459 for (s2 in e1) "ref" == s2 ? l4 = e1[s2] : u2[s2] = e1[s2]; 49460 var a2 = { 49461 type: _1, 49462 props: u2, 49463 key: n2, 49464 ref: l4, 49465 __k: null, 49466 __: null, 49467 __b: 0, 49468 __e: null, 49469 __d: void 0, 49470 __c: null, 49471 __h: null, 49472 constructor: void 0, 49473 __v: --$bd9dd35321b03dd4$var$o, 49474 __source: t2, 49475 __self: f 49476 }; 49477 if ("function" == typeof _1 && (l4 = _1.defaultProps)) for (s2 in l4) void 0 === u2[s2] && (u2[s2] = l4[s2]); 49478 return (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).vnode && (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).vnode(a2), a2; 49479 } 49480 function $f72b75cf796873c7$var$set(key, value) { 49481 try { 49482 window.localStorage[`emoji-mart.${key}`] = JSON.stringify(value); 49483 } catch (error) { 49484 } 49485 } 49486 function $f72b75cf796873c7$var$get(key) { 49487 try { 49488 const value = window.localStorage[`emoji-mart.${key}`]; 49489 if (value) return JSON.parse(value); 49490 } catch (error) { 49491 } 49492 } 49493 var $f72b75cf796873c7$export$2e2bcd8739ae039 = { 49494 set: $f72b75cf796873c7$var$set, 49495 get: $f72b75cf796873c7$var$get 49496 }; 49497 var $c84d045dcc34faf5$var$CACHE = /* @__PURE__ */ new Map(); 49498 var $c84d045dcc34faf5$var$VERSIONS = [ 49499 { 49500 v: 15, 49501 emoji: "\u{1FAE8}" 49502 }, 49503 { 49504 v: 14, 49505 emoji: "\u{1FAE0}" 49506 }, 49507 { 49508 v: 13.1, 49509 emoji: "\u{1F636}\u200D\u{1F32B}\uFE0F" 49510 }, 49511 { 49512 v: 13, 49513 emoji: "\u{1F978}" 49514 }, 49515 { 49516 v: 12.1, 49517 emoji: "\u{1F9D1}\u200D\u{1F9B0}" 49518 }, 49519 { 49520 v: 12, 49521 emoji: "\u{1F971}" 49522 }, 49523 { 49524 v: 11, 49525 emoji: "\u{1F970}" 49526 }, 49527 { 49528 v: 5, 49529 emoji: "\u{1F929}" 49530 }, 49531 { 49532 v: 4, 49533 emoji: "\u{1F471}\u200D\u2640\uFE0F" 49534 }, 49535 { 49536 v: 3, 49537 emoji: "\u{1F923}" 49538 }, 49539 { 49540 v: 2, 49541 emoji: "\u{1F44B}\u{1F3FB}" 49542 }, 49543 { 49544 v: 1, 49545 emoji: "\u{1F643}" 49546 } 49547 ]; 49548 function $c84d045dcc34faf5$var$latestVersion() { 49549 for (const { v: v3, emoji } of $c84d045dcc34faf5$var$VERSIONS) { 49550 if ($c84d045dcc34faf5$var$isSupported(emoji)) return v3; 49551 } 49552 } 49553 function $c84d045dcc34faf5$var$noCountryFlags() { 49554 if ($c84d045dcc34faf5$var$isSupported("\u{1F1E8}\u{1F1E6}")) return false; 49555 return true; 49556 } 49557 function $c84d045dcc34faf5$var$isSupported(emoji) { 49558 if ($c84d045dcc34faf5$var$CACHE.has(emoji)) return $c84d045dcc34faf5$var$CACHE.get(emoji); 49559 const supported = $c84d045dcc34faf5$var$isEmojiSupported(emoji); 49560 $c84d045dcc34faf5$var$CACHE.set(emoji, supported); 49561 return supported; 49562 } 49563 var $c84d045dcc34faf5$var$isEmojiSupported = (() => { 49564 let ctx = null; 49565 try { 49566 if (!navigator.userAgent.includes("jsdom")) ctx = document.createElement("canvas").getContext("2d", { 49567 willReadFrequently: true 49568 }); 49569 } catch { 49570 } 49571 if (!ctx) return () => false; 49572 const CANVAS_HEIGHT = 25; 49573 const CANVAS_WIDTH = 20; 49574 const textSize = Math.floor(CANVAS_HEIGHT / 2); 49575 ctx.font = textSize + "px Arial, Sans-Serif"; 49576 ctx.textBaseline = "top"; 49577 ctx.canvas.width = CANVAS_WIDTH * 2; 49578 ctx.canvas.height = CANVAS_HEIGHT; 49579 return (unicode) => { 49580 ctx.clearRect(0, 0, CANVAS_WIDTH * 2, CANVAS_HEIGHT); 49581 ctx.fillStyle = "#FF0000"; 49582 ctx.fillText(unicode, 0, 22); 49583 ctx.fillStyle = "#0000FF"; 49584 ctx.fillText(unicode, CANVAS_WIDTH, 22); 49585 const a2 = ctx.getImageData(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT).data; 49586 const count = a2.length; 49587 let i2 = 0; 49588 for (; i2 < count && !a2[i2 + 3]; i2 += 4) ; 49589 if (i2 >= count) return false; 49590 const x3 = CANVAS_WIDTH + i2 / 4 % CANVAS_WIDTH; 49591 const y3 = Math.floor(i2 / 4 / CANVAS_WIDTH); 49592 const b3 = ctx.getImageData(x3, y3, 1, 1).data; 49593 if (a2[i2] !== b3[0] || a2[i2 + 2] !== b3[2]) return false; 49594 if (ctx.measureText(unicode).width >= CANVAS_WIDTH) return false; 49595 return true; 49596 }; 49597 })(); 49598 var $c84d045dcc34faf5$export$2e2bcd8739ae039 = { 49599 latestVersion: $c84d045dcc34faf5$var$latestVersion, 49600 noCountryFlags: $c84d045dcc34faf5$var$noCountryFlags 49601 }; 49602 var $b22cfd0a55410b4f$var$DEFAULTS = [ 49603 "+1", 49604 "grinning", 49605 "kissing_heart", 49606 "heart_eyes", 49607 "laughing", 49608 "stuck_out_tongue_winking_eye", 49609 "sweat_smile", 49610 "joy", 49611 "scream", 49612 "disappointed", 49613 "unamused", 49614 "weary", 49615 "sob", 49616 "sunglasses", 49617 "heart" 49618 ]; 49619 var $b22cfd0a55410b4f$var$Index = null; 49620 function $b22cfd0a55410b4f$var$add(emoji) { 49621 $b22cfd0a55410b4f$var$Index || ($b22cfd0a55410b4f$var$Index = (0, $f72b75cf796873c7$export$2e2bcd8739ae039).get("frequently") || {}); 49622 const emojiId = emoji.id || emoji; 49623 if (!emojiId) return; 49624 $b22cfd0a55410b4f$var$Index[emojiId] || ($b22cfd0a55410b4f$var$Index[emojiId] = 0); 49625 $b22cfd0a55410b4f$var$Index[emojiId] += 1; 49626 (0, $f72b75cf796873c7$export$2e2bcd8739ae039).set("last", emojiId); 49627 (0, $f72b75cf796873c7$export$2e2bcd8739ae039).set("frequently", $b22cfd0a55410b4f$var$Index); 49628 } 49629 function $b22cfd0a55410b4f$var$get({ maxFrequentRows, perLine }) { 49630 if (!maxFrequentRows) return []; 49631 $b22cfd0a55410b4f$var$Index || ($b22cfd0a55410b4f$var$Index = (0, $f72b75cf796873c7$export$2e2bcd8739ae039).get("frequently")); 49632 let emojiIds = []; 49633 if (!$b22cfd0a55410b4f$var$Index) { 49634 $b22cfd0a55410b4f$var$Index = {}; 49635 for (let i2 in $b22cfd0a55410b4f$var$DEFAULTS.slice(0, perLine)) { 49636 const emojiId = $b22cfd0a55410b4f$var$DEFAULTS[i2]; 49637 $b22cfd0a55410b4f$var$Index[emojiId] = perLine - i2; 49638 emojiIds.push(emojiId); 49639 } 49640 return emojiIds; 49641 } 49642 const max2 = maxFrequentRows * perLine; 49643 const last = (0, $f72b75cf796873c7$export$2e2bcd8739ae039).get("last"); 49644 for (let emojiId in $b22cfd0a55410b4f$var$Index) emojiIds.push(emojiId); 49645 emojiIds.sort((a2, b3) => { 49646 const aScore = $b22cfd0a55410b4f$var$Index[b3]; 49647 const bScore = $b22cfd0a55410b4f$var$Index[a2]; 49648 if (aScore == bScore) return a2.localeCompare(b3); 49649 return aScore - bScore; 49650 }); 49651 if (emojiIds.length > max2) { 49652 const removedIds = emojiIds.slice(max2); 49653 emojiIds = emojiIds.slice(0, max2); 49654 for (let removedId of removedIds) { 49655 if (removedId == last) continue; 49656 delete $b22cfd0a55410b4f$var$Index[removedId]; 49657 } 49658 if (last && emojiIds.indexOf(last) == -1) { 49659 delete $b22cfd0a55410b4f$var$Index[emojiIds[emojiIds.length - 1]]; 49660 emojiIds.splice(-1, 1, last); 49661 } 49662 (0, $f72b75cf796873c7$export$2e2bcd8739ae039).set("frequently", $b22cfd0a55410b4f$var$Index); 49663 } 49664 return emojiIds; 49665 } 49666 var $b22cfd0a55410b4f$export$2e2bcd8739ae039 = { 49667 add: $b22cfd0a55410b4f$var$add, 49668 get: $b22cfd0a55410b4f$var$get, 49669 DEFAULTS: $b22cfd0a55410b4f$var$DEFAULTS 49670 }; 49671 var $8d50d93417ef682a$exports = {}; 49672 $8d50d93417ef682a$exports = JSON.parse('{"search":"Search","search_no_results_1":"Oh no!","search_no_results_2":"That emoji couldn\u2019t be found","pick":"Pick an emoji\u2026","add_custom":"Add custom emoji","categories":{"activity":"Activity","custom":"Custom","flags":"Flags","foods":"Food & Drink","frequent":"Frequently used","nature":"Animals & Nature","objects":"Objects","people":"Smileys & People","places":"Travel & Places","search":"Search Results","symbols":"Symbols"},"skins":{"1":"Default","2":"Light","3":"Medium-Light","4":"Medium","5":"Medium-Dark","6":"Dark","choose":"Choose default skin tone"}}'); 49673 var $b247ea80b67298d5$export$2e2bcd8739ae039 = { 49674 autoFocus: { 49675 value: false 49676 }, 49677 dynamicWidth: { 49678 value: false 49679 }, 49680 emojiButtonColors: { 49681 value: null 49682 }, 49683 emojiButtonRadius: { 49684 value: "100%" 49685 }, 49686 emojiButtonSize: { 49687 value: 36 49688 }, 49689 emojiSize: { 49690 value: 24 49691 }, 49692 emojiVersion: { 49693 value: 17, 49694 choices: [ 49695 1, 49696 2, 49697 3, 49698 4, 49699 5, 49700 11, 49701 12, 49702 12.1, 49703 13, 49704 13.1, 49705 14, 49706 15, 49707 16, 49708 17 49709 ] 49710 }, 49711 exceptEmojis: { 49712 value: [] 49713 }, 49714 icons: { 49715 value: "auto", 49716 choices: [ 49717 "auto", 49718 "outline", 49719 "solid" 49720 ] 49721 }, 49722 locale: { 49723 value: "en", 49724 choices: [ 49725 "en", 49726 "ar", 49727 "be", 49728 "cs", 49729 "de", 49730 "es", 49731 "fa", 49732 "fi", 49733 "fr", 49734 "hi", 49735 "it", 49736 "ja", 49737 "ko", 49738 "nl", 49739 "pl", 49740 "pt", 49741 "ru", 49742 "sa", 49743 "tr", 49744 "uk", 49745 "vi", 49746 "zh" 49747 ] 49748 }, 49749 maxFrequentRows: { 49750 value: 4 49751 }, 49752 navPosition: { 49753 value: "top", 49754 choices: [ 49755 "top", 49756 "bottom", 49757 "none" 49758 ] 49759 }, 49760 noCountryFlags: { 49761 value: false 49762 }, 49763 noResultsEmoji: { 49764 value: null 49765 }, 49766 perLine: { 49767 value: 9 49768 }, 49769 previewEmoji: { 49770 value: null 49771 }, 49772 previewPosition: { 49773 value: "bottom", 49774 choices: [ 49775 "top", 49776 "bottom", 49777 "none" 49778 ] 49779 }, 49780 searchPosition: { 49781 value: "sticky", 49782 choices: [ 49783 "sticky", 49784 "static", 49785 "none" 49786 ] 49787 }, 49788 set: { 49789 value: "native", 49790 choices: [ 49791 "native", 49792 "apple", 49793 "facebook", 49794 "google", 49795 "twitter" 49796 ] 49797 }, 49798 skin: { 49799 value: 1, 49800 choices: [ 49801 1, 49802 2, 49803 3, 49804 4, 49805 5, 49806 6 49807 ] 49808 }, 49809 skinTonePosition: { 49810 value: "preview", 49811 choices: [ 49812 "preview", 49813 "search", 49814 "none" 49815 ] 49816 }, 49817 theme: { 49818 value: "auto", 49819 choices: [ 49820 "auto", 49821 "light", 49822 "dark" 49823 ] 49824 }, 49825 // Data 49826 categories: null, 49827 categoryIcons: null, 49828 custom: null, 49829 data: null, 49830 i18n: null, 49831 // Callbacks 49832 getImageURL: null, 49833 getSpritesheetURL: null, 49834 onAddCustomEmoji: null, 49835 onClickOutside: null, 49836 onEmojiSelect: null, 49837 // Deprecated 49838 stickySearch: { 49839 deprecated: true, 49840 value: true 49841 } 49842 }; 49843 var $7adb23b0109cc36a$export$dbe3113d60765c1a = null; 49844 var $7adb23b0109cc36a$export$2d0294657ab35f1b = null; 49845 var $7adb23b0109cc36a$var$fetchCache = {}; 49846 async function $7adb23b0109cc36a$var$fetchJSON(src) { 49847 if ($7adb23b0109cc36a$var$fetchCache[src]) return $7adb23b0109cc36a$var$fetchCache[src]; 49848 const response = await fetch(src); 49849 const json = await response.json(); 49850 $7adb23b0109cc36a$var$fetchCache[src] = json; 49851 return json; 49852 } 49853 var $7adb23b0109cc36a$var$promise = null; 49854 var $7adb23b0109cc36a$var$initCallback = null; 49855 var $7adb23b0109cc36a$var$initialized = false; 49856 function $7adb23b0109cc36a$export$2cd8252107eb640b(options, { caller } = {}) { 49857 $7adb23b0109cc36a$var$promise || ($7adb23b0109cc36a$var$promise = new Promise((resolve) => { 49858 $7adb23b0109cc36a$var$initCallback = resolve; 49859 })); 49860 if (options) $7adb23b0109cc36a$var$_init(options); 49861 else if (caller && !$7adb23b0109cc36a$var$initialized) console.warn(`\`${caller}\` requires data to be initialized first. Promise will be pending until \`init\` is called.`); 49862 return $7adb23b0109cc36a$var$promise; 49863 } 49864 async function $7adb23b0109cc36a$var$_init(props) { 49865 $7adb23b0109cc36a$var$initialized = true; 49866 let { emojiVersion, set, locale } = props; 49867 emojiVersion || (emojiVersion = (0, $b247ea80b67298d5$export$2e2bcd8739ae039).emojiVersion.value); 49868 set || (set = (0, $b247ea80b67298d5$export$2e2bcd8739ae039).set.value); 49869 locale || (locale = (0, $b247ea80b67298d5$export$2e2bcd8739ae039).locale.value); 49870 if (!$7adb23b0109cc36a$export$2d0294657ab35f1b) { 49871 $7adb23b0109cc36a$export$2d0294657ab35f1b = (typeof props.data === "function" ? await props.data() : props.data) || await $7adb23b0109cc36a$var$fetchJSON(`https://cdn.jsdelivr.net/npm/@emoji-mart/data@latest/sets/${emojiVersion}/${set}.json`); 49872 $7adb23b0109cc36a$export$2d0294657ab35f1b.emoticons = {}; 49873 $7adb23b0109cc36a$export$2d0294657ab35f1b.natives = {}; 49874 $7adb23b0109cc36a$export$2d0294657ab35f1b.categories.unshift({ 49875 id: "frequent", 49876 emojis: [] 49877 }); 49878 for (const alias in $7adb23b0109cc36a$export$2d0294657ab35f1b.aliases) { 49879 const emojiId = $7adb23b0109cc36a$export$2d0294657ab35f1b.aliases[alias]; 49880 const emoji = $7adb23b0109cc36a$export$2d0294657ab35f1b.emojis[emojiId]; 49881 if (!emoji) continue; 49882 emoji.aliases || (emoji.aliases = []); 49883 emoji.aliases.push(alias); 49884 } 49885 $7adb23b0109cc36a$export$2d0294657ab35f1b.originalCategories = $7adb23b0109cc36a$export$2d0294657ab35f1b.categories; 49886 } else $7adb23b0109cc36a$export$2d0294657ab35f1b.categories = $7adb23b0109cc36a$export$2d0294657ab35f1b.categories.filter((c2) => { 49887 const isCustom = !!c2.name; 49888 if (!isCustom) return true; 49889 return false; 49890 }); 49891 $7adb23b0109cc36a$export$dbe3113d60765c1a = (typeof props.i18n === "function" ? await props.i18n() : props.i18n) || (locale == "en" ? (0, /* @__PURE__ */ $parcel$interopDefault($8d50d93417ef682a$exports)) : await $7adb23b0109cc36a$var$fetchJSON(`https://cdn.jsdelivr.net/npm/@emoji-mart/data@latest/i18n/${locale}.json`)); 49892 if (props.custom) for (let i2 in props.custom) { 49893 i2 = parseInt(i2); 49894 const category = props.custom[i2]; 49895 const prevCategory = props.custom[i2 - 1]; 49896 if (!category.emojis || !category.emojis.length) continue; 49897 category.id || (category.id = `custom_${i2 + 1}`); 49898 category.name || (category.name = $7adb23b0109cc36a$export$dbe3113d60765c1a.categories.custom); 49899 if (prevCategory && !category.icon) category.target = prevCategory.target || prevCategory; 49900 $7adb23b0109cc36a$export$2d0294657ab35f1b.categories.push(category); 49901 for (const emoji of category.emojis) $7adb23b0109cc36a$export$2d0294657ab35f1b.emojis[emoji.id] = emoji; 49902 } 49903 if (props.categories) $7adb23b0109cc36a$export$2d0294657ab35f1b.categories = $7adb23b0109cc36a$export$2d0294657ab35f1b.originalCategories.filter((c2) => { 49904 return props.categories.indexOf(c2.id) != -1; 49905 }).sort((c1, c2) => { 49906 const i1 = props.categories.indexOf(c1.id); 49907 const i2 = props.categories.indexOf(c2.id); 49908 return i1 - i2; 49909 }); 49910 let latestVersionSupport = null; 49911 let noCountryFlags = null; 49912 if (set == "native") { 49913 latestVersionSupport = emojiVersion; 49914 noCountryFlags = props.noCountryFlags || (0, $c84d045dcc34faf5$export$2e2bcd8739ae039).noCountryFlags(); 49915 } 49916 let categoryIndex = $7adb23b0109cc36a$export$2d0294657ab35f1b.categories.length; 49917 let resetSearchIndex = false; 49918 while (categoryIndex--) { 49919 const category = $7adb23b0109cc36a$export$2d0294657ab35f1b.categories[categoryIndex]; 49920 if (category.id == "frequent") { 49921 let { maxFrequentRows, perLine } = props; 49922 maxFrequentRows = maxFrequentRows >= 0 ? maxFrequentRows : (0, $b247ea80b67298d5$export$2e2bcd8739ae039).maxFrequentRows.value; 49923 perLine || (perLine = (0, $b247ea80b67298d5$export$2e2bcd8739ae039).perLine.value); 49924 category.emojis = (0, $b22cfd0a55410b4f$export$2e2bcd8739ae039).get({ 49925 maxFrequentRows, 49926 perLine 49927 }); 49928 } 49929 if (!category.emojis || !category.emojis.length) { 49930 $7adb23b0109cc36a$export$2d0294657ab35f1b.categories.splice(categoryIndex, 1); 49931 continue; 49932 } 49933 const { categoryIcons } = props; 49934 if (categoryIcons) { 49935 const icon = categoryIcons[category.id]; 49936 if (icon && !category.icon) category.icon = icon; 49937 } 49938 let emojiIndex = category.emojis.length; 49939 while (emojiIndex--) { 49940 const emojiId = category.emojis[emojiIndex]; 49941 const emoji = emojiId.id ? emojiId : $7adb23b0109cc36a$export$2d0294657ab35f1b.emojis[emojiId]; 49942 const ignore = () => { 49943 category.emojis.splice(emojiIndex, 1); 49944 }; 49945 if (!emoji || props.exceptEmojis && props.exceptEmojis.includes(emoji.id)) { 49946 ignore(); 49947 continue; 49948 } 49949 if (latestVersionSupport && emoji.version > latestVersionSupport) { 49950 ignore(); 49951 continue; 49952 } 49953 if (noCountryFlags && category.id == "flags") { 49954 if (!(0, $e6eae5155b87f591$export$bcb25aa587e9cb13).includes(emoji.id)) { 49955 ignore(); 49956 continue; 49957 } 49958 } 49959 if (!emoji.search) { 49960 resetSearchIndex = true; 49961 emoji.search = "," + [ 49962 [ 49963 emoji.id, 49964 false 49965 ], 49966 [ 49967 emoji.name, 49968 true 49969 ], 49970 [ 49971 emoji.keywords, 49972 false 49973 ], 49974 [ 49975 emoji.emoticons, 49976 false 49977 ] 49978 ].map(([strings, split]) => { 49979 if (!strings) return; 49980 return (Array.isArray(strings) ? strings : [ 49981 strings 49982 ]).map((string) => { 49983 return (split ? string.split(/[-|_|\s]+/) : [ 49984 string 49985 ]).map((s2) => s2.toLowerCase()); 49986 }).flat(); 49987 }).flat().filter((a2) => a2 && a2.trim()).join(","); 49988 if (emoji.emoticons) for (const emoticon of emoji.emoticons) { 49989 if ($7adb23b0109cc36a$export$2d0294657ab35f1b.emoticons[emoticon]) continue; 49990 $7adb23b0109cc36a$export$2d0294657ab35f1b.emoticons[emoticon] = emoji.id; 49991 } 49992 let skinIndex = 0; 49993 for (const skin of emoji.skins) { 49994 if (!skin) continue; 49995 skinIndex++; 49996 const { native } = skin; 49997 if (native) { 49998 $7adb23b0109cc36a$export$2d0294657ab35f1b.natives[native] = emoji.id; 49999 emoji.search += `,${native}`; 50000 } 50001 const skinShortcodes = skinIndex == 1 ? "" : `:skin-tone-${skinIndex}:`; 50002 skin.shortcodes = `:${emoji.id}:${skinShortcodes}`; 50003 } 50004 } 50005 } 50006 } 50007 if (resetSearchIndex) (0, $c4d155af13ad4d4b$export$2e2bcd8739ae039).reset(); 50008 $7adb23b0109cc36a$var$initCallback(); 50009 } 50010 function $7adb23b0109cc36a$export$75fe5f91d452f94b(props, defaultProps2, element) { 50011 props || (props = {}); 50012 const _props = {}; 50013 for (let k2 in defaultProps2) _props[k2] = $7adb23b0109cc36a$export$88c9ddb45cea7241(k2, props, defaultProps2, element); 50014 return _props; 50015 } 50016 function $7adb23b0109cc36a$export$88c9ddb45cea7241(propName, props, defaultProps2, element) { 50017 const defaults = defaultProps2[propName]; 50018 let value = element && element.getAttribute(propName) || (props[propName] != null && props[propName] != void 0 ? props[propName] : null); 50019 if (!defaults) return value; 50020 if (value != null && defaults.value && typeof defaults.value != typeof value) { 50021 if (typeof defaults.value == "boolean") value = value == "false" ? false : true; 50022 else value = defaults.value.constructor(value); 50023 } 50024 if (defaults.transform && value) value = defaults.transform(value); 50025 if (value == null || defaults.choices && defaults.choices.indexOf(value) == -1) value = defaults.value; 50026 return value; 50027 } 50028 var $c4d155af13ad4d4b$var$SHORTCODES_REGEX = /^(?:\:([^\:]+)\:)(?:\:skin-tone-(\d)\:)?$/; 50029 var $c4d155af13ad4d4b$var$Pool = null; 50030 function $c4d155af13ad4d4b$var$get(emojiId) { 50031 if (emojiId.id) return emojiId; 50032 return (0, $7adb23b0109cc36a$export$2d0294657ab35f1b).emojis[emojiId] || (0, $7adb23b0109cc36a$export$2d0294657ab35f1b).emojis[(0, $7adb23b0109cc36a$export$2d0294657ab35f1b).aliases[emojiId]] || (0, $7adb23b0109cc36a$export$2d0294657ab35f1b).emojis[(0, $7adb23b0109cc36a$export$2d0294657ab35f1b).natives[emojiId]]; 50033 } 50034 function $c4d155af13ad4d4b$var$reset() { 50035 $c4d155af13ad4d4b$var$Pool = null; 50036 } 50037 async function $c4d155af13ad4d4b$var$search(value, { maxResults, caller } = {}) { 50038 if (!value || !value.trim().length) return null; 50039 maxResults || (maxResults = 90); 50040 await (0, $7adb23b0109cc36a$export$2cd8252107eb640b)(null, { 50041 caller: caller || "SearchIndex.search" 50042 }); 50043 const values = value.toLowerCase().replace(/(\w)-/, "$1 ").split(/[\s|,]+/).filter((word, i2, words) => { 50044 return word.trim() && words.indexOf(word) == i2; 50045 }); 50046 if (!values.length) return; 50047 let pool = $c4d155af13ad4d4b$var$Pool || ($c4d155af13ad4d4b$var$Pool = Object.values((0, $7adb23b0109cc36a$export$2d0294657ab35f1b).emojis)); 50048 let results, scores; 50049 for (const value1 of values) { 50050 if (!pool.length) break; 50051 results = []; 50052 scores = {}; 50053 for (const emoji of pool) { 50054 if (!emoji.search) continue; 50055 const score = emoji.search.indexOf(`,${value1}`); 50056 if (score == -1) continue; 50057 results.push(emoji); 50058 scores[emoji.id] || (scores[emoji.id] = 0); 50059 scores[emoji.id] += emoji.id == value1 ? 0 : score + 1; 50060 } 50061 pool = results; 50062 } 50063 if (results.length < 2) return results; 50064 results.sort((a2, b3) => { 50065 const aScore = scores[a2.id]; 50066 const bScore = scores[b3.id]; 50067 if (aScore == bScore) return a2.id.localeCompare(b3.id); 50068 return aScore - bScore; 50069 }); 50070 if (results.length > maxResults) results = results.slice(0, maxResults); 50071 return results; 50072 } 50073 var $c4d155af13ad4d4b$export$2e2bcd8739ae039 = { 50074 search: $c4d155af13ad4d4b$var$search, 50075 get: $c4d155af13ad4d4b$var$get, 50076 reset: $c4d155af13ad4d4b$var$reset, 50077 SHORTCODES_REGEX: $c4d155af13ad4d4b$var$SHORTCODES_REGEX 50078 }; 50079 var $e6eae5155b87f591$export$bcb25aa587e9cb13 = [ 50080 "checkered_flag", 50081 "crossed_flags", 50082 "pirate_flag", 50083 "rainbow-flag", 50084 "transgender_flag", 50085 "triangular_flag_on_post", 50086 "waving_black_flag", 50087 "waving_white_flag" 50088 ]; 50089 function $693b183b0a78708f$export$9cb4719e2e525b7a(a2, b3) { 50090 return Array.isArray(a2) && Array.isArray(b3) && a2.length === b3.length && a2.every((val, index) => val == b3[index]); 50091 } 50092 async function $693b183b0a78708f$export$e772c8ff12451969(frames = 1) { 50093 for (let _3 in [ 50094 ...Array(frames).keys() 50095 ]) await new Promise(requestAnimationFrame); 50096 } 50097 function $693b183b0a78708f$export$d10ac59fbe52a745(emoji, { skinIndex = 0 } = {}) { 50098 const skin = emoji.skins[skinIndex] || (() => { 50099 skinIndex = 0; 50100 return emoji.skins[skinIndex]; 50101 })(); 50102 const emojiData = { 50103 id: emoji.id, 50104 name: emoji.name, 50105 native: skin.native, 50106 unified: skin.unified, 50107 keywords: emoji.keywords, 50108 shortcodes: skin.shortcodes || emoji.shortcodes 50109 }; 50110 if (emoji.skins.length > 1) emojiData.skin = skinIndex + 1; 50111 if (skin.src) emojiData.src = skin.src; 50112 if (emoji.aliases && emoji.aliases.length) emojiData.aliases = emoji.aliases; 50113 if (emoji.emoticons && emoji.emoticons.length) emojiData.emoticons = emoji.emoticons; 50114 return emojiData; 50115 } 50116 var $fcccfb36ed0cde68$var$categories = { 50117 activity: { 50118 outline: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50119 xmlns: "http://www.w3.org/2000/svg", 50120 viewBox: "0 0 24 24", 50121 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50122 d: "M12 0C5.373 0 0 5.372 0 12c0 6.627 5.373 12 12 12 6.628 0 12-5.373 12-12 0-6.628-5.372-12-12-12m9.949 11H17.05c.224-2.527 1.232-4.773 1.968-6.113A9.966 9.966 0 0 1 21.949 11M13 11V2.051a9.945 9.945 0 0 1 4.432 1.564c-.858 1.491-2.156 4.22-2.392 7.385H13zm-2 0H8.961c-.238-3.165-1.536-5.894-2.393-7.385A9.95 9.95 0 0 1 11 2.051V11zm0 2v8.949a9.937 9.937 0 0 1-4.432-1.564c.857-1.492 2.155-4.221 2.393-7.385H11zm4.04 0c.236 3.164 1.534 5.893 2.392 7.385A9.92 9.92 0 0 1 13 21.949V13h2.04zM4.982 4.887C5.718 6.227 6.726 8.473 6.951 11h-4.9a9.977 9.977 0 0 1 2.931-6.113M2.051 13h4.9c-.226 2.527-1.233 4.771-1.969 6.113A9.972 9.972 0 0 1 2.051 13m16.967 6.113c-.735-1.342-1.744-3.586-1.968-6.113h4.899a9.961 9.961 0 0 1-2.931 6.113" 50123 }) 50124 }), 50125 solid: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50126 xmlns: "http://www.w3.org/2000/svg", 50127 viewBox: "0 0 512 512", 50128 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50129 d: "M16.17 337.5c0 44.98 7.565 83.54 13.98 107.9C35.22 464.3 50.46 496 174.9 496c9.566 0 19.59-.4707 29.84-1.271L17.33 307.3C16.53 317.6 16.17 327.7 16.17 337.5zM495.8 174.5c0-44.98-7.565-83.53-13.98-107.9c-4.688-17.54-18.34-31.23-36.04-35.95C435.5 27.91 392.9 16 337 16c-9.564 0-19.59 .4707-29.84 1.271l187.5 187.5C495.5 194.4 495.8 184.3 495.8 174.5zM26.77 248.8l236.3 236.3c142-36.1 203.9-150.4 222.2-221.1L248.9 26.87C106.9 62.96 45.07 177.2 26.77 248.8zM256 335.1c0 9.141-7.474 16-16 16c-4.094 0-8.188-1.564-11.31-4.689L164.7 283.3C161.6 280.2 160 276.1 160 271.1c0-8.529 6.865-16 16-16c4.095 0 8.189 1.562 11.31 4.688l64.01 64C254.4 327.8 256 331.9 256 335.1zM304 287.1c0 9.141-7.474 16-16 16c-4.094 0-8.188-1.564-11.31-4.689L212.7 235.3C209.6 232.2 208 228.1 208 223.1c0-9.141 7.473-16 16-16c4.094 0 8.188 1.562 11.31 4.688l64.01 64.01C302.5 279.8 304 283.9 304 287.1zM256 175.1c0-9.141 7.473-16 16-16c4.094 0 8.188 1.562 11.31 4.688l64.01 64.01c3.125 3.125 4.688 7.219 4.688 11.31c0 9.133-7.468 16-16 16c-4.094 0-8.189-1.562-11.31-4.688l-64.01-64.01C257.6 184.2 256 180.1 256 175.1z" 50130 }) 50131 }) 50132 }, 50133 custom: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50134 xmlns: "http://www.w3.org/2000/svg", 50135 viewBox: "0 0 448 512", 50136 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50137 d: "M417.1 368c-5.937 10.27-16.69 16-27.75 16c-5.422 0-10.92-1.375-15.97-4.281L256 311.4V448c0 17.67-14.33 32-31.1 32S192 465.7 192 448V311.4l-118.3 68.29C68.67 382.6 63.17 384 57.75 384c-11.06 0-21.81-5.734-27.75-16c-8.828-15.31-3.594-34.88 11.72-43.72L159.1 256L41.72 187.7C26.41 178.9 21.17 159.3 29.1 144C36.63 132.5 49.26 126.7 61.65 128.2C65.78 128.7 69.88 130.1 73.72 132.3L192 200.6V64c0-17.67 14.33-32 32-32S256 46.33 256 64v136.6l118.3-68.29c3.838-2.213 7.939-3.539 12.07-4.051C398.7 126.7 411.4 132.5 417.1 144c8.828 15.31 3.594 34.88-11.72 43.72L288 256l118.3 68.28C421.6 333.1 426.8 352.7 417.1 368z" 50138 }) 50139 }), 50140 flags: { 50141 outline: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50142 xmlns: "http://www.w3.org/2000/svg", 50143 viewBox: "0 0 24 24", 50144 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50145 d: "M0 0l6.084 24H8L1.916 0zM21 5h-4l-1-4H4l3 12h3l1 4h13L21 5zM6.563 3h7.875l2 8H8.563l-2-8zm8.832 10l-2.856 1.904L12.063 13h3.332zM19 13l-1.5-6h1.938l2 8H16l3-2z" 50146 }) 50147 }), 50148 solid: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50149 xmlns: "http://www.w3.org/2000/svg", 50150 viewBox: "0 0 512 512", 50151 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50152 d: "M64 496C64 504.8 56.75 512 48 512h-32C7.25 512 0 504.8 0 496V32c0-17.75 14.25-32 32-32s32 14.25 32 32V496zM476.3 0c-6.365 0-13.01 1.35-19.34 4.233c-45.69 20.86-79.56 27.94-107.8 27.94c-59.96 0-94.81-31.86-163.9-31.87C160.9 .3055 131.6 4.867 96 15.75v350.5c32-9.984 59.87-14.1 84.85-14.1c73.63 0 124.9 31.78 198.6 31.78c31.91 0 68.02-5.971 111.1-23.09C504.1 355.9 512 344.4 512 332.1V30.73C512 11.1 495.3 0 476.3 0z" 50153 }) 50154 }) 50155 }, 50156 foods: { 50157 outline: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50158 xmlns: "http://www.w3.org/2000/svg", 50159 viewBox: "0 0 24 24", 50160 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50161 d: "M17 4.978c-1.838 0-2.876.396-3.68.934.513-1.172 1.768-2.934 4.68-2.934a1 1 0 0 0 0-2c-2.921 0-4.629 1.365-5.547 2.512-.064.078-.119.162-.18.244C11.73 1.838 10.798.023 9.207.023 8.579.022 7.85.306 7 .978 5.027 2.54 5.329 3.902 6.492 4.999 3.609 5.222 0 7.352 0 12.969c0 4.582 4.961 11.009 9 11.009 1.975 0 2.371-.486 3-1 .629.514 1.025 1 3 1 4.039 0 9-6.418 9-11 0-5.953-4.055-8-7-8M8.242 2.546c.641-.508.943-.523.965-.523.426.169.975 1.405 1.357 3.055-1.527-.629-2.741-1.352-2.98-1.846.059-.112.241-.356.658-.686M15 21.978c-1.08 0-1.21-.109-1.559-.402l-.176-.146c-.367-.302-.816-.452-1.266-.452s-.898.15-1.266.452l-.176.146c-.347.292-.477.402-1.557.402-2.813 0-7-5.389-7-9.009 0-5.823 4.488-5.991 5-5.991 1.939 0 2.484.471 3.387 1.251l.323.276a1.995 1.995 0 0 0 2.58 0l.323-.276c.902-.78 1.447-1.251 3.387-1.251.512 0 5 .168 5 6 0 3.617-4.187 9-7 9" 50162 }) 50163 }), 50164 solid: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50165 xmlns: "http://www.w3.org/2000/svg", 50166 viewBox: "0 0 512 512", 50167 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50168 d: "M481.9 270.1C490.9 279.1 496 291.3 496 304C496 316.7 490.9 328.9 481.9 337.9C472.9 346.9 460.7 352 448 352H64C51.27 352 39.06 346.9 30.06 337.9C21.06 328.9 16 316.7 16 304C16 291.3 21.06 279.1 30.06 270.1C39.06 261.1 51.27 256 64 256H448C460.7 256 472.9 261.1 481.9 270.1zM475.3 388.7C478.3 391.7 480 395.8 480 400V416C480 432.1 473.3 449.3 461.3 461.3C449.3 473.3 432.1 480 416 480H96C79.03 480 62.75 473.3 50.75 461.3C38.74 449.3 32 432.1 32 416V400C32 395.8 33.69 391.7 36.69 388.7C39.69 385.7 43.76 384 48 384H464C468.2 384 472.3 385.7 475.3 388.7zM50.39 220.8C45.93 218.6 42.03 215.5 38.97 211.6C35.91 207.7 33.79 203.2 32.75 198.4C31.71 193.5 31.8 188.5 32.99 183.7C54.98 97.02 146.5 32 256 32C365.5 32 457 97.02 479 183.7C480.2 188.5 480.3 193.5 479.2 198.4C478.2 203.2 476.1 207.7 473 211.6C469.1 215.5 466.1 218.6 461.6 220.8C457.2 222.9 452.3 224 447.3 224H64.67C59.73 224 54.84 222.9 50.39 220.8zM372.7 116.7C369.7 119.7 368 123.8 368 128C368 131.2 368.9 134.3 370.7 136.9C372.5 139.5 374.1 141.6 377.9 142.8C380.8 143.1 384 144.3 387.1 143.7C390.2 143.1 393.1 141.6 395.3 139.3C397.6 137.1 399.1 134.2 399.7 131.1C400.3 128 399.1 124.8 398.8 121.9C397.6 118.1 395.5 116.5 392.9 114.7C390.3 112.9 387.2 111.1 384 111.1C379.8 111.1 375.7 113.7 372.7 116.7V116.7zM244.7 84.69C241.7 87.69 240 91.76 240 96C240 99.16 240.9 102.3 242.7 104.9C244.5 107.5 246.1 109.6 249.9 110.8C252.8 111.1 256 112.3 259.1 111.7C262.2 111.1 265.1 109.6 267.3 107.3C269.6 105.1 271.1 102.2 271.7 99.12C272.3 96.02 271.1 92.8 270.8 89.88C269.6 86.95 267.5 84.45 264.9 82.7C262.3 80.94 259.2 79.1 256 79.1C251.8 79.1 247.7 81.69 244.7 84.69V84.69zM116.7 116.7C113.7 119.7 112 123.8 112 128C112 131.2 112.9 134.3 114.7 136.9C116.5 139.5 118.1 141.6 121.9 142.8C124.8 143.1 128 144.3 131.1 143.7C134.2 143.1 137.1 141.6 139.3 139.3C141.6 137.1 143.1 134.2 143.7 131.1C144.3 128 143.1 124.8 142.8 121.9C141.6 118.1 139.5 116.5 136.9 114.7C134.3 112.9 131.2 111.1 128 111.1C123.8 111.1 119.7 113.7 116.7 116.7L116.7 116.7z" 50169 }) 50170 }) 50171 }, 50172 frequent: { 50173 outline: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50174 xmlns: "http://www.w3.org/2000/svg", 50175 viewBox: "0 0 24 24", 50176 children: [ 50177 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50178 d: "M13 4h-2l-.001 7H9v2h2v2h2v-2h4v-2h-4z" 50179 }), 50180 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50181 d: "M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0m0 22C6.486 22 2 17.514 2 12S6.486 2 12 2s10 4.486 10 10-4.486 10-10 10" 50182 }) 50183 ] 50184 }), 50185 solid: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50186 xmlns: "http://www.w3.org/2000/svg", 50187 viewBox: "0 0 512 512", 50188 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50189 d: "M256 512C114.6 512 0 397.4 0 256C0 114.6 114.6 0 256 0C397.4 0 512 114.6 512 256C512 397.4 397.4 512 256 512zM232 256C232 264 236 271.5 242.7 275.1L338.7 339.1C349.7 347.3 364.6 344.3 371.1 333.3C379.3 322.3 376.3 307.4 365.3 300L280 243.2V120C280 106.7 269.3 96 255.1 96C242.7 96 231.1 106.7 231.1 120L232 256z" 50190 }) 50191 }) 50192 }, 50193 nature: { 50194 outline: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50195 xmlns: "http://www.w3.org/2000/svg", 50196 viewBox: "0 0 24 24", 50197 children: [ 50198 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50199 d: "M15.5 8a1.5 1.5 0 1 0 .001 3.001A1.5 1.5 0 0 0 15.5 8M8.5 8a1.5 1.5 0 1 0 .001 3.001A1.5 1.5 0 0 0 8.5 8" 50200 }), 50201 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50202 d: "M18.933 0h-.027c-.97 0-2.138.787-3.018 1.497-1.274-.374-2.612-.51-3.887-.51-1.285 0-2.616.133-3.874.517C7.245.79 6.069 0 5.093 0h-.027C3.352 0 .07 2.67.002 7.026c-.039 2.479.276 4.238 1.04 5.013.254.258.882.677 1.295.882.191 3.177.922 5.238 2.536 6.38.897.637 2.187.949 3.2 1.102C8.04 20.6 8 20.795 8 21c0 1.773 2.35 3 4 3 1.648 0 4-1.227 4-3 0-.201-.038-.393-.072-.586 2.573-.385 5.435-1.877 5.925-7.587.396-.22.887-.568 1.104-.788.763-.774 1.079-2.534 1.04-5.013C23.929 2.67 20.646 0 18.933 0M3.223 9.135c-.237.281-.837 1.155-.884 1.238-.15-.41-.368-1.349-.337-3.291.051-3.281 2.478-4.972 3.091-5.031.256.015.731.27 1.265.646-1.11 1.171-2.275 2.915-2.352 5.125-.133.546-.398.858-.783 1.313M12 22c-.901 0-1.954-.693-2-1 0-.654.475-1.236 1-1.602V20a1 1 0 1 0 2 0v-.602c.524.365 1 .947 1 1.602-.046.307-1.099 1-2 1m3-3.48v.02a4.752 4.752 0 0 0-1.262-1.02c1.092-.516 2.239-1.334 2.239-2.217 0-1.842-1.781-2.195-3.977-2.195-2.196 0-3.978.354-3.978 2.195 0 .883 1.148 1.701 2.238 2.217A4.8 4.8 0 0 0 9 18.539v-.025c-1-.076-2.182-.281-2.973-.842-1.301-.92-1.838-3.045-1.853-6.478l.023-.041c.496-.826 1.49-1.45 1.804-3.102 0-2.047 1.357-3.631 2.362-4.522C9.37 3.178 10.555 3 11.948 3c1.447 0 2.685.192 3.733.57 1 .9 2.316 2.465 2.316 4.48.313 1.651 1.307 2.275 1.803 3.102.035.058.068.117.102.178-.059 5.967-1.949 7.01-4.902 7.19m6.628-8.202c-.037-.065-.074-.13-.113-.195a7.587 7.587 0 0 0-.739-.987c-.385-.455-.648-.768-.782-1.313-.076-2.209-1.241-3.954-2.353-5.124.531-.376 1.004-.63 1.261-.647.636.071 3.044 1.764 3.096 5.031.027 1.81-.347 3.218-.37 3.235" 50203 }) 50204 ] 50205 }), 50206 solid: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50207 xmlns: "http://www.w3.org/2000/svg", 50208 viewBox: "0 0 576 512", 50209 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50210 d: "M332.7 19.85C334.6 8.395 344.5 0 356.1 0C363.6 0 370.6 3.52 375.1 9.502L392 32H444.1C456.8 32 469.1 37.06 478.1 46.06L496 64H552C565.3 64 576 74.75 576 88V112C576 156.2 540.2 192 496 192H426.7L421.6 222.5L309.6 158.5L332.7 19.85zM448 64C439.2 64 432 71.16 432 80C432 88.84 439.2 96 448 96C456.8 96 464 88.84 464 80C464 71.16 456.8 64 448 64zM416 256.1V480C416 497.7 401.7 512 384 512H352C334.3 512 320 497.7 320 480V364.8C295.1 377.1 268.8 384 240 384C211.2 384 184 377.1 160 364.8V480C160 497.7 145.7 512 128 512H96C78.33 512 64 497.7 64 480V249.8C35.23 238.9 12.64 214.5 4.836 183.3L.9558 167.8C-3.331 150.6 7.094 133.2 24.24 128.1C41.38 124.7 58.76 135.1 63.05 152.2L66.93 167.8C70.49 182 83.29 191.1 97.97 191.1H303.8L416 256.1z" 50211 }) 50212 }) 50213 }, 50214 objects: { 50215 outline: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50216 xmlns: "http://www.w3.org/2000/svg", 50217 viewBox: "0 0 24 24", 50218 children: [ 50219 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50220 d: "M12 0a9 9 0 0 0-5 16.482V21s2.035 3 5 3 5-3 5-3v-4.518A9 9 0 0 0 12 0zm0 2c3.86 0 7 3.141 7 7s-3.14 7-7 7-7-3.141-7-7 3.14-7 7-7zM9 17.477c.94.332 1.946.523 3 .523s2.06-.19 3-.523v.834c-.91.436-1.925.689-3 .689a6.924 6.924 0 0 1-3-.69v-.833zm.236 3.07A8.854 8.854 0 0 0 12 21c.965 0 1.888-.167 2.758-.451C14.155 21.173 13.153 22 12 22c-1.102 0-2.117-.789-2.764-1.453z" 50221 }), 50222 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50223 d: "M14.745 12.449h-.004c-.852-.024-1.188-.858-1.577-1.824-.421-1.061-.703-1.561-1.182-1.566h-.009c-.481 0-.783.497-1.235 1.537-.436.982-.801 1.811-1.636 1.791l-.276-.043c-.565-.171-.853-.691-1.284-1.794-.125-.313-.202-.632-.27-.913-.051-.213-.127-.53-.195-.634C7.067 9.004 7.039 9 6.99 9A1 1 0 0 1 7 7h.01c1.662.017 2.015 1.373 2.198 2.134.486-.981 1.304-2.058 2.797-2.075 1.531.018 2.28 1.153 2.731 2.141l.002-.008C14.944 8.424 15.327 7 16.979 7h.032A1 1 0 1 1 17 9h-.011c-.149.076-.256.474-.319.709a6.484 6.484 0 0 1-.311.951c-.429.973-.79 1.789-1.614 1.789" 50224 }) 50225 ] 50226 }), 50227 solid: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50228 xmlns: "http://www.w3.org/2000/svg", 50229 viewBox: "0 0 384 512", 50230 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50231 d: "M112.1 454.3c0 6.297 1.816 12.44 5.284 17.69l17.14 25.69c5.25 7.875 17.17 14.28 26.64 14.28h61.67c9.438 0 21.36-6.401 26.61-14.28l17.08-25.68c2.938-4.438 5.348-12.37 5.348-17.7L272 415.1h-160L112.1 454.3zM191.4 .0132C89.44 .3257 16 82.97 16 175.1c0 44.38 16.44 84.84 43.56 115.8c16.53 18.84 42.34 58.23 52.22 91.45c.0313 .25 .0938 .5166 .125 .7823h160.2c.0313-.2656 .0938-.5166 .125-.7823c9.875-33.22 35.69-72.61 52.22-91.45C351.6 260.8 368 220.4 368 175.1C368 78.61 288.9-.2837 191.4 .0132zM192 96.01c-44.13 0-80 35.89-80 79.1C112 184.8 104.8 192 96 192S80 184.8 80 176c0-61.76 50.25-111.1 112-111.1c8.844 0 16 7.159 16 16S200.8 96.01 192 96.01z" 50232 }) 50233 }) 50234 }, 50235 people: { 50236 outline: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50237 xmlns: "http://www.w3.org/2000/svg", 50238 viewBox: "0 0 24 24", 50239 children: [ 50240 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50241 d: "M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0m0 22C6.486 22 2 17.514 2 12S6.486 2 12 2s10 4.486 10 10-4.486 10-10 10" 50242 }), 50243 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50244 d: "M8 7a2 2 0 1 0-.001 3.999A2 2 0 0 0 8 7M16 7a2 2 0 1 0-.001 3.999A2 2 0 0 0 16 7M15.232 15c-.693 1.195-1.87 2-3.349 2-1.477 0-2.655-.805-3.347-2H15m3-2H6a6 6 0 1 0 12 0" 50245 }) 50246 ] 50247 }), 50248 solid: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50249 xmlns: "http://www.w3.org/2000/svg", 50250 viewBox: "0 0 512 512", 50251 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50252 d: "M0 256C0 114.6 114.6 0 256 0C397.4 0 512 114.6 512 256C512 397.4 397.4 512 256 512C114.6 512 0 397.4 0 256zM256 432C332.1 432 396.2 382 415.2 314.1C419.1 300.4 407.8 288 393.6 288H118.4C104.2 288 92.92 300.4 96.76 314.1C115.8 382 179.9 432 256 432V432zM176.4 160C158.7 160 144.4 174.3 144.4 192C144.4 209.7 158.7 224 176.4 224C194 224 208.4 209.7 208.4 192C208.4 174.3 194 160 176.4 160zM336.4 224C354 224 368.4 209.7 368.4 192C368.4 174.3 354 160 336.4 160C318.7 160 304.4 174.3 304.4 192C304.4 209.7 318.7 224 336.4 224z" 50253 }) 50254 }) 50255 }, 50256 places: { 50257 outline: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50258 xmlns: "http://www.w3.org/2000/svg", 50259 viewBox: "0 0 24 24", 50260 children: [ 50261 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50262 d: "M6.5 12C5.122 12 4 13.121 4 14.5S5.122 17 6.5 17 9 15.879 9 14.5 7.878 12 6.5 12m0 3c-.275 0-.5-.225-.5-.5s.225-.5.5-.5.5.225.5.5-.225.5-.5.5M17.5 12c-1.378 0-2.5 1.121-2.5 2.5s1.122 2.5 2.5 2.5 2.5-1.121 2.5-2.5-1.122-2.5-2.5-2.5m0 3c-.275 0-.5-.225-.5-.5s.225-.5.5-.5.5.225.5.5-.225.5-.5.5" 50263 }), 50264 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50265 d: "M22.482 9.494l-1.039-.346L21.4 9h.6c.552 0 1-.439 1-.992 0-.006-.003-.008-.003-.008H23c0-1-.889-2-1.984-2h-.642l-.731-1.717C19.262 3.012 18.091 2 16.764 2H7.236C5.909 2 4.738 3.012 4.357 4.283L3.626 6h-.642C1.889 6 1 7 1 8h.003S1 8.002 1 8.008C1 8.561 1.448 9 2 9h.6l-.043.148-1.039.346a2.001 2.001 0 0 0-1.359 2.097l.751 7.508a1 1 0 0 0 .994.901H3v1c0 1.103.896 2 2 2h2c1.104 0 2-.897 2-2v-1h6v1c0 1.103.896 2 2 2h2c1.104 0 2-.897 2-2v-1h1.096a.999.999 0 0 0 .994-.901l.751-7.508a2.001 2.001 0 0 0-1.359-2.097M6.273 4.857C6.402 4.43 6.788 4 7.236 4h9.527c.448 0 .834.43.963.857L19.313 9H4.688l1.585-4.143zM7 21H5v-1h2v1zm12 0h-2v-1h2v1zm2.189-3H2.811l-.662-6.607L3 11h18l.852.393L21.189 18z" 50266 }) 50267 ] 50268 }), 50269 solid: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50270 xmlns: "http://www.w3.org/2000/svg", 50271 viewBox: "0 0 512 512", 50272 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50273 d: "M39.61 196.8L74.8 96.29C88.27 57.78 124.6 32 165.4 32H346.6C387.4 32 423.7 57.78 437.2 96.29L472.4 196.8C495.6 206.4 512 229.3 512 256V448C512 465.7 497.7 480 480 480H448C430.3 480 416 465.7 416 448V400H96V448C96 465.7 81.67 480 64 480H32C14.33 480 0 465.7 0 448V256C0 229.3 16.36 206.4 39.61 196.8V196.8zM109.1 192H402.9L376.8 117.4C372.3 104.6 360.2 96 346.6 96H165.4C151.8 96 139.7 104.6 135.2 117.4L109.1 192zM96 256C78.33 256 64 270.3 64 288C64 305.7 78.33 320 96 320C113.7 320 128 305.7 128 288C128 270.3 113.7 256 96 256zM416 320C433.7 320 448 305.7 448 288C448 270.3 433.7 256 416 256C398.3 256 384 270.3 384 288C384 305.7 398.3 320 416 320z" 50274 }) 50275 }) 50276 }, 50277 symbols: { 50278 outline: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50279 xmlns: "http://www.w3.org/2000/svg", 50280 viewBox: "0 0 24 24", 50281 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50282 d: "M0 0h11v2H0zM4 11h3V6h4V4H0v2h4zM15.5 17c1.381 0 2.5-1.116 2.5-2.493s-1.119-2.493-2.5-2.493S13 13.13 13 14.507 14.119 17 15.5 17m0-2.986c.276 0 .5.222.5.493 0 .272-.224.493-.5.493s-.5-.221-.5-.493.224-.493.5-.493M21.5 19.014c-1.381 0-2.5 1.116-2.5 2.493S20.119 24 21.5 24s2.5-1.116 2.5-2.493-1.119-2.493-2.5-2.493m0 2.986a.497.497 0 0 1-.5-.493c0-.271.224-.493.5-.493s.5.222.5.493a.497.497 0 0 1-.5.493M22 13l-9 9 1.513 1.5 8.99-9.009zM17 11c2.209 0 4-1.119 4-2.5V2s.985-.161 1.498.949C23.01 4.055 23 6 23 6s1-1.119 1-3.135C24-.02 21 0 21 0h-2v6.347A5.853 5.853 0 0 0 17 6c-2.209 0-4 1.119-4 2.5s1.791 2.5 4 2.5M10.297 20.482l-1.475-1.585a47.54 47.54 0 0 1-1.442 1.129c-.307-.288-.989-1.016-2.045-2.183.902-.836 1.479-1.466 1.729-1.892s.376-.871.376-1.336c0-.592-.273-1.178-.818-1.759-.546-.581-1.329-.871-2.349-.871-1.008 0-1.79.293-2.344.879-.556.587-.832 1.181-.832 1.784 0 .813.419 1.748 1.256 2.805-.847.614-1.444 1.208-1.794 1.784a3.465 3.465 0 0 0-.523 1.833c0 .857.308 1.56.924 2.107.616.549 1.423.823 2.42.823 1.173 0 2.444-.379 3.813-1.137L8.235 24h2.819l-2.09-2.383 1.333-1.135zm-6.736-6.389a1.02 1.02 0 0 1 .73-.286c.31 0 .559.085.747.254a.849.849 0 0 1 .283.659c0 .518-.419 1.112-1.257 1.784-.536-.651-.805-1.231-.805-1.742a.901.901 0 0 1 .302-.669M3.74 22c-.427 0-.778-.116-1.057-.349-.279-.232-.418-.487-.418-.766 0-.594.509-1.288 1.527-2.083.968 1.134 1.717 1.946 2.248 2.438-.921.507-1.686.76-2.3.76" 50283 }) 50284 }), 50285 solid: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50286 xmlns: "http://www.w3.org/2000/svg", 50287 viewBox: "0 0 512 512", 50288 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50289 d: "M500.3 7.251C507.7 13.33 512 22.41 512 31.1V175.1C512 202.5 483.3 223.1 447.1 223.1C412.7 223.1 383.1 202.5 383.1 175.1C383.1 149.5 412.7 127.1 447.1 127.1V71.03L351.1 90.23V207.1C351.1 234.5 323.3 255.1 287.1 255.1C252.7 255.1 223.1 234.5 223.1 207.1C223.1 181.5 252.7 159.1 287.1 159.1V63.1C287.1 48.74 298.8 35.61 313.7 32.62L473.7 .6198C483.1-1.261 492.9 1.173 500.3 7.251H500.3zM74.66 303.1L86.5 286.2C92.43 277.3 102.4 271.1 113.1 271.1H174.9C185.6 271.1 195.6 277.3 201.5 286.2L213.3 303.1H239.1C266.5 303.1 287.1 325.5 287.1 351.1V463.1C287.1 490.5 266.5 511.1 239.1 511.1H47.1C21.49 511.1-.0019 490.5-.0019 463.1V351.1C-.0019 325.5 21.49 303.1 47.1 303.1H74.66zM143.1 359.1C117.5 359.1 95.1 381.5 95.1 407.1C95.1 434.5 117.5 455.1 143.1 455.1C170.5 455.1 191.1 434.5 191.1 407.1C191.1 381.5 170.5 359.1 143.1 359.1zM440.3 367.1H496C502.7 367.1 508.6 372.1 510.1 378.4C513.3 384.6 511.6 391.7 506.5 396L378.5 508C372.9 512.1 364.6 513.3 358.6 508.9C352.6 504.6 350.3 496.6 353.3 489.7L391.7 399.1H336C329.3 399.1 323.4 395.9 321 389.6C318.7 383.4 320.4 376.3 325.5 371.1L453.5 259.1C459.1 255 467.4 254.7 473.4 259.1C479.4 263.4 481.6 271.4 478.7 278.3L440.3 367.1zM116.7 219.1L19.85 119.2C-8.112 90.26-6.614 42.31 24.85 15.34C51.82-8.137 93.26-3.642 118.2 21.83L128.2 32.32L137.7 21.83C162.7-3.642 203.6-8.137 231.6 15.34C262.6 42.31 264.1 90.26 236.1 119.2L139.7 219.1C133.2 225.6 122.7 225.6 116.7 219.1H116.7z" 50290 }) 50291 }) 50292 } 50293 }; 50294 var $fcccfb36ed0cde68$var$search = { 50295 loupe: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50296 xmlns: "http://www.w3.org/2000/svg", 50297 viewBox: "0 0 20 20", 50298 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50299 d: "M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z" 50300 }) 50301 }), 50302 delete: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("svg", { 50303 xmlns: "http://www.w3.org/2000/svg", 50304 viewBox: "0 0 20 20", 50305 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("path", { 50306 d: "M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z" 50307 }) 50308 }) 50309 }; 50310 var $fcccfb36ed0cde68$export$2e2bcd8739ae039 = { 50311 categories: $fcccfb36ed0cde68$var$categories, 50312 search: $fcccfb36ed0cde68$var$search 50313 }; 50314 function $254755d3f438722f$export$2e2bcd8739ae039(props) { 50315 let { id: id3, skin, emoji } = props; 50316 if (props.shortcodes) { 50317 const matches = props.shortcodes.match((0, $c4d155af13ad4d4b$export$2e2bcd8739ae039).SHORTCODES_REGEX); 50318 if (matches) { 50319 id3 = matches[1]; 50320 if (matches[2]) skin = matches[2]; 50321 } 50322 } 50323 emoji || (emoji = (0, $c4d155af13ad4d4b$export$2e2bcd8739ae039).get(id3 || props.native)); 50324 if (!emoji) return props.fallback; 50325 const emojiSkin = emoji.skins[skin - 1] || emoji.skins[0]; 50326 const imageSrc = emojiSkin.src || (props.set != "native" && !props.spritesheet ? typeof props.getImageURL === "function" ? props.getImageURL(props.set, emojiSkin.unified) : `https://cdn.jsdelivr.net/npm/emoji-datasource-${props.set}@15.0.1/img/${props.set}/64/${emojiSkin.unified}.png` : void 0); 50327 const spritesheetSrc = typeof props.getSpritesheetURL === "function" ? props.getSpritesheetURL(props.set) : `https://cdn.jsdelivr.net/npm/emoji-datasource-${props.set}@15.0.1/img/${props.set}/sheets-256/64.png`; 50328 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("span", { 50329 class: "emoji-mart-emoji", 50330 "data-emoji-set": props.set, 50331 children: imageSrc ? /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("img", { 50332 style: { 50333 maxWidth: props.size || "1em", 50334 maxHeight: props.size || "1em", 50335 display: "inline-block" 50336 }, 50337 alt: emojiSkin.native || emojiSkin.shortcodes, 50338 src: imageSrc 50339 }) : props.set == "native" ? /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("span", { 50340 style: { 50341 fontSize: props.size, 50342 fontFamily: '"EmojiMart", "Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Apple Color Emoji", "Twemoji Mozilla", "Noto Color Emoji", "Android Emoji"' 50343 }, 50344 children: emojiSkin.native 50345 }) : /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("span", { 50346 style: { 50347 display: "block", 50348 width: props.size, 50349 height: props.size, 50350 backgroundImage: `url(${spritesheetSrc})`, 50351 backgroundSize: `${100 * (0, $7adb23b0109cc36a$export$2d0294657ab35f1b).sheet.cols}% ${100 * (0, $7adb23b0109cc36a$export$2d0294657ab35f1b).sheet.rows}%`, 50352 backgroundPosition: `${100 / ((0, $7adb23b0109cc36a$export$2d0294657ab35f1b).sheet.cols - 1) * emojiSkin.x}% ${100 / ((0, $7adb23b0109cc36a$export$2d0294657ab35f1b).sheet.rows - 1) * emojiSkin.y}%` 50353 } 50354 }) 50355 }); 50356 } 50357 var $6f57cc9cd54c5aaa$var$WindowHTMLElement = typeof window !== "undefined" && window.HTMLElement ? window.HTMLElement : Object; 50358 var $6f57cc9cd54c5aaa$export$2e2bcd8739ae039 = class extends $6f57cc9cd54c5aaa$var$WindowHTMLElement { 50359 static get observedAttributes() { 50360 return Object.keys(this.Props); 50361 } 50362 update(props = {}) { 50363 for (let k2 in props) this.attributeChangedCallback(k2, null, props[k2]); 50364 } 50365 attributeChangedCallback(attr, _3, newValue) { 50366 if (!this.component) return; 50367 const value = (0, $7adb23b0109cc36a$export$88c9ddb45cea7241)(attr, { 50368 [attr]: newValue 50369 }, this.constructor.Props, this); 50370 if (this.component.componentWillReceiveProps) this.component.componentWillReceiveProps({ 50371 [attr]: value 50372 }); 50373 else { 50374 this.component.props[attr] = value; 50375 this.component.forceUpdate(); 50376 } 50377 } 50378 disconnectedCallback() { 50379 this.disconnected = true; 50380 if (this.component && this.component.unregister) this.component.unregister(); 50381 } 50382 constructor(props = {}) { 50383 super(); 50384 this.props = props; 50385 if (props.parent || props.ref) { 50386 let ref = null; 50387 const parent = props.parent || (ref = props.ref && props.ref.current); 50388 if (ref) ref.innerHTML = ""; 50389 if (parent) parent.appendChild(this); 50390 } 50391 } 50392 }; 50393 var $26f27c338a96b1a6$export$2e2bcd8739ae039 = class extends (0, $6f57cc9cd54c5aaa$export$2e2bcd8739ae039) { 50394 setShadow() { 50395 this.attachShadow({ 50396 mode: "open" 50397 }); 50398 } 50399 injectStyles(styles) { 50400 if (!styles) return; 50401 const style = document.createElement("style"); 50402 style.textContent = styles; 50403 this.shadowRoot.insertBefore(style, this.shadowRoot.firstChild); 50404 } 50405 constructor(props, { styles } = {}) { 50406 super(props); 50407 this.setShadow(); 50408 this.injectStyles(styles); 50409 } 50410 }; 50411 var $3d90f6e46fb2dd47$export$2e2bcd8739ae039 = { 50412 fallback: "", 50413 id: "", 50414 native: "", 50415 shortcodes: "", 50416 size: { 50417 value: "", 50418 transform: (value) => { 50419 if (!/\D/.test(value)) return `${value}px`; 50420 return value; 50421 } 50422 }, 50423 // Shared 50424 set: (0, $b247ea80b67298d5$export$2e2bcd8739ae039).set, 50425 skin: (0, $b247ea80b67298d5$export$2e2bcd8739ae039).skin 50426 }; 50427 var $331b4160623139bf$export$2e2bcd8739ae039 = class extends (0, $6f57cc9cd54c5aaa$export$2e2bcd8739ae039) { 50428 async connectedCallback() { 50429 const props = (0, $7adb23b0109cc36a$export$75fe5f91d452f94b)(this.props, (0, $3d90f6e46fb2dd47$export$2e2bcd8739ae039), this); 50430 props.element = this; 50431 props.ref = (component) => { 50432 this.component = component; 50433 }; 50434 await (0, $7adb23b0109cc36a$export$2cd8252107eb640b)(); 50435 if (this.disconnected) return; 50436 (0, $fb96b826c0c5f37a$export$b3890eb0ae9dca99)(/* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)((0, $254755d3f438722f$export$2e2bcd8739ae039), { 50437 ...props 50438 }), this); 50439 } 50440 constructor(props) { 50441 super(props); 50442 } 50443 }; 50444 (0, $c770c458706daa72$export$2e2bcd8739ae039)($331b4160623139bf$export$2e2bcd8739ae039, "Props", (0, $3d90f6e46fb2dd47$export$2e2bcd8739ae039)); 50445 if (typeof customElements !== "undefined" && !customElements.get("em-emoji")) customElements.define("em-emoji", $331b4160623139bf$export$2e2bcd8739ae039); 50446 var $1a9a8ef576b7773d$var$t; 50447 var $1a9a8ef576b7773d$var$u; 50448 var $1a9a8ef576b7773d$var$r; 50449 var $1a9a8ef576b7773d$var$i = []; 50450 var $1a9a8ef576b7773d$var$c = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__b; 50451 var $1a9a8ef576b7773d$var$f = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__r; 50452 var $1a9a8ef576b7773d$var$e = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).diffed; 50453 var $1a9a8ef576b7773d$var$a = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__c; 50454 var $1a9a8ef576b7773d$var$v = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).unmount; 50455 function $1a9a8ef576b7773d$var$x() { 50456 var t6; 50457 for ($1a9a8ef576b7773d$var$i.sort(function(n11, t7) { 50458 return n11.__v.__b - t7.__v.__b; 50459 }); t6 = $1a9a8ef576b7773d$var$i.pop(); ) if (t6.__P) try { 50460 t6.__H.__h.forEach($1a9a8ef576b7773d$var$g), t6.__H.__h.forEach($1a9a8ef576b7773d$var$j), t6.__H.__h = []; 50461 } catch (u4) { 50462 t6.__H.__h = [], (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__e(u4, t6.__v); 50463 } 50464 } 50465 (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__b = function(n12) { 50466 $1a9a8ef576b7773d$var$u = null, $1a9a8ef576b7773d$var$c && $1a9a8ef576b7773d$var$c(n12); 50467 }, (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__r = function(n13) { 50468 $1a9a8ef576b7773d$var$f && $1a9a8ef576b7773d$var$f(n13), $1a9a8ef576b7773d$var$t = 0; 50469 var r8 = ($1a9a8ef576b7773d$var$u = n13.__c).__H; 50470 r8 && (r8.__h.forEach($1a9a8ef576b7773d$var$g), r8.__h.forEach($1a9a8ef576b7773d$var$j), r8.__h = []); 50471 }, (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).diffed = function(t8) { 50472 $1a9a8ef576b7773d$var$e && $1a9a8ef576b7773d$var$e(t8); 50473 var o6 = t8.__c; 50474 o6 && o6.__H && o6.__H.__h.length && (1 !== $1a9a8ef576b7773d$var$i.push(o6) && $1a9a8ef576b7773d$var$r === (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).requestAnimationFrame || (($1a9a8ef576b7773d$var$r = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).requestAnimationFrame) || function(n14) { 50475 var t9, u5 = function() { 50476 clearTimeout(r9), $1a9a8ef576b7773d$var$b && cancelAnimationFrame(t9), setTimeout(n14); 50477 }, r9 = setTimeout(u5, 100); 50478 $1a9a8ef576b7773d$var$b && (t9 = requestAnimationFrame(u5)); 50479 })($1a9a8ef576b7773d$var$x)), $1a9a8ef576b7773d$var$u = null; 50480 }, (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__c = function(t10, u6) { 50481 u6.some(function(t11) { 50482 try { 50483 t11.__h.forEach($1a9a8ef576b7773d$var$g), t11.__h = t11.__h.filter(function(n15) { 50484 return !n15.__ || $1a9a8ef576b7773d$var$j(n15); 50485 }); 50486 } catch (r10) { 50487 u6.some(function(n16) { 50488 n16.__h && (n16.__h = []); 50489 }), u6 = [], (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__e(r10, t11.__v); 50490 } 50491 }), $1a9a8ef576b7773d$var$a && $1a9a8ef576b7773d$var$a(t10, u6); 50492 }, (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).unmount = function(t12) { 50493 $1a9a8ef576b7773d$var$v && $1a9a8ef576b7773d$var$v(t12); 50494 var u7, r11 = t12.__c; 50495 r11 && r11.__H && (r11.__H.__.forEach(function(n17) { 50496 try { 50497 $1a9a8ef576b7773d$var$g(n17); 50498 } catch (n18) { 50499 u7 = n18; 50500 } 50501 }), u7 && (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__e(u7, r11.__v)); 50502 }; 50503 var $1a9a8ef576b7773d$var$b = "function" == typeof requestAnimationFrame; 50504 function $1a9a8ef576b7773d$var$g(n19) { 50505 var t13 = $1a9a8ef576b7773d$var$u, r12 = n19.__c; 50506 "function" == typeof r12 && (n19.__c = void 0, r12()), $1a9a8ef576b7773d$var$u = t13; 50507 } 50508 function $1a9a8ef576b7773d$var$j(n20) { 50509 var t14 = $1a9a8ef576b7773d$var$u; 50510 n20.__c = n20.__(), $1a9a8ef576b7773d$var$u = t14; 50511 } 50512 function $dc040a17866866fa$var$S(n1, t1) { 50513 for (var e1 in t1) n1[e1] = t1[e1]; 50514 return n1; 50515 } 50516 function $dc040a17866866fa$var$C(n2, t2) { 50517 for (var e2 in n2) if ("__source" !== e2 && !(e2 in t2)) return true; 50518 for (var r1 in t2) if ("__source" !== r1 && n2[r1] !== t2[r1]) return true; 50519 return false; 50520 } 50521 function $dc040a17866866fa$export$221d75b3f55bb0bd(n3) { 50522 this.props = n3; 50523 } 50524 ($dc040a17866866fa$export$221d75b3f55bb0bd.prototype = new (0, $fb96b826c0c5f37a$export$16fa2f45be04daa8)()).isPureReactComponent = true, $dc040a17866866fa$export$221d75b3f55bb0bd.prototype.shouldComponentUpdate = function(n6, t5) { 50525 return $dc040a17866866fa$var$C(this.props, n6) || $dc040a17866866fa$var$C(this.state, t5); 50526 }; 50527 var $dc040a17866866fa$var$w = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__b; 50528 (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__b = function(n7) { 50529 n7.type && n7.type.__f && n7.ref && (n7.props.ref = n7.ref, n7.ref = null), $dc040a17866866fa$var$w && $dc040a17866866fa$var$w(n7); 50530 }; 50531 var $dc040a17866866fa$var$R = "undefined" != typeof Symbol && Symbol.for && Symbol.for("react.forward_ref") || 3911; 50532 var $dc040a17866866fa$var$A = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__e; 50533 (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__e = function(n12, t10, e6) { 50534 if (n12.then) { 50535 for (var r5, u1 = t10; u1 = u1.__; ) if ((r5 = u1.__c) && r5.__c) return null == t10.__e && (t10.__e = e6.__e, t10.__k = e6.__k), r5.__c(n12, t10); 50536 } 50537 $dc040a17866866fa$var$A(n12, t10, e6); 50538 }; 50539 var $dc040a17866866fa$var$O = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).unmount; 50540 function $dc040a17866866fa$export$74bf444e3cd11ea5() { 50541 this.__u = 0, this.t = null, this.__b = null; 50542 } 50543 function $dc040a17866866fa$var$U(n13) { 50544 var t11 = n13.__.__c; 50545 return t11 && t11.__e && t11.__e(n13); 50546 } 50547 function $dc040a17866866fa$export$998bcd577473dd93() { 50548 this.u = null, this.o = null; 50549 } 50550 (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).unmount = function(n17) { 50551 var t13 = n17.__c; 50552 t13 && t13.__R && t13.__R(), t13 && true === n17.__h && (n17.type = null), $dc040a17866866fa$var$O && $dc040a17866866fa$var$O(n17); 50553 }, ($dc040a17866866fa$export$74bf444e3cd11ea5.prototype = new (0, $fb96b826c0c5f37a$export$16fa2f45be04daa8)()).__c = function(n18, t14) { 50554 var e8 = t14.__c, r7 = this; 50555 null == r7.t && (r7.t = []), r7.t.push(e8); 50556 var u4 = $dc040a17866866fa$var$U(r7.__v), o1 = false, i1 = function() { 50557 o1 || (o1 = true, e8.__R = null, u4 ? u4(l1) : l1()); 50558 }; 50559 e8.__R = i1; 50560 var l1 = function() { 50561 if (!--r7.__u) { 50562 if (r7.state.__e) { 50563 var n19 = r7.state.__e; 50564 r7.__v.__k[0] = function n22(t17, e9, r8) { 50565 return t17 && (t17.__v = null, t17.__k = t17.__k && t17.__k.map(function(t18) { 50566 return n22(t18, e9, r8); 50567 }), t17.__c && t17.__c.__P === e9 && (t17.__e && r8.insertBefore(t17.__e, t17.__d), t17.__c.__e = true, t17.__c.__P = r8)), t17; 50568 }(n19, n19.__c.__P, n19.__c.__O); 50569 } 50570 var t15; 50571 for (r7.setState({ 50572 __e: r7.__b = null 50573 }); t15 = r7.t.pop(); ) t15.forceUpdate(); 50574 } 50575 }, c1 = true === t14.__h; 50576 r7.__u++ || c1 || r7.setState({ 50577 __e: r7.__b = r7.__v.__k[0] 50578 }), n18.then(i1, i1); 50579 }, $dc040a17866866fa$export$74bf444e3cd11ea5.prototype.componentWillUnmount = function() { 50580 this.t = []; 50581 }, $dc040a17866866fa$export$74bf444e3cd11ea5.prototype.render = function(n23, t19) { 50582 if (this.__b) { 50583 if (this.__v.__k) { 50584 var e10 = document.createElement("div"), r9 = this.__v.__k[0].__c; 50585 this.__v.__k[0] = function n24(t20, e13, r12) { 50586 return t20 && (t20.__c && t20.__c.__H && (t20.__c.__H.__.forEach(function(n25) { 50587 "function" == typeof n25.__c && n25.__c(); 50588 }), t20.__c.__H = null), null != (t20 = $dc040a17866866fa$var$S({}, t20)).__c && (t20.__c.__P === r12 && (t20.__c.__P = e13), t20.__c = null), t20.__k = t20.__k && t20.__k.map(function(t21) { 50589 return n24(t21, e13, r12); 50590 })), t20; 50591 }(this.__b, e10, r9.__O = r9.__P); 50592 } 50593 this.__b = null; 50594 } 50595 var u5 = t19.__e && (0, $fb96b826c0c5f37a$export$c8a8987d4410bf2d)((0, $fb96b826c0c5f37a$export$ffb0004e005737fa), null, n23.fallback); 50596 return u5 && (u5.__h = null), [ 50597 (0, $fb96b826c0c5f37a$export$c8a8987d4410bf2d)((0, $fb96b826c0c5f37a$export$ffb0004e005737fa), null, t19.__e ? null : n23.children), 50598 u5 50599 ]; 50600 }; 50601 var $dc040a17866866fa$var$T = function(n26, t22, e14) { 50602 if (++e14[1] === e14[0] && n26.o.delete(t22), n26.props.revealOrder && ("t" !== n26.props.revealOrder[0] || !n26.o.size)) for (e14 = n26.u; e14; ) { 50603 for (; e14.length > 3; ) e14.pop()(); 50604 if (e14[1] < e14[0]) break; 50605 n26.u = e14 = e14[2]; 50606 } 50607 }; 50608 ($dc040a17866866fa$export$998bcd577473dd93.prototype = new (0, $fb96b826c0c5f37a$export$16fa2f45be04daa8)()).__e = function(n33) { 50609 var t25 = this, e16 = $dc040a17866866fa$var$U(t25.__v), r13 = t25.o.get(n33); 50610 return r13[0]++, function(u6) { 50611 var o2 = function() { 50612 t25.props.revealOrder ? (r13.push(u6), $dc040a17866866fa$var$T(t25, n33, r13)) : u6(); 50613 }; 50614 e16 ? e16(o2) : o2(); 50615 }; 50616 }, $dc040a17866866fa$export$998bcd577473dd93.prototype.render = function(n34) { 50617 this.u = null, this.o = /* @__PURE__ */ new Map(); 50618 var t26 = (0, $fb96b826c0c5f37a$export$47e4c5b300681277)(n34.children); 50619 n34.revealOrder && "b" === n34.revealOrder[0] && t26.reverse(); 50620 for (var e17 = t26.length; e17--; ) this.o.set(t26[e17], this.u = [ 50621 1, 50622 0, 50623 this.u 50624 ]); 50625 return n34.children; 50626 }, $dc040a17866866fa$export$998bcd577473dd93.prototype.componentDidUpdate = $dc040a17866866fa$export$998bcd577473dd93.prototype.componentDidMount = function() { 50627 var n35 = this; 50628 this.o.forEach(function(t27, e18) { 50629 $dc040a17866866fa$var$T(n35, e18, t27); 50630 }); 50631 }; 50632 var $dc040a17866866fa$var$j = "undefined" != typeof Symbol && Symbol.for && Symbol.for("react.element") || 60103; 50633 var $dc040a17866866fa$var$P = /^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|marker(?!H|W|U)|overline|paint|stop|strikethrough|stroke|text(?!L)|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/; 50634 var $dc040a17866866fa$var$V = "undefined" != typeof document; 50635 var $dc040a17866866fa$var$z = function(n36) { 50636 return ("undefined" != typeof Symbol && "symbol" == typeof Symbol() ? /fil|che|rad/i : /fil|che|ra/i).test(n36); 50637 }; 50638 (0, $fb96b826c0c5f37a$export$16fa2f45be04daa8).prototype.isReactComponent = {}, [ 50639 "componentWillMount", 50640 "componentWillReceiveProps", 50641 "componentWillUpdate" 50642 ].forEach(function(n39) { 50643 Object.defineProperty((0, $fb96b826c0c5f37a$export$16fa2f45be04daa8).prototype, n39, { 50644 configurable: true, 50645 get: function() { 50646 return this["UNSAFE_" + n39]; 50647 }, 50648 set: function(t30) { 50649 Object.defineProperty(this, n39, { 50650 configurable: true, 50651 writable: true, 50652 value: t30 50653 }); 50654 } 50655 }); 50656 }); 50657 var $dc040a17866866fa$var$H = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).event; 50658 function $dc040a17866866fa$var$Z() { 50659 } 50660 function $dc040a17866866fa$var$Y() { 50661 return this.cancelBubble; 50662 } 50663 function $dc040a17866866fa$var$q() { 50664 return this.defaultPrevented; 50665 } 50666 (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).event = function(n40) { 50667 return $dc040a17866866fa$var$H && (n40 = $dc040a17866866fa$var$H(n40)), n40.persist = $dc040a17866866fa$var$Z, n40.isPropagationStopped = $dc040a17866866fa$var$Y, n40.isDefaultPrevented = $dc040a17866866fa$var$q, n40.nativeEvent = n40; 50668 }; 50669 var $dc040a17866866fa$var$G; 50670 var $dc040a17866866fa$var$J = { 50671 configurable: true, 50672 get: function() { 50673 return this.class; 50674 } 50675 }; 50676 var $dc040a17866866fa$var$K = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).vnode; 50677 (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).vnode = function(n41) { 50678 var t31 = n41.type, e21 = n41.props, r14 = e21; 50679 if ("string" == typeof t31) { 50680 var u7 = -1 === t31.indexOf("-"); 50681 for (var o3 in r14 = {}, e21) { 50682 var i2 = e21[o3]; 50683 $dc040a17866866fa$var$V && "children" === o3 && "noscript" === t31 || "value" === o3 && "defaultValue" in e21 && null == i2 || ("defaultValue" === o3 && "value" in e21 && null == e21.value ? o3 = "value" : "download" === o3 && true === i2 ? i2 = "" : /ondoubleclick/i.test(o3) ? o3 = "ondblclick" : /^onchange(textarea|input)/i.test(o3 + t31) && !$dc040a17866866fa$var$z(e21.type) ? o3 = "oninput" : /^onfocus$/i.test(o3) ? o3 = "onfocusin" : /^onblur$/i.test(o3) ? o3 = "onfocusout" : /^on(Ani|Tra|Tou|BeforeInp)/.test(o3) ? o3 = o3.toLowerCase() : u7 && $dc040a17866866fa$var$P.test(o3) ? o3 = o3.replace(/[A-Z0-9]/, "-$&").toLowerCase() : null === i2 && (i2 = void 0), r14[o3] = i2); 50684 } 50685 "select" == t31 && r14.multiple && Array.isArray(r14.value) && (r14.value = (0, $fb96b826c0c5f37a$export$47e4c5b300681277)(e21.children).forEach(function(n42) { 50686 n42.props.selected = -1 != r14.value.indexOf(n42.props.value); 50687 })), "select" == t31 && null != r14.defaultValue && (r14.value = (0, $fb96b826c0c5f37a$export$47e4c5b300681277)(e21.children).forEach(function(n43) { 50688 n43.props.selected = r14.multiple ? -1 != r14.defaultValue.indexOf(n43.props.value) : r14.defaultValue == n43.props.value; 50689 })), n41.props = r14, e21.class != e21.className && ($dc040a17866866fa$var$J.enumerable = "className" in e21, null != e21.className && (r14.class = e21.className), Object.defineProperty(r14, "className", $dc040a17866866fa$var$J)); 50690 } 50691 n41.$$typeof = $dc040a17866866fa$var$j, $dc040a17866866fa$var$K && $dc040a17866866fa$var$K(n41); 50692 }; 50693 var $dc040a17866866fa$var$Q = (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__r; 50694 (0, $fb96b826c0c5f37a$export$41c562ebe57d11e2).__r = function(n44) { 50695 $dc040a17866866fa$var$Q && $dc040a17866866fa$var$Q(n44), $dc040a17866866fa$var$G = n44.__c; 50696 }; 50697 var $ec8c39fdad15601a$var$THEME_ICONS = { 50698 light: "outline", 50699 dark: "solid" 50700 }; 50701 var $ec8c39fdad15601a$export$2e2bcd8739ae039 = class extends (0, $dc040a17866866fa$export$221d75b3f55bb0bd) { 50702 renderIcon(category) { 50703 const { icon } = category; 50704 if (icon) { 50705 if (icon.svg) return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("span", { 50706 class: "flex", 50707 dangerouslySetInnerHTML: { 50708 __html: icon.svg 50709 } 50710 }); 50711 if (icon.src) return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("img", { 50712 src: icon.src 50713 }); 50714 } 50715 const categoryIcons = (0, $fcccfb36ed0cde68$export$2e2bcd8739ae039).categories[category.id] || (0, $fcccfb36ed0cde68$export$2e2bcd8739ae039).categories.custom; 50716 const style = this.props.icons == "auto" ? $ec8c39fdad15601a$var$THEME_ICONS[this.props.theme] : this.props.icons; 50717 return categoryIcons[style] || categoryIcons; 50718 } 50719 render() { 50720 let selectedCategoryIndex = null; 50721 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("nav", { 50722 id: "nav", 50723 class: "padding", 50724 "data-position": this.props.position, 50725 dir: this.props.dir, 50726 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 50727 class: "flex relative", 50728 children: [ 50729 this.categories.map((category, i2) => { 50730 const title = category.name || (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).categories[category.id]; 50731 const selected = !this.props.unfocused && category.id == this.state.categoryId; 50732 if (selected) selectedCategoryIndex = i2; 50733 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("button", { 50734 "aria-label": title, 50735 "aria-selected": selected || void 0, 50736 title, 50737 type: "button", 50738 class: "flex flex-grow flex-center", 50739 onMouseDown: (e2) => e2.preventDefault(), 50740 onClick: () => { 50741 this.props.onClick({ 50742 category, 50743 i: i2 50744 }); 50745 }, 50746 children: this.renderIcon(category) 50747 }); 50748 }), 50749 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 50750 class: "bar", 50751 style: { 50752 width: `${100 / this.categories.length}%`, 50753 opacity: selectedCategoryIndex == null ? 0 : 1, 50754 transform: this.props.dir === "rtl" ? `scaleX(-1) translateX(${selectedCategoryIndex * 100}%)` : `translateX(${selectedCategoryIndex * 100}%)` 50755 } 50756 }) 50757 ] 50758 }) 50759 }); 50760 } 50761 constructor() { 50762 super(); 50763 this.categories = (0, $7adb23b0109cc36a$export$2d0294657ab35f1b).categories.filter((category) => { 50764 return !category.target; 50765 }); 50766 this.state = { 50767 categoryId: this.categories[0].id 50768 }; 50769 } 50770 }; 50771 var $e0d4dda61265ff1e$export$2e2bcd8739ae039 = class extends (0, $dc040a17866866fa$export$221d75b3f55bb0bd) { 50772 shouldComponentUpdate(nextProps) { 50773 for (let k2 in nextProps) { 50774 if (k2 == "children") continue; 50775 if (nextProps[k2] != this.props[k2]) return true; 50776 } 50777 return false; 50778 } 50779 render() { 50780 return this.props.children; 50781 } 50782 }; 50783 var $89bd6bb200cc8fef$var$Performance = { 50784 rowsPerRender: 10 50785 }; 50786 var $89bd6bb200cc8fef$export$2e2bcd8739ae039 = class extends (0, $fb96b826c0c5f37a$export$16fa2f45be04daa8) { 50787 getInitialState(props = this.props) { 50788 return { 50789 skin: (0, $f72b75cf796873c7$export$2e2bcd8739ae039).get("skin") || props.skin, 50790 theme: this.initTheme(props.theme) 50791 }; 50792 } 50793 componentWillMount() { 50794 this.dir = (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).rtl ? "rtl" : "ltr"; 50795 this.refs = { 50796 menu: (0, $fb96b826c0c5f37a$export$7d1e3a5e95ceca43)(), 50797 navigation: (0, $fb96b826c0c5f37a$export$7d1e3a5e95ceca43)(), 50798 scroll: (0, $fb96b826c0c5f37a$export$7d1e3a5e95ceca43)(), 50799 search: (0, $fb96b826c0c5f37a$export$7d1e3a5e95ceca43)(), 50800 searchInput: (0, $fb96b826c0c5f37a$export$7d1e3a5e95ceca43)(), 50801 skinToneButton: (0, $fb96b826c0c5f37a$export$7d1e3a5e95ceca43)(), 50802 skinToneRadio: (0, $fb96b826c0c5f37a$export$7d1e3a5e95ceca43)() 50803 }; 50804 this.initGrid(); 50805 if (this.props.stickySearch == false && this.props.searchPosition == "sticky") { 50806 console.warn("[EmojiMart] Deprecation warning: `stickySearch` has been renamed `searchPosition`."); 50807 this.props.searchPosition = "static"; 50808 } 50809 } 50810 componentDidMount() { 50811 this.register(); 50812 this.shadowRoot = this.base.parentNode; 50813 if (this.props.autoFocus) { 50814 const { searchInput } = this.refs; 50815 if (searchInput.current) searchInput.current.focus(); 50816 } 50817 } 50818 componentWillReceiveProps(nextProps) { 50819 this.nextState || (this.nextState = {}); 50820 for (const k1 in nextProps) this.nextState[k1] = nextProps[k1]; 50821 clearTimeout(this.nextStateTimer); 50822 this.nextStateTimer = setTimeout(() => { 50823 let requiresGridReset = false; 50824 for (const k2 in this.nextState) { 50825 this.props[k2] = this.nextState[k2]; 50826 if (k2 === "custom" || k2 === "categories") requiresGridReset = true; 50827 } 50828 delete this.nextState; 50829 const nextState = this.getInitialState(); 50830 if (requiresGridReset) return this.reset(nextState); 50831 this.setState(nextState); 50832 }); 50833 } 50834 componentWillUnmount() { 50835 this.unregister(); 50836 } 50837 async reset(nextState = {}) { 50838 await (0, $7adb23b0109cc36a$export$2cd8252107eb640b)(this.props); 50839 this.initGrid(); 50840 this.unobserve(); 50841 this.setState(nextState, () => { 50842 this.observeCategories(); 50843 this.observeRows(); 50844 }); 50845 } 50846 register() { 50847 document.addEventListener("click", this.handleClickOutside); 50848 this.observe(); 50849 } 50850 unregister() { 50851 document.removeEventListener("click", this.handleClickOutside); 50852 this.darkMedia?.removeEventListener("change", this.darkMediaCallback); 50853 this.unobserve(); 50854 } 50855 observe() { 50856 this.observeCategories(); 50857 this.observeRows(); 50858 } 50859 unobserve({ except = [] } = {}) { 50860 if (!Array.isArray(except)) except = [ 50861 except 50862 ]; 50863 for (const observer of this.observers) { 50864 if (except.includes(observer)) continue; 50865 observer.disconnect(); 50866 } 50867 this.observers = [].concat(except); 50868 } 50869 initGrid() { 50870 const { categories } = (0, $7adb23b0109cc36a$export$2d0294657ab35f1b); 50871 this.refs.categories = /* @__PURE__ */ new Map(); 50872 const navKey = (0, $7adb23b0109cc36a$export$2d0294657ab35f1b).categories.map((category) => category.id).join(","); 50873 if (this.navKey && this.navKey != navKey) this.refs.scroll.current && (this.refs.scroll.current.scrollTop = 0); 50874 this.navKey = navKey; 50875 this.grid = []; 50876 this.grid.setsize = 0; 50877 const addRow = (rows, category) => { 50878 const row = []; 50879 row.__categoryId = category.id; 50880 row.__index = rows.length; 50881 this.grid.push(row); 50882 const rowIndex = this.grid.length - 1; 50883 const rowRef = rowIndex % $89bd6bb200cc8fef$var$Performance.rowsPerRender ? {} : (0, $fb96b826c0c5f37a$export$7d1e3a5e95ceca43)(); 50884 rowRef.index = rowIndex; 50885 rowRef.posinset = this.grid.setsize + 1; 50886 rows.push(rowRef); 50887 return row; 50888 }; 50889 for (let category1 of categories) { 50890 const rows = []; 50891 let row = addRow(rows, category1); 50892 for (let emoji of category1.emojis) { 50893 if (row.length == this.getPerLine()) row = addRow(rows, category1); 50894 this.grid.setsize += 1; 50895 row.push(emoji); 50896 } 50897 this.refs.categories.set(category1.id, { 50898 root: (0, $fb96b826c0c5f37a$export$7d1e3a5e95ceca43)(), 50899 rows 50900 }); 50901 } 50902 } 50903 initTheme(theme2) { 50904 if (theme2 != "auto") return theme2; 50905 if (!this.darkMedia) { 50906 this.darkMedia = matchMedia("(prefers-color-scheme: dark)"); 50907 if (this.darkMedia.media.match(/^not/)) return "light"; 50908 this.darkMedia.addEventListener("change", this.darkMediaCallback); 50909 } 50910 return this.darkMedia.matches ? "dark" : "light"; 50911 } 50912 initDynamicPerLine(props = this.props) { 50913 if (!props.dynamicWidth) return; 50914 const { element, emojiButtonSize } = props; 50915 const calculatePerLine = () => { 50916 const { width } = element.getBoundingClientRect(); 50917 return Math.floor(width / emojiButtonSize); 50918 }; 50919 const observer = new ResizeObserver(() => { 50920 this.unobserve({ 50921 except: observer 50922 }); 50923 this.setState({ 50924 perLine: calculatePerLine() 50925 }, () => { 50926 this.initGrid(); 50927 this.forceUpdate(() => { 50928 this.observeCategories(); 50929 this.observeRows(); 50930 }); 50931 }); 50932 }); 50933 observer.observe(element); 50934 this.observers.push(observer); 50935 return calculatePerLine(); 50936 } 50937 getPerLine() { 50938 return this.state.perLine || this.props.perLine; 50939 } 50940 getEmojiByPos([p1, p2]) { 50941 const grid = this.state.searchResults || this.grid; 50942 const emoji = grid[p1] && grid[p1][p2]; 50943 if (!emoji) return; 50944 return (0, $c4d155af13ad4d4b$export$2e2bcd8739ae039).get(emoji); 50945 } 50946 observeCategories() { 50947 const navigation = this.refs.navigation.current; 50948 if (!navigation) return; 50949 const visibleCategories = /* @__PURE__ */ new Map(); 50950 const setFocusedCategory = (categoryId) => { 50951 if (categoryId != navigation.state.categoryId) navigation.setState({ 50952 categoryId 50953 }); 50954 }; 50955 const observerOptions2 = { 50956 root: this.refs.scroll.current, 50957 threshold: [ 50958 0, 50959 1 50960 ] 50961 }; 50962 const observer = new IntersectionObserver((entries2) => { 50963 for (const entry of entries2) { 50964 const id3 = entry.target.dataset.id; 50965 visibleCategories.set(id3, entry.intersectionRatio); 50966 } 50967 const ratios = [ 50968 ...visibleCategories 50969 ]; 50970 for (const [id3, ratio] of ratios) if (ratio) { 50971 setFocusedCategory(id3); 50972 break; 50973 } 50974 }, observerOptions2); 50975 for (const { root } of this.refs.categories.values()) observer.observe(root.current); 50976 this.observers.push(observer); 50977 } 50978 observeRows() { 50979 const visibleRows = { 50980 ...this.state.visibleRows 50981 }; 50982 const observer = new IntersectionObserver((entries2) => { 50983 for (const entry of entries2) { 50984 const index = parseInt(entry.target.dataset.index); 50985 if (entry.isIntersecting) visibleRows[index] = true; 50986 else delete visibleRows[index]; 50987 } 50988 this.setState({ 50989 visibleRows 50990 }); 50991 }, { 50992 root: this.refs.scroll.current, 50993 rootMargin: `${this.props.emojiButtonSize * ($89bd6bb200cc8fef$var$Performance.rowsPerRender + 5)}px 0px ${this.props.emojiButtonSize * $89bd6bb200cc8fef$var$Performance.rowsPerRender}px` 50994 }); 50995 for (const { rows } of this.refs.categories.values()) { 50996 for (const row of rows) if (row.current) observer.observe(row.current); 50997 } 50998 this.observers.push(observer); 50999 } 51000 preventDefault(e2) { 51001 e2.preventDefault(); 51002 } 51003 unfocusSearch() { 51004 const input = this.refs.searchInput.current; 51005 if (!input) return; 51006 input.blur(); 51007 } 51008 navigate({ e: e2, input, left, right, up, down }) { 51009 const grid = this.state.searchResults || this.grid; 51010 if (!grid.length) return; 51011 let [p1, p2] = this.state.pos; 51012 const pos = (() => { 51013 if (p1 == 0) { 51014 if (p2 == 0 && !e2.repeat && (left || up)) return null; 51015 } 51016 if (p1 == -1) { 51017 if (!e2.repeat && (right || down) && input.selectionStart == input.value.length) return [ 51018 0, 51019 0 51020 ]; 51021 return null; 51022 } 51023 if (left || right) { 51024 let row = grid[p1]; 51025 const increment = left ? -1 : 1; 51026 p2 += increment; 51027 if (!row[p2]) { 51028 p1 += increment; 51029 row = grid[p1]; 51030 if (!row) { 51031 p1 = left ? 0 : grid.length - 1; 51032 p2 = left ? 0 : grid[p1].length - 1; 51033 return [ 51034 p1, 51035 p2 51036 ]; 51037 } 51038 p2 = left ? row.length - 1 : 0; 51039 } 51040 return [ 51041 p1, 51042 p2 51043 ]; 51044 } 51045 if (up || down) { 51046 p1 += up ? -1 : 1; 51047 const row = grid[p1]; 51048 if (!row) { 51049 p1 = up ? 0 : grid.length - 1; 51050 p2 = up ? 0 : grid[p1].length - 1; 51051 return [ 51052 p1, 51053 p2 51054 ]; 51055 } 51056 if (!row[p2]) p2 = row.length - 1; 51057 return [ 51058 p1, 51059 p2 51060 ]; 51061 } 51062 })(); 51063 if (pos) e2.preventDefault(); 51064 else { 51065 if (this.state.pos[0] > -1) this.setState({ 51066 pos: [ 51067 -1, 51068 -1 51069 ] 51070 }); 51071 return; 51072 } 51073 this.setState({ 51074 pos, 51075 keyboard: true 51076 }, () => { 51077 this.scrollTo({ 51078 row: pos[0] 51079 }); 51080 }); 51081 } 51082 scrollTo({ categoryId, row }) { 51083 const grid = this.state.searchResults || this.grid; 51084 if (!grid.length) return; 51085 const scroll = this.refs.scroll.current; 51086 const scrollRect = scroll.getBoundingClientRect(); 51087 let scrollTop = 0; 51088 if (row >= 0) categoryId = grid[row].__categoryId; 51089 if (categoryId) { 51090 const ref = this.refs[categoryId] || this.refs.categories.get(categoryId).root; 51091 const categoryRect = ref.current.getBoundingClientRect(); 51092 scrollTop = categoryRect.top - (scrollRect.top - scroll.scrollTop) + 1; 51093 } 51094 if (row >= 0) { 51095 if (!row) scrollTop = 0; 51096 else { 51097 const rowIndex = grid[row].__index; 51098 const rowTop = scrollTop + rowIndex * this.props.emojiButtonSize; 51099 const rowBot = rowTop + this.props.emojiButtonSize + this.props.emojiButtonSize * 0.88; 51100 if (rowTop < scroll.scrollTop) scrollTop = rowTop; 51101 else if (rowBot > scroll.scrollTop + scrollRect.height) scrollTop = rowBot - scrollRect.height; 51102 else return; 51103 } 51104 } 51105 this.ignoreMouse(); 51106 scroll.scrollTop = scrollTop; 51107 } 51108 ignoreMouse() { 51109 this.mouseIsIgnored = true; 51110 clearTimeout(this.ignoreMouseTimer); 51111 this.ignoreMouseTimer = setTimeout(() => { 51112 delete this.mouseIsIgnored; 51113 }, 100); 51114 } 51115 handleEmojiOver(pos) { 51116 if (this.mouseIsIgnored || this.state.showSkins) return; 51117 this.setState({ 51118 pos: pos || [ 51119 -1, 51120 -1 51121 ], 51122 keyboard: false 51123 }); 51124 } 51125 handleEmojiClick({ e: e2, emoji, pos }) { 51126 if (!this.props.onEmojiSelect) return; 51127 if (!emoji && pos) emoji = this.getEmojiByPos(pos); 51128 if (emoji) { 51129 const emojiData = (0, $693b183b0a78708f$export$d10ac59fbe52a745)(emoji, { 51130 skinIndex: this.state.skin - 1 51131 }); 51132 if (this.props.maxFrequentRows) (0, $b22cfd0a55410b4f$export$2e2bcd8739ae039).add(emojiData, this.props); 51133 this.props.onEmojiSelect(emojiData, e2); 51134 } 51135 } 51136 closeSkins() { 51137 if (!this.state.showSkins) return; 51138 this.setState({ 51139 showSkins: null, 51140 tempSkin: null 51141 }); 51142 this.base.removeEventListener("click", this.handleBaseClick); 51143 this.base.removeEventListener("keydown", this.handleBaseKeydown); 51144 } 51145 handleSkinMouseOver(tempSkin) { 51146 this.setState({ 51147 tempSkin 51148 }); 51149 } 51150 handleSkinClick(skin) { 51151 this.ignoreMouse(); 51152 this.closeSkins(); 51153 this.setState({ 51154 skin, 51155 tempSkin: null 51156 }); 51157 (0, $f72b75cf796873c7$export$2e2bcd8739ae039).set("skin", skin); 51158 } 51159 renderNav() { 51160 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)((0, $ec8c39fdad15601a$export$2e2bcd8739ae039), { 51161 ref: this.refs.navigation, 51162 icons: this.props.icons, 51163 theme: this.state.theme, 51164 dir: this.dir, 51165 unfocused: !!this.state.searchResults, 51166 position: this.props.navPosition, 51167 onClick: this.handleCategoryClick 51168 }, this.navKey); 51169 } 51170 renderPreview() { 51171 const emoji = this.getEmojiByPos(this.state.pos); 51172 const noSearchResults = this.state.searchResults && !this.state.searchResults.length; 51173 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51174 id: "preview", 51175 class: "flex flex-middle", 51176 dir: this.dir, 51177 "data-position": this.props.previewPosition, 51178 children: [ 51179 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51180 class: "flex flex-middle flex-grow", 51181 children: [ 51182 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51183 class: "flex flex-auto flex-middle flex-center", 51184 style: { 51185 height: this.props.emojiButtonSize, 51186 fontSize: this.props.emojiButtonSize 51187 }, 51188 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)((0, $254755d3f438722f$export$2e2bcd8739ae039), { 51189 emoji, 51190 id: noSearchResults ? this.props.noResultsEmoji || "cry" : this.props.previewEmoji || (this.props.previewPosition == "top" ? "point_down" : "point_up"), 51191 set: this.props.set, 51192 size: this.props.emojiButtonSize, 51193 skin: this.state.tempSkin || this.state.skin, 51194 spritesheet: true, 51195 getSpritesheetURL: this.props.getSpritesheetURL 51196 }) 51197 }), 51198 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51199 class: `margin-${this.dir[0]}`, 51200 children: emoji || noSearchResults ? /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51201 class: `padding-${this.dir[2]} align-${this.dir[0]}`, 51202 children: [ 51203 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51204 class: "preview-title ellipsis", 51205 children: emoji ? emoji.name : (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).search_no_results_1 51206 }), 51207 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51208 class: "preview-subtitle ellipsis color-c", 51209 children: emoji ? emoji.skins[0].shortcodes : (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).search_no_results_2 51210 }) 51211 ] 51212 }) : /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51213 class: "preview-placeholder color-c", 51214 children: (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).pick 51215 }) 51216 }) 51217 ] 51218 }), 51219 !emoji && this.props.skinTonePosition == "preview" && this.renderSkinToneButton() 51220 ] 51221 }); 51222 } 51223 renderEmojiButton(emoji, { pos, posinset, grid }) { 51224 const size2 = this.props.emojiButtonSize; 51225 const skin = this.state.tempSkin || this.state.skin; 51226 const emojiSkin = emoji.skins[skin - 1] || emoji.skins[0]; 51227 const native = emojiSkin.native; 51228 const selected = (0, $693b183b0a78708f$export$9cb4719e2e525b7a)(this.state.pos, pos); 51229 const key = pos.concat(emoji.id).join(""); 51230 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)((0, $e0d4dda61265ff1e$export$2e2bcd8739ae039), { 51231 selected, 51232 skin, 51233 size: size2, 51234 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("button", { 51235 "aria-label": native, 51236 "aria-selected": selected || void 0, 51237 "aria-posinset": posinset, 51238 "aria-setsize": grid.setsize, 51239 "data-keyboard": this.state.keyboard, 51240 title: this.props.previewPosition == "none" ? emoji.name : void 0, 51241 type: "button", 51242 class: "flex flex-center flex-middle", 51243 tabindex: "-1", 51244 onClick: (e2) => this.handleEmojiClick({ 51245 e: e2, 51246 emoji 51247 }), 51248 onMouseEnter: () => this.handleEmojiOver(pos), 51249 onMouseLeave: () => this.handleEmojiOver(), 51250 style: { 51251 width: this.props.emojiButtonSize, 51252 height: this.props.emojiButtonSize, 51253 fontSize: this.props.emojiSize, 51254 lineHeight: 0 51255 }, 51256 children: [ 51257 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51258 "aria-hidden": "true", 51259 class: "background", 51260 style: { 51261 borderRadius: this.props.emojiButtonRadius, 51262 backgroundColor: this.props.emojiButtonColors ? this.props.emojiButtonColors[(posinset - 1) % this.props.emojiButtonColors.length] : void 0 51263 } 51264 }), 51265 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)((0, $254755d3f438722f$export$2e2bcd8739ae039), { 51266 emoji, 51267 set: this.props.set, 51268 size: this.props.emojiSize, 51269 skin, 51270 spritesheet: true, 51271 getSpritesheetURL: this.props.getSpritesheetURL 51272 }) 51273 ] 51274 }) 51275 }, key); 51276 } 51277 renderSearch() { 51278 const renderSkinTone = this.props.previewPosition == "none" || this.props.skinTonePosition == "search"; 51279 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51280 children: [ 51281 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51282 class: "spacer" 51283 }), 51284 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51285 class: "flex flex-middle", 51286 children: [ 51287 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51288 class: "search relative flex-grow", 51289 children: [ 51290 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("input", { 51291 type: "search", 51292 ref: this.refs.searchInput, 51293 placeholder: (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).search, 51294 onClick: this.handleSearchClick, 51295 onInput: this.handleSearchInput, 51296 onKeyDown: this.handleSearchKeyDown, 51297 autoComplete: "off" 51298 }), 51299 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("span", { 51300 class: "icon loupe flex", 51301 children: (0, $fcccfb36ed0cde68$export$2e2bcd8739ae039).search.loupe 51302 }), 51303 this.state.searchResults && /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("button", { 51304 title: "Clear", 51305 "aria-label": "Clear", 51306 type: "button", 51307 class: "icon delete flex", 51308 onClick: this.clearSearch, 51309 onMouseDown: this.preventDefault, 51310 children: (0, $fcccfb36ed0cde68$export$2e2bcd8739ae039).search.delete 51311 }) 51312 ] 51313 }), 51314 renderSkinTone && this.renderSkinToneButton() 51315 ] 51316 }) 51317 ] 51318 }); 51319 } 51320 renderSearchResults() { 51321 const { searchResults } = this.state; 51322 if (!searchResults) return null; 51323 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51324 class: "category", 51325 ref: this.refs.search, 51326 children: [ 51327 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51328 class: `sticky padding-small align-${this.dir[0]}`, 51329 children: (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).categories.search 51330 }), 51331 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51332 children: !searchResults.length ? /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51333 class: `padding-small align-${this.dir[0]}`, 51334 children: this.props.onAddCustomEmoji && /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("a", { 51335 onClick: this.props.onAddCustomEmoji, 51336 children: (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).add_custom 51337 }) 51338 }) : searchResults.map((row, i2) => { 51339 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51340 class: "flex", 51341 children: row.map((emoji, ii) => { 51342 return this.renderEmojiButton(emoji, { 51343 pos: [ 51344 i2, 51345 ii 51346 ], 51347 posinset: i2 * this.props.perLine + ii + 1, 51348 grid: searchResults 51349 }); 51350 }) 51351 }); 51352 }) 51353 }) 51354 ] 51355 }); 51356 } 51357 renderCategories() { 51358 const { categories } = (0, $7adb23b0109cc36a$export$2d0294657ab35f1b); 51359 const hidden = !!this.state.searchResults; 51360 const perLine = this.getPerLine(); 51361 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51362 style: { 51363 visibility: hidden ? "hidden" : void 0, 51364 display: hidden ? "none" : void 0, 51365 height: "100%" 51366 }, 51367 children: categories.map((category) => { 51368 const { root, rows } = this.refs.categories.get(category.id); 51369 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51370 "data-id": category.target ? category.target.id : category.id, 51371 class: "category", 51372 ref: root, 51373 children: [ 51374 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51375 class: `sticky padding-small align-${this.dir[0]}`, 51376 children: category.name || (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).categories[category.id] 51377 }), 51378 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51379 class: "relative", 51380 style: { 51381 height: rows.length * this.props.emojiButtonSize 51382 }, 51383 children: rows.map((row, i2) => { 51384 const targetRow = row.index - row.index % $89bd6bb200cc8fef$var$Performance.rowsPerRender; 51385 const visible = this.state.visibleRows[targetRow]; 51386 const ref = "current" in row ? row : void 0; 51387 if (!visible && !ref) return null; 51388 const start3 = i2 * perLine; 51389 const end = start3 + perLine; 51390 const emojiIds = category.emojis.slice(start3, end); 51391 if (emojiIds.length < perLine) emojiIds.push(...new Array(perLine - emojiIds.length)); 51392 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51393 "data-index": row.index, 51394 ref, 51395 class: "flex row", 51396 style: { 51397 top: i2 * this.props.emojiButtonSize 51398 }, 51399 children: visible && emojiIds.map((emojiId, ii) => { 51400 if (!emojiId) return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51401 style: { 51402 width: this.props.emojiButtonSize, 51403 height: this.props.emojiButtonSize 51404 } 51405 }); 51406 const emoji = (0, $c4d155af13ad4d4b$export$2e2bcd8739ae039).get(emojiId); 51407 return this.renderEmojiButton(emoji, { 51408 pos: [ 51409 row.index, 51410 ii 51411 ], 51412 posinset: row.posinset + ii, 51413 grid: this.grid 51414 }); 51415 }) 51416 }, row.index); 51417 }) 51418 }) 51419 ] 51420 }); 51421 }) 51422 }); 51423 } 51424 renderSkinToneButton() { 51425 if (this.props.skinTonePosition == "none") return null; 51426 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51427 class: "flex flex-auto flex-center flex-middle", 51428 style: { 51429 position: "relative", 51430 width: this.props.emojiButtonSize, 51431 height: this.props.emojiButtonSize 51432 }, 51433 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("button", { 51434 type: "button", 51435 ref: this.refs.skinToneButton, 51436 class: "skin-tone-button flex flex-auto flex-center flex-middle", 51437 "aria-selected": this.state.showSkins ? "" : void 0, 51438 "aria-label": (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).skins.choose, 51439 title: (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).skins.choose, 51440 onClick: this.openSkins, 51441 style: { 51442 width: this.props.emojiSize, 51443 height: this.props.emojiSize 51444 }, 51445 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("span", { 51446 class: `skin-tone skin-tone-${this.state.skin}` 51447 }) 51448 }) 51449 }); 51450 } 51451 renderLiveRegion() { 51452 const emoji = this.getEmojiByPos(this.state.pos); 51453 const contents = emoji ? emoji.name : ""; 51454 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51455 "aria-live": "polite", 51456 class: "sr-only", 51457 children: contents 51458 }); 51459 } 51460 renderSkins() { 51461 const skinToneButton = this.refs.skinToneButton.current; 51462 const skinToneButtonRect = skinToneButton.getBoundingClientRect(); 51463 const baseRect = this.base.getBoundingClientRect(); 51464 const position = {}; 51465 if (this.dir == "ltr") position.right = baseRect.right - skinToneButtonRect.right - 3; 51466 else position.left = skinToneButtonRect.left - baseRect.left - 3; 51467 if (this.props.previewPosition == "bottom" && this.props.skinTonePosition == "preview") position.bottom = baseRect.bottom - skinToneButtonRect.top + 6; 51468 else { 51469 position.top = skinToneButtonRect.bottom - baseRect.top + 3; 51470 position.bottom = "auto"; 51471 } 51472 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51473 ref: this.refs.menu, 51474 role: "radiogroup", 51475 dir: this.dir, 51476 "aria-label": (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).skins.choose, 51477 class: "menu hidden", 51478 "data-position": position.top ? "top" : "bottom", 51479 style: position, 51480 children: [ 51481 ...Array(6).keys() 51482 ].map((i2) => { 51483 const skin = i2 + 1; 51484 const checked = this.state.skin == skin; 51485 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51486 children: [ 51487 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("input", { 51488 type: "radio", 51489 name: "skin-tone", 51490 value: skin, 51491 "aria-label": (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).skins[skin], 51492 ref: checked ? this.refs.skinToneRadio : null, 51493 defaultChecked: checked, 51494 onChange: () => this.handleSkinMouseOver(skin), 51495 onKeyDown: (e2) => { 51496 if (e2.code == "Enter" || e2.code == "Space" || e2.code == "Tab") { 51497 e2.preventDefault(); 51498 this.handleSkinClick(skin); 51499 } 51500 } 51501 }), 51502 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("button", { 51503 "aria-hidden": "true", 51504 tabindex: "-1", 51505 onClick: () => this.handleSkinClick(skin), 51506 onMouseEnter: () => this.handleSkinMouseOver(skin), 51507 onMouseLeave: () => this.handleSkinMouseOver(), 51508 class: "option flex flex-grow flex-middle", 51509 children: [ 51510 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("span", { 51511 class: `skin-tone skin-tone-${skin}` 51512 }), 51513 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("span", { 51514 class: "margin-small-lr", 51515 children: (0, $7adb23b0109cc36a$export$dbe3113d60765c1a).skins[skin] 51516 }) 51517 ] 51518 }) 51519 ] 51520 }); 51521 }) 51522 }); 51523 } 51524 render() { 51525 const lineWidth = this.props.perLine * this.props.emojiButtonSize; 51526 return /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("section", { 51527 id: "root", 51528 class: "flex flex-column", 51529 dir: this.dir, 51530 style: { 51531 width: this.props.dynamicWidth ? "100%" : `calc(${lineWidth}px + (var(--padding) + var(--sidebar-width)))` 51532 }, 51533 "data-emoji-set": this.props.set, 51534 "data-theme": this.state.theme, 51535 "data-menu": this.state.showSkins ? "" : void 0, 51536 children: [ 51537 this.props.previewPosition == "top" && this.renderPreview(), 51538 this.props.navPosition == "top" && this.renderNav(), 51539 this.props.searchPosition == "sticky" && /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51540 class: "padding-lr", 51541 children: this.renderSearch() 51542 }), 51543 /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51544 ref: this.refs.scroll, 51545 class: "scroll flex-grow padding-lr", 51546 children: /* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)("div", { 51547 style: { 51548 width: this.props.dynamicWidth ? "100%" : lineWidth, 51549 height: "100%" 51550 }, 51551 children: [ 51552 this.props.searchPosition == "static" && this.renderSearch(), 51553 this.renderSearchResults(), 51554 this.renderCategories() 51555 ] 51556 }) 51557 }), 51558 this.props.navPosition == "bottom" && this.renderNav(), 51559 this.props.previewPosition == "bottom" && this.renderPreview(), 51560 this.state.showSkins && this.renderSkins(), 51561 this.renderLiveRegion() 51562 ] 51563 }); 51564 } 51565 constructor(props) { 51566 super(); 51567 (0, $c770c458706daa72$export$2e2bcd8739ae039)(this, "darkMediaCallback", () => { 51568 if (this.props.theme != "auto") return; 51569 this.setState({ 51570 theme: this.darkMedia.matches ? "dark" : "light" 51571 }); 51572 }); 51573 (0, $c770c458706daa72$export$2e2bcd8739ae039)(this, "handleClickOutside", (e2) => { 51574 const { element } = this.props; 51575 if (e2.target != element) { 51576 if (this.state.showSkins) this.closeSkins(); 51577 if (this.props.onClickOutside) this.props.onClickOutside(e2); 51578 } 51579 }); 51580 (0, $c770c458706daa72$export$2e2bcd8739ae039)(this, "handleBaseClick", (e2) => { 51581 if (!this.state.showSkins) return; 51582 if (!e2.target.closest(".menu")) { 51583 e2.preventDefault(); 51584 e2.stopImmediatePropagation(); 51585 this.closeSkins(); 51586 } 51587 }); 51588 (0, $c770c458706daa72$export$2e2bcd8739ae039)(this, "handleBaseKeydown", (e2) => { 51589 if (!this.state.showSkins) return; 51590 if (e2.key == "Escape") { 51591 e2.preventDefault(); 51592 e2.stopImmediatePropagation(); 51593 this.closeSkins(); 51594 } 51595 }); 51596 (0, $c770c458706daa72$export$2e2bcd8739ae039)(this, "handleSearchClick", () => { 51597 const emoji = this.getEmojiByPos(this.state.pos); 51598 if (!emoji) return; 51599 this.setState({ 51600 pos: [ 51601 -1, 51602 -1 51603 ] 51604 }); 51605 }); 51606 (0, $c770c458706daa72$export$2e2bcd8739ae039)(this, "handleSearchInput", async () => { 51607 const input = this.refs.searchInput.current; 51608 if (!input) return; 51609 const { value } = input; 51610 const searchResults = await (0, $c4d155af13ad4d4b$export$2e2bcd8739ae039).search(value); 51611 const afterRender = () => { 51612 if (!this.refs.scroll.current) return; 51613 this.refs.scroll.current.scrollTop = 0; 51614 }; 51615 if (!searchResults) return this.setState({ 51616 searchResults, 51617 pos: [ 51618 -1, 51619 -1 51620 ] 51621 }, afterRender); 51622 const pos = input.selectionStart == input.value.length ? [ 51623 0, 51624 0 51625 ] : [ 51626 -1, 51627 -1 51628 ]; 51629 const grid = []; 51630 grid.setsize = searchResults.length; 51631 let row = null; 51632 for (let emoji of searchResults) { 51633 if (!grid.length || row.length == this.getPerLine()) { 51634 row = []; 51635 row.__categoryId = "search"; 51636 row.__index = grid.length; 51637 grid.push(row); 51638 } 51639 row.push(emoji); 51640 } 51641 this.ignoreMouse(); 51642 this.setState({ 51643 searchResults: grid, 51644 pos 51645 }, afterRender); 51646 }); 51647 (0, $c770c458706daa72$export$2e2bcd8739ae039)(this, "handleSearchKeyDown", (e2) => { 51648 const input = e2.currentTarget; 51649 e2.stopImmediatePropagation(); 51650 switch (e2.key) { 51651 case "ArrowLeft": 51652 this.navigate({ 51653 e: e2, 51654 input, 51655 left: true 51656 }); 51657 break; 51658 case "ArrowRight": 51659 this.navigate({ 51660 e: e2, 51661 input, 51662 right: true 51663 }); 51664 break; 51665 case "ArrowUp": 51666 this.navigate({ 51667 e: e2, 51668 input, 51669 up: true 51670 }); 51671 break; 51672 case "ArrowDown": 51673 this.navigate({ 51674 e: e2, 51675 input, 51676 down: true 51677 }); 51678 break; 51679 case "Enter": 51680 e2.preventDefault(); 51681 this.handleEmojiClick({ 51682 e: e2, 51683 pos: this.state.pos 51684 }); 51685 break; 51686 case "Escape": 51687 e2.preventDefault(); 51688 if (this.state.searchResults) this.clearSearch(); 51689 else this.unfocusSearch(); 51690 break; 51691 default: 51692 break; 51693 } 51694 }); 51695 (0, $c770c458706daa72$export$2e2bcd8739ae039)(this, "clearSearch", () => { 51696 const input = this.refs.searchInput.current; 51697 if (!input) return; 51698 input.value = ""; 51699 input.focus(); 51700 this.handleSearchInput(); 51701 }); 51702 (0, $c770c458706daa72$export$2e2bcd8739ae039)(this, "handleCategoryClick", ({ category, i: i2 }) => { 51703 this.scrollTo(i2 == 0 ? { 51704 row: -1 51705 } : { 51706 categoryId: category.id 51707 }); 51708 }); 51709 (0, $c770c458706daa72$export$2e2bcd8739ae039)(this, "openSkins", (e2) => { 51710 const { currentTarget } = e2; 51711 const rect = currentTarget.getBoundingClientRect(); 51712 this.setState({ 51713 showSkins: rect 51714 }, async () => { 51715 await (0, $693b183b0a78708f$export$e772c8ff12451969)(2); 51716 const menu = this.refs.menu.current; 51717 if (!menu) return; 51718 menu.classList.remove("hidden"); 51719 this.refs.skinToneRadio.current.focus(); 51720 this.base.addEventListener("click", this.handleBaseClick, true); 51721 this.base.addEventListener("keydown", this.handleBaseKeydown, true); 51722 }); 51723 }); 51724 this.observers = []; 51725 this.state = { 51726 pos: [ 51727 -1, 51728 -1 51729 ], 51730 perLine: this.initDynamicPerLine(props), 51731 visibleRows: { 51732 0: true 51733 }, 51734 ...this.getInitialState(props) 51735 }; 51736 } 51737 }; 51738 var $efa000751917694d$export$2e2bcd8739ae039 = class extends (0, $26f27c338a96b1a6$export$2e2bcd8739ae039) { 51739 async connectedCallback() { 51740 const props = (0, $7adb23b0109cc36a$export$75fe5f91d452f94b)(this.props, (0, $b247ea80b67298d5$export$2e2bcd8739ae039), this); 51741 props.element = this; 51742 props.ref = (component) => { 51743 this.component = component; 51744 }; 51745 await (0, $7adb23b0109cc36a$export$2cd8252107eb640b)(props); 51746 if (this.disconnected) return; 51747 (0, $fb96b826c0c5f37a$export$b3890eb0ae9dca99)(/* @__PURE__ */ (0, $bd9dd35321b03dd4$export$34b9dba7ce09269b)((0, $89bd6bb200cc8fef$export$2e2bcd8739ae039), { 51748 ...props 51749 }), this.shadowRoot); 51750 } 51751 constructor(props) { 51752 super(props, { 51753 styles: (0, /* @__PURE__ */ $parcel$interopDefault($329d53ba9fd7125f$exports)) 51754 }); 51755 } 51756 }; 51757 (0, $c770c458706daa72$export$2e2bcd8739ae039)($efa000751917694d$export$2e2bcd8739ae039, "Props", (0, $b247ea80b67298d5$export$2e2bcd8739ae039)); 51758 if (typeof customElements !== "undefined" && !customElements.get("em-emoji-picker")) customElements.define("em-emoji-picker", $efa000751917694d$export$2e2bcd8739ae039); 51759 var $329d53ba9fd7125f$exports = {}; 51760 $329d53ba9fd7125f$exports = ':host {\n width: min-content;\n height: 435px;\n min-height: 230px;\n border-radius: var(--border-radius);\n box-shadow: var(--shadow);\n --border-radius: 10px;\n --category-icon-size: 18px;\n --font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;\n --font-size: 15px;\n --preview-placeholder-size: 21px;\n --preview-title-size: 1.1em;\n --preview-subtitle-size: .9em;\n --shadow-color: 0deg 0% 0%;\n --shadow: .3px .5px 2.7px hsl(var(--shadow-color) / .14), .4px .8px 1px -3.2px hsl(var(--shadow-color) / .14), 1px 2px 2.5px -4.5px hsl(var(--shadow-color) / .14);\n display: flex;\n}\n\n[data-theme="light"] {\n --em-rgb-color: var(--rgb-color, 34, 36, 39);\n --em-rgb-accent: var(--rgb-accent, 34, 102, 237);\n --em-rgb-background: var(--rgb-background, 255, 255, 255);\n --em-rgb-input: var(--rgb-input, 255, 255, 255);\n --em-color-border: var(--color-border, rgba(0, 0, 0, .05));\n --em-color-border-over: var(--color-border-over, rgba(0, 0, 0, .1));\n}\n\n[data-theme="dark"] {\n --em-rgb-color: var(--rgb-color, 222, 222, 221);\n --em-rgb-accent: var(--rgb-accent, 58, 130, 247);\n --em-rgb-background: var(--rgb-background, 21, 22, 23);\n --em-rgb-input: var(--rgb-input, 0, 0, 0);\n --em-color-border: var(--color-border, rgba(255, 255, 255, .1));\n --em-color-border-over: var(--color-border-over, rgba(255, 255, 255, .2));\n}\n\n#root {\n --color-a: rgb(var(--em-rgb-color));\n --color-b: rgba(var(--em-rgb-color), .65);\n --color-c: rgba(var(--em-rgb-color), .45);\n --padding: 12px;\n --padding-small: calc(var(--padding) / 2);\n --sidebar-width: 16px;\n --duration: 225ms;\n --duration-fast: 125ms;\n --duration-instant: 50ms;\n --easing: cubic-bezier(.4, 0, .2, 1);\n width: 100%;\n text-align: left;\n border-radius: var(--border-radius);\n background-color: rgb(var(--em-rgb-background));\n position: relative;\n}\n\n@media (prefers-reduced-motion) {\n #root {\n --duration: 0;\n --duration-fast: 0;\n --duration-instant: 0;\n }\n}\n\n#root[data-menu] button {\n cursor: auto;\n}\n\n#root[data-menu] .menu button {\n cursor: pointer;\n}\n\n:host, #root, input, button {\n color: rgb(var(--em-rgb-color));\n font-family: var(--font-family);\n font-size: var(--font-size);\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n line-height: normal;\n}\n\n*, :before, :after {\n box-sizing: border-box;\n min-width: 0;\n margin: 0;\n padding: 0;\n}\n\n.relative {\n position: relative;\n}\n\n.flex {\n display: flex;\n}\n\n.flex-auto {\n flex: none;\n}\n\n.flex-center {\n justify-content: center;\n}\n\n.flex-column {\n flex-direction: column;\n}\n\n.flex-grow {\n flex: auto;\n}\n\n.flex-middle {\n align-items: center;\n}\n\n.flex-wrap {\n flex-wrap: wrap;\n}\n\n.padding {\n padding: var(--padding);\n}\n\n.padding-t {\n padding-top: var(--padding);\n}\n\n.padding-lr {\n padding-left: var(--padding);\n padding-right: var(--padding);\n}\n\n.padding-r {\n padding-right: var(--padding);\n}\n\n.padding-small {\n padding: var(--padding-small);\n}\n\n.padding-small-b {\n padding-bottom: var(--padding-small);\n}\n\n.padding-small-lr {\n padding-left: var(--padding-small);\n padding-right: var(--padding-small);\n}\n\n.margin {\n margin: var(--padding);\n}\n\n.margin-r {\n margin-right: var(--padding);\n}\n\n.margin-l {\n margin-left: var(--padding);\n}\n\n.margin-small-l {\n margin-left: var(--padding-small);\n}\n\n.margin-small-lr {\n margin-left: var(--padding-small);\n margin-right: var(--padding-small);\n}\n\n.align-l {\n text-align: left;\n}\n\n.align-r {\n text-align: right;\n}\n\n.color-a {\n color: var(--color-a);\n}\n\n.color-b {\n color: var(--color-b);\n}\n\n.color-c {\n color: var(--color-c);\n}\n\n.ellipsis {\n white-space: nowrap;\n max-width: 100%;\n width: auto;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.sr-only {\n width: 1px;\n height: 1px;\n position: absolute;\n top: auto;\n left: -10000px;\n overflow: hidden;\n}\n\na {\n cursor: pointer;\n color: rgb(var(--em-rgb-accent));\n}\n\na:hover {\n text-decoration: underline;\n}\n\n.spacer {\n height: 10px;\n}\n\n[dir="rtl"] .scroll {\n padding-left: 0;\n padding-right: var(--padding);\n}\n\n.scroll {\n padding-right: 0;\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.scroll::-webkit-scrollbar {\n width: var(--sidebar-width);\n height: var(--sidebar-width);\n}\n\n.scroll::-webkit-scrollbar-track {\n border: 0;\n}\n\n.scroll::-webkit-scrollbar-button {\n width: 0;\n height: 0;\n display: none;\n}\n\n.scroll::-webkit-scrollbar-corner {\n background-color: rgba(0, 0, 0, 0);\n}\n\n.scroll::-webkit-scrollbar-thumb {\n min-height: 20%;\n min-height: 65px;\n border: 4px solid rgb(var(--em-rgb-background));\n border-radius: 8px;\n}\n\n.scroll::-webkit-scrollbar-thumb:hover {\n background-color: var(--em-color-border-over) !important;\n}\n\n.scroll:hover::-webkit-scrollbar-thumb {\n background-color: var(--em-color-border);\n}\n\n.sticky {\n z-index: 1;\n background-color: rgba(var(--em-rgb-background), .9);\n -webkit-backdrop-filter: blur(4px);\n backdrop-filter: blur(4px);\n font-weight: 500;\n position: sticky;\n top: -1px;\n}\n\n[dir="rtl"] .search input[type="search"] {\n padding: 10px 2.2em 10px 2em;\n}\n\n[dir="rtl"] .search .loupe {\n left: auto;\n right: .7em;\n}\n\n[dir="rtl"] .search .delete {\n left: .7em;\n right: auto;\n}\n\n.search {\n z-index: 2;\n position: relative;\n}\n\n.search input, .search button {\n font-size: calc(var(--font-size) - 1px);\n}\n\n.search input[type="search"] {\n width: 100%;\n background-color: var(--em-color-border);\n transition-duration: var(--duration);\n transition-property: background-color, box-shadow;\n transition-timing-function: var(--easing);\n border: 0;\n border-radius: 10px;\n outline: 0;\n padding: 10px 2em 10px 2.2em;\n display: block;\n}\n\n.search input[type="search"]::-ms-input-placeholder {\n color: inherit;\n opacity: .6;\n}\n\n.search input[type="search"]::placeholder {\n color: inherit;\n opacity: .6;\n}\n\n.search input[type="search"], .search input[type="search"]::-webkit-search-decoration, .search input[type="search"]::-webkit-search-cancel-button, .search input[type="search"]::-webkit-search-results-button, .search input[type="search"]::-webkit-search-results-decoration {\n -webkit-appearance: none;\n -ms-appearance: none;\n appearance: none;\n}\n\n.search input[type="search"]:focus {\n background-color: rgb(var(--em-rgb-input));\n box-shadow: inset 0 0 0 1px rgb(var(--em-rgb-accent)), 0 1px 3px rgba(65, 69, 73, .2);\n}\n\n.search .icon {\n z-index: 1;\n color: rgba(var(--em-rgb-color), .7);\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n}\n\n.search .loupe {\n pointer-events: none;\n left: .7em;\n}\n\n.search .delete {\n right: .7em;\n}\n\nsvg {\n fill: currentColor;\n width: 1em;\n height: 1em;\n}\n\nbutton {\n -webkit-appearance: none;\n -ms-appearance: none;\n appearance: none;\n cursor: pointer;\n color: currentColor;\n background-color: rgba(0, 0, 0, 0);\n border: 0;\n}\n\n#nav {\n z-index: 2;\n padding-top: 12px;\n padding-bottom: 12px;\n padding-right: var(--sidebar-width);\n position: relative;\n}\n\n#nav button {\n color: var(--color-b);\n transition: color var(--duration) var(--easing);\n}\n\n#nav button:hover {\n color: var(--color-a);\n}\n\n#nav svg, #nav img {\n width: var(--category-icon-size);\n height: var(--category-icon-size);\n}\n\n#nav[dir="rtl"] .bar {\n left: auto;\n right: 0;\n}\n\n#nav .bar {\n width: 100%;\n height: 3px;\n background-color: rgb(var(--em-rgb-accent));\n transition: transform var(--duration) var(--easing);\n border-radius: 3px 3px 0 0;\n position: absolute;\n bottom: -12px;\n left: 0;\n}\n\n#nav button[aria-selected] {\n color: rgb(var(--em-rgb-accent));\n}\n\n#preview {\n z-index: 2;\n padding: calc(var(--padding) + 4px) var(--padding);\n padding-right: var(--sidebar-width);\n position: relative;\n}\n\n#preview .preview-placeholder {\n font-size: var(--preview-placeholder-size);\n}\n\n#preview .preview-title {\n font-size: var(--preview-title-size);\n}\n\n#preview .preview-subtitle {\n font-size: var(--preview-subtitle-size);\n}\n\n#nav:before, #preview:before {\n content: "";\n height: 2px;\n position: absolute;\n left: 0;\n right: 0;\n}\n\n#nav[data-position="top"]:before, #preview[data-position="top"]:before {\n background: linear-gradient(to bottom, var(--em-color-border), transparent);\n top: 100%;\n}\n\n#nav[data-position="bottom"]:before, #preview[data-position="bottom"]:before {\n background: linear-gradient(to top, var(--em-color-border), transparent);\n bottom: 100%;\n}\n\n.category:last-child {\n min-height: calc(100% + 1px);\n}\n\n.category button {\n font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, sans-serif;\n position: relative;\n}\n\n.category button > * {\n position: relative;\n}\n\n.category button .background {\n opacity: 0;\n background-color: var(--em-color-border);\n transition: opacity var(--duration-fast) var(--easing) var(--duration-instant);\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n}\n\n.category button:hover .background {\n transition-duration: var(--duration-instant);\n transition-delay: 0s;\n}\n\n.category button[aria-selected] .background {\n opacity: 1;\n}\n\n.category button[data-keyboard] .background {\n transition: none;\n}\n\n.row {\n width: 100%;\n position: absolute;\n top: 0;\n left: 0;\n}\n\n.skin-tone-button {\n border: 1px solid rgba(0, 0, 0, 0);\n border-radius: 100%;\n}\n\n.skin-tone-button:hover {\n border-color: var(--em-color-border);\n}\n\n.skin-tone-button:active .skin-tone {\n transform: scale(.85) !important;\n}\n\n.skin-tone-button .skin-tone {\n transition: transform var(--duration) var(--easing);\n}\n\n.skin-tone-button[aria-selected] {\n background-color: var(--em-color-border);\n border-top-color: rgba(0, 0, 0, .05);\n border-bottom-color: rgba(0, 0, 0, 0);\n border-left-width: 0;\n border-right-width: 0;\n}\n\n.skin-tone-button[aria-selected] .skin-tone {\n transform: scale(.9);\n}\n\n.menu {\n z-index: 2;\n white-space: nowrap;\n border: 1px solid var(--em-color-border);\n background-color: rgba(var(--em-rgb-background), .9);\n -webkit-backdrop-filter: blur(4px);\n backdrop-filter: blur(4px);\n transition-property: opacity, transform;\n transition-duration: var(--duration);\n transition-timing-function: var(--easing);\n border-radius: 10px;\n padding: 4px;\n position: absolute;\n box-shadow: 1px 1px 5px rgba(0, 0, 0, .05);\n}\n\n.menu.hidden {\n opacity: 0;\n}\n\n.menu[data-position="bottom"] {\n transform-origin: 100% 100%;\n}\n\n.menu[data-position="bottom"].hidden {\n transform: scale(.9)rotate(-3deg)translateY(5%);\n}\n\n.menu[data-position="top"] {\n transform-origin: 100% 0;\n}\n\n.menu[data-position="top"].hidden {\n transform: scale(.9)rotate(3deg)translateY(-5%);\n}\n\n.menu input[type="radio"] {\n clip: rect(0 0 0 0);\n width: 1px;\n height: 1px;\n border: 0;\n margin: 0;\n padding: 0;\n position: absolute;\n overflow: hidden;\n}\n\n.menu input[type="radio"]:checked + .option {\n box-shadow: 0 0 0 2px rgb(var(--em-rgb-accent));\n}\n\n.option {\n width: 100%;\n border-radius: 6px;\n padding: 4px 6px;\n}\n\n.option:hover {\n color: #fff;\n background-color: rgb(var(--em-rgb-accent));\n}\n\n.skin-tone {\n width: 16px;\n height: 16px;\n border-radius: 100%;\n display: inline-block;\n position: relative;\n overflow: hidden;\n}\n\n.skin-tone:after {\n content: "";\n mix-blend-mode: overlay;\n background: linear-gradient(rgba(255, 255, 255, .2), rgba(0, 0, 0, 0));\n border: 1px solid rgba(0, 0, 0, .8);\n border-radius: 100%;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n box-shadow: inset 0 -2px 3px #000, inset 0 1px 2px #fff;\n}\n\n.skin-tone-1 {\n background-color: #ffc93a;\n}\n\n.skin-tone-2 {\n background-color: #ffdab7;\n}\n\n.skin-tone-3 {\n background-color: #e7b98f;\n}\n\n.skin-tone-4 {\n background-color: #c88c61;\n}\n\n.skin-tone-5 {\n background-color: #a46134;\n}\n\n.skin-tone-6 {\n background-color: #5d4437;\n}\n\n[data-index] {\n justify-content: space-between;\n}\n\n[data-emoji-set="twitter"] .skin-tone:after {\n box-shadow: none;\n border-color: rgba(0, 0, 0, .5);\n}\n\n[data-emoji-set="twitter"] .skin-tone-1 {\n background-color: #fade72;\n}\n\n[data-emoji-set="twitter"] .skin-tone-2 {\n background-color: #f3dfd0;\n}\n\n[data-emoji-set="twitter"] .skin-tone-3 {\n background-color: #eed3a8;\n}\n\n[data-emoji-set="twitter"] .skin-tone-4 {\n background-color: #cfad8d;\n}\n\n[data-emoji-set="twitter"] .skin-tone-5 {\n background-color: #a8805d;\n}\n\n[data-emoji-set="twitter"] .skin-tone-6 {\n background-color: #765542;\n}\n\n[data-emoji-set="google"] .skin-tone:after {\n box-shadow: inset 0 0 2px 2px rgba(0, 0, 0, .4);\n}\n\n[data-emoji-set="google"] .skin-tone-1 {\n background-color: #f5c748;\n}\n\n[data-emoji-set="google"] .skin-tone-2 {\n background-color: #f1d5aa;\n}\n\n[data-emoji-set="google"] .skin-tone-3 {\n background-color: #d4b48d;\n}\n\n[data-emoji-set="google"] .skin-tone-4 {\n background-color: #aa876b;\n}\n\n[data-emoji-set="google"] .skin-tone-5 {\n background-color: #916544;\n}\n\n[data-emoji-set="google"] .skin-tone-6 {\n background-color: #61493f;\n}\n\n[data-emoji-set="facebook"] .skin-tone:after {\n border-color: rgba(0, 0, 0, .4);\n box-shadow: inset 0 -2px 3px #000, inset 0 1px 4px #fff;\n}\n\n[data-emoji-set="facebook"] .skin-tone-1 {\n background-color: #f5c748;\n}\n\n[data-emoji-set="facebook"] .skin-tone-2 {\n background-color: #f1d5aa;\n}\n\n[data-emoji-set="facebook"] .skin-tone-3 {\n background-color: #d4b48d;\n}\n\n[data-emoji-set="facebook"] .skin-tone-4 {\n background-color: #aa876b;\n}\n\n[data-emoji-set="facebook"] .skin-tone-5 {\n background-color: #916544;\n}\n\n[data-emoji-set="facebook"] .skin-tone-6 {\n background-color: #61493f;\n}\n\n'; 51761 51762
51762// app/javascript/src/emoji_mart/native.json 51763 var native_default = { categories: [{ id: "people", emojis: ["grinning", "smiley", "smile", "grin", "laughing", "sweat_smile", "rolling_on_the_floor_laughing", "joy", "slightly_smiling_face", "upside_down_face", "melting_face", "wink", "blush", "innocent", "smiling_face_with_3_hearts", "heart_eyes", "star-struck", "kissing_heart", "kissing", "relaxed", "kissing_closed_eyes", "kissing_smiling_eyes", "smiling_face_with_tear", "yum", "stuck_out_tongue", "stuck_out_tongue_winking_eye", "zany_face", "stuck_out_tongue_closed_eyes", "money_mouth_face", "hugging_face", "face_with_hand_over_mouth", "face_with_open_eyes_and_hand_over_mouth", "face_with_peeking_eye", "shushing_face", "thinking_face", "saluting_face", "zipper_mouth_face", "face_with_raised_eyebrow", "neutral_face", "expressionless", "no_mouth", "dotted_line_face", "face_in_clouds", "smirk", "unamused", "face_with_rolling_eyes", "grimacing", "face_exhaling", "lying_face", "shaking_face", "head_shaking_horizontally", "head_shaking_vertically", "relieved", "pensive", "sleepy", "drooling_face", "sleeping", "face_with_bags_under_eyes", "mask", "face_with_thermometer", "face_with_head_bandage", "nauseated_face", "face_vomiting", "sneezing_face", "hot_face", "cold_face", "woozy_face", "dizzy_face", "face_with_spiral_eyes", "exploding_head", "face_with_cowboy_hat", "partying_face", "disguised_face", "sunglasses", "nerd_face", "face_with_monocle", "confused", "face_with_diagonal_mouth", "worried", "slightly_frowning_face", "white_frowning_face", "open_mouth", "hushed", "astonished", "flushed", "pleading_face", "face_holding_back_tears", "frowning", "anguished", "fearful", "cold_sweat", "disappointed_relieved", "cry", "sob", "scream", "confounded", "persevere", "disappointed", "sweat", "weary", "tired_face", "yawning_face", "triumph", "rage", "angry", "face_with_symbols_on_mouth", "smiling_imp", "imp", "skull", "skull_and_crossbones", "hankey", "clown_face", "japanese_ogre", "japanese_goblin", "wave", "raised_back_of_hand", "raised_hand_with_fingers_splayed", "hand", "spock-hand", "rightwards_hand", "leftwards_hand", "palm_down_hand", "palm_up_hand", "leftwards_pushing_hand", "rightwards_pushing_hand", "ok_hand", "pinched_fingers", "pinching_hand", "v", "crossed_fingers", "hand_with_index_finger_and_thumb_crossed", "i_love_you_hand_sign", "the_horns", "call_me_hand", "point_left", "point_right", "point_up_2", "middle_finger", "point_down", "point_up", "index_pointing_at_the_viewer", "+1", "-1", "fist", "facepunch", "left-facing_fist", "right-facing_fist", "clap", "raised_hands", "heart_hands", "open_hands", "palms_up_together", "handshake", "pray", "writing_hand", "nail_care", "selfie", "muscle", "mechanical_arm", "mechanical_leg", "leg", "foot", "ear", "ear_with_hearing_aid", "nose", "brain", "anatomical_heart", "lungs", "tooth", "bone", "eyes", "eye", "tongue", "lips", "biting_lip", "baby", "child", "boy", "girl", "adult", "person_with_blond_hair", "man", "bearded_person", "man_with_beard", "woman_with_beard", "red_haired_man", "curly_haired_man", "white_haired_man", "bald_man", "woman", "red_haired_woman", "red_haired_person", "curly_haired_woman", "curly_haired_person", "white_haired_woman", "white_haired_person", "bald_woman", "bald_person", "blond-haired-woman", "blond-haired-man", "older_adult", "older_man", "older_woman", "person_frowning", "man-frowning", "woman-frowning", "person_with_pouting_face", "man-pouting", "woman-pouting", "no_good", "man-gesturing-no", "woman-gesturing-no", "ok_woman", "man-gesturing-ok", "woman-gesturing-ok", "information_desk_person", "man-tipping-hand", "woman-tipping-hand", "raising_hand", "man-raising-hand", "woman-raising-hand", "deaf_person", "deaf_man", "deaf_woman", "bow", "man-bowing", "woman-bowing", "face_palm", "man-facepalming", "woman-facepalming", "shrug", "man-shrugging", "woman-shrugging", "health_worker", "male-doctor", "female-doctor", "student", "male-student", "female-student", "teacher", "male-teacher", "female-teacher", "judge", "male-judge", "female-judge", "farmer", "male-farmer", "female-farmer", "co
vendor: 5,074 bytes, line 51763
51763ok", "male-cook", "female-cook", "mechanic", "male-mechanic", "female-mechanic", "factory_worker", "male-factory-worker", "female-factory-worker", "office_worker", "male-office-worker", "female-office-worker", "scientist", "male-scientist", "female-scientist", "technologist", "male-technologist", "female-technologist", "singer", "male-singer", "female-singer", "artist", "male-artist", "female-artist", "pilot", "male-pilot", "female-pilot", "astronaut", "male-astronaut", "female-astronaut", "firefighter", "male-firefighter", "female-firefighter", "cop", "male-police-officer", "female-police-officer", "sleuth_or_spy", "male-detective", "female-detective", "guardsman", "male-guard", "female-guard", "ninja", "construction_worker", "male-construction-worker", "female-construction-worker", "person_with_crown", "prince", "princess", "man_with_turban", "man-wearing-turban", "woman-wearing-turban", "man_with_gua_pi_mao", "person_with_headscarf", "person_in_tuxedo", "man_in_tuxedo", "woman_in_tuxedo", "bride_with_veil", "man_with_veil", "woman_with_veil", "pregnant_woman", "pregnant_man", "pregnant_person", "breast-feeding", "woman_feeding_baby", "man_feeding_baby", "person_feeding_baby", "angel", "santa", "mrs_claus", "mx_claus", "superhero", "male_superhero", "female_superhero", "supervillain", "male_supervillain", "female_supervillain", "mage", "male_mage", "female_mage", "fairy", "male_fairy", "female_fairy", "vampire", "male_vampire", "female_vampire", "merperson", "merman", "mermaid", "elf", "male_elf", "female_elf", "genie", "male_genie", "female_genie", "zombie", "male_zombie", "female_zombie", "troll", "massage", "man-getting-massage", "woman-getting-massage", "haircut", "man-getting-haircut", "woman-getting-haircut", "walking", "man-walking", "woman-walking", "person_walking_facing_right", "woman_walking_facing_right", "man_walking_facing_right", "standing_person", "man_standing", "woman_standing", "kneeling_person", "man_kneeling", "woman_kneeling", "person_kneeling_facing_right", "woman_kneeling_facing_right", "man_kneeling_facing_right", "person_with_probing_cane", "person_with_white_cane_facing_right", "man_with_probing_cane", "man_with_white_cane_facing_right", "woman_with_probing_cane", "woman_with_white_cane_facing_right", "person_in_motorized_wheelchair", "person_in_motorized_wheelchair_facing_right", "man_in_motorized_wheelchair", "man_in_motorized_wheelchair_facing_right", "woman_in_motorized_wheelchair", "woman_in_motorized_wheelchair_facing_right", "person_in_manual_wheelchair", "person_in_manual_wheelchair_facing_right", "man_in_manual_wheelchair", "man_in_manual_wheelchair_facing_right", "woman_in_manual_wheelchair", "woman_in_manual_wheelchair_facing_right", "runner", "man-running", "woman-running", "person_running_facing_right", "woman_running_facing_right", "man_running_facing_right", "dancer", "man_dancing", "man_in_business_suit_levitating", "dancers", "men-with-bunny-ears-partying", "women-with-bunny-ears-partying", "person_in_steamy_room", "man_in_steamy_room", "woman_in_steamy_room", "person_climbing", "man_climbing", "woman_climbing", "fencer", "horse_racing", "skier", "snowboarder", "golfer", "man-golfing", "woman-golfing", "surfer", "man-surfing", "woman-surfing", "rowboat", "man-rowing-boat", "woman-rowing-boat", "swimmer", "man-swimming", "woman-swimming", "person_with_ball", "man-bouncing-ball", "woman-bouncing-ball", "weight_lifter", "man-lifting-weights", "woman-lifting-weights", "bicyclist", "man-biking", "woman-biking", "mountain_bicyclist", "man-mountain-biking", "woman-mountain-biking", "person_doing_cartwheel", "man-cartwheeling", "woman-cartwheeling", "wrestlers", "man-wrestling", "woman-wrestling", "water_polo", "man-playing-water-polo", "woman-playing-water-polo", "handball", "man-playing-handball", "woman-playing-handball", "juggling", "man-juggling", "woman-juggling", "person_in_lotus_position", "man_in_lotus_position", "woman_in_lotus_position", "bath", "sleeping_accommodation", "people_holding_hands", "two_women_holding_hands", "man_and_woman_holding_hands", "two_men_holding_hands", "couplekiss", "woman-kiss-man", "man-kiss-man", "woman-kiss-woman", "couple_with_heart", "woman-heart-man", "man-heart-man", "woman-heart-woman", "man-woman-boy", "man-woman-girl", "man-woman-girl-boy", "man-woman-boy-boy", "man-woman-girl-girl", "man-man-boy", "man-man-girl", "man-man-girl-boy", "man-man-boy-boy", "man-man-girl-girl", "woman-woman-boy", "woman-woman-girl", "woman-woman-girl-boy", "woman-woman-boy-boy", "woman-woman-girl-girl", "man-boy", "man-boy-boy", "man-girl", "man-girl-boy", "man-girl-girl", "woman-boy", "woman-boy-boy", "woman-girl", "woman-girl-boy", "woman-girl-girl", "speaking_head_in_silhouette", "bust_in_silhouette", "busts_in_silhouette", "people_hugging", "family", "family_adult_adult_child", "family_adult_adult_child_child", "family_adult_child", "family_adult_child_child", "footprints", "fingerprint", "ghost", "alien", "space_invader", "robot_face", "smiley_cat", "smile_cat", "joy_cat", "heart_eyes_cat", "smirk_cat", "kissing_c
51763at", "scream_cat", "crying_cat_face", "pouting_cat", "see_no_evil", "hear_no_evil", "speak_no_evil", "love_letter", "cupid", "gift_heart", "sparkling_heart", "heartpulse", "heartbeat", "revolving_hearts", "two_hearts", "heart_decoration", "heavy_heart_exclamation_mark_ornament", "broken_heart", "heart_on_fire", "mending_heart", "heart", "pink_heart", "orange_heart", "yellow_heart", "green_heart", "blue_heart", "light_blue_heart", "purple_heart", "brown_heart", "black_heart", "grey_heart", "white_heart", "kiss", "100", "anger", "boom", "dizzy", "sweat_drops", "dash", "hole", "speech_balloon", "eye-in-speech-bubble", "left_speech_bubble", "right_anger_bubble", "thought_balloon", "zzz", "distorted_face", "fight_cloud", "hairy_creature", "ballet_dancer"] }, { id: "nature", emojis: ["monkey_face", "monkey", "gorilla", "orangutan", "dog", "dog2", "guide_dog", "service_dog", "poodle", "wolf", "fox_face", "raccoon", "cat", "cat2", "black_cat", "lion_face", "tiger", "tiger2", "leopard", "horse", "moose", "donkey", "racehorse", "unicorn_face", "zebra_face", "deer", "bison", "cow", "ox", "water_buffalo", "cow2", "pig", "pig2", "boar", "pig_nose", "ram", "sheep", "goat", "dromedary_camel", "camel", "llama", "giraffe_face", "elephant", "mammoth", "rhinoceros", "hippopotamus", "mouse", "mouse2", "rat", "hamster", "rabbit", "rabbit2", "chipmunk", "beaver", "hedgehog", "bat", "bear", "polar_bear", "koala", "panda_face", "sloth", "otter", "skunk", "kangaroo", "badger", "feet", "turkey", "chicken", "rooster", "hatching_chick", "baby_chick", "hatched_chick", "bird", "penguin", "dove_of_peace", "eagle", "duck", "swan", "owl", "dodo", "feather", "flamingo", "peacock", "parrot", "wing", "black_bird", "goose", "phoenix", "frog", "crocodile", "turtle", "lizard", "snake", "dragon_face", "dragon", "sauropod", "t-rex", "whale", "whale2", "dolphin", "seal", "fish", "tropical_fish", "blowfish", "shark", "octopus", "shell", "coral", "jellyfish", "crab", "lobster", "shrimp", "squid", "oyster", "snail", "butterfly", "bug", "ant", "bee", "beetle", "ladybug", "cricket", "cockroach", "spider", "spider_web", "scorpion", "mosquito", "fly", "worm", "microbe", "bouquet", "cherry_blossom", "white_flower", "lotus", "rosette", "rose", "wilted_flower", "hibiscus", "sunflower", "blossom", "tulip", "hyacinth", "seedling", "potted_plant", "evergreen_tree", "deciduous_tree", "palm_tree", "cactus", "ear_of_rice", "herb", "shamrock", "four_leaf_clover", "maple_leaf", "fallen_leaf", "leaves", "empty_nest", "nest_with_eggs", "mushroom", "leafless_tree", "orca"] }, { id: "foods", emojis: ["grapes", "melon", "watermelon", "tangerine", "lemon", "lime", "banana", "pineapple", "mango", "apple", "green_apple", "pear", "peach", "cherries", "strawberry", "blueberries", "kiwifruit", "tomato", "olive", "coconut", "avocado", "eggplant", "potato", "carrot", "corn", "hot_pepper", "bell_pepper", "cucumber", "leafy_green", "broccoli", "garlic", "onion", "peanuts", "beans", "chestnut", "ginger_root", "pea_pod", "brown_mushroom", "root_vegetable", "bread", "croissant", "baguette_bread", "flatbread", "pretzel", "bagel", "pancakes", "waffle", "cheese_wedge", "meat_on_bone", "poultry_leg", "cut_of_meat", "bacon", "hamburger", "fries", "pizza", "hotdog", "sandwich", "taco", "burrito", "tamale", "stuffed_flatbread", "falafel", "egg", "fried_egg", "shallow_pan_of_food", "stew", "fondue", "bowl_with_spoon", "green_salad", "popcorn", "butter", "salt", "canned_food", "bento", "rice_cracker", "rice_ball", "rice", "curry", "ramen", "spaghetti", "sweet_potato", "oden", "sushi", "fried_shrimp", "fish_cake", "moon_cake", "dango", "dumpling", "fortune_cookie", "takeout_box", "icecream", "shaved_ice", "ice_cream", "doughnut", "cookie", "birthday", "cake", "cupcake", "pie", "chocolate_bar", "candy", "lollipop", "custard", "honey_pot", "baby_bottle", "glass_of_milk", "coffee", "teapot", "tea", "sake", "champagne", "wine_glass", "cocktail", "tropical_drink", "beer", "beers", "clinking_glasses", "tumbler_glass", "pouring_liquid", "cup_with_straw", "bubble_tea", "beverage_box", "mate_drink", "ice_cube", "chopsticks", "knife_fork_plate", "fork_and_knife", "spoon", "hocho", "jar", "amphora"] }, { id: "activity", emojis: ["jack_o_lantern", "christmas_tree", "fireworks", "sparkler", "firecracker", "sparkles", "balloon", "tada", "confetti_ball", "tanabata_tree", "bamboo", "dolls", "flags", "wind_chime", "rice_scene", "red_envelope", "ribbon", "gift", "reminder_ribbon", "admission_tickets", "ticket", "medal", "trophy", "sports_medal", "first_place_medal", "second_place_medal", "third_place_medal", "soccer", "baseball", "softball", "basketball", "volleyball", "football", "rugby_football", "tennis", "flying_disc", "bowling", "cricket_bat_and_ball", "field_hockey_stick_and_ball", "ice_hockey_stick_and_puck", "lacrosse", "table_tennis_paddle_and_ball", "badminton_racquet_and_shuttlecock", "boxing_glove", "martial_arts_uniform", "goal_net", "golf", "ice_skate", "fishing_pole_and_fish", "diving_mask", "running_shirt_with_sash", "ski", "sled", "curling_stone", "dart", "yo-yo", "kite", "gun", "8ball", "crystal_ball", "magic_wand", "video_game", "joystick", "slot_machine", "game_die", "jigsaw", "teddy_bear", "pinata", "mirror_ball", "nesting_dolls", "spades", "hearts", "diamonds", "clubs", "chess_pawn", "black_joker", "mahjong", "flower_playing_cards", "performing_arts", "frame_with_picture", "art", "thread", "sewing_needle", "yarn", "knot"] }, { id: "places", emojis: ["earth_africa", "earth_americas", "earth_asia", "globe_with_meri
51763dians", "world_map", "japan", "compass", "snow_capped_mountain", "mountain", "volcano", "mount_fuji", "camping", "beach_with_umbrella", "desert", "desert_island", "national_park", "stadium", "classical_building", "building_construction", "bricks", "rock", "wood", "hut", "house_buildings", "derelict_house_building", "house", "house_with_garden", "office", "post_office", "european_post_office", "hospital", "bank", "hotel", "love_hotel", "convenience_store", "school", "department_store", "factory", "japanese_castle", "european_castle", "wedding", "tokyo_tower", "statue_of_liberty", "church", "mosque", "hindu_temple", "synagogue", "shinto_shrine", "kaaba", "fountain", "tent", "foggy", "night_with_stars", "cityscape", "sunrise_over_mountains", "sunrise", "city_sunset", "city_sunrise", "bridge_at_night", "hotsprings", "carousel_horse", "playground_slide", "ferris_wheel", "roller_coaster", "barber", "circus_tent", "steam_locomotive", "railway_car", "bullettrain_side", "bullettrain_front", "train2", "metro", "light_rail", "station", "tram", "monorail", "mountain_railway", "train", "bus", "oncoming_bus", "trolleybus", "minibus", "ambulance", "fire_engine", "police_car", "oncoming_police_car", "taxi", "oncoming_taxi", "car", "oncoming_automobile", "blue_car", "pickup_truck", "truck", "articulated_lorry", "tractor", "racing_car", "racing_motorcycle", "motor_scooter", "manual_wheelchair", "motorized_wheelchair", "auto_rickshaw", "bike", "scooter", "skateboard", "roller_skate", "busstop", "motorway", "railway_track", "oil_drum", "fuelpump", "wheel", "rotating_light", "traffic_light", "vertical_traffic_light", "octagonal_sign", "construction", "anchor", "ring_buoy", "boat", "canoe", "speedboat", "passenger_ship", "ferry", "motor_boat", "ship", "airplane", "small_airplane", "airplane_departure", "airplane_arriving", "parachute", "seat", "helicopter", "suspension_railway", "mountain_cableway", "aerial_tramway", "satellite", "rocket", "flying_saucer", "bellhop_bell", "luggage", "hourglass", "hourglass_flowing_sand", "watch", "alarm_clock", "stopwatch", "timer_clock", "mantelpiece_clock", "clock12", "clock1230", "clock1", "clock130", "clock2", "clock230", "clock3", "clock330", "clock4", "clock430", "clock5", "clock530", "clock6", "clock630", "clock7", "clock730", "clock8", "clock830", "clock9", "clock930", "clock10", "clock1030", "clock11", "clock1130", "new_moon", "waxing_crescent_moon", "first_quarter_moon", "moon", "full_moon", "waning_gibbous_moon", "last_quarter_moon", "waning_crescent_moon", "crescent_moon", "new_moon_with_face", "first_quarter_moon_with_face", "last_quarter_moon_with_face", "thermometer", "sunny", "full_moon_with_face", "sun_with_face", "ringed_planet", "star", "star2", "stars", "milky_way", "cloud", "partly_sunny", "thunder_cloud_and_rain", "mostly_sunny", "barely_sunny", "partly_sunny_rain", "rain_cloud", "snow_cloud", "lightning", "tornado", "fog", "wind_blowing_face", "cyclone", "rainbow", "closed_umbrella", "umbrella", "umbrella_with_rain_drops", "umbrella_on_ground", "zap", "snowflake", "snowman", "snowman_without_snow", "comet", "fire", "droplet", "ocean", "landslide"] }, { id: "objects", emojis: ["eyeglasses", "dark_sunglasses", "goggles", "lab_coat", "safety_vest", "necktie", "shirt", "jeans", "scarf", "gloves", "coat", "socks", "dress", "kimono", "sari", "one-piece_swimsuit", "briefs", "shorts", "bikini", "womans_clothes", "folding_hand_fan", "purse", "handbag", "pouch", "shopping_bags", "school_satchel", "thong_sandal", "mans_shoe", "athletic_shoe", "hiking_boot", "womans_flat_shoe", "high_heel", "sandal", "ballet_shoes", "boot", "hair_pick", "crown", "womans_hat", "tophat", "mortar_board", "billed_cap", "military_helmet", "helmet_with_white_cross", "prayer_beads", "lipstick", "ring", "gem", "mute", "speaker", "sound", "loud_sound", "loudspeaker", "mega", "postal_horn", "bell", "no_bell", "musical_score", "musical_note", "notes", "studio_microphone", "level_slider", "control_knobs", "microphone", "headphones", "radio", "saxophone", "accordion", "guitar", "musical_keyboard", "trumpet", "violin", "banjo", "drum_with_drumsticks", "long_drum", "maracas", "flute", "harp", "iphone", "calling", "phone", "telephone_receiver", "pager", "fax", "battery", "low_battery", "electric_plug", "computer", "desktop_computer", "printer", "keyboard", "three_button_mouse", "trackball", "minidisc", "floppy_disk", "cd", "dvd", "abacus", "movie_camera", "film_frames", "film_projector", "clapper", "tv", "camera", "camera_with_flash", "video_camera", "vhs", "mag", "mag_right", "candle", "bulb", "flashlight", "izakaya_lantern", "diya_lamp", "notebook_with_decorative_cover", "closed_book", "book", "green_book", "blue_book", "orange_book", "books", "notebook", "ledger", "page_with_curl", "scroll", "page_facing_up", "newspaper", "rolled_up_newspaper", "bookmark_tabs", "bookmark", "label", "moneybag", "coin", "yen", "dollar", "euro", "pound", "money_with_wings", "credit_card", "receipt", "chart", "email", "e-mail", "incoming_envelope", "envelope_with_arrow", "outbox_tray", "inbox_tray", "package", "mailbox", "mailbox_closed", "mailbox_with_mail", "mailbox_with_no_mail", "postbox", "ballot_box_with_ballot", "pencil2", "black_nib", "lower_left_fountain_pen", "lower_left_ballpoint_pen", "lower_left_paintbrush", "lower_left_crayon", "memo", "briefcase", "file_folder", "open_file_folder", "card_index_dividers", "date", "calendar", "spiral_note_pad", "spiral_calendar_pad", "card_index", "chart_with_upwards_trend", "chart_with_downwards_trend", "bar_chart", "clipboard", "pushpin", "round_pushpin", "paperclip", "linked_paperclips", "straight_ruler", "triangular_ruler", "scissors", "card_file_box", "file_cabinet", "wastebasket", "lock", "unlock", "lock_with_ink_pen", "closed_lock_with_key", "key", "old_key", "hammer", "axe", "pick", "hammer_and_pick", "hammer_and_wrench", "dagger_knife", "crossed_swords", "bomb", "boomerang", "bow_and_arrow", "shield", "carpentry_saw", "wrench", "screwdriver", "nut_and_bolt", "gear", "compression", "scales", "probing_cane", "link", "broken_chain", "chains", "hook", "toolbox", "magnet", "ladder", "shovel", "alembic", "test_tube", "petri_dish", "dna", "microscope", "telescope", "satellite_antenna", "syringe", "drop_of_blood", "pill", "adhesive_bandage", "crutch", "stethoscope", "x-ray", "door", "elevator", "mirror", "window", "bed", "couch_and_lamp", "chair", "toilet", "plunger", "shower", "bathtub", "mouse_trap", "razor", "lotion_bottle", "safety_pin", "broom", "basket", "roll_of_paper", "bucket", "soap", "bubbles", "toothbrush", "sponge", "fire_extinguisher", "shopping_trolley", "smoking", "coffin", "headstone", "funeral_urn", "nazar_amulet", "hamsa", "moyai", "placard", "identification_card", "trombone", "treasure_chest"] }, { id: "symbols", emojis: ["atm", "put_litter_in_its_place", "potable_water", "wheelchair", "mens", "womens", "restroom", "baby_symbol", "wc", "passport_control", "customs", "baggage_claim", "left_luggage", "warning", "children_crossing", "no_entry", "no_entry_sign", "no_bicycles", "no_smoking", "do_not_litter", "non-potable_water", "no_pedestrians", "no_mobile_phones", "underage", "radioactive_sign", "biohazard_sign", "arrow_up", "arrow_upper_right", "arrow_right", "arrow_lower_right", "arrow_down", "arrow_lower_left", "arrow_left", "arrow_upper_left", "arrow_up_down", "left_right_arrow", "leftwards_arrow_with_hook", "arrow_right_hook", "arrow_heading_up", "arrow_heading_down", "arrows_clockwise", "arrows_counterclockwise", "back", "end", "on", "soon", "top", "place_of_worship", "atom_symbol", "om_symbol", "star_of_david", "wheel_of_dharma", "yin_yang", "latin_cross", "orthodox_cross", "star_and_crescent", "peace_symbol", "menorah_with_nine_branches", "six_pointed_star", "khanda", "aries", "taurus", "gemini", "cancer", "leo", "virgo", "libra", "scorpius", "sagittarius", "capricorn", "aquarius", "pisces", "ophiuchus", "twisted_rightwards_arrows", "repeat", "repeat_one", "arrow_forward", "fast_forward", "black_right_pointing_double_triangle_with_vertical_bar", "black_right_pointing_triangle_with_double_vertical_bar", "arrow_backward", "rewind", "black_left_pointing_double_triangle_with_vertical_bar", "arrow_up_small", "arrow_double_up", "arrow_down_small", "arrow_double_down", "double_vertical_bar", "black_square_for_stop", "black_circle_for_record", "eject", "cinema", "low_brightness", "high_brightness", "signal_strength", "wireless", "vibration_mode", "mobile_phone_off", "female_sign", "male_sign", "transgender_symbol", "heavy_multiplication_x", "heavy_plus_sign", "heavy_minus_sign", "heavy_division_sign", "heavy_equals_sign", "infinity", "bangbang", "interrobang", "question", "grey_question", "grey_exclamation", "exclamation", "wavy_dash", "currency_exchange", "heavy_dollar_sign", "medical_symbol", "recycle", "fleur_de_lis", "trident", "name_badge", "beginner", "o", "white_check_mark", "ballot_box_with_check", "heavy_check_mark", "x", "negative_squared_cross_mark", "curly_loop", "loop", "part_alternation_mark", "eight_spoked_asterisk", "eight_pointed_black_star", "sparkle", "copyright", "registered", "tm", "splatter", "hash", "keycap_star", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "keycap_ten", "capital_abcd", "abcd", "1234", "symbols", "abc", "a", "ab", "b", "cl", "cool", "free", "information_source", "id", "m", "new", "ng", "o2", "ok", "parking", "sos", "up", "vs", "koko", "sa", "u6708", "u6709", "u
517636307", "ideograph_advantage", "u5272", "u7121", "u7981", "accept", "u7533", "u5408", "u7a7a", "congratulations", "secret", "u55b6", "u6e80", "red_circle", "large_orange_circle", "large_yellow_circle", "large_green_circle", "large_blue_circle", "large_purple_circle", "large_brown_circle", "black_circle", "white_circle", "large_red_square", "large_orange_square", "large_yellow_square", "large_green_square", "large_blue_square", "large_purple_square", "large_brown_square", "black_large_square", "white_large_square", "black_medium_square", "white_medium_square", "black_medium_small_square", "white_medium_small_square", "black_small_square", "white_small_square", "large_orange_diamond", "large_blue_diamond", "small_orange_diamond", "small_blue_diamond", "small_red_triangle", "small_red_triangle_down", "diamond_shape_with_a_dot_inside", "radio_button", "white_square_button", "black_square_button"] }, { id: "flags", emojis: ["checkered_flag", "cn", "crossed_flags", "de", "es", "flag-ac", "flag-ad", "flag-ae", "flag-af", "flag-ag", "flag-ai", "flag-al", "flag-am", "flag-ao", "flag-aq", "flag-ar", "flag-as", "flag-at", "flag-au", "flag-aw", "flag-ax", "flag-az", "flag-ba", "flag-bb", "flag-bd", "flag-be", "flag-bf", "flag-bg", "flag-bh", "flag-bi", "flag-bj", "flag-bl", "flag-bm", "flag-bn", "flag-bo", "flag-bq", "flag-br", "flag-bs", "flag-bt", "flag-bv", "flag-bw", "flag-by", "flag-bz", "flag-ca", "flag-cc", "flag-cd", "flag-cf", "flag-cg", "flag-ch", "flag-ci", "flag-ck", "flag-cl", "flag-cm", "flag-co", "flag-cp", "flag-cr", "flag-cu", "flag-cv", "flag-cw", "flag-cx", "flag-cy", "flag-cz", "flag-dg", "flag-dj", "flag-dk", "flag-dm", "flag-do", "flag-dz", "flag-ea", "flag-ec", "flag-ee", "flag-eg", "flag-eh", "flag-england", "flag-er", "flag-et", "flag-eu", "flag-fi", "flag-fj", "flag-fk", "flag-fm", "flag-fo", "flag-ga", "flag-gd", "flag-ge", "flag-gf", "flag-gg", "flag-gh", "flag-gi", "flag-gl", "flag-gm", "flag-gn", "flag-gp", "flag-gq", "flag-gr", "flag-gs", "flag-gt", "flag-gu", "flag-gw", "flag-gy", "flag-hk", "flag-hm", "flag-hn", "flag-hr", "flag-ht", "flag-hu", "flag-ic", "flag-id", "flag-ie", "flag-il", "flag-im", "flag-in", "flag-io", "flag-iq", "flag-ir", "flag-is", "flag-je", "flag-jm", "flag-jo", "flag-ke", "flag-kg", "flag-kh", "flag-ki", "flag-km", "flag-kn", "flag-kp", "flag-kw", "flag-ky", "flag-kz", "flag-la", "flag-lb", "flag-lc", "flag-li", "flag-lk", "flag-lr", "flag-ls", "flag-lt", "flag-lu", "flag-lv", "flag-ly", "flag-ma", "flag-mc", "flag-md", "flag-me", "flag-mf", "flag-mg", "flag-mh", "flag-mk", "flag-ml", "flag-mm", "flag-mn", "flag-mo", "flag-mp", "flag-mq", "flag-mr", "flag-ms", "flag-mt", "flag-mu", "flag-mv", "flag-mw", "flag-mx", "flag-my", "flag-mz", "flag-na", "flag-nc", "flag-ne", "flag-nf", "flag-ng", "flag-ni", "flag-nl", "flag-no", "flag-np", "flag-nr", "flag-nu", "flag-nz", "flag-om", "flag-pa", "flag-pe", "flag-pf", "flag-pg", "flag-ph", "flag-pk", "flag-pl", "flag-pm", "flag-pn", "flag-pr", "flag-ps", "flag-pt", "flag-pw", "flag-py", "flag-qa", "flag-re", "flag-ro", "flag-rs", "flag-rw", "flag-sa", "flag-sark", "flag-sb", "flag-sc", "flag-scotland", "flag-sd", "flag-se", "flag-sg", "flag-sh", "flag-si", "flag-sj", "flag-sk", "flag-sl", "flag-sm", "flag-sn", "flag-so", "flag-sr", "flag-ss", "flag-st", "flag-sv", "flag-sx", "flag-sy", "flag-sz", "flag-ta", "flag-tc", "flag-td", "flag-tf", "flag-tg", "flag-th", "flag-tj", "flag-tk", "flag-tl", "flag-tm", "flag-tn", "flag-to", "flag-tr", "flag-tt", "flag-tv", "flag-tw", "flag-tz", "flag-ua", "flag-ug", "flag-um", "flag-un", "flag-uy", "flag-uz", "flag-va", "flag-vc", "flag-ve", "flag-vg", "flag-vi", "flag-vn", "flag-vu", "flag-wales", "flag-wf", "flag-ws", "flag-xk", "flag-ye", "flag-yt", "flag-za", "flag-zm", "flag-zw", "fr", "gb", "it", "jp", "kr", "pirate_flag", "rainbow-flag", "ru", "transgender_flag", "triangular_flag_on_post", "us", "waving_black_flag", "waving_white_flag"] }], emojis: { "100": { id: "100", name: "Hundred Points", keywords: ["100", "score", "perfect", "numbers", "century", "exam", "quiz", "test", "pass"], skins: [{ unified: "1f4af", native: "\u{1F4AF}" }], version: 1 }, "1234": { id: "1234", name: "Input Numbers", keywords: ["1234", "blue", "square", "1", "2", "3", "4"], skins: [{ unified: "1f522", native: "\u{1F522}" }], version: 1 }, grinning: { id: "grinning", name: "Grinning Face", emoticons: [":D"], keywords: ["smile", "happy", "joy", ":D", "grin"], skins: [{ unified: "1f600", native: "\u{1F600}" }], version: 1 }, smiley: { id: "smiley", name: "Grinning Face with Big Eyes", emoticons: [":)", "=)", "=-)"], keywords: ["smiley", "happy", "joy", "haha", ":D", ":)", "smile", "funny"], skins: [{ unified: "1f603", native: "\u{1F603}" }], version: 1 }, smile: { id: "smile", name: "Grinning Face with Smiling Eyes", emoticons: [":)", "C:", "c:", ":D", ":-D"], keywords: ["smile", "happy", "joy", "funny", "haha", "laugh", "like", ":D", ":)"], skins: [{ unified: "1f604", native: "\u{1F604}" }], version: 1 }, grin: { id: "grin", name: "Beaming Face with Smiling Eyes", keywords: ["grin", "happy", "smile", "joy", "kawaii"], skins: [{ unified: "1f601", native: "\u{1F601}" }], version: 1 }, laughing: { id: "laughing", name: "Grinning Squinting Face", emoticons: [":>", ":->"], keywords: ["laughing", "satisfied", "happy", "joy", "lol", "haha", "glad", "XD", "laugh"], skins: [{ unified: "1f606", native: "\u{1F606}" }], version: 1 }, sweat_smile: { id: "sweat_smile", name: "Grinning Face with Sweat", keywords: ["smile", "hot", "happy", "laugh", "relief"], skins: [{ unified: "1f605", native: "\u{1F605}" }], version: 1 }, rolling_on_the_floor_laughing: { id: "rolling_on_the_floor_laughing", name: "Rolling on the Floor Laughing", keywords: ["face", "lol", "haha", "rofl"], skins: [{ unified: "1f923", native: "\u{1F923}" }], version: 3 }, joy: { id: "joy", name: "Face with Tears of Joy", keywords: ["cry", "weep", "happy", "happytears", "haha"], skins: [{ unified: "1f602", native: "\u{1F602}" }], version: 1 }, slightly_smiling_face: { id: "slightly_smiling_face", name: "Slightly Smiling Face", emoticons: [":)", "(:", ":-)"], keywords: ["smile"], skins: [{ unified: "1f642", native: "\u{1F642}" }], version: 1 }, upside_down_face: { id: "upside_down_face", name: "Upside-Down Face", keywords: ["upside", "down", "flipped", "silly", "smile"], skins: [{ unified: "1f643", native: "\u{1F643}" }], version: 1 }, melting_face: { id: "melting_face", name: "Melting Face", keywords: ["hot", "heat"], skins: [{ unified: "1fae0", native: "\u{1FAE0}" }], version: 14 }, wink: { id: "wink", name: "Winking Face", emoticons: [";)", ";-)"], keywords: ["wink", "happy", "mischievous", "secret", ";)", "smile", "eye"], skins: [{ unified: "1f609", native: "\u{1F609}" }], version: 1 }, blush: { id: "blush", name: "Smiling Face with Smiling Eyes", emoticons: [":)"], keywords: ["blush", "smile", "happy", "flushed", "crush", "embarrassed", "shy", "joy"], skins: [{ unified: "1f60a", native: "\u{1F60A}" }], version: 1 }, innocent: { id: "innocent", name: "Smiling Face with Halo", keywords: ["innocent", "angel", "heaven"], skins: [{ unified: "1f607", native: "\u{1F607}" }], version: 1 }, smiling_face_with_3_hearts: { id: "smiling_face_with_3_hearts", name: "Smiling Face with Hearts", keywords: ["3", "love", "like", "affection", "valentines", "infatuation", "crush", "adore"], skins: [{ unified: "1f970", native: "\u{1F970}" }], version: 11 }, heart_eyes: { id: "heart_eyes", name: "Smiling Face with Heart-Eyes", keywords: ["heart", "eyes", "love", "like", "affection", "valentines", "infatuation", "crush"], skins: [{ unified: "1f60d", native: "\u{1F60D}" }], version: 1 }, "star-struck": { id: "star-struck", name: "Star-Struck", keywords: ["star", "struck", "grinning", "face", "with", "eyes", "smile", "starry"], skins: [{ unified: "1f929", native: "\u{1F929}" }], version: 5 }, kissing_heart: { id: "kissing_heart", name: "Face Blowing a Kiss", emoticons: [":*", ":-*"], keywords: ["kissing", "heart", "love", "like", "affection", "valentines", "infatuation"], skins: [{ unified: "1f618", native: "\u{1F618}" }], version: 1 }, kissing: { id: "kissing", name: "Kissing Face", keywords: ["love", "like", "3", "valentines", "infatuation", "kiss"], skins: [{ unified: "1f617", native: "\u{1F617}" }], version: 1 }, relaxed: { id: "relaxed", name: "Smiling Face", keywords: ["relaxed", "blush", "massage", "happiness"], skins: [{ unified: "263a-fe0f", native: "\u263A\uFE0F" }], version: 1 }, kissing_closed_eyes: { id: "kissing_closed_eyes", name: "Kissing Face with Closed Eyes", keywords: ["love", "like", "affection", "valentines", "infatuation", "kiss"], skins: [{ unified: "1f61a", native: "\u{1F61A}" }], version: 1 }, kissing_smiling_eyes: { id: "kissing_smiling_eyes", name: "Kissing Face with Smiling Eyes", keywords: ["affection", "valentines", "infatuation", "kiss"], skins: [{ unified: "1f619", native: "\u{1F619}" }], version: 1 }, smiling_face_with_tear: { id: "smiling_face_with_tear", name: "Smiling Face with Tear", keywords: ["sad", "cry", "pretend"], skins: [{ unified: "1f972", native: "\u{1F972}" }
51763], version: 13 }, yum: { id: "yum", name: "Face Savoring Food", keywords: ["yum", "happy", "joy", "tongue", "smile", "silly", "yummy", "nom", "delicious", "savouring"], skins: [{ unified: "1f60b", native: "\u{1F60B}" }], version: 1 }, stuck_out_tongue: { id: "stuck_out_tongue", name: "Face with Tongue", emoticons: [":p", ":-p", ":P", ":-P", ":b", ":-b"], keywords: ["stuck", "out", "prank", "childish", "playful", "mischievous", "smile"], skins: [{ unified: "1f61b", native: "\u{1F61B}" }], version: 1 }, stuck_out_tongue_winking_eye: { id: "stuck_out_tongue_winking_eye", name: "Winking Face with Tongue", emoticons: [";p", ";-p", ";b", ";-b", ";P", ";-P"], keywords: ["stuck", "out", "eye", "prank", "childish", "playful", "mischievous", "smile", "wink"], skins: [{ unified: "1f61c", native: "\u{1F61C}" }], version: 1 }, zany_face: { id: "zany_face", name: "Zany Face", keywords: ["grinning", "with", "one", "large", "and", "small", "eye", "goofy", "crazy"], skins: [{ unified: "1f92a", native: "\u{1F92A}" }], version: 5 }, stuck_out_tongue_closed_eyes: { id: "stuck_out_tongue_closed_eyes", name: "Squinting Face with Tongue", keywords: ["stuck", "out", "closed", "eyes", "prank", "playful", "mischievous", "smile"], skins: [{ unified: "1f61d", native: "\u{1F61D}" }], version: 1 }, money_mouth_face: { id: "money_mouth_face", name: "Money-Mouth Face", keywords: ["money", "mouth", "rich", "dollar"], skins: [{ unified: "1f911", native: "\u{1F911}" }], version: 1 }, hugging_face: { id: "hugging_face", name: "Hugging Face", keywords: ["smile", "hug"], skins: [{ unified: "1f917", native: "\u{1F917}" }], version: 1 }, face_with_hand_over_mouth: { id: "face_with_hand_over_mouth", name: "Face with Hand over Mouth", keywords: ["smiling", "eyes", "and", "covering", "whoops", "shock", "surprise"], skins: [{ unified: "1f92d", native: "\u{1F92D}" }], version: 5 }, face_with_open_eyes_and_hand_over_mouth: { id: "face_with_open_eyes_and_hand_over_mouth", name: "Face with Open Eyes and Hand over Mouth", keywords: ["silence", "secret", "shock", "surprise"], skins: [{ unified: "1fae2", native: "\u{1FAE2}" }], version: 14 }, face_with_peeking_eye: { id: "face_with_peeking_eye", name: "Face with Peeking Eye", keywords: ["scared", "frightening", "embarrassing", "shy"], skins: [{ unified: "1fae3", native: "\u{1FAE3}" }], version: 14 }, shushing_face: { id: "shushing_face", name: "Shushing Face", keywords: ["with", "finger", "covering", "closed", "lips", "quiet", "shhh"], skins: [{ unified: "1f92b", native: "\u{1F92B}" }], version: 5 }, thinking_face: { id: "thinking_face", name: "Thinking Face", keywords: ["hmmm", "think", "consider"], skins: [{ unified: "1f914", native: "\u{1F914}" }], version: 1 }, saluting_face: { id: "saluting_face", name: "Saluting Face", keywords: ["respect", "salute"], skins: [{ unified: "1fae1", native: "\u{1FAE1}" }], version: 14 }, zipper_mouth_face: { id: "zipper_mouth_face", name: "Zipper-Mouth Face", keywords: ["zipper", "mouth", "sealed", "secret"], skins: [{ unified: "1f910", native: "\u{1F910}" }], version: 1 }, face_with_raised_eyebrow: { id: "face_with_raised_eyebrow", name: "Face with Raised Eyebrow", keywords: ["one", "distrust", "scepticism", "disapproval", "disbelief", "surprise", "suspicious"], skins: [{ unified: "1f928", native: "\u{1F928}" }], version: 5 }, neutral_face: { id: "neutral_face", name: "Neutral Face", emoticons: [":|", ":-|"], keywords: ["indifference", "meh", ":", ""], skins: [{ unified: "1f610", native: "\u{1F610}" }], version: 1 }, expressionless: { id: "expressionless", name: "Expressionless Face", emoticons: ["-_-"], keywords: ["indifferent", "-", "", "meh", "deadpan"], skins: [{ unified: "1f611", native: "\u{1F611}" }], version: 1 }, no_mouth: { id: "no_mouth", name: "Face Without Mouth", keywords: ["no"], skins: [{ unified: "1f636", native: "\u{1F636}" }], version: 1 }, dotted_line_face: { id: "dotted_line_face", name: "Dotted Line Face", keywords: ["invisible", "lonely", "isolation", "depression"], skins: [{ unified: "1fae5", native: "\u{1FAE5}" }], version: 14 }, face_in_clouds: { id: "face_in_clouds", name: "Face in Clouds", keywords: ["shower", "steam", "dream"], skins: [{ unified: "1f636-200d-1f32b-fe0f", native: "\u{1F636}\u200D\u{1F32B}\uFE0F" }], version: 13.1 }, smirk: { id: "smirk", name: "Smirking Face", keywords: ["smirk", "smile", "mean", "prank", "smug", "sarcasm"], skins: [{ unified: "1f60f", native: "\u{1F60F}" }], version: 1 }, unamused: { id: "unamused", name: "Unamused Face", emoticons: [":("], keywords: ["indifference", "bored", "straight", "serious", "sarcasm", "unimpressed", "skeptical", "dubious", "ugh", "side", "eye"], skins: [{ unified: "1f612", native: "\u{1F612}" }], version: 1 }, face_with_rolling_eyes: { id: "face_with_rolling_eyes", name: "Face with Rolling Eyes", keywords: ["eyeroll", "frustrated"], skins: [{ unified: "1f644", native: "\u{1F644}" }], version: 1 }, grimacing: { id: "grimacing", name: "Grimacing Face", keywords: ["grimace", "teeth"], skins: [{ unified: "1f62c", native: "\u{1F62C}" }], version: 1 }, face_exhaling: { id: "face_exhaling", name: "Face Exhaling", keywords: ["relieve", "relief", "tired", "sigh"], skins: [{ unified: "1f62e-200d-1f4a8", native: "\u{1F62E}\u200D\u{1F4A8}" }], version: 13.1 }, lying_face: { id: "lying_face", name: "Lying Face", keywords: ["lie", "pinocchio"], skins: [{ unified: "1f925", native: "\u{1F925}" }], version: 3 }, shaking_face: { id: "shaking_face", name: "Shaking Face", keywords: ["dizzy", "shock", "blurry", "earthquake"], skins: [{ unified: "1fae8", native: "\u{1FAE8}" }], version: 15 }, head_shaking_horizontally: { id: "head_shaking_horizontally", name: "Head Shaking Horizontally", keywords: ["disapprove", "indiffernt", "left"], skins: [{ unified: "1f642-200d-2194-fe0f", native: "\u{1F642}\u200D\u2194\uFE0F" }], version: 15.1 }, head_shaking_vertically: { id: "head_shaking_vertically", name: "Head Shaking Vertically", keywords: ["down", "nod"], skins: [{ unified: "1f642-200d-2195-fe0f", native: "\u{1F642}\u200D\u2195\uFE0F" }], version: 15.1 }, relieved: { id: "relieved", name: "Relieved Face", keywords: ["relaxed", "phew", "massage", "happiness"], skins: [{ unified: "1f60c", native: "\u{1F60C}" }], version: 1 }, pensive: { id: "pensive", name: "Pensive Face", keywords: ["sad", "depressed", "upset"], skins: [{ unified: "1f614", native: "\u{1F614}" }], version: 1 }, sleepy: { id: "sleepy", name: "Sleepy Face", keywords: ["tired", "rest", "nap"], skins: [{ unified: "1f62a", native: "\u{1F62A}" }], version: 1 }, drooling_face: { id: "drooling_face", name: "Drooling Face", keywords: [], skins: [{ unified: "1f924", native: "\u{1F924}" }], version: 3 }, sleeping: { id: "sleeping", name: "Sleeping Face", keywords: ["tired", "sleepy", "night", "zzz"], skins: [{ unified: "1f634", native: "\u{1F634}" }], version: 1 }, face_with_bags_under_eyes: { id: "face_with_bags_under_eyes", name: "Face with Bags Under Eyes", keywords: [], skins: [{ unified: "1fae9", native: "\u{1FAE9}" }], version: 16 }, mask: { id: "mask", name: "Face with Medical Mask", keywords: ["sick", "ill", "disease", "covid"], skins: [{ unified: "1f637", native: "\u{1F637}" }], version: 1 }, face_with_thermometer: { id: "face_with_thermometer", name: "Face with Thermometer", keywords: ["sick", "temperature", "cold", "fever", "covid"], skins: [{ unified: "1f912", native: "\u{1F912}" }], version: 1 }, face_with_head_bandage: { id: "face_with_head_bandage", name: "Face with Head-Bandage", keywords: ["head", "bandage", "injured", "clumsy", "hurt"], skins: [{ unified: "1f915", native: "\u{1F915}" }], version: 1 }, nauseated_face: { id: "nauseated_face", name: "Nauseated Face", keywords: ["vomit", "gross", "green", "sick", "throw", "up", "ill"], skins: [{ unified: "1f922", native: "\u{1F922}" }], version: 3 }, face_vomiting: { id: "face_vomiting", name: "Face Vomiting", keywords: ["with", "open", "mouth", "sick"], skins: [{ unified: "1f92e", native: "\u{1F92E}" }], version: 5 }, sneezing_face: { id: "sneezing_face", name: "Sneezing Face", keywords: ["gesundheit", "sneeze", "sick", "allergy"], skins: [{ unified: "1f927", native: "\u{1F927}" }], version: 3 }, hot_face: { id: "hot_face", name: "Hot Face", keywords: ["feverish", "heat", "red", "sweating"], skins: [{ unified: "1f975", native: "\u{1F975}" }], version: 11 }, cold_face: { id: "cold_face", name: "Cold Face", keywords: ["blue", "freezing", "frozen", "frostbite", "icicles"], skins: [{ unified: "1f976", native: "\u{1F976}" }], version: 11 }, woozy_face: { id: "woozy_face", name: "Woozy Face", keywords: ["dizzy", "intoxicated", "tipsy", "wavy"], skins: [{ unified: "1f974", native: "\u{1F974}" }], version: 11 }, dizzy_face: { id: "dizzy_face", name: "Dizzy Face", keywords: ["spent", "unconscious", "xox"], skins: [{ unified: "1f635", native: "\u{1F635}" }], version: 1 }, face_with_spiral_eyes: { id: "face_with_spiral_eyes", name: "Face with Spiral Eyes", keywords: ["sick", "ill", "confused", "nauseous", "nausea"], skins: [{ unified: "1f635-200d-1f4ab", native: "\u{1F635}\u200D\u{1F4AB}" }], version: 13.1 }, exploding_head: { id: "exploding_head", name: "Exploding Head", keywords: ["shocked", "face", "with", "mind", "blown"], skins: [{ unified: "1f92f", native: "\u{1F92F}" }], version: 5 }, face_with_cowboy_hat: { id: "face_with_cowboy_hat", name: "Cowboy Hat Face", keywords: ["with", "cowgirl"], skins: [{ unified: "1f920", native: "\u{1F920}" }], version: 3 }, partying_face: { id: "partying_face", name: "Partying Face", keywords: ["celebration", "woohoo"], skins: [{ unified: "1f973", native: "\u{1F973}" }], version: 11 }, disguised_face: { id: "disguised_face", name: "Disguised Face", keywords: ["pretent", "brows", "glasses", "moustache"], skins: [{ unified: "1f978", native: "\u{1F978}" }], version: 13 }, sunglasses: { id: "sunglasses", name: "Smiling Face with Sunglasses", emoticons: ["8)"], keywords: ["cool", "smile", "summer", "beach", "sunglass"], skins: [{ unified: "1f60e", native: "\u{1F60E}" }], version: 1 }, nerd_face: { id: "nerd_face", name: "Nerd Face", keywords: ["nerdy", "geek", "dork"], skins: [{ unified: "1f913", native: "\u{1F913}" }], version: 1 }, face_with_monocle: { id: "face_with_monocle", name: "Face with Monocle", keywords: ["stuffy", "wealthy"], skins: [{ unified: "1f9d0", native: "\u{1F9D0}" }], version: 5 }, confused: { id: "confused", name: "Confused Face", emoticons: [":\\", ":-\\", ":/", ":-/"], keywords: ["indifference", "huh", "weird", "hmmm", ":/"], skins: [{ unified: "1f615", native: "\u{1F615}" }], version: 1 }, face_with_diagonal_mouth: { id: "face_with_diagonal_mouth", name: "Face with Diagonal Mouth", keywords: ["skeptic", "confuse", "frustrated", "indifferent"], skins: [{ unified: "1fae4", native: "\u{1FAE4}" }
51763], version: 14 }, worried: { id: "worried", name: "Worried Face", keywords: ["concern", "nervous", ":("], skins: [{ unified: "1f61f", native: "\u{1F61F}" }], version: 1 }, slightly_frowning_face: { id: "slightly_frowning_face", name: "Slightly Frowning Face", keywords: ["disappointed", "sad", "upset"], skins: [{ unified: "1f641", native: "\u{1F641}" }], version: 1 }, white_frowning_face: { id: "white_frowning_face", name: "Frowning Face", keywords: ["white", "sad", "upset", "frown"], skins: [{ unified: "2639-fe0f", native: "\u2639\uFE0F" }], version: 1 }, open_mouth: { id: "open_mouth", name: "Face with Open Mouth", emoticons: [":o", ":-o", ":O", ":-O"], keywords: ["surprise", "impressed", "wow", "whoa", ":O"], skins: [{ unified: "1f62e", native: "\u{1F62E}" }], version: 1 }, hushed: { id: "hushed", name: "Hushed Face", keywords: ["woo", "shh"], skins: [{ unified: "1f62f", native: "\u{1F62F}" }], version: 1 }, astonished: { id: "astonished", name: "Astonished Face", keywords: ["xox", "surprised", "poisoned"], skins: [{ unified: "1f632", native: "\u{1F632}" }], version: 1 }, flushed: { id: "flushed", name: "Flushed Face", keywords: ["blush", "shy", "flattered"], skins: [{ unified: "1f633", native: "\u{1F633}" }], version: 1 }, pleading_face: { id: "pleading_face", name: "Pleading Face", keywords: ["begging", "mercy", "cry", "tears", "sad", "grievance"], skins: [{ unified: "1f97a", native: "\u{1F97A}" }], version: 11 }, face_holding_back_tears: { id: "face_holding_back_tears", name: "Face Holding Back Tears", keywords: ["touched", "gratitude", "cry"], skins: [{ unified: "1f979", native: "\u{1F979}" }], version: 14 }, frowning: { id: "frowning", name: "Frowning Face with Open Mouth", keywords: ["aw", "what"], skins: [{ unified: "1f626", native: "\u{1F626}" }], version: 1 }, anguished: { id: "anguished", name: "Anguished Face", emoticons: ["D:"], keywords: ["stunned", "nervous"], skins: [{ unified: "1f627", native: "\u{1F627}" }], version: 1 }, fearful: { id: "fearful", name: "Fearful Face", keywords: ["scared", "terrified", "nervous"], skins: [{ unified: "1f628", native: "\u{1F628}" }], version: 1 }, cold_sweat: { id: "cold_sweat", name: "Anxious Face with Sweat", keywords: ["cold", "nervous"], skins: [{ unified: "1f630", native: "\u{1F630}" }], version: 1 }, disappointed_relieved: { id: "disappointed_relieved", name: "Sad but Relieved Face", keywords: ["disappointed", "phew", "sweat", "nervous"], skins: [{ unified: "1f625", native: "\u{1F625}" }], version: 1 }, cry: { id: "cry", name: "Crying Face", emoticons: [":'("], keywords: ["cry", "tears", "sad", "depressed", "upset", ":'("], skins: [{ unified: "1f622", native: "\u{1F622}" }], version: 1 }, sob: { id: "sob", name: "Loudly Crying Face", emoticons: [":'("], keywords: ["sob", "sobbing", "cry", "tears", "sad", "upset", "depressed"], skins: [{ unified: "1f62d", native: "\u{1F62D}" }], version: 1 }, scream: { id: "scream", name: "Face Screaming in Fear", keywords: ["scream", "munch", "scared", "omg"], skins: [{ unified: "1f631", native: "\u{1F631}" }], version: 1 }, confounded: { id: "confounded", name: "Confounded Face", keywords: ["confused", "sick", "unwell", "oops", ":S"], skins: [{ unified: "1f616", native: "\u{1F616}" }], version: 1 }, persevere: { id: "persevere", name: "Persevering Face", keywords: ["persevere", "sick", "no", "upset", "oops"], skins: [{ unified: "1f623", native: "\u{1F623}" }], version: 1 }, disappointed: { id: "disappointed", name: "Disappointed Face", emoticons: ["):", ":(", ":-("], keywords: ["sad", "upset", "depressed", ":("], skins: [{ unified: "1f61e", native: "\u{1F61E}" }], version: 1 }, sweat: { id: "sweat", name: "Face with Cold Sweat", keywords: ["downcast", "hot", "sad", "tired", "exercise"], skins: [{ unified: "1f613", native: "\u{1F613}" }], version: 1 }, weary: { id: "weary", name: "Weary Face", keywords: ["tired", "sleepy", "sad", "frustrated", "upset"], skins: [{ unified: "1f629", native: "\u{1F629}" }], version: 1 }, tired_face: { id: "tired_face", name: "Tired Face", keywords: ["sick", "whine", "upset", "frustrated"], skins: [{ unified: "1f62b", native: "\u{1F62B}" }], version: 1 }, yawning_face: { id: "yawning_face", name: "Yawning Face", keywords: ["tired", "sleepy"], skins: [{ unified: "1f971", native: "\u{1F971}" }], version: 12 }, triumph: { id: "triumph", name: "Face with Look of Triumph", keywords: ["steam", "from", "nose", "gas", "phew", "proud", "pride"], skins: [{ unified: "1f624", native: "\u{1F624}" }], version: 1 }, rage: { id: "rage", name: "Pouting Face", keywords: ["rage", "angry", "mad", "hate", "despise"], skins: [{ unified: "1f621", native: "\u{1F621}" }], version: 1 }, angry: { id: "angry", name: "Angry Face", emoticons: [">:(", ">:-("], keywords: ["mad", "annoyed", "frustrated"], skins: [{ unified: "1f620", native: "\u{1F620}" }], version: 1 }, face_with_symbols_on_mouth: { id: "face_with_symbols_on_mouth", name: "Face with Symbols on Mouth", keywords: ["serious", "covering", "swearing", "cursing", "cussing", "profanity", "expletive"], skins: [{ unified: "1f92c", native: "\u{1F92C}" }], version: 5 }, smiling_imp: { id: "smiling_imp", name: "Smiling Face with Horns", keywords: ["imp", "devil"], skins: [{ unified: "1f608", native: "\u{1F608}" }], version: 1 }, imp: { id: "imp", name: "Imp", keywords: ["angry", "face", "with", "horns", "devil"], skins: [{ unified: "1f47f", native: "\u{1F47F}" }], version: 1 }, skull: { id: "skull", name: "Skull", keywords: ["dead", "skeleton", "creepy", "death"], skins: [{ unified: "1f480", native: "\u{1F480}" }], version: 1 }, skull_and_crossbones: { id: "skull_and_crossbones", name: "Skull and Crossbones", keywords: ["poison", "danger", "deadly", "scary", "death", "pirate", "evil"], skins: [{ unified: "2620-fe0f", native: "\u2620\uFE0F" }], version: 1 }, hankey: { id: "hankey", name: "Pile of Poo", keywords: ["hankey", "poop", "shit", "shitface", "fail", "turd"], skins: [{ unified: "1f4a9", native: "\u{1F4A9}" }], version: 1 }, clown_face: { id: "clown_face", name: "Clown Face", keywords: [], skins: [{ unified: "1f921", native: "\u{1F921}" }], version: 3 }, japanese_ogre: { id: "japanese_ogre", name: "Ogre", keywords: ["japanese", "monster", "red", "mask", "halloween", "scary", "creepy", "devil", "demon"], skins: [{ unified: "1f479", native: "\u{1F479}" }], version: 1 }, japanese_goblin: { id: "japanese_goblin", name: "Goblin", keywords: ["japanese", "red", "evil", "mask", "monster", "scary", "creepy"], skins: [{ unified: "1f47a", native: "\u{1F47A}" }], version: 1 }, ghost: { id: "ghost", name: "Ghost", keywords: ["halloween", "spooky", "scary"], skins: [{ unified: "1f47b", native: "\u{1F47B}" }], version: 1 }, alien: { id: "alien", name: "Alien", keywords: ["UFO", "paul", "weird", "outer", "space"], skins: [{ unified: "1f47d", native: "\u{1F47D}" }], version: 1 }, space_invader: { id: "space_invader", name: "Alien Monster", keywords: ["space", "invader", "game", "arcade", "play"], skins: [{ unified: "1f47e", native: "\u{1F47E}" }], version: 1 }, robot_face: { id: "robot_face", name: "Robot", keywords: ["face", "computer", "machine", "bot"], skins: [{ unified: "1f916", native: "\u{1F916}" }], version: 1 }, smiley_cat: { id: "smiley_cat", name: "Grinning Cat", keywords: ["smiley", "animal", "cats", "happy", "smile"], skins: [{ unified: "1f63a", native: "\u{1F63A}" }], version: 1 }, smile_cat: { id: "smile_cat", name: "Grinning Cat with Smiling Eyes", keywords: ["smile", "animal", "cats"], skins: [{ unified: "1f638", native: "\u{1F638}" }], version: 1 }, joy_cat: { id: "joy_cat", name: "Cat with Tears of Joy", keywords: ["animal", "cats", "haha", "happy"], skins: [{ unified: "1f639", native: "\u{1F639}" }], version: 1 }, heart_eyes_cat: { id: "heart_eyes_cat", name: "Smiling Cat with Heart-Eyes", keywords: ["heart", "eyes", "animal", "love", "like", "affection", "cats", "valentines"], skins: [{ unified: "1f63b", native: "\u{1F63B}" }], version: 1 }, smirk_cat: { id: "smirk_cat", name: "Cat with Wry Smile", keywords: ["smirk", "animal", "cats"], skins: [{ unified: "1f63c", native: "\u{1F63C}" }], version: 1 }
51763, kissing_cat: { id: "kissing_cat", name: "Kissing Cat", keywords: ["animal", "cats", "kiss"], skins: [{ unified: "1f63d", native: "\u{1F63D}" }], version: 1 }, scream_cat: { id: "scream_cat", name: "Weary Cat", keywords: ["scream", "animal", "cats", "munch", "scared"], skins: [{ unified: "1f640", native: "\u{1F640}" }], version: 1 }, crying_cat_face: { id: "crying_cat_face", name: "Crying Cat", keywords: ["face", "animal", "tears", "weep", "sad", "cats", "upset", "cry"], skins: [{ unified: "1f63f", native: "\u{1F63F}" }], version: 1 }, pouting_cat: { id: "pouting_cat", name: "Pouting Cat", keywords: ["animal", "cats"], skins: [{ unified: "1f63e", native: "\u{1F63E}" }], version: 1 }, see_no_evil: { id: "see_no_evil", name: "See-No-Evil Monkey", keywords: ["see", "no", "evil", "animal", "nature", "haha"], skins: [{ unified: "1f648", native: "\u{1F648}" }], version: 1 }, hear_no_evil: { id: "hear_no_evil", name: "Hear-No-Evil Monkey", keywords: ["hear", "no", "evil", "animal", "nature"], skins: [{ unified: "1f649", native: "\u{1F649}" }], version: 1 }, speak_no_evil: { id: "speak_no_evil", name: "Speak-No-Evil Monkey", keywords: ["speak", "no", "evil", "animal", "nature", "omg"], skins: [{ unified: "1f64a", native: "\u{1F64A}" }], version: 1 }, love_letter: { id: "love_letter", name: "Love Letter", keywords: ["email", "like", "affection", "envelope", "valentines"], skins: [{ unified: "1f48c", native: "\u{1F48C}" }], version: 1 }, cupid: { id: "cupid", name: "Heart with Arrow", keywords: ["cupid", "love", "like", "affection", "valentines"], skins: [{ unified: "1f498", native: "\u{1F498}" }], version: 1 }, gift_heart: { id: "gift_heart", name: "Heart with Ribbon", keywords: ["gift", "love", "valentines"], skins: [{ unified: "1f49d", native: "\u{1F49D}" }], version: 1 }, sparkling_heart: { id: "sparkling_heart", name: "Sparkling Heart", keywords: ["love", "like", "affection", "valentines"], skins: [{ unified: "1f496", native: "\u{1F496}" }], version: 1 }, heartpulse: { id: "heartpulse", name: "Growing Heart", keywords: ["heartpulse", "like", "love", "affection", "valentines", "pink"], skins: [{ unified: "1f497", native: "\u{1F497}" }], version: 1 }, heartbeat: { id: "heartbeat", name: "Beating Heart", keywords: ["heartbeat", "love", "like", "affection", "valentines", "pink"], skins: [{ unified: "1f493", native: "\u{1F493}" }], version: 1 }, revolving_hearts: { id: "revolving_hearts", name: "Revolving Hearts", keywords: ["love", "like", "affection", "valentines"], skins: [{ unified: "1f49e", native: "\u{1F49E}" }], version: 1 }, two_hearts: { id: "two_hearts", name: "Two Hearts", keywords: ["love", "like", "affection", "valentines", "heart"], skins: [{ unified: "1f495", native: "\u{1F495}" }], version: 1 }, heart_decoration: { id: "heart_decoration", name: "Heart Decoration", keywords: ["purple", "square", "love", "like"], skins: [{ unified: "1f49f", native: "\u{1F49F}" }], version: 1 }, heavy_heart_exclamation_mark_ornament: { id: "heavy_heart_exclamation_mark_ornament", name: "Heart Exclamation", keywords: ["heavy", "mark", "ornament", "decoration", "love"], skins: [{ unified: "2763-fe0f", native: "\u2763\uFE0F" }], version: 1 }, broken_heart: { id: "broken_heart", name: "Broken Heart", emoticons: ["</3"], keywords: ["sad", "sorry", "break", "heartbreak"], skins: [{ unified: "1f494", native: "\u{1F494}" }], version: 1 }, heart_on_fire: { id: "heart_on_fire", name: "Heart on Fire", keywords: ["passionate", "enthusiastic"], skins: [{ unified: "2764-fe0f-200d-1f525", native: "\u2764\uFE0F\u200D\u{1F525}" }], version: 13.1 }, mending_heart: { id: "mending_heart", name: "Mending Heart", keywords: ["broken", "bandage", "wounded"], skins: [{ unified: "2764-fe0f-200d-1fa79", native: "\u2764\uFE0F\u200D\u{1FA79}" }], version: 13.1 }, heart: { id: "heart", name: "Red Heart", emoticons: ["<3"], keywords: ["love", "like", "valentines"], skins: [{ unified: "2764-fe0f", native: "\u2764\uFE0F" }], version: 1 }, pink_heart: { id: "pink_heart", name: "Pink Heart", keywords: ["valentines"], skins: [{ unified: "1fa77", native: "\u{1FA77}" }], version: 15 }, orange_heart: { id: "orange_heart", name: "Orange Heart", keywords: ["love", "like", "affection", "valentines"], skins: [{ unified: "1f9e1", native: "\u{1F9E1}" }], version: 5 }, yellow_heart: { id: "yellow_heart", name: "Yellow Heart", emoticons: ["<3"], keywords: ["love", "like", "affection", "valentines"], skins: [{ unified: "1f49b", native: "\u{1F49B}" }], version: 1 }, green_heart: { id: "green_heart", name: "Green Heart", emoticons: ["<3"], keywords: ["love", "like", "affection", "valentines"], skins: [{ unified: "1f49a", native: "\u{1F49A}" }], version: 1 }, blue_heart: { id: "blue_heart", name: "Blue Heart", emoticons: ["<3"], keywords: ["love", "like", "affection", "valentines"], skins: [{ unified: "1f499", native: "\u{1F499}" }], version: 1 }, light_blue_heart: { id: "light_blue_heart", name: "Light Blue Heart", keywords: ["ice", "baby"], skins: [{ unified: "1fa75", native: "\u{1FA75}" }], version: 15 }, purple_heart: { id: "purple_heart", name: "Purple Heart", emoticons: ["<3"], keywords: ["love", "like", "affection", "valentines"], skins: [{ unified: "1f49c", native: "\u{1F49C}" }], version: 1 }, brown_heart: { id: "brown_heart", name: "Brown Heart", keywords: ["coffee"], skins: [{ unified: "1f90e", native: "\u{1F90E}" }], version: 12 }, black_heart: { id: "black_heart", name: "Black Heart", keywords: ["evil"], skins: [{ unified: "1f5a4", native: "\u{1F5A4}" }], version: 3 }, grey_heart: { id: "grey_heart", name: "Grey Heart", keywords: ["silver", "monochrome"], skins: [{ unified: "1fa76", native: "\u{1FA76}" }], version: 15 }, white_heart: { id: "white_heart", name: "White Heart", keywords: ["pure"], skins: [{ unified: "1f90d", native: "\u{1F90D}" }], version: 12 }, kiss: { id: "kiss", name: "Kiss Mark", keywords: ["face", "lips", "love", "like", "affection", "valentines"], skins: [{ unified: "1f48b", native: "\u{1F48B}" }], version: 1 }, anger: { id: "anger", name: "Anger Symbol", keywords: ["angry", "mad"], skins: [{ unified: "1f4a2", native: "\u{1F4A2}" }], version: 1 }, boom: { id: "boom", name: "Collision", keywords: ["boom", "bomb", "explode", "explosion", "blown"], skins: [{ unified: "1f4a5", native: "\u{1F4A5}" }], version: 1 }, dizzy: { id: "dizzy", name: "Dizzy", keywords: ["star", "sparkle", "shoot", "magic"], skins: [{ unified: "1f4ab", native: "\u{1F4AB}" }], version: 1 }, sweat_drops: { id: "sweat_drops", name: "Sweat Droplets", keywords: ["drops", "water", "drip", "oops"], skins: [{ unified: "1f4a6", native: "\u{1F4A6}" }], version: 1 }, dash: { id: "dash", name: "Dash Symbol", keywords: ["dashing", "away", "wind", "air", "fast", "shoo", "fart", "smoke", "puff"], skins: [{ unified: "1f4a8", native: "\u{1F4A8}" }], version: 1 }, hole: { id: "hole", name: "Hole", keywords: ["embarrassing"], skins: [{ unified: "1f573-fe0f", native: "\u{1F573}\uFE0F" }], version: 1 }, speech_balloon: { id: "speech_balloon", name: "Speech Balloon", keywords: ["bubble", "words", "message", "talk", "chatting"], skins: [{ unified: "1f4ac", native: "\u{1F4AC}" }], version: 1 }, "eye-in-speech-bubble": { id: "eye-in-speech-bubble", name: "Eye in Speech Bubble", keywords: ["in-speech-bubble", "info"], skins: [{ unified: "1f441-fe0f-200d-1f5e8-fe0f", native: "\u{1F441}\uFE0F\u200D\u{1F5E8}\uFE0F" }], version: 2 }, left_speech_bubble: { id: "left_speech_bubble", name: "Left Speech Bubble", keywords: ["words", "message", "talk", "chatting"], skins: [{ unified: "1f5e8-fe0f", native: "\u{1F5E8}\uFE0F" }], version: 2 }, right_anger_bubble: { id: "right_anger_bubble", name: "Right Anger Bubble", keywords: ["caption", "speech", "thinking", "mad"], skins: [{ unified: "1f5ef-fe0f", native: "\u{1F5EF}\uFE0F" }], version: 1 }, thought_balloon: { id: "thought_balloon", name: "Thought Balloon", keywords: ["bubble", "cloud", "speech", "thinking", "dream"], skins: [{ unified: "1f4ad", native: "\u{1F4AD}" }], version: 1 }, zzz: { id: "zzz", name: "Zzz", keywords: ["sleepy", "tired", "dream"], skins: [{ unified: "1f4a4", native: "\u{1F4A4}" }], version: 1 }, wave: { id: "wave", name: "Waving Hand", keywords: ["wave", "hands", "gesture", "goodbye", "solong", "farewell", "hello", "hi", "palm"], skins: [{ unified: "1f44b", native: "\u{1F44B}" }, { unified: "1f44b-1f3fb", native: "\u{1F44B}\u{1F3FB}" }, { unified: "1f44b-1f3fc", native: "\u{1F44B}\u{1F3FC}" }, { unified: "1f44b-1f3fd", native: "\u{1F44B}\u{1F3FD}" }, { unified: "1f44b-1f3fe", native: "\u{1F44B}\u{1F3FE}" }, { unified: "1f44b-1f3ff", native: "\u{1F44B}\u{1F3FF}" }], version: 1 }, raised_back_of_hand: { id: "raised_back_of_hand", name: "Raised Back of Hand", keywords: ["fingers", "backhand"], skins: [{ unified: "1f91a", native: "\u{1F91A}" }, { unified: "1f91a-1f3fb", native: "\u{1F91A}\u{1F3FB}" }, { unified: "1f91a-1f3fc", native: "\u{1F91A}\u{1F3FC}" }, { unified: "1f91a-1f3fd", native: "\u{1F91A}\u{1F3FD}" }, { unified: "1f91a-1f3fe", native: "\u{1F91A}\u{1F3FE}" }, { unified: "1f91a-1f3ff", native: "\u{1F91A}\u{1F3FF}" }], version: 3 }, raised_hand_with_fingers_splayed: { id: "raised_hand_with_fingers_splayed", name: "Hand with Fingers Splayed", keywords: ["raised", "palm"], skins: [{ unified: "1f590-fe0f", native: "\u{1F590}\uFE0F" }, { unified: "1f590-1f3fb", native: "\u{1F590}\u{1F3FB}" }, { unified: "1f590-1f3fc", native: "\u{1F590}\u{1F3FC}" }, { unified: "1f590-1f3fd", native: "\u{1F590}\u{1F3FD}" }, { unified: "1f590-1f3fe", native: "\u{1F590}\u{1F3FE}" }, { unified: "1f590-1f3ff", native: "\u{1F590}\u{1F3FF}" }], version: 1 }, hand: { id: "hand", name: "Raised Hand", keywords: ["fingers", "stop", "highfive", "high", "five", "palm", "ban"], skins: [{ unified: "270b", native: "\u270B" }, { unified: "270b-1f3fb", native: "\u270B\u{1F3FB}" }, { unified: "270b-1f3fc", native: "\u270B\u{1F3FC}" }, { unified: "270b-1f3fd", native: "\u270B\u{1F3FD}" }, { unified: "270b-1f3fe", native: "\u270B\u{1F3FE}" }, { unified: "270b-1f3ff", native: "\u270B\u{1F3FF}" }], version: 1 }, "spock-hand": { id: "spock-hand", name: "Vulcan Salute", keywords: ["spock", "hand", "fingers", "star", "trek"], skins: [{ unified: "1f596", native: "\u{1F596}" }, { unified: "1f596-1f3fb", native: "\u{1F596}\u{1F3FB}" }, { unified: "1f596-1f3fc", native: "\u{1F596}\u{1F3FC}" }, { unified: "1f596-1f3fd", native: "\u{1F596}\u{1F3FD}" }, { unified: "1f596-1f3fe", native: "\u{1F596}\u{1F3FE}" }, { unified: "1f596-1f3ff", native: "\u{1F596}\u{1F3FF}" }], version: 1 }, rightwards_hand: { id: "rightwards_hand", name: "Rightwards Hand", keywords: ["palm", "offer"], skins: [{ unified: "1faf1", native: "\u{1FAF1}" }, { unified: "1faf1-1f3fb", native: "\u{1FAF1}\u{1F3FB}" }, { unified: "1faf1-1f3fc", native: "\u{1FAF1}\u{1F3FC}" }, { unified: "1faf1-1f3fd", native: "\u{1FAF1}\u{1F3FD}" }, { unified: "1faf1-1f3fe", native: "\u{1FAF1}\u{1F3FE}" }, { unified: "1faf1-1f3ff", native: "\u{1FAF1}\u{1F3FF}" }], version: 14 }, leftwards_hand: { id: "leftwards_hand", name: "Leftwards Hand", keywords: ["palm", "offer"], skins: [{ unified: "1faf2", native: "\u{1FAF2}" }, { unified: "1faf2-1f3fb", native: "\u{1FAF2}\u{1F3FB}" }, { unified: "1faf2-1f3fc", native: "\u{1FAF2}\u{1F3FC}" }, { unified: "1faf2-1f3fd", native: "\u{1FAF2}\u{1F3FD}" }, { unified: "1faf2-1f3fe", native: "\u{1FAF2}\u{1F3FE}" }, { unified: "1faf2-1f3ff", native: "\u{1FAF2}\u{1F3FF}" }], version: 14 }, palm_down_hand: { id: "palm_down_hand", name: "Palm Down Hand", keywords: ["drop"], skins: [{ unified: "1faf3", native: "\u{1FAF3}" }, { unified: "1faf3-1f3fb", native: "\u{1FAF3}\u{1F3FB}" }, { unified: "1faf3-1f3fc", native: "\u{1FAF3}\u{1F3FC}" }, { unified: "1faf3-1f3fd", native: "\u{1FAF3}\u{1F3FD}" }, { unified: "1faf3-1f3fe", native: "\u{1FAF3}\u{1F3FE}" }, { unified: "1faf3-1f3ff", native: "\u{1FAF3}\u{1F3FF}" }], version: 14 }, palm_up_hand: { id: "palm_up_hand", name: "Palm Up Hand", keywords: ["lift", "offer", "demand"], skins: [{ unified: "1faf4", native: "\u{1FAF4}" }, { unified: "1faf4-1f3fb", native: "\u{1FAF4}\u{1F3FB}" }, { unified: "1faf4-1f3fc", native: "\u{1FAF4}\u{1F3FC}" }, { unified: "1faf4-1f3fd", native: "\u{1FAF4}\u{1F3FD}" }, { unified: "1faf4-1f3fe", native: "\u{1FAF4}\u{1F3FE}" }, { unified: "1faf4-1f3ff", native: "\u{1FAF4}\u{1F3FF}" }], version: 14 }, leftwards_pushing_hand: { id: "leftwards_pushing_hand", name: "Leftwards Pushing Hand", keywords: ["highfive", "high", "five", "pressing", "stop"], skins: [{ unified: "1faf7", native: "\u{1FAF7}" }, { unified: "1faf7-1f3fb", native: "\u{1FAF7}\u{1F3FB}" }, { unified: "1faf7-1f3fc", native: "\u{1FAF7}\u{1F3FC}" }, { unified: "1faf7-1f3fd", native: "\u{1FAF7}\u{1F3FD}" }, { unified: "1faf7-1f3fe", native: "\u{1FAF7}\u{1F3FE}" }, { unified: "1faf7-1f3ff", native: "\u{1FAF7}\u{1F3FF}" }], version: 15 }, rightwards_pushing_hand: { id: "rightwards_pushing_hand", name: "Rightwards Pushing Hand", keywords: ["highfive", "high", "five", "pressing", "stop"], skins: [{ unified: "1faf8", native: "\u{1FAF8}" }, { unified: "1faf8-1f3fb", native: "\u{1FAF8}\u{1F3FB}" }, { unified: "1faf8-1f3fc", native: "\u{1FAF8}\u{1F3FC}" }, { unified: "1faf8-1f3fd", native: "\u{1FAF8}\u{1F3FD}" }, { unified: "1faf8-1f3fe", native: "\u{1FAF8}\u{1F3FE}" }, { unified: "1faf8-1f3ff", native: "\u{1FAF8}\u{1F3FF}" }], version: 15 }, ok_hand: { id: "ok_hand", name: "Ok Hand", keywords: ["fingers", "limbs", "perfect", "okay"], skins: [{ unified: "1f44c", native: "\u{1F44C}" }, { unified: "1f44c-1f3fb", native: "\u{1F44C}\u{1F3FB}" }, { unified: "1f44c-1f3fc", native: "\u{1F44C}\u{1F3FC}" }, { unified: "1f44c-1f3fd", native: "\u{1F44C}\u{1F3FD}" }, { unified: "1f44c-1f3fe", native: "\u{1F44C}\u{1F3FE}" }, { unified: "1f44c-1f3ff", native: "\u{1F44C}\u{1F3FF}" }], version: 1 }, pinched_fingers: { id: "pinched_fingers", name: "Pinched Fingers", keywords: ["size", "tiny", "small"], skins: [{ unified: "1f90c", native: "\u{1F90C}" }, { unified: "1f90c-1f3fb", native: "\u{1F90C}\u{1F3FB}" }, { unified: "1f90c-1f3fc", native: "\u{1F90C}\u{1F3FC}" }, { unified: "1f90c-1f3fd", native: "\u{1F90C}\u{1F3FD}" }, { unified: "1f90c-1f3fe", native: "\u{1F90C}\u{1F3FE}" }, { unified: "1f90c-1f3ff", native: "\u{1F90C}\u{1F3FF}" }], version: 13 }, pinching_hand: { id: "pinching_hand", name: "Pinching Hand", keywords: ["tiny", "small", "size"], skins: [{ unified: "1f90f", native: "\u{1F90F}" }, { unified: "1f90f-1f3fb", native: "\u{1F90F}\u{1F3FB}" }, { unified: "1f90f-1f3fc", native: "\u{1F90F}\u{1F3FC}" }, { unified: "1f90f-1f3fd", native: "\u{1F90F}\u{1F3FD}" }, { unified: "1f90f-1f3fe", native: "\u{1F90F}\u{1F3FE}" }, { unified: "1f90f-1f3ff", native: "\u{1F90F}\u{1F3FF}" }], version: 12 }, v: { id: "v", name: "Victory Hand", keywords: ["v", "fingers", "ohyeah", "peace", "two"], skins: [{ unified: "270c-fe0f", native: "\u270C\uFE0F" }, { unified: "270c-1f3fb", native: "\u270C\u{1F3FB}" }, { unified: "270c-1f3fc", native: "\u270C\u{1F3FC}" }, { unified: "270c-1f3fd", native: "\u270C\u{1F3FD}" }, { unified: "270c-1f3fe", native: "\u270C\u{1F3FE}" }, { unified: "270c-1f3ff", native: "\u270C\u{1F3FF}" }], version: 1 }, crossed_fingers: { id: "crossed_fingers", name: "Crossed Fingers", keywords: ["hand", "with", "index", "and", "middle", "good", "lucky"], skins: [{ unified: "1f91e", native: "\u{1F91E}" }, { unified: "1f91e-1f3fb", native: "\u{1F91E}\u{1F3FB}" }, { unified: "1f91e-1f3fc", native: "\u{1F91E}\u{1F3FC}" }, { unified: "1f91e-1f3fd", native: "\u{1F91E}\u{1F3FD}" }, { unified: "1f91e-1f3fe", native: "\u{1F91E}\u{1F3FE}" }, { unified: "1f91e-1f3ff", native: "\u{1F91E}\u{1F3FF}" }], version: 3 }, hand_with_index_finger_and_thumb_crossed: { id: "hand_with_index_finger_and_thumb_crossed", name: "Hand with Index Finger and Thumb Crossed", keywords: ["heart", "love", "money", "expensive"], skins: [{ unified: "1faf0", native: "\u{1FAF0}" }, { unified: "1faf0-1f3fb", native: "\u{1FAF0}\u{1F3FB}" }, { unified: "1faf0-1f3fc", native: "\u{1FAF0}\u{1F3FC}" }, { unified: "1faf0-1f3fd", native: "\u{1FAF0}\u{1F3FD}" }, { unified: "1faf0-1f3fe", native: "\u{1FAF0}\u{1F3FE}" }, { unified: "1faf0-1f3ff", native: "\u{1FAF0}\u{1F3FF}" }], version: 14 }, i_love_you_hand_sign: { id: "i_love_you_hand_sign", name: "Love-You Gesture", keywords: ["i", "love", "you", "hand", "sign", "fingers"], skins: [{ unified: "1f91f", native: "\u{1F91F}" }, { unified: "1f91f-1f3fb", na
51763tive: "\u{1F91F}\u{1F3FB}" }, { unified: "1f91f-1f3fc", native: "\u{1F91F}\u{1F3FC}" }, { unified: "1f91f-1f3fd", native: "\u{1F91F}\u{1F3FD}" }, { unified: "1f91f-1f3fe", native: "\u{1F91F}\u{1F3FE}" }, { unified: "1f91f-1f3ff", native: "\u{1F91F}\u{1F3FF}" }], version: 5 }, the_horns: { id: "the_horns", name: "Sign of the Horns", keywords: ["hand", "fingers", "evil", "eye", "rock", "on"], skins: [{ unified: "1f918", native: "\u{1F918}" }, { unified: "1f918-1f3fb", native: "\u{1F918}\u{1F3FB}" }, { unified: "1f918-1f3fc", native: "\u{1F918}\u{1F3FC}" }, { unified: "1f918-1f3fd", native: "\u{1F918}\u{1F3FD}" }, { unified: "1f918-1f3fe", native: "\u{1F918}\u{1F3FE}" }, { unified: "1f918-1f3ff", native: "\u{1F918}\u{1F3FF}" }], version: 1 }, call_me_hand: { id: "call_me_hand", name: "Call Me Hand", keywords: ["hands", "gesture", "shaka"], skins: [{ unified: "1f919", native: "\u{1F919}" }, { unified: "1f919-1f3fb", native: "\u{1F919}\u{1F3FB}" }, { unified: "1f919-1f3fc", native: "\u{1F919}\u{1F3FC}" }, { unified: "1f919-1f3fd", native: "\u{1F919}\u{1F3FD}" }, { unified: "1f919-1f3fe", native: "\u{1F919}\u{1F3FE}" }, { unified: "1f919-1f3ff", native: "\u{1F919}\u{1F3FF}" }], version: 3 }, point_left: { id: "point_left", name: "Backhand Index Pointing Left", keywords: ["point", "direction", "fingers", "hand"], skins: [{ unified: "1f448", native: "\u{1F448}" }, { unified: "1f448-1f3fb", native: "\u{1F448}\u{1F3FB}" }, { unified: "1f448-1f3fc", native: "\u{1F448}\u{1F3FC}" }, { unified: "1f448-1f3fd", native: "\u{1F448}\u{1F3FD}" }, { unified: "1f448-1f3fe", native: "\u{1F448}\u{1F3FE}" }, { unified: "1f448-1f3ff", native: "\u{1F448}\u{1F3FF}" }], version: 1 }, point_right: { id: "point_right", name: "Backhand Index Pointing Right", keywords: ["point", "fingers", "hand", "direction"], skins: [{ unified: "1f449", native: "\u{1F449}" }, { unified: "1f449-1f3fb", native: "\u{1F449}\u{1F3FB}" }, { unified: "1f449-1f3fc", native: "\u{1F449}\u{1F3FC}" }, { unified: "1f449-1f3fd", native: "\u{1F449}\u{1F3FD}" }, { unified: "1f449-1f3fe", native: "\u{1F449}\u{1F3FE}" }, { unified: "1f449-1f3ff", native: "\u{1F449}\u{1F3FF}" }], version: 1 }, point_up_2: { id: "point_up_2", name: "Backhand Index Pointing Up", keywords: ["point", "2", "fingers", "hand", "direction"], skins: [{ unified: "1f446", native: "\u{1F446}" }, { unified: "1f446-1f3fb", native: "\u{1F446}\u{1F3FB}" }, { unified: "1f446-1f3fc", native: "\u{1F446}\u{1F3FC}" }, { unified: "1f446-1f3fd", native: "\u{1F446}\u{1F3FD}" }, { unified: "1f446-1f3fe", native: "\u{1F446}\u{1F3FE}" }, { unified: "1f446-1f3ff", native: "\u{1F446}\u{1F3FF}" }], version: 1 }, middle_finger: { id: "middle_finger", name: "Middle Finger", keywords: ["reversed", "hand", "with", "extended", "fingers", "rude", "flipping"], skins: [{ unified: "1f595", native: "\u{1F595}" }, { unified: "1f595-1f3fb", native: "\u{1F595}\u{1F3FB}" }, { unified: "1f595-1f3fc", native: "\u{1F595}\u{1F3FC}" }, { unified: "1f595-1f3fd", native: "\u{1F595}\u{1F3FD}" }, { unified: "1f595-1f3fe", native: "\u{1F595}\u{1F3FE}" }, { unified: "1f595-1f3ff", native: "\u{1F595}\u{1F3FF}" }], version: 1 }, point_down: { id: "point_down", name: "Backhand Index Pointing Down", keywords: ["point", "fingers", "hand", "direction"], skins: [{ unified: "1f447", native: "\u{1F447}" }, { unified: "1f447-1f3fb", native: "\u{1F447}\u{1F3FB}" }, { unified: "1f447-1f3fc", native: "\u{1F447}\u{1F3FC}" }, { unified: "1f447-1f3fd", native: "\u{1F447}\u{1F3FD}" }, { unified: "1f447-1f3fe", native: "\u{1F447}\u{1F3FE}" }, { unified: "1f447-1f3ff", native: "\u{1F447}\u{1F3FF}" }], version: 1 }, point_up: { id: "point_up", name: "Index Pointing Up", keywords: ["point", "hand", "fingers", "direction"], skins: [{ unified: "261d-fe0f", native: "\u261D\uFE0F" }, { unified: "261d-1f3fb", native: "\u261D\u{1F3FB}" }, { unified: "261d-1f3fc", native: "\u261D\u{1F3FC}" }, { unified: "261d-1f3fd", native: "\u261D\u{1F3FD}" }, { unified: "261d-1f3fe", native: "\u261D\u{1F3FE}" }, { unified: "261d-1f3ff", native: "\u261D\u{1F3FF}" }], version: 1 }, index_pointing_at_the_viewer: { id: "index_pointing_at_the_viewer", name: "Index Pointing at the Viewer", keywords: ["you", "recruit"], skins: [{ unified: "1faf5", native: "\u{1FAF5}" }, { unified: "1faf5-1f3fb", native: "\u{1FAF5}\u{1F3FB}" }, { unified: "1faf5-1f3fc", native: "\u{1FAF5}\u{1F3FC}" }, { unified: "1faf5-1f3fd", native: "\u{1FAF5}\u{1F3FD}" }, { unified: "1faf5-1f3fe", native: "\u{1FAF5}\u{1F3FE}" }, { unified: "1faf5-1f3ff", native: "\u{1FAF5}\u{1F3FF}" }], version: 14 }, "+1": { id: "+1", name: "Thumbs Up", keywords: ["+1", "thumbsup", "yes", "awesome", "good", "agree", "accept", "cool", "hand", "like"], skins: [{ unified: "1f44d", native: "\u{1F44D}" }, { unified: "1f44d-1f3fb", native: "\u{1F44D}\u{1F3FB}" }, { unified: "1f44d-1f3fc", native: "\u{1F44D}\u{1F3FC}" }, { unified: "1f44d-1f3fd", native: "\u{1F44D}\u{1F3FD}" }, { unified: "1f44d-1f3fe", native: "\u{1F44D}\u{1F3FE}" }, { unified: "1f44d-1f3ff", native: "\u{1F44D}\u{1F3FF}" }], version: 1 }, "-1": { id: "-1", name: "Thumbs Down", keywords: ["-1", "thumbsdown", "no", "dislike", "hand"], skins: [{ unified: "1f44e", native: "\u{1F44E}" }, { unified: "1f44e-1f3fb", native: "\u{1F44E}\u{1F3FB}" }, { unified: "1f44e-1f3fc", native: "\u{1F44E}\u{1F3FC}" }, { unified: "1f44e-1f3fd", native: "\u{1F44E}\u{1F3FD}" }, { unified: "1f44e-1f3fe", native: "\u{1F44E}\u{1F3FE}" }, { unified: "1f44e-1f3ff", native: "\u{1F44E}\u{1F3FF}" }], version: 1 }, fist: { id: "fist", name: "Raised Fist", keywords: ["fingers", "hand", "grasp"], skins: [{ unified: "270a", native: "\u270A" }, { unified: "270a-1f3fb", native: "\u270A\u{1F3FB}" }, { unified: "270a-1f3fc", native: "\u270A\u{1F3FC}" }, { unified: "270a-1f3fd", native: "\u270A\u{1F3FD}" }, { unified: "270a-1f3fe", native: "\u270A\u{1F3FE}" }, { unified: "270a-1f3ff", native: "\u270A\u{1F3FF}" }], version: 1 }, facepunch: { id: "facepunch", name: "Oncoming Fist", keywords: ["facepunch", "punch", "angry", "violence", "hit", "attack", "hand"], skins: [{ unified: "1f44a", native: "\u{1F44A}" }, { unified: "1f44a-1f3fb", native: "\u{1F44A}\u{1F3FB}" }, { unified: "1f44a-1f3fc", native: "\u{1F44A}\u{1F3FC}" }, { unified: "1f44a-1f3fd", native: "\u{1F44A}\u{1F3FD}" }, { unified: "1f44a-1f3fe", native: "\u{1F44A}\u{1F3FE}" }, { unified: "1f44a-1f3ff", native: "\u{1F44A}\u{1F3FF}" }], version: 1 }, "left-facing_fist": { id: "left-facing_fist", name: "Left-Facing Fist", keywords: ["left", "facing", "hand", "fistbump"], skins: [{ unified: "1f91b", native: "\u{1F91B}" }, { unified: "1f91b-1f3fb", native: "\u{1F91B}\u{1F3FB}" }, { unified: "1f91b-1f3fc", native: "\u{1F91B}\u{1F3FC}" }, { unified: "1f91b-1f3fd", native: "\u{1F91B}\u{1F3FD}" }, { unified: "1f91b-1f3fe", native: "\u{1F91B}\u{1F3FE}" }, { unified: "1f91b-1f3ff", native: "\u{1F91B}\u{1F3FF}" }], version: 3 }, "right-facing_fist": { id: "right-facing_fist", name: "Right-Facing Fist", keywords: ["right", "facing", "hand", "fistbump"], skins: [{ unified: "1f91c", native: "\u{1F91C}" }, { unified: "1f91c-1f3fb", native: "\u{1F91C}\u{1F3FB}" }, { unified: "1f91c-1f3fc", native: "\u{1F91C}\u{1F3FC}" }, { unified: "1f91c-1f3fd", native: "\u{1F91C}\u{1F3FD}" }, { unified: "1f91c-1f3fe", native: "\u{1F91C}\u{1F3FE}" }, { unified: "1f91c-1f3ff", native: "\u{1F91C}\u{1F3FF}" }], version: 3 }, clap: { id: "clap", name: "Clapping Hands", keywords: ["clap", "praise", "applause", "congrats", "yay"], skins: [{ unified: "1f44f", native: "\u{1F44F}" }, { unified: "1f44f-1f3fb", native: "\u{1F44F}\u{1F3FB}" }, { unified: "1f44f-1f3fc", native: "\u{1F44F}\u{1F3FC}" }, { unified: "1f44f-1f3fd", native: "\u{1F44F}\u{1F3FD}" }, { unified: "1f44f-1f3fe", native: "\u{1F44F}\u{1F3FE}" }, { unified: "1f44f-1f3ff", native: "\u{1F44F}\u{1F3FF}" }], version: 1 }, raised_hands: { id: "raised_hands", name: "Raising Hands", keywords: ["raised", "gesture", "hooray", "yea", "celebration"], skins: [{ unified: "1f64c", native: "\u{1F64C}" }, { unified: "1f64c-1f3fb", native: "\u{1F64C}\u{1F3FB}" }, { unified: "1f64c-1f3fc", native: "\u{1F64C}\u{1F3FC}" }, { unified: "1f64c-1f3fd", native: "\u{1F64C}\u{1F3FD}" }, { unified: "1f64c-1f3fe", native: "\u{1F64C}\u{1F3FE}" }, { unified: "1f64c-1f3ff", native: "\u{1F64C}\u{1F3FF}" }], version: 1 }, heart_hands: { id: "heart_hands", name: "Heart Hands", keywords: ["love", "appreciation", "support"], skins: [{ unified: "1faf6", native: "\u{1FAF6}" }, { unified: "1faf6-1f3fb", native: "\u{1FAF6}
51763\u{1F3FB}" }, { unified: "1faf6-1f3fc", native: "\u{1FAF6}\u{1F3FC}" }, { unified: "1faf6-1f3fd", native: "\u{1FAF6}\u{1F3FD}" }, { unified: "1faf6-1f3fe", native: "\u{1FAF6}\u{1F3FE}" }, { unified: "1faf6-1f3ff", native: "\u{1FAF6}\u{1F3FF}" }], version: 14 }, open_hands: { id: "open_hands", name: "Open Hands", keywords: ["fingers", "butterfly"], skins: [{ unified: "1f450", native: "\u{1F450}" }, { unified: "1f450-1f3fb", native: "\u{1F450}\u{1F3FB}" }, { unified: "1f450-1f3fc", native: "\u{1F450}\u{1F3FC}" }, { unified: "1f450-1f3fd", native: "\u{1F450}\u{1F3FD}" }, { unified: "1f450-1f3fe", native: "\u{1F450}\u{1F3FE}" }, { unified: "1f450-1f3ff", native: "\u{1F450}\u{1F3FF}" }], version: 1 }, palms_up_together: { id: "palms_up_together", name: "Palms Up Together", keywords: ["hands", "gesture", "cupped", "prayer"], skins: [{ unified: "1f932", native: "\u{1F932}" }, { unified: "1f932-1f3fb", native: "\u{1F932}\u{1F3FB}" }, { unified: "1f932-1f3fc", native: "\u{1F932}\u{1F3FC}" }, { unified: "1f932-1f3fd", native: "\u{1F932}\u{1F3FD}" }, { unified: "1f932-1f3fe", native: "\u{1F932}\u{1F3FE}" }, { unified: "1f932-1f3ff", native: "\u{1F932}\u{1F3FF}" }], version: 5 }, handshake: { id: "handshake", name: "Handshake", keywords: ["agreement", "shake"], skins: [{ unified: "1f91d", native: "\u{1F91D}" }, { unified: "1f91d-1f3fb", native: "\u{1F91D}\u{1F3FB}" }, { unified: "1f91d-1f3fc", native: "\u{1F91D}\u{1F3FC}" }, { unified: "1f91d-1f3fd", native: "\u{1F91D}\u{1F3FD}" }, { unified: "1f91d-1f3fe", native: "\u{1F91D}\u{1F3FE}" }, { unified: "1f91d-1f3ff", native: "\u{1F91D}\u{1F3FF}" }], version: 3 }, pray: { id: "pray", name: "Folded Hands", keywords: ["pray", "please", "hope", "wish", "namaste", "highfive", "high", "five", "thank", "you", "thanks", "appreciate"], skins: [{ unified: "1f64f", native: "\u{1F64F}" }, { unified: "1f64f-1f3fb", native: "\u{1F64F}\u{1F3FB}" }, { unified: "1f64f-1f3fc", native: "\u{1F64F}\u{1F3FC}" }, { unified: "1f64f-1f3fd", native: "\u{1F64F}\u{1F3FD}" }, { unified: "1f64f-1f3fe", native: "\u{1F64F}\u{1F3FE}" }, { unified: "1f64f-1f3ff", native: "\u{1F64F}\u{1F3FF}" }], version: 1 }, writing_hand: { id: "writing_hand", name: "Writing Hand", keywords: ["lower", "left", "ballpoint", "pen", "stationery", "write", "compose"], skins: [{ unified: "270d-fe0f", native: "\u270D\uFE0F" }, { unified: "270d-1f3fb", native: "\u270D\u{1F3FB}" }, { unified: "270d-1f3fc", native: "\u270D\u{1F3FC}" }, { unified: "270d-1f3fd", native: "\u270D\u{1F3FD}" }, { unified: "270d-1f3fe", native: "\u270D\u{1F3FE}" }, { unified: "270d-1f3ff", native: "\u270D\u{1F3FF}" }], version: 1 }, nail_care: { id: "nail_care", name: "Nail Polish", keywords: ["care", "beauty", "manicure", "finger", "fashion", "slay"], skins: [{ unified: "1f485", native: "\u{1F485}" }, { unified: "1f485-1f3fb", native: "\u{1F485}\u{1F3FB}" }, { unified: "1f485-1f3fc", native: "\u{1F485}\u{1F3FC}" }, { unified: "1f485-1f3fd", native: "\u{1F485}\u{1F3FD}" }, { unified: "1f485-1f3fe", native: "\u{1F485}\u{1F3FE}" }, { unified: "1f485-1f3ff", native: "\u{1F485}\u{1F3FF}" }], version: 1 }, selfie: { id: "selfie", name: "Selfie", keywords: ["camera", "phone"], skins: [{ unified: "1f933", native: "\u{1F933}" }, { unified: "1f933-1f3fb", native: "\u{1F933}\u{1F3FB}" }, { unified: "1f933-1f3fc", native: "\u{1F933}\u{1F3FC}" }, { unified: "1f933-1f3fd", native: "\u{1F933}\u{1F3FD}" }, { unified: "1f933-1f3fe", native: "\u{1F933}\u{1F3FE}" }, { unified: "1f933-1f3ff", native: "\u{1F933}\u{1F3FF}" }], version: 3 }, muscle: { id: "muscle", name: "Flexed Biceps", keywords: ["muscle", "arm", "flex", "hand", "summer", "strong"], skins: [{ unified: "1f4aa", native: "\u{1F4AA}" }, { unified: "1f4aa-1f3fb", native: "\u{1F4AA}\u{1F3FB}" }, { unified: "1f4aa-1f3fc", native: "\u{1F4AA}\u{1F3FC}" }, { unified: "1f4aa-1f3fd", native: "\u{1F4AA}\u{1F3FD}" }, { unified: "1f4aa-1f3fe", native: "\u{1F4AA}\u{1F3FE}" }, { unified: "1f4aa-1f3ff", native: "\u{1F4AA}\u{1F3FF}" }], version: 1 }, mechanical_arm: { id: "mechanical_arm", name: "Mechanical Arm", keywords: ["accessibility"], skins: [{ unified: "1f9be", native: "\u{1F9BE}" }], version: 12 }, mechanical_leg: { id: "mechanical_leg", name: "Mechanical Leg", keywords: ["accessibility"], skins: [{ unified: "1f9bf", native: "\u{1F9BF}" }], version: 12 }, leg: { id: "leg", name: "Leg", keywords: ["kick", "limb"], skins: [{ unified: "1f9b5", native: "\u{1F9B5}" }, { unified: "1f9b5-1f3fb", native: "\u{1F9B5}\u{1F3FB}" }, { unified: "1f9b5-1f3fc", native: "\u{1F9B5}\u{1F3FC}" }, { unified: "1f9b5-1f3fd", native: "\u{1F9B5}\u{1F3FD}" }, { unified: "1f9b5-1f3fe", native: "\u{1F9B5}\u{1F3FE}" }, { unified: "1f9b5-1f3ff", native: "\u{1F9B5}\u{1F3FF}" }], version: 11 }, foot: { id: "foot", name: "Foot", keywords: ["kick", "stomp"], skins: [{ unified: "1f9b6", native: "\u{1F9B6}" }, { unified: "1f9b6-1f3fb", native: "\u{1F9B6}\u{1F3FB}" }, { unified: "1f9b6-1f3fc", native: "\u{1F9B6}\u{1F3FC}" }, { unified: "1f9b6-1f3fd", native: "\u{1F9B6}\u{1F3FD}" }, { unified: "1f9b6-1f3fe", native: "\u{1F9B6}\u{1F3FE}" }, { unified: "1f9b6-1f3ff", native: "\u{1F9B6}\u{1F3FF}" }], version: 11 }, ear: { id: "ear", name: "Ear", keywords: ["face", "hear", "sound", "listen"], skins: [{ unified: "1f442", native: "\u{1F442}" }, { unified: "1f442-1f3fb", native: "\u{1F442}\u{1F3FB}" }, { unified: "1f442-1f3fc", native: "\u{1F442}\u{1F3FC}" }, { unified: "1f442-1f3fd", native: "\u{1F442}\u{1F3FD}" }, { unified: "1f442-1f3fe", native: "\u{1F442}\u{1F3FE}" }, { unified: "1f442-1f3ff", native: "\u{1F442}\u{1F3FF}" }], version: 1 }, ear_with_hearing_aid: { id: "ear_with_hearing_aid", name: "Ear with Hearing Aid", keywords: ["accessibility"], skins: [{ unified: "1f9bb", native: "\u{1F9BB}" }, { unified: "1f9bb-1f3fb", native: "\u{1F9BB}\u{1F3FB}" }, { unified: "1f9bb-1f3fc", native: "\u{1F9BB}\u{1F3FC}" }, { unified: "1f9bb-1f3fd", native: "\u{1F9BB}\u{1F3FD}" }, { unified: "1f9bb-1f3fe", native: "\u{1F9BB}\u{1F3FE}" }, { unified: "1f9bb-1f3ff", native: "\u{1F9BB}\u{1F3FF}" }], version: 12 }, nose: { id: "nose", name: "Nose", keywords: ["smell", "sniff"], skins: [{ unified: "1f443", native: "\u{1F443}" }, { unified: "1f443-1f3fb", native: "\u{1F443}\u{1F3FB}" }, { unified: "1f443-1f3fc", native: "\u{1F443}\u{1F3FC}" }, { unified: "1f443-1f3fd", native: "\u{1F443}\u{1F3FD}" }, { unified: "1f443-1f3fe", native: "\u{1F443}\u{1F3FE}" }, { unified: "1f443-1f3ff", native: "\u{1F443}\u{1F3FF}" }], version: 1 }, brain: { id: "brain", name: "Brain", keywords: ["smart", "intelligent"], skins: [{ unified: "1f9e0", native: "\u{1F9E0}" }], version: 5 }, anatomical_heart: { id: "anatomical_heart", name: "Anatomical Heart", keywords: ["health", "heartbeat"], skins: [{ unified: "1fac0", native: "\u{1FAC0}" }], version: 13 }, lungs: { id: "lungs", name: "Lungs", keywords: ["breathe"], skins: [{ unified: "1fac1", native: "\u{1FAC1}" }], version: 13 }, tooth: { id: "tooth", name: "Tooth", keywords: ["teeth", "dentist"], skins: [{ unified: "1f9b7", native: "\u{1F9B7}" }], version: 11 }, bone: { id: "bone", name: "Bone", keywords: ["skeleton"], skins: [{ unified: "1f9b4", native: "\u{1F9B4}" }], version: 11 }, eyes: { id: "eyes", name: "Eyes", keywords: ["look", "watch", "stalk", "peek", "see"], skins: [{ unified: "1f440", native: "\u{1F440}" }], version: 1 }, eye: { id: "eye", name: "Eye", keywords: ["face", "look", "see", "watch", "stare"], skins: [{ unified: "1f441-fe0f", native: "\u{1F441}\uFE0F" }], version: 1 }, tongue: { id: "tongue", name: "Tongue", keywords: ["mouth", "playful"], skins: [{ unified: "1f445", native: "\u{1F445}" }], version: 1 }, lips: { id: "lips", name: "Mouth", keywords: ["lips", "kiss"], skins: [{ unified: "1f444", native: "\u{1F444}" }], version: 1 }, biting_lip: { id: "biting_lip", name: "Biting Lip", keywords: ["flirt", "sexy", "pain", "worry"], skins: [{ unified: "1fae6", native: "\u{1FAE6}" }], version: 14 }, baby: { id: "baby", name: "Baby", keywords: ["child", "boy", "girl", "toddler"], skins: [{ unified: "1f476", native: "\u{1F476}" }, { unified: "1f476-1f3fb", native: "\u{1F476}\u{1F3FB}" }, { unified: "1f476-1f3fc", native: "\u{1F476}\u{1F3FC}" }, { unified: "1f476-1f3fd", native: "\u{1F476}\u{1F3FD}" }, { unified: "1f476-1f3fe", native: "\u{1F476}\u{1F3FE}" }, { unified: "1f476-1f3ff", native: "\u{1F476}\u{1F3FF}" }], version: 1 }, child: { id: "child", name: "Child", keywords: ["gender", "neutral", "young"], skins: [{ unified: "1f9d2", native: "\u{1F9D2}" }, { unified: "1f9d2-1f3fb", native: "\u{1F9D2}\u{1F3FB}" }, { unified: "1f9d2-1f3fc", native: "\u{1F9D2}\u{1F3FC}" }, { unified: "1f9d2-1f3fd", native: "\u{1F9D2}\u{1F3FD}" }, { unified: "1f9d2-1f3fe", native: "\u{1F9D2}\u{1F3FE}" }, { unified: "1f9d2-1f3ff", native: "\u{1F9D2}\u{1F3FF}" }], version: 5 }, boy: { id: "boy", name: "Boy", keywords: ["man", "male", "guy", "teenager"], skins: [{ unified: "1f466", native: "\u{1F466}" }, { unified: "1f466-1f3fb", native: "\u{1F466}\u{1F3FB}" }, { unified: "1f466-1f3fc", native: "\u{1F466}\u{1F3FC}" }, { unified: "1f466-1f3fd", native: "\u{1F466}\u{1F3FD}" }, { unified: "1f466-1f3fe", native: "\u{1F466}\u{1F3FE}" }, { unified: "1f466-1f3ff", native: "\u{1F466}\u{1F3FF}" }], version: 1 }, girl: { id: "girl", name: "Girl", keywords: ["female", "woman", "teenager"], skins: [{ unified: "1f467", native: "\u{1F467}" }, { unified: "1f467-1f3fb", native: "\u{1F467}\u{1F3FB}" }, { unified: "1f467-1f3fc", native: "\u{1F467}\u{1F3FC}" }, { unified: "1f467-1f3fd", native: "\u{1F467}\u{1F3FD}" }, { unified: "1f467-1f3fe", native: "\u{1F467}\u{1F3FE}" }, { unified: "1f467-1f3ff", native: "\u{1F467}\u{1F3FF}" }], version: 1 }, adult: { id: "adult", name: "Adult", keywords: ["person", "gender", "neutral"], skins: [{ unified: "1f9d1", native: "\u{1F9D1}" }, { unified: "1f9d1-1f3fb", native: "\u{1F9D1}\u{1F3FB}" }, { unified: "1f9d1-1f3fc", native: "\u{1F9D1}\u{1F3FC}" }, { unified: "1f9d1-1f3fd", native: "\u{1F9D1}\u{1F3FD}" }, { unified: "1f9d1-1f3fe", native: "\u{1F9D1}\u{1F3FE}" }, { unified: "1f9d1-1f3ff", native: "\u{1F9D1}\u{1F3FF}" }], version: 5 }, person_with_blond_hair: { id: "person_with_blond_hair", name: "Person Blond Hair", keywords: ["with", "hairstyle"], skins: [{ unified: "1f471", native: "\u{1F471}" }, { unified: "1f471-1f3fb", native: "\u{1F471}\u{1F3FB}" }, { unified: "1f471-1f3fc", native: "\u{1F471}\u{1F3FC}" }, { unified: "1f471-1f3fd", native: "\u{1F471}\u{1F3FD}" }, { unified: "1f471-1f3fe", native: "\u{1F471}\u{1F3FE}" }, { unified: "1f471-1f3ff", native: "\u{1F471}\u{1F3FF}" }], version: 1 }, man: { id: "man", name: "Man", keywords: ["mustache", "father", "dad", "guy", "classy", "sir", "moustache"], skins: [{ unified: "1f468", native: "\u{1F468}" }, { unified: "1f468-1f3fb", native: "\u{1F468}\u{1F3FB}" }, { unified: "1f468-1f3fc", native: "\u{1F468}\u{1F3FC}" }, { unified: "1f468-1f3fd", native: "\u{1F468}\u{1F3FD}" }, { unified: "1f468-1f3fe", native: "\u{1F468}\u{1F3FE}" }, { unified: "1f468-1f3ff", native: "\u{1F468}\u{1F3FF}" }], version: 1 }, bearded_person: { id: "bearded_person", name: "Person Beard", keywords: ["bearded", "man", "bewhiskered"], skins: [{ unified: "1f9d4", native: "\u{1F9D4}" }, { unified: "1f9d4-1f3fb", native: "\u{1F9D4}\u{1F3FB}" }, { unified: "1f9d4-1f3fc", native: "\u{1F9D4}\u{1F3FC}" }, { unified: "1f9d4-1f3fd", native: "\u{1F9D4}\u{1F3FD}" }, { unified: "1f9d4-1f3fe", native: "\u{1F9D4}\u{1F3FE}" }, { unified: "1f9d4-1f3ff", native: "\u{1F9D4}\u{1F3FF}" }], version: 5 }, man_with_beard: { id: "man_with_beard", name: "Man: Beard", keywords: ["man", "with", "facial", "hair"], skins: [{ unified: "1f9d4-200d-2642-fe0f", native: "\u{1F9D4}\u200D\u2642\uFE0F" }, { unified: "1f9d4-1f3fb-200d-2642-fe0f", native: "\u{1F9D4}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9d4-1f3fc-200d-2642-fe0f", native: "\u{1F9D4}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9d4-1f3fd-200d-2642-fe0f", native: "\u{1F9D4}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9d4-1f3fe-200d-2642-fe0f", native: "\u{1F9D4}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9d4-1f3ff-200d-2642-fe0f", native: "\u{1F9D4}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 13.1 }, woman_with_beard: { id: "woman_with_beard", name: "Woman: Beard", keywords: ["woman", "with", "facial", "hair"], skins: [{ unified: "1f9d4-200d-2640-fe0f", native: "\u{1F9D4}\u200D\u2640\uFE0F" }, { unified: "1f9d4-1f3fb-200d-2640-fe0f", native: "\u{1F9D4}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9d4-1f3fc-200d-2640-fe0f", native: "\u{1F9D4}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9d4-1f3fd-200d-2640-fe0f", native: "\u{1F9D4}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9d4-1f3fe-200d-2640-fe0f", native: "\u{1F9D4}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9d4-1f3ff-200d-2640-fe0f", native: "\u{1F9D4}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 13.1 }, red_haired_man: { id: "red_haired_man", name: "Man: Red Hair", keywords: ["haired", "man", "hairstyle"], skins: [{ unified: "1f468-200d-1f9b0", native: "\u{1F468}\u200D\u{1F9B0}" }, { unified: "1f468-1f3fb-200d-1f9b0", native: "\u{1F468}\u{1F3FB}\u200D\u{1F9B0}" }, { unified: "1f468-1f3fc-200d-1f9b0", native: "\u{1F468}\u{1F3FC}\u200D\u{1F9B0}" }, { unified: "1f468-1f3fd-200d-1f9b0", native: "\u{1F468}\u{1F3FD}\u200D\u{1F9B0}" }, { unified: "1f468-1f3fe-200d-1f9b0", native: "\u{1F468}\u{1F3FE}\u200D\u{1F9B0}" }, { unified: "1f468-1f3ff-200d-1f9b0", native: "\u{1F468}\u{1F3FF}\u200D\u{1F9B0}" }], version: 11 }, curly_haired_man: { id: "curly_haired_man", name: "Man: Curly Hair", keywords: ["haired", "man", "hairstyle"], skins: [{ unified: "1f468-200d-1f9b1", native: "\u{1F468}\u200D\u{1F9B1}" }, { unified: "1f468-1f3fb-200d-1f9b1", native: "\u{1F468}\u{1F3FB}\u200D\u{1F9B1}" }, { unified: "1f468-1f3fc-200d-1f9b1", native: "\u{1F468}\u{1F3FC}\u200D\u{1F9B1}" }, { unified: "1f468-1f3fd-200d-1f9b1", native: "\u{1F468}\u{1F3FD}\u200D\u{1F9B1}" }, { unified: "1f468-1f3fe-200d-1f9b1", native: "\u{1F468}\u{1F3FE}\u200D\u{1F9B1}" }, { unified: "1f468-1f3ff-200d-1f9b1", native: "\u{1F468}\u{1F3FF}\u200D\u{1F9B1}" }], version: 11 }, white_haired_man: { id: "white_haired_man", name: "Man: White Hair", keywords: ["haired", "man", "old", "elder"], skins: [{ unified: "1f468-200d-1f9b3", native: "\u{1F468}\u200D\u{1F9B3}" }, { unified: "1f468-1f3fb-200d-1f9b3", native: "\u{1F468}\u{1F3FB}\u200D\u{1F9B3}" }, { unified: "1f468-1f3fc-200d-1f9b3", native: "\u{1F468}\u{1F3FC}\u200D\u{1F9B3}" }, { unified: "1f468-1f3fd-200d-1f9b3", native: "\u{1F468}\u{1F3FD}\u200D\u{1F9B3}" }, { unified: "1f468-1f3fe-200d-1f9b3", native: "\u{1F468}\u{1F3FE}\u200D\u{1F9B3}" }, { unified: "1f468-1f3ff-200d-1f9b3", native: "\u{1F468}\u{1F3FF}\u200D\u{1F9B3}" }], version: 11 }, bald_man: { id: "bald_man", name: "Man: Bald", keywords: ["man", "hairless"], skins: [{ unified: "1f468-200d-1f9b2", native: "\u{1F468}\u200D\u{1F9B2}" }, { unified: "1f468-1f3fb-200d-1f9b2", native: "\u{1F468}\u{1F3FB}\u200D\u{1F9B2}" }, { unified: "1f468-1f3fc-200d-1f9b2", native: "\u{1F468}\u{1F3FC}\u200D\u{1F9B2}" }, { unified: "1f468-1f3fd-200d-1f9b2", native: "\u{1F468}\u{1F3FD}\u200D\u{1F9B2}" }, { unified: "1f468-1f3fe-200d-1f9b2", native: "\u{1F468}\u{1F3FE}\u200D\u{1F9B2}" }, { unified: "1f468-1f3ff-200d-1f9b2", native: "\u{1F468}\u{1F3FF}\u200D\u{1F9B2}" }], version: 11 }, woman: { id: "woman", name: "Woman", keywords: ["female", "girls", "lady"], skins: [{ unified: "1f469", native: "\u{1F469}" }, { unified: "1f469-1f3fb", native: "\u{1F469}\u{1F3FB}" }, { unified: "1f469-1f3fc", native: "\u{1F469}\u{1F3FC}" }, { unified: "1f469-1f3fd", native: "\u{1F469}\u{1F3FD}" }, { unified: "1f469-1f3fe", native: "\u{1F469}\u{1F3FE}" }, { unified: "1f469-1f3ff", native: "\u{1F469}\u{1F3FF}" }], version: 1 }, red_haired_woman: { id: "red_haired_woman", name: "Woman: Red Hair", keywords: ["haired", "woman", "hairstyle"], skins: [{ unified: "1f469-200d-1f9b0", native: "\u{1F469}\u200D\u{1F9B0}" }, { unified: "1f469-1f3fb-200d-1f9b0", native: "\u{1F469}\u{1F3FB}\u200D\u{1F9B0}" }, { unified: "1f469-1f3fc-200d-1f9b0", native: "\u{1F469}\u{1F3FC}\u200D\u{1F9B0}" }, { unified: "1f469-1f3fd-200d-1f9b0", native: "\u{1F469}\u{1F3FD}\u200D\u{1F9B0}" }, { unified: "1f469-1f3fe-200d-1f9b0", native: "\u{1F469}\u{1F3FE}\u200D\u{1F9B0}" }, { unified: "1f469-1f3ff-200d-1f9b0", native: "\u{1F469}\u{1F3FF}\u200D\u{1F9B0}" }], version: 11 }, red_haired_person: { id: "red_h
51763aired_person", name: "Person: Red Hair", keywords: ["haired", "person", "hairstyle"], skins: [{ unified: "1f9d1-200d-1f9b0", native: "\u{1F9D1}\u200D\u{1F9B0}" }, { unified: "1f9d1-1f3fb-200d-1f9b0", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F9B0}" }, { unified: "1f9d1-1f3fc-200d-1f9b0", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F9B0}" }, { unified: "1f9d1-1f3fd-200d-1f9b0", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F9B0}" }, { unified: "1f9d1-1f3fe-200d-1f9b0", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F9B0}" }, { unified: "1f9d1-1f3ff-200d-1f9b0", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F9B0}" }], version: 12.1 }, curly_haired_woman: { id: "curly_haired_woman", name: "Woman: Curly Hair", keywords: ["haired", "woman", "hairstyle"], skins: [{ unified: "1f469-200d-1f9b1", native: "\u{1F469}\u200D\u{1F9B1}" }, { unified: "1f469-1f3fb-200d-1f9b1", native: "\u{1F469}\u{1F3FB}\u200D\u{1F9B1}" }, { unified: "1f469-1f3fc-200d-1f9b1", native: "\u{1F469}\u{1F3FC}\u200D\u{1F9B1}" }, { unified: "1f469-1f3fd-200d-1f9b1", native: "\u{1F469}\u{1F3FD}\u200D\u{1F9B1}" }, { unified: "1f469-1f3fe-200d-1f9b1", native: "\u{1F469}\u{1F3FE}\u200D\u{1F9B1}" }, { unified: "1f469-1f3ff-200d-1f9b1", native: "\u{1F469}\u{1F3FF}\u200D\u{1F9B1}" }], version: 11 }, curly_haired_person: { id: "curly_haired_person", name: "Person: Curly Hair", keywords: ["haired", "person", "hairstyle"], skins: [{ unified: "1f9d1-200d-1f9b1", native: "\u{1F9D1}\u200D\u{1F9B1}" }, { unified: "1f9d1-1f3fb-200d-1f9b1", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F9B1}" }, { unified: "1f9d1-1f3fc-200d-1f9b1", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F9B1}" }, { unified: "1f9d1-1f3fd-200d-1f9b1", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F9B1}" }, { unified: "1f9d1-1f3fe-200d-1f9b1", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F9B1}" }, { unified: "1f9d1-1f3ff-200d-1f9b1", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F9B1}" }], version: 12.1 }, white_haired_woman: { id: "white_haired_woman", name: "Woman: White Hair", keywords: ["haired", "woman", "old", "elder"], skins: [{ unified: "1f469-200d-1f9b3", native: "\u{1F469}\u200D\u{1F9B3}" }, { unified: "1f469-1f3fb-200d-1f9b3", native: "\u{1F469}\u{1F3FB}\u200D\u{1F9B3}" }, { unified: "1f469-1f3fc-200d-1f9b3", native: "\u{1F469}\u{1F3FC}\u200D\u{1F9B3}" }, { unified: "1f469-1f3fd-200d-1f9b3", native: "\u{1F469}\u{1F3FD}\u200D\u{1F9B3}" }, { unified: "1f469-1f3fe-200d-1f9b3", native: "\u{1F469}\u{1F3FE}\u200D\u{1F9B3}" }, { unified: "1f469-1f3ff-200d-1f9b3", native: "\u{1F469}\u{1F3FF}\u200D\u{1F9B3}" }], version: 11 }, white_haired_person: { id: "white_haired_person", name: "Person: White Hair", keywords: ["haired", "person", "elder", "old"], skins: [{ unified: "1f9d1-200d-1f9b3", native: "\u{1F9D1}\u200D\u{1F9B3}" }, { unified: "1f9d1-1f3fb-200d-1f9b3", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F9B3}" }, { unified: "1f9d1-1f3fc-200d-1f9b3", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F9B3}" }, { unified: "1f9d1-1f3fd-200d-1f9b3", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F9B3}" }, { unified: "1f9d1-1f3fe-200d-1f9b3", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F9B3}" }, { unified: "1f9d1-1f3ff-200d-1f9b3", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F9B3}" }], version: 12.1 }, bald_woman: { id: "bald_woman", name: "Woman: Bald", keywords: ["woman", "hairless"], skins: [{ unified: "1f469-200d-1f9b2", native: "\u{1F469}\u200D\u{1F9B2}" }, { unified: "1f469-1f3fb-200d-1f9b2", native: "\u{1F469}\u{1F3FB}\u200D\u{1F9B2}" }, { unified: "1f469-1f3fc-200d-1f9b2", native: "\u{1F469}\u{1F3FC}\u200D\u{1F9B2}" }, { unified: "1f469-1f3fd-200d-1f9b2", native: "\u{1F469}\u{1F3FD}\u200D\u{1F9B2}" }, { unified: "1f469-1f3fe-200d-1f9b2", native: "\u{1F469}\u{1F3FE}\u200D\u{1F9B2}" }, { unified: "1f469-1f3ff-200d-1f9b2", native: "\u{1F469}\u{1F3FF}\u200D\u{1F9B2}" }], version: 11 }, bald_person: { id: "bald_person", name: "Person: Bald", keywords: ["person", "hairless"], skins: [{ unified: "1f9d1-200d-1f9b2", native: "\u{1F9D1}\u200D\u{1F9B2}" }, { unified: "1f9d1-1f3fb-200d-1f9b2", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F9B2}" }, { unified: "1f9d1-1f3fc-200d-1f9b2", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F9B2}" }, { unified: "1f9d1-1f3fd-200d-1f9b2", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F9B2}" }, { unified: "1f9d1-1f3fe-200d-1f9b2", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F9B2}" }, { unified: "1f9d1-1f3ff-200d-1f9b2", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F9B2}" }], version: 12.1 }, "blond-haired-woman": { id: "blond-haired-woman", name: "Woman: Blond Hair", keywords: ["haired-woman", "woman", "female", "girl", "blonde", "person"], skins: [{ unified: "1f471-200d-2640-fe0f", native: "\u{1F471}\u200D\u2640\uFE0F" }, { unified: "1f471-1f3fb-200d-2640-fe0f", native: "\u{1F471}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f471-1f3fc-200d-2640-fe0f", native: "\u{1F471}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f471-1f3fd-200d-2640-fe0f", native: "\u{1F471}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f471-1f3fe-200d-2640-fe0f", native: "\u{1F471}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f471-1f3ff-200d-2640-fe0f", native: "\u{1F471}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, "blond-haired-man": { id: "blond-haired-man", name: "Man: Blond Hair", keywords: ["haired-man", "man", "male", "boy", "blonde", "guy", "person"], skins: [{ unified: "1f471-200d-2642-fe0f", native: "\u{1F471}\u200D\u2642\uFE0F" }, { unified: "1f471-1f3fb-200d-2642-fe0f", native: "\u{1F471}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f471-1f3fc-200d-2642-fe0f", native: "\u{1F471}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f471-1f3fd-200d-2642-fe0f", native: "\u{1F471}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f471-1f3fe-200d-2642-fe0f", native: "\u{1F471}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f471-1f3ff-200d-2642-fe0f", native: "\u{1F471}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, older_adult: { id: "older_adult", name: "Older Adult", keywords: ["person", "human", "elder", "senior", "gender", "neutral"], skins: [{ unified: "1f9d3", native: "\u{1F9D3}" }, { unified: "1f9d3-1f3fb", native: "\u{1F9D3}\u{1F3FB}" }, { unified: "1f9d3-1f3fc", native: "\u{1F9D3}\u{1F3FC}" }, { unified: "1f9d3-1f3fd", native: "\u{1F9D3}\u{1F3FD}" }, { unified: "1f9d3-1f3fe", native: "\u{1F9D3}\u{1F3FE}" }, { unified: "1f9d3-1f3ff", native: "\u{1F9D3}\u{1F3FF}" }], version: 5 }, older_man: { id: "older_man", name: "Old Man", keywords: ["older", "human", "male", "men", "elder", "senior"], skins: [{ unified: "1f474", native: "\u{1F474}" }, { unified: "1f474-1f3fb", native: "\u{1F474}\u{1F3FB}" }, { unified: "1f474-1f3fc", native: "\u{1F474}\u{1F3FC}" }, { unified: "1f474-1f3fd", native: "\u{1F474}\u{1F3FD}" }, { unified: "1f474-1f3fe", native: "\u{1F474}\u{1F3FE}" }, { unified: "1f474-1f3ff", native: "\u{1F474}\u{1F3FF}" }], version: 1 }, older_woman: { id: "older_woman", name: "Old Woman", keywords: ["older", "human", "female", "women", "lady", "elder", "senior"], skins: [{ unified: "1f475", native: "\u{1F475}" }, { unified: "1f475-1f3fb", native: "\u{1F475}\u{1F3FB}" }, { unified: "1f475-1f3fc", native: "\u{1F475}\u{1F3FC}" }, { unified: "1f475-1f3fd", native: "\u{1F475}\u{1F3FD}" }, { unified: "1f475-1f3fe", native: "\u{1F475}\u{1F3FE}" }, { unified: "1f475-1f3ff", native: "\u{1F475}\u{1F3FF}" }], version: 1 }, person_frowning: { id: "person_frowning", name: "Person Frowning", keywords: ["worried"], skins: [{ unified: "1f64d", native: "\u{1F64D}" }, { unified: "1f64d-1f3fb", native: "\u{1F64D}\u{1F3FB}" }, { unified: "1f64d-1f3fc", native: "\u{1F64D}\u{1F3FC}" }, { unified: "1f64d-1f3fd", native: "\u{1F64D}\u{1F3FD}" }, { unified: "1f64d-1f3fe", native: "\u{1F64D}\u{1F3FE}" }, { unified: "1f64d-1f3ff", native: "\u{1F64D}\u{1F3FF}" }], version: 1 }, "man-frowning": { id: "man-frowning", name: "Man Frowning", keywords: ["male", "boy", "sad", "depressed", "discouraged", "unhappy"], skins: [{ unified: "1f64d-200d-2642-fe0f", native: "\u{1F64D}\u200D\u2642\uFE0F" }, { unified: "1f64d-1f3fb-200d-2642-fe0f", native: "\u{1F64D}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f64d-1f3fc-200d-2642-fe0f", native: "\u{1F64D}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f64d-1f3fd-200d-2642-fe0f", native: "\u{1F64D}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f64d-1f3fe-200d-2642-fe0f", native: "\u{1F64D}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f64d-1f3ff-200d-2642-fe0f", native: "\u{1F64D}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-frowning": { id: "woman-frowning", name: "Woman Frowning", keywords: ["female", "girl", "sad", "depressed", "discouraged", "unhappy"], skins: [{ unified: "1f64d-200d-2640-fe0f", native: "\u{1F64D}\u200D\u2640\uFE0F" }, { unified: "1f64d-1f3fb-200d-2640-fe0f", native: "\u{1F64D}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f64d-1f3fc-200d-2640-fe0f", native: "\u{1F64D}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f64d-1f3fd-200d-2640-fe0f", native: "\u{1F64D}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f64d-1f3fe-200d-2640-fe0f", native: "\u{1F64D}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f64d-1f3ff-200d-2640-fe0f", native: "\u{1F64D}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, person_with_pouting_face: { id: "person_with_pouting_face", name: "Person Pouting", keywords: ["with", "face", "upset"], skins: [{ unified: "1f64e", native: "\u{1F64E}" }, { unified: "1f64e-1f3fb", native: "\u{1F64E}\u{1F3FB}" }, { unified: "1f64e-1f3fc", native: "\u{1F64E}\u{1F3FC}" }, { unified: "1f64e-1f3fd", native: "\u{1F64E}\u{1F3FD}" }, { unified: "1f64e-1f3fe", native: "\u{1F64E}\u{1F3FE}" }, { unified: "1f64e-1f3ff", native: "\u{1F64E}\u{1F3FF}" }], version: 1 }, "man-pouting": { id: "man-pouting", name: "Man Pouting", keywords: ["male", "boy"], skins: [{ unified: "1f64e-200d-2642-fe0f", native: "\u{1F64E}\u200D\u2642\uFE0F" }, { unified: "1f64e-1f3fb-200d-2642-fe0f", native: "\u{1F64E}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f64e-1f3fc-200d-2642-fe0f", native: "\u{1F64E}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f64e-1f3fd-200d-2642-fe0f", native: "\u{1F64E}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f64e-1f3fe-200d-2642-fe0f", native: "\u{1F64E}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f64e-1f3ff-200d-2642-fe0f", native: "\u{1F64E}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-pouting": { id: "woman-pouting", name: "Woman Pouting", keywords: ["female", "girl"], skins: [{ unified: "1f64e-200d-2640-fe0f", native: "\u{1F64E}\u200D\u2640\uFE0F" }, { unified: "1f64e-1f3fb-200d-2640-fe0f", native: "\u{1F64E}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f64e-1f3fc-200d-2640-fe0f", native: "\u{1F64E}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f64e-1f3fd-200d-2640-fe0f", native: "\u{1F64E}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f64e-1f3fe-200d-2640-fe0f", native: "\u{1F64E}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f64e-1f3ff-200d-2640-fe0f", native: "\u{1F64E}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, no_good: { id: "no_good", name: "Person Gesturing No", keywords: ["good", "decline"], skins: [{ unified: "1f645", native: "\u{1F645}" }, { unified: "1f645-1f3fb", native: "\u{1F645}\u{1F3FB}" }, { unified: "1f645-1f3fc", native: "\u{1F645}\u{1F3FC}" }, { unified: "1f645-1f3fd", native: "\u{1F645}\u{1F3FD}" }, { unified: "1f645-1f3fe", native: "\u{1F645}\u{1F3FE}" }, { unified: "1f645-1f3ff", native: "\u{1F645}\u{1F3FF}" }], version: 1 }, "man-gesturing-no": { id: "man-gesturing-no", name: "Man Gesturing No", keywords: ["gesturing-no", "male", "boy", "nope"], skins: [{ unified: "1f645-200d-2642-fe0f", native: "\u{1F645}\u200D\u2642\uFE0F" }, { unified: "1f645-1f3fb-200d-2642-fe0f", native: "\u{1F645}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f645-1f3fc-200d-2642-fe0f", native: "\u{1F645}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f645-1f3fd-200d-2642-fe0f", native: "\u{1F645}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f645-1f3fe-200d-2642-fe0f", native: "\u{1F645}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f645-1f3ff-200d-2642-fe0f", native: "\u{1F645}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-gesturing-no": { id: "woman-gesturing-no", name: "Woman Gesturing No", keywords: ["gesturing-no", "female", "girl", "nope"], skins: [{ unified: "1f645-200d-2640-fe0f", native: "\u{1F645}\u200D\u2640\uFE0F" }, { unified: "1f645-1f3fb-200d-2640-fe0f", native: "\u{1F645}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f645-1f3fc-200d-2640-fe0f", native: "\u{1F645}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f645-1f3fd-200d-2640-fe0f", native: "\u{1F645}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f645-1f3fe-200d-2640-fe0f", native: "\u{1F645}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f645-1f3ff-200d-2640-fe0f", native: "\u{1F645}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, ok_woman: { id: "ok_woman", name: "Person Gesturing Ok", keywords: ["woman", "agree"], skins: [{ unified: "1f646", native: "\u{1F646}" }, { unified: "1f646-1f3fb", native: "\u{1F646}\u{1F3FB}" }, { unified: "1f646-1f3fc", native: "\u{1F646}\u{1F3FC}" }, { unified: "1f646-1f3fd", native: "\u{1F646}\u{1F3FD}" }, { unified: "1f646-1f3fe", native: "\u{1F646}\u{1F3FE}" }, { unified: "1f646-1f3ff", native: "\u{1F646}\u{1F3FF}" }], version: 1 }, "man-gesturing-ok": { id: "man-gesturing-ok", name: "Man Gesturing Ok", keywords: ["gesturing-ok", "men", "boy", "male", "blue", "human"], skins: [{ unified: "1f646-200d-2642-fe0f", native: "\u{1F646}\u200D\u2642\uFE0F" }, { unified: "1f646-1f3fb-200d-2642-fe0f", native: "\u{1F646}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f646-1f3fc-200d-2642-fe0f", native: "\u{1F646}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f646-1f3fd-200d-2642-fe0f", native: "\u{1F646}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f646-1f3fe-200d-2642-fe0f", native: "\u{1F646}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f646-1f3ff-200d-2642-fe0f", native: "\u{1F646}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-gesturing-ok": { id: "woman-gesturing-ok", name: "Woman Gesturing Ok", keywords: ["gesturing-ok", "women", "girl", "female", "pink", "human"], skins: [{ unified: "1f646-200d-2640-fe0f", native: "\u{1F646}\u200D\u2640\uFE0F" }, { unified: "1f646-1f3fb-200d-2640-fe0f", native: "\u{1F646}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f646-1f3fc-200d-2640-fe0f", native: "\u{1F646}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f646-1f3fd-200d-2640-fe0f", native: "\u{1F646}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f646-1f3fe-200d-2640-fe0f", native: "\u{1F646}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f646-1f3ff-200d-2640-fe0f", native: "\u{1F646}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, information_desk_person: { id: "information_desk_person", name: "Person Tipping Hand", keywords: ["information", "desk"], skins: [{ unified: "1f481", native: "\u{1F481}" }, { unified: "1f481-1f3fb", native: "\u{1F481}\u{1F3FB}" }, { unified: "1f481-1f3fc", native: "\u{1F481}\u{1F3FC}" }, { unified: "1f481-1f3fd", native: "\u{1F481}\u{1F3FD}" }, { unified: "1f481-1f3fe", native: "\u{1F481}\u{1F3FE}" }, { unified: "1f481-1f3ff", native: "\u{1F481}\u{1F3FF}" }], version: 1 }, "man-tipping-hand": { id: "man-tipping-hand", name: "Man Tipping Hand", keywords: ["tipping-hand", "male", "boy", "human", "information"], skins: [{ unified: "1f481-200d-2642-fe0f", native: "\u{1F481}\u200D\u2642\uFE0F" }, { unified: "1f481-1f3fb-200d-2642-fe0f", native: "\u{1F481}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f481-1f3fc-200d-2642-fe0f", native: "\u{1F481}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f481-1f3fd-200d-2642-fe0f", native: "\u{1F481}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f481-1f3fe-200d-2642-fe0f", native: "\u{1F481}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f481-1f3ff-200d-2642-fe0f", native: "\u{1F481}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-tipping-hand": { id: "woman-tipping-hand", name: "Woman Tipping Hand", keywords: ["tipping-hand", "female", "girl", "human", "information"], skins: [{ unified: "1f481-200d-2640-fe0f", native: "\u{1F481}\u200D\u2640\uFE0F" }, { unified: "1f481-1f3fb-200d-2640-fe0f", native: "\u{1F481}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f481-1f3fc-200d-2640-fe0f", native: "\u{1F481}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f481-1f3fd-200d-2640-fe0f", native: "\u{1F481}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f481-1f3fe-200d-2640-fe0f", native: "\u{1F481}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f481-1f3ff-200d-2640-fe0f", native: "\u{1F481}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, raising_hand: { id: "raising_hand", name: "Person Raising Hand", keywords: ["questio
51763n"], skins: [{ unified: "1f64b", native: "\u{1F64B}" }, { unified: "1f64b-1f3fb", native: "\u{1F64B}\u{1F3FB}" }, { unified: "1f64b-1f3fc", native: "\u{1F64B}\u{1F3FC}" }, { unified: "1f64b-1f3fd", native: "\u{1F64B}\u{1F3FD}" }, { unified: "1f64b-1f3fe", native: "\u{1F64B}\u{1F3FE}" }, { unified: "1f64b-1f3ff", native: "\u{1F64B}\u{1F3FF}" }], version: 1 }, "man-raising-hand": { id: "man-raising-hand", name: "Man Raising Hand", keywords: ["raising-hand", "male", "boy"], skins: [{ unified: "1f64b-200d-2642-fe0f", native: "\u{1F64B}\u200D\u2642\uFE0F" }, { unified: "1f64b-1f3fb-200d-2642-fe0f", native: "\u{1F64B}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f64b-1f3fc-200d-2642-fe0f", native: "\u{1F64B}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f64b-1f3fd-200d-2642-fe0f", native: "\u{1F64B}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f64b-1f3fe-200d-2642-fe0f", native: "\u{1F64B}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f64b-1f3ff-200d-2642-fe0f", native: "\u{1F64B}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-raising-hand": { id: "woman-raising-hand", name: "Woman Raising Hand", keywords: ["raising-hand", "female", "girl"], skins: [{ unified: "1f64b-200d-2640-fe0f", native: "\u{1F64B}\u200D\u2640\uFE0F" }, { unified: "1f64b-1f3fb-200d-2640-fe0f", native: "\u{1F64B}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f64b-1f3fc-200d-2640-fe0f", native: "\u{1F64B}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f64b-1f3fd-200d-2640-fe0f", native: "\u{1F64B}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f64b-1f3fe-200d-2640-fe0f", native: "\u{1F64B}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f64b-1f3ff-200d-2640-fe0f", native: "\u{1F64B}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, deaf_person: { id: "deaf_person", name: "Deaf Person", keywords: ["accessibility"], skins: [{ unified: "1f9cf", native: "\u{1F9CF}" }, { unified: "1f9cf-1f3fb", native: "\u{1F9CF}\u{1F3FB}" }, { unified: "1f9cf-1f3fc", native: "\u{1F9CF}\u{1F3FC}" }, { unified: "1f9cf-1f3fd", native: "\u{1F9CF}\u{1F3FD}" }, { unified: "1f9cf-1f3fe", native: "\u{1F9CF}\u{1F3FE}" }, { unified: "1f9cf-1f3ff", native: "\u{1F9CF}\u{1F3FF}" }], version: 12 }, deaf_man: { id: "deaf_man", name: "Deaf Man", keywords: ["accessibility"], skins: [{ unified: "1f9cf-200d-2642-fe0f", native: "\u{1F9CF}\u200D\u2642\uFE0F" }, { unified: "1f9cf-1f3fb-200d-2642-fe0f", native: "\u{1F9CF}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9cf-1f3fc-200d-2642-fe0f", native: "\u{1F9CF}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9cf-1f3fd-200d-2642-fe0f", native: "\u{1F9CF}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9cf-1f3fe-200d-2642-fe0f", native: "\u{1F9CF}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9cf-1f3ff-200d-2642-fe0f", native: "\u{1F9CF}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 12 }, deaf_woman: { id: "deaf_woman", name: "Deaf Woman", keywords: ["accessibility"], skins: [{ unified: "1f9cf-200d-2640-fe0f", native: "\u{1F9CF}\u200D\u2640\uFE0F" }, { unified: "1f9cf-1f3fb-200d-2640-fe0f", native: "\u{1F9CF}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9cf-1f3fc-200d-2640-fe0f", native: "\u{1F9CF}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9cf-1f3fd-200d-2640-fe0f", native: "\u{1F9CF}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9cf-1f3fe-200d-2640-fe0f", native: "\u{1F9CF}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9cf-1f3ff-200d-2640-fe0f", native: "\u{1F9CF}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 12 }, bow: { id: "bow", name: "Person Bowing", keywords: ["bow", "respectiful"], skins: [{ unified: "1f647", native: "\u{1F647}" }, { unified: "1f647-1f3fb", native: "\u{1F647}\u{1F3FB}" }, { unified: "1f647-1f3fc", native: "\u{1F647}\u{1F3FC}" }, { unified: "1f647-1f3fd", native: "\u{1F647}\u{1F3FD}" }, { unified: "1f647-1f3fe", native: "\u{1F647}\u{1F3FE}" }, { unified: "1f647-1f3ff", native: "\u{1F647}\u{1F3FF}" }], version: 1 }, "man-bowing": { id: "man-bowing", name: "Man Bowing", keywords: ["male", "boy"], skins: [{ unified: "1f647-200d-2642-fe0f", native: "\u{1F647}\u200D\u2642\uFE0F" }, { unified: "1f647-1f3fb-200d-2642-fe0f", native: "\u{1F647}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f647-1f3fc-200d-2642-fe0f", native: "\u{1F647}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f647-1f3fd-200d-2642-fe0f", native: "\u{1F647}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f647-1f3fe-200d-2642-fe0f", native: "\u{1F647}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f647-1f3ff-200d-2642-fe0f", native: "\u{1F647}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-bowing": { id: "woman-bowing", name: "Woman Bowing", keywords: ["female", "girl"], skins: [{ unified: "1f647-200d-2640-fe0f", native: "\u{1F647}\u200D\u2640\uFE0F" }, { unified: "1f647-1f3fb-200d-2640-fe0f", native: "\u{1F647}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f647-1f3fc-200d-2640-fe0f", native: "\u{1F647}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f647-1f3fd-200d-2640-fe0f", native: "\u{1F647}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f647-1f3fe-200d-2640-fe0f", native: "\u{1F647}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f647-1f3ff-200d-2640-fe0f", native: "\u{1F647}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, face_palm: { id: "face_palm", name: "Face Palm", keywords: ["person", "facepalming", "disappointed"], skins: [{ unified: "1f926", native: "\u{1F926}" }, { unified: "1f926-1f3fb", native: "\u{1F926}\u{1F3FB}" }, { unified: "1f926-1f3fc", native: "\u{1F926}\u{1F3FC}" }, { unified: "1f926-1f3fd", native: "\u{1F926}\u{1F3FD}" }, { unified: "1f926-1f3fe", native: "\u{1F926}\u{1F3FE}" }, { unified: "1f926-1f3ff", native: "\u{1F926}\u{1F3FF}" }], version: 3 }, "man-facepalming": { id: "man-facepalming", name: "Man Facepalming", keywords: ["male", "boy", "disbelief"], skins: [{ unified: "1f926-200d-2642-fe0f", native: "\u{1F926}\u200D\u2642\uFE0F" }, { unified: "1f926-1f3fb-200d-2642-fe0f", native: "\u{1F926}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f926-1f3fc-200d-2642-fe0f", native: "\u{1F926}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f926-1f3fd-200d-2642-fe0f", native: "\u{1F926}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f926-1f3fe-200d-2642-fe0f", native: "\u{1F926}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f926-1f3ff-200d-2642-fe0f", native: "\u{1F926}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-facepalming": { id: "woman-facepalming", name: "Woman Facepalming", keywords: ["female", "girl", "disbelief"], skins: [{ unified: "1f926-200d-2640-fe0f", native: "\u{1F926}\u200D\u2640\uFE0F" }, { unified: "1f926-1f3fb-200d-2640-fe0f", native: "\u{1F926}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f926-1f3fc-200d-2640-fe0f", native: "\u{1F926}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f926-1f3fd-200d-2640-fe0f", native: "\u{1F926}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f926-1f3fe-200d-2640-fe0f", native: "\u{1F926}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f926-1f3ff-200d-2640-fe0f", native: "\u{1F926}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, shrug: { id: "shrug", name: "Shrug", keywords: ["person", "shrugging", "regardless"], skins: [{ unified: "1f937", native: "\u{1F937}" }, { unified: "1f937-1f3fb", native: "\u{1F937}\u{1F3FB}" }, { unified: "1f937-1f3fc", native: "\u{1F937}\u{1F3FC}" }, { unified: "1f937-1f3fd", native: "\u{1F937}\u{1F3FD}" }, { unified: "1f937-1f3fe", native: "\u{1F937}\u{1F3FE}" }, { unified: "1f937-1f3ff", native: "\u{1F937}\u{1F3FF}" }], version: 3 }, "man-shrugging": { id: "man-shrugging", name: "Man Shrugging", keywords: ["male", "boy", "confused", "indifferent", "doubt"], skins: [{ unified: "1f937-200d-2642-fe0f", native: "\u{1F937}\u200D\u2642\uFE0F" }, { unified: "1f937-1f3fb-200d-2642-fe0f", native: "\u{1F937}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f937-1f3fc-200d-2642-fe0f", native: "\u{1F937}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f937-1f3fd-200d-2642-fe0f", native: "\u{1F937}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f937-1f3fe-200d-2642-fe0f", native: "\u{1F937}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f937-1f3ff-200d-2642-fe0f", native: "\u{1F937}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-shrugging": { id: "woman-shrugging", name: "Woman Shrugging", keywords: ["female", "girl", "confused", "indifferent", "doubt"], skins: [{ unified: "1f937-200d-2640-fe0f", native: "\u{1F937}\u200D\u2640\uFE0F" }, { unified: "1f937-1f3fb-200d-2640-fe0f", native: "\u{1F937}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f937-1f3fc-200d-2640-fe0f", native: "\u{1F937}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f937-1f3fd-200d-2640-fe0f", native: "\u{1F937}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f937-1f3fe-200d-2640-fe0f", native: "\u{1F937}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f937-1f3ff-200d-2640-fe0f", native: "\u{1F937}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, health_worker: { id: "health_worker", name: "Health Worker", keywords: ["hospital"], skins: [{ unified: "1f9d1-200d-2695-fe0f", native: "\u{1F9D1}\u200D\u2695\uFE0F" }, { unified: "1f9d1-1f3fb-200d-2695-fe0f", native: "\u{1F9D1}\u{1F3FB}\u200D\u2695\uFE0F" }, { unified: "1f9d1-1f3fc-200d-2695-fe0f", native: "\u{1F9D1}\u{1F3FC}\u200D\u2695\uFE0F" }, { unified: "1f9d1-1f3fd-200d-2695-fe0f", native: "\u{1F9D1}\u{1F3FD}\u200D\u2695\uFE0F" }, { unified: "1f9d1-1f3fe-200d-2695-fe0f", native: "\u{1F9D1}\u{1F3FE}\u200D\u2695\uFE0F" }, { unified: "1f9d1-1f3ff-200d-2695-fe0f", native: "\u{1F9D1}\u{1F3FF}\u200D\u2695\uFE0F" }], version: 12.1 }, "male-doctor": { id: "male-doctor", name: "Man Health Worker", keywords: ["male", "doctor", "nurse", "therapist", "healthcare", "human"], skins: [{ unified: "1f468-200d-2695-fe0f", native: "\u{1F468}\u200D\u2695\uFE0F" }, { unified: "1f468-1f3fb-200d-2695-fe0f", native: "\u{1F468}\u{1F3FB}\u200D\u2695\uFE0F" }, { unified: "1f468-1f3fc-200d-2695-fe0f", native: "\u{1F468}\u{1F3FC}\u200D\u2695\uFE0F" }, { unified: "1f468-1f3fd-200d-2695-fe0f", native: "\u{1F468}\u{1F3FD}\u200D\u2695\uFE0F" }, { unified: "1f468-1f3fe-200d-2695-fe0f", native: "\u{1F468}\u{1F3FE}\u200D\u2695\uFE0F" }, { unified: "1f468-1f3ff-200d-2695-fe0f", native: "\u{1F468}\u{1F3FF}\u200D\u2695\uFE0F" }], version: 4 }, "female-doctor": { id: "female-doctor", name: "Woman Health Worker", keywords: ["female", "doctor", "nurse", "therapist", "healthcare", "human"], skins: [{ unified: "1f469-200d-2695-fe0f", native: "\u{1F469}\u200D\u2695\uFE0F" }, { unified: "1f469-1f3fb-200d-2695-fe0f", native: "\u{1F469}\u{1F3FB}\u200D\u2695\uFE0F" }, { unified: "1f469-1f3fc-200d-2695-fe0f", native: "\u{1F469}\u{1F3FC}\u200D\u2695\uFE0F" }, { unified: "1f469-1f3fd-200d-2695-fe0f", native: "\u{1F469}\u{1F3FD}\u200D\u2695\uFE0F" }, { unified: "1f469-1f3fe-200d-2695-fe0f", native: "\u{1F469}\u{1F3FE}\u200D\u2695\uFE0F" }, { unified: "1f469-1f3ff-200d-2695-fe0f", native: "\u{1F469}\u{1F3FF}\u200D\u2695\uFE0F" }], version: 4 }, student: { id: "student", name: "Student", keywords: ["learn"], skins: [{ unified: "1f9d1-200d-1f393", native: "\u{1F9D1}\u200D\u{1F393}" }, { unified: "1f9d1-1f3fb-200d-1f393", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F393}" }, { unified: "1f9d1-1f3fc-200d-1f393", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F393}" }, { unified: "1f9d1-1f3fd-200d-1f393", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F393}" }, { unified: "1f9d1-1f3fe-200d-1f393", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F393}" }, { unified: "1f9d1-1f3ff-200d-1f393", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F393}" }
51763], version: 12.1 }, "male-student": { id: "male-student", name: "Man Student", keywords: ["male", "graduate", "human"], skins: [{ unified: "1f468-200d-1f393", native: "\u{1F468}\u200D\u{1F393}" }, { unified: "1f468-1f3fb-200d-1f393", native: "\u{1F468}\u{1F3FB}\u200D\u{1F393}" }, { unified: "1f468-1f3fc-200d-1f393", native: "\u{1F468}\u{1F3FC}\u200D\u{1F393}" }, { unified: "1f468-1f3fd-200d-1f393", native: "\u{1F468}\u{1F3FD}\u200D\u{1F393}" }, { unified: "1f468-1f3fe-200d-1f393", native: "\u{1F468}\u{1F3FE}\u200D\u{1F393}" }, { unified: "1f468-1f3ff-200d-1f393", native: "\u{1F468}\u{1F3FF}\u200D\u{1F393}" }], version: 4 }, "female-student": { id: "female-student", name: "Woman Student", keywords: ["female", "graduate", "human"], skins: [{ unified: "1f469-200d-1f393", native: "\u{1F469}\u200D\u{1F393}" }, { unified: "1f469-1f3fb-200d-1f393", native: "\u{1F469}\u{1F3FB}\u200D\u{1F393}" }, { unified: "1f469-1f3fc-200d-1f393", native: "\u{1F469}\u{1F3FC}\u200D\u{1F393}" }, { unified: "1f469-1f3fd-200d-1f393", native: "\u{1F469}\u{1F3FD}\u200D\u{1F393}" }, { unified: "1f469-1f3fe-200d-1f393", native: "\u{1F469}\u{1F3FE}\u200D\u{1F393}" }, { unified: "1f469-1f3ff-200d-1f393", native: "\u{1F469}\u{1F3FF}\u200D\u{1F393}" }], version: 4 }, teacher: { id: "teacher", name: "Teacher", keywords: ["professor"], skins: [{ unified: "1f9d1-200d-1f3eb", native: "\u{1F9D1}\u200D\u{1F3EB}" }, { unified: "1f9d1-1f3fb-200d-1f3eb", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F3EB}" }, { unified: "1f9d1-1f3fc-200d-1f3eb", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F3EB}" }, { unified: "1f9d1-1f3fd-200d-1f3eb", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F3EB}" }, { unified: "1f9d1-1f3fe-200d-1f3eb", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F3EB}" }, { unified: "1f9d1-1f3ff-200d-1f3eb", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F3EB}" }], version: 12.1 }, "male-teacher": { id: "male-teacher", name: "Man Teacher", keywords: ["male", "instructor", "professor", "human"], skins: [{ unified: "1f468-200d-1f3eb", native: "\u{1F468}\u200D\u{1F3EB}" }, { unified: "1f468-1f3fb-200d-1f3eb", native: "\u{1F468}\u{1F3FB}\u200D\u{1F3EB}" }, { unified: "1f468-1f3fc-200d-1f3eb", native: "\u{1F468}\u{1F3FC}\u200D\u{1F3EB}" }, { unified: "1f468-1f3fd-200d-1f3eb", native: "\u{1F468}\u{1F3FD}\u200D\u{1F3EB}" }, { unified: "1f468-1f3fe-200d-1f3eb", native: "\u{1F468}\u{1F3FE}\u200D\u{1F3EB}" }, { unified: "1f468-1f3ff-200d-1f3eb", native: "\u{1F468}\u{1F3FF}\u200D\u{1F3EB}" }], version: 4 }, "female-teacher": { id: "female-teacher", name: "Woman Teacher", keywords: ["female", "instructor", "professor", "human"], skins: [{ unified: "1f469-200d-1f3eb", native: "\u{1F469}\u200D\u{1F3EB}" }, { unified: "1f469-1f3fb-200d-1f3eb", native: "\u{1F469}\u{1F3FB}\u200D\u{1F3EB}" }, { unified: "1f469-1f3fc-200d-1f3eb", native: "\u{1F469}\u{1F3FC}\u200D\u{1F3EB}" }, { unified: "1f469-1f3fd-200d-1f3eb", native: "\u{1F469}\u{1F3FD}\u200D\u{1F3EB}" }, { unified: "1f469-1f3fe-200d-1f3eb", native: "\u{1F469}\u{1F3FE}\u200D\u{1F3EB}" }, { unified: "1f469-1f3ff-200d-1f3eb", native: "\u{1F469}\u{1F3FF}\u200D\u{1F3EB}" }], version: 4 }, judge: { id: "judge", name: "Judge", keywords: ["law"], skins: [{ unified: "1f9d1-200d-2696-fe0f", native: "\u{1F9D1}\u200D\u2696\uFE0F" }, { unified: "1f9d1-1f3fb-200d-2696-fe0f", native: "\u{1F9D1}\u{1F3FB}\u200D\u2696\uFE0F" }, { unified: "1f9d1-1f3fc-200d-2696-fe0f", native: "\u{1F9D1}\u{1F3FC}\u200D\u2696\uFE0F" }, { unified: "1f9d1-1f3fd-200d-2696-fe0f", native: "\u{1F9D1}\u{1F3FD}\u200D\u2696\uFE0F" }, { unified: "1f9d1-1f3fe-200d-2696-fe0f", native: "\u{1F9D1}\u{1F3FE}\u200D\u2696\uFE0F" }, { unified: "1f9d1-1f3ff-200d-2696-fe0f", native: "\u{1F9D1}\u{1F3FF}\u200D\u2696\uFE0F" }], version: 12.1 }, "male-judge": { id: "male-judge", name: "Man Judge", keywords: ["male", "justice", "court", "human"], skins: [{ unified: "1f468-200d-2696-fe0f", native: "\u{1F468}\u200D\u2696\uFE0F" }, { unified: "1f468-1f3fb-200d-2696-fe0f", native: "\u{1F468}\u{1F3FB}\u200D\u2696\uFE0F" }, { unified: "1f468-1f3fc-200d-2696-fe0f", native: "\u{1F468}\u{1F3FC}\u200D\u2696\uFE0F" }, { unified: "1f468-1f3fd-200d-2696-fe0f", native: "\u{1F468}\u{1F3FD}\u200D\u2696\uFE0F" }, { unified: "1f468-1f3fe-200d-2696-fe0f", native: "\u{1F468}\u{1F3FE}\u200D\u2696\uFE0F" }, { unified: "1f468-1f3ff-200d-2696-fe0f", native: "\u{1F468}\u{1F3FF}\u200D\u2696\uFE0F" }], version: 4 }, "female-judge": { id: "female-judge", name: "Woman Judge", keywords: ["female", "justice", "court", "human"], skins: [{ unified: "1f469-200d-2696-fe0f", native: "\u{1F469}\u200D\u2696\uFE0F" }, { unified: "1f469-1f3fb-200d-2696-fe0f", native: "\u{1F469}\u{1F3FB}\u200D\u2696\uFE0F" }, { unified: "1f469-1f3fc-200d-2696-fe0f", native: "\u{1F469}\u{1F3FC}\u200D\u2696\uFE0F" }, { unified: "1f469-1f3fd-200d-2696-fe0f", native: "\u{1F469}\u{1F3FD}\u200D\u2696\uFE0F" }, { unified: "1f469-1f3fe-200d-2696-fe0f", native: "\u{1F469}\u{1F3FE}\u200D\u2696\uFE0F" }, { unified: "1f469-1f3ff-200d-2696-fe0f", native: "\u{1F469}\u{1F3FF}\u200D\u2696\uFE0F" }], version: 4 }, farmer: { id: "farmer", name: "Farmer", keywords: ["crops"], skins: [{ unified: "1f9d1-200d-1f33e", native: "\u{1F9D1}\u200D\u{1F33E}" }, { unified: "1f9d1-1f3fb-200d-1f33e", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F33E}" }, { unified: "1f9d1-1f3fc-200d-1f33e", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F33E}" }, { unified: "1f9d1-1f3fd-200d-1f33e", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F33E}" }, { unified: "1f9d1-1f3fe-200d-1f33e", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F33E}" }, { unified: "1f9d1-1f3ff-200d-1f33e", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F33E}" }], version: 12.1 }, "male-farmer": { id: "male-farmer", name: "Man Farmer", keywords: ["male", "rancher", "gardener", "human"], skins: [{ unified: "1f468-200d-1f33e", native: "\u{1F468}\u200D\u{1F33E}" }, { unified: "1f468-1f3fb-200d-1f33e", native: "\u{1F468}\u{1F3FB}\u200D\u{1F33E}" }, { unified: "1f468-1f3fc-200d-1f33e", native: "\u{1F468}\u{1F3FC}\u200D\u{1F33E}" }, { unified: "1f468-1f3fd-200d-1f33e", native: "\u{1F468}\u{1F3FD}\u200D\u{1F33E}" }, { unified: "1f468-1f3fe-200d-1f33e", native: "\u{1F468}\u{1F3FE}\u200D\u{1F33E}" }, { unified: "1f468-1f3ff-200d-1f33e", native: "\u{1F468}\u{1F3FF}\u200D\u{1F33E}" }], version: 4 }, "female-farmer": { id: "female-farmer", name: "Woman Farmer", keywords: ["female", "rancher", "gardener", "human"], skins: [{ unified: "1f469-200d-1f33e", native: "\u{1F469}\u200D\u{1F33E}" }, { unified: "1f469-1f3fb-200d-1f33e", native: "\u{1F469}\u{1F3FB}\u200D\u{1F33E}" }, { unified: "1f469-1f3fc-200d-1f33e", native: "\u{1F469}\u{1F3FC}\u200D\u{1F33E}" }, { unified: "1f469-1f3fd-200d-1f33e", native: "\u{1F469}\u{1F3FD}\u200D\u{1F33E}" }, { unified: "1f469-1f3fe-200d-1f33e", native: "\u{1F469}\u{1F3FE}\u200D\u{1F33E}" }, { unified: "1f469-1f3ff-200d-1f33e", native: "\u{1F469}\u{1F3FF}\u200D\u{1F33E}" }], version: 4 }
51763, cook: { id: "cook", name: "Cook", keywords: ["food", "kitchen", "culinary"], skins: [{ unified: "1f9d1-200d-1f373", native: "\u{1F9D1}\u200D\u{1F373}" }, { unified: "1f9d1-1f3fb-200d-1f373", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F373}" }, { unified: "1f9d1-1f3fc-200d-1f373", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F373}" }, { unified: "1f9d1-1f3fd-200d-1f373", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F373}" }, { unified: "1f9d1-1f3fe-200d-1f373", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F373}" }, { unified: "1f9d1-1f3ff-200d-1f373", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F373}" }], version: 12.1 }, "male-cook": { id: "male-cook", name: "Man Cook", keywords: ["male", "chef", "human"], skins: [{ unified: "1f468-200d-1f373", native: "\u{1F468}\u200D\u{1F373}" }, { unified: "1f468-1f3fb-200d-1f373", native: "\u{1F468}\u{1F3FB}\u200D\u{1F373}" }, { unified: "1f468-1f3fc-200d-1f373", native: "\u{1F468}\u{1F3FC}\u200D\u{1F373}" }, { unified: "1f468-1f3fd-200d-1f373", native: "\u{1F468}\u{1F3FD}\u200D\u{1F373}" }, { unified: "1f468-1f3fe-200d-1f373", native: "\u{1F468}\u{1F3FE}\u200D\u{1F373}" }, { unified: "1f468-1f3ff-200d-1f373", native: "\u{1F468}\u{1F3FF}\u200D\u{1F373}" }], version: 4 }, "female-cook": { id: "female-cook", name: "Woman Cook", keywords: ["female", "chef", "human"], skins: [{ unified: "1f469-200d-1f373", native: "\u{1F469}\u200D\u{1F373}" }, { unified: "1f469-1f3fb-200d-1f373", native: "\u{1F469}\u{1F3FB}\u200D\u{1F373}" }, { unified: "1f469-1f3fc-200d-1f373", native: "\u{1F469}\u{1F3FC}\u200D\u{1F373}" }, { unified: "1f469-1f3fd-200d-1f373", native: "\u{1F469}\u{1F3FD}\u200D\u{1F373}" }, { unified: "1f469-1f3fe-200d-1f373", native: "\u{1F469}\u{1F3FE}\u200D\u{1F373}" }, { unified: "1f469-1f3ff-200d-1f373", native: "\u{1F469}\u{1F3FF}\u200D\u{1F373}" }], version: 4 }, mechanic: { id: "mechanic", name: "Mechanic", keywords: ["worker", "technician"], skins: [{ unified: "1f9d1-200d-1f527", native: "\u{1F9D1}\u200D\u{1F527}" }, { unified: "1f9d1-1f3fb-200d-1f527", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F527}" }, { unified: "1f9d1-1f3fc-200d-1f527", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F527}" }, { unified: "1f9d1-1f3fd-200d-1f527", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F527}" }, { unified: "1f9d1-1f3fe-200d-1f527", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F527}" }, { unified: "1f9d1-1f3ff-200d-1f527", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F527}" }], version: 12.1 }, "male-mechanic": { id: "male-mechanic", name: "Man Mechanic", keywords: ["male", "plumber", "human", "wrench"], skins: [{ unified: "1f468-200d-1f527", native: "\u{1F468}\u200D\u{1F527}" }, { unified: "1f468-1f3fb-200d-1f527", native: "\u{1F468}\u{1F3FB}\u200D\u{1F527}" }, { unified: "1f468-1f3fc-200d-1f527", native: "\u{1F468}\u{1F3FC}\u200D\u{1F527}" }, { unified: "1f468-1f3fd-200d-1f527", native: "\u{1F468}\u{1F3FD}\u200D\u{1F527}" }, { unified: "1f468-1f3fe-200d-1f527", native: "\u{1F468}\u{1F3FE}\u200D\u{1F527}" }, { unified: "1f468-1f3ff-200d-1f527", native: "\u{1F468}\u{1F3FF}\u200D\u{1F527}" }], version: 4 }, "female-mechanic": { id: "female-mechanic", name: "Woman Mechanic", keywords: ["female", "plumber", "human", "wrench"], skins: [{ unified: "1f469-200d-1f527", native: "\u{1F469}\u200D\u{1F527}" }, { unified: "1f469-1f3fb-200d-1f527", native: "\u{1F469}\u{1F3FB}\u200D\u{1F527}" }, { unified: "1f469-1f3fc-200d-1f527", native: "\u{1F469}\u{1F3FC}\u200D\u{1F527}" }, { unified: "1f469-1f3fd-200d-1f527", native: "\u{1F469}\u{1F3FD}\u200D\u{1F527}" }, { unified: "1f469-1f3fe-200d-1f527", native: "\u{1F469}\u{1F3FE}\u200D\u{1F527}" }, { unified: "1f469-1f3ff-200d-1f527", native: "\u{1F469}\u{1F3FF}\u200D\u{1F527}" }], version: 4 }, factory_worker: { id: "factory_worker", name: "Factory Worker", keywords: ["labor"], skins: [{ unified: "1f9d1-200d-1f3ed", native: "\u{1F9D1}\u200D\u{1F3ED}" }, { unified: "1f9d1-1f3fb-200d-1f3ed", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F3ED}" }, { unified: "1f9d1-1f3fc-200d-1f3ed", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F3ED}" }, { unified: "1f9d1-1f3fd-200d-1f3ed", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F3ED}" }, { unified: "1f9d1-1f3fe-200d-1f3ed", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F3ED}" }, { unified: "1f9d1-1f3ff-200d-1f3ed", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F3ED}" }], version: 12.1 }, "male-factory-worker": { id: "male-factory-worker", name: "Man Factory Worker", keywords: ["male", "factory-worker", "assembly", "industrial", "human"], skins: [{ unified: "1f468-200d-1f3ed", native: "\u{1F468}\u200D\u{1F3ED}" }, { unified: "1f468-1f3fb-200d-1f3ed", native: "\u{1F468}\u{1F3FB}\u200D\u{1F3ED}" }, { unified: "1f468-1f3fc-200d-1f3ed", native: "\u{1F468}\u{1F3FC}\u200D\u{1F3ED}" }, { unified: "1f468-1f3fd-200d-1f3ed", native: "\u{1F468}\u{1F3FD}\u200D\u{1F3ED}" }, { unified: "1f468-1f3fe-200d-1f3ed", native: "\u{1F468}\u{1F3FE}\u200D\u{1F3ED}" }, { unified: "1f468-1f3ff-200d-1f3ed", native: "\u{1F468}\u{1F3FF}\u200D\u{1F3ED}" }], version: 4 }, "female-factory-worker": { id: "female-factory-worker", name: "Woman Factory Worker", keywords: ["female", "factory-worker", "assembly", "industrial", "human"], skins: [{ unified: "1f469-200d-1f3ed", native: "\u{1F469}\u200D\u{1F3ED}" }, { unified: "1f469-1f3fb-200d-1f3ed", native: "\u{1F469}\u{1F3FB}\u200D\u{1F3ED}" }, { unified: "1f469-1f3fc-200d-1f3ed", native: "\u{1F469}\u{1F3FC}\u200D\u{1F3ED}" }, { unified: "1f469-1f3fd-200d-1f3ed", native: "\u{1F469}\u{1F3FD}\u200D\u{1F3ED}" }, { unified: "1f469-1f3fe-200d-1f3ed", native: "\u{1F469}\u{1F3FE}\u200D\u{1F3ED}" }, { unified: "1f469-1f3ff-200d-1f3ed", native: "\u{1F469}\u{1F3FF}\u200D\u{1F3ED}" }], version: 4 }, office_worker: { id: "office_worker", name: "Office Worker", keywords: ["business"], skins: [{ unified: "1f9d1-200d-1f4bc", native: "\u{1F9D1}\u200D\u{1F4BC}" }, { unified: "1f9d1-1f3fb-200d-1f4bc", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F4BC}" }, { unified: "1f9d1-1f3fc-200d-1f4bc", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F4BC}" }, { unified: "1f9d1-1f3fd-200d-1f4bc", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F4BC}" }, { unified: "1f9d1-1f3fe-200d-1f4bc", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F4BC}" }, { unified: "1f9d1-1f3ff-200d-1f4bc", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F4BC}" }], version: 12.1 }, "male-office-worker": { id: "male-office-worker", name: "Man Office Worker", keywords: ["male", "office-worker", "business", "manager", "human"], skins: [{ unified: "1f468-200d-1f4bc", native: "\u{1F468}\u200D\u{1F4BC}" }, { unified: "1f468-1f3fb-200d-1f4bc", native: "\u{1F468}\u{1F3FB}\u200D\u{1F4BC}" }, { unified: "1f468-1f3fc-200d-1f4bc", native: "\u{1F468}\u{1F3FC}\u200D\u{1F4BC}" }, { unified: "1f468-1f3fd-200d-1f4bc", native: "\u{1F468}\u{1F3FD}\u200D\u{1F4BC}" }, { unified: "1f468-1f3fe-200d-1f4bc", native: "\u{1F468}\u{1F3FE}\u200D\u{1F4BC}" }, { unified: "1f468-1f3ff-200d-1f4bc", native: "\u{1F468}\u{1F3FF}\u200D\u{1F4BC}" }], version: 4 }, "female-office-worker": { id: "female-office-worker", name: "Woman Office Worker", keywords: ["female", "office-worker", "business", "manager", "human"], skins: [{ unified: "1f469-200d-1f4bc", native: "\u{1F469}\u200D\u{1F4BC}" }, { unified: "1f469-1f3fb-200d-1f4bc", native: "\u{1F469}\u{1F3FB}\u200D\u{1F4BC}" }, { unified: "1f469-1f3fc-200d-1f4bc", native: "\u{1F469}\u{1F3FC}\u200D\u{1F4BC}" }, { unified: "1f469-1f3fd-200d-1f4bc", native: "\u{1F469}\u{1F3FD}\u200D\u{1F4BC}" }, { unified: "1f469-1f3fe-200d-1f4bc", native: "\u{1F469}\u{1F3FE}\u200D\u{1F4BC}" }, { unified: "1f469-1f3ff-200d-1f4bc", native: "\u{1F469}\u{1F3FF}\u200D\u{1F4BC}" }], version: 4 }
51763, scientist: { id: "scientist", name: "Scientist", keywords: ["chemistry"], skins: [{ unified: "1f9d1-200d-1f52c", native: "\u{1F9D1}\u200D\u{1F52C}" }, { unified: "1f9d1-1f3fb-200d-1f52c", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F52C}" }, { unified: "1f9d1-1f3fc-200d-1f52c", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F52C}" }, { unified: "1f9d1-1f3fd-200d-1f52c", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F52C}" }, { unified: "1f9d1-1f3fe-200d-1f52c", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F52C}" }, { unified: "1f9d1-1f3ff-200d-1f52c", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F52C}" }], version: 12.1 }, "male-scientist": { id: "male-scientist", name: "Man Scientist", keywords: ["male", "biologist", "chemist", "engineer", "physicist", "human"], skins: [{ unified: "1f468-200d-1f52c", native: "\u{1F468}\u200D\u{1F52C}" }, { unified: "1f468-1f3fb-200d-1f52c", native: "\u{1F468}\u{1F3FB}\u200D\u{1F52C}" }, { unified: "1f468-1f3fc-200d-1f52c", native: "\u{1F468}\u{1F3FC}\u200D\u{1F52C}" }, { unified: "1f468-1f3fd-200d-1f52c", native: "\u{1F468}\u{1F3FD}\u200D\u{1F52C}" }, { unified: "1f468-1f3fe-200d-1f52c", native: "\u{1F468}\u{1F3FE}\u200D\u{1F52C}" }, { unified: "1f468-1f3ff-200d-1f52c", native: "\u{1F468}\u{1F3FF}\u200D\u{1F52C}" }], version: 4 }, "female-scientist": { id: "female-scientist", name: "Woman Scientist", keywords: ["female", "biologist", "chemist", "engineer", "physicist", "human"], skins: [{ unified: "1f469-200d-1f52c", native: "\u{1F469}\u200D\u{1F52C}" }, { unified: "1f469-1f3fb-200d-1f52c", native: "\u{1F469}\u{1F3FB}\u200D\u{1F52C}" }, { unified: "1f469-1f3fc-200d-1f52c", native: "\u{1F469}\u{1F3FC}\u200D\u{1F52C}" }, { unified: "1f469-1f3fd-200d-1f52c", native: "\u{1F469}\u{1F3FD}\u200D\u{1F52C}" }, { unified: "1f469-1f3fe-200d-1f52c", native: "\u{1F469}\u{1F3FE}\u200D\u{1F52C}" }, { unified: "1f469-1f3ff-200d-1f52c", native: "\u{1F469}\u{1F3FF}\u200D\u{1F52C}" }], version: 4 }, technologist: { id: "technologist", name: "Technologist", keywords: ["computer"], skins: [{ unified: "1f9d1-200d-1f4bb", native: "\u{1F9D1}\u200D\u{1F4BB}" }, { unified: "1f9d1-1f3fb-200d-1f4bb", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F4BB}" }, { unified: "1f9d1-1f3fc-200d-1f4bb", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F4BB}" }, { unified: "1f9d1-1f3fd-200d-1f4bb", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F4BB}" }, { unified: "1f9d1-1f3fe-200d-1f4bb", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F4BB}" }, { unified: "1f9d1-1f3ff-200d-1f4bb", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F4BB}" }], version: 12.1 }, "male-technologist": { id: "male-technologist", name: "Man Technologist", keywords: ["male", "coder", "developer", "engineer", "programmer", "software", "human", "laptop", "computer"], skins: [{ unified: "1f468-200d-1f4bb", native: "\u{1F468}\u200D\u{1F4BB}" }, { unified: "1f468-1f3fb-200d-1f4bb", native: "\u{1F468}\u{1F3FB}\u200D\u{1F4BB}" }, { unified: "1f468-1f3fc-200d-1f4bb", native: "\u{1F468}\u{1F3FC}\u200D\u{1F4BB}" }, { unified: "1f468-1f3fd-200d-1f4bb", native: "\u{1F468}\u{1F3FD}\u200D\u{1F4BB}" }, { unified: "1f468-1f3fe-200d-1f4bb", native: "\u{1F468}\u{1F3FE}\u200D\u{1F4BB}" }, { unified: "1f468-1f3ff-200d-1f4bb", native: "\u{1F468}\u{1F3FF}\u200D\u{1F4BB}" }], version: 4 }, "female-technologist": { id: "female-technologist", name: "Woman Technologist", keywords: ["female", "coder", "developer", "engineer", "programmer", "software", "human", "laptop", "computer"], skins: [{ unified: "1f469-200d-1f4bb", native: "\u{1F469}\u200D\u{1F4BB}" }, { unified: "1f469-1f3fb-200d-1f4bb", native: "\u{1F469}\u{1F3FB}\u200D\u{1F4BB}" }, { unified: "1f469-1f3fc-200d-1f4bb", native: "\u{1F469}\u{1F3FC}\u200D\u{1F4BB}" }, { unified: "1f469-1f3fd-200d-1f4bb", native: "\u{1F469}\u{1F3FD}\u200D\u{1F4BB}" }, { unified: "1f469-1f3fe-200d-1f4bb", native: "\u{1F469}\u{1F3FE}\u200D\u{1F4BB}" }, { unified: "1f469-1f3ff-200d-1f4bb", native: "\u{1F469}\u{1F3FF}\u200D\u{1F4BB}" }], version: 4 }, singer: { id: "singer", name: "Singer", keywords: ["song", "artist", "performer"], skins: [{ unified: "1f9d1-200d-1f3a4", native: "\u{1F9D1}\u200D\u{1F3A4}" }, { unified: "1f9d1-1f3fb-200d-1f3a4", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F3A4}" }, { unified: "1f9d1-1f3fc-200d-1f3a4", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F3A4}" }, { unified: "1f9d1-1f3fd-200d-1f3a4", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F3A4}" }, { unified: "1f9d1-1f3fe-200d-1f3a4", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F3A4}" }, { unified: "1f9d1-1f3ff-200d-1f3a4", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F3A4}" }], version: 12.1 }, "male-singer": { id: "male-singer", name: "Man Singer", keywords: ["male", "rockstar", "entertainer", "human"], skins: [{ unified: "1f468-200d-1f3a4", native: "\u{1F468}\u200D\u{1F3A4}" }, { unified: "1f468-1f3fb-200d-1f3a4", native: "\u{1F468}\u{1F3FB}\u200D\u{1F3A4}" }, { unified: "1f468-1f3fc-200d-1f3a4", native: "\u{1F468}\u{1F3FC}\u200D\u{1F3A4}" }, { unified: "1f468-1f3fd-200d-1f3a4", native: "\u{1F468}\u{1F3FD}\u200D\u{1F3A4}" }, { unified: "1f468-1f3fe-200d-1f3a4", native: "\u{1F468}\u{1F3FE}\u200D\u{1F3A4}" }, { unified: "1f468-1f3ff-200d-1f3a4", native: "\u{1F468}\u{1F3FF}\u200D\u{1F3A4}" }], version: 4 }, "female-singer": { id: "female-singer", name: "Woman Singer", keywords: ["female", "rockstar", "entertainer", "human"], skins: [{ unified: "1f469-200d-1f3a4", native: "\u{1F469}\u200D\u{1F3A4}" }, { unified: "1f469-1f3fb-200d-1f3a4", native: "\u{1F469}\u{1F3FB}\u200D\u{1F3A4}" }, { unified: "1f469-1f3fc-200d-1f3a4", native: "\u{1F469}\u{1F3FC}\u200D\u{1F3A4}" }, { unified: "1f469-1f3fd-200d-1f3a4", native: "\u{1F469}\u{1F3FD}\u200D\u{1F3A4}" }, { unified: "1f469-1f3fe-200d-1f3a4", native: "\u{1F469}\u{1F3FE}\u200D\u{1F3A4}" }, { unified: "1f469-1f3ff-200d-1f3a4", native: "\u{1F469}\u{1F3FF}\u200D\u{1F3A4}" }], version: 4 }, artist: { id: "artist", name: "Artist", keywords: ["painting", "draw", "creativity"], skins: [{ unified: "1f9d1-200d-1f3a8", native: "\u{1F9D1}\u200D\u{1F3A8}" }, { unified: "1f9d1-1f3fb-200d-1f3a8", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F3A8}" }, { unified: "1f9d1-1f3fc-200d-1f3a8", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F3A8}" }, { unified: "1f9d1-1f3fd-200d-1f3a8", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F3A8}" }, { unified: "1f9d1-1f3fe-200d-1f3a8", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F3A8}" }, { unified: "1f9d1-1f3ff-200d-1f3a8", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F3A8}" }
51763], version: 12.1 }, "male-artist": { id: "male-artist", name: "Man Artist", keywords: ["male", "painter", "human"], skins: [{ unified: "1f468-200d-1f3a8", native: "\u{1F468}\u200D\u{1F3A8}" }, { unified: "1f468-1f3fb-200d-1f3a8", native: "\u{1F468}\u{1F3FB}\u200D\u{1F3A8}" }, { unified: "1f468-1f3fc-200d-1f3a8", native: "\u{1F468}\u{1F3FC}\u200D\u{1F3A8}" }, { unified: "1f468-1f3fd-200d-1f3a8", native: "\u{1F468}\u{1F3FD}\u200D\u{1F3A8}" }, { unified: "1f468-1f3fe-200d-1f3a8", native: "\u{1F468}\u{1F3FE}\u200D\u{1F3A8}" }, { unified: "1f468-1f3ff-200d-1f3a8", native: "\u{1F468}\u{1F3FF}\u200D\u{1F3A8}" }], version: 4 }, "female-artist": { id: "female-artist", name: "Woman Artist", keywords: ["female", "painter", "human"], skins: [{ unified: "1f469-200d-1f3a8", native: "\u{1F469}\u200D\u{1F3A8}" }, { unified: "1f469-1f3fb-200d-1f3a8", native: "\u{1F469}\u{1F3FB}\u200D\u{1F3A8}" }, { unified: "1f469-1f3fc-200d-1f3a8", native: "\u{1F469}\u{1F3FC}\u200D\u{1F3A8}" }, { unified: "1f469-1f3fd-200d-1f3a8", native: "\u{1F469}\u{1F3FD}\u200D\u{1F3A8}" }, { unified: "1f469-1f3fe-200d-1f3a8", native: "\u{1F469}\u{1F3FE}\u200D\u{1F3A8}" }, { unified: "1f469-1f3ff-200d-1f3a8", native: "\u{1F469}\u{1F3FF}\u200D\u{1F3A8}" }], version: 4 }, pilot: { id: "pilot", name: "Pilot", keywords: ["fly", "plane", "airplane"], skins: [{ unified: "1f9d1-200d-2708-fe0f", native: "\u{1F9D1}\u200D\u2708\uFE0F" }, { unified: "1f9d1-1f3fb-200d-2708-fe0f", native: "\u{1F9D1}\u{1F3FB}\u200D\u2708\uFE0F" }, { unified: "1f9d1-1f3fc-200d-2708-fe0f", native: "\u{1F9D1}\u{1F3FC}\u200D\u2708\uFE0F" }, { unified: "1f9d1-1f3fd-200d-2708-fe0f", native: "\u{1F9D1}\u{1F3FD}\u200D\u2708\uFE0F" }, { unified: "1f9d1-1f3fe-200d-2708-fe0f", native: "\u{1F9D1}\u{1F3FE}\u200D\u2708\uFE0F" }, { unified: "1f9d1-1f3ff-200d-2708-fe0f", native: "\u{1F9D1}\u{1F3FF}\u200D\u2708\uFE0F" }], version: 12.1 }, "male-pilot": { id: "male-pilot", name: "Man Pilot", keywords: ["male", "aviator", "plane", "human"], skins: [{ unified: "1f468-200d-2708-fe0f", native: "\u{1F468}\u200D\u2708\uFE0F" }, { unified: "1f468-1f3fb-200d-2708-fe0f", native: "\u{1F468}\u{1F3FB}\u200D\u2708\uFE0F" }, { unified: "1f468-1f3fc-200d-2708-fe0f", native: "\u{1F468}\u{1F3FC}\u200D\u2708\uFE0F" }, { unified: "1f468-1f3fd-200d-2708-fe0f", native: "\u{1F468}\u{1F3FD}\u200D\u2708\uFE0F" }, { unified: "1f468-1f3fe-200d-2708-fe0f", native: "\u{1F468}\u{1F3FE}\u200D\u2708\uFE0F" }, { unified: "1f468-1f3ff-200d-2708-fe0f", native: "\u{1F468}\u{1F3FF}\u200D\u2708\uFE0F" }], version: 4 }, "female-pilot": { id: "female-pilot", name: "Woman Pilot", keywords: ["female", "aviator", "plane", "human"], skins: [{ unified: "1f469-200d-2708-fe0f", native: "\u{1F469}\u200D\u2708\uFE0F" }, { unified: "1f469-1f3fb-200d-2708-fe0f", native: "\u{1F469}\u{1F3FB}\u200D\u2708\uFE0F" }, { unified: "1f469-1f3fc-200d-2708-fe0f", native: "\u{1F469}\u{1F3FC}\u200D\u2708\uFE0F" }, { unified: "1f469-1f3fd-200d-2708-fe0f", native: "\u{1F469}\u{1F3FD}\u200D\u2708\uFE0F" }, { unified: "1f469-1f3fe-200d-2708-fe0f", native: "\u{1F469}\u{1F3FE}\u200D\u2708\uFE0F" }, { unified: "1f469-1f3ff-200d-2708-fe0f", native: "\u{1F469}\u{1F3FF}\u200D\u2708\uFE0F" }], version: 4 }, astronaut: { id: "astronaut", name: "Astronaut", keywords: ["outerspace"], skins: [{ unified: "1f9d1-200d-1f680", native: "\u{1F9D1}\u200D\u{1F680}" }, { unified: "1f9d1-1f3fb-200d-1f680", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F680}" }, { unified: "1f9d1-1f3fc-200d-1f680", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F680}" }, { unified: "1f9d1-1f3fd-200d-1f680", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F680}" }, { unified: "1f9d1-1f3fe-200d-1f680", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F680}" }, { unified: "1f9d1-1f3ff-200d-1f680", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F680}" }], version: 12.1 }, "male-astronaut": { id: "male-astronaut", name: "Man Astronaut", keywords: ["male", "space", "rocket", "human"], skins: [{ unified: "1f468-200d-1f680", native: "\u{1F468}\u200D\u{1F680}" }, { unified: "1f468-1f3fb-200d-1f680", native: "\u{1F468}\u{1F3FB}\u200D\u{1F680}" }, { unified: "1f468-1f3fc-200d-1f680", native: "\u{1F468}\u{1F3FC}\u200D\u{1F680}" }, { unified: "1f468-1f3fd-200d-1f680", native: "\u{1F468}\u{1F3FD}\u200D\u{1F680}" }, { unified: "1f468-1f3fe-200d-1f680", native: "\u{1F468}\u{1F3FE}\u200D\u{1F680}" }, { unified: "1f468-1f3ff-200d-1f680", native: "\u{1F468}\u{1F3FF}\u200D\u{1F680}" }], version: 4 }, "female-astronaut": { id: "female-astronaut", name: "Woman Astronaut", keywords: ["female", "space", "rocket", "human"], skins: [{ unified: "1f469-200d-1f680", native: "\u{1F469}\u200D\u{1F680}" }, { unified: "1f469-1f3fb-200d-1f680", native: "\u{1F469}\u{1F3FB}\u200D\u{1F680}" }, { unified: "1f469-1f3fc-200d-1f680", native: "\u{1F469}\u{1F3FC}\u200D\u{1F680}" }, { unified: "1f469-1f3fd-200d-1f680", native: "\u{1F469}\u{1F3FD}\u200D\u{1F680}" }, { unified: "1f469-1f3fe-200d-1f680", native: "\u{1F469}\u{1F3FE}\u200D\u{1F680}" }, { unified: "1f469-1f3ff-200d-1f680", native: "\u{1F469}\u{1F3FF}\u200D\u{1F680}" }], version: 4 }, firefighter: { id: "firefighter", name: "Firefighter", keywords: ["fire"], skins: [{ unified: "1f9d1-200d-1f692", native: "\u{1F9D1}\u200D\u{1F692}" }, { unified: "1f9d1-1f3fb-200d-1f692", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F692}" }, { unified: "1f9d1-1f3fc-200d-1f692", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F692}" }, { unified: "1f9d1-1f3fd-200d-1f692", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F692}" }, { unified: "1f9d1-1f3fe-200d-1f692", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F692}" }, { unified: "1f9d1-1f3ff-200d-1f692", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F692}" }], version: 12.1 }, "male-firefighter": { id: "male-firefighter", name: "Man Firefighter", keywords: ["male", "fireman", "human"], skins: [{ unified: "1f468-200d-1f692", native: "\u{1F468}\u200D\u{1F692}" }, { unified: "1f468-1f3fb-200d-1f692", native: "\u{1F468}\u{1F3FB}\u200D\u{1F692}" }, { unified: "1f468-1f3fc-200d-1f692", native: "\u{1F468}\u{1F3FC}\u200D\u{1F692}" }, { unified: "1f468-1f3fd-200d-1f692", native: "\u{1F468}\u{1F3FD}\u200D\u{1F692}" }, { unified: "1f468-1f3fe-200d-1f692", native: "\u{1F468}\u{1F3FE}\u200D\u{1F692}" }, { unified: "1f468-1f3ff-200d-1f692", native: "\u{1F468}\u{1F3FF}\u200D\u{1F692}" }], version: 4 }, "female-firefighter": { id: "female-firefighter", name: "Woman Firefighter", keywords: ["female", "fireman", "human"], skins: [{ unified: "1f469-200d-1f692", native: "\u{1F469}\u200D\u{1F692}" }, { unified: "1f469-1f3fb-200d-1f692", native: "\u{1F469}\u{1F3FB}\u200D\u{1F692}" }, { unified: "1f469-1f3fc-200d-1f692", native: "\u{1F469}\u{1F3FC}\u200D\u{1F692}" }, { unified: "1f469-1f3fd-200d-1f692", native: "\u{1F469}\u{1F3FD}\u200D\u{1F692}" }, { unified: "1f469-1f3fe-200d-1f692", native: "\u{1F469}\u{1F3FE}\u200D\u{1F692}" }, { unified: "1f469-1f3ff-200d-1f692", native: "\u{1F469}\u{1F3FF}\u200D\u{1F692}" }], version: 4 }
51763, cop: { id: "cop", name: "Police Officer", keywords: ["cop"], skins: [{ unified: "1f46e", native: "\u{1F46E}" }, { unified: "1f46e-1f3fb", native: "\u{1F46E}\u{1F3FB}" }, { unified: "1f46e-1f3fc", native: "\u{1F46E}\u{1F3FC}" }, { unified: "1f46e-1f3fd", native: "\u{1F46E}\u{1F3FD}" }, { unified: "1f46e-1f3fe", native: "\u{1F46E}\u{1F3FE}" }, { unified: "1f46e-1f3ff", native: "\u{1F46E}\u{1F3FF}" }], version: 1 }, "male-police-officer": { id: "male-police-officer", name: "Man Police Officer", keywords: ["male", "police-officer", "law", "legal", "enforcement", "arrest", "911"], skins: [{ unified: "1f46e-200d-2642-fe0f", native: "\u{1F46E}\u200D\u2642\uFE0F" }, { unified: "1f46e-1f3fb-200d-2642-fe0f", native: "\u{1F46E}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f46e-1f3fc-200d-2642-fe0f", native: "\u{1F46E}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f46e-1f3fd-200d-2642-fe0f", native: "\u{1F46E}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f46e-1f3fe-200d-2642-fe0f", native: "\u{1F46E}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f46e-1f3ff-200d-2642-fe0f", native: "\u{1F46E}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "female-police-officer": { id: "female-police-officer", name: "Woman Police Officer", keywords: ["female", "police-officer", "law", "legal", "enforcement", "arrest", "911"], skins: [{ unified: "1f46e-200d-2640-fe0f", native: "\u{1F46E}\u200D\u2640\uFE0F" }, { unified: "1f46e-1f3fb-200d-2640-fe0f", native: "\u{1F46E}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f46e-1f3fc-200d-2640-fe0f", native: "\u{1F46E}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f46e-1f3fd-200d-2640-fe0f", native: "\u{1F46E}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f46e-1f3fe-200d-2640-fe0f", native: "\u{1F46E}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f46e-1f3ff-200d-2640-fe0f", native: "\u{1F46E}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, sleuth_or_spy: { id: "sleuth_or_spy", name: "Detective", keywords: ["sleuth", "or", "spy", "human"], skins: [{ unified: "1f575-fe0f", native: "\u{1F575}\uFE0F" }, { unified: "1f575-1f3fb", native: "\u{1F575}\u{1F3FB}" }, { unified: "1f575-1f3fc", native: "\u{1F575}\u{1F3FC}" }, { unified: "1f575-1f3fd", native: "\u{1F575}\u{1F3FD}" }, { unified: "1f575-1f3fe", native: "\u{1F575}\u{1F3FE}" }, { unified: "1f575-1f3ff", native: "\u{1F575}\u{1F3FF}" }], version: 1 }, "male-detective": { id: "male-detective", name: "Man Detective", keywords: ["male", "crime"], skins: [{ unified: "1f575-fe0f-200d-2642-fe0f", native: "\u{1F575}\uFE0F\u200D\u2642\uFE0F" }, { unified: "1f575-1f3fb-200d-2642-fe0f", native: "\u{1F575}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f575-1f3fc-200d-2642-fe0f", native: "\u{1F575}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f575-1f3fd-200d-2642-fe0f", native: "\u{1F575}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f575-1f3fe-200d-2642-fe0f", native: "\u{1F575}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f575-1f3ff-200d-2642-fe0f", native: "\u{1F575}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "female-detective": { id: "female-detective", name: "Woman Detective", keywords: ["female", "human", "spy"], skins: [{ unified: "1f575-fe0f-200d-2640-fe0f", native: "\u{1F575}\uFE0F\u200D\u2640\uFE0F" }, { unified: "1f575-1f3fb-200d-2640-fe0f", native: "\u{1F575}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f575-1f3fc-200d-2640-fe0f", native: "\u{1F575}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f575-1f3fd-200d-2640-fe0f", native: "\u{1F575}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f575-1f3fe-200d-2640-fe0f", native: "\u{1F575}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f575-1f3ff-200d-2640-fe0f", native: "\u{1F575}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, guardsman: { id: "guardsman", name: "Guard", keywords: ["guardsman", "protect"], skins: [{ unified: "1f482", native: "\u{1F482}" }, { unified: "1f482-1f3fb", native: "\u{1F482}\u{1F3FB}" }, { unified: "1f482-1f3fc", native: "\u{1F482}\u{1F3FC}" }, { unified: "1f482-1f3fd", native: "\u{1F482}\u{1F3FD}" }, { unified: "1f482-1f3fe", native: "\u{1F482}\u{1F3FE}" }, { unified: "1f482-1f3ff", native: "\u{1F482}\u{1F3FF}" }], version: 1 }, "male-guard": { id: "male-guard", name: "Man Guard", keywords: ["male", "uk", "gb", "british", "guy", "royal"], skins: [{ unified: "1f482-200d-2642-fe0f", native: "\u{1F482}\u200D\u2642\uFE0F" }, { unified: "1f482-1f3fb-200d-2642-fe0f", native: "\u{1F482}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f482-1f3fc-200d-2642-fe0f", native: "\u{1F482}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f482-1f3fd-200d-2642-fe0f", native: "\u{1F482}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f482-1f3fe-200d-2642-fe0f", native: "\u{1F482}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f482-1f3ff-200d-2642-fe0f", native: "\u{1F482}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "female-guard": { id: "female-guard", name: "Woman Guard", keywords: ["female", "uk", "gb", "british", "royal"], skins: [{ unified: "1f482-200d-2640-fe0f", native: "\u{1F482}\u200D\u2640\uFE0F" }, { unified: "1f482-1f3fb-200d-2640-fe0f", native: "\u{1F482}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f482-1f3fc-200d-2640-fe0f", native: "\u{1F482}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f482-1f3fd-200d-2640-fe0f", native: "\u{1F482}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f482-1f3fe-200d-2640-fe0f", native: "\u{1F482}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f482-1f3ff-200d-2640-fe0f", native: "\u{1F482}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, ninja: { id: "ninja", name: "Ninja", keywords: ["ninjutsu", "skills", "japanese"], skins: [{ unified: "1f977", native: "\u{1F977}" }, { unified: "1f977-1f3fb", native: "\u{1F977}\u{1F3FB}" }, { unified: "1f977-1f3fc", native: "\u{1F977}\u{1F3FC}" }, { unified: "1f977-1f3fd", native: "\u{1F977}\u{1F3FD}" }, { unified: "1f977-1f3fe", native: "\u{1F977}\u{1F3FE}" }, { unified: "1f977-1f3ff", native: "\u{1F977}\u{1F3FF}" }], version: 13 }
51763, construction_worker: { id: "construction_worker", name: "Construction Worker", keywords: ["labor", "build"], skins: [{ unified: "1f477", native: "\u{1F477}" }, { unified: "1f477-1f3fb", native: "\u{1F477}\u{1F3FB}" }, { unified: "1f477-1f3fc", native: "\u{1F477}\u{1F3FC}" }, { unified: "1f477-1f3fd", native: "\u{1F477}\u{1F3FD}" }, { unified: "1f477-1f3fe", native: "\u{1F477}\u{1F3FE}" }, { unified: "1f477-1f3ff", native: "\u{1F477}\u{1F3FF}" }], version: 1 }, "male-construction-worker": { id: "male-construction-worker", name: "Man Construction Worker", keywords: ["male", "construction-worker", "human", "wip", "guy", "build", "labor"], skins: [{ unified: "1f477-200d-2642-fe0f", native: "\u{1F477}\u200D\u2642\uFE0F" }, { unified: "1f477-1f3fb-200d-2642-fe0f", native: "\u{1F477}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f477-1f3fc-200d-2642-fe0f", native: "\u{1F477}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f477-1f3fd-200d-2642-fe0f", native: "\u{1F477}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f477-1f3fe-200d-2642-fe0f", native: "\u{1F477}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f477-1f3ff-200d-2642-fe0f", native: "\u{1F477}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "female-construction-worker": { id: "female-construction-worker", name: "Woman Construction Worker", keywords: ["female", "construction-worker", "human", "wip", "build", "labor"], skins: [{ unified: "1f477-200d-2640-fe0f", native: "\u{1F477}\u200D\u2640\uFE0F" }, { unified: "1f477-1f3fb-200d-2640-fe0f", native: "\u{1F477}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f477-1f3fc-200d-2640-fe0f", native: "\u{1F477}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f477-1f3fd-200d-2640-fe0f", native: "\u{1F477}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f477-1f3fe-200d-2640-fe0f", native: "\u{1F477}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f477-1f3ff-200d-2640-fe0f", native: "\u{1F477}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, person_with_crown: { id: "person_with_crown", name: "Person with Crown", keywords: ["royalty", "power"], skins: [{ unified: "1fac5", native: "\u{1FAC5}" }, { unified: "1fac5-1f3fb", native: "\u{1FAC5}\u{1F3FB}" }, { unified: "1fac5-1f3fc", native: "\u{1FAC5}\u{1F3FC}" }, { unified: "1fac5-1f3fd", native: "\u{1FAC5}\u{1F3FD}" }, { unified: "1fac5-1f3fe", native: "\u{1FAC5}\u{1F3FE}" }, { unified: "1fac5-1f3ff", native: "\u{1FAC5}\u{1F3FF}" }], version: 14 }, prince: { id: "prince", name: "Prince", keywords: ["boy", "man", "male", "crown", "royal", "king"], skins: [{ unified: "1f934", native: "\u{1F934}" }, { unified: "1f934-1f3fb", native: "\u{1F934}\u{1F3FB}" }, { unified: "1f934-1f3fc", native: "\u{1F934}\u{1F3FC}" }, { unified: "1f934-1f3fd", native: "\u{1F934}\u{1F3FD}" }, { unified: "1f934-1f3fe", native: "\u{1F934}\u{1F3FE}" }, { unified: "1f934-1f3ff", native: "\u{1F934}\u{1F3FF}" }], version: 3 }, princess: { id: "princess", name: "Princess", keywords: ["girl", "woman", "female", "blond", "crown", "royal", "queen"], skins: [{ unified: "1f478", native: "\u{1F478}" }, { unified: "1f478-1f3fb", native: "\u{1F478}\u{1F3FB}" }, { unified: "1f478-1f3fc", native: "\u{1F478}\u{1F3FC}" }, { unified: "1f478-1f3fd", native: "\u{1F478}\u{1F3FD}" }, { unified: "1f478-1f3fe", native: "\u{1F478}\u{1F3FE}" }, { unified: "1f478-1f3ff", native: "\u{1F478}\u{1F3FF}" }], version: 1 }, man_with_turban: { id: "man_with_turban", name: "Man with Turban", keywords: ["person", "wearing", "headdress"], skins: [{ unified: "1f473", native: "\u{1F473}" }, { unified: "1f473-1f3fb", native: "\u{1F473}\u{1F3FB}" }, { unified: "1f473-1f3fc", native: "\u{1F473}\u{1F3FC}" }, { unified: "1f473-1f3fd", native: "\u{1F473}\u{1F3FD}" }, { unified: "1f473-1f3fe", native: "\u{1F473}\u{1F3FE}" }, { unified: "1f473-1f3ff", native: "\u{1F473}\u{1F3FF}" }], version: 1 }, "man-wearing-turban": { id: "man-wearing-turban", name: "Man Wearing Turban", keywords: ["wearing-turban", "male", "indian", "hinduism", "arabs"], skins: [{ unified: "1f473-200d-2642-fe0f", native: "\u{1F473}\u200D\u2642\uFE0F" }, { unified: "1f473-1f3fb-200d-2642-fe0f", native: "\u{1F473}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f473-1f3fc-200d-2642-fe0f", native: "\u{1F473}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f473-1f3fd-200d-2642-fe0f", native: "\u{1F473}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f473-1f3fe-200d-2642-fe0f", native: "\u{1F473}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f473-1f3ff-200d-2642-fe0f", native: "\u{1F473}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-wearing-turban": { id: "woman-wearing-turban", name: "Woman Wearing Turban", keywords: ["wearing-turban", "female", "indian", "hinduism", "arabs"], skins: [{ unified: "1f473-200d-2640-fe0f", native: "\u{1F473}\u200D\u2640\uFE0F" }, { unified: "1f473-1f3fb-200d-2640-fe0f", native: "\u{1F473}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f473-1f3fc-200d-2640-fe0f", native: "\u{1F473}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f473-1f3fd-200d-2640-fe0f", native: "\u{1F473}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f473-1f3fe-200d-2640-fe0f", native: "\u{1F473}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f473-1f3ff-200d-2640-fe0f", native: "\u{1F473}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, man_with_gua_pi_mao: { id: "man_with_gua_pi_mao", name: "Man with Gua Pi Mao", keywords: ["skullcap", "male", "boy", "chinese"], skins: [{ unified: "1f472", native: "\u{1F472}" }, { unified: "1f472-1f3fb", native: "\u{1F472}\u{1F3FB}" }, { unified: "1f472-1f3fc", native: "\u{1F472}\u{1F3FC}" }, { unified: "1f472-1f3fd", native: "\u{1F472}\u{1F3FD}" }, { unified: "1f472-1f3fe", native: "\u{1F472}\u{1F3FE}" }, { unified: "1f472-1f3ff", native: "\u{1F472}\u{1F3FF}" }], version: 1 }, person_with_headscarf: { id: "person_with_headscarf", name: "Woman with Headscarf", keywords: ["person", "female", "hijab", "mantilla", "tichel"], skins: [{ unified: "1f9d5", native: "\u{1F9D5}" }, { unified: "1f9d5-1f3fb", native: "\u{1F9D5}\u{1F3FB}" }, { unified: "1f9d5-1f3fc", native: "\u{1F9D5}\u{1F3FC}" }, { unified: "1f9d5-1f3fd", native: "\u{1F9D5}\u{1F3FD}" }, { unified: "1f9d5-1f3fe", native: "\u{1F9D5}\u{1F3FE}" }, { unified: "1f9d5-1f3ff", native: "\u{1F9D5}\u{1F3FF}" }], version: 5 }, person_in_tuxedo: { id: "person_in_tuxedo", name: "Man in Tuxedo", keywords: ["person", "couple", "marriage", "wedding", "groom"], skins: [{ unified: "1f935", native: "\u{1F935}" }, { unified: "1f935-1f3fb", native: "\u{1F935}\u{1F3FB}" }, { unified: "1f935-1f3fc", native: "\u{1F935}\u{1F3FC}" }, { unified: "1f935-1f3fd", native: "\u{1F935}\u{1F3FD}" }, { unified: "1f935-1f3fe", native: "\u{1F935}\u{1F3FE}" }, { unified: "1f935-1f3ff", native: "\u{1F935}\u{1F3FF}" }], version: 3 }, man_in_tuxedo: { id: "man_in_tuxedo", name: "Man in Tuxedo", keywords: ["formal", "fashion"], skins: [{ unified: "1f935-200d-2642-fe0f", native: "\u{1F935}\u200D\u2642\uFE0F" }, { unified: "1f935-1f3fb-200d-2642-fe0f", native: "\u{1F935}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f935-1f3fc-200d-2642-fe0f", native: "\u{1F935}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f935-1f3fd-200d-2642-fe0f", native: "\u{1F935}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f935-1f3fe-200d-2642-fe0f", native: "\u{1F935}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f935-1f3ff-200d-2642-fe0f", native: "\u{1F935}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 13 }, woman_in_tuxedo: { id: "woman_in_tuxedo", name: "Woman in Tuxedo", keywords: ["formal", "fashion"], skins: [{ unified: "1f935-200d-2640-fe0f", native: "\u{1F935}\u200D\u2640\uFE0F" }, { unified: "1f935-1f3fb-200d-2640-fe0f", native: "\u{1F935}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f935-1f3fc-200d-2640-fe0f", native: "\u{1F935}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f935-1f3fd-200d-2640-fe0f", native: "\u{1F935}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f935-1f3fe-200d-2640-fe0f", native: "\u{1F935}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f935-1f3ff-200d-2640-fe0f", native: "\u{1F935}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 13 }, bride_with_veil: { id: "bride_with_veil", name: "Bride with Veil", keywords: ["couple", "marriage", "wedding", "woman"], skins: [{ unified: "1f470", native: "\u{1F470}" }, { unified: "1f470-1f3fb", native: "\u{1F470}\u{1F3FB}" }, { unified: "1f470-1f3fc", native: "\u{1F470}\u{1F3FC}" }, { unified: "1f470-1f3fd", native: "\u{1F470}\u{1F3FD}" }, { unified: "1f470-1f3fe", native: "\u{1F470}\u{1F3FE}" }, { unified: "1f470-1f3ff", native: "\u{1F470}\u{1F3FF}" }], version: 1 }, man_with_veil: { id: "man_with_veil", name: "Man with Veil", keywords: ["wedding", "marriage"], skins: [{ unified: "1f470-200d-2642-fe0f", native: "\u{1F470}\u200D\u2642\uFE0F" }, { unified: "1f470-1f3fb-200d-2642-fe0f", native: "\u{1F470}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f470-1f3fc-200d-2642-fe0f", native: "\u{1F470}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f470-1f3fd-200d-2642-fe0f", native: "\u{1F470}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f470-1f3fe-200d-2642-fe0f", native: "\u{1F470}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f470-1f3ff-200d-2642-fe0f", native: "\u{1F470}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 13 }, woman_with_veil: { id: "woman_with_veil", name: "Woman with Veil", keywords: ["wedding", "marriage"], skins: [{ unified: "1f470-200d-2640-fe0f", native: "\u{1F470}\u200D\u2640\uFE0F" }, { unified: "1f470-1f3fb-200d-2640-fe0f", native: "\u{1F470}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f470-1f3fc-200d-2640-fe0f", native: "\u{1F470}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f470-1f3fd-200d-2640-fe0f", native: "\u{1F470}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f470-1f3fe-200d-2640-fe0f", native: "\u{1F470}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f470-1f3ff-200d-2640-fe0f", native: "\u{1F470}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 13 }, pregnant_woman: { id: "pregnant_woman", name: "Pregnant Woman", keywords: ["baby"], skins: [{ unified: "1f930", native: "\u{1F930}" }, { unified: "1f930-1f3fb", native: "\u{1F930}\u{1F3FB}" }, { unified: "1f930-1f3fc", native: "\u{1F930}\u{1F3FC}" }, { unified: "1f930-1f3fd", native: "\u{1F930}\u{1F3FD}" }, { unified: "1f930-1f3fe", native: "\u{1F930}\u{1F3FE}" }, { unified: "1f930-1f3ff", native: "\u{1F930}\u{1F3FF}" }], version: 3 }, pregnant_man: { id: "pregnant_man", name: "Pregnant Man", keywords: ["baby", "belly"], skins: [{ unified: "1fac3", native: "\u{1FAC3}" }, { unified: "1fac3-1f3fb", native: "\u{1FAC3}\u{1F3FB}" }, { unified: "1fac3-1f3fc", native: "\u{1FAC3}\u{1F3FC}" }, { unified: "1fac3-1f3fd", native: "\u{1FAC3}\u{1F3FD}" }, { unified: "1fac3-1f3fe", native: "\u{1FAC3}\u{1F3FE}" }, { unified: "1fac3-1f3ff", native: "\u{1FAC3}\u{1F3FF}" }], version: 14 }, pregnant_person: { id: "pregnant_person", name: "Pregnant Person", keywords: ["baby", "belly"], skins: [{ unified: "1fac4", native: "\u{1FAC4}" }, { unified: "1fac4-1f3fb", native: "\u{1FAC4}\u{1F3FB}" }, { unified: "1fac4-1f3fc", native: "\u{1FAC4}\u{1F3FC}" }, { unified: "1fac4-1f3fd", native: "\u{1FAC4}\u{1F3FD}" }, { unified: "1fac4-1f3fe", native: "\u{1FAC4}\u{1F3FE}" }, { unified: "1fac4-1f3ff", native: "\u{1FAC4}\u{1F3FF}" }], version: 14 }, "breast-feeding": { id: "breast-feeding", name: "Breast-Feeding", keywords: ["breast", "feeding", "nursing", "baby"], skins: [{ unified: "1f931", native: "\u{1F931}" }, { unified: "1f931-1f3fb", native: "\u{1F931}\u{1F3FB}" }, { unified: "1f931-1f3fc", native: "\u{1F931}\u{1F3FC}" }, { unified: "1f931-1f3fd", native: "\u{1F931}\u{1F3FD}" }, { unified: "1f931-1f3fe", native: "\u{1F931}\u{1F3FE}" }, { unified: "1f931-1f3ff", native: "\u{1F931}\u{1F3FF}" }], version: 5 }, woman_feeding_baby: { id: "woman_feeding_baby", name: "Woman Feeding Baby", keywords: ["birth", "food"], skins: [{ unified: "1f469-200d-1f37c", native: "\u{1F469}\u200D\u{1F37C}" }, { unified: "1f469-1f3fb-200d-1f37c", native: "\u{1F469}\u{1F3FB}\u200D\u{1F37C}" }, { unified: "1f469-1f3fc-200d-1f37c", native: "\u{1F469}\u{1F3FC}\u200D\u{1F37C}" }, { unified: "1f469-1f3fd-200d-1f37c", native: "\u{1F469}\u{1F3FD}\u200D\u{1F37C}" }, { unified: "1f469-1f3fe-200d-1f37c", native: "\u{1F469}\u{1F3FE}\u200D\u{1F37C}" }, { unified: "1f469-1f3ff-200d-1f37c", native: "\u{1F469}\u{1F3FF}\u200D\u{1F37C}" }], version: 13 }, man_feeding_baby: { id: "man_feeding_baby", name: "Man Feeding Baby", keywords: ["birth", "food"], skins: [{ unified: "1f468-200d-1f37c", native: "\u{1F468}\u200D\u{1F37C}" }, { unified: "1f468-1f3fb-200d-1f37c", native: "\u{1F468}\u{1F3FB}\u200D\u{1F37C}" }, { unified: "1f468-1f3fc-200d-1f37c", native: "\u{1F468}\u{1F3FC}\u200D\u{1F37C}" }, { unified: "1f468-1f3fd-200d-1f37c", native: "\u{1F468}\u{1F3FD}\u200D\u{1F37C}" }, { unified: "1f468-1f3fe-200d-1f37c", native: "\u{1F468}\u{1F3FE}\u200D\u{1F37C}" }, { unified: "1f468-1f3ff-200d-1f37c", native: "\u{1F468}\u{1F3FF}\u200D\u{1F37C}" }], version: 13 }, person_feeding_baby: { id: "person_feeding_baby", name: "Person Feeding Baby", keywords: ["birth", "food"], skins: [{ unified: "1f9d1-200d-1f37c", native: "\u{1F9D1}\u200D\u{1F37C}" }, { unified: "1f9d1-1f3fb-200d-1f37c", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F37C}" }, { unified: "1f9d1-1f3fc-200d-1f37c", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F37C}" }, { unified: "1f9d1-1f3fd-200d-1f37c", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F37C}" }, { unified: "1f9d1-1f3fe-200d-1f37c", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F37C}" }, { unified: "1f9d1-1f3ff-200d-1f37c", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F37C}" }], version: 13 }, angel: { id: "angel", name: "Baby Angel", keywords: ["heaven", "wings", "halo"], skins: [{ unified: "1f47c", native: "\u{1F47C}" }, { unified: "1f47c-1f3fb", native: "\u{1F47C}\u{1F3FB}" }, { unified: "1f47c-1f3fc", native: "\u{1F47C}\u{1F3FC}" }, { unified: "1f47c-1f3fd", native: "\u{1F47C}\u{1F3FD}" }, { unified: "1f47c-1f3fe", native: "\u{1F47C}\u{1F3FE}" }, { unified: "1f47c-1f3ff", native: "\u{1F47C}\u{1F3FF}" }], version: 1 }, santa: { id: "santa", name: "Santa Claus", keywords: ["festival", "man", "male", "xmas", "father", "christmas"], skins: [{ unified: "1f385", native: "\u{1F385}" }, { unified: "1f385-1f3fb", native: "\u{1F385}\u{1F3FB}" }, { unified: "1f385-1f3fc", native: "\u{1F385}\u{1F3FC}" }, { unified: "1f385-1f3fd", native: "\u{1F385}\u{1F3FD}" }, { unified: "1f385-1f3fe", native: "\u{1F385}\u{1F3FE}" }, { unified: "1f385-1f3ff", native: "\u{1F385}\u{1F3FF}" }], version: 1 }, mrs_claus: { id: "mrs_claus", name: "Mrs. Claus", keywords: ["mrs", "mother", "christmas", "woman", "female", "xmas"], skins: [{ unified: "1f936", native: "\u{1F936}" }, { unified: "1f936-1f3fb", native: "\u{1F936}\u{1F3FB}" }, { unified: "1f936-1f3fc", native: "\u{1F936}\u{1F3FC}" }, { unified: "1f936-1f3fd", native: "\u{1F936}\u{1F3FD}" }, { unified: "1f936-1f3fe", native: "\u{1F936}\u{1F3FE}" }, { unified: "1f936-1f3ff", native: "\u{1F936}\u{1F3FF}" }], version: 3 }, mx_claus: { id: "mx_claus", name: "Mx Claus", keywords: ["christmas"], skins: [{ unified: "1f9d1-200d-1f384", native: "\u{1F9D1}\u200D\u{1F384}" }, { unified: "1f9d1-1f3fb-200d-1f384", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F384}" }, { unified: "1f9d1-1f3fc-200d-1f384", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F384}" }, { unified: "1f9d1-1f3fd-200d-1f384", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F384}" }, { unified: "1f9d1-1f3fe-200d-1f384", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F384}" }, { unified: "1f9d1-1f3ff-200d-1f384", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F384}" }], version: 13 }, superhero: { id: "superhero", name: "Superhero", keywords: ["marvel"], skins: [{ unified: "1f9b8", native: "\u{1F9B8}" }, { unified: "1f9b8-1f3fb", native: "\u{1F9B8}\u{1F3FB}" }, { unified: "1f9b8-1f3fc", native: "\u{1F9B8}\u{1F3FC}" }, { unified: "1f9b8-1f3fd", native: "\u{1F9B8}\u{1F3FD}" }, { unified: "1f9b8-1f3fe", native: "\u{1F9B8}\u{1F3FE}" }, { unified: "1f9b8-1f3ff", native: "\u{1F9B8}\u{1F3FF}" }], version: 11 }, male_superhero: { id: "male_superhero", name: "Man Superhero", keywords: ["male", "good", "hero", "superpowers"], skins: [{ unified: "1f9b8-200d-2642-fe0f", native: "\u{1F9B8}\u200D\u2642\uFE0F" }, { unified: "1f9b8-1f3fb-200d-2642-fe0f", native: "\u{1F9B8}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9b8-1f3fc-200d-2642-fe0f", native: "\u{1F9B8}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9b8-1f3fd-200d-2642-fe0f", native: "\u{1F9B8}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9b8-1f3fe-200d-2642-fe0f", native: "\u{1F9B8}\u{1F3FE}\u200D\u2642\uFE0F
51763" }, { unified: "1f9b8-1f3ff-200d-2642-fe0f", native: "\u{1F9B8}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 11 }, female_superhero: { id: "female_superhero", name: "Woman Superhero", keywords: ["female", "good", "heroine", "superpowers"], skins: [{ unified: "1f9b8-200d-2640-fe0f", native: "\u{1F9B8}\u200D\u2640\uFE0F" }, { unified: "1f9b8-1f3fb-200d-2640-fe0f", native: "\u{1F9B8}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9b8-1f3fc-200d-2640-fe0f", native: "\u{1F9B8}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9b8-1f3fd-200d-2640-fe0f", native: "\u{1F9B8}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9b8-1f3fe-200d-2640-fe0f", native: "\u{1F9B8}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9b8-1f3ff-200d-2640-fe0f", native: "\u{1F9B8}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 11 }, supervillain: { id: "supervillain", name: "Supervillain", keywords: ["marvel"], skins: [{ unified: "1f9b9", native: "\u{1F9B9}" }, { unified: "1f9b9-1f3fb", native: "\u{1F9B9}\u{1F3FB}" }, { unified: "1f9b9-1f3fc", native: "\u{1F9B9}\u{1F3FC}" }, { unified: "1f9b9-1f3fd", native: "\u{1F9B9}\u{1F3FD}" }, { unified: "1f9b9-1f3fe", native: "\u{1F9B9}\u{1F3FE}" }, { unified: "1f9b9-1f3ff", native: "\u{1F9B9}\u{1F3FF}" }], version: 11 }, male_supervillain: { id: "male_supervillain", name: "Man Supervillain", keywords: ["male", "evil", "bad", "criminal", "hero", "superpowers"], skins: [{ unified: "1f9b9-200d-2642-fe0f", native: "\u{1F9B9}\u200D\u2642\uFE0F" }, { unified: "1f9b9-1f3fb-200d-2642-fe0f", native: "\u{1F9B9}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9b9-1f3fc-200d-2642-fe0f", native: "\u{1F9B9}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9b9-1f3fd-200d-2642-fe0f", native: "\u{1F9B9}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9b9-1f3fe-200d-2642-fe0f", native: "\u{1F9B9}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9b9-1f3ff-200d-2642-fe0f", native: "\u{1F9B9}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 11 }, female_supervillain: { id: "female_supervillain", name: "Woman Supervillain", keywords: ["female", "evil", "bad", "criminal", "heroine", "superpowers"], skins: [{ unified: "1f9b9-200d-2640-fe0f", native: "\u{1F9B9}\u200D\u2640\uFE0F" }, { unified: "1f9b9-1f3fb-200d-2640-fe0f", native: "\u{1F9B9}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9b9-1f3fc-200d-2640-fe0f", native: "\u{1F9B9}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9b9-1f3fd-200d-2640-fe0f", native: "\u{1F9B9}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9b9-1f3fe-200d-2640-fe0f", native: "\u{1F9B9}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9b9-1f3ff-200d-2640-fe0f", native: "\u{1F9B9}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 11 }, mage: { id: "mage", name: "Mage", keywords: ["magic"], skins: [{ unified: "1f9d9", native: "\u{1F9D9}" }, { unified: "1f9d9-1f3fb", native: "\u{1F9D9}\u{1F3FB}" }, { unified: "1f9d9-1f3fc", native: "\u{1F9D9}\u{1F3FC}" }, { unified: "1f9d9-1f3fd", native: "\u{1F9D9}\u{1F3FD}" }, { unified: "1f9d9-1f3fe", native: "\u{1F9D9}\u{1F3FE}" }, { unified: "1f9d9-1f3ff", native: "\u{1F9D9}\u{1F3FF}" }], version: 5 }, male_mage: { id: "male_mage", name: "Man Mage", keywords: ["male", "sorcerer"], skins: [{ unified: "1f9d9-200d-2642-fe0f", native: "\u{1F9D9}\u200D\u2642\uFE0F" }, { unified: "1f9d9-1f3fb-200d-2642-fe0f", native: "\u{1F9D9}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9d9-1f3fc-200d-2642-fe0f", native: "\u{1F9D9}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9d9-1f3fd-200d-2642-fe0f", native: "\u{1F9D9}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9d9-1f3fe-200d-2642-fe0f", native: "\u{1F9D9}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9d9-1f3ff-200d-2642-fe0f", native: "\u{1F9D9}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 5 }, female_mage: { id: "female_mage", name: "Woman Mage", keywords: ["female", "witch"], skins: [{ unified: "1f9d9-200d-2640-fe0f", native: "\u{1F9D9}\u200D\u2640\uFE0F" }, { unified: "1f9d9-1f3fb-200d-2640-fe0f", native: "\u{1F9D9}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9d9-1f3fc-200d-2640-fe0f", native: "\u{1F9D9}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9d9-1f3fd-200d-2640-fe0f", native: "\u{1F9D9}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9d9-1f3fe-200d-2640-fe0f", native: "\u{1F9D9}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9d9-1f3ff-200d-2640-fe0f", native: "\u{1F9D9}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 5 }, fairy: { id: "fairy", name: "Fairy", keywords: ["wings", "magical"], skins: [{ unified: "1f9da", native: "\u{1F9DA}" }, { unified: "1f9da-1f3fb", native: "\u{1F9DA}\u{1F3FB}" }, { unified: "1f9da-1f3fc", native: "\u{1F9DA}\u{1F3FC}" }, { unified: "1f9da-1f3fd", native: "\u{1F9DA}\u{1F3FD}" }, { unified: "1f9da-1f3fe", native: "\u{1F9DA}\u{1F3FE}" }, { unified: "1f9da-1f3ff", native: "\u{1F9DA}\u{1F3FF}" }], version: 5 }, male_fairy: { id: "male_fairy", name: "Man Fairy", keywords: ["male"], skins: [{ unified: "1f9da-200d-2642-fe0f", native: "\u{1F9DA}\u200D\u2642\uFE0F" }, { unified: "1f9da-1f3fb-200d-2642-fe0f", native: "\u{1F9DA}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9da-1f3fc-200d-2642-fe0f", native: "\u{1F9DA}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9da-1f3fd-200d-2642-fe0f", native: "\u{1F9DA}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9da-1f3fe-200d-2642-fe0f", native: "\u{1F9DA}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9da-1f3ff-200d-2642-fe0f", native: "\u{1F9DA}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 5 }, female_fairy: { id: "female_fairy", name: "Woman Fairy", keywords: ["female"], skins: [{ unified: "1f9da-200d-2640-fe0f", native: "\u{1F9DA}\u200D\u2640\uFE0F" }, { unified: "1f9da-1f3fb-200d-2640-fe0f", native: "\u{1F9DA}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9da-1f3fc-200d-2640-fe0f", native: "\u{1F9DA}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9da-1f3fd-200d-2640-fe0f", native: "\u{1F9DA}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9da-1f3fe-200d-2640-fe0f", native: "\u{1F9DA}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9da-1f3ff-200d-2640-fe0f", native: "\u{1F9DA}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 5 }, vampire: { id: "vampire", name: "Vampire", keywords: ["blood", "twilight"], skins: [{ unified: "1f9db", native: "\u{1F9DB}" }, { unified: "1f9db-1f3fb", native: "\u{1F9DB}\u{1F3FB}" }, { unified: "1f9db-1f3fc", native: "\u{1F9DB}\u{1F3FC}" }, { unified: "1f9db-1f3fd", native: "\u{1F9DB}\u{1F3FD}" }, { unified: "1f9db-1f3fe", native: "\u{1F9DB}\u{1F3FE}" }, { unified: "1f9db-1f3ff", native: "\u{1F9DB}\u{1F3FF}" }], version: 5 }, male_vampire: { id: "male_vampire", name: "Man Vampire", keywords: ["male", "dracula"], skins: [{ unified: "1f9db-200d-2642-fe0f", native: "\u{1F9DB}\u200D\u2642\uFE0F" }, { unified: "1f9db-1f3fb-200d-2642-fe0f", native: "\u{1F9DB}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9db-1f3fc-200d-2642-fe0f", native: "\u{1F9DB}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9db-1f3fd-200d-2642-fe0f", native: "\u{1F9DB}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9db-1f3fe-200d-2642-fe0f", native: "\u{1F9DB}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9db-1f3ff-200d-2642-fe0f", native: "\u{1F9DB}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 5 }, female_vampire: { id: "female_vampire", name: "Woman Vampire", keywords: ["female"], skins: [{ unified: "1f9db-200d-2640-fe0f", native: "\u{1F9DB}\u200D\u2640\uFE0F" }, { unified: "1f9db-1f3fb-200d-2640-fe0f", native: "\u{1F9DB}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9db-1f3fc-200d-2640-fe0f", native: "\u{1F9DB}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9db-1f3fd-200d-2640-fe0f", native: "\u{1F9DB}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9db-1f3fe-200d-2640-fe0f", native: "\u{1F9DB}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9db-1f3ff-200d-2640-fe0f", native: "\u{1F9DB}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 5 }, merperson: { id: "merperson", name: "Merperson", keywords: ["sea"], skins: [{ unified: "1f9dc", native: "\u{1F9DC}" }, { unified: "1f9dc-1f3fb", native: "\u{1F9DC}
51763\u{1F3FB}" }, { unified: "1f9dc-1f3fc", native: "\u{1F9DC}\u{1F3FC}" }, { unified: "1f9dc-1f3fd", native: "\u{1F9DC}\u{1F3FD}" }, { unified: "1f9dc-1f3fe", native: "\u{1F9DC}\u{1F3FE}" }, { unified: "1f9dc-1f3ff", native: "\u{1F9DC}\u{1F3FF}" }], version: 5 }, merman: { id: "merman", name: "Merman", keywords: ["man", "male", "triton"], skins: [{ unified: "1f9dc-200d-2642-fe0f", native: "\u{1F9DC}\u200D\u2642\uFE0F" }, { unified: "1f9dc-1f3fb-200d-2642-fe0f", native: "\u{1F9DC}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9dc-1f3fc-200d-2642-fe0f", native: "\u{1F9DC}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9dc-1f3fd-200d-2642-fe0f", native: "\u{1F9DC}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9dc-1f3fe-200d-2642-fe0f", native: "\u{1F9DC}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9dc-1f3ff-200d-2642-fe0f", native: "\u{1F9DC}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 5 }, mermaid: { id: "mermaid", name: "Mermaid", keywords: ["woman", "female", "merwoman", "ariel"], skins: [{ unified: "1f9dc-200d-2640-fe0f", native: "\u{1F9DC}\u200D\u2640\uFE0F" }, { unified: "1f9dc-1f3fb-200d-2640-fe0f", native: "\u{1F9DC}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9dc-1f3fc-200d-2640-fe0f", native: "\u{1F9DC}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9dc-1f3fd-200d-2640-fe0f", native: "\u{1F9DC}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9dc-1f3fe-200d-2640-fe0f", native: "\u{1F9DC}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9dc-1f3ff-200d-2640-fe0f", native: "\u{1F9DC}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 5 }, elf: { id: "elf", name: "Elf", keywords: ["magical"], skins: [{ unified: "1f9dd", native: "\u{1F9DD}" }, { unified: "1f9dd-1f3fb", native: "\u{1F9DD}\u{1F3FB}" }, { unified: "1f9dd-1f3fc", native: "\u{1F9DD}\u{1F3FC}" }, { unified: "1f9dd-1f3fd", native: "\u{1F9DD}\u{1F3FD}" }, { unified: "1f9dd-1f3fe", native: "\u{1F9DD}\u{1F3FE}" }, { unified: "1f9dd-1f3ff", native: "\u{1F9DD}\u{1F3FF}" }], version: 5 }, male_elf: { id: "male_elf", name: "Man Elf", keywords: ["male"], skins: [{ unified: "1f9dd-200d-2642-fe0f", native: "\u{1F9DD}\u200D\u2642\uFE0F" }, { unified: "1f9dd-1f3fb-200d-2642-fe0f", native: "\u{1F9DD}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9dd-1f3fc-200d-2642-fe0f", native: "\u{1F9DD}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9dd-1f3fd-200d-2642-fe0f", native: "\u{1F9DD}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9dd-1f3fe-200d-2642-fe0f", native: "\u{1F9DD}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9dd-1f3ff-200d-2642-fe0f", native: "\u{1F9DD}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 5 }, female_elf: { id: "female_elf", name: "Woman Elf", keywords: ["female"], skins: [{ unified: "1f9dd-200d-2640-fe0f", native: "\u{1F9DD}\u200D\u2640\uFE0F" }, { unified: "1f9dd-1f3fb-200d-2640-fe0f", native: "\u{1F9DD}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9dd-1f3fc-200d-2640-fe0f", native: "\u{1F9DD}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9dd-1f3fd-200d-2640-fe0f", native: "\u{1F9DD}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9dd-1f3fe-200d-2640-fe0f", native: "\u{1F9DD}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9dd-1f3ff-200d-2640-fe0f", native: "\u{1F9DD}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 5 }, genie: { id: "genie", name: "Genie", keywords: ["magical", "wishes"], skins: [{ unified: "1f9de", native: "\u{1F9DE}" }], version: 5 }, male_genie: { id: "male_genie", name: "Man Genie", keywords: ["male"], skins: [{ unified: "1f9de-200d-2642-fe0f", native: "\u{1F9DE}\u200D\u2642\uFE0F" }], version: 5 }, female_genie: { id: "female_genie", name: "Woman Genie", keywords: ["female"], skins: [{ unified: "1f9de-200d-2640-fe0f", native: "\u{1F9DE}\u200D\u2640\uFE0F" }], version: 5 }, zombie: { id: "zombie", name: "Zombie", keywords: ["dead"], skins: [{ unified: "1f9df", native: "\u{1F9DF}" }], version: 5 }, male_zombie: { id: "male_zombie", name: "Man Zombie", keywords: ["male", "dracula", "undead", "walking", "dead"], skins: [{ unified: "1f9df-200d-2642-fe0f", native: "\u{1F9DF}\u200D\u2642\uFE0F" }], version: 5 }, female_zombie: { id: "female_zombie", name: "Woman Zombie", keywords: ["female", "undead", "walking", "dead"], skins: [{ unified: "1f9df-200d-2640-fe0f", native: "\u{1F9DF}\u200D\u2640\uFE0F" }], version: 5 }, troll: { id: "troll", name: "Troll", keywords: ["mystical", "monster"], skins: [{ unified: "1f9cc", native: "\u{1F9CC}" }], version: 14 }, massage: { id: "massage", name: "Face Massage", keywords: ["person", "getting", "relax"], skins: [{ unified: "1f486", native: "\u{1F486}" }, { unified: "1f486-1f3fb", native: "\u{1F486}\u{1F3FB}" }, { unified: "1f486-1f3fc", native: "\u{1F486}\u{1F3FC}" }, { unified: "1f486-1f3fd", native: "\u{1F486}\u{1F3FD}" }, { unified: "1f486-1f3fe", native: "\u{1F486}\u{1F3FE}" }, { unified: "1f486-1f3ff", native: "\u{1F486}\u{1F3FF}" }], version: 1 }, "man-getting-massage": { id: "man-getting-massage", name: "Man Getting Massage", keywords: ["getting-massage", "male", "boy", "head"], skins: [{ unified: "1f486-200d-2642-fe0f", native: "\u{1F486}\u200D\u2642\uFE0F" }, { unified: "1f486-1f3fb-200d-2642-fe0f", native: "\u{1F486}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f486-1f3fc-200d-2642-fe0f", native: "\u{1F486}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f486-1f3fd-200d-2642-fe0f", native: "\u{1F486}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f486-1f3fe-200d-2642-fe0f", native: "\u{1F486}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f486-1f3ff-200d-2642-fe0f", native: "\u{1F486}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-getting-massage": { id: "woman-getting-massage", name: "Woman Getting Massage", keywords: ["getting-massage", "female", "girl", "head"], skins: [{ unified: "1f486-200d-2640-fe0f", native: "\u{1F486}\u200D\u2640\uFE0F" }, { unified: "1f486-1f3fb-200d-2640-fe0f", native: "\u{1F486}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f486-1f3fc-200d-2640-fe0f", native: "\u{1F486}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f486-1f3fd-200d-2640-fe0f", native: "\u{1F486}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f486-1f3fe-200d-2640-fe0f", native: "\u{1F486}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f486-1f3ff-200d-2640-fe0f", native: "\u{1F486}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, haircut: { id: "haircut", name: "Haircut", keywords: ["person", "getting", "hairstyle"], skins: [{ unified: "1f487", native: "\u{1F487}" }, { unified: "1f487-1f3fb", native: "\u{1F487}\u{1F3FB}" }, { unified: "1f487-1f3fc", native: "\u{1F487}\u{1F3FC}" }, { unified: "1f487-1f3fd", native: "\u{1F487}\u{1F3FD}" }, { unified: "1f487-1f3fe", native: "\u{1F487}\u{1F3FE}" }, { unified: "1f487-1f3ff", native: "\u{1F487}\u{1F3FF}" }], version: 1 }, "man-getting-haircut": { id: "man-getting-haircut", name: "Man Getting Haircut", keywords: ["getting-haircut", "male", "boy"], skins: [{ unified: "1f487-200d-2642-fe0f", native: "\u{1F487}\u200D\u2642\uFE0F" }, { unified: "1f487-1f3fb-200d-2642-fe0f", native: "\u{1F487}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f487-1f3fc-200d-2642-fe0f", native: "\u{1F487}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f487-1f3fd-200d-2642-fe0f", native: "\u{1F487}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f487-1f3fe-200d-2642-fe0f", native: "\u{1F487}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f487-1f3ff-200d-2642-fe0f", native: "\u{1F487}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-getting-haircut": { id: "woman-getting-haircut", name: "Woman Getting Haircut", keywords: ["getting-haircut", "female", "girl"], skins: [{ unified: "1f487-200d-2640-fe0f", native: "\u{1F487}\u200D\u2640\uFE0F" }, { unified: "1f487-1f3fb-200d-2640-fe0f", native: "\u{1F487}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f487-1f3fc-200d-2640-fe0f", native: "\u{1F487}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f487-1f3fd-200d-2640-fe0f", native: "\u{1F487}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f487-1f3fe-200d-2640-fe0f", native: "\u{1F487}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f487-1f3ff-200d-2640-fe0f", native: "\u{1F487}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, walking: { id: "walking", name: "Pedestrian", keywords: ["walking", "person", "move"], skins: [{ unified: "1f6b6", native: "\u{1F6B6}" }, { unified: "1f6b6-1f3fb", native: "\u{1F6B6}\u{1F3FB}" }, { unified: "1f6b6-1f3fc", native: "\u{1F6B6}\u{1F3FC}" }, { unified: "1f6b6-1f3fd", native: "\u{1F6B6}\u{1F3FD}" }, { unified: "1f6b6-1f3fe", native: "\u{1F6B6}\u{1F3FE}" }, { unified: "1f6b6-1f3ff", native: "\u{1F6B6}\u{1F3FF}" }], version: 1 }, "man-walking": { id: "man-walking", name: "Man Walking", keywords: ["human", "feet", "steps"], skins: [{ unified: "1f6b6-200d-2642-fe0f", native: "\u{1F6B6}\u200D\u2642\uFE0F" }, { unified: "1f6b6-1f3fb-200d-2642-fe0f", native: "\u{1F6B6}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f6b6-1f3fc-200d-2642-fe0f", native: "\u{1F6B6}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f6b6-1f3fd-200d-2642-fe0f", native: "\u{1F6B6}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f6b6-1f3fe-200d-2642-fe0f", native: "\u{1F6B6}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f6b6-1f3ff-200d-2642-fe0f", native: "\u{1F6B6}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-walking": { id: "woman-walking", name: "Woman Walking", keywords: ["human", "feet", "steps", "female"], skins: [{ unified: "1f6b6-200d-2640-fe0f", native: "\u{1F6B6}\u200D\u2640\uFE0F" }, { unified: "1f6b6-1f3fb-200d-2640-fe0f", native: "\u{1F6B6}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f6b6-1f3fc-200d-2640-fe0f", native: "\u{1F6B6}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f6b6-1f3fd-200d-2640-fe0f", native: "\u{1F6B6}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f6b6-1f3fe-200d-2640-fe0f", native: "\u{1F6B6}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f6b6-1f3ff-200d-2640-fe0f", native: "\u{1F6B6}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, person_walking_facing_right: { id: "person_walking_facing_right", name: "Person Walking Facing Right", keywords: ["peerson", "exercise"], skins: [{ unified: "1f6b6-200d-27a1-fe0f", native: "\u{1F6B6}\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fb-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FB}\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fc-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FC}\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fd-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FD}\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fe-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FE}\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3ff-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FF}\u200D\u27A1\uFE0F" }], version: 15.1 }, woman_walking_facing_right: { id: "woman_walking_facing_right", name: "Woman Walking Facing Right", keywords: ["person", "exercise"], skins: [{ unified: "1f6b6-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fb-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FB}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fc-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FC}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fd-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FD}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fe-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FE}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3ff-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FF}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }], version: 15.1 }, man_walking_facing_right: { id: "man_walking_facing_right", name: "Man Walking Facing Right", keywords: ["person", "exercise"], skins: [{ unified: "1f6b6-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fb-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FB}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fc-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FC}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fd-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FD}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3fe-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FE}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f6b6-1f3ff-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F6B6}\u{1F3FF}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }], version: 15.1 }, standing_person: { id: "standing_person", name: "Standing Person", keywords: ["still"], skins: [{ unified: "1f9cd", native: "\u{1F9C
51763D}" }, { unified: "1f9cd-1f3fb", native: "\u{1F9CD}\u{1F3FB}" }, { unified: "1f9cd-1f3fc", native: "\u{1F9CD}\u{1F3FC}" }, { unified: "1f9cd-1f3fd", native: "\u{1F9CD}\u{1F3FD}" }, { unified: "1f9cd-1f3fe", native: "\u{1F9CD}\u{1F3FE}" }, { unified: "1f9cd-1f3ff", native: "\u{1F9CD}\u{1F3FF}" }], version: 12 }, man_standing: { id: "man_standing", name: "Man Standing", keywords: ["still"], skins: [{ unified: "1f9cd-200d-2642-fe0f", native: "\u{1F9CD}\u200D\u2642\uFE0F" }, { unified: "1f9cd-1f3fb-200d-2642-fe0f", native: "\u{1F9CD}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9cd-1f3fc-200d-2642-fe0f", native: "\u{1F9CD}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9cd-1f3fd-200d-2642-fe0f", native: "\u{1F9CD}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9cd-1f3fe-200d-2642-fe0f", native: "\u{1F9CD}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9cd-1f3ff-200d-2642-fe0f", native: "\u{1F9CD}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 12 }, woman_standing: { id: "woman_standing", name: "Woman Standing", keywords: ["still"], skins: [{ unified: "1f9cd-200d-2640-fe0f", native: "\u{1F9CD}\u200D\u2640\uFE0F" }, { unified: "1f9cd-1f3fb-200d-2640-fe0f", native: "\u{1F9CD}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9cd-1f3fc-200d-2640-fe0f", native: "\u{1F9CD}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9cd-1f3fd-200d-2640-fe0f", native: "\u{1F9CD}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9cd-1f3fe-200d-2640-fe0f", native: "\u{1F9CD}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9cd-1f3ff-200d-2640-fe0f", native: "\u{1F9CD}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 12 }, kneeling_person: { id: "kneeling_person", name: "Kneeling Person", keywords: ["pray", "respectful"], skins: [{ unified: "1f9ce", native: "\u{1F9CE}" }, { unified: "1f9ce-1f3fb", native: "\u{1F9CE}\u{1F3FB}" }, { unified: "1f9ce-1f3fc", native: "\u{1F9CE}\u{1F3FC}" }, { unified: "1f9ce-1f3fd", native: "\u{1F9CE}\u{1F3FD}" }, { unified: "1f9ce-1f3fe", native: "\u{1F9CE}\u{1F3FE}" }, { unified: "1f9ce-1f3ff", native: "\u{1F9CE}\u{1F3FF}" }], version: 12 }, man_kneeling: { id: "man_kneeling", name: "Man Kneeling", keywords: ["pray", "respectful"], skins: [{ unified: "1f9ce-200d-2642-fe0f", native: "\u{1F9CE}\u200D\u2642\uFE0F" }, { unified: "1f9ce-1f3fb-200d-2642-fe0f", native: "\u{1F9CE}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9ce-1f3fc-200d-2642-fe0f", native: "\u{1F9CE}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9ce-1f3fd-200d-2642-fe0f", native: "\u{1F9CE}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9ce-1f3fe-200d-2642-fe0f", native: "\u{1F9CE}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9ce-1f3ff-200d-2642-fe0f", native: "\u{1F9CE}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 12 }, woman_kneeling: { id: "woman_kneeling", name: "Woman Kneeling", keywords: ["respectful", "pray"], skins: [{ unified: "1f9ce-200d-2640-fe0f", native: "\u{1F9CE}\u200D\u2640\uFE0F" }, { unified: "1f9ce-1f3fb-200d-2640-fe0f", native: "\u{1F9CE}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9ce-1f3fc-200d-2640-fe0f", native: "\u{1F9CE}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9ce-1f3fd-200d-2640-fe0f", native: "\u{1F9CE}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9ce-1f3fe-200d-2640-fe0f", native: "\u{1F9CE}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9ce-1f3ff-200d-2640-fe0f", native: "\u{1F9CE}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 12 }, person_kneeling_facing_right: { id: "person_kneeling_facing_right", name: "Person Kneeling Facing Right", keywords: ["pray"], skins: [{ unified: "1f9ce-200d-27a1-fe0f", native: "\u{1F9CE}\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fb-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FB}\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fc-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FC}\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fd-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FD}\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fe-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FE}\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3ff-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FF}\u200D\u27A1\uFE0F" }], version: 15.1 }, woman_kneeling_facing_right: { id: "woman_kneeling_facing_right", name: "Woman Kneeling Facing Right", keywords: ["pray", "worship"], skins: [{ unified: "1f9ce-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fb-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FB}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fc-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FC}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fd-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FD}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fe-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FE}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3ff-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FF}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }], version: 15.1 }, man_kneeling_facing_right: { id: "man_kneeling_facing_right", name: "Man Kneeling Facing Right", keywords: ["pray", "worship"], skins: [{ unified: "1f9ce-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fb-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FB}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fc-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FC}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fd-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FD}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3fe-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FE}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f9ce-1f3ff-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F9CE}\u{1F3FF}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }], version: 15.1 }, person_with_probing_cane: { id: "person_with_probing_cane", name: "Person with White Cane", keywords: ["probing", "blind"], skins: [{ unified: "1f9d1-200d-1f9af", native: "\u{1F9D1}\u200D\u{1F9AF}" }, { unified: "1f9d1-1f3fb-200d-1f9af", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F9AF}" }, { unified: "1f9d1-1f3fc-200d-1f9af", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F9AF}" }, { unified: "1f9d1-1f3fd-200d-1f9af", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F9AF}" }, { unified: "1f9d1-1f3fe-200d-1f9af", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F9AF}" }, { unified: "1f9d1-1f3ff-200d-1f9af", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F9AF}" }], version: 12.1 }
51763, person_with_white_cane_facing_right: { id: "person_with_white_cane_facing_right", name: "Person with White Cane Facing Right", keywords: ["walk", "visually", "impaired", "blind"], skins: [{ unified: "1f9d1-200d-1f9af-200d-27a1-fe0f", native: "\u{1F9D1}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fb-200d-1f9af-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fc-200d-1f9af-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fd-200d-1f9af-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fe-200d-1f9af-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3ff-200d-1f9af-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }], version: 15.1 }, man_with_probing_cane: { id: "man_with_probing_cane", name: "Man with White Cane", keywords: ["probing", "blind"], skins: [{ unified: "1f468-200d-1f9af", native: "\u{1F468}\u200D\u{1F9AF}" }, { unified: "1f468-1f3fb-200d-1f9af", native: "\u{1F468}\u{1F3FB}\u200D\u{1F9AF}" }, { unified: "1f468-1f3fc-200d-1f9af", native: "\u{1F468}\u{1F3FC}\u200D\u{1F9AF}" }, { unified: "1f468-1f3fd-200d-1f9af", native: "\u{1F468}\u{1F3FD}\u200D\u{1F9AF}" }, { unified: "1f468-1f3fe-200d-1f9af", native: "\u{1F468}\u{1F3FE}\u200D\u{1F9AF}" }, { unified: "1f468-1f3ff-200d-1f9af", native: "\u{1F468}\u{1F3FF}\u200D\u{1F9AF}" }], version: 12 }, man_with_white_cane_facing_right: { id: "man_with_white_cane_facing_right", name: "Man with White Cane Facing Right", keywords: ["visually", "impaired", "blind", "walk", "stick"], skins: [{ unified: "1f468-200d-1f9af-200d-27a1-fe0f", native: "\u{1F468}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fb-200d-1f9af-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FB}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fc-200d-1f9af-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FC}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fd-200d-1f9af-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FD}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fe-200d-1f9af-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FE}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3ff-200d-1f9af-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FF}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }], version: 15.1 }, woman_with_probing_cane: { id: "woman_with_probing_cane", name: "Woman with White Cane", keywords: ["probing", "blind"], skins: [{ unified: "1f469-200d-1f9af", native: "\u{1F469}\u200D\u{1F9AF}" }, { unified: "1f469-1f3fb-200d-1f9af", native: "\u{1F469}\u{1F3FB}\u200D\u{1F9AF}" }, { unified: "1f469-1f3fc-200d-1f9af", native: "\u{1F469}\u{1F3FC}\u200D\u{1F9AF}" }, { unified: "1f469-1f3fd-200d-1f9af", native: "\u{1F469}\u{1F3FD}\u200D\u{1F9AF}" }, { unified: "1f469-1f3fe-200d-1f9af", native: "\u{1F469}\u{1F3FE}\u200D\u{1F9AF}" }, { unified: "1f469-1f3ff-200d-1f9af", native: "\u{1F469}\u{1F3FF}\u200D\u{1F9AF}" }], version: 12 }, woman_with_white_cane_facing_right: { id: "woman_with_white_cane_facing_right", name: "Woman with White Cane Facing Right", keywords: ["stick", "visually", "impaired", "blind"], skins: [{ unified: "1f469-200d-1f9af-200d-27a1-fe0f", native: "\u{1F469}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fb-200d-1f9af-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FB}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fc-200d-1f9af-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FC}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fd-200d-1f9af-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FD}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fe-200d-1f9af-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FE}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3ff-200d-1f9af-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FF}\u200D\u{1F9AF}\u200D\u27A1\uFE0F" }], version: 15.1 }, person_in_motorized_wheelchair: { id: "person_in_motorized_wheelchair", name: "Person in Motorized Wheelchair", keywords: ["disability", "accessibility"], skins: [{ unified: "1f9d1-200d-1f9bc", native: "\u{1F9D1}\u200D\u{1F9BC}" }, { unified: "1f9d1-1f3fb-200d-1f9bc", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F9BC}" }, { unified: "1f9d1-1f3fc-200d-1f9bc", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F9BC}" }, { unified: "1f9d1-1f3fd-200d-1f9bc", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F9BC}" }, { unified: "1f9d1-1f3fe-200d-1f9bc", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F9BC}" }, { unified: "1f9d1-1f3ff-200d-1f9bc", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F9BC}" }], version: 12.1 }, person_in_motorized_wheelchair_facing_right: { id: "person_in_motorized_wheelchair_facing_right", name: "Person in Motorized Wheelchair Facing Right", keywords: ["accessibility", "disability"], skins: [{ unified: "1f9d1-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F9D1}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fb-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fc-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fd-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fe-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3ff-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }], version: 15.1 }, man_in_motorized_wheelchair: { id: "man_in_motorized_wheelchair", name: "Man in Motorized Wheelchair", keywords: ["disability", "accessibility"], skins: [{ unified: "1f468-200d-1f9bc", native: "\u{1F468}\u200D\u{1F9BC}" }, { unified: "1f468-1f3fb-200d-1f9bc", native: "\u{1F468}\u{1F3FB}\u200D\u{1F9BC}" }, { unified: "1f468-1f3fc-200d-1f9bc", native: "\u{1F468}\u{1F3FC}\u200D\u{1F9BC}" }, { unified: "1f468-1f3fd-200d-1f9bc", native: "\u{1F468}\u{1F3FD}\u200D\u{1F9BC}" }, { unified: "1f468-1f3fe-200d-1f9bc", native: "\u{1F468}\u{1F3FE}\u200D\u{1F9BC}" }, { unified: "1f468-1f3ff-200d-1f9bc", native: "\u{1F468}\u{1F3FF}\u200D\u{1F9BC}" }], version: 12 }, man_in_motorized_wheelchair_facing_right: { id: "man_in_motorized_wheelchair_facing_right", name: "Man in Motorized Wheelchair Facing Right", keywords: ["disability", "accessibility", "mobility"], skins: [{ unified: "1f468-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F468}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fb-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FB}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fc-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FC}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fd-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FD}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fe-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FE}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3ff-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FF}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }], version: 15.1 }, woman_in_motorized_wheelchair: { id: "woman_in_motorized_wheelchair", name: "Woman in Motorized Wheelchair", keywords: ["disability", "accessibility"], skins: [{ unified: "1f469-200d-1f9bc", native: "\u{1F469}\u200D\u{1F9BC}" }, { unified: "1f469-1f3fb-200d-1f9bc", native: "\u{1F469}\u{1F3FB}\u200D\u{1F9BC}" }, { unified: "1f469-1f3fc-200d-1f9bc", native: "\u{1F469}\u{1F3FC}\u200D\u{1F9BC}" }, { unified: "1f469-1f3fd-200d-1f9bc", native: "\u{1F469}\u{1F3FD}\u200D\u{1F9BC}" }, { unified: "1f469-1f3fe-200d-1f9bc", native: "\u{1F469}\u{1F3FE}\u200D\u{1F9BC}" }, { unified: "1f469-1f3ff-200d-1f9bc", native: "\u{1F469}\u{1F3FF}\u200D\u{1F9BC}" }], version: 12 }, woman_in_motorized_wheelchair_facing_right: { id: "woman_in_motorized_wheelchair_facing_right", name: "Woman in Motorized Wheelchair Facing Right", keywords: ["mobility", "accessibility", "disability"], skins: [{ unified: "1f469-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F469}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fb-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FB}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fc-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FC}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fd-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FD}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fe-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FE}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3ff-200d-1f9bc-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FF}\u200D\u{1F9BC}\u200D\u27A1\uFE0F" }], version: 15.1 }, person_in_manual_wheelchair: { id: "person_in_manual_wheelchair", name: "Person in Manual Wheelchair", keywords: ["disability", "accessibility"], skins: [{ unified: "1f9d1-200d-1f9bd", native: "\u{1F9D1}\u200D\u{1F9BD}" }, { unified: "1f9d1-1f3fb-200d-1f9bd", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F9BD}" }, { unified: "1f9d1-1f3fc-200d-1f9bd", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F9BD}" }, { unified: "1f9d1-1f3fd-200d-1f9bd", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F9BD}" }, { unified: "1f9d1-1f3fe-200d-1f9bd", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F9BD}" }, { unified: "1f9d1-1f3ff-200d-1f9bd", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F9BD}" }], version: 12.1 }, person_in_manual_wheelchair_facing_right: { id: "person_in_manual_wheelchair_facing_right", name: "Person in Manual Wheelchair Facing Right", keywords: ["mobility", "accessibility", "disability"], skins: [{ unified: "1f9d1-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F9D1}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fb-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fc-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fd-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3fe-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f9d1-1f3ff-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }], version: 15.1 }, man_in_manual_wheelchair: { id: "man_in_manual_wheelchair", name: "Man in Manual Wheelchair", keywords: ["disability", "accessibility"], skins: [{ unified: "1f468-200d-1f9bd", native: "\u{1F468}\u200D\u{1F9BD}" }, { unified: "1f468-1f3fb-200d-1f9bd", native: "\u{1F468}\u{1F3FB}\u200D\u{1F9BD}" }, { unified: "1f468-1f3fc-200d-1f9bd", native: "\u{1F468}\u{1F3FC}\u200D\u{1F9BD}" }, { unified: "1f468-1f3fd-200d-1f9bd", native: "\u{1F468}\u{1F3FD}\u200D\u{1F9BD}" }, { unified: "1f468-1f3fe-200d-1f9bd", native: "\u{1F468}\u{1F3FE}\u200D\u{1F9BD}" }, { unified: "1f468-1f3ff-200d-1f9bd", native: "\u{1F468}\u{1F3FF}\u200D\u{1F9BD}" }], version: 12 }, man_in_manual_wheelchair_facing_right: { id: "man_in_manual_wheelchair_facing_right", name: "Man in Manual Wheelchair Facing Right", keywords: ["mobility", "accessibility", "disability"], skins: [{ unified: "1f468-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F468}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fb-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FB}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fc-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FC}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fd-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FD}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3fe-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FE}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f468-1f3ff-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F468}\u{1F3FF}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }], version: 15.1 }, woman_in_manual_wheelchair: { id: "woman_in_manual_wheelchair", name: "Woman in Manual Wheelchair", keywords: ["disability", "accessibility"], skins: [{ unified: "1f469-200d-1f9bd", native: "\u{1F469}\u200D\u{1F9BD}" }, { unified: "1f469-1f3fb-200d-1f9bd", native: "\u{1F469}\u{1F3FB}\u200D\u{1F9BD}" }, { unified: "1f469-1f3fc-200d-1f9bd", native: "\u{1F469}\u{1F3FC}\u200D\u{1F9BD}" }, { unified: "1f469-1f3fd-200d-1f9bd", native: "\u{1F469}\u{1F3FD}\u200D\u{1F9BD}" }, { unified: "1f469-1f3fe-200d-1f9bd", native: "\u{1F469}\u{1F3FE}\u200D\u{1F9BD}" }, { unified: "1f469-1f3ff-200d-1f9bd", native: "\u{1F469}\u{1F3FF}\u200D\u{1F9BD}" }], version: 12 }, woman_in_manual_wheelchair_facing_right: { id: "woman_in_manual_wheelchair_facing_right", name: "Woman in Manual Wheelchair Facing Right", keywords: ["disability", "mobility", "accessibility"], skins: [{ unified: "1f469-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F469}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fb-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FB}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fc-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FC}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fd-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FD}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3fe-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FE}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }, { unified: "1f469-1f3ff-200d-1f9bd-200d-27a1-fe0f", native: "\u{1F469}\u{1F3FF}\u200D\u{1F9BD}\u200D\u27A1\uFE0F" }], version: 15.1 }, runner: { id: "runner", name: "Runner", keywords: ["running", "person", "move"], skins: [{ unified: "1f3c3", native: "\u{1F3C3}" }, { unified: "1f3c3-1f3fb", native: "\u{1F3C3}\u{1F3FB}" }, { unified: "1f3c3-1f3fc", native: "\u{1F3C3}\u{1F3FC}" }, { unified: "1f3c3-1f3fd", native: "\u{1F3C3}\u{1F3FD}" }, { unified: "1f3c3-1f3fe", native: "\u{1F3C3}\u{1F3FE}" }, { unified: "1f3c3-1f3ff", native: "\u{1F3C3}\u{1F3FF}" }], version: 1 }, "man-running": { id: "man-running", name: "Man Running", keywords: ["walking", "exercise", "race"], skins: [{ unified: "1f3c3-200d-2642-fe0f", native: "\u{1F3C3}\u200D\u2642\uFE0F" }, { unified: "1f3c3-1f3fb-200d-2642-fe0f", native: "\u{1F3C3}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f3c3-1f3fc-200d-2642-fe0f", native: "\u{1F3C3}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f3c3-1f3fd-200d-2642-fe0f", native: "\u{1F3C3}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f3c3-1f3fe-200d-2642-fe0f", native: "\u{1F3C3}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f3c3-1f3ff-200d-2642-fe0f", native: "\u{1F3C3}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-running": { id: "woman-running", name: "Woman Running", keywords: ["walking", "exercise", "race", "female"], skins: [{ unified: "1f3c3-200d-2640-fe0f", native: "\u{1F3C3}\u200D\u2640\uFE0F" }, { unified: "1f3c3-1f3fb-200d-2640-fe0f", native: "\u{1F3C3}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f3c3-1f3fc-200d-2640-fe0f", native: "\u{1F3C3}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f3c3-1f3fd-200d-2640-fe0f", native: "\u{1F3C3}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f3c3-1f3fe-200d-2640-fe0f", native: "\u{1F3C3}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f3c3-1f3ff-200d-2640-fe0f", native: "\u{1F3C3}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, person_running_facing_right: { id: "person_running_facing_right", name: "Person Running Facing Right", keywords: ["exercise", "jog"], skins: [{ unified: "1f3c3-200d-27a1-fe0f", native: "\u{1F3C3}\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fb-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FB}\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fc-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FC}\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fd-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FD}\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fe-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FE}\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3ff-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FF}\u200D\u27A1\uFE0F" }], version: 15.1 }, woman_running_facing_right: { id: "woman_running_facing_right", name: "Woman Running Facing Right", keywords: ["exercise", "jog"], skins: [{ unified: "1f3c3-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fb-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FB}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fc-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FC}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fd-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FD}
51763\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fe-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FE}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3ff-200d-2640-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FF}\u200D\u2640\uFE0F\u200D\u27A1\uFE0F" }], version: 15.1 }, man_running_facing_right: { id: "man_running_facing_right", name: "Man Running Facing Right", keywords: ["jog", "exercise"], skins: [{ unified: "1f3c3-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fb-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FB}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fc-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FC}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fd-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FD}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3fe-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FE}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }, { unified: "1f3c3-1f3ff-200d-2642-fe0f-200d-27a1-fe0f", native: "\u{1F3C3}\u{1F3FF}\u200D\u2642\uFE0F\u200D\u27A1\uFE0F" }], version: 15.1 }, dancer: { id: "dancer", name: "Dancer", keywords: ["woman", "dancing", "female", "girl", "fun"], skins: [{ unified: "1f483", native: "\u{1F483}" }, { unified: "1f483-1f3fb", native: "\u{1F483}\u{1F3FB}" }, { unified: "1f483-1f3fc", native: "\u{1F483}\u{1F3FC}" }, { unified: "1f483-1f3fd", native: "\u{1F483}\u{1F3FD}" }, { unified: "1f483-1f3fe", native: "\u{1F483}\u{1F3FE}" }, { unified: "1f483-1f3ff", native: "\u{1F483}\u{1F3FF}" }], version: 1 }, man_dancing: { id: "man_dancing", name: "Man Dancing", keywords: ["male", "boy", "fun", "dancer"], skins: [{ unified: "1f57a", native: "\u{1F57A}" }, { unified: "1f57a-1f3fb", native: "\u{1F57A}\u{1F3FB}" }, { unified: "1f57a-1f3fc", native: "\u{1F57A}\u{1F3FC}" }, { unified: "1f57a-1f3fd", native: "\u{1F57A}\u{1F3FD}" }, { unified: "1f57a-1f3fe", native: "\u{1F57A}\u{1F3FE}" }, { unified: "1f57a-1f3ff", native: "\u{1F57A}\u{1F3FF}" }], version: 3 }, man_in_business_suit_levitating: { id: "man_in_business_suit_levitating", name: "Person in Suit Levitating", keywords: ["man", "business", "levitate", "hover", "jump"], skins: [{ unified: "1f574-fe0f", native: "\u{1F574}\uFE0F" }, { unified: "1f574-1f3fb", native: "\u{1F574}\u{1F3FB}" }, { unified: "1f574-1f3fc", native: "\u{1F574}\u{1F3FC}" }, { unified: "1f574-1f3fd", native: "\u{1F574}\u{1F3FD}" }, { unified: "1f574-1f3fe", native: "\u{1F574}\u{1F3FE}" }, { unified: "1f574-1f3ff", native: "\u{1F574}\u{1F3FF}" }], version: 1 }, dancers: { id: "dancers", name: "Woman with Bunny Ears", keywords: ["dancers", "people", "perform", "costume"], skins: [{ unified: "1f46f", native: "\u{1F46F}" }], version: 1 }, "men-with-bunny-ears-partying": { id: "men-with-bunny-ears-partying", name: "Men with Bunny Ears", keywords: ["with-bunny-ears-partying", "man", "male", "boys"], skins: [{ unified: "1f46f-200d-2642-fe0f", native: "\u{1F46F}\u200D\u2642\uFE0F" }], version: 4 }, "women-with-bunny-ears-partying": { id: "women-with-bunny-ears-partying", name: "Women with Bunny Ears", keywords: ["with-bunny-ears-partying", "woman", "female", "girls"], skins: [{ unified: "1f46f-200d-2640-fe0f", native: "\u{1F46F}\u200D\u2640\uFE0F" }], version: 4 }, person_in_steamy_room: { id: "person_in_steamy_room", name: "Person in Steamy Room", keywords: ["relax", "spa"], skins: [{ unified: "1f9d6", native: "\u{1F9D6}" }, { unified: "1f9d6-1f3fb", native: "\u{1F9D6}\u{1F3FB}" }, { unified: "1f9d6-1f3fc", native: "\u{1F9D6}\u{1F3FC}" }, { unified: "1f9d6-1f3fd", native: "\u{1F9D6}\u{1F3FD}" }, { unified: "1f9d6-1f3fe", native: "\u{1F9D6}\u{1F3FE}" }, { unified: "1f9d6-1f3ff", native: "\u{1F9D6}\u{1F3FF}" }], version: 5 }, man_in_steamy_room: { id: "man_in_steamy_room", name: "Man in Steamy Room", keywords: ["male", "spa", "steamroom", "sauna"], skins: [{ unified: "1f9d6-200d-2642-fe0f", native: "\u{1F9D6}\u200D\u2642\uFE0F" }, { unified: "1f9d6-1f3fb-200d-2642-fe0f", native: "\u{1F9D6}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9d6-1f3fc-200d-2642-fe0f", native: "\u{1F9D6}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9d6-1f3fd-200d-2642-fe0f", native: "\u{1F9D6}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9d6-1f3fe-200d-2642-fe0f", native: "\u{1F9D6}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9d6-1f3ff-200d-2642-fe0f", native: "\u{1F9D6}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 5 }, woman_in_steamy_room: { id: "woman_in_steamy_room", name: "Woman in Steamy Room", keywords: ["female", "spa", "steamroom", "sauna"], skins: [{ unified: "1f9d6-200d-2640-fe0f", native: "\u{1F9D6}\u200D\u2640\uFE0F" }, { unified: "1f9d6-1f3fb-200d-2640-fe0f", native: "\u{1F9D6}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9d6-1f3fc-200d-2640-fe0f", native: "\u{1F9D6}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9d6-1f3fd-200d-2640-fe0f", native: "\u{1F9D6}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9d6-1f3fe-200d-2640-fe0f", native: "\u{1F9D6}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9d6-1f3ff-200d-2640-fe0f", native: "\u{1F9D6}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 5 }, person_climbing: { id: "person_climbing", name: "Person Climbing", keywords: ["sport"], skins: [{ unified: "1f9d7", native: "\u{1F9D7}" }, { unified: "1f9d7-1f3fb", native: "\u{1F9D7}\u{1F3FB}" }, { unified: "1f9d7-1f3fc", native: "\u{1F9D7}\u{1F3FC}" }, { unified: "1f9d7-1f3fd", native: "\u{1F9D7}\u{1F3FD}" }, { unified: "1f9d7-1f3fe", native: "\u{1F9D7}\u{1F3FE}" }, { unified: "1f9d7-1f3ff", native: "\u{1F9D7}\u{1F3FF}" }], version: 5 }, man_climbing: { id: "man_climbing", name: "Man Climbing", keywords: ["sports", "hobby", "male", "rock"], skins: [{ unified: "1f9d7-200d-2642-fe0f", native: "\u{1F9D7}\u200D\u2642\uFE0F" }, { unified: "1f9d7-1f3fb-200d-2642-fe0f", native: "\u{1F9D7}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9d7-1f3fc-200d-2642-fe0f", native: "\u{1F9D7}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9d7-1f3fd-200d-2642-fe0f", native: "\u{1F9D7}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9d7-1f3fe-200d-2642-fe0f", native: "\u{1F9D7}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9d7-1f3ff-200d-2642-fe0f", native: "\u{1F9D7}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 5 }, woman_climbing: { id: "woman_climbing", name: "Woman Climbing", keywords: ["sports", "hobby", "female", "rock"], skins: [{ unified: "1f9d7-200d-2640-fe0f", native: "\u{1F9D7}\u200D\u2640\uFE0F" }, { unified: "1f9d7-1f3fb-200d-2640-fe0f", native: "\u{1F9D7}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9d7-1f3fc-200d-2640-fe0f", native: "\u{1F9D7}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9d7-1f3fd-200d-2640-fe0f", native: "\u{1F9D7}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9d7-1f3fe-200d-2640-fe0f", native: "\u{1F9D7}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9d7-1f3ff-200d-2640-fe0f", native: "\u{1F9D7}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 5 }, fencer: { id: "fencer", name: "Fencer", keywords: ["person", "fencing", "sports", "sword"], skins: [{ unified: "1f93a", native: "\u{1F93A}" }], version: 3 }, horse_racing: { id: "horse_racing", name: "Horse Racing", keywords: ["animal", "betting", "competition", "gambling", "luck"], skins: [{ unified: "1f3c7", native: "\u{1F3C7}" }, { unified: "1f3c7-1f3fb", native: "\u{1F3C7}\u{1F3FB}" }, { unified: "1f3c7-1f3fc", native: "\u{1F3C7}\u{1F3FC}" }, { unified: "1f3c7-1f3fd", native: "\u{1F3C7}\u{1F3FD}" }, { unified: "1f3c7-1f3fe", native: "\u{1F3C7}\u{1F3FE}" }, { unified: "1f3c7-1f3ff", native: "\u{1F3C7}\u{1F3FF}" }], version: 1 }, skier: { id: "skier", name: "Skier", keywords: ["sports", "winter", "snow"], skins: [{ unified: "26f7-fe0f", native: "\u26F7\uFE0F" }], version: 1 }, snowboarder: { id: "snowboarder", name: "Snowboarder", keywords: ["sports", "winter"], skins: [{ unified: "1f3c2", native: "\u{1F3C2}" }, { unified: "1f3c2-1f3fb", native: "\u{1F3C2}\u{1F3FB}" }, { unified: "1f3c2-1f3fc", native: "\u{1F3C2}\u{1F3FC}" }, { unified: "1f3c2-1f3fd", native: "\u{1F3C2}\u{1F3FD}" }, { unified: "1f3c2-1f3fe", native: "\u{1F3C2}\u{1F3FE}" }, { unified: "1f3c2-1f3ff", native: "\u{1F3C2}\u{1F3FF}" }], version: 1 }, golfer: { id: "golfer", name: "Person Golfing", keywords: ["golfer", "sports", "business"], skins: [{ unified: "1f3cc-fe0f", native: "\u{1F3CC}\uFE0F" }, { unified: "1f3cc-1f3fb", native: "\u{1F3CC}\u{1F3FB}" }, { unified: "1f3cc-1f3fc", native: "\u{1F3CC}\u{1F3FC}" }, { unified: "1f3cc-1f3fd", native: "\u{1F3CC}\u{1F3FD}" }, { unified: "1f3cc-1f3fe", native: "\u{1F3CC}\u{1F3FE}" }, { unified: "1f3cc-1f3ff", native: "\u{1F3CC}\u{1F3FF}" }], version: 1 }, "man-golfing": { id: "man-golfing", name: "Man Golfing", keywords: ["sport"], skins: [{ unified: "1f3cc-fe0f-200d-2642-fe0f", native: "\u{1F3CC}\uFE0F\u200D\u2642\uFE0F" }, { unified: "1f3cc-1f3fb-200d-2642-fe0f", native: "\u{1F3CC}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f3cc-1f3fc-200d-2642-fe0f", native: "\u{1F3CC}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f3cc-1f3fd-200d-2642-fe0f", native: "\u{1F3CC}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f3cc-1f3fe-200d-2642-fe0f", native: "\u{1F3CC}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f3cc-1f3ff-200d-2642-fe0f", native: "\u{1F3CC}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-golfing": { id: "woman-golfing", name: "Woman Golfing", keywords: ["sports", "business", "female"], skins: [{ unified: "1f3cc-fe0f-200d-2640-fe0f", native: "\u{1F3CC}\uFE0F\u200D\u2640\uFE0F" }, { unified: "1f3cc-1f3fb-200d-2640-fe0f", native: "\u{1F3CC}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f3cc-1f3fc-200d-2640-fe0f", native: "\u{1F3CC}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f3cc-1f3fd-200d-2640-fe0f", native: "\u{1F3CC}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f3cc-1f3fe-200d-2640-fe0f", native: "\u{1F3CC}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f3cc-1f3ff-200d-2640-fe0f", native: "\u{1F3CC}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, surfer: { id: "surfer", name: "Surfer", keywords: ["person", "surfing", "sport", "sea"], skins: [{ unified: "1f3c4", native: "\u{1F3C4}" }, { unified: "1f3c4-1f3fb", native: "\u{1F3C4}\u{1F3FB}" }, { unified: "1f3c4-1f3fc", native: "\u{1F3C4}\u{1F3FC}" }, { unified: "1f3c4-1f3fd", native: "\u{1F3C4}\u{1F3FD}" }, { unified: "1f3c4-1f3fe", native: "\u{1F3C4}\u{1F3FE}" }, { unified: "1f3c4-1f3ff", native: "\u{1F3C4}\u{1F3FF}" }], version: 1 }
51763, "man-surfing": { id: "man-surfing", name: "Man Surfing", keywords: ["sports", "ocean", "sea", "summer", "beach"], skins: [{ unified: "1f3c4-200d-2642-fe0f", native: "\u{1F3C4}\u200D\u2642\uFE0F" }, { unified: "1f3c4-1f3fb-200d-2642-fe0f", native: "\u{1F3C4}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f3c4-1f3fc-200d-2642-fe0f", native: "\u{1F3C4}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f3c4-1f3fd-200d-2642-fe0f", native: "\u{1F3C4}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f3c4-1f3fe-200d-2642-fe0f", native: "\u{1F3C4}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f3c4-1f3ff-200d-2642-fe0f", native: "\u{1F3C4}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-surfing": { id: "woman-surfing", name: "Woman Surfing", keywords: ["sports", "ocean", "sea", "summer", "beach", "female"], skins: [{ unified: "1f3c4-200d-2640-fe0f", native: "\u{1F3C4}\u200D\u2640\uFE0F" }, { unified: "1f3c4-1f3fb-200d-2640-fe0f", native: "\u{1F3C4}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f3c4-1f3fc-200d-2640-fe0f", native: "\u{1F3C4}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f3c4-1f3fd-200d-2640-fe0f", native: "\u{1F3C4}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f3c4-1f3fe-200d-2640-fe0f", native: "\u{1F3C4}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f3c4-1f3ff-200d-2640-fe0f", native: "\u{1F3C4}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, rowboat: { id: "rowboat", name: "Rowboat", keywords: ["person", "rowing", "boat", "sport", "move"], skins: [{ unified: "1f6a3", native: "\u{1F6A3}" }, { unified: "1f6a3-1f3fb", native: "\u{1F6A3}\u{1F3FB}" }, { unified: "1f6a3-1f3fc", native: "\u{1F6A3}\u{1F3FC}" }, { unified: "1f6a3-1f3fd", native: "\u{1F6A3}\u{1F3FD}" }, { unified: "1f6a3-1f3fe", native: "\u{1F6A3}\u{1F3FE}" }, { unified: "1f6a3-1f3ff", native: "\u{1F6A3}\u{1F3FF}" }], version: 1 }, "man-rowing-boat": { id: "man-rowing-boat", name: "Man Rowing Boat", keywords: ["rowing-boat", "sports", "hobby", "water", "ship"], skins: [{ unified: "1f6a3-200d-2642-fe0f", native: "\u{1F6A3}\u200D\u2642\uFE0F" }, { unified: "1f6a3-1f3fb-200d-2642-fe0f", native: "\u{1F6A3}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f6a3-1f3fc-200d-2642-fe0f", native: "\u{1F6A3}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f6a3-1f3fd-200d-2642-fe0f", native: "\u{1F6A3}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f6a3-1f3fe-200d-2642-fe0f", native: "\u{1F6A3}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f6a3-1f3ff-200d-2642-fe0f", native: "\u{1F6A3}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-rowing-boat": { id: "woman-rowing-boat", name: "Woman Rowing Boat", keywords: ["rowing-boat", "sports", "hobby", "water", "ship", "female"], skins: [{ unified: "1f6a3-200d-2640-fe0f", native: "\u{1F6A3}\u200D\u2640\uFE0F" }, { unified: "1f6a3-1f3fb-200d-2640-fe0f", native: "\u{1F6A3}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f6a3-1f3fc-200d-2640-fe0f", native: "\u{1F6A3}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f6a3-1f3fd-200d-2640-fe0f", native: "\u{1F6A3}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f6a3-1f3fe-200d-2640-fe0f", native: "\u{1F6A3}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f6a3-1f3ff-200d-2640-fe0f", native: "\u{1F6A3}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, swimmer: { id: "swimmer", name: "Swimmer", keywords: ["person", "swimming", "sport", "pool"], skins: [{ unified: "1f3ca", native: "\u{1F3CA}" }, { unified: "1f3ca-1f3fb", native: "\u{1F3CA}\u{1F3FB}" }, { unified: "1f3ca-1f3fc", native: "\u{1F3CA}\u{1F3FC}" }, { unified: "1f3ca-1f3fd", native: "\u{1F3CA}\u{1F3FD}" }, { unified: "1f3ca-1f3fe", native: "\u{1F3CA}\u{1F3FE}" }, { unified: "1f3ca-1f3ff", native: "\u{1F3CA}\u{1F3FF}" }], version: 1 }, "man-swimming": { id: "man-swimming", name: "Man Swimming", keywords: ["sports", "exercise", "human", "athlete", "water", "summer"], skins: [{ unified: "1f3ca-200d-2642-fe0f", native: "\u{1F3CA}\u200D\u2642\uFE0F" }, { unified: "1f3ca-1f3fb-200d-2642-fe0f", native: "\u{1F3CA}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f3ca-1f3fc-200d-2642-fe0f", native: "\u{1F3CA}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f3ca-1f3fd-200d-2642-fe0f", native: "\u{1F3CA}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f3ca-1f3fe-200d-2642-fe0f", native: "\u{1F3CA}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f3ca-1f3ff-200d-2642-fe0f", native: "\u{1F3CA}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-swimming": { id: "woman-swimming", name: "Woman Swimming", keywords: ["sports", "exercise", "human", "athlete", "water", "summer", "female"], skins: [{ unified: "1f3ca-200d-2640-fe0f", native: "\u{1F3CA}\u200D\u2640\uFE0F" }, { unified: "1f3ca-1f3fb-200d-2640-fe0f", native: "\u{1F3CA}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f3ca-1f3fc-200d-2640-fe0f", native: "\u{1F3CA}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f3ca-1f3fd-200d-2640-fe0f", native: "\u{1F3CA}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f3ca-1f3fe-200d-2640-fe0f", native: "\u{1F3CA}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f3ca-1f3ff-200d-2640-fe0f", native: "\u{1F3CA}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, person_with_ball: { id: "person_with_ball", name: "Person Bouncing Ball", keywords: ["with", "sports", "human"], skins: [{ unified: "26f9-fe0f", native: "\u26F9\uFE0F" }, { unified: "26f9-1f3fb", native: "\u26F9\u{1F3FB}" }, { unified: "26f9-1f3fc", native: "\u26F9\u{1F3FC}" }, { unified: "26f9-1f3fd", native: "\u26F9\u{1F3FD}" }, { unified: "26f9-1f3fe", native: "\u26F9\u{1F3FE}" }, { unified: "26f9-1f3ff", native: "\u26F9\u{1F3FF}" }], version: 1 }, "man-bouncing-ball": { id: "man-bouncing-ball", name: "Man Bouncing Ball", keywords: ["bouncing-ball", "sport"], skins: [{ unified: "26f9-fe0f-200d-2642-fe0f", native: "\u26F9\uFE0F\u200D\u2642\uFE0F" }, { unified: "26f9-1f3fb-200d-2642-fe0f", native: "\u26F9\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "26f9-1f3fc-200d-2642-fe0f", native: "\u26F9\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "26f9-1f3fd-200d-2642-fe0f", native: "\u26F9\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "26f9-1f3fe-200d-2642-fe0f", native: "\u26F9\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "26f9-1f3ff-200d-2642-fe0f", native: "\u26F9\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-bouncing-ball": { id: "woman-bouncing-ball", name: "Woman Bouncing Ball", keywords: ["bouncing-ball", "sports", "human", "female"], skins: [{ unified: "26f9-fe0f-200d-2640-fe0f", native: "\u26F9\uFE0F\u200D\u2640\uFE0F" }, { unified: "26f9-1f3fb-200d-2640-fe0f", native: "\u26F9\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "26f9-1f3fc-200d-2640-fe0f", native: "\u26F9\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "26f9-1f3fd-200d-2640-fe0f", native: "\u26F9\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "26f9-1f3fe-200d-2640-fe0f", native: "\u26F9\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "26f9-1f3ff-200d-2640-fe0f", native: "\u26F9\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, weight_lifter: { id: "weight_lifter", name: "Person Lifting Weights", keywords: ["weight", "lifter", "sports", "training", "exercise"], skins: [{ unified: "1f3cb-fe0f", native: "\u{1F3CB}\uFE0F" }, { unified: "1f3cb-1f3fb", native: "\u{1F3CB}\u{1F3FB}" }, { unified: "1f3cb-1f3fc", native: "\u{1F3CB}\u{1F3FC}" }, { unified: "1f3cb-1f3fd", native: "\u{1F3CB}\u{1F3FD}" }, { unified: "1f3cb-1f3fe", native: "\u{1F3CB}\u{1F3FE}" }, { unified: "1f3cb-1f3ff", native: "\u{1F3CB}\u{1F3FF}" }], version: 1 }, "man-lifting-weights": { id: "man-lifting-weights", name: "Man Lifting Weights", keywords: ["lifting-weights", "sport"], skins: [{ unified: "1f3cb-fe0f-200d-2642-fe0f", native: "\u{1F3CB}\uFE0F\u200D\u2642\uFE0F" }, { unified: "1f3cb-1f3fb-200d-2642-fe0f", native: "\u{1F3CB}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f3cb-1f3fc-200d-2642-fe0f", native: "\u{1F3CB}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f3cb-1f3fd-200d-2642-fe0f", native: "\u{1F3CB}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f3cb-1f3fe-200d-2642-fe0f", native: "\u{1F3CB}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f3cb-1f3ff-200d-2642-fe0f", native: "\u{1F3CB}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-lifting-weights": { id: "woman-lifting-weights", name: "Woman Lifting Weights", keywords: ["lifting-weights", "sports", "training", "exercise", "female"], skins: [{ unified: "1f3cb-fe0f-200d-2640-fe0f", native: "\u{1F3CB}\uFE0F\u200D\u2640\uFE0F" }, { unified: "1f3cb-1f3fb-200d-2640-fe0f", native: "\u{1F3CB}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f3cb-1f3fc-200d-2640-fe0f", native: "\u{1F3CB}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f3cb-1f3fd-200d-2640-fe0f", native: "\u{1F3CB}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f3cb-1f3fe-200d-2640-fe0f", native: "\u{1F3CB}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f3cb-1f3ff-200d-2640-fe0f", native: "\u{1F3CB}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, bicyclist: { id: "bicyclist", name: "Bicyclist", keywords: ["person", "biking", "bicycle", "bike", "cyclist", "sport", "move"], skins: [{ unified: "1f6b4", native: "\u{1F6B4}" }, { unified: "1f6b4-1f3fb", native: "\u{1F6B4}\u{1F3FB}" }, { unified: "1f6b4-1f3fc", native: "\u{1F6B4}\u{1F3FC}" }, { unified: "1f6b4-1f3fd", native: "\u{1F6B4}\u{1F3FD}" }, { unified: "1f6b4-1f3fe", native: "\u{1F6B4}\u{1F3FE}" }, { unified: "1f6b4-1f3ff", native: "\u{1F6B4}\u{1F3FF}" }], version: 1 }, "man-biking": { id: "man-biking", name: "Man Biking", keywords: ["bicycle", "bike", "cyclist", "sports", "exercise", "hipster"], skins: [{ unified: "1f6b4-200d-2642-fe0f", native: "\u{1F6B4}\u200D\u2642\uFE0F" }, { unified: "1f6b4-1f3fb-200d-2642-fe0f", native: "\u{1F6B4}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f6b4-1f3fc-200d-2642-fe0f", native: "\u{1F6B4}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f6b4-1f3fd-200d-2642-fe0f", native: "\u{1F6B4}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f6b4-1f3fe-200d-2642-fe0f", native: "\u{1F6B4}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f6b4-1f3ff-200d-2642-fe0f", native: "\u{1F6B4}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-biking": { id: "woman-biking", name: "Woman Biking", keywords: ["bicycle", "bike", "cyclist", "sports", "exercise", "hipster", "female"], skins: [{ unified: "1f6b4-200d-2640-fe0f", native: "\u{1F6B4}\u200D\u2640\uFE0F" }, { unified: "1f6b4-1f3fb-200d-2640-fe0f", native: "\u{1F6B4}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f6b4-1f3fc-200d-2640-fe0f", native: "\u{1F6B4}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f6b4-1f3fd-200d-2640-fe0f", native: "\u{1F6B4}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f6b4-1f3fe-200d-2640-fe0f", native: "\u{1F6B4}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f6b4-1f3ff-200d-2640-fe0f", native: "\u{1F6B4}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, mountain_bicyclist: { id: "mountain_bicyclist", name: "Mountain Bicyclist", keywords: ["person", "biking", "bicycle", "bike", "cyclist", "sport", "move"], skins: [{ unified: "1f6b5", native: "\u{1F6B5}" }, { unified: "1f6b5-1f3fb", native: "\u{1F6B5}\u{1F3FB}" }, { unified: "1f6b5-1f3fc", native: "\u{1F6B5}\u{1F3FC}" }, { unified: "1f6b5-1f3fd", native: "\u{1F6B5}\u{1F3FD}" }, { unified: "1f6b5-1f3fe", native: "\u{1F6B5}\u{1F3FE}" }, { unified: "1f6b5-1f3ff", native: "\u{1F6B5}\u{1F3FF}" }], version: 1 }, "man-mountain-biking": { id: "man-mountain-biking", name: "Man Mountain Biking", keywords: ["mountain-biking", "bicycle", "bike", "cyclist", "transportation", "sports", "human", "race"], skins: [{ unified: "1f6b5-200d-2642-fe0f", native: "\u{1F6B5}\u200D\u2642\uFE0F" }, { unified: "1f6b5-1f3fb-200d-2642-fe0f", native: "\u{1F6B5}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f6b5-1f3fc-200d-2642-fe0f", native: "\u{1F6B5}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f6b5-1f3fd-200d-2642-fe0f", native: "\u{1F6B5}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f6b5-1f3fe-200d-2642-fe0f", native: "\u{1F6B5}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f6b5-1f3ff-200d-2642-fe0f", native: "\u{1F6B5}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-mountain-biking": { id: "woman-mountain-biking", name: "Woman Mountain Biking", keywords: ["mountain-biking", "bicycle", "bike", "cyclist", "transportation", "sports", "human", "race", "female"], skins: [{ unified: "1f6b5-200d-2640-fe0f", native: "\u{1F6B5}\u200D\u2640\uFE0F" }, { unified: "1f6b5-1f3fb-200d-2640-fe0f", native: "\u{1F6B5}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f6b5-1f3fc-200d-2640-fe0f", native: "\u{1F6B5}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f6b5-1f3fd-200d-2640-fe0f", native: "\u{1F6B5}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f6b5-1f3fe-200d-2640-fe0f", native: "\u{1F6B5}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f6b5-1f3ff-200d-2640-fe0f", native: "\u{1F6B5}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, person_doing_cartwheel: { id: "person_doing_cartwheel", name: "Person Cartwheeling", keywords: ["doing", "cartwheel", "sport", "gymnastic"], skins: [{ unified: "1f938", native: "\u{1F938}" }, { unified: "1f938-1f3fb", native: "\u{1F938}\u{1F3FB}" }, { unified: "1f938-1f3fc", native: "\u{1F938}\u{1F3FC}" }, { unified: "1f938-1f3fd", native: "\u{1F938}\u{1F3FD}" }, { unified: "1f938-1f3fe", native: "\u{1F938}\u{1F3FE}" }, { unified: "1f938-1f3ff", native: "\u{1F938}\u{1F3FF}" }], version: 3 }, "man-cartwheeling": { id: "man-cartwheeling", name: "Man Cartwheeling", keywords: ["gymnastics"], skins: [{ unified: "1f938-200d-2642-fe0f", native: "\u{1F938}\u200D\u2642\uFE0F" }, { unified: "1f938-1f3fb-200d-2642-fe0f", native: "\u{1F938}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f938-1f3fc-200d-2642-fe0f", native: "\u{1F938}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f938-1f3fd-200d-2642-fe0f", native: "\u{1F938}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f938-1f3fe-200d-2642-fe0f", native: "\u{1F938}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f938-1f3ff-200d-2642-fe0f", native: "\u{1F938}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-cartwheeling": { id: "woman-cartwheeling", name: "Woman Cartwheeling", keywords: ["gymnastics"], skins: [{ unified: "1f938-200d-2640-fe0f", native: "\u{1F938}\u200D\u2640\uFE0F" }, { unified: "1f938-1f3fb-200d-2640-fe0f", native: "\u{1F938}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f938-1f3fc-200d-2640-fe0f", native: "\u{1F938}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f938-1f3fd-200d-2640-fe0f", native: "\u{1F938}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f938-1f3fe-200d-2640-fe0f", native: "\u{1F938}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f938-1f3ff-200d-2640-fe0f", native: "\u{1F938}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, wrestlers: { id: "wrestlers", name: "Wrestlers", keywords: ["people", "wrestling", "sport"], skins: [{ unified: "1f93c", native: "\u{1F93C}" }], version: 3 }, "man-wrestling": { id: "man-wrestling", name: "Men Wrestling", keywords: ["man", "sports", "wrestlers"], skins: [{ unified: "1f93c-200d-2642-fe0f", native: "\u{1F93C}\u200D\u2642\uFE0F" }], version: 4 }, "woman-wrestling": { id: "woman-wrestling", name: "Women Wrestling", keywords: ["woman", "sports", "wrestlers"], skins: [{ unified: "1f93c-200d-2640-fe0f", native: "\u{1F93C}\u200D\u2640\uFE0F" }], version: 4 }, water_polo: { id: "water_polo", name: "Water Polo", keywords: ["person", "playing", "sport"], skins: [{ unified: "1f93d", native: "\u{1F93D}" }, { unified: "1f93d-1f3fb", native: "\u{1F93D}\u{1F3FB}" }, { unified: "1f93d-1f3fc", native: "\u{1F93D}\u{1F3FC}" }, { unified: "1f93d-1f3fd", native: "\u{1F93D}\u{1F3FD}" }, { unified: "1f93d-1f3fe", native: "\u{1F93D}\u{1F3FE}" }, { unified: "1f93d-1f3ff", native: "\u{1F93D}\u{1F3FF}" }], version: 3 }, "man-playing-water-polo": { id: "man-playing-water-polo", name: "Man Playing Water Polo", keywords: ["playing-water-polo", "sports", "pool"], skins: [{ unified: "1f93d-200d-2642-fe0f", native: "\u{1F93D}\u200D\u2642\uFE0F" }, { unified: "1f93d-1f3fb-200d-2642-fe0f", native: "\u{1F93D}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f93d-1f3fc-200d-2642-fe0f", native: "\u{1F93D}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f93d-1f3fd-200d-2642-fe0f", native: "\u{1F93D}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f93d-1f3fe-200d-2642-fe0f", native: "\u{1F93D}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f93d-1f3ff-200d-2642-fe0f", native: "\u{1F93D}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-playing-water-polo": { id: "woman-playing-water-polo", name: "Woman Playing Water Polo", keywords: ["playing-water-polo", "sports", "pool"], skins: [{ unified: "1f93d-200d-2640-fe0f", native: "\u{1F93D}\u200D\u2640\uFE0F" }, { uni
51763fied: "1f93d-1f3fb-200d-2640-fe0f", native: "\u{1F93D}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f93d-1f3fc-200d-2640-fe0f", native: "\u{1F93D}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f93d-1f3fd-200d-2640-fe0f", native: "\u{1F93D}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f93d-1f3fe-200d-2640-fe0f", native: "\u{1F93D}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f93d-1f3ff-200d-2640-fe0f", native: "\u{1F93D}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, handball: { id: "handball", name: "Handball", keywords: ["person", "playing", "sport"], skins: [{ unified: "1f93e", native: "\u{1F93E}" }, { unified: "1f93e-1f3fb", native: "\u{1F93E}\u{1F3FB}" }, { unified: "1f93e-1f3fc", native: "\u{1F93E}\u{1F3FC}" }, { unified: "1f93e-1f3fd", native: "\u{1F93E}\u{1F3FD}" }, { unified: "1f93e-1f3fe", native: "\u{1F93E}\u{1F3FE}" }, { unified: "1f93e-1f3ff", native: "\u{1F93E}\u{1F3FF}" }], version: 3 }, "man-playing-handball": { id: "man-playing-handball", name: "Man Playing Handball", keywords: ["playing-handball", "sports"], skins: [{ unified: "1f93e-200d-2642-fe0f", native: "\u{1F93E}\u200D\u2642\uFE0F" }, { unified: "1f93e-1f3fb-200d-2642-fe0f", native: "\u{1F93E}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f93e-1f3fc-200d-2642-fe0f", native: "\u{1F93E}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f93e-1f3fd-200d-2642-fe0f", native: "\u{1F93E}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f93e-1f3fe-200d-2642-fe0f", native: "\u{1F93E}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f93e-1f3ff-200d-2642-fe0f", native: "\u{1F93E}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-playing-handball": { id: "woman-playing-handball", name: "Woman Playing Handball", keywords: ["playing-handball", "sports"], skins: [{ unified: "1f93e-200d-2640-fe0f", native: "\u{1F93E}\u200D\u2640\uFE0F" }, { unified: "1f93e-1f3fb-200d-2640-fe0f", native: "\u{1F93E}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f93e-1f3fc-200d-2640-fe0f", native: "\u{1F93E}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f93e-1f3fd-200d-2640-fe0f", native: "\u{1F93E}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f93e-1f3fe-200d-2640-fe0f", native: "\u{1F93E}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f93e-1f3ff-200d-2640-fe0f", native: "\u{1F93E}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, juggling: { id: "juggling", name: "Juggling", keywords: ["person", "performance", "balance"], skins: [{ unified: "1f939", native: "\u{1F939}" }, { unified: "1f939-1f3fb", native: "\u{1F939}\u{1F3FB}" }, { unified: "1f939-1f3fc", native: "\u{1F939}\u{1F3FC}" }, { unified: "1f939-1f3fd", native: "\u{1F939}\u{1F3FD}" }, { unified: "1f939-1f3fe", native: "\u{1F939}\u{1F3FE}" }, { unified: "1f939-1f3ff", native: "\u{1F939}\u{1F3FF}" }], version: 3 }, "man-juggling": { id: "man-juggling", name: "Man Juggling", keywords: ["juggle", "balance", "skill", "multitask"], skins: [{ unified: "1f939-200d-2642-fe0f", native: "\u{1F939}\u200D\u2642\uFE0F" }, { unified: "1f939-1f3fb-200d-2642-fe0f", native: "\u{1F939}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f939-1f3fc-200d-2642-fe0f", native: "\u{1F939}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f939-1f3fd-200d-2642-fe0f", native: "\u{1F939}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f939-1f3fe-200d-2642-fe0f", native: "\u{1F939}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f939-1f3ff-200d-2642-fe0f", native: "\u{1F939}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 4 }, "woman-juggling": { id: "woman-juggling", name: "Woman Juggling", keywords: ["juggle", "balance", "skill", "multitask"], skins: [{ unified: "1f939-200d-2640-fe0f", native: "\u{1F939}\u200D\u2640\uFE0F" }, { unified: "1f939-1f3fb-200d-2640-fe0f", native: "\u{1F939}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f939-1f3fc-200d-2640-fe0f", native: "\u{1F939}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f939-1f3fd-200d-2640-fe0f", native: "\u{1F939}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f939-1f3fe-200d-2640-fe0f", native: "\u{1F939}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f939-1f3ff-200d-2640-fe0f", native: "\u{1F939}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 4 }, person_in_lotus_position: { id: "person_in_lotus_position", name: "Person in Lotus Position", keywords: ["meditate"], skins: [{ unified: "1f9d8", native: "\u{1F9D8}" }, { unified: "1f9d8-1f3fb", native: "\u{1F9D8}\u{1F3FB}" }, { unified: "1f9d8-1f3fc", native: "\u{1F9D8}\u{1F3FC}" }, { unified: "1f9d8-1f3fd", native: "\u{1F9D8}\u{1F3FD}" }, { unified: "1f9d8-1f3fe", native: "\u{1F9D8}\u{1F3FE}" }, { unified: "1f9d8-1f3ff", native: "\u{1F9D8}\u{1F3FF}" }], version: 5 }, man_in_lotus_position: { id: "man_in_lotus_position", name: "Man in Lotus Position", keywords: ["male", "meditation", "yoga", "serenity", "zen", "mindfulness"], skins: [{ unified: "1f9d8-200d-2642-fe0f", native: "\u{1F9D8}\u200D\u2642\uFE0F" }, { unified: "1f9d8-1f3fb-200d-2642-fe0f", native: "\u{1F9D8}\u{1F3FB}\u200D\u2642\uFE0F" }, { unified: "1f9d8-1f3fc-200d-2642-fe0f", native: "\u{1F9D8}\u{1F3FC}\u200D\u2642\uFE0F" }, { unified: "1f9d8-1f3fd-200d-2642-fe0f", native: "\u{1F9D8}\u{1F3FD}\u200D\u2642\uFE0F" }, { unified: "1f9d8-1f3fe-200d-2642-fe0f", native: "\u{1F9D8}\u{1F3FE}\u200D\u2642\uFE0F" }, { unified: "1f9d8-1f3ff-200d-2642-fe0f", native: "\u{1F9D8}\u{1F3FF}\u200D\u2642\uFE0F" }], version: 5 }, woman_in_lotus_position: { id: "woman_in_lotus_position", name: "Woman in Lotus Position", keywords: ["female", "meditation", "yoga", "serenity", "zen", "mindfulness"], skins: [{ unified: "1f9d8-200d-2640-fe0f", native: "\u{1F9D8}\u200D\u2640\uFE0F" }, { unified: "1f9d8-1f3fb-200d-2640-fe0f", native: "\u{1F9D8}\u{1F3FB}\u200D\u2640\uFE0F" }, { unified: "1f9d8-1f3fc-200d-2640-fe0f", native: "\u{1F9D8}\u{1F3FC}\u200D\u2640\uFE0F" }, { unified: "1f9d8-1f3fd-200d-2640-fe0f", native: "\u{1F9D8}\u{1F3FD}\u200D\u2640\uFE0F" }, { unified: "1f9d8-1f3fe-200d-2640-fe0f", native: "\u{1F9D8}\u{1F3FE}\u200D\u2640\uFE0F" }, { unified: "1f9d8-1f3ff-200d-2640-fe0f", native: "\u{1F9D8}\u{1F3FF}\u200D\u2640\uFE0F" }], version: 5 }, bath: { id: "bath", name: "Bath", keywords: ["person", "taking", "clean", "shower", "bathroom"], skins: [{ unified: "1f6c0", native: "\u{1F6C0}" }, { unified: "1f6c0-1f3fb", native: "\u{1F6C0}\u{1F3FB}" }, { unified: "1f6c0-1f3fc", native: "\u{1F6C0}\u{1F3FC}" }, { unified: "1f6c0-1f3fd", native: "\u{1F6C0}\u{1F3FD}" }, { unified: "1f6c0-1f3fe", native: "\u{1F6C0}\u{1F3FE}" }, { unified: "1f6c0-1f3ff", native: "\u{1F6C0}\u{1F3FF}" }], version: 1 }, sleeping_accommodation: { id: "sleeping_accommodation", name: "Person in Bed", keywords: ["sleeping", "accommodation", "rest"], skins: [{ unified: "1f6cc", native: "\u{1F6CC}" }, { unified: "1f6cc-1f3fb", native: "\u{1F6CC}\u{1F3FB}" }, { unified: "1f6cc-1f3fc", native: "\u{1F6CC}\u{1F3FC}" }, { unified: "1f6cc-1f3fd", native: "\u{1F6CC}\u{1F3FD}" }, { unified: "1f6cc-1f3fe", native: "\u{1F6CC}\u{1F3FE}" }, { unified: "1f6cc-1f3ff", native: "\u{1F6CC}\u{1F3FF}" }], version: 1 }, people_holding_hands: { id: "people_holding_hands", name: "People Holding Hands", keywords: ["friendship"], skins: [{ unified: "1f9d1-200d-1f91d-200d-1f9d1", native: "\u{1F9D1}\u200D\u{1F91D}\u200D\u{1F9D1}" }, { unified: "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fb", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1F91D}\u200D\u{1F9D1}\u{1F3FB}" }, { unified: "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fc", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1F91D}\u200D\u{1F9D1}\u{1F3FC}" }, { unified: "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fd", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1F91D}\u200D\u{1F9D1}\u{1F3FD}" }, { unified: "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fe", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1F91D}\u200D\u{1F9D1}\u{1F3FE}" }, { unified: "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3ff", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1F91D}\u200D\u{1F9D1}\u{1F3FF}" }], version: 12 }, two_women_holding_hands: { id: "two_women_holding_hands", name: "Women Holding Hands", keywords: ["two", "pair", "friendship", "couple", "love", "like", "female", "people", "human"], skins: [{ unified: "1f46d", native: "\u{1F46D}" }, { unified: "1f46d-1f3fb", native: "\u{1F46D}\u{1F3FB}" }, { unified: "1f46d-1f3fc", native: "\u{1F46D}\u{1F3FC}" }, { unified: "1f46d-1f3fd", native: "\u{1F46D}\u{1F3FD}" }, { unified: "1f46d-1f3fe", native: "\u{1F46D}\u{1F3FE}" }, { unified: "1f46d-1f3ff", native: "\u{1F46D}\u{1F3FF}" }], version: 1 }, man_and_woman_holding_hands: { id: "man_and_woman_holding_hands", name: "Man and Woman Holding Hands", keywords: ["couple", "pair", "people", "human", "love", "date", "dating", "like", "affection", "valentines", "marriage"], skins: [{ unified: "1f46b", native: "\u{1F46B}" }, { unified: "1f46b-1f3fb", native: "\u{1F46B}\u{1F3FB}" }, { unified: "1f46b-1f3fc", native: "\u{1F46B}\u{1F3FC}" }, { unified: "1f46b-1f3fd", native: "\u{1F46B}\u{1F3FD}" }, { unified: "1f46b-1f3fe", native: "\u{1F46B}\u{1F3FE}" }, { unified: "1f46b-1f3ff", native: "\u{1F46B}\u{1F3FF}" }], version: 1 }
51763, two_men_holding_hands: { id: "two_men_holding_hands", name: "Men Holding Hands", keywords: ["two", "pair", "couple", "love", "like", "bromance", "friendship", "people", "human"], skins: [{ unified: "1f46c", native: "\u{1F46C}" }, { unified: "1f46c-1f3fb", native: "\u{1F46C}\u{1F3FB}" }, { unified: "1f46c-1f3fc", native: "\u{1F46C}\u{1F3FC}" }, { unified: "1f46c-1f3fd", native: "\u{1F46C}\u{1F3FD}" }, { unified: "1f46c-1f3fe", native: "\u{1F46C}\u{1F3FE}" }, { unified: "1f46c-1f3ff", native: "\u{1F46C}\u{1F3FF}" }], version: 1 }, couplekiss: { id: "couplekiss", name: "Kiss", keywords: ["couplekiss", "pair", "valentines", "love", "like", "dating", "marriage"], skins: [{ unified: "1f48f", native: "\u{1F48F}" }, { unified: "1f48f-1f3fb", native: "\u{1F48F}\u{1F3FB}" }, { unified: "1f48f-1f3fc", native: "\u{1F48F}\u{1F3FC}" }, { unified: "1f48f-1f3fd", native: "\u{1F48F}\u{1F3FD}" }, { unified: "1f48f-1f3fe", native: "\u{1F48F}\u{1F3FE}" }, { unified: "1f48f-1f3ff", native: "\u{1F48F}\u{1F3FF}" }], version: 1 }, "woman-kiss-man": { id: "woman-kiss-man", name: "Kiss: Woman, Man", keywords: ["woman", "kiss-man", "kiss", "love"], skins: [{ unified: "1f469-200d-2764-fe0f-200d-1f48b-200d-1f468", native: "\u{1F469}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}" }, { unified: "1f469-1f3fb-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fb", native: "\u{1F469}\u{1F3FB}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}\u{1F3FB}" }, { unified: "1f469-1f3fc-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fc", native: "\u{1F469}\u{1F3FC}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}\u{1F3FC}" }, { unified: "1f469-1f3fd-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fd", native: "\u{1F469}\u{1F3FD}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}\u{1F3FD}" }, { unified: "1f469-1f3fe-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fe", native: "\u{1F469}\u{1F3FE}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}\u{1F3FE}" }, { unified: "1f469-1f3ff-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3ff", native: "\u{1F469}\u{1F3FF}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}\u{1F3FF}" }], version: 2 }, "man-kiss-man": { id: "man-kiss-man", name: "Kiss: Man, Man", keywords: ["kiss-man", "kiss", "pair", "valentines", "love", "like", "dating", "marriage"], skins: [{ unified: "1f468-200d-2764-fe0f-200d-1f48b-200d-1f468", native: "\u{1F468}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}" }, { unified: "1f468-1f3fb-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fb", native: "\u{1F468}\u{1F3FB}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}\u{1F3FB}" }, { unified: "1f468-1f3fc-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fc", native: "\u{1F468}\u{1F3FC}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}\u{1F3FC}" }, { unified: "1f468-1f3fd-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fd", native: "\u{1F468}\u{1F3FD}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}\u{1F3FD}" }, { unified: "1f468-1f3fe-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3fe", native: "\u{1F468}\u{1F3FE}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}\u{1F3FE}" }, { unified: "1f468-1f3ff-200d-2764-fe0f-200d-1f48b-200d-1f468-1f3ff", native: "\u{1F468}\u{1F3FF}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F468}\u{1F3FF}" }], version: 2 }, "woman-kiss-woman": { id: "woman-kiss-woman", name: "Kiss: Woman, Woman", keywords: ["kiss-woman", "kiss", "pair", "valentines", "love", "like", "dating", "marriage"], skins: [{ unified: "1f469-200d-2764-fe0f-200d-1f48b-200d-1f469", native: "\u{1F469}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F469}" }, { unified: "1f469-1f3fb-200d-2764-fe0f-200d-1f48b-200d-1f469-1f3fb", native: "\u{1F469}\u{1F3FB}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F469}\u{1F3FB}" }, { unified: "1f469-1f3fc-200d-2764-fe0f-200d-1f48b-200d-1f469-1f3fc", native: "\u{1F469}\u{1F3FC}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F469}\u{1F3FC}" }, { unified: "1f469-1f3fd-200d-2764-fe0f-200d-1f48b-200d-1f469-1f3fd", native: "\u{1F469}\u{1F3FD}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F469}\u{1F3FD}" }, { unified: "1f469-1f3fe-200d-2764-fe0f-200d-1f48b-200d-1f469-1f3fe", native: "\u{1F469}\u{1F3FE}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F469}\u{1F3FE}" }, { unified: "1f469-1f3ff-200d-2764-fe0f-200d-1f48b-200d-1f469-1f3ff", native: "\u{1F469}\u{1F3FF}\u200D\u2764\uFE0F\u200D\u{1F48B}\u200D\u{1F469}\u{1F3FF}" }], version: 2 }, couple_with_heart: { id: "couple_with_heart", name: "Couple with Heart", keywords: ["pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"], skins: [{ unified: "1f491", native: "\u{1F491}" }, { unified: "1f491-1f3fb", native: "\u{1F491}\u{1F3FB}" }, { unified: "1f491-1f3fc", native: "\u{1F491}\u{1F3FC}" }, { unified: "1f491-1f3fd", native: "\u{1F491}\u{1F3FD}" }, { unified: "1f491-1f3fe", native: "\u{1F491}\u{1F3FE}" }, { unified: "1f491-1f3ff", native: "\u{1F491}\u{1F3FF}" }], version: 1 }, "woman-heart-man": { id: "woman-heart-man", name: "Couple with Heart: Woman, Man", keywords: ["woman", "heart-man", "heart", "love"], skins: [{ unified: "1f469-200d-2764-fe0f-200d-1f468", native: "\u{1F469}\u200D\u2764\uFE0F\u200D\u{1F468}" }, { unified: "1f469-1f3fb-200d-2764-fe0f-200d-1f468-1f3fb", native: "\u{1F469}\u{1F3FB}\u200D\u2764\uFE0F\u200D\u{1F468}\u{1F3FB}" }, { unified: "1f469-1f3fc-200d-2764-fe0f-200d-1f468-1f3fc", native: "\u{1F469}\u{1F3FC}\u200D\u2764\uFE0F\u200D\u{1F468}\u{1F3FC}" }, { unified: "1f469-1f3fd-200d-2764-fe0f-200d-1f468-1f3fd", native: "\u{1F469}\u{1F3FD}\u200D\u2764\uFE0F\u200D\u{1F468}\u{1F3FD}" }, { unified: "1f469-1f3fe-200d-2764-fe0f-200d-1f468-1f3fe", native: "\u{1F469}\u{1F3FE}\u200D\u2764\uFE0F\u200D\u{1F468}\u{1F3FE}" }, { unified: "1f469-1f3ff-200d-2764-fe0f-200d-1f468-1f3ff", native: "\u{1F469}\u{1F3FF}\u200D\u2764\uFE0F\u200D\u{1F468}\u{1F3FF}" }], version: 2 }, "man-heart-man": { id: "man-heart-man", name: "Couple with Heart: Man, Man", keywords: ["heart-man", "heart", "pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"], skins: [{ unified: "1f468-200d-2764-fe0f-200d-1f468", native: "\u{1F468}\u200D\u2764\uFE0F\u200D\u{1F468}" }, { unified: "1f468-1f3fb-200d-2764-fe0f-200d-1f468-1f3fb", native: "\u{1F468}\u{1F3FB}\u200D\u2764\uFE0F\u200D\u{1F468}\u{1F3FB}" }, { unified: "1f468-1f3fc-200d-2764-fe0f-200d-1f468-1f3fc", native: "\u{1F468}\u{1F3FC}\u200D\u2764\uFE0F\u200D\u{1F468}\u{1F3FC}" }, { unified: "1f468-1f3fd-200d-2764-fe0f-200d-1f468-1f3fd", native: "\u{1F468}\u{1F3FD}\u200D\u2764\uFE0F\u200D\u{1F468}\u{1F3FD}" }, { unified: "1f468-1f3fe-200d-2764-fe0f-200d-1f468-1f3fe", native: "\u{1F468}\u{1F3FE}\u200D\u2764\uFE0F\u200D\u{1F468}\u{1F3FE}" }, { unified: "1f468-1f3ff-200d-2764-fe0f-200d-1f468-1f3ff", native: "\u{1F468}\u{1F3FF}\u200D\u2764\uFE0F\u200D\u{1F468}\u{1F3FF}" }], version: 2 }, "woman-heart-woman": { id: "woman-heart-woman", name: "Couple with Heart: Woman, Woman", keywords: ["heart-woman", "heart", "pair", "love", "like", "affection", "human", "dating", "valentines", "marriage"], skins: [{ unified: "1f469-200d-2764-fe0f-200d-1f469", native: "\u{1F469}\u200D\u2764\uFE0F\u200D\u{1F469}" }, { unified: "1f469-1f3fb-200d-2764-fe0f-200d-1f469-1f3fb", native: "\u{1F469}\u{1F3FB}\u200D\u2764\uFE0F\u200D\u{1F469}\u{1F3FB}" }, { unified: "1f469-1f3fc-200d-2764-fe0f-200d-1f469-1f3fc", native: "\u{1F469}\u{1F3FC}\u200D\u2764\uFE0F\u200D\u{1F469}\u{1F3FC}" }, { unified: "1f469-1f3fd-200d-2764-fe0f-200d-1f469-1f3fd", native: "\u{1F469}\u{1F3FD}\u200D\u2764\uFE0F\u200D\u{1F469}\u{1F3FD}" }, { unified: "1f469-1f3fe-200d-2764-fe0f-200d-1f469-1f3fe", native: "\u{1F469}\u{1F3FE}\u200D\u2764\uFE0F\u200D\u{1F469}\u{1F3FE}" }, { unified: "1f469-1f3ff-200d-2764-fe0f-200d-1f469-1f3ff", native: "\u{1F469}\u{1F3FF}\u200D\u2764\uFE0F\u200D\u{1F469}\u{1F3FF}" }], version: 2 }, "man-woman-boy": { id: "man-woman-boy", name: "Family: Man, Woman, Boy", keywords: ["man", "woman-boy", "family", "woman", "love"], skins: [{ unified: "1f468-200d-1f469-200d-1f466", native: "\u{1F468}\u200D\u{1F469}\u200D\u{1F466}" }], version: 2 }, "man-woman-girl": { id: "man-woman-girl", name: "Family: Man, Woman, Girl", keywords: ["man", "woman-girl", "family", "woman", "home", "parents", "peo
51763ple", "human", "child"], skins: [{ unified: "1f468-200d-1f469-200d-1f467", native: "\u{1F468}\u200D\u{1F469}\u200D\u{1F467}" }], version: 2 }, "man-woman-girl-boy": { id: "man-woman-girl-boy", name: "Family: Man, Woman, Girl, Boy", keywords: ["man", "woman-girl-boy", "family", "woman", "girl", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f469-200d-1f467-200d-1f466", native: "\u{1F468}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F466}" }], version: 2 }, "man-woman-boy-boy": { id: "man-woman-boy-boy", name: "Family: Man, Woman, Boy, Boy", keywords: ["man", "woman-boy-boy", "family", "woman", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f469-200d-1f466-200d-1f466", native: "\u{1F468}\u200D\u{1F469}\u200D\u{1F466}\u200D\u{1F466}" }], version: 2 }, "man-woman-girl-girl": { id: "man-woman-girl-girl", name: "Family: Man, Woman, Girl, Girl", keywords: ["man", "woman-girl-girl", "family", "woman", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f469-200d-1f467-200d-1f467", native: "\u{1F468}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F467}" }], version: 2 }, "man-man-boy": { id: "man-man-boy", name: "Family: Man, Man, Boy", keywords: ["man", "man-boy", "family", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f468-200d-1f466", native: "\u{1F468}\u200D\u{1F468}\u200D\u{1F466}" }], version: 2 }, "man-man-girl": { id: "man-man-girl", name: "Family: Man, Man, Girl", keywords: ["man", "man-girl", "family", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f468-200d-1f467", native: "\u{1F468}\u200D\u{1F468}\u200D\u{1F467}" }], version: 2 }, "man-man-girl-boy": { id: "man-man-girl-boy", name: "Family: Man, Man, Girl, Boy", keywords: ["man", "man-girl-boy", "family", "girl", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f468-200d-1f467-200d-1f466", native: "\u{1F468}\u200D\u{1F468}\u200D\u{1F467}\u200D\u{1F466}" }], version: 2 }, "man-man-boy-boy": { id: "man-man-boy-boy", name: "Family: Man, Man, Boy, Boy", keywords: ["man", "man-boy-boy", "family", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f468-200d-1f466-200d-1f466", native: "\u{1F468}\u200D\u{1F468}\u200D\u{1F466}\u200D\u{1F466}" }], version: 2 }, "man-man-girl-girl": { id: "man-man-girl-girl", name: "Family: Man, Man, Girl, Girl", keywords: ["man", "man-girl-girl", "family", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f468-200d-1f467-200d-1f467", native: "\u{1F468}\u200D\u{1F468}\u200D\u{1F467}\u200D\u{1F467}" }], version: 2 }, "woman-woman-boy": { id: "woman-woman-boy", name: "Family: Woman, Woman, Boy", keywords: ["woman", "woman-boy", "family", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f469-200d-1f469-200d-1f466", native: "\u{1F469}\u200D\u{1F469}\u200D\u{1F466}" }], version: 2 }, "woman-woman-girl": { id: "woman-woman-girl", name: "Family: Woman, Woman, Girl", keywords: ["woman", "woman-girl", "family", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f469-200d-1f469-200d-1f467", native: "\u{1F469}\u200D\u{1F469}\u200D\u{1F467}" }], version: 2 }, "woman-woman-girl-boy": { id: "woman-woman-girl-boy", name: "Family: Woman, Woman, Girl, Boy", keywords: ["woman", "woman-girl-boy", "family", "girl", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f469-200d-1f469-200d-1f467-200d-1f466", native: "\u{1F469}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F466}" }], version: 2 }, "woman-woman-boy-boy": { id: "woman-woman-boy-boy", name: "Family: Woman, Woman, Boy, Boy", keywords: ["woman", "woman-boy-boy", "family", "home", "parents", "people", "human", "children"], skins: [{ unified: "1f469-200d-1f469-200d-1f466-200d-1f466", native: "\u{1F469}\u200D\u{1F469}\u200D\u{1F466}\u200D\u{1F466}" }], version: 2 }, "woman-woman-girl-girl": { id: "woman-woman-girl-girl", name: "Family: Woman, Woman, Girl, Girl", keywords: ["woman", "woman-girl-girl", "family", "home", "parents", "peo
51763ple", "human", "children"], skins: [{ unified: "1f469-200d-1f469-200d-1f467-200d-1f467", native: "\u{1F469}\u200D\u{1F469}\u200D\u{1F467}\u200D\u{1F467}" }], version: 2 }, "man-boy": { id: "man-boy", name: "Family: Man, Boy", keywords: ["man", "family", "home", "parent", "people", "human", "child"], skins: [{ unified: "1f468-200d-1f466", native: "\u{1F468}\u200D\u{1F466}" }], version: 4 }, "man-boy-boy": { id: "man-boy-boy", name: "Family: Man, Boy, Boy", keywords: ["man", "boy-boy", "family", "home", "parent", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f466-200d-1f466", native: "\u{1F468}\u200D\u{1F466}\u200D\u{1F466}" }], version: 4 }, "man-girl": { id: "man-girl", name: "Family: Man, Girl", keywords: ["man", "family", "home", "parent", "people", "human", "child"], skins: [{ unified: "1f468-200d-1f467", native: "\u{1F468}\u200D\u{1F467}" }], version: 4 }, "man-girl-boy": { id: "man-girl-boy", name: "Family: Man, Girl, Boy", keywords: ["man", "girl-boy", "family", "girl", "home", "parent", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f467-200d-1f466", native: "\u{1F468}\u200D\u{1F467}\u200D\u{1F466}" }], version: 4 }, "man-girl-girl": { id: "man-girl-girl", name: "Family: Man, Girl, Girl", keywords: ["man", "girl-girl", "family", "home", "parent", "people", "human", "children"], skins: [{ unified: "1f468-200d-1f467-200d-1f467", native: "\u{1F468}\u200D\u{1F467}\u200D\u{1F467}" }], version: 4 }, "woman-boy": { id: "woman-boy", name: "Family: Woman, Boy", keywords: ["woman", "family", "home", "parent", "people", "human", "child"], skins: [{ unified: "1f469-200d-1f466", native: "\u{1F469}\u200D\u{1F466}" }], version: 4 }, "woman-boy-boy": { id: "woman-boy-boy", name: "Family: Woman, Boy, Boy", keywords: ["woman", "boy-boy", "family", "home", "parent", "people", "human", "children"], skins: [{ unified: "1f469-200d-1f466-200d-1f466", native: "\u{1F469}\u200D\u{1F466}\u200D\u{1F466}" }], version: 4 }, "woman-girl": { id: "woman-girl", name: "Family: Woman, Girl", keywords: ["woman", "family", "home", "parent", "people", "human", "child"], skins: [{ unified: "1f469-200d-1f467", native: "\u{1F469}\u200D\u{1F467}" }], version: 4 }, "woman-girl-boy": { id: "woman-girl-boy", name: "Family: Woman, Girl, Boy", keywords: ["woman", "girl-boy", "family", "girl", "home", "parent", "people", "human", "children"], skins: [{ unified: "1f469-200d-1f467-200d-1f466", native: "\u{1F469}\u200D\u{1F467}\u200D\u{1F466}" }], version: 4 }, "woman-girl-girl": { id: "woman-girl-girl", name: "Family: Woman, Girl, Girl", keywords: ["woman", "girl-girl", "family", "home", "parent", "people", "human", "children"], skins: [{ unified: "1f469-200d-1f467-200d-1f467", native: "\u{1F469}\u200D\u{1F467}\u200D\u{1F467}" }], version: 4 }, speaking_head_in_silhouette: { id: "speaking_head_in_silhouette", name: "Speaking Head", keywords: ["in", "silhouette", "user", "person", "human", "sing", "say", "talk"], skins: [{ unified: "1f5e3-fe0f", native: "\u{1F5E3}\uFE0F" }], version: 1 }, bust_in_silhouette: { id: "bust_in_silhouette", name: "Bust in Silhouette", keywords: ["user", "person", "human"], skins: [{ unified: "1f464", native: "\u{1F464}" }], version: 1 }, busts_in_silhouette: { id: "busts_in_silhouette", name: "Busts in Silhouette", keywords: ["user", "person", "human", "group", "team"], skins: [{ unified: "1f465", native: "\u{1F465}" }], version: 1 }, people_hugging: { id: "people_hugging", name: "People Hugging", keywords: ["care"], skins: [{ unified: "1fac2", native: "\u{1FAC2}" }], version: 13 }, family: { id: "family", name: "Family", keywords: ["home", "parents", "child", "mom", "dad", "father", "mother", "people", "human"], skins: [{ unified: "1f46a", native: "\u{1F46A}" }], version: 1 }, family_adult_adult_child: { id: "family_adult_adult_child", name: "Family: Adult, Adult, Child", keywords: ["family", "adult", "kid", "parents"], skins: [{ unified: "1f9d1-200d-1f9d1-200d-1f9d2", native: "\u{1F9D1}\u200D\u{1F9D1}\u200D\u{1F9D2}" }], version: 15.1 }, family_adult_adult_child_child: { id: "family_adult_adult_child_child", name: "Family: Adult, Adult, Child, Child", keywords: ["family", "adult", "children", "parents"], skins: [{ unified: "1f9d1-200d-1f9d1-200d-1f9d2-200d-1f9d2", native: "\u{1F9D1}\u200D\u{1F9D1}\u200D\u{1F9D2}\u200D\u{1F9D2}" }], version: 15.1 }, family_adult_child: { id: "family_adult_child", name: "Family: Adult, Child", keywords: ["family", "adult", "parent", "kid"], skins: [{ unified: "1f9d1-200d-1f9d2", native: "\u{1F9D1}\u200D\u{1F9D2}" }], version: 15.1 }, family_adult_child_child: { id: "family_adult_child_child", name: "Family: Adult, Child, Child", keywords: ["family", "adult", "parent", "children"], skins: [{ unified: "1f9d1-200d-1f9d2-200d-1f9d2", native: "\u{1F9D1}\u200D\u{1F9D2}\u200D\u{1F9D2}" }], version: 15.1 }, footprints: { id: "footprints", name: "Footprints", keywords: ["feet", "tracking", "walking", "beach"], skins: [{ unified: "1f463", native: "\u{1F463}" }], version: 1 }, fingerprint: { id: "fingerprint", name: "Fingerprint", keywords: [], skins: [{ unified: "1fac6", native: "\u{1FAC6}" }], version: 16 }, monkey_face: { id: "monkey_face", name: "Monkey Face", emoticons: [":o)"], keywords: ["animal", "nature", "circus"], skins: [{ unified: "1f435", native: "\u{1F435}" }], version: 1 }, monkey: { id: "monkey", name: "Monkey", keywords: ["animal", "nature", "banana", "circus"], skins: [{ unified: "1f412", native: "\u{1F412}" }], version: 1 }, gorilla: { id: "gorilla", name: "Gorilla", keywords: ["animal", "nature", "circus"], skins: [{ unified: "1f98d", native: "\u{1F98D}" }], version: 3 }, orangutan: { id: "orangutan", name: "Orangutan", keywords: ["animal"], skins: [{ unified: "1f9a7", native: "\u{1F9A7}" }], version: 12 }, dog: { id: "dog", name: "Dog Face", keywords: ["animal", "friend", "nature", "woof", "puppy", "pet", "faithful"], skins: [{ unified: "1f436", native: "\u{1F436}" }], version: 1 }, dog2: { id: "dog2", name: "Dog", keywords: ["dog2", "animal", "nature", "friend", "doge", "pet", "faithful"], skins: [{ unified: "1f415", native: "\u{1F415}" }], version: 1 }, guide_dog: { id: "guide_dog", name: "Guide Dog", keywords: ["animal", "blind"], skins: [{ unified: "1f9ae", native: "\u{1F9AE}" }], version: 12 }, service_dog: { id: "service_dog", name: "Service Dog", keywords: ["blind", "animal"], skins: [{ unified: "1f415-200d-1f9ba", native: "\u{1F415}\u200D\u{1F9BA}" }], version: 12 }, poodle: { id: "poodle", name: "Poodle", keywords: ["dog", "animal", "101", "nature", "pet"], skins: [{ unified: "1f429", native: "\u{1F429}" }], version: 1 }, wolf: { id: "wolf", name: "Wolf", keywords: ["animal", "nature", "wild"], skins: [{ unified: "1f43a", native: "\u{1F43A}" }], version: 1 }, fox_face: { id: "fox_face", name: "Fox", keywords: ["face", "animal", "nature"], skins: [{ unified: "1f98a", native: "\u{1F98A}" }
51763], version: 3 }, raccoon: { id: "raccoon", name: "Raccoon", keywords: ["animal", "nature"], skins: [{ unified: "1f99d", native: "\u{1F99D}" }], version: 11 }, cat: { id: "cat", name: "Cat Face", keywords: ["animal", "meow", "nature", "pet", "kitten"], skins: [{ unified: "1f431", native: "\u{1F431}" }], version: 1 }, cat2: { id: "cat2", name: "Cat", keywords: ["cat2", "animal", "meow", "pet", "cats"], skins: [{ unified: "1f408", native: "\u{1F408}" }], version: 1 }, black_cat: { id: "black_cat", name: "Black Cat", keywords: ["superstition", "luck"], skins: [{ unified: "1f408-200d-2b1b", native: "\u{1F408}\u200D\u2B1B" }], version: 13 }, lion_face: { id: "lion_face", name: "Lion", keywords: ["face", "animal", "nature"], skins: [{ unified: "1f981", native: "\u{1F981}" }], version: 1 }, tiger: { id: "tiger", name: "Tiger Face", keywords: ["animal", "cat", "danger", "wild", "nature", "roar"], skins: [{ unified: "1f42f", native: "\u{1F42F}" }], version: 1 }, tiger2: { id: "tiger2", name: "Tiger", keywords: ["tiger2", "animal", "nature", "roar"], skins: [{ unified: "1f405", native: "\u{1F405}" }], version: 1 }, leopard: { id: "leopard", name: "Leopard", keywords: ["animal", "nature"], skins: [{ unified: "1f406", native: "\u{1F406}" }], version: 1 }, horse: { id: "horse", name: "Horse Face", keywords: ["animal", "brown", "nature"], skins: [{ unified: "1f434", native: "\u{1F434}" }], version: 1 }, moose: { id: "moose", name: "Moose", keywords: ["shrek", "canada", "sweden", "sven", "cool"], skins: [{ unified: "1face", native: "\u{1FACE}" }], version: 15 }, donkey: { id: "donkey", name: "Donkey", keywords: ["eeyore", "mule"], skins: [{ unified: "1facf", native: "\u{1FACF}" }], version: 15 }, racehorse: { id: "racehorse", name: "Horse", keywords: ["racehorse", "animal", "gamble", "luck"], skins: [{ unified: "1f40e", native: "\u{1F40E}" }], version: 1 }, unicorn_face: { id: "unicorn_face", name: "Unicorn", keywords: ["face", "animal", "nature", "mystical"], skins: [{ unified: "1f984", native: "\u{1F984}" }], version: 1 }, zebra_face: { id: "zebra_face", name: "Zebra", keywords: ["face", "animal", "nature", "stripes", "safari"], skins: [{ unified: "1f993", native: "\u{1F993}" }], version: 5 }, deer: { id: "deer", name: "Deer", keywords: ["animal", "nature", "horns", "venison"], skins: [{ unified: "1f98c", native: "\u{1F98C}" }], version: 3 }, bison: { id: "bison", name: "Bison", keywords: ["ox"], skins: [{ unified: "1f9ac", native: "\u{1F9AC}" }], version: 13 }, cow: { id: "cow", name: "Cow Face", keywords: ["beef", "ox", "animal", "nature", "moo", "milk"], skins: [{ unified: "1f42e", native: "\u{1F42E}" }], version: 1 }, ox: { id: "ox", name: "Ox", keywords: ["animal", "cow", "beef"], skins: [{ unified: "1f402", native: "\u{1F402}" }], version: 1 }, water_buffalo: { id: "water_buffalo", name: "Water Buffalo", keywords: ["animal", "nature", "ox", "cow"], skins: [{ unified: "1f403", native: "\u{1F403}" }], version: 1 }, cow2: { id: "cow2", name: "Cow", keywords: ["cow2", "beef", "ox", "animal", "nature", "moo", "milk"], skins: [{ unified: "1f404", native: "\u{1F404}" }], version: 1 }, pig: { id: "pig", name: "Pig Face", keywords: ["animal", "oink", "nature"], skins: [{ unified: "1f437", native: "\u{1F437}" }], version: 1 }, pig2: { id: "pig2", name: "Pig", keywords: ["pig2", "animal", "nature"], skins: [{ unified: "1f416", native: "\u{1F416}" }], version: 1 }, boar: { id: "boar", name: "Boar", keywords: ["animal", "nature"], skins: [{ unified: "1f417", native: "\u{1F417}" }], version: 1 }, pig_nose: { id: "pig_nose", name: "Pig Nose", keywords: ["animal", "oink"], skins: [{ unified: "1f43d", native: "\u{1F43D}" }], version: 1 }, ram: { id: "ram", name: "Ram", keywords: ["animal", "sheep", "nature"], skins: [{ unified: "1f40f", native: "\u{1F40F}" }], version: 1 }, sheep: { id: "sheep", name: "Ewe", keywords: ["sheep", "animal", "nature", "wool", "shipit"], skins: [{ unified: "1f411", native: "\u{1F411}" }], version: 1 }, goat: { id: "goat", name: "Goat", keywords: ["animal", "nature"], skins: [{ unified: "1f410", native: "\u{1F410}" }], version: 1 }, dromedary_camel: { id: "dromedary_camel", name: "Camel", keywords: ["dromedary", "animal", "hot", "desert", "hump"], skins: [{ unified: "1f42a", native: "\u{1F42A}" }], version: 1 }, camel: { id: "camel", name: "Bactrian Camel", keywords: ["two", "hump", "animal", "nature", "hot", "desert"], skins: [{ unified: "1f42b", native: "\u{1F42B}" }], version: 1 }, llama: { id: "llama", name: "Llama", keywords: ["animal", "nature", "alpaca"], skins: [{ unified: "1f999", native: "\u{1F999}" }], version: 11 }, giraffe_face: { id: "giraffe_face", name: "Giraffe", keywords: ["face", "animal", "nature", "spots", "safari"], skins: [{ unified: "1f992", native: "\u{1F992}" }], version: 5 }, elephant: { id: "elephant", name: "Elephant", keywords: ["animal", "nature", "nose", "th", "cir
51763cus"], skins: [{ unified: "1f418", native: "\u{1F418}" }], version: 1 }, mammoth: { id: "mammoth", name: "Mammoth", keywords: ["elephant", "tusks"], skins: [{ unified: "1f9a3", native: "\u{1F9A3}" }], version: 13 }, rhinoceros: { id: "rhinoceros", name: "Rhinoceros", keywords: ["animal", "nature", "horn"], skins: [{ unified: "1f98f", native: "\u{1F98F}" }], version: 3 }, hippopotamus: { id: "hippopotamus", name: "Hippopotamus", keywords: ["animal", "nature"], skins: [{ unified: "1f99b", native: "\u{1F99B}" }], version: 11 }, mouse: { id: "mouse", name: "Mouse Face", keywords: ["animal", "nature", "cheese", "wedge", "rodent"], skins: [{ unified: "1f42d", native: "\u{1F42D}" }], version: 1 }, mouse2: { id: "mouse2", name: "Mouse", keywords: ["mouse2", "animal", "nature", "rodent"], skins: [{ unified: "1f401", native: "\u{1F401}" }], version: 1 }, rat: { id: "rat", name: "Rat", keywords: ["animal", "mouse", "rodent"], skins: [{ unified: "1f400", native: "\u{1F400}" }], version: 1 }, hamster: { id: "hamster", name: "Hamster", keywords: ["animal", "nature"], skins: [{ unified: "1f439", native: "\u{1F439}" }], version: 1 }, rabbit: { id: "rabbit", name: "Rabbit Face", keywords: ["animal", "nature", "pet", "spring", "magic", "bunny"], skins: [{ unified: "1f430", native: "\u{1F430}" }], version: 1 }, rabbit2: { id: "rabbit2", name: "Rabbit", keywords: ["rabbit2", "animal", "nature", "pet", "magic", "spring"], skins: [{ unified: "1f407", native: "\u{1F407}" }], version: 1 }, chipmunk: { id: "chipmunk", name: "Chipmunk", keywords: ["animal", "nature", "rodent", "squirrel"], skins: [{ unified: "1f43f-fe0f", native: "\u{1F43F}\uFE0F" }], version: 1 }, beaver: { id: "beaver", name: "Beaver", keywords: ["animal", "rodent"], skins: [{ unified: "1f9ab", native: "\u{1F9AB}" }], version: 13 }, hedgehog: { id: "hedgehog", name: "Hedgehog", keywords: ["animal", "nature", "spiny"], skins: [{ unified: "1f994", native: "\u{1F994}" }], version: 5 }, bat: { id: "bat", name: "Bat", keywords: ["animal", "nature", "blind", "vampire"], skins: [{ unified: "1f987", native: "\u{1F987}" }], version: 3 }, bear: { id: "bear", name: "Bear", keywords: ["animal", "nature", "wild"], skins: [{ unified: "1f43b", native: "\u{1F43B}" }], version: 1 }, polar_bear: { id: "polar_bear", name: "Polar Bear", keywords: ["animal", "arctic"], skins: [{ unified: "1f43b-200d-2744-fe0f", native: "\u{1F43B}\u200D\u2744\uFE0F" }], version: 13 }, koala: { id: "koala", name: "Koala", keywords: ["animal", "nature"], skins: [{ unified: "1f428", native: "\u{1F428}" }], version: 1 }, panda_face: { id: "panda_face", name: "Panda", keywords: ["face", "animal", "nature"], skins: [{ unified: "1f43c", native: "\u{1F43C}" }], version: 1 }, sloth: { id: "sloth", name: "Sloth", keywords: ["animal"], skins: [{ unified: "1f9a5", native: "\u{1F9A5}" }], version: 12 }, otter: { id: "otter", name: "Otter", keywords: ["animal"], skins: [{ unified: "1f9a6", native: "\u{1F9A6}" }], version: 12 }, skunk: { id: "skunk", name: "Skunk", keywords: ["animal"], skins: [{ unified: "1f9a8", native: "\u{1F9A8}" }], version: 12 }, kangaroo: { id: "kangaroo", name: "Kangaroo", keywords: ["animal", "nature", "australia", "joey", "hop", "marsupial"], skins: [{ unified: "1f998", native: "\u{1F998}" }], version: 11 }, badger: { id: "badger", name: "Badger", keywords: ["animal", "nature", "honey"], skins: [{ unified: "1f9a1", native: "\u{1F9A1}" }], version: 11 }, feet: { id: "feet", name: "Paw Prints", keywords: ["feet", "animal", "tracking", "footprints", "dog", "cat", "pet"], skins: [{ unified: "1f43e", native: "\u{1F43E}" }], version: 1 }, turkey: { id: "turkey", name: "Turkey", keywords: ["animal", "bird"], skins: [{ unified: "1f983", native: "\u{1F983}" }], version: 1 }, chicken: { id: "chicken", name: "Chicken", keywords: ["animal", "cluck", "nature", "bird"], skins: [{ unified: "1f414", native: "\u{1F414}" }], version: 1 }, rooster: { id: "rooster", name: "Rooster", keywords: ["animal", "nature", "chicken"], skins: [{ unified: "1f413", native: "\u{1F413}" }], version: 1 }, hatching_chick: { id: "hatching_chick", name: "Hatching Chick", keywords: ["animal", "chicken", "egg", "born", "baby", "bird"], skins: [{ unified: "1f423", native: "\u{1F423}" }], version: 1 }, baby_chick: { id: "baby_chick", name: "Baby Chick", keywords: ["animal", "chicken", "bird"], skins: [{ unified: "1f424", native: "\u{1F424}" }], version: 1 }, hatched_chick: { id: "hatched_chick", name: "Front-Facing Baby Chick", keywords: ["hatched", "front", "facing", "animal", "chicken", "bird"], skins: [{ unified: "1f425", native: "\u{1F425}" }], version: 1 }, bird: { id: "bird", name: "Bird", keywords: ["animal", "nature", "fly", "tweet", "spring"], skins: [{ unified: "1f426", native: "\u{1F426}" }], version: 1 }, penguin: { id: "penguin", name: "Penguin", keywords: ["animal", "nature"], skins: [{ unified: "1f427", native: "\u{1F427}" }], version: 1 }, dove_of_peace: { id: "dove_of_peace", name: "Dove", keywords: ["of", "peace", "animal", "bird"], skins: [{ unified: "1f54a-fe0f", native: "\u{1F54A}\uFE0F" }], version: 1 }, eagle: { id: "eagle", name: "Eagle", keywords: ["animal", "nature", "bird"], skins: [{ unified: "1f985", native: "\u{1F985}" }], version: 3 }, duck: { id: "duck", name: "Duck", keywords: ["animal", "nature", "bird", "mallard"], skins: [{ unified: "1f986", native: "\u{1F986}" }], version: 3 }, swan: { id: "swan", name: "Swan", keywords: ["animal", "nature", "bird"], skins: [{ unified: "1f9a2", native: "\u{1F9A2}" }], version: 11 }, owl: { id: "owl", name: "Owl", keywords: ["animal", "nature", "bird", "hoot"], skins: [{ unified: "1f989", native: "\u{1F989}" }], version: 3 }, dodo: { id: "dodo", name: "Dodo", keywords: ["animal", "bird"], skins: [{ unified: "1f9a4", native: "\u{1F9A4}" }], version: 13 }, feather: { id: "feather", name: "Feather", keywords: ["bird", "fly"], skins: [{ unified: "1fab6", native: "\u{1FAB6}" }], version: 13 }, flamingo: { id: "flamingo", name: "Flamingo", keywords: ["animal"], skins: [{ unified: "1f9a9", native: "\u{1F9A9}" }], version: 12 }, peacock: { id: "peacock", name: "Peacock", keywords: ["animal", "nature", "peahen", "bird"], skins: [{ unified: "1f99a", native: "\u{1F99A}" }], version: 11 }, parrot: { id: "parrot", name: "Parrot", keywords: ["animal", "nature", "bird", "pirate", "talk"], skins: [{ unified: "1f99c", native: "\u{1F99C}" }], version: 11 }, wing: { id: "wing", name: "Wing", keywords: ["angel", "birds", "flying"], skins: [{ unified: "1fabd", native: "\u{1FABD}" }], version: 15 }, black_bird: { id: "black_bird", name: "Black Bird", keywords: ["crow"], skins: [{ unified: "1f426-200d-2b1b", native: "\u{1F426}\u200D\u2B1B" }], version: 15 }, goose: { id: "goose", name: "Goose", keywords: ["silly", "jemima", "goosebumps"], skins: [{ unified: "1fabf", native: "\u{1FABF}" }], version: 15 }, phoenix: { id: "phoenix", name: "Phoenix", keywords: ["immortal", "bird", "mythtical", "reborn"], skins: [{ unified: "1f426-200d-1f525", native: "\u{1F426}\u200D\u{1F525}" }], version: 15.1 }, frog: { id: "frog", name: "Frog", keywords: ["animal", "nature", "croak", "toad"], skins: [{ unified: "1f438", native: "\u{1F438}" }], version: 1 }, crocodile: { id: "crocodile", name: "Crocodile", keywords: ["animal", "nature", "reptile", "lizard", "alligator"], skins: [{ unified: "1f40a", native: "\u{1F40A}" }], version: 1 }, turtle: { id: "turtle", name: "Turtle", keywords: ["animal", "slow", "nature", "tortoise"], skins: [{ unified: "1f422", native: "\u{1F422}" }], version: 1 }, lizard: { id: "lizard", name: "Lizard", keywords: ["animal", "nature", "reptile"], skins: [{ unified: "1f98e", native: "\u{1F98E}" }], version: 3 }, snake: { id: "snake", name: "Snake", keywords: ["animal", "evil", "nature", "hiss", "python"], skins: [{ unified: "1f40d", native: "\u{1F40D}" }], version: 1 }, dragon_face: { id: "dragon_face", name: "Dragon Face", keywords: ["animal", "myth", "nature", "chinese", "green"], skins: [{ unified: "1f432", native: "\u{1F432}" }], version: 1 }, dragon: { id: "dragon", name: "Dragon", keywords: ["animal", "myth", "nature", "chinese", "green"], skins: [{ unified: "1f409", native: "\u{1F409}" }], version: 1 }, sauropod: { id: "sauropod", name: "Sauropod", keywords: ["animal", "nature", "dinosaur", "brachiosaurus", "brontosaurus", "diplodocus", "extinct"], skins: [{ unified: "1f995", native: "\u{1F995}" }], version: 5 }, "t-rex": { id: "t-rex", name: "T-Rex", keywords: ["t", "rex", "animal", "nature", "dinosaur", "tyrannosaurus", "extinct"], skins: [{ unified: "1f996", native: "\u{1F996}" }], version: 5 }, whale: { id: "whale", name: "Spouting Whale", keywords: ["animal", "nature", "sea", "ocean"], skins: [{ unified: "1f433", native: "\u{1F433}" }
51763], version: 1 }, whale2: { id: "whale2", name: "Whale", keywords: ["whale2", "animal", "nature", "sea", "ocean"], skins: [{ unified: "1f40b", native: "\u{1F40B}" }], version: 1 }, dolphin: { id: "dolphin", name: "Dolphin", keywords: ["flipper", "animal", "nature", "fish", "sea", "ocean", "fins", "beach"], skins: [{ unified: "1f42c", native: "\u{1F42C}" }], version: 1 }, seal: { id: "seal", name: "Seal", keywords: ["animal", "creature", "sea"], skins: [{ unified: "1f9ad", native: "\u{1F9AD}" }], version: 13 }, fish: { id: "fish", name: "Fish", keywords: ["animal", "food", "nature"], skins: [{ unified: "1f41f", native: "\u{1F41F}" }], version: 1 }, tropical_fish: { id: "tropical_fish", name: "Tropical Fish", keywords: ["animal", "swim", "ocean", "beach", "nemo"], skins: [{ unified: "1f420", native: "\u{1F420}" }], version: 1 }, blowfish: { id: "blowfish", name: "Blowfish", keywords: ["animal", "nature", "food", "sea", "ocean"], skins: [{ unified: "1f421", native: "\u{1F421}" }], version: 1 }, shark: { id: "shark", name: "Shark", keywords: ["animal", "nature", "fish", "sea", "ocean", "jaws", "fins", "beach"], skins: [{ unified: "1f988", native: "\u{1F988}" }], version: 3 }, octopus: { id: "octopus", name: "Octopus", keywords: ["animal", "creature", "ocean", "sea", "nature", "beach"], skins: [{ unified: "1f419", native: "\u{1F419}" }], version: 1 }, shell: { id: "shell", name: "Spiral Shell", keywords: ["nature", "sea", "beach"], skins: [{ unified: "1f41a", native: "\u{1F41A}" }], version: 1 }, coral: { id: "coral", name: "Coral", keywords: ["ocean", "sea", "reef"], skins: [{ unified: "1fab8", native: "\u{1FAB8}" }], version: 14 }, jellyfish: { id: "jellyfish", name: "Jellyfish", keywords: ["sting", "tentacles"], skins: [{ unified: "1fabc", native: "\u{1FABC}" }], version: 15 }, crab: { id: "crab", name: "Crab", keywords: ["animal", "crustacean"], skins: [{ unified: "1f980", native: "\u{1F980}" }], version: 1 }, lobster: { id: "lobster", name: "Lobster", keywords: ["animal", "nature", "bisque", "claws", "seafood"], skins: [{ unified: "1f99e", native: "\u{1F99E}" }], version: 11 }, shrimp: { id: "shrimp", name: "Shrimp", keywords: ["animal", "ocean", "nature", "seafood"], skins: [{ unified: "1f990", native: "\u{1F990}" }], version: 3 }, squid: { id: "squid", name: "Squid", keywords: ["animal", "nature", "ocean", "sea"], skins: [{ unified: "1f991", native: "\u{1F991}" }], version: 3 }, oyster: { id: "oyster", name: "Oyster", keywords: ["food"], skins: [{ unified: "1f9aa", native: "\u{1F9AA}" }], version: 12 }, snail: { id: "snail", name: "Snail", keywords: ["slow", "animal", "shell"], skins: [{ unified: "1f40c", native: "\u{1F40C}" }], version: 1 }, butterfly: { id: "butterfly", name: "Butterfly", keywords: ["animal", "insect", "nature", "caterpillar"], skins: [{ unified: "1f98b", native: "\u{1F98B}" }], version: 3 }, bug: { id: "bug", name: "Bug", keywords: ["animal", "insect", "nature", "worm"], skins: [{ unified: "1f41b", native: "\u{1F41B}" }], version: 1 }, ant: { id: "ant", name: "Ant", keywords: ["animal", "insect", "nature", "bug"], skins: [{ unified: "1f41c", native: "\u{1F41C}" }], version: 1 }, bee: { id: "bee", name: "Honeybee", keywords: ["bee", "animal", "insect", "nature", "bug", "spring", "honey"], skins: [{ unified: "1f41d", native: "\u{1F41D}" }], version: 1 }, beetle: { id: "beetle", name: "Beetle", keywords: ["insect"], skins: [{ unified: "1fab2", native: "\u{1FAB2}" }], version: 13 }, ladybug: { id: "ladybug", name: "Lady Beetle", keywords: ["ladybug", "animal", "insect", "nature"], skins: [{ unified: "1f41e", native: "\u{1F41E}" }], version: 1 }, cricket: { id: "cricket", name: "Cricket", keywords: ["animal", "chirp"], skins: [{ unified: "1f997", native: "\u{1F997}" }], version: 5 }, cockroach: { id: "cockroach", name: "Cockroach", keywords: ["insect", "pests"], skins: [{ unified: "1fab3", native: "\u{1FAB3}" }], version: 13 }, spider: { id: "spider", name: "Spider", keywords: ["animal", "arachnid"], skins: [{ unified: "1f577-fe0f", native: "\u{1F577}\uFE0F" }], version: 1 }, spider_web: { id: "spider_web", name: "Spider Web", keywords: ["animal", "insect", "arachnid", "silk"], skins: [{ unified: "1f578-fe0f", native: "\u{1F578}\uFE0F" }], version: 1 }, scorpion: { id: "scorpion", name: "Scorpion", keywords: ["animal", "arachnid"], skins: [{ unified: "1f982", native: "\u{1F982}" }], version: 1 }, mosquito: { id: "mosquito", name: "Mosquito", keywords: ["animal", "nature", "insect", "malaria"], skins: [{ unified: "1f99f", native: "\u{1F99F}" }], version: 11 }, fly: { id: "fly", name: "Fly", keywords: ["insect"], skins: [{ unified: "1fab0", native: "\u{1FAB0}" }], version: 13 }, worm: { id: "worm", name: "Worm", keywords: ["animal"], skins: [{ unified: "1fab1", native: "\u{1FAB1}" }], version: 13 }, microbe: { id: "microbe", name: "Microbe", keywords: ["amoeba", "bacteria", "germs", "virus", "covid"], skins: [{ unified: "1f9a0", native: "\u{1F9A0}" }], version: 11 }, bouquet: { id: "bouquet", name: "Bouquet", keywords: ["flowers", "nature", "spring"], skins: [{ unified: "1f490", native: "\u{1F490}" }], version: 1 }, cherry_blossom: { id: "cherry_blossom", name: "Cherry Blossom", keywords: ["nature", "plant", "spring", "flower"], skins: [{ unified: "1f338", native: "\u{1F338}" }], version: 1 }, white_flower: { id: "white_flower", name: "White Flower", keywords: ["japanese", "spring"], skins: [{ unified: "1f4ae", native: "\u{1F4AE}" }], version: 1 }, lotus: { id: "lotus", name: "Lotus", keywords: ["flower", "calm", "meditation"], skins: [{ unified: "1fab7", native: "\u{1FAB7}" }], version: 14 }, rosette: { id: "rosette", name: "Rosette", keywords: ["flower", "decoration", "military"], skins: [{ unified: "1f3f5-fe0f", native: "\u{1F3F5}\uFE0F" }], version: 1 }, rose: { id: "rose", name: "Rose", keywords: ["flowers", "valentines", "love", "spring"], skins: [{ unified: "1f339", native: "\u{1F339}" }], version: 1 }, wilted_flower: { id: "wilted_flower", name: "Wilted Flower", keywords: ["plant", "nature", "rose"], skins: [{ unified: "1f940", native: "\u{1F940}" }], version: 3 }, hibiscus: { id: "hibiscus", name: "Hibiscus", keywords: ["plant", "vegetable", "flowers", "beach"], skins: [{ unified: "1f33a", native: "\u{1F33A}" }
51763], version: 1 }, sunflower: { id: "sunflower", name: "Sunflower", keywords: ["nature", "plant", "fall"], skins: [{ unified: "1f33b", native: "\u{1F33B}" }], version: 1 }, blossom: { id: "blossom", name: "Blossom", keywords: ["nature", "flowers", "yellow"], skins: [{ unified: "1f33c", native: "\u{1F33C}" }], version: 1 }, tulip: { id: "tulip", name: "Tulip", keywords: ["flowers", "plant", "nature", "summer", "spring"], skins: [{ unified: "1f337", native: "\u{1F337}" }], version: 1 }, hyacinth: { id: "hyacinth", name: "Hyacinth", keywords: ["flower", "lavender"], skins: [{ unified: "1fabb", native: "\u{1FABB}" }], version: 15 }, seedling: { id: "seedling", name: "Seedling", keywords: ["plant", "nature", "grass", "lawn", "spring"], skins: [{ unified: "1f331", native: "\u{1F331}" }], version: 1 }, potted_plant: { id: "potted_plant", name: "Potted Plant", keywords: ["greenery", "house"], skins: [{ unified: "1fab4", native: "\u{1FAB4}" }], version: 13 }, evergreen_tree: { id: "evergreen_tree", name: "Evergreen Tree", keywords: ["plant", "nature"], skins: [{ unified: "1f332", native: "\u{1F332}" }], version: 1 }, deciduous_tree: { id: "deciduous_tree", name: "Deciduous Tree", keywords: ["plant", "nature"], skins: [{ unified: "1f333", native: "\u{1F333}" }], version: 1 }, palm_tree: { id: "palm_tree", name: "Palm Tree", keywords: ["plant", "vegetable", "nature", "summer", "beach", "mojito", "tropical"], skins: [{ unified: "1f334", native: "\u{1F334}" }], version: 1 }, cactus: { id: "cactus", name: "Cactus", keywords: ["vegetable", "plant", "nature"], skins: [{ unified: "1f335", native: "\u{1F335}" }], version: 1 }, ear_of_rice: { id: "ear_of_rice", name: "Ear of Rice", keywords: ["sheaf", "nature", "plant"], skins: [{ unified: "1f33e", native: "\u{1F33E}" }], version: 1 }, herb: { id: "herb", name: "Herb", keywords: ["vegetable", "plant", "medicine", "weed", "grass", "lawn"], skins: [{ unified: "1f33f", native: "\u{1F33F}" }], version: 1 }, shamrock: { id: "shamrock", name: "Shamrock", keywords: ["vegetable", "plant", "nature", "irish", "clover"], skins: [{ unified: "2618-fe0f", native: "\u2618\uFE0F" }], version: 1 }, four_leaf_clover: { id: "four_leaf_clover", name: "Four Leaf Clover", keywords: ["vegetable", "plant", "nature", "lucky", "irish"], skins: [{ unified: "1f340", native: "\u{1F340}" }], version: 1 }, maple_leaf: { id: "maple_leaf", name: "Maple Leaf", keywords: ["nature", "plant", "vegetable", "ca", "fall"], skins: [{ unified: "1f341", native: "\u{1F341}" }], version: 1 }, fallen_leaf: { id: "fallen_leaf", name: "Fallen Leaf", keywords: ["nature", "plant", "vegetable", "leaves"], skins: [{ unified: "1f342", native: "\u{1F342}" }], version: 1 }, leaves: { id: "leaves", name: "Leaf Fluttering in Wind", keywords: ["leaves", "nature", "plant", "tree", "vegetable", "grass", "lawn", "spring"], skins: [{ unified: "1f343", native: "\u{1F343}" }], version: 1 }, empty_nest: { id: "empty_nest", name: "Empty Nest", keywords: ["bird"], skins: [{ unified: "1fab9", native: "\u{1FAB9}" }], version: 14 }, nest_with_eggs: { id: "nest_with_eggs", name: "Nest with Eggs", keywords: ["bird"], skins: [{ unified: "1faba", native: "\u{1FABA}" }], version: 14 }, mushroom: { id: "mushroom", name: "Mushroom", keywords: ["plant", "vegetable"], skins: [{ unified: "1f344", native: "\u{1F344}" }], version: 1 }, leafless_tree: { id: "leafless_tree", name: "Leafless Tree", keywords: [], skins: [{ unified: "1fabe", native: "\u{1FABE}" }], version: 16 }, grapes: { id: "grapes", name: "Grapes", keywords: ["fruit", "food", "wine"], skins: [{ unified: "1f347", native: "\u{1F347}" }], version: 1 }, melon: { id: "melon", name: "Melon", keywords: ["fruit", "nature", "food"], skins: [{ unified: "1f348", native: "\u{1F348}" }], version: 1 }, watermelon: { id: "watermelon", name: "Watermelon", keywords: ["fruit", "food", "picnic", "summer"], skins: [{ unified: "1f349", native: "\u{1F349}" }], version: 1 }, tangerine: { id: "tangerine", name: "Tangerine", keywords: ["food", "fruit", "nature", "orange"], skins: [{ unified: "1f34a", native: "\u{1F34A}" }], version: 1 }, lemon: { id: "lemon", name: "Lemon", keywords: ["fruit", "nature"], skins: [{ unified: "1f34b", native: "\u{1F34B}" }], version: 1 }, lime: { id: "lime", name: "Lime", keywords: ["fruit", "acidic", "citric"], skins: [{ unified: "1f34b-200d-1f7e9", native: "\u{1F34B}\u200D\u{1F7E9}" }], version: 15.1 }, banana: { id: "banana", name: "Banana", keywords: ["fruit", "food", "monkey"], skins: [{ unified: "1f34c", native: "\u{1F34C}" }], version: 1 }, pineapple: { id: "pineapple", name: "Pineapple", keywords: ["fruit", "nature", "food"], skins: [{ unified: "1f34d", native: "\u{1F34D}" }], version: 1 }, mango: { id: "mango", name: "Mango", keywords: ["fruit", "food", "tropical"], skins: [{ unified: "1f96d", native: "\u{1F96D}" }], version: 11 }, apple: { id: "apple", name: "Red Apple", keywords: ["fruit", "mac", "school"], skins: [{ unified: "1f34e", native: "\u{1F34E}" }], version: 1 }, green_apple: { id: "green_apple", name: "Green Apple", keywords: ["fruit", "nature"], skins: [{ unified: "1f34f", native: "\u{1F34F}" }], version: 1 }, pear: { id: "pear", name: "Pear", keywords: ["fruit", "nature", "food"], skins: [{ unified: "1f350", native: "\u{1F350}" }], version: 1 }, peach: { id: "peach", name: "Peach", keywords: ["fruit", "nature", "food"], skins: [{ unified: "1f351", native: "\u{1F351}" }], version: 1 }, cherries: { id: "cherries", name: "Cherries", keywords: ["food", "fruit"], skins: [{ unified: "1f352", native: "\u{1F352}" }
51763], version: 1 }, strawberry: { id: "strawberry", name: "Strawberry", keywords: ["fruit", "food", "nature"], skins: [{ unified: "1f353", native: "\u{1F353}" }], version: 1 }, blueberries: { id: "blueberries", name: "Blueberries", keywords: ["fruit"], skins: [{ unified: "1fad0", native: "\u{1FAD0}" }], version: 13 }, kiwifruit: { id: "kiwifruit", name: "Kiwifruit", keywords: ["kiwi", "fruit", "food"], skins: [{ unified: "1f95d", native: "\u{1F95D}" }], version: 3 }, tomato: { id: "tomato", name: "Tomato", keywords: ["fruit", "vegetable", "nature", "food"], skins: [{ unified: "1f345", native: "\u{1F345}" }], version: 1 }, olive: { id: "olive", name: "Olive", keywords: ["fruit"], skins: [{ unified: "1fad2", native: "\u{1FAD2}" }], version: 13 }, coconut: { id: "coconut", name: "Coconut", keywords: ["fruit", "nature", "food", "palm"], skins: [{ unified: "1f965", native: "\u{1F965}" }], version: 5 }, avocado: { id: "avocado", name: "Avocado", keywords: ["fruit", "food"], skins: [{ unified: "1f951", native: "\u{1F951}" }], version: 3 }, eggplant: { id: "eggplant", name: "Eggplant", keywords: ["vegetable", "nature", "food", "aubergine"], skins: [{ unified: "1f346", native: "\u{1F346}" }], version: 1 }, potato: { id: "potato", name: "Potato", keywords: ["food", "tuber", "vegatable", "starch"], skins: [{ unified: "1f954", native: "\u{1F954}" }], version: 3 }, carrot: { id: "carrot", name: "Carrot", keywords: ["vegetable", "food", "orange"], skins: [{ unified: "1f955", native: "\u{1F955}" }], version: 3 }, corn: { id: "corn", name: "Ear of Corn", keywords: ["food", "vegetable", "plant"], skins: [{ unified: "1f33d", native: "\u{1F33D}" }], version: 1 }, hot_pepper: { id: "hot_pepper", name: "Hot Pepper", keywords: ["food", "spicy", "chilli", "chili"], skins: [{ unified: "1f336-fe0f", native: "\u{1F336}\uFE0F" }], version: 1 }, bell_pepper: { id: "bell_pepper", name: "Bell Pepper", keywords: ["fruit", "plant"], skins: [{ unified: "1fad1", native: "\u{1FAD1}" }], version: 13 }, cucumber: { id: "cucumber", name: "Cucumber", keywords: ["fruit", "food", "pickle"], skins: [{ unified: "1f952", native: "\u{1F952}" }], version: 3 }, leafy_green: { id: "leafy_green", name: "Leafy Green", keywords: ["food", "vegetable", "plant", "bok", "choy", "cabbage", "kale", "lettuce"], skins: [{ unified: "1f96c", native: "\u{1F96C}" }], version: 11 }, broccoli: { id: "broccoli", name: "Broccoli", keywords: ["fruit", "food", "vegetable"], skins: [{ unified: "1f966", native: "\u{1F966}" }], version: 5 }, garlic: { id: "garlic", name: "Garlic", keywords: ["food", "spice", "co
51763ok"], skins: [{ unified: "1f9c4", native: "\u{1F9C4}" }], version: 12 }, onion: { id: "onion", name: "Onion", keywords: ["cook", "food", "spice"], skins: [{ unified: "1f9c5", native: "\u{1F9C5}" }], version: 12 }, peanuts: { id: "peanuts", name: "Peanuts", keywords: ["food", "nut"], skins: [{ unified: "1f95c", native: "\u{1F95C}" }], version: 3 }, beans: { id: "beans", name: "Beans", keywords: ["food"], skins: [{ unified: "1fad8", native: "\u{1FAD8}" }], version: 14 }, chestnut: { id: "chestnut", name: "Chestnut", keywords: ["food", "squirrel"], skins: [{ unified: "1f330", native: "\u{1F330}" }], version: 1 }, ginger_root: { id: "ginger_root", name: "Ginger Root", keywords: ["spice", "yellow", "cooking", "gingerbread"], skins: [{ unified: "1fada", native: "\u{1FADA}" }], version: 15 }, pea_pod: { id: "pea_pod", name: "Pea Pod", keywords: ["cozy", "green"], skins: [{ unified: "1fadb", native: "\u{1FADB}" }], version: 15 }, brown_mushroom: { id: "brown_mushroom", name: "Brown Mushroom", keywords: ["toadstool", "fungus"], skins: [{ unified: "1f344-200d-1f7eb", native: "\u{1F344}\u200D\u{1F7EB}" }], version: 15.1 }, root_vegetable: { id: "root_vegetable", name: "Root Vegetable", keywords: [], skins: [{ unified: "1fadc", native: "\u{1FADC}" }], version: 16 }, bread: { id: "bread", name: "Bread", keywords: ["food", "wheat", "breakfast", "toast"], skins: [{ unified: "1f35e", native: "\u{1F35E}" }], version: 1 }, croissant: { id: "croissant", name: "Croissant", keywords: ["food", "bread", "french"], skins: [{ unified: "1f950", native: "\u{1F950}" }], version: 3 }, baguette_bread: { id: "baguette_bread", name: "Baguette Bread", keywords: ["food", "french", "france", "bakery"], skins: [{ unified: "1f956", native: "\u{1F956}" }], version: 3 }, flatbread: { id: "flatbread", name: "Flatbread", keywords: ["flour", "food", "bakery"], skins: [{ unified: "1fad3", native: "\u{1FAD3}" }], version: 13 }, pretzel: { id: "pretzel", name: "Pretzel", keywords: ["food", "bread", "twisted", "germany", "bakery"], skins: [{ unified: "1f968", native: "\u{1F968}" }], version: 5 }, bagel: { id: "bagel", name: "Bagel", keywords: ["food", "bread", "bakery", "schmear", "jewish"], skins: [{ unified: "1f96f", native: "\u{1F96F}" }], version: 11 }, pancakes: { id: "pancakes", name: "Pancakes", keywords: ["food", "breakfast", "flapjacks", "hotcakes", "brunch"], skins: [{ unified: "1f95e", native: "\u{1F95E}" }], version: 3 }, waffle: { id: "waffle", name: "Waffle", keywords: ["food", "breakfast", "brunch"], skins: [{ unified: "1f9c7", native: "\u{1F9C7}" }], version: 12 }, cheese_wedge: { id: "cheese_wedge", name: "Cheese Wedge", keywords: ["food", "chadder", "swiss"], skins: [{ unified: "1f9c0", native: "\u{1F9C0}" }], version: 1 }, meat_on_bone: { id: "meat_on_bone", name: "Meat on Bone", keywords: ["good", "food", "drumstick"], skins: [{ unified: "1f356", native: "\u{1F356}" }], version: 1 }, poultry_leg: { id: "poultry_leg", name: "Poultry Leg", keywords: ["food", "meat", "drumstick", "bird", "chicken", "turkey"], skins: [{ unified: "1f357", native: "\u{1F357}" }], version: 1 }, cut_of_meat: { id: "cut_of_meat", name: "Cut of Meat", keywords: ["food", "cow", "chop", "lambchop", "porkchop"], skins: [{ unified: "1f969", native: "\u{1F969}" }], version: 5 }, bacon: { id: "bacon", name: "Bacon", keywords: ["food", "breakfast", "pork", "pig", "meat", "brunch"], skins: [{ unified: "1f953", native: "\u{1F953}" }], version: 3 }, hamburger: { id: "hamburger", name: "Hamburger", keywords: ["meat", "fast", "food", "beef", "cheeseburger", "mcdonalds", "burger", "king"], skins: [{ unified: "1f354", native: "\u{1F354}" }], version: 1 }, fries: { id: "fries", name: "French Fries", keywords: ["chips", "snack", "fast", "food", "potato"], skins: [{ unified: "1f35f", native: "\u{1F35F}" }], version: 1 }, pizza: { id: "pizza", name: "Pizza", keywords: ["food", "party", "italy"], skins: [{ unified: "1f355", native: "\u{1F355}" }], version: 1 }, hotdog: { id: "hotdog", name: "Hot Dog", keywords: ["hotdog", "food", "frankfurter", "america"], skins: [{ unified: "1f32d", native: "\u{1F32D}" }], version: 1 }, sandwich: { id: "sandwich", name: "Sandwich", keywords: ["food", "lunch", "bread", "toast", "bakery"], skins: [{ unified: "1f96a", native: "\u{1F96A}" }], version: 5 }, taco: { id: "taco", name: "Taco", keywords: ["food", "mexican"], skins: [{ unified: "1f32e", native: "\u{1F32E}" }], version: 1 }, burrito: { id: "burrito", name: "Burrito", keywords: ["food", "mexican"], skins: [{ unified: "1f32f", native: "\u{1F32F}" }], version: 1 }, tamale: { id: "tamale", name: "Tamale", keywords: ["food", "masa"], skins: [{ unified: "1fad4", native: "\u{1FAD4}" }], version: 13 }, stuffed_flatbread: { id: "stuffed_flatbread", name: "Stuffed Flatbread", keywords: ["food", "gyro", "mediterranean"], skins: [{ unified: "1f959", native: "\u{1F959}" }], version: 3 }, falafel: { id: "falafel", name: "Falafel", keywords: ["food", "mediterranean"], skins: [{ unified: "1f9c6", native: "\u{1F9C6}" }], version: 12 }, egg: { id: "egg", name: "Egg", keywords: ["food", "chicken", "breakfast"], skins: [{ unified: "1f95a", native: "\u{1F95A}" }], version: 3 }, fried_egg: { id: "fried_egg", name: "Cooking", keywords: ["fried", "egg", "food", "breakfast", "kitchen", "skillet"], skins: [{ unified: "1f373", native: "\u{1F373}" }], version: 1 }, shallow_pan_of_food: { id: "shallow_pan_of_food", name: "Shallow Pan of Food", keywords: ["cooking", "casserole", "paella", "skillet"], skins: [{ unified: "1f958", native: "\u{1F958}" }], version: 3 }, stew: { id: "stew", name: "Pot of Food", keywords: ["stew", "meat", "soup", "hot"], skins: [{ unified: "1f372", native: "\u{1F372}" }], version: 1 }, fondue: { id: "fondue", name: "Fondue", keywords: ["cheese", "pot", "food"], skins: [{ unified: "1fad5", native: "\u{1FAD5}" }], version: 13 }, bowl_with_spoon: { id: "bowl_with_spoon", name: "Bowl with Spoon", keywords: ["food", "breakfast", "cereal", "oatmeal", "porridge"], skins: [{ unified: "1f963", native: "\u{1F963}" }], version: 5 }, green_salad: { id: "green_salad", name: "Green Salad", keywords: ["food", "healthy", "lettuce", "vegetable"], skins: [{ unified: "1f957", native: "\u{1F957}" }], version: 3 }, popcorn: { id: "popcorn", name: "Popcorn", keywords: ["food", "movie", "theater", "films", "snack", "drama"], skins: [{ unified: "1f37f", native: "\u{1F37F}" }], version: 1 }, butter: { id: "butter", name: "Butter", keywords: ["food", "cook"], skins: [{ unified: "1f9c8", native: "\u{1F9C8}" }], version: 12 }, salt: { id: "salt", name: "Salt", keywords: ["condiment", "shaker"], skins: [{ unified: "1f9c2", native: "\u{1F9C2}" }], version: 11 }, canned_food: { id: "canned_food", name: "Canned Food", keywords: ["soup", "tomatoes"], skins: [{ unified: "1f96b", native: "\u{1F96B}" }], version: 5 }, bento: { id: "bento", name: "Bento Box", keywords: ["food", "japanese", "lunch"], skins: [{ unified: "1f371", native: "\u{1F371}" }], version: 1 }, rice_cracker: { id: "rice_cracker", name: "Rice Cracker", keywords: ["food", "japanese", "snack", "senbei"], skins: [{ unified: "1f358", native: "\u{1F358}" }], version: 1 }, rice_ball: { id: "rice_ball", name: "Rice Ball", keywords: ["food", "japanese", "onigiri", "omusubi"], skins: [{ unified: "1f359", native: "\u{1F359}" }], version: 1 }, rice: { id: "rice", name: "Cooked Rice", keywords: ["food", "asian"], skins: [{ unified: "1f35a", native: "\u{1F35A}" }], version: 1 }, curry: { id: "curry", name: "Curry Rice", keywords: ["food", "spicy", "hot", "indian"], skins: [{ unified: "1f35b", native: "\u{1F35B}" }], version: 1 }, ramen: { id: "ramen", name: "Steaming Bowl", keywords: ["ramen", "food", "japanese", "noodle", "chopsticks"], skins: [{ unified: "1f35c", native: "\u{1F35C}" }], version: 1 }, spaghetti: { id: "spaghetti", name: "Spaghetti", keywords: ["food", "italian", "pasta", "noodle"], skins: [{ unified: "1f35d", native: "\u{1F35D}" }], version: 1 }, sweet_potato: { id: "sweet_potato", name: "Roasted Sweet Potato", keywords: ["food", "nature", "plant"], skins: [{ unified: "1f360", native: "\u{1F360}" }], version: 1 }, oden: { id: "oden", name: "Oden", keywords: ["skewer", "food", "japanese"], skins: [{ unified: "1f362", native: "\u{1F362}" }], version: 1 }, sushi: { id: "sushi", name: "Sushi", keywords: ["food", "fish", "japanese", "rice"], skins: [{ unified: "1f363", native: "\u{1F363}" }], version: 1 }, fried_shrimp: { id: "fried_shrimp", name: "Fried Shrimp", keywords: ["food", "animal", "appetizer", "summer"], skins: [{ unified: "1f364", native: "\u{1F364}" }], version: 1 }, fish_cake: { id: "fish_cake", name: "Fish Cake with Swirl", keywords: ["food", "japan", "sea", "beach", "narutomaki", "pink", "kamaboko", "surimi", "ramen"], skins: [{ unified: "1f365", native: "\u{1F365}" }], version: 1 }, moon_cake: { id: "moon_cake", name: "Moon Cake", keywords: ["food", "autumn", "dessert"], skins: [{ unified: "1f96e", native: "\u{1F96E}" }], version: 11 }, dango: { id: "dango", name: "Dango", keywords: ["food", "dessert", "sweet", "japanese", "barbecue", "meat"], skins: [{ unified: "1f361", native: "\u{1F361}" }], version: 1 }, dumpling: { id: "dumpling", name: "Dumpling", keywords: ["food", "empanad
51763a", "pierogi", "potsticker", "gyoza"], skins: [{ unified: "1f95f", native: "\u{1F95F}" }], version: 5 }, fortune_cookie: { id: "fortune_cookie", name: "Fortune Cookie", keywords: ["food", "prophecy", "dessert"], skins: [{ unified: "1f960", native: "\u{1F960}" }], version: 5 }, takeout_box: { id: "takeout_box", name: "Takeout Box", keywords: ["food", "leftovers"], skins: [{ unified: "1f961", native: "\u{1F961}" }], version: 5 }, icecream: { id: "icecream", name: "Soft Ice Cream", keywords: ["icecream", "food", "hot", "dessert", "summer"], skins: [{ unified: "1f366", native: "\u{1F366}" }], version: 1 }, shaved_ice: { id: "shaved_ice", name: "Shaved Ice", keywords: ["hot", "dessert", "summer"], skins: [{ unified: "1f367", native: "\u{1F367}" }], version: 1 }, ice_cream: { id: "ice_cream", name: "Ice Cream", keywords: ["food", "hot", "dessert"], skins: [{ unified: "1f368", native: "\u{1F368}" }], version: 1 }, doughnut: { id: "doughnut", name: "Doughnut", keywords: ["food", "dessert", "snack", "sweet", "donut"], skins: [{ unified: "1f369", native: "\u{1F369}" }], version: 1 }, cookie: { id: "cookie", name: "Cookie", keywords: ["food", "snack", "oreo", "chocolate", "sweet", "dessert"], skins: [{ unified: "1f36a", native: "\u{1F36A}" }], version: 1 }, birthday: { id: "birthday", name: "Birthday Cake", keywords: ["food", "dessert"], skins: [{ unified: "1f382", native: "\u{1F382}" }], version: 1 }, cake: { id: "cake", name: "Shortcake", keywords: ["cake", "food", "dessert"], skins: [{ unified: "1f370", native: "\u{1F370}" }], version: 1 }, cupcake: { id: "cupcake", name: "Cupcake", keywords: ["food", "dessert", "bakery", "sweet"], skins: [{ unified: "1f9c1", native: "\u{1F9C1}" }], version: 11 }, pie: { id: "pie", name: "Pie", keywords: ["food", "dessert", "pastry"], skins: [{ unified: "1f967", native: "\u{1F967}" }], version: 5 }, chocolate_bar: { id: "chocolate_bar", name: "Chocolate Bar", keywords: ["food", "snack", "dessert", "sweet"], skins: [{ unified: "1f36b", native: "\u{1F36B}" }], version: 1 }, candy: { id: "candy", name: "Candy", keywords: ["snack", "dessert", "sweet", "lolly"], skins: [{ unified: "1f36c", native: "\u{1F36C}" }], version: 1 }, lollipop: { id: "lollipop", name: "Lollipop", keywords: ["food", "snack", "candy", "sweet"], skins: [{ unified: "1f36d", native: "\u{1F36D}" }], version: 1 }, custard: { id: "custard", name: "Custard", keywords: ["dessert", "food", "pudding", "flan"], skins: [{ unified: "1f36e", native: "\u{1F36E}" }], version: 1 }, honey_pot: { id: "honey_pot", name: "Honey Pot", keywords: ["bees", "sweet", "kitchen"], skins: [{ unified: "1f36f", native: "\u{1F36F}" }], version: 1 }, baby_bottle: { id: "baby_bottle", name: "Baby Bottle", keywords: ["food", "container", "milk"], skins: [{ unified: "1f37c", native: "\u{1F37C}" }], version: 1 }, glass_of_milk: { id: "glass_of_milk", name: "Glass of Milk", keywords: ["beverage", "drink", "cow"], skins: [{ unified: "1f95b", native: "\u{1F95B}" }], version: 3 }, coffee: { id: "coffee", name: "Hot Beverage", keywords: ["coffee", "caffeine", "latte", "espresso", "mug"], skins: [{ unified: "2615", native: "\u2615" }], version: 1 }, teapot: { id: "teapot", name: "Teapot", keywords: ["drink", "hot"], skins: [{ unified: "1fad6", native: "\u{1FAD6}" }], version: 13 }, tea: { id: "tea", name: "Teacup Without Handle", keywords: ["tea", "drink", "bowl", "breakfast", "green", "british"], skins: [{ unified: "1f375", native: "\u{1F375}" }], version: 1 }, sake: { id: "sake", name: "Sake", keywords: ["wine", "drink", "drunk", "beverage", "japanese", "alcohol", "booze"], skins: [{ unified: "1f376", native: "\u{1F376}" }], version: 1 }, champagne: { id: "champagne", name: "Bottle with Popping Cork", keywords: ["champagne", "drink", "wine", "celebration"], skins: [{ unified: "1f37e", native: "\u{1F37E}" }], version: 1 }, wine_glass: { id: "wine_glass", name: "Wine Glass", keywords: ["drink", "beverage", "drunk", "alcohol", "booze"], skins: [{ unified: "1f377", native: "\u{1F377}" }], version: 1 }, cocktail: { id: "cocktail", name: "Cocktail Glass", keywords: ["drink", "drunk", "alcohol", "beverage", "booze", "mojito"], skins: [{ unified: "1f378", native: "\u{1F378}" }], version: 1 }, tropical_drink: { id: "tropical_drink", name: "Tropical Drink", keywords: ["beverage", "cocktail", "summer", "beach", "alcohol", "booze", "mojito"], skins: [{ unified: "1f379", native: "\u{1F379}" }], version: 1 }, beer: { id: "beer", name: "Beer Mug", keywords: ["relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze"], skins: [{ unified: "1f37a", native: "\u{1F37A}" }], version: 1 }, beers: { id: "beers", name: "Clinking Beer Mugs", keywords: ["beers", "relax", "beverage", "drink", "drunk", "party", "pub", "summer", "alcohol", "booze"], skins: [{ unified: "1f37b", native: "\u{1F37B}" }], version: 1 }, clinking_glasses: { id: "clinking_glasses", name: "Clinking Glasses", keywords: ["beverage", "drink", "party", "alcohol", "celebrate", "cheers", "wine", "champagne", "toast"], skins: [{ unified: "1f942", native: "\u{1F942}" }], version: 3 }, tumbler_glass: { id: "tumbler_glass", name: "Tumbler Glass", keywords: ["drink", "beverage", "drunk", "alcohol", "liquor", "booze", "bourbon", "scotch", "whisky", "shot"], skins: [{ unified: "1f943", native: "\u{1F943}" }], version: 3 }, pouring_liquid: { id: "pouring_liquid", name: "Pouring Liquid", keywords: ["cup", "water"], skins: [{ unified: "1fad7", native: "\u{1FAD7}" }], version: 14 }
51763, cup_with_straw: { id: "cup_with_straw", name: "Cup with Straw", keywords: ["drink", "soda"], skins: [{ unified: "1f964", native: "\u{1F964}" }], version: 5 }, bubble_tea: { id: "bubble_tea", name: "Bubble Tea", keywords: ["taiwan", "boba", "milk", "straw"], skins: [{ unified: "1f9cb", native: "\u{1F9CB}" }], version: 13 }, beverage_box: { id: "beverage_box", name: "Beverage Box", keywords: ["drink"], skins: [{ unified: "1f9c3", native: "\u{1F9C3}" }], version: 12 }, mate_drink: { id: "mate_drink", name: "Mate", keywords: ["drink", "tea", "beverage"], skins: [{ unified: "1f9c9", native: "\u{1F9C9}" }], version: 12 }, ice_cube: { id: "ice_cube", name: "Ice", keywords: ["cube", "water", "cold"], skins: [{ unified: "1f9ca", native: "\u{1F9CA}" }], version: 12 }, chopsticks: { id: "chopsticks", name: "Chopsticks", keywords: ["food"], skins: [{ unified: "1f962", native: "\u{1F962}" }], version: 5 }, knife_fork_plate: { id: "knife_fork_plate", name: "Fork and Knife with Plate", keywords: ["food", "eat", "meal", "lunch", "dinner", "restaurant"], skins: [{ unified: "1f37d-fe0f", native: "\u{1F37D}\uFE0F" }], version: 1 }, fork_and_knife: { id: "fork_and_knife", name: "Fork and Knife", keywords: ["cutlery", "kitchen"], skins: [{ unified: "1f374", native: "\u{1F374}" }], version: 1 }, spoon: { id: "spoon", name: "Spoon", keywords: ["cutlery", "kitchen", "tableware"], skins: [{ unified: "1f944", native: "\u{1F944}" }], version: 3 }, hocho: { id: "hocho", name: "Hocho", keywords: ["knife", "kitchen", "blade", "cutlery", "weapon"], skins: [{ unified: "1f52a", native: "\u{1F52A}" }], version: 1 }, jar: { id: "jar", name: "Jar", keywords: ["container", "sauce"], skins: [{ unified: "1fad9", native: "\u{1FAD9}" }], version: 14 }, amphora: { id: "amphora", name: "Amphora", keywords: ["vase", "jar"], skins: [{ unified: "1f3fa", native: "\u{1F3FA}" }], version: 1 }, earth_africa: { id: "earth_africa", name: "Earth Globe Europe-Africa", keywords: ["africa", "showing", "europe", "world", "international"], skins: [{ unified: "1f30d", native: "\u{1F30D}" }], version: 1 }, earth_americas: { id: "earth_americas", name: "Earth Globe Americas", keywords: ["showing", "world", "USA", "international"], skins: [{ unified: "1f30e", native: "\u{1F30E}" }], version: 1 }, earth_asia: { id: "earth_asia", name: "Earth Globe Asia-Australia", keywords: ["asia", "showing", "australia", "world", "east", "international"], skins: [{ unified: "1f30f", native: "\u{1F30F}" }], version: 1 }, globe_with_meridians: { id: "globe_with_meridians", name: "Globe with Meridians", keywords: ["earth", "international", "world", "internet", "interweb", "i18n"], skins: [{ unified: "1f310", native: "\u{1F310}" }], version: 1 }, world_map: { id: "world_map", name: "World Map", keywords: ["location", "direction"], skins: [{ unified: "1f5fa-fe0f", native: "\u{1F5FA}\uFE0F" }], version: 1 }, japan: { id: "japan", name: "Map of Japan", keywords: ["nation", "country", "japanese", "asia"], skins: [{ unified: "1f5fe", native: "\u{1F5FE}" }], version: 1 }, compass: { id: "compass", name: "Compass", keywords: ["magnetic", "navigation", "orienteering"], skins: [{ unified: "1f9ed", native: "\u{1F9ED}" }], version: 11 }, snow_capped_mountain: { id: "snow_capped_mountain", name: "Snow-Capped Mountain", keywords: ["snow", "capped", "photo", "nature", "environment", "winter", "cold"], skins: [{ unified: "1f3d4-fe0f", native: "\u{1F3D4}\uFE0F" }], version: 1 }, mountain: { id: "mountain", name: "Mountain", keywords: ["photo", "nature", "environment"], skins: [{ unified: "26f0-fe0f", native: "\u26F0\uFE0F" }], version: 1 }, volcano: { id: "volcano", name: "Volcano", keywords: ["photo", "nature", "disaster"], skins: [{ unified: "1f30b", native: "\u{1F30B}" }], version: 1 }, mount_fuji: { id: "mount_fuji", name: "Mount Fuji", keywords: ["photo", "mountain", "nature", "japanese"], skins: [{ unified: "1f5fb", native: "\u{1F5FB}" }], version: 1 }, camping: { id: "camping", name: "Camping", keywords: ["photo", "outdoors", "tent"], skins: [{ unified: "1f3d5-fe0f", native: "\u{1F3D5}\uFE0F" }], version: 1 }, beach_with_umbrella: { id: "beach_with_umbrella", name: "Beach with Umbrella", keywords: ["weather", "summer", "sunny", "sand", "mojito"], skins: [{ unified: "1f3d6-fe0f", native: "\u{1F3D6}\uFE0F" }], version: 1 }, desert: { id: "desert", name: "Desert", keywords: ["photo", "warm", "saharah"], skins: [{ unified: "1f3dc-fe0f", native: "\u{1F3DC}\uFE0F" }], version: 1 }, desert_island: { id: "desert_island", name: "Desert Island", keywords: ["photo", "tropical", "mojito"], skins: [{ unified: "1f3dd-fe0f", native: "\u{1F3DD}\uFE0F" }], version: 1 }, national_park: { id: "national_park", name: "National Park", keywords: ["photo", "environment", "nature"], skins: [{ unified: "1f3de-fe0f", native: "\u{1F3DE}\uFE0F" }], version: 1 }, stadium: { id: "stadium", name: "Stadium", keywords: ["photo", "place", "sports", "concert", "venue"], skins: [{ unified: "1f3df-fe0f", native: "\u{1F3DF}\uFE0F" }], version: 1 }, classical_building: { id: "classical_building", name: "Classical Building", keywords: ["art", "culture", "history"], skins: [{ unified: "1f3db-fe0f", native: "\u{1F3DB}\uFE0F" }], version: 1 }, building_construction: { id: "building_construction", name: "Building Construction", keywords: ["wip", "working", "progress"], skins: [{ unified: "1f3d7-fe0f", native: "\u{1F3D7}\uFE0F" }], version: 1 }, bricks: { id: "bricks", name: "Brick", keywords: ["bricks"], skins: [{ unified: "1f9f1", native: "\u{1F9F1}" }], version: 11 }, rock: { id: "rock", name: "Rock", keywords: ["stone"], skins: [{ unified: "1faa8", native: "\u{1FAA8}" }
51763], version: 13 }, wood: { id: "wood", name: "Wood", keywords: ["nature", "timber", "trunk"], skins: [{ unified: "1fab5", native: "\u{1FAB5}" }], version: 13 }, hut: { id: "hut", name: "Hut", keywords: ["house", "structure"], skins: [{ unified: "1f6d6", native: "\u{1F6D6}" }], version: 13 }, house_buildings: { id: "house_buildings", name: "Houses", keywords: ["house", "buildings", "photo"], skins: [{ unified: "1f3d8-fe0f", native: "\u{1F3D8}\uFE0F" }], version: 1 }, derelict_house_building: { id: "derelict_house_building", name: "Derelict House", keywords: ["building", "abandon", "evict", "broken"], skins: [{ unified: "1f3da-fe0f", native: "\u{1F3DA}\uFE0F" }], version: 1 }, house: { id: "house", name: "House", keywords: ["building", "home"], skins: [{ unified: "1f3e0", native: "\u{1F3E0}" }], version: 1 }, house_with_garden: { id: "house_with_garden", name: "House with Garden", keywords: ["home", "plant", "nature"], skins: [{ unified: "1f3e1", native: "\u{1F3E1}" }], version: 1 }, office: { id: "office", name: "Office Building", keywords: ["bureau", "work"], skins: [{ unified: "1f3e2", native: "\u{1F3E2}" }], version: 1 }, post_office: { id: "post_office", name: "Japanese Post Office", keywords: ["building", "envelope", "communication"], skins: [{ unified: "1f3e3", native: "\u{1F3E3}" }], version: 1 }, european_post_office: { id: "european_post_office", name: "Post Office", keywords: ["european", "building", "email"], skins: [{ unified: "1f3e4", native: "\u{1F3E4}" }], version: 1 }, hospital: { id: "hospital", name: "Hospital", keywords: ["building", "health", "surgery", "doctor"], skins: [{ unified: "1f3e5", native: "\u{1F3E5}" }], version: 1 }, bank: { id: "bank", name: "Bank", keywords: ["building", "money", "sales", "cash", "business", "enterprise"], skins: [{ unified: "1f3e6", native: "\u{1F3E6}" }], version: 1 }, hotel: { id: "hotel", name: "Hotel", keywords: ["building", "accomodation", "checkin"], skins: [{ unified: "1f3e8", native: "\u{1F3E8}" }], version: 1 }, love_hotel: { id: "love_hotel", name: "Love Hotel", keywords: ["like", "affection", "dating"], skins: [{ unified: "1f3e9", native: "\u{1F3E9}" }], version: 1 }, convenience_store: { id: "convenience_store", name: "Convenience Store", keywords: ["building", "shopping", "groceries"], skins: [{ unified: "1f3ea", native: "\u{1F3EA}" }], version: 1 }, school: { id: "school", name: "School", keywords: ["building", "student", "education", "learn", "teach"], skins: [{ unified: "1f3eb", native: "\u{1F3EB}" }], version: 1 }, department_store: { id: "department_store", name: "Department Store", keywords: ["building", "shopping", "mall"], skins: [{ unified: "1f3ec", native: "\u{1F3EC}" }], version: 1 }, factory: { id: "factory", name: "Factory", keywords: ["building", "industry", "pollution", "smoke"], skins: [{ unified: "1f3ed", native: "\u{1F3ED}" }], version: 1 }, japanese_castle: { id: "japanese_castle", name: "Japanese Castle", keywords: ["photo", "building"], skins: [{ unified: "1f3ef", native: "\u{1F3EF}" }], version: 1 }, european_castle: { id: "european_castle", name: "Castle", keywords: ["european", "building", "royalty", "history"], skins: [{ unified: "1f3f0", native: "\u{1F3F0}" }], version: 1 }, wedding: { id: "wedding", name: "Wedding", keywords: ["love", "like", "affection", "couple", "marriage", "bride", "groom"], skins: [{ unified: "1f492", native: "\u{1F492}" }], version: 1 }, tokyo_tower: { id: "tokyo_tower", name: "Tokyo Tower", keywords: ["photo", "japanese"], skins: [{ unified: "1f5fc", native: "\u{1F5FC}" }], version: 1 }, statue_of_liberty: { id: "statue_of_liberty", name: "Statue of Liberty", keywords: ["american", "newyork"], skins: [{ unified: "1f5fd", native: "\u{1F5FD}" }], version: 1 }, church: { id: "church", name: "Church", keywords: ["building", "religion", "christ"], skins: [{ unified: "26ea", native: "\u26EA" }], version: 1 }, mosque: { id: "mosque", name: "Mosque", keywords: ["islam", "worship", "minaret"], skins: [{ unified: "1f54c", native: "\u{1F54C}" }], version: 1 }, hindu_temple: { id: "hindu_temple", name: "Hindu Temple", keywords: ["religion"], skins: [{ unified: "1f6d5", native: "\u{1F6D5}" }], version: 12 }, synagogue: { id: "synagogue", name: "Synagogue", keywords: ["judaism", "worship", "temple", "jewish"], skins: [{ unified: "1f54d", native: "\u{1F54D}" }], version: 1 }, shinto_shrine: { id: "shinto_shrine", name: "Shinto Shrine", keywords: ["temple", "japan", "kyoto"], skins: [{ unified: "26e9-fe0f", native: "\u26E9\uFE0F" }], version: 1 }, kaaba: { id: "kaaba", name: "Kaaba", keywords: ["mecca", "mosque", "islam"], skins: [{ unified: "1f54b", native: "\u{1F54B}" }], version: 1 }, fountain: { id: "fountain", name: "Fountain", keywords: ["photo", "summer", "water", "fresh"], skins: [{ unified: "26f2", native: "\u26F2" }], version: 1 }, tent: { id: "tent", name: "Tent", keywords: ["photo", "camping", "outdoors"], skins: [{ unified: "26fa", native: "\u26FA" }], version: 1 }, foggy: { id: "foggy", name: "Foggy", keywords: ["photo", "mountain"], skins: [{ unified: "1f301", native: "\u{1F301}" }], version: 1 }, night_with_stars: { id: "night_with_stars", name: "Night with Stars", keywords: ["evening", "city", "downtown"], skins: [{ unified: "1f303", native: "\u{1F303}" }], version: 1 }, cityscape: { id: "cityscape", name: "Cityscape", keywords: ["photo", "night", "life", "urban"], skins: [{ unified: "1f3d9-fe0f", native: "\u{1F3D9}\uFE0F" }], version: 1 }, sunrise_over_mountains: { id: "sunrise_over_mountains", name: "Sunrise over Mountains", keywords: ["view", "vacation", "photo"], skins: [{ unified: "1f304", native: "\u{1F304}" }], version: 1 }, sunrise: { id: "sunrise", name: "Sunrise", keywords: ["morning", "view", "vacation", "photo"], skins: [{ unified: "1f305", native: "\u{1F305}" }], version: 1 }, city_sunset: { id: "city_sunset", name: "Cityscape at Dusk", keywords: ["city", "sunset", "photo", "evening", "sky", "buildings"], skins: [{ unified: "1f306", native: "\u{1F306}" }], version: 1 }, city_sunrise: { id: "city_sunrise", name: "Sunset", keywords: ["city", "sunrise", "photo", "good", "morning", "dawn"], skins: [{ unified: "1f307", native: "\u{1F307}" }], version: 1 }, bridge_at_night: { id: "bridge_at_night", name: "Bridge at Night", keywords: ["photo", "sanfrancisco"], skins: [{ unified: "1f309", native: "\u{1F309}" }], version: 1 }, hotsprings: { id: "hotsprings", name: "Hot Springs", keywords: ["hotsprings", "bath", "warm", "relax"], skins: [{ unified: "2668-fe0f", native: "\u2668\uFE0F" }], version: 1 }, carousel_horse: { id: "carousel_horse", name: "Carousel Horse", keywords: ["photo", "carnival"], skins: [{ unified: "1f3a0", native: "\u{1F3A0}" }], version: 1 }, playground_slide: { id: "playground_slide", name: "Playground Slide", keywords: ["fun", "park"], skins: [{ unified: "1f6dd", native: "\u{1F6DD}" }], version: 14 }, ferris_wheel: { id: "ferris_wheel", name: "Ferris Wheel", keywords: ["photo", "carnival", "londoneye"], skins: [{ unified: "1f3a1", native: "\u{1F3A1}" }], version: 1 }, roller_coaster: { id: "roller_coaster", name: "Roller Coaster", keywords: ["carnival", "playground", "photo", "fun"], skins: [{ unified: "1f3a2", native: "\u{1F3A2}" }], version: 1 }, barber: { id: "barber", name: "Barber Pole", keywords: ["hair", "salon", "style"], skins: [{ unified: "1f488", native: "\u{1F488}" }], version: 1 }, circus_tent: { id: "circus_tent", name: "Circus Tent", keywords: ["festival", "carnival", "party"], skins: [{ unified: "1f3aa", native: "\u{1F3AA}" }], version: 1 }, steam_locomotive: { id: "steam_locomotive", name: "Locomotive", keywords: ["steam", "transportation", "vehicle", "train"], skins: [{ unified: "1f682", native: "\u{1F682}" }], version: 1 }, railway_car: { id: "railway_car", name: "Railway Car", keywords: ["transportation", "vehicle"], skins: [{ unified: "1f683", native: "\u{1F683}" }], version: 1 }, bullettrain_side: { id: "bullettrain_side", name: "High-Speed Train", keywords: ["bullettrain", "side", "high", "speed", "transportation", "vehicle"], skins: [{ unified: "1f684", native: "\u{1F684}" }], version: 1 }, bullettrain_front: { id: "bullettrain_front", name: "Bullet Train", keywords: ["bullettrain", "front", "transportation", "vehicle", "speed", "fast", "public", "travel"], skins: [{ unified: "1f685", native: "\u{1F685}" }], version: 1 }, train2: { id: "train2", name: "Train", keywords: ["train2", "transportation", "vehicle"], skins: [{ unified: "1f686", native: "\u{1F686}" }], version: 1 }, metro: { id: "metro", name: "Metro", keywords: ["transportation", "blue", "square", "mrt", "underground", "tube"], skins: [{ unified: "1f687", native: "\u{1F687}" }], version: 1 }, light_rail: { id: "light_rail", name: "Light Rail", keywords: ["transportation", "vehicle"], skins: [{ unified: "1f688", native: "\u{1F688}" }], version: 1 }, station: { id: "station", name: "Station", keywords: ["transportation", "vehicle", "public"], skins: [{ unified: "1f689", native: "\u{1F689}" }], version: 1 }, tram: { id: "tram", name: "Tram", keywords: ["transportation", "vehicle"], skins: [{ unified: "1f68a", native: "\u{1F68A}" }], version: 1 }, monorail: { id: "monorail", name: "Monorail", keywords: ["transportation", "vehicle"], skins: [{ unified: "1f69d", native: "\u{1F69D}" }], version: 1 }, mountain_railway: { id: "mountain_railway", name: "Mountain Railway", keywords: ["transportation", "vehicle"], skins: [{ unified: "1f69e", native: "\u{1F69E}" }], version: 1 }, train: { id: "train", name: "Tram Car", keywords: ["train", "transportation", "vehicle", "carriage", "public", "travel"], skins: [{ unified: "1f68b", native: "\u{1F68B}" }], version: 1 }, bus: { id: "bus", name: "Bus", keywords: ["car", "vehicle", "transportation"], skins: [{ unified: "1f68c", native: "\u{1F68C}" }], version: 1 }, oncoming_bus: { id: "oncoming_bus", name: "Oncoming Bus", keywords: ["vehicle", "transportation"], skins: [{ unified: "1f68d", native: "\u{1F68D}" }], version: 1 }, trolleybus: { id: "trolleybus", name: "Trolleybus", keywords: ["bart", "transportation", "vehicle"], skins: [{ unified: "1f68e", native: "\u{1F68E}" }], version: 1 }, minibus: { id: "minibus", name: "Minibus", keywords: ["vehicle", "car", "transportation"], skins: [{ unified: "1f690", native: "\u{1F690}" }], version: 1 }, ambulance: { id: "ambulance", name: "Ambulance", keywords: ["health", "911", "hospital"], skins: [{ unified: "1f691", native: "\u{1F691}" }], version: 1 }, fire_engine: { id: "fire_engine", name: "Fire Engine", keywords: ["transportation", "cars", "vehicle"], skins: [{ unified: "1f692", native: "\u{1F692}" }], version: 1 }, police_car: { id: "police_car", name: "Police Car", keywords: ["vehicle", "cars", "transportation", "law", "legal", "enforcement"], skins: [{ unified: "1f693", native: "\u{1F693}" }], version: 1 }, oncoming_police_car: { id: "oncoming_police_car", name: "Oncoming Police Car", keywords: ["vehicle", "law", "legal", "enforcement", "911"], skins: [{ unified: "1f694", native: "\u{1F694}" }], version: 1 }, taxi: { id: "taxi", name: "Taxi", keywords: ["uber", "vehicle", "cars", "transportation"], skins: [{ unified: "1f695", native: "\u{1F695}" }], version: 1 }, oncoming_taxi: { id: "oncoming_taxi", name: "Oncoming Taxi", keywords: ["vehicle", "cars", "uber"], skins: [{ unified: "1f696", native: "\u{1F696}" }], version: 1 }, car: { id: "car", name: "Automobile", keywords: ["car", "red", "transportation", "vehicle"], skins: [{ unified: "1f697", native: "\u{1F697}" }], version: 1 }, oncoming_automobile: { id: "oncoming_automobile", name: "Oncoming Automobile", keywords: ["car", "vehicle", "transportation"], skins: [{ unified: "1f698", native: "\u{1F698}" }], version: 1 }, blue_car: { id: "blue_car", name: "Recreational Vehicle", keywords: ["blue", "car", "sport", "utility", "transportation"], skins: [{ unified: "1f699", native: "\u{1F699}" }], version: 1 }, pickup_truck: { id: "pickup_truck", name: "Pickup Truck", keywords: ["car", "transportation"], skins: [{ unified: "1f6fb", native: "\u{1F6FB}" }], version: 13 }, truck: { id: "truck", name: "Delivery Truck", keywords: ["cars", "transportation"], skins: [{ unified: "1f69a", native: "\u{1F69A}" }], version: 1 }, articulated_lorry: { id: "articulated_lorry", name: "Articulated Lorry", keywords: ["vehicle", "cars", "transportation", "express"], skins: [{ unified: "1f69b", native: "\u{1F69B}" }], version: 1 }, tractor: { id: "tractor", name: "Tractor", keywords: ["vehicle", "car", "farming", "agriculture"], skins: [{ unified: "1f69c", native: "\u{1F69C}" }], version: 1 }, racing_car: { id: "racing_car", name: "Racing Car", keywords: ["sports", "race", "fast", "formula", "f1"], skins: [{ unified: "1f3ce-fe0f", native: "\u{1F3CE}\uFE0F" }], version: 1 }, racing_motorcycle: { id: "racing_motorcycle", name: "Motorcycle", keywords: ["racing", "race", "sports", "fast"], skins: [{ unified: "1f3cd-fe0f", native: "\u{1F3CD}\uFE0F" }], version: 1 }, motor_scooter: { id: "motor_scooter", name: "Motor Scooter", keywords: ["vehicle", "vespa", "sasha"], skins: [{ unified: "1f6f5", native: "\u{1F6F5}" }], version: 3 }, manual_wheelchair: { id: "manual_wheelchair", name: "Manual Wheelchair", keywords: ["accessibility"], skins: [{ unified: "1f9bd", native: "\u{1F9BD}" }], version: 12 }, motorized_wheelchair: { id: "motorized_wheelchair", name: "Motorized Wheelchair", keywords: ["accessibility"], skins: [{ unified: "1f9bc", native: "\u{1F9BC}" }], version: 12 }, auto_rickshaw: { id: "auto_rickshaw", name: "Auto Rickshaw", keywords: ["move", "transportation"], skins: [{ unified: "1f6fa", native: "\u{1F6FA}" }], version: 12 }, bike: { id: "bike", name: "Bicycle", keywords: ["bike", "sports", "exercise", "hipster"], skins: [{ unified: "1f6b2", native: "\u{1F6B2}" }], version: 1 }, scooter: { id: "scooter", name: "Scooter", keywords: ["kick", "vehicle", "razor"], skins: [{ unified: "1f6f4", native: "\u{1F6F4}" }
51763], version: 3 }, skateboard: { id: "skateboard", name: "Skateboard", keywords: ["board"], skins: [{ unified: "1f6f9", native: "\u{1F6F9}" }], version: 11 }, roller_skate: { id: "roller_skate", name: "Roller Skate", keywords: ["footwear", "sports"], skins: [{ unified: "1f6fc", native: "\u{1F6FC}" }], version: 13 }, busstop: { id: "busstop", name: "Bus Stop", keywords: ["busstop", "transportation", "wait"], skins: [{ unified: "1f68f", native: "\u{1F68F}" }], version: 1 }, motorway: { id: "motorway", name: "Motorway", keywords: ["road", "cupertino", "interstate", "highway"], skins: [{ unified: "1f6e3-fe0f", native: "\u{1F6E3}\uFE0F" }], version: 1 }, railway_track: { id: "railway_track", name: "Railway Track", keywords: ["train", "transportation"], skins: [{ unified: "1f6e4-fe0f", native: "\u{1F6E4}\uFE0F" }], version: 1 }, oil_drum: { id: "oil_drum", name: "Oil Drum", keywords: ["barrell"], skins: [{ unified: "1f6e2-fe0f", native: "\u{1F6E2}\uFE0F" }], version: 1 }, fuelpump: { id: "fuelpump", name: "Fuel Pump", keywords: ["fuelpump", "gas", "station", "petroleum"], skins: [{ unified: "26fd", native: "\u26FD" }], version: 1 }, wheel: { id: "wheel", name: "Wheel", keywords: ["car", "transport"], skins: [{ unified: "1f6de", native: "\u{1F6DE}" }], version: 14 }, rotating_light: { id: "rotating_light", name: "Police Car Light", keywords: ["rotating", "ambulance", "911", "emergency", "alert", "error", "pinged", "law", "legal"], skins: [{ unified: "1f6a8", native: "\u{1F6A8}" }], version: 1 }, traffic_light: { id: "traffic_light", name: "Horizontal Traffic Light", keywords: ["transportation", "signal"], skins: [{ unified: "1f6a5", native: "\u{1F6A5}" }], version: 1 }, vertical_traffic_light: { id: "vertical_traffic_light", name: "Vertical Traffic Light", keywords: ["transportation", "driving"], skins: [{ unified: "1f6a6", native: "\u{1F6A6}" }], version: 1 }, octagonal_sign: { id: "octagonal_sign", name: "Stop Sign", keywords: ["octagonal"], skins: [{ unified: "1f6d1", native: "\u{1F6D1}" }], version: 3 }, construction: { id: "construction", name: "Construction", keywords: ["wip", "progress", "caution", "warning"], skins: [{ unified: "1f6a7", native: "\u{1F6A7}" }], version: 1 }, anchor: { id: "anchor", name: "Anchor", keywords: ["ship", "ferry", "sea", "boat"], skins: [{ unified: "2693", native: "\u2693" }], version: 1 }, ring_buoy: { id: "ring_buoy", name: "Ring Buoy", keywords: ["life", "saver", "preserver"], skins: [{ unified: "1f6df", native: "\u{1F6DF}" }], version: 14 }, boat: { id: "boat", name: "Sailboat", keywords: ["boat", "ship", "summer", "transportation", "water", "sailing"], skins: [{ unified: "26f5", native: "\u26F5" }], version: 1 }, canoe: { id: "canoe", name: "Canoe", keywords: ["boat", "paddle", "water", "ship"], skins: [{ unified: "1f6f6", native: "\u{1F6F6}" }], version: 3 }, speedboat: { id: "speedboat", name: "Speedboat", keywords: ["ship", "transportation", "vehicle", "summer"], skins: [{ unified: "1f6a4", native: "\u{1F6A4}" }], version: 1 }, passenger_ship: { id: "passenger_ship", name: "Passenger Ship", keywords: ["yacht", "cruise", "ferry"], skins: [{ unified: "1f6f3-fe0f", native: "\u{1F6F3}\uFE0F" }], version: 1 }, ferry: { id: "ferry", name: "Ferry", keywords: ["boat", "ship", "yacht"], skins: [{ unified: "26f4-fe0f", native: "\u26F4\uFE0F" }], version: 1 }, motor_boat: { id: "motor_boat", name: "Motor Boat", keywords: ["ship"], skins: [{ unified: "1f6e5-fe0f", native: "\u{1F6E5}\uFE0F" }], version: 1 }, ship: { id: "ship", name: "Ship", keywords: ["transportation", "titanic", "deploy"], skins: [{ unified: "1f6a2", native: "\u{1F6A2}" }], version: 1 }, airplane: { id: "airplane", name: "Airplane", keywords: ["vehicle", "transportation", "flight", "fly"], skins: [{ unified: "2708-fe0f", native: "\u2708\uFE0F" }], version: 1 }, small_airplane: { id: "small_airplane", name: "Small Airplane", keywords: ["flight", "transportation", "fly", "vehicle"], skins: [{ unified: "1f6e9-fe0f", native: "\u{1F6E9}\uFE0F" }], version: 1 }, airplane_departure: { id: "airplane_departure", name: "Airplane Departure", keywords: ["airport", "flight", "landing"], skins: [{ unified: "1f6eb", native: "\u{1F6EB}" }], version: 1 }, airplane_arriving: { id: "airplane_arriving", name: "Airplane Arrival", keywords: ["arriving", "airport", "flight", "boarding"], skins: [{ unified: "1f6ec", native: "\u{1F6EC}" }], version: 1 }, parachute: { id: "parachute", name: "Parachute", keywords: ["fly", "glide"], skins: [{ unified: "1fa82", native: "\u{1FA82}" }], version: 12 }, seat: { id: "seat", name: "Seat", keywords: ["sit", "airplane", "transport", "bus", "flight", "fly"], skins: [{ unified: "1f4ba", native: "\u{1F4BA}" }], version: 1 }, helicopter: { id: "helicopter", name: "Helicopter", keywords: ["transportation", "vehicle", "fly"], skins: [{ unified: "1f681", native: "\u{1F681}" }], version: 1 }, suspension_railway: { id: "suspension_railway", name: "Suspension Railway", keywords: ["vehicle", "transportation"], skins: [{ unified: "1f69f", native: "\u{1F69F}" }], version: 1 }, mountain_cableway: { id: "mountain_cableway", name: "Mountain Cableway", keywords: ["transportation", "vehicle", "ski"], skins: [{ unified: "1f6a0", native: "\u{1F6A0}" }], version: 1 }, aerial_tramway: { id: "aerial_tramway", name: "Aerial Tramway", keywords: ["transportation", "vehicle", "ski"], skins: [{ unified: "1f6a1", native: "\u{1F6A1}" }], version: 1 }, satellite: { id: "satellite", name: "Satellite", keywords: ["communication", "gps", "orbit", "spaceflight", "NASA", "ISS"], skins: [{ unified: "1f6f0-fe0f", native: "\u{1F6F0}\uFE0F" }], version: 1 }, rocket: { id: "rocket", name: "Rocket", keywords: ["launch", "ship", "staffmode", "NASA", "outer", "space", "fly"], skins: [{ unified: "1f680", native: "\u{1F680}" }], version: 1 }, flying_saucer: { id: "flying_saucer", name: "Flying Saucer", keywords: ["transportation", "vehicle", "ufo"], skins: [{ unified: "1f6f8", native: "\u{1F6F8}" }], version: 5 }, bellhop_bell: { id: "bellhop_bell", name: "Bellhop Bell", keywords: ["service"], skins: [{ unified: "1f6ce-fe0f", native: "\u{1F6CE}\uFE0F" }], version: 1 }, luggage: { id: "luggage", name: "Luggage", keywords: ["packing", "travel"], skins: [{ unified: "1f9f3", native: "\u{1F9F3}" }], version: 11 }, hourglass: { id: "hourglass", name: "Hourglass", keywords: ["done", "time", "clock", "oldschool", "limit", "exam", "quiz", "test"], skins: [{ unified: "231b", native: "\u231B" }], version: 1 }, hourglass_flowing_sand: { id: "hourglass_flowing_sand", name: "Hourglass Not Done", keywords: ["flowing", "sand", "oldschool", "time", "countdown"], skins: [{ unified: "23f3", native: "\u23F3" }], version: 1 }, watch: { id: "watch", name: "Watch", keywords: ["time", "accessories"], skins: [{ unified: "231a", native: "\u231A" }], version: 1 }, alarm_clock: { id: "alarm_clock", name: "Alarm Clock", keywords: ["time", "wake"], skins: [{ unified: "23f0", native: "\u23F0" }], version: 1 }, stopwatch: { id: "stopwatch", name: "Stopwatch", keywords: ["time", "deadline"], skins: [{ unified: "23f1-fe0f", native: "\u23F1\uFE0F" }], version: 1 }, timer_clock: { id: "timer_clock", name: "Timer Clock", keywords: ["alarm"], skins: [{ unified: "23f2-fe0f", native: "\u23F2\uFE0F" }], version: 1 }, mantelpiece_clock: { id: "mantelpiece_clock", name: "Mantelpiece Clock", keywords: ["time"], skins: [{ unified: "1f570-fe0f", native: "\u{1F570}\uFE0F" }], version: 1 }, clock12: { id: "clock12", name: "Twelve O\u2019clock", keywords: ["clock12", "o", "clock", "12", "00:00", "0000", "12:00", "1200", "time", "noon", "midnight", "midday", "late", "early", "schedule"], skins: [{ unified: "1f55b", native: "\u{1F55B}" }], version: 1 }, clock1230: { id: "clock1230", name: "Twelve-Thirty", keywords: ["clock1230", "twelve", "thirty", "00:30", "0030", "12:30", "1230", "time", "late", "early", "schedule"], skins: [{ unified: "1f567", native: "\u{1F567}" }], version: 1 }, clock1: { id: "clock1", name: "One O\u2019clock", keywords: ["clock1", "o", "clock", "1", "1:00", "100", "13:00", "1300", "time", "late", "early", "schedule"], skins: [{ unified: "1f550", native: "\u{1F550}" }], version: 1 }, clock130: { id: "clock130", name: "One-Thirty", keywords: ["clock130", "one", "thirty", "1:30", "130", "13:30", "1330", "time", "late", "early", "schedule"], skins: [{ unified: "1f55c", native: "\u{1F55C}" }], version: 1 }, clock2: { id: "clock2", name: "Two O\u2019clock", keywords: ["clock2", "o", "clock", "2", "2:00", "200", "14:00", "1400", "time", "late", "early", "schedule"], skins: [{ unified: "1f551", native: "\u{1F551}" }], version: 1 }, clock230: { id: "clock230", name: "Two-Thirty", keywords: ["clock230", "two", "thirty", "2:30", "230", "14:30", "1430", "time", "late", "early", "schedule"], skins: [{ unified: "1f55d", native: "\u{1F55D}" }], version: 1 }, clock3: { id: "clock3", name: "Three O\u2019clock", keywords: ["clock3", "o", "clock", "3", "3:00", "300", "15:00", "1500", "time", "late", "early", "schedule"], skins: [{ unified: "1f552", native: "\u{1F552}" }], version: 1 }, clock330: { id: "clock330", name: "Three-Thirty", keywords: ["clock330", "three", "thirty", "3:30", "330", "15:30", "1530", "time", "late", "early", "schedule"], skins: [{ unified: "1f55e", native: "\u{1F55E}" }], version: 1 }, clock4: { id: "clock4", name: "Four O\u2019clock", keywords: ["clock4", "o", "clock", "4", "4:00", "400", "16:00", "1600", "time", "late", "early", "schedule"], skins: [{ unified: "1f553", native: "\u{1F553}" }], version: 1 }, clock430: { id: "clock430", name: "Four-Thirty", keywords: ["clock430", "four", "thirty", "4:30", "430", "16:30", "1630", "time", "late", "early", "schedule"], skins: [{ unified: "1f55f", native: "\u{1F55F}" }], version: 1 }, clock5: { id: "clock5", name: "Five O\u2019clock", keywords: ["clock5", "o", "clock", "5", "5:00", "500", "17:00", "1700", "time", "late", "early", "schedule"], skins: [{ unified: "1f554", native: "\u{1F554}" }], version: 1 }, clock530: { id: "clock530", name: "Five-Thirty", keywords: ["clock530", "five", "thirty", "5:30", "530", "17:30", "1730", "time", "late", "early", "schedule"], skins: [{ unified: "1f560", native: "\u{1F560}" }], version: 1 }, clock6: { id: "clock6", name: "Six O\u2019clock", keywords: ["clock6", "o", "clock", "6", "6:00", "600", "18:00", "1800", "time", "late", "early", "schedule", "dawn", "dusk"], skins: [{ unified: "1f555", native: "\u{1F555}" }], version: 1 }, clock630: { id: "clock630", name: "Six-Thirty", keywords: ["clock630", "six", "thirty", "6:30", "630", "18:30", "1830", "time", "late", "early", "schedule"], skins: [{ unified: "1f561", native: "\u{1F561}" }], version: 1 }, clock7: { id: "clock7", name: "Seven O\u2019clock", keywords: ["clock7", "o", "clock", "7", "7:00", "700", "19:00", "1900", "time", "late", "early", "schedule"], skins: [{ unified: "1f556", native: "\u{1F556}" }], version: 1 }, clock730: { id: "clock730", name: "Seven-Thirty", keywords: ["clock730", "seven", "thirty", "7:30", "730", "19:30", "1930", "time", "late", "early", "schedule"], skins: [{ unified: "1f562", native: "\u{1F562}" }], version: 1 }, clock8: { id: "clock8", name: "Eight O\u2019clock", keywords: ["clock8", "o", "clock", "8", "8:00", "800", "20:00", "2000", "time", "late", "early", "schedule"], skins: [{ unified: "1f557", native: "\u{1F557}" }], version: 1 }, clock830: { id: "clock830", name: "Eight-Thirty", keywords: ["clock830", "eight", "thirty", "8:30", "830", "20:30", "2030", "time", "late", "early", "schedule"], skins: [{ unified: "1f563", native: "\u{1F563}" }], version: 1 }, clock9: { id: "clock9", name: "Nine O\u2019clock", keywords: ["clock9", "o", "clock", "9", "9:00", "900", "21:00", "2100", "time", "late", "early", "schedule"], skins: [{ unified: "1f558", native: "\u{1F558}" }], version: 1 }, clock930: { id: "clock930", name: "Nine-Thirty", keywords: ["clock930", "nine", "thirty", "9:30", "930", "21:30", "2130", "time", "late", "early", "schedule"], skins: [{ unified: "1f564", native: "\u{1F564}" }], version: 1 }, clock10: { id: "clock10", name: "Ten O\u2019clock", keywords: ["clock10", "o", "clock", "10", "10:00", "1000", "22:00", "2200", "time", "late", "early", "schedule"], skins: [{ unified: "1f559", native: "\u{1F559}" }], version: 1 }, clock1030: { id: "clock1030", name: "Ten-Thirty", keywords: ["clock1030", "ten", "thirty", "10:30", "1030", "22:30", "2230", "time", "late", "early", "schedule"], skins: [{ unified: "1f565", native: "\u{1F565}" }], version: 1 }, clock11: { id: "clock11", name: "Eleven O\u2019clock", keywords: ["clock11", "o", "clock", "11", "11:00", "1100", "23:00", "2300", "time", "late", "early", "schedule"], skins: [{ unified: "1f55a", native: "\u{1F55A}" }], version: 1 }, clock1130: { id: "clock1130", name: "Eleven-Thirty", keywords: ["clock1130", "eleven", "thirty", "11:30", "1130", "23:30", "2330", "time", "late", "early", "schedule"], skins: [{ unified: "1f566", native: "\u{1F566}" }], version: 1 }, new_moon: { id: "new_moon", name: "New Moon", keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], skins: [{ unified: "1f311", native: "\u{1F311}" }], version: 1 }, waxing_crescent_moon: { id: "waxing_crescent_moon", name: "Waxing Crescent Moon", keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], skins: [{ unified: "1f312", native: "\u{1F312}" }], version: 1 }, first_quarter_moon: { id: "first_quarter_moon", name: "First Quarter Moon", keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], skins: [{ unified: "1f313", native: "\u{1F313}" }], version: 1 }, moon: { id: "moon", name: "Waxing Gibbous Moon", keywords: ["nature", "night", "sky", "gray", "twilight", "planet", "space", "evening", "sleep"], skins: [{ unified: "1f314", native: "\u{1F314}" }], version: 1 }, full_moon: { id: "full_moon", name: "Full Moon", keywords: ["nature", "yellow", "twilight", "planet", "space", "night", "evening", "sleep"], skins: [{ unified: "1f315", native: "\u{1F315}" }], version: 1 }, waning_gibbous_moon: { id: "waning_gibbous_moon", name: "Waning Gibbous Moon", keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep", "waxing"], skins: [{ unified: "1f316", native: "\u{1F316}" }], version: 1 }, last_quarter_moon: { id: "last_quarter_moon", name: "Last Quarter Moon", keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], skins: [{ unified: "1f317", native: "\u{1F317}" }], version: 1 }, waning_crescent_moon: { id: "waning_crescent_moon", name: "Waning Crescent Moon", keywords: ["nature", "twilight", "planet", "space", "night", "evening", "sleep"], skins: [{ unified: "1f318", native: "\u{1F318}" }], version: 1 }, crescent_moon: { id: "crescent_moon", name: "Crescent Moon", keywords: ["night", "sleep", "sky", "evening", "magic"], skins: [{ unified: "1f319", native: "\u{1F319}" }], version: 1 }
51763, new_moon_with_face: { id: "new_moon_with_face", name: "New Moon Face", keywords: ["with", "nature", "twilight", "planet", "space", "night", "evening", "sleep"], skins: [{ unified: "1f31a", native: "\u{1F31A}" }], version: 1 }, first_quarter_moon_with_face: { id: "first_quarter_moon_with_face", name: "First Quarter Moon Face", keywords: ["with", "nature", "twilight", "planet", "space", "night", "evening", "sleep"], skins: [{ unified: "1f31b", native: "\u{1F31B}" }], version: 1 }, last_quarter_moon_with_face: { id: "last_quarter_moon_with_face", name: "Last Quarter Moon Face", keywords: ["with", "nature", "twilight", "planet", "space", "night", "evening", "sleep"], skins: [{ unified: "1f31c", native: "\u{1F31C}" }], version: 1 }, thermometer: { id: "thermometer", name: "Thermometer", keywords: ["weather", "temperature", "hot", "cold"], skins: [{ unified: "1f321-fe0f", native: "\u{1F321}\uFE0F" }], version: 1 }, sunny: { id: "sunny", name: "Sun", keywords: ["sunny", "weather", "nature", "brightness", "summer", "beach", "spring"], skins: [{ unified: "2600-fe0f", native: "\u2600\uFE0F" }], version: 1 }, full_moon_with_face: { id: "full_moon_with_face", name: "Full Moon Face", keywords: ["with", "nature", "twilight", "planet", "space", "night", "evening", "sleep"], skins: [{ unified: "1f31d", native: "\u{1F31D}" }], version: 1 }, sun_with_face: { id: "sun_with_face", name: "Sun with Face", keywords: ["nature", "morning", "sky"], skins: [{ unified: "1f31e", native: "\u{1F31E}" }], version: 1 }, ringed_planet: { id: "ringed_planet", name: "Ringed Planet", keywords: ["outerspace"], skins: [{ unified: "1fa90", native: "\u{1FA90}" }], version: 12 }, star: { id: "star", name: "Star", keywords: ["night", "yellow"], skins: [{ unified: "2b50", native: "\u2B50" }], version: 1 }, star2: { id: "star2", name: "Glowing Star", keywords: ["star2", "night", "sparkle", "awesome", "good", "magic"], skins: [{ unified: "1f31f", native: "\u{1F31F}" }], version: 1 }, stars: { id: "stars", name: "Shooting Star", keywords: ["stars", "night", "photo"], skins: [{ unified: "1f320", native: "\u{1F320}" }], version: 1 }, milky_way: { id: "milky_way", name: "Milky Way", keywords: ["photo", "space", "stars"], skins: [{ unified: "1f30c", native: "\u{1F30C}" }], version: 1 }, cloud: { id: "cloud", name: "Cloud", keywords: ["weather", "sky"], skins: [{ unified: "2601-fe0f", native: "\u2601\uFE0F" }], version: 1 }, partly_sunny: { id: "partly_sunny", name: "Sun Behind Cloud", keywords: ["partly", "sunny", "weather", "nature", "cloudy", "morning", "fall", "spring"], skins: [{ unified: "26c5", native: "\u26C5" }], version: 1 }, thunder_cloud_and_rain: { id: "thunder_cloud_and_rain", name: "Cloud with Lightning and Rain", keywords: ["thunder", "weather"], skins: [{ unified: "26c8-fe0f", native: "\u26C8\uFE0F" }], version: 1 }, mostly_sunny: { id: "mostly_sunny", name: "Sun Behind Small Cloud", keywords: ["mostly", "sunny", "weather"], skins: [{ unified: "1f324-fe0f", native: "\u{1F324}\uFE0F" }], version: 1 }, barely_sunny: { id: "barely_sunny", name: "Sun Behind Large Cloud", keywords: ["barely", "sunny", "weather"], skins: [{ unified: "1f325-fe0f", native: "\u{1F325}\uFE0F" }], version: 1 }, partly_sunny_rain: { id: "partly_sunny_rain", name: "Sun Behind Rain Cloud", keywords: ["partly", "sunny", "weather"], skins: [{ unified: "1f326-fe0f", native: "\u{1F326}\uFE0F" }], version: 1 }, rain_cloud: { id: "rain_cloud", name: "Cloud with Rain", keywords: ["weather"], skins: [{ unified: "1f327-fe0f", native: "\u{1F327}\uFE0F" }], version: 1 }, snow_cloud: { id: "snow_cloud", name: "Cloud with Snow", keywords: ["weather"], skins: [{ unified: "1f328-fe0f", native: "\u{1F328}\uFE0F" }], version: 1 }, lightning: { id: "lightning", name: "Cloud with Lightning", keywords: ["weather", "thunder"], skins: [{ unified: "1f329-fe0f", native: "\u{1F329}\uFE0F" }], version: 1 }, tornado: { id: "tornado", name: "Tornado", keywords: ["cloud", "weather", "cyclone", "twister"], skins: [{ unified: "1f32a-fe0f", native: "\u{1F32A}\uFE0F" }], version: 1 }, fog: { id: "fog", name: "Fog", keywords: ["weather"], skins: [{ unified: "1f32b-fe0f", native: "\u{1F32B}\uFE0F" }], version: 1 }, wind_blowing_face: { id: "wind_blowing_face", name: "Wind Face", keywords: ["blowing", "gust", "air"], skins: [{ unified: "1f32c-fe0f", native: "\u{1F32C}\uFE0F" }], version: 1 }, cyclone: { id: "cyclone", name: "Cyclone", keywords: ["weather", "swirl", "blue", "cloud", "vortex", "spiral", "whirlpool", "spin", "tornado", "hurricane", "typhoon"], skins: [{ unified: "1f300", native: "\u{1F300}" }], version: 1 }, rainbow: { id: "rainbow", name: "Rainbow", keywords: ["nature", "happy", "unicorn", "face", "photo", "sky", "spring"], skins: [{ unified: "1f308", native: "\u{1F308}" }], version: 1 }, closed_umbrella: { id: "closed_umbrella", name: "Closed Umbrella", keywords: ["weather", "rain", "drizzle"], skins: [{ unified: "1f302", native: "\u{1F302}" }], version: 1 }, umbrella: { id: "umbrella", name: "Umbrella", keywords: ["weather", "spring"], skins: [{ unified: "2602-fe0f", native: "\u2602\uFE0F" }], version: 1 }, umbrella_with_rain_drops: { id: "umbrella_with_rain_drops", name: "Umbrella with Rain Drops", keywords: ["rainy", "weather", "spring"], skins: [{ unified: "2614", native: "\u2614" }], version: 1 }, umbrella_on_ground: { id: "umbrella_on_ground", name: "Umbrella on Ground", keywords: ["weather", "summer"], skins: [{ unified: "26f1-fe0f", native: "\u26F1\uFE0F" }], version: 1 }, zap: { id: "zap", name: "High Voltage", keywords: ["zap", "thunder", "weather", "lightning", "bolt", "fast"], skins: [{ unified: "26a1", native: "\u26A1" }], version: 1 }, snowflake: { id: "snowflake", name: "Snowflake", keywords: ["winter", "season", "cold", "weather", "christmas", "xmas"], skins: [{ unified: "2744-fe0f", native: "\u2744\uFE0F" }], version: 1 }, snowman: { id: "snowman", name: "Snowman", keywords: ["winter", "season", "cold", "weather", "christmas", "xmas", "frozen"], skins: [{ unified: "2603-fe0f", native: "\u2603\uFE0F" }], version: 1 }, snowman_without_snow: { id: "snowman_without_snow", name: "Snowman Without Snow", keywords: ["winter", "season", "cold", "weather", "christmas", "xmas", "frozen"], skins: [{ unified: "26c4", native: "\u26C4" }], version: 1 }, comet: { id: "comet", name: "Comet", keywords: ["space"], skins: [{ unified: "2604-fe0f", native: "\u2604\uFE0F" }], version: 1 }, fire: { id: "fire", name: "Fire", keywords: ["hot", "cook", "flame"], skins: [{ unified: "1f525", native: "\u{1F525}" }], version: 1 }, droplet: { id: "droplet", name: "Droplet", keywords: ["water", "drip", "faucet", "spring"], skins: [{ unified: "1f4a7", native: "\u{1F4A7}" }], version: 1 }, ocean: { id: "ocean", name: "Water Wave", keywords: ["ocean", "sea", "nature", "tsunami", "disaster"], skins: [{ unified: "1f30a", native: "\u{1F30A}" }], version: 1 }, jack_o_lantern: { id: "jack_o_lantern", name: "Jack-O-Lantern", keywords: ["jack", "o", "lantern", "halloween", "light", "pumpkin", "creepy", "fall"], skins: [{ unified: "1f383", native: "\u{1F383}" }], version: 1 }, christmas_tree: { id: "christmas_tree", name: "Christmas Tree", keywords: ["festival", "vacation", "december", "xmas", "celebration"], skins: [{ unified: "1f384", native: "\u{1F384}" }], version: 1 }, fireworks: { id: "fireworks", name: "Fireworks", keywords: ["photo", "festival", "carnival", "congratulations"], skins: [{ unified: "1f386", native: "\u{1F386}" }], version: 1 }, sparkler: { id: "sparkler", name: "Sparkler", keywords: ["stars", "night", "shine"], skins: [{ unified: "1f387", native: "\u{1F387}" }], version: 1 }, firecracker: { id: "firecracker", name: "Firecracker", keywords: ["dynamite", "boom", "explode", "explosion", "explosive"], skins: [{ unified: "1f9e8", native: "\u{1F9E8}" }], version: 11 }, sparkles: { id: "sparkles", name: "Sparkles", keywords: ["stars", "shine", "shiny", "cool", "awesome", "good", "magic"], skins: [{ unified: "2728", native: "\u2728" }], version: 1 }, balloon: { id: "balloon", name: "Balloon", keywords: ["party", "celebration", "birthday", "cir
51763cus"], skins: [{ unified: "1f388", native: "\u{1F388}" }], version: 1 }, tada: { id: "tada", name: "Party Popper", keywords: ["tada", "congratulations", "birthday", "magic", "circus", "celebration"], skins: [{ unified: "1f389", native: "\u{1F389}" }], version: 1 }, confetti_ball: { id: "confetti_ball", name: "Confetti Ball", keywords: ["festival", "party", "birthday", "circus"], skins: [{ unified: "1f38a", native: "\u{1F38A}" }], version: 1 }, tanabata_tree: { id: "tanabata_tree", name: "Tanabata Tree", keywords: ["plant", "nature", "branch", "summer", "bamboo", "wish", "star", "festival", "tanzaku"], skins: [{ unified: "1f38b", native: "\u{1F38B}" }], version: 1 }, bamboo: { id: "bamboo", name: "Pine Decoration", keywords: ["bamboo", "japanese", "plant", "nature", "vegetable", "panda", "new", "years"], skins: [{ unified: "1f38d", native: "\u{1F38D}" }], version: 1 }, dolls: { id: "dolls", name: "Japanese Dolls", keywords: ["toy", "kimono"], skins: [{ unified: "1f38e", native: "\u{1F38E}" }], version: 1 }, flags: { id: "flags", name: "Carp Streamer", keywords: ["flags", "fish", "japanese", "koinobori", "banner"], skins: [{ unified: "1f38f", native: "\u{1F38F}" }], version: 1 }, wind_chime: { id: "wind_chime", name: "Wind Chime", keywords: ["nature", "ding", "spring", "bell"], skins: [{ unified: "1f390", native: "\u{1F390}" }], version: 1 }, rice_scene: { id: "rice_scene", name: "Moon Viewing Ceremony", keywords: ["rice", "scene", "photo", "japan", "asia", "tsukimi"], skins: [{ unified: "1f391", native: "\u{1F391}" }], version: 1 }, red_envelope: { id: "red_envelope", name: "Red Envelope", keywords: ["gift"], skins: [{ unified: "1f9e7", native: "\u{1F9E7}" }], version: 11 }, ribbon: { id: "ribbon", name: "Ribbon", keywords: ["decoration", "pink", "girl", "bowtie"], skins: [{ unified: "1f380", native: "\u{1F380}" }], version: 1 }, gift: { id: "gift", name: "Wrapped Gift", keywords: ["present", "birthday", "christmas", "xmas"], skins: [{ unified: "1f381", native: "\u{1F381}" }], version: 1 }, reminder_ribbon: { id: "reminder_ribbon", name: "Reminder Ribbon", keywords: ["sports", "cause", "support", "awareness"], skins: [{ unified: "1f397-fe0f", native: "\u{1F397}\uFE0F" }], version: 1 }, admission_tickets: { id: "admission_tickets", name: "Admission Tickets", keywords: ["sports", "concert", "entrance"], skins: [{ unified: "1f39f-fe0f", native: "\u{1F39F}\uFE0F" }], version: 1 }, ticket: { id: "ticket", name: "Ticket", keywords: ["event", "concert", "pass"], skins: [{ unified: "1f3ab", native: "\u{1F3AB}" }], version: 1 }, medal: { id: "medal", name: "Military Medal", keywords: ["award", "winning", "army"], skins: [{ unified: "1f396-fe0f", native: "\u{1F396}\uFE0F" }], version: 1 }, trophy: { id: "trophy", name: "Trophy", keywords: ["win", "award", "contest", "place", "ftw", "ceremony"], skins: [{ unified: "1f3c6", native: "\u{1F3C6}" }], version: 1 }, sports_medal: { id: "sports_medal", name: "Sports Medal", keywords: ["award", "winning"], skins: [{ unified: "1f3c5", native: "\u{1F3C5}" }], version: 1 }, first_place_medal: { id: "first_place_medal", name: "1st Place Medal", keywords: ["first", "award", "winning"], skins: [{ unified: "1f947", native: "\u{1F947}" }], version: 3 }, second_place_medal: { id: "second_place_medal", name: "2nd Place Medal", keywords: ["second", "award"], skins: [{ unified: "1f948", native: "\u{1F948}" }], version: 3 }, third_place_medal: { id: "third_place_medal", name: "3rd Place Medal", keywords: ["third", "award"], skins: [{ unified: "1f949", native: "\u{1F949}" }], version: 3 }, soccer: { id: "soccer", name: "Soccer Ball", keywords: ["sports", "football"], skins: [{ unified: "26bd", native: "\u26BD" }], version: 1 }, baseball: { id: "baseball", name: "Baseball", keywords: ["sports", "balls"], skins: [{ unified: "26be", native: "\u26BE" }], version: 1 }, softball: { id: "softball", name: "Softball", keywords: ["sports", "balls"], skins: [{ unified: "1f94e", native: "\u{1F94E}" }], version: 11 }, basketball: { id: "basketball", name: "Basketball", keywords: ["sports", "balls", "NBA"], skins: [{ unified: "1f3c0", native: "\u{1F3C0}" }], version: 1 }, volleyball: { id: "volleyball", name: "Volleyball", keywords: ["sports", "balls"], skins: [{ unified: "1f3d0", native: "\u{1F3D0}" }], version: 1 }, football: { id: "football", name: "American Football", keywords: ["sports", "balls", "NFL"], skins: [{ unified: "1f3c8", native: "\u{1F3C8}" }], version: 1 }, rugby_football: { id: "rugby_football", name: "Rugby Football", keywords: ["sports", "team"], skins: [{ unified: "1f3c9", native: "\u{1F3C9}" }], version: 1 }, tennis: { id: "tennis", name: "Tennis", keywords: ["sports", "balls", "green"], skins: [{ unified: "1f3be", native: "\u{1F3BE}" }], version: 1 }, flying_disc: { id: "flying_disc", name: "Flying Disc", keywords: ["sports", "frisbee", "ultimate"], skins: [{ unified: "1f94f", native: "\u{1F94F}" }], version: 11 }, bowling: { id: "bowling", name: "Bowling", keywords: ["sports", "fun", "play"], skins: [{ unified: "1f3b3", native: "\u{1F3B3}" }], version: 1 }, cricket_bat_and_ball: { id: "cricket_bat_and_ball", name: "Cricket Game", keywords: ["bat", "and", "ball", "sports"], skins: [{ unified: "1f3cf", native: "\u{1F3CF}" }], version: 1 }, field_hockey_stick_and_ball: { id: "field_hockey_stick_and_ball", name: "Field Hockey", keywords: ["stick", "and", "ball", "sports"], skins: [{ unified: "1f3d1", native: "\u{1F3D1}" }], version: 1 }, ice_hockey_stick_and_puck: { id: "ice_hockey_stick_and_puck", name: "Ice Hockey", keywords: ["stick", "and", "puck", "sports"], skins: [{ unified: "1f3d2", native: "\u{1F3D2}" }], version: 1 }, lacrosse: { id: "lacrosse", name: "Lacrosse", keywords: ["sports", "ball", "stick"], skins: [{ unified: "1f94d", native: "\u{1F94D}" }], version: 11 }, table_tennis_paddle_and_ball: { id: "table_tennis_paddle_and_ball", name: "Ping Pong", keywords: ["table", "tennis", "paddle", "and", "ball", "sports", "pingpong"], skins: [{ unified: "1f3d3", native: "\u{1F3D3}" }], version: 1 }, badminton_racquet_and_shuttlecock: { id: "badminton_racquet_and_shuttlecock", name: "Badminton", keywords: ["racquet", "and", "shuttlecock", "sports"], skins: [{ unified: "1f3f8", native: "\u{1F3F8}" }], version: 1 }, boxing_glove: { id: "boxing_glove", name: "Boxing Glove", keywords: ["sports", "fighting"], skins: [{ unified: "1f94a", native: "\u{1F94A}" }], version: 3 }, martial_arts_uniform: { id: "martial_arts_uniform", name: "Martial Arts Uniform", keywords: ["judo", "karate", "taekwondo"], skins: [{ unified: "1f94b", native: "\u{1F94B}" }], version: 3 }, goal_net: { id: "goal_net", name: "Goal Net", keywords: ["sports"], skins: [{ unified: "1f945", native: "\u{1F945}" }], version: 3 }, golf: { id: "golf", name: "Flag in Hole", keywords: ["golf", "sports", "business", "summer"], skins: [{ unified: "26f3", native: "\u26F3" }], version: 1 }, ice_skate: { id: "ice_skate", name: "Ice Skate", keywords: ["sports"], skins: [{ unified: "26f8-fe0f", native: "\u26F8\uFE0F" }], version: 1 }, fishing_pole_and_fish: { id: "fishing_pole_and_fish", name: "Fishing Pole", keywords: ["and", "fish", "food", "hobby", "summer"], skins: [{ unified: "1f3a3", native: "\u{1F3A3}" }], version: 1 }, diving_mask: { id: "diving_mask", name: "Diving Mask", keywords: ["sport", "ocean"], skins: [{ unified: "1f93f", native: "\u{1F93F}" }], version: 12 }, running_shirt_with_sash: { id: "running_shirt_with_sash", name: "Running Shirt", keywords: ["with", "sash", "play", "pageant"], skins: [{ unified: "1f3bd", native: "\u{1F3BD}" }], version: 1 }, ski: { id: "ski", name: "Skis", keywords: ["ski", "sports", "winter", "cold", "snow"], skins: [{ unified: "1f3bf", native: "\u{1F3BF}" }], version: 1 }, sled: { id: "sled", name: "Sled", keywords: ["sleigh", "luge", "toboggan"], skins: [{ unified: "1f6f7", native: "\u{1F6F7}" }], version: 5 }, curling_stone: { id: "curling_stone", name: "Curling Stone", keywords: ["sports"], skins: [{ unified: "1f94c", native: "\u{1F94C}" }], version: 5 }, dart: { id: "dart", name: "Bullseye", keywords: ["dart", "direct", "hit", "game", "play", "bar", "target"], skins: [{ unified: "1f3af", native: "\u{1F3AF}" }], version: 1 }, "yo-yo": { id: "yo-yo", name: "Yo-Yo", keywords: ["yo", "toy"], skins: [{ unified: "1fa80", native: "\u{1FA80}" }], version: 12 }, kite: { id: "kite", name: "Kite", keywords: ["wind", "fly"], skins: [{ unified: "1fa81", native: "\u{1FA81}" }], version: 12 }, gun: { id: "gun", name: "Pistol", keywords: ["gun", "violence", "weapon", "revolver"], skins: [{ unified: "1f52b", native: "\u{1F52B}" }], version: 1 }, "8ball": { id: "8ball", name: "Billiards", keywords: ["8ball", "pool", "8", "ball", "hobby", "game", "luck", "magic"], skins: [{ unified: "1f3b1", native: "\u{1F3B1}" }], version: 1 }, crystal_ball: { id: "crystal_ball", name: "Crystal Ball", keywords: ["disco", "party", "magic", "cir
51763cus", "fortune", "teller"], skins: [{ unified: "1f52e", native: "\u{1F52E}" }], version: 1 }, magic_wand: { id: "magic_wand", name: "Magic Wand", keywords: ["supernature", "power"], skins: [{ unified: "1fa84", native: "\u{1FA84}" }], version: 13 }, video_game: { id: "video_game", name: "Video Game", keywords: ["play", "console", "PS4", "controller"], skins: [{ unified: "1f3ae", native: "\u{1F3AE}" }], version: 1 }, joystick: { id: "joystick", name: "Joystick", keywords: ["game", "play"], skins: [{ unified: "1f579-fe0f", native: "\u{1F579}\uFE0F" }], version: 1 }, slot_machine: { id: "slot_machine", name: "Slot Machine", keywords: ["bet", "gamble", "vegas", "fruit", "luck", "casino"], skins: [{ unified: "1f3b0", native: "\u{1F3B0}" }], version: 1 }, game_die: { id: "game_die", name: "Game Die", keywords: ["dice", "random", "tabletop", "play", "luck"], skins: [{ unified: "1f3b2", native: "\u{1F3B2}" }], version: 1 }, jigsaw: { id: "jigsaw", name: "Puzzle Piece", keywords: ["jigsaw", "interlocking"], skins: [{ unified: "1f9e9", native: "\u{1F9E9}" }], version: 11 }, teddy_bear: { id: "teddy_bear", name: "Teddy Bear", keywords: ["plush", "stuffed"], skins: [{ unified: "1f9f8", native: "\u{1F9F8}" }], version: 11 }, pinata: { id: "pinata", name: "Pinata", keywords: ["mexico", "candy", "celebration"], skins: [{ unified: "1fa85", native: "\u{1FA85}" }], version: 13 }, mirror_ball: { id: "mirror_ball", name: "Mirror Ball", keywords: ["disco", "dance", "party"], skins: [{ unified: "1faa9", native: "\u{1FAA9}" }], version: 14 }, nesting_dolls: { id: "nesting_dolls", name: "Nesting Dolls", keywords: ["matryoshka", "toy"], skins: [{ unified: "1fa86", native: "\u{1FA86}" }], version: 13 }, spades: { id: "spades", name: "Spade Suit", keywords: ["spades", "poker", "cards", "suits", "magic"], skins: [{ unified: "2660-fe0f", native: "\u2660\uFE0F" }], version: 1 }, hearts: { id: "hearts", name: "Heart Suit", keywords: ["hearts", "poker", "cards", "magic", "suits"], skins: [{ unified: "2665-fe0f", native: "\u2665\uFE0F" }], version: 1 }, diamonds: { id: "diamonds", name: "Diamond Suit", keywords: ["diamonds", "poker", "cards", "magic", "suits"], skins: [{ unified: "2666-fe0f", native: "\u2666\uFE0F" }], version: 1 }, clubs: { id: "clubs", name: "Club Suit", keywords: ["clubs", "poker", "cards", "magic", "suits"], skins: [{ unified: "2663-fe0f", native: "\u2663\uFE0F" }], version: 1 }, chess_pawn: { id: "chess_pawn", name: "Chess Pawn", keywords: ["expendable"], skins: [{ unified: "265f-fe0f", native: "\u265F\uFE0F" }], version: 11 }, black_joker: { id: "black_joker", name: "Joker", keywords: ["black", "poker", "cards", "game", "play", "magic"], skins: [{ unified: "1f0cf", native: "\u{1F0CF}" }], version: 1 }, mahjong: { id: "mahjong", name: "Mahjong Red Dragon", keywords: ["game", "play", "chinese", "kanji"], skins: [{ unified: "1f004", native: "\u{1F004}" }], version: 1 }, flower_playing_cards: { id: "flower_playing_cards", name: "Flower Playing Cards", keywords: ["game", "sunset", "red"], skins: [{ unified: "1f3b4", native: "\u{1F3B4}" }], version: 1 }, performing_arts: { id: "performing_arts", name: "Performing Arts", keywords: ["acting", "theater", "drama"], skins: [{ unified: "1f3ad", native: "\u{1F3AD}" }], version: 1 }, frame_with_picture: { id: "frame_with_picture", name: "Framed Picture", keywords: ["frame", "with", "photography"], skins: [{ unified: "1f5bc-fe0f", native: "\u{1F5BC}\uFE0F" }], version: 1 }, art: { id: "art", name: "Artist Palette", keywords: ["art", "design", "paint", "draw", "colors"], skins: [{ unified: "1f3a8", native: "\u{1F3A8}" }], version: 1 }, thread: { id: "thread", name: "Thread", keywords: ["needle", "sewing", "spool", "string"], skins: [{ unified: "1f9f5", native: "\u{1F9F5}" }], version: 11 }, sewing_needle: { id: "sewing_needle", name: "Sewing Needle", keywords: ["stitches"], skins: [{ unified: "1faa1", native: "\u{1FAA1}" }], version: 13 }, yarn: { id: "yarn", name: "Yarn", keywords: ["ball", "crochet", "knit"], skins: [{ unified: "1f9f6", native: "\u{1F9F6}" }], version: 11 }, knot: { id: "knot", name: "Knot", keywords: ["rope", "scout"], skins: [{ unified: "1faa2", native: "\u{1FAA2}" }], version: 13 }, eyeglasses: { id: "eyeglasses", name: "Glasses", keywords: ["eyeglasses", "fashion", "accessories", "eyesight", "nerdy", "dork", "geek"], skins: [{ unified: "1f453", native: "\u{1F453}" }], version: 1 }, dark_sunglasses: { id: "dark_sunglasses", name: "Sunglasses", keywords: ["dark", "face", "co
51763ol", "accessories"], skins: [{ unified: "1f576-fe0f", native: "\u{1F576}\uFE0F" }], version: 1 }, goggles: { id: "goggles", name: "Goggles", keywords: ["eyes", "protection", "safety"], skins: [{ unified: "1f97d", native: "\u{1F97D}" }], version: 11 }, lab_coat: { id: "lab_coat", name: "Lab Coat", keywords: ["doctor", "experiment", "scientist", "chemist"], skins: [{ unified: "1f97c", native: "\u{1F97C}" }], version: 11 }, safety_vest: { id: "safety_vest", name: "Safety Vest", keywords: ["protection"], skins: [{ unified: "1f9ba", native: "\u{1F9BA}" }], version: 12 }, necktie: { id: "necktie", name: "Necktie", keywords: ["shirt", "suitup", "formal", "fashion", "cloth", "business"], skins: [{ unified: "1f454", native: "\u{1F454}" }], version: 1 }, shirt: { id: "shirt", name: "T-Shirt", keywords: ["shirt", "tshirt", "t", "fashion", "cloth", "casual", "tee"], skins: [{ unified: "1f455", native: "\u{1F455}" }], version: 1 }, jeans: { id: "jeans", name: "Jeans", keywords: ["fashion", "shopping"], skins: [{ unified: "1f456", native: "\u{1F456}" }], version: 1 }, scarf: { id: "scarf", name: "Scarf", keywords: ["neck", "winter", "clothes"], skins: [{ unified: "1f9e3", native: "\u{1F9E3}" }], version: 5 }, gloves: { id: "gloves", name: "Gloves", keywords: ["hands", "winter", "clothes"], skins: [{ unified: "1f9e4", native: "\u{1F9E4}" }], version: 5 }, coat: { id: "coat", name: "Coat", keywords: ["jacket"], skins: [{ unified: "1f9e5", native: "\u{1F9E5}" }], version: 5 }, socks: { id: "socks", name: "Socks", keywords: ["stockings", "clothes"], skins: [{ unified: "1f9e6", native: "\u{1F9E6}" }], version: 5 }, dress: { id: "dress", name: "Dress", keywords: ["clothes", "fashion", "shopping"], skins: [{ unified: "1f457", native: "\u{1F457}" }], version: 1 }, kimono: { id: "kimono", name: "Kimono", keywords: ["dress", "fashion", "women", "female", "japanese"], skins: [{ unified: "1f458", native: "\u{1F458}" }], version: 1 }, sari: { id: "sari", name: "Sari", keywords: ["dress"], skins: [{ unified: "1f97b", native: "\u{1F97B}" }], version: 12 }, "one-piece_swimsuit": { id: "one-piece_swimsuit", name: "One-Piece Swimsuit", keywords: ["one", "piece", "fashion"], skins: [{ unified: "1fa71", native: "\u{1FA71}" }], version: 12 }, briefs: { id: "briefs", name: "Briefs", keywords: ["clothing"], skins: [{ unified: "1fa72", native: "\u{1FA72}" }], version: 12 }, shorts: { id: "shorts", name: "Shorts", keywords: ["clothing"], skins: [{ unified: "1fa73", native: "\u{1FA73}" }], version: 12 }, bikini: { id: "bikini", name: "Bikini", keywords: ["swimming", "female", "woman", "girl", "fashion", "beach", "summer"], skins: [{ unified: "1f459", native: "\u{1F459}" }], version: 1 }, womans_clothes: { id: "womans_clothes", name: "Womans Clothes", keywords: ["woman", "s", "fashion", "shopping", "bags", "female"], skins: [{ unified: "1f45a", native: "\u{1F45A}" }], version: 1 }, folding_hand_fan: { id: "folding_hand_fan", name: "Folding Hand Fan", keywords: ["flamenco", "hot"], skins: [{ unified: "1faad", native: "\u{1FAAD}" }], version: 15 }, purse: { id: "purse", name: "Purse", keywords: ["fashion", "accessories", "money", "sales", "shopping"], skins: [{ unified: "1f45b", native: "\u{1F45B}" }], version: 1 }, handbag: { id: "handbag", name: "Handbag", keywords: ["fashion", "accessory", "accessories", "shopping"], skins: [{ unified: "1f45c", native: "\u{1F45C}" }], version: 1 }, pouch: { id: "pouch", name: "Pouch", keywords: ["clutch", "bag", "accessories", "shopping"], skins: [{ unified: "1f45d", native: "\u{1F45D}" }], version: 1 }, shopping_bags: { id: "shopping_bags", name: "Shopping Bags", keywords: ["mall", "buy", "purchase"], skins: [{ unified: "1f6cd-fe0f", native: "\u{1F6CD}\uFE0F" }], version: 1 }, school_satchel: { id: "school_satchel", name: "Backpack", keywords: ["school", "satchel", "student", "education", "bag"], skins: [{ unified: "1f392", native: "\u{1F392}" }], version: 1 }, thong_sandal: { id: "thong_sandal", name: "Thong Sandal", keywords: ["footwear", "summer"], skins: [{ unified: "1fa74", native: "\u{1FA74}" }], version: 13 }, mans_shoe: { id: "mans_shoe", name: "Mans Shoe", keywords: ["man", "s", "fashion", "male"], skins: [{ unified: "1f45e", native: "\u{1F45E}" }], version: 1 }, athletic_shoe: { id: "athletic_shoe", name: "Running Shoe", keywords: ["athletic", "shoes", "sports", "sneakers"], skins: [{ unified: "1f45f", native: "\u{1F45F}" }], version: 1 }, hiking_boot: { id: "hiking_boot", name: "Hiking Boot", keywords: ["backpacking", "camping"], skins: [{ unified: "1f97e", native: "\u{1F97E}" }], version: 11 }, womans_flat_shoe: { id: "womans_flat_shoe", name: "Flat Shoe", keywords: ["womans", "ballet", "slip", "on", "slipper"], skins: [{ unified: "1f97f", native: "\u{1F97F}" }], version: 11 }, high_heel: { id: "high_heel", name: "High-Heeled Shoe", keywords: ["high", "heel", "heeled", "fashion", "shoes", "female", "pumps", "stiletto"], skins: [{ unified: "1f460", native: "\u{1F460}" }], version: 1 }, sandal: { id: "sandal", name: "Womans Sandal", keywords: ["woman", "s", "shoes", "fashion", "flip", "flops"], skins: [{ unified: "1f461", native: "\u{1F461}" }], version: 1 }, ballet_shoes: { id: "ballet_shoes", name: "Ballet Shoes", keywords: ["dance"], skins: [{ unified: "1fa70", native: "\u{1FA70}" }], version: 12 }, boot: { id: "boot", name: "Womans Boots", keywords: ["boot", "woman", "s", "shoes", "fashion"], skins: [{ unified: "1f462", native: "\u{1F462}" }], version: 1 }, hair_pick: { id: "hair_pick", name: "Hair Pick", keywords: ["afro", "comb"], skins: [{ unified: "1faae", native: "\u{1FAAE}" }], version: 15 }, crown: { id: "crown", name: "Crown", keywords: ["king", "kod", "leader", "royalty", "lord"], skins: [{ unified: "1f451", native: "\u{1F451}" }], version: 1 }, womans_hat: { id: "womans_hat", name: "Womans Hat", keywords: ["woman", "s", "fashion", "accessories", "female", "lady", "spring"], skins: [{ unified: "1f452", native: "\u{1F452}" }], version: 1 }, tophat: { id: "tophat", name: "Top Hat", keywords: ["tophat", "magic", "gentleman", "classy", "cir
51763cus"], skins: [{ unified: "1f3a9", native: "\u{1F3A9}" }], version: 1 }, mortar_board: { id: "mortar_board", name: "Graduation Cap", keywords: ["mortar", "board", "school", "college", "degree", "university", "hat", "legal", "learn", "education"], skins: [{ unified: "1f393", native: "\u{1F393}" }], version: 1 }, billed_cap: { id: "billed_cap", name: "Billed Cap", keywords: ["baseball"], skins: [{ unified: "1f9e2", native: "\u{1F9E2}" }], version: 5 }, military_helmet: { id: "military_helmet", name: "Military Helmet", keywords: ["army", "protection"], skins: [{ unified: "1fa96", native: "\u{1FA96}" }], version: 13 }, helmet_with_white_cross: { id: "helmet_with_white_cross", name: "Rescue Worker\u2019s Helmet", keywords: ["with", "white", "cross", "worker", "s", "construction", "build"], skins: [{ unified: "26d1-fe0f", native: "\u26D1\uFE0F" }], version: 1 }, prayer_beads: { id: "prayer_beads", name: "Prayer Beads", keywords: ["dhikr", "religious"], skins: [{ unified: "1f4ff", native: "\u{1F4FF}" }], version: 1 }, lipstick: { id: "lipstick", name: "Lipstick", keywords: ["female", "girl", "fashion", "woman"], skins: [{ unified: "1f484", native: "\u{1F484}" }], version: 1 }, ring: { id: "ring", name: "Ring", keywords: ["wedding", "propose", "marriage", "valentines", "diamond", "fashion", "jewelry", "gem", "engagement"], skins: [{ unified: "1f48d", native: "\u{1F48D}" }], version: 1 }, gem: { id: "gem", name: "Gem Stone", keywords: ["blue", "ruby", "diamond", "jewelry"], skins: [{ unified: "1f48e", native: "\u{1F48E}" }], version: 1 }, mute: { id: "mute", name: "Muted Speaker", keywords: ["mute", "sound", "volume", "silence", "quiet"], skins: [{ unified: "1f507", native: "\u{1F507}" }], version: 1 }, speaker: { id: "speaker", name: "Speaker", keywords: ["low", "volume", "sound", "silence", "broadcast"], skins: [{ unified: "1f508", native: "\u{1F508}" }], version: 1 }, sound: { id: "sound", name: "Speaker Medium Volume", keywords: ["sound", "broadcast"], skins: [{ unified: "1f509", native: "\u{1F509}" }], version: 1 }, loud_sound: { id: "loud_sound", name: "Speaker High Volume", keywords: ["loud", "sound", "noise", "noisy", "broadcast"], skins: [{ unified: "1f50a", native: "\u{1F50A}" }], version: 1 }, loudspeaker: { id: "loudspeaker", name: "Loudspeaker", keywords: ["volume", "sound"], skins: [{ unified: "1f4e2", native: "\u{1F4E2}" }], version: 1 }, mega: { id: "mega", name: "Megaphone", keywords: ["mega", "sound", "speaker", "volume"], skins: [{ unified: "1f4e3", native: "\u{1F4E3}" }], version: 1 }, postal_horn: { id: "postal_horn", name: "Postal Horn", keywords: ["instrument", "music"], skins: [{ unified: "1f4ef", native: "\u{1F4EF}" }], version: 1 }, bell: { id: "bell", name: "Bell", keywords: ["sound", "notification", "christmas", "xmas", "chime"], skins: [{ unified: "1f514", native: "\u{1F514}" }], version: 1 }, no_bell: { id: "no_bell", name: "Bell with Slash", keywords: ["no", "sound", "volume", "mute", "quiet", "silent"], skins: [{ unified: "1f515", native: "\u{1F515}" }], version: 1 }, musical_score: { id: "musical_score", name: "Musical Score", keywords: ["treble", "clef", "compose"], skins: [{ unified: "1f3bc", native: "\u{1F3BC}" }], version: 1 }, musical_note: { id: "musical_note", name: "Musical Note", keywords: ["score", "tone", "sound"], skins: [{ unified: "1f3b5", native: "\u{1F3B5}" }], version: 1 }, notes: { id: "notes", name: "Musical Notes", keywords: ["music", "score"], skins: [{ unified: "1f3b6", native: "\u{1F3B6}" }], version: 1 }, studio_microphone: { id: "studio_microphone", name: "Studio Microphone", keywords: ["sing", "recording", "artist", "talkshow"], skins: [{ unified: "1f399-fe0f", native: "\u{1F399}\uFE0F" }], version: 1 }, level_slider: { id: "level_slider", name: "Level Slider", keywords: ["scale"], skins: [{ unified: "1f39a-fe0f", native: "\u{1F39A}\uFE0F" }], version: 1 }, control_knobs: { id: "control_knobs", name: "Control Knobs", keywords: ["dial"], skins: [{ unified: "1f39b-fe0f", native: "\u{1F39B}\uFE0F" }], version: 1 }, microphone: { id: "microphone", name: "Microphone", keywords: ["sound", "music", "PA", "sing", "talkshow"], skins: [{ unified: "1f3a4", native: "\u{1F3A4}" }], version: 1 }, headphones: { id: "headphones", name: "Headphone", keywords: ["headphones", "music", "score", "gadgets"], skins: [{ unified: "1f3a7", native: "\u{1F3A7}" }], version: 1 }, radio: { id: "radio", name: "Radio", keywords: ["communication", "music", "podcast", "program"], skins: [{ unified: "1f4fb", native: "\u{1F4FB}" }], version: 1 }, saxophone: { id: "saxophone", name: "Saxophone", keywords: ["music", "instrument", "jazz", "blues"], skins: [{ unified: "1f3b7", native: "\u{1F3B7}" }], version: 1 }, accordion: { id: "accordion", name: "Accordion", keywords: ["music"], skins: [{ unified: "1fa97", native: "\u{1FA97}" }], version: 13 }, guitar: { id: "guitar", name: "Guitar", keywords: ["music", "instrument"], skins: [{ unified: "1f3b8", native: "\u{1F3B8}" }], version: 1 }, musical_keyboard: { id: "musical_keyboard", name: "Musical Keyboard", keywords: ["piano", "instrument", "compose"], skins: [{ unified: "1f3b9", native: "\u{1F3B9}" }], version: 1 }, trumpet: { id: "trumpet", name: "Trumpet", keywords: ["music", "brass"], skins: [{ unified: "1f3ba", native: "\u{1F3BA}" }], version: 1 }, violin: { id: "violin", name: "Violin", keywords: ["music", "instrument", "orchestra", "symphony"], skins: [{ unified: "1f3bb", native: "\u{1F3BB}" }], version: 1 }, banjo: { id: "banjo", name: "Banjo", keywords: ["music", "instructment"], skins: [{ unified: "1fa95", native: "\u{1FA95}" }], version: 12 }, drum_with_drumsticks: { id: "drum_with_drumsticks", name: "Drum", keywords: ["with", "drumsticks", "music", "instrument", "snare"], skins: [{ unified: "1f941", native: "\u{1F941}" }], version: 3 }, long_drum: { id: "long_drum", name: "Long Drum", keywords: ["music"], skins: [{ unified: "1fa98", native: "\u{1FA98}" }], version: 13 }, maracas: { id: "maracas", name: "Maracas", keywords: ["music", "instrument", "percussion"], skins: [{ unified: "1fa87", native: "\u{1FA87}" }], version: 15 }, flute: { id: "flute", name: "Flute", keywords: ["bamboo", "music", "instrument", "pied", "piper"], skins: [{ unified: "1fa88", native: "\u{1FA88}" }
51763], version: 15 }, harp: { id: "harp", name: "Harp", keywords: [], skins: [{ unified: "1fa89", native: "\u{1FA89}" }], version: 16 }, iphone: { id: "iphone", name: "Mobile Phone", keywords: ["iphone", "technology", "apple", "gadgets", "dial"], skins: [{ unified: "1f4f1", native: "\u{1F4F1}" }], version: 1 }, calling: { id: "calling", name: "Mobile Phone with Arrow", keywords: ["calling", "iphone", "incoming"], skins: [{ unified: "1f4f2", native: "\u{1F4F2}" }], version: 1 }, phone: { id: "phone", name: "Telephone", keywords: ["phone", "technology", "communication", "dial"], skins: [{ unified: "260e-fe0f", native: "\u260E\uFE0F" }], version: 1 }, telephone_receiver: { id: "telephone_receiver", name: "Telephone Receiver", keywords: ["technology", "communication", "dial"], skins: [{ unified: "1f4de", native: "\u{1F4DE}" }], version: 1 }, pager: { id: "pager", name: "Pager", keywords: ["bbcall", "oldschool", "90s"], skins: [{ unified: "1f4df", native: "\u{1F4DF}" }], version: 1 }, fax: { id: "fax", name: "Fax Machine", keywords: ["communication", "technology"], skins: [{ unified: "1f4e0", native: "\u{1F4E0}" }], version: 1 }, battery: { id: "battery", name: "Battery", keywords: ["power", "energy", "sustain"], skins: [{ unified: "1f50b", native: "\u{1F50B}" }], version: 1 }, low_battery: { id: "low_battery", name: "Low Battery", keywords: ["drained", "dead"], skins: [{ unified: "1faab", native: "\u{1FAAB}" }], version: 14 }, electric_plug: { id: "electric_plug", name: "Electric Plug", keywords: ["charger", "power"], skins: [{ unified: "1f50c", native: "\u{1F50C}" }], version: 1 }, computer: { id: "computer", name: "Laptop", keywords: ["computer", "technology", "screen", "display", "monitor"], skins: [{ unified: "1f4bb", native: "\u{1F4BB}" }], version: 1 }, desktop_computer: { id: "desktop_computer", name: "Desktop Computer", keywords: ["technology", "computing", "screen"], skins: [{ unified: "1f5a5-fe0f", native: "\u{1F5A5}\uFE0F" }], version: 1 }, printer: { id: "printer", name: "Printer", keywords: ["paper", "ink"], skins: [{ unified: "1f5a8-fe0f", native: "\u{1F5A8}\uFE0F" }], version: 1 }, keyboard: { id: "keyboard", name: "Keyboard", keywords: ["technology", "computer", "type", "input", "text"], skins: [{ unified: "2328-fe0f", native: "\u2328\uFE0F" }], version: 1 }, three_button_mouse: { id: "three_button_mouse", name: "Computer Mouse", keywords: ["three", "button", "click"], skins: [{ unified: "1f5b1-fe0f", native: "\u{1F5B1}\uFE0F" }], version: 1 }, trackball: { id: "trackball", name: "Trackball", keywords: ["technology", "trackpad"], skins: [{ unified: "1f5b2-fe0f", native: "\u{1F5B2}\uFE0F" }], version: 1 }, minidisc: { id: "minidisc", name: "Minidisc", keywords: ["computer", "disk", "technology", "record", "data", "90s"], skins: [{ unified: "1f4bd", native: "\u{1F4BD}" }], version: 1 }, floppy_disk: { id: "floppy_disk", name: "Floppy Disk", keywords: ["oldschool", "technology", "save", "90s", "80s"], skins: [{ unified: "1f4be", native: "\u{1F4BE}" }], version: 1 }, cd: { id: "cd", name: "Optical Disc", keywords: ["cd", "disk", "technology", "dvd", "90s"], skins: [{ unified: "1f4bf", native: "\u{1F4BF}" }], version: 1 }, dvd: { id: "dvd", name: "Dvd", keywords: ["cd", "disk", "disc"], skins: [{ unified: "1f4c0", native: "\u{1F4C0}" }], version: 1 }, abacus: { id: "abacus", name: "Abacus", keywords: ["calculation"], skins: [{ unified: "1f9ee", native: "\u{1F9EE}" }], version: 11 }, movie_camera: { id: "movie_camera", name: "Movie Camera", keywords: ["film", "record"], skins: [{ unified: "1f3a5", native: "\u{1F3A5}" }], version: 1 }, film_frames: { id: "film_frames", name: "Film Frames", keywords: ["movie"], skins: [{ unified: "1f39e-fe0f", native: "\u{1F39E}\uFE0F" }], version: 1 }, film_projector: { id: "film_projector", name: "Film Projector", keywords: ["video", "tape", "record", "movie"], skins: [{ unified: "1f4fd-fe0f", native: "\u{1F4FD}\uFE0F" }], version: 1 }, clapper: { id: "clapper", name: "Clapper Board", keywords: ["movie", "film", "record"], skins: [{ unified: "1f3ac", native: "\u{1F3AC}" }], version: 1 }, tv: { id: "tv", name: "Television", keywords: ["tv", "technology", "program", "oldschool", "show"], skins: [{ unified: "1f4fa", native: "\u{1F4FA}" }], version: 1 }, camera: { id: "camera", name: "Camera", keywords: ["gadgets", "photography"], skins: [{ unified: "1f4f7", native: "\u{1F4F7}" }], version: 1 }, camera_with_flash: { id: "camera_with_flash", name: "Camera with Flash", keywords: ["photography", "gadgets"], skins: [{ unified: "1f4f8", native: "\u{1F4F8}" }], version: 1 }, video_camera: { id: "video_camera", name: "Video Camera", keywords: ["film", "record"], skins: [{ unified: "1f4f9", native: "\u{1F4F9}" }], version: 1 }, vhs: { id: "vhs", name: "Videocassette", keywords: ["vhs", "record", "video", "oldschool", "90s", "80s"], skins: [{ unified: "1f4fc", native: "\u{1F4FC}" }], version: 1 }, mag: { id: "mag", name: "Magnifying Glass Tilted Left", keywords: ["mag", "search", "zoom", "find", "detective"], skins: [{ unified: "1f50d", native: "\u{1F50D}" }], version: 1 }, mag_right: { id: "mag_right", name: "Magnifying Glass Tilted Right", keywords: ["mag", "search", "zoom", "find", "detective"], skins: [{ unified: "1f50e", native: "\u{1F50E}" }], version: 1 }, candle: { id: "candle", name: "Candle", keywords: ["fire", "wax"], skins: [{ unified: "1f56f-fe0f", native: "\u{1F56F}\uFE0F" }], version: 1 }, bulb: { id: "bulb", name: "Light Bulb", keywords: ["electricity", "idea"], skins: [{ unified: "1f4a1", native: "\u{1F4A1}" }], version: 1 }, flashlight: { id: "flashlight", name: "Flashlight", keywords: ["dark", "camping", "sight", "night"], skins: [{ unified: "1f526", native: "\u{1F526}" }], version: 1 }, izakaya_lantern: { id: "izakaya_lantern", name: "Izakaya Lantern", keywords: ["red", "paper", "light", "halloween", "spooky"], skins: [{ unified: "1f3ee", native: "\u{1F3EE}" }], version: 1 }, diya_lamp: { id: "diya_lamp", name: "Diya Lamp", keywords: ["lighting"], skins: [{ unified: "1fa94", native: "\u{1FA94}" }], version: 12 }, notebook_with_decorative_cover: { id: "notebook_with_decorative_cover", name: "Notebook with Decorative
51763Cover", keywords: ["classroom", "notes", "record", "paper", "study"], skins: [{ unified: "1f4d4", native: "\u{1F4D4}" }], version: 1 }, closed_book: { id: "closed_book", name: "Closed Book", keywords: ["read", "library", "knowledge", "textbook", "learn"], skins: [{ unified: "1f4d5", native: "\u{1F4D5}" }], version: 1 }, book: { id: "book", name: "Open Book", keywords: ["read", "library", "knowledge", "literature", "learn", "study"], skins: [{ unified: "1f4d6", native: "\u{1F4D6}" }], version: 1 }, green_book: { id: "green_book", name: "Green Book", keywords: ["read", "library", "knowledge", "study"], skins: [{ unified: "1f4d7", native: "\u{1F4D7}" }], version: 1 }, blue_book: { id: "blue_book", name: "Blue Book", keywords: ["read", "library", "knowledge", "learn", "study"], skins: [{ unified: "1f4d8", native: "\u{1F4D8}" }], version: 1 }, orange_book: { id: "orange_book", name: "Orange Book", keywords: ["read", "library", "knowledge", "textbook", "study"], skins: [{ unified: "1f4d9", native: "\u{1F4D9}" }], version: 1 }, books: { id: "books", name: "Books", keywords: ["literature", "library", "study"], skins: [{ unified: "1f4da", native: "\u{1F4DA}" }], version: 1 }, notebook: { id: "notebook", name: "Notebook", keywords: ["stationery", "record", "notes", "paper", "study"], skins: [{ unified: "1f4d3", native: "\u{1F4D3}" }], version: 1 }, ledger: { id: "ledger", name: "Ledger", keywords: ["notes", "paper"], skins: [{ unified: "1f4d2", native: "\u{1F4D2}" }], version: 1 }, page_with_curl: { id: "page_with_curl", name: "Page with Curl", keywords: ["documents", "office", "paper"], skins: [{ unified: "1f4c3", native: "\u{1F4C3}" }], version: 1 }, scroll: { id: "scroll", name: "Scroll", keywords: ["documents", "ancient", "history", "paper"], skins: [{ unified: "1f4dc", native: "\u{1F4DC}" }], version: 1 }, page_facing_up: { id: "page_facing_up", name: "Page Facing Up", keywords: ["documents", "office", "paper", "information"], skins: [{ unified: "1f4c4", native: "\u{1F4C4}" }], version: 1 }, newspaper: { id: "newspaper", name: "Newspaper", keywords: ["press", "headline"], skins: [{ unified: "1f4f0", native: "\u{1F4F0}" }], version: 1 }, rolled_up_newspaper: { id: "rolled_up_newspaper", name: "Rolled-Up Newspaper", keywords: ["rolled", "up", "press", "headline"], skins: [{ unified: "1f5de-fe0f", native: "\u{1F5DE}\uFE0F" }], version: 1 }, bookmark_tabs: { id: "bookmark_tabs", name: "Bookmark Tabs", keywords: ["favorite", "save", "order", "tidy"], skins: [{ unified: "1f4d1", native: "\u{1F4D1}" }], version: 1 }, bookmark: { id: "bookmark", name: "Bookmark", keywords: ["favorite", "label", "save"], skins: [{ unified: "1f516", native: "\u{1F516}" }], version: 1 }, label: { id: "label", name: "Label", keywords: ["sale", "tag"], skins: [{ unified: "1f3f7-fe0f", native: "\u{1F3F7}\uFE0F" }], version: 1 }, moneybag: { id: "moneybag", name: "Money Bag", keywords: ["moneybag", "dollar", "payment", "coins", "sale"], skins: [{ unified: "1f4b0", native: "\u{1F4B0}" }], version: 1 }, coin: { id: "coin", name: "Coin", keywords: ["money", "currency"], skins: [{ unified: "1fa99", native: "\u{1FA99}" }], version: 13 }, yen: { id: "yen", name: "Yen Banknote", keywords: ["money", "sales", "japanese", "dollar", "currency"], skins: [{ unified: "1f4b4", native: "\u{1F4B4}" }], version: 1 }, dollar: { id: "dollar", name: "Dollar Banknote", keywords: ["money", "sales", "bill", "currency"], skins: [{ unified: "1f4b5", native: "\u{1F4B5}" }], version: 1 }, euro: { id: "euro", name: "Euro Banknote", keywords: ["money", "sales", "dollar", "currency"], skins: [{ unified: "1f4b6", native: "\u{1F4B6}" }], version: 1 }, pound: { id: "pound", name: "Pound Banknote", keywords: ["british", "sterling", "money", "sales", "bills", "uk", "england", "currency"], skins: [{ unified: "1f4b7", native: "\u{1F4B7}" }], version: 1 }, money_with_wings: { id: "money_with_wings", name: "Money with Wings", keywords: ["dollar", "bills", "payment", "sale"], skins: [{ unified: "1f4b8", native: "\u{1F4B8}" }], version: 1 }, credit_card: { id: "credit_card", name: "Credit Card", keywords: ["money", "sales", "dollar", "bill", "payment", "shopping"], skins: [{ unified: "1f4b3", native: "\u{1F4B3}" }], version: 1 }, receipt: { id: "receipt", name: "Receipt", keywords: ["accounting", "expenses"], skins: [{ unified: "1f9fe", native: "\u{1F9FE}" }], version: 11 }, chart: { id: "chart", name: "Chart Increasing with Yen", keywords: ["green", "square", "graph", "presentation", "stats"], skins: [{ unified: "1f4b9", native: "\u{1F4B9}" }], version: 1 }, email: { id: "email", name: "Envelope", keywords: ["email", "letter", "postal", "inbox", "communication"], skins: [{ unified: "2709-fe0f", native: "\u2709\uFE0F" }], version: 1 }, "e-mail": { id: "e-mail", name: "E-Mail", keywords: ["e", "mail", "communication", "inbox"], skins: [{ unified: "1f4e7", native: "\u{1F4E7}" }], version: 1 }, incoming_envelope: { id: "incoming_envelope", name: "Incoming Envelope", keywords: ["email", "inbox"], skins: [{ unified: "1f4e8", native: "\u{1F4E8}" }], version: 1 }, envelope_with_arrow: { id: "envelope_with_arrow", name: "Envelope with Arrow", keywords: ["email", "communication"], skins: [{ unified: "1f4e9", native: "\u{1F4E9}" }], version: 1 }, outbox_tray: { id: "outbox_tray", name: "Outbox Tray", keywords: ["inbox", "email"], skins: [{ unified: "1f4e4", native: "\u{1F4E4}" }], version: 1 }, inbox_tray: { id: "inbox_tray", name: "Inbox Tray", keywords: ["email", "documents"], skins: [{ unified: "1f4e5", native: "\u{1F4E5}" }], version: 1 }, package: { id: "package", name: "Package", keywords: ["mail", "gift", "cardboard", "box", "moving"], skins: [{ unified: "1f4e6", native: "\u{1F4E6}" }], version: 1 }, mailbox: { id: "mailbox", name: "Closed Mailbox with Raised Flag", keywords: ["email", "inbox", "communication"], skins: [{ unified: "1f4eb", native: "\u{1F4EB}" }], version: 1 }, mailbox_closed: { id: "mailbox_closed", name: "Closed Mailbox with Lowered Flag", keywords: ["email", "communication", "inbox"], skins: [{ unified: "1f4ea", native: "\u{1F4EA}" }], version: 1 }, mailbox_with_mail: { id: "mailbox_with_mail", name: "Open Mailbox with Raised Flag", keywords: ["mail", "email", "inbox", "communication"], skins: [{ unified: "1f4ec", native: "\u{1F4EC}" }], version: 1 }, mailbox_with_no_mail: { id: "mailbox_with_no_mail", name: "Open Mailbox with Lowered Flag", keywords: ["no", "mail", "email", "inbox"], skins: [{ unified: "1f4ed", native: "\u{1F4ED}" }], version: 1 }, postbox: { id: "postbox", name: "Postbox", keywords: ["email", "letter", "envelope"], skins: [{ unified: "1f4ee", native: "\u{1F4EE}" }], version: 1 }, ballot_box_with_ballot: { id: "ballot_box_with_ballot", name: "Ballot Box with Ballot", keywords: ["election", "vote"], skins: [{ unified: "1f5f3-fe0f", native: "\u{1F5F3}\uFE0F" }], version: 1 }, pencil2: { id: "pencil2", name: "Pencil", keywords: ["pencil2", "stationery", "write", "paper", "writing", "school", "study"], skins: [{ unified: "270f-fe0f", native: "\u270F\uFE0F" }], version: 1 }, black_nib: { id: "black_nib", name: "Black Nib", keywords: ["pen", "stationery", "writing", "write"], skins: [{ unified: "2712-fe0f", native: "\u2712\uFE0F" }], version: 1 }, lower_left_fountain_pen: { id: "lower_left_fountain_pen", name: "Fountain Pen", keywords: ["lower", "left", "stationery", "writing", "write"], skins: [{ unified: "1f58b-fe0f", native: "\u{1F58B}\uFE0F" }], version: 1 }, lower_left_ballpoint_pen: { id: "lower_left_ballpoint_pen", name: "Pen", keywords: ["lower", "left", "ballpoint", "stationery", "writing", "write"], skins: [{ unified: "1f58a-fe0f", native: "\u{1F58A}\uFE0F" }], version: 1 }, lower_left_paintbrush: { id: "lower_left_paintbrush", name: "Paintbrush", keywords: ["lower", "left", "drawing", "creativity", "art"], skins: [{ unified: "1f58c-fe0f", native: "\u{1F58C}\uFE0F" }], version: 1 }, lower_left_crayon: { id: "lower_left_crayon", name: "Crayon", keywords: ["lower", "left", "drawing", "creativity"], skins: [{ unified: "1f58d-fe0f", native: "\u{1F58D}\uFE0F" }], version: 1 }, memo: { id: "memo", name: "Memo", keywords: ["pencil", "write", "documents", "stationery", "paper", "writing", "legal", "exam", "quiz", "test", "study", "compose"], skins: [{ unified: "1f4dd", native: "\u{1F4DD}" }], version: 1 }, briefcase: { id: "briefcase", name: "Briefcase", keywords: ["business", "documents", "work", "law", "legal", "job", "career"], skins: [{ unified: "1f4bc", native: "\u{1F4BC}" }], version: 1 }, file_folder: { id: "file_folder", name: "File Folder", keywords: ["documents", "business", "office"], skins: [{ unified: "1f4c1", native: "\u{1F4C1}" }], version: 1 }, open_file_folder: { id: "open_file_folder", name: "Open File Folder", keywords: ["documents", "load"], skins: [{ unified: "1f4c2", native: "\u{1F4C2}" }], version: 1 }, card_index_dividers: { id: "card_index_dividers", name: "Card Index Divi
51763ders", keywords: ["organizing", "business", "stationery"], skins: [{ unified: "1f5c2-fe0f", native: "\u{1F5C2}\uFE0F" }], version: 1 }, date: { id: "date", name: "Calendar", keywords: ["date", "schedule"], skins: [{ unified: "1f4c5", native: "\u{1F4C5}" }], version: 1 }, calendar: { id: "calendar", name: "Tear-off Calendar", keywords: ["tear", "off", "schedule", "date", "planning"], skins: [{ unified: "1f4c6", native: "\u{1F4C6}" }], version: 1 }, spiral_note_pad: { id: "spiral_note_pad", name: "Spiral Notepad", keywords: ["note", "pad", "memo", "stationery"], skins: [{ unified: "1f5d2-fe0f", native: "\u{1F5D2}\uFE0F" }], version: 1 }, spiral_calendar_pad: { id: "spiral_calendar_pad", name: "Spiral Calendar", keywords: ["pad", "date", "schedule", "planning"], skins: [{ unified: "1f5d3-fe0f", native: "\u{1F5D3}\uFE0F" }], version: 1 }, card_index: { id: "card_index", name: "Card Index", keywords: ["business", "stationery"], skins: [{ unified: "1f4c7", native: "\u{1F4C7}" }], version: 1 }, chart_with_upwards_trend: { id: "chart_with_upwards_trend", name: "Chart Increasing", keywords: ["with", "upwards", "trend", "graph", "presentation", "stats", "recovery", "business", "economics", "money", "sales", "good", "success"], skins: [{ unified: "1f4c8", native: "\u{1F4C8}" }], version: 1 }, chart_with_downwards_trend: { id: "chart_with_downwards_trend", name: "Chart Decreasing", keywords: ["with", "downwards", "trend", "graph", "presentation", "stats", "recession", "business", "economics", "money", "sales", "bad", "failure"], skins: [{ unified: "1f4c9", native: "\u{1F4C9}" }], version: 1 }, bar_chart: { id: "bar_chart", name: "Bar Chart", keywords: ["graph", "presentation", "stats"], skins: [{ unified: "1f4ca", native: "\u{1F4CA}" }], version: 1 }, clipboard: { id: "clipboard", name: "Clipboard", keywords: ["stationery", "documents"], skins: [{ unified: "1f4cb", native: "\u{1F4CB}" }], version: 1 }, pushpin: { id: "pushpin", name: "Pushpin", keywords: ["stationery", "mark", "here"], skins: [{ unified: "1f4cc", native: "\u{1F4CC}" }], version: 1 }, round_pushpin: { id: "round_pushpin", name: "Round Pushpin", keywords: ["stationery", "location", "map", "here"], skins: [{ unified: "1f4cd", native: "\u{1F4CD}" }], version: 1 }, paperclip: { id: "paperclip", name: "Paperclip", keywords: ["documents", "stationery"], skins: [{ unified: "1f4ce", native: "\u{1F4CE}" }], version: 1 }, linked_paperclips: { id: "linked_paperclips", name: "Linked Paperclips", keywords: ["documents", "stationery"], skins: [{ unified: "1f587-fe0f", native: "\u{1F587}\uFE0F" }], version: 1 }, straight_ruler: { id: "straight_ruler", name: "Straight Ruler", keywords: ["stationery", "calculate", "length", "math", "school", "drawing", "architect", "sketch"], skins: [{ unified: "1f4cf", native: "\u{1F4CF}" }], version: 1 }, triangular_ruler: { id: "triangular_ruler", name: "Triangular Ruler", keywords: ["stationery", "math", "architect", "sketch"], skins: [{ unified: "1f4d0", native: "\u{1F4D0}" }], version: 1 }, scissors: { id: "scissors", name: "Scissors", keywords: ["stationery", "cut"], skins: [{ unified: "2702-fe0f", native: "\u2702\uFE0F" }], version: 1 }, card_file_box: { id: "card_file_box", name: "Card File Box", keywords: ["business", "stationery"], skins: [{ unified: "1f5c3-fe0f", native: "\u{1F5C3}\uFE0F" }], version: 1 }, file_cabinet: { id: "file_cabinet", name: "File Cabinet", keywords: ["filing", "organizing"], skins: [{ unified: "1f5c4-fe0f", native: "\u{1F5C4}\uFE0F" }], version: 1 }, wastebasket: { id: "wastebasket", name: "Wastebasket", keywords: ["bin", "trash", "rubbish", "garbage", "toss"], skins: [{ unified: "1f5d1-fe0f", native: "\u{1F5D1}\uFE0F" }], version: 1 }, lock: { id: "lock", name: "Lock", keywords: ["locked", "security", "password", "padlock"], skins: [{ unified: "1f512", native: "\u{1F512}" }], version: 1 }, unlock: { id: "unlock", name: "Unlocked", keywords: ["unlock", "privacy", "security"], skins: [{ unified: "1f513", native: "\u{1F513}" }], version: 1 }, lock_with_ink_pen: { id: "lock_with_ink_pen", name: "Locked with Pen", keywords: ["lock", "ink", "security", "secret"], skins: [{ unified: "1f50f", native: "\u{1F50F}" }], version: 1 }, closed_lock_with_key: { id: "closed_lock_with_key", name: "Locked with Key", keywords: ["closed", "lock", "security", "privacy"], skins: [{ unified: "1f510", native: "\u{1F510}" }], version: 1 }, key: { id: "key", name: "Key", keywords: ["lock", "door", "password"], skins: [{ unified: "1f511", native: "\u{1F511}" }], version: 1 }, old_key: { id: "old_key", name: "Old Key", keywords: ["lock", "door", "password"], skins: [{ unified: "1f5dd-fe0f", native: "\u{1F5DD}\uFE0F" }], version: 1 }, hammer: { id: "hammer", name: "Hammer", keywords: ["tools", "build", "create"], skins: [{ unified: "1f528", native: "\u{1F528}" }
51763], version: 1 }, axe: { id: "axe", name: "Axe", keywords: ["tool", "chop", "cut"], skins: [{ unified: "1fa93", native: "\u{1FA93}" }], version: 12 }, pick: { id: "pick", name: "Pick", keywords: ["tools", "dig"], skins: [{ unified: "26cf-fe0f", native: "\u26CF\uFE0F" }], version: 1 }, hammer_and_pick: { id: "hammer_and_pick", name: "Hammer and Pick", keywords: ["tools", "build", "create"], skins: [{ unified: "2692-fe0f", native: "\u2692\uFE0F" }], version: 1 }, hammer_and_wrench: { id: "hammer_and_wrench", name: "Hammer and Wrench", keywords: ["tools", "build", "create"], skins: [{ unified: "1f6e0-fe0f", native: "\u{1F6E0}\uFE0F" }], version: 1 }, dagger_knife: { id: "dagger_knife", name: "Dagger", keywords: ["knife", "weapon"], skins: [{ unified: "1f5e1-fe0f", native: "\u{1F5E1}\uFE0F" }], version: 1 }, crossed_swords: { id: "crossed_swords", name: "Crossed Swords", keywords: ["weapon"], skins: [{ unified: "2694-fe0f", native: "\u2694\uFE0F" }], version: 1 }, bomb: { id: "bomb", name: "Bomb", keywords: ["boom", "explode", "explosion", "terrorism"], skins: [{ unified: "1f4a3", native: "\u{1F4A3}" }], version: 1 }, boomerang: { id: "boomerang", name: "Boomerang", keywords: ["weapon"], skins: [{ unified: "1fa83", native: "\u{1FA83}" }], version: 13 }, bow_and_arrow: { id: "bow_and_arrow", name: "Bow and Arrow", keywords: ["sports"], skins: [{ unified: "1f3f9", native: "\u{1F3F9}" }], version: 1 }, shield: { id: "shield", name: "Shield", keywords: ["protection", "security"], skins: [{ unified: "1f6e1-fe0f", native: "\u{1F6E1}\uFE0F" }], version: 1 }, carpentry_saw: { id: "carpentry_saw", name: "Carpentry Saw", keywords: ["cut", "chop"], skins: [{ unified: "1fa9a", native: "\u{1FA9A}" }], version: 13 }, wrench: { id: "wrench", name: "Wrench", keywords: ["tools", "diy", "ikea", "fix", "maintainer"], skins: [{ unified: "1f527", native: "\u{1F527}" }], version: 1 }, screwdriver: { id: "screwdriver", name: "Screwdriver", keywords: ["tools"], skins: [{ unified: "1fa9b", native: "\u{1FA9B}" }], version: 13 }, nut_and_bolt: { id: "nut_and_bolt", name: "Nut and Bolt", keywords: ["handy", "tools", "fix"], skins: [{ unified: "1f529", native: "\u{1F529}" }], version: 1 }, gear: { id: "gear", name: "Gear", keywords: ["cog"], skins: [{ unified: "2699-fe0f", native: "\u2699\uFE0F" }], version: 1 }, compression: { id: "compression", name: "Clamp", keywords: ["compression", "tool"], skins: [{ unified: "1f5dc-fe0f", native: "\u{1F5DC}\uFE0F" }], version: 1 }, scales: { id: "scales", name: "Balance Scale", keywords: ["scales", "law", "fairness", "weight"], skins: [{ unified: "2696-fe0f", native: "\u2696\uFE0F" }], version: 1 }, probing_cane: { id: "probing_cane", name: "White Cane", keywords: ["probing", "accessibility"], skins: [{ unified: "1f9af", native: "\u{1F9AF}" }], version: 12 }, link: { id: "link", name: "Link", keywords: ["rings", "url"], skins: [{ unified: "1f517", native: "\u{1F517}" }], version: 1 }, broken_chain: { id: "broken_chain", name: "Broken Chain", keywords: ["constraint", "break"], skins: [{ unified: "26d3-fe0f-200d-1f4a5", native: "\u26D3\uFE0F\u200D\u{1F4A5}" }], version: 15.1 }, chains: { id: "chains", name: "Chains", keywords: ["lock", "arrest"], skins: [{ unified: "26d3-fe0f", native: "\u26D3\uFE0F" }], version: 1 }, hook: { id: "hook", name: "Hook", keywords: ["tools"], skins: [{ unified: "1fa9d", native: "\u{1FA9D}" }], version: 13 }, toolbox: { id: "toolbox", name: "Toolbox", keywords: ["tools", "diy", "fix", "maintainer", "mechanic"], skins: [{ unified: "1f9f0", native: "\u{1F9F0}" }], version: 11 }, magnet: { id: "magnet", name: "Magnet", keywords: ["attraction", "magnetic"], skins: [{ unified: "1f9f2", native: "\u{1F9F2}" }], version: 11 }, ladder: { id: "ladder", name: "Ladder", keywords: ["tools"], skins: [{ unified: "1fa9c", native: "\u{1FA9C}" }], version: 13 }, shovel: { id: "shovel", name: "Shovel", keywords: [], skins: [{ unified: "1fa8f", native: "\u{1FA8F}" }], version: 16 }, alembic: { id: "alembic", name: "Alembic", keywords: ["distilling", "science", "experiment", "chemistry"], skins: [{ unified: "2697-fe0f", native: "\u2697\uFE0F" }], version: 1 }, test_tube: { id: "test_tube", name: "Test Tube", keywords: ["chemistry", "experiment", "lab", "science"], skins: [{ unified: "1f9ea", native: "\u{1F9EA}" }], version: 11 }, petri_dish: { id: "petri_dish", name: "Petri Dish", keywords: ["bacteria", "biology", "culture", "lab"], skins: [{ unified: "1f9eb", native: "\u{1F9EB}" }], version: 11 }, dna: { id: "dna", name: "Dna", keywords: ["biologist", "genetics", "life"], skins: [{ unified: "1f9ec", native: "\u{1F9EC}" }], version: 11 }, microscope: { id: "microscope", name: "Microscope", keywords: ["laboratory", "experiment", "zoomin", "science", "study"], skins: [{ unified: "1f52c", native: "\u{1F52C}" }], version: 1 }, telescope: { id: "telescope", name: "Telescope", keywords: ["stars", "space", "zoom", "science", "astronomy"], skins: [{ unified: "1f52d", native: "\u{1F52D}" }], version: 1 }, satellite_antenna: { id: "satellite_antenna", name: "Satellite Antenna", keywords: ["communication", "future", "radio", "space"], skins: [{ unified: "1f4e1", native: "\u{1F4E1}" }], version: 1 }, syringe: { id: "syringe", name: "Syringe", keywords: ["health", "hospital", "drugs", "blood", "medicine", "needle", "doctor", "nurse"], skins: [{ unified: "1f489", native: "\u{1F489}" }], version: 1 }, drop_of_blood: { id: "drop_of_blood", name: "Drop of Blood", keywords: ["period", "hurt", "harm", "wound"], skins: [{ unified: "1fa78", native: "\u{1FA78}" }], version: 12 }, pill: { id: "pill", name: "Pill", keywords: ["health", "medicine", "doctor", "pharmacy", "drug"], skins: [{ unified: "1f48a", native: "\u{1F48A}" }], version: 1 }, adhesive_bandage: { id: "adhesive_bandage", name: "Adhesive Bandage", keywords: ["heal"], skins: [{ unified: "1fa79", native: "\u{1FA79}" }], version: 12 }, crutch: { id: "crutch", name: "Crutch", keywords: ["accessibility", "assist"], skins: [{ unified: "1fa7c", native: "\u{1FA7C}" }], version: 14 }, stethoscope: { id: "stethoscope", name: "Stethoscope", keywords: ["health"], skins: [{ unified: "1fa7a", native: "\u{1FA7A}" }], version: 12 }, "x-ray": { id: "x-ray", name: "X-Ray", keywords: ["x", "ray", "skeleton", "medicine"], skins: [{ unified: "1fa7b", native: "\u{1FA7B}" }], version: 14 }, door: { id: "door", name: "Door", keywords: ["house", "entry", "exit"], skins: [{ unified: "1f6aa", native: "\u{1F6AA}" }], version: 1 }, elevator: { id: "elevator", name: "Elevator", keywords: ["lift"], skins: [{ unified: "1f6d7", native: "\u{1F6D7}" }], version: 13 }, mirror: { id: "mirror", name: "Mirror", keywords: ["reflection"], skins: [{ unified: "1fa9e", native: "\u{1FA9E}" }], version: 13 }
51763, window: { id: "window", name: "Window", keywords: ["scenery"], skins: [{ unified: "1fa9f", native: "\u{1FA9F}" }], version: 13 }, bed: { id: "bed", name: "Bed", keywords: ["sleep", "rest"], skins: [{ unified: "1f6cf-fe0f", native: "\u{1F6CF}\uFE0F" }], version: 1 }, couch_and_lamp: { id: "couch_and_lamp", name: "Couch and Lamp", keywords: ["read", "chill"], skins: [{ unified: "1f6cb-fe0f", native: "\u{1F6CB}\uFE0F" }], version: 1 }, chair: { id: "chair", name: "Chair", keywords: ["sit", "furniture"], skins: [{ unified: "1fa91", native: "\u{1FA91}" }], version: 12 }, toilet: { id: "toilet", name: "Toilet", keywords: ["restroom", "wc", "washroom", "bathroom", "potty"], skins: [{ unified: "1f6bd", native: "\u{1F6BD}" }], version: 1 }, plunger: { id: "plunger", name: "Plunger", keywords: ["toilet"], skins: [{ unified: "1faa0", native: "\u{1FAA0}" }], version: 13 }, shower: { id: "shower", name: "Shower", keywords: ["clean", "water", "bathroom"], skins: [{ unified: "1f6bf", native: "\u{1F6BF}" }], version: 1 }, bathtub: { id: "bathtub", name: "Bathtub", keywords: ["clean", "shower", "bathroom"], skins: [{ unified: "1f6c1", native: "\u{1F6C1}" }], version: 1 }, mouse_trap: { id: "mouse_trap", name: "Mouse Trap", keywords: ["cheese"], skins: [{ unified: "1faa4", native: "\u{1FAA4}" }], version: 13 }, razor: { id: "razor", name: "Razor", keywords: ["cut"], skins: [{ unified: "1fa92", native: "\u{1FA92}" }], version: 12 }, lotion_bottle: { id: "lotion_bottle", name: "Lotion Bottle", keywords: ["moisturizer", "sunscreen"], skins: [{ unified: "1f9f4", native: "\u{1F9F4}" }], version: 11 }, safety_pin: { id: "safety_pin", name: "Safety Pin", keywords: ["diaper"], skins: [{ unified: "1f9f7", native: "\u{1F9F7}" }], version: 11 }, broom: { id: "broom", name: "Broom", keywords: ["cleaning", "sweeping", "witch"], skins: [{ unified: "1f9f9", native: "\u{1F9F9}" }], version: 11 }, basket: { id: "basket", name: "Basket", keywords: ["laundry"], skins: [{ unified: "1f9fa", native: "\u{1F9FA}" }], version: 11 }, roll_of_paper: { id: "roll_of_paper", name: "Roll of Paper", keywords: [], skins: [{ unified: "1f9fb", native: "\u{1F9FB}" }], version: 11 }
51763, bucket: { id: "bucket", name: "Bucket", keywords: ["water", "container"], skins: [{ unified: "1faa3", native: "\u{1FAA3}" }], version: 13 }, soap: { id: "soap", name: "Soap", keywords: ["bar", "bathing", "cleaning", "lather"], skins: [{ unified: "1f9fc", native: "\u{1F9FC}" }], version: 11 }, bubbles: { id: "bubbles", name: "Bubbles", keywords: ["soap", "fun", "carbonation", "sparkling"], skins: [{ unified: "1fae7", native: "\u{1FAE7}" }], version: 14 }, toothbrush: { id: "toothbrush", name: "Toothbrush", keywords: ["hygiene", "dental"], skins: [{ unified: "1faa5", native: "\u{1FAA5}" }], version: 13 }, sponge: { id: "sponge", name: "Sponge", keywords: ["absorbing", "cleaning", "porous"], skins: [{ unified: "1f9fd", native: "\u{1F9FD}" }], version: 11 }, fire_extinguisher: { id: "fire_extinguisher", name: "Fire Extinguisher", keywords: ["quench"], skins: [{ unified: "1f9ef", native: "\u{1F9EF}" }], version: 11 }, shopping_trolley: { id: "shopping_trolley", name: "Shopping Cart", keywords: ["trolley"], skins: [{ unified: "1f6d2", native: "\u{1F6D2}" }], version: 3 }, smoking: { id: "smoking", name: "Cigarette", keywords: ["smoking", "kills", "tobacco", "joint", "smoke"], skins: [{ unified: "1f6ac", native: "\u{1F6AC}" }], version: 1 }, coffin: { id: "coffin", name: "Coffin", keywords: ["vampire", "dead", "die", "death", "rip", "graveyard", "cemetery", "casket", "funeral", "box"], skins: [{ unified: "26b0-fe0f", native: "\u26B0\uFE0F" }], version: 1 }, headstone: { id: "headstone", name: "Headstone", keywords: ["death", "rip", "grave"], skins: [{ unified: "1faa6", native: "\u{1FAA6}" }], version: 13 }, funeral_urn: { id: "funeral_urn", name: "Funeral Urn", keywords: ["dead", "die", "death", "rip", "ashes"], skins: [{ unified: "26b1-fe0f", native: "\u26B1\uFE0F" }], version: 1 }, nazar_amulet: { id: "nazar_amulet", name: "Nazar Amulet", keywords: ["bead", "charm"], skins: [{ unified: "1f9ff", native: "\u{1F9FF}" }], version: 11 }, hamsa: { id: "hamsa", name: "Hamsa", keywords: ["religion", "protection"], skins: [{ unified: "1faac", native: "\u{1FAAC}" }], version: 14 }, moyai: { id: "moyai", name: "Moai", keywords: ["moyai", "rock", "easter", "island"], skins: [{ unified: "1f5ff", native: "\u{1F5FF}" }], version: 1 }, placard: { id: "placard", name: "Placard", keywords: ["announcement"], skins: [{ unified: "1faa7", native: "\u{1FAA7}" }], version: 13 }, identification_card: { id: "identification_card", name: "Identification Card", keywords: ["document"], skins: [{ unified: "1faaa", native: "\u{1FAAA}" }], version: 14 }, atm: { id: "atm", name: "Atm Sign", keywords: ["money", "sales", "cash", "blue", "square", "payment", "bank"], skins: [{ unified: "1f3e7", native: "\u{1F3E7}" }], version: 1 }, put_litter_in_its_place: { id: "put_litter_in_its_place", name: "Litter in Bin Sign", keywords: ["put", "its", "place", "blue", "square", "human", "info"], skins: [{ unified: "1f6ae", native: "\u{1F6AE}" }], version: 1 }, potable_water: { id: "potable_water", name: "Potable Water", keywords: ["blue", "square", "liquid", "restroom", "cleaning", "faucet"], skins: [{ unified: "1f6b0", native: "\u{1F6B0}" }], version: 1 }, wheelchair: { id: "wheelchair", name: "Wheelchair Symbol", keywords: ["blue", "square", "disabled", "accessibility"], skins: [{ unified: "267f", native: "\u267F" }], version: 1 }, mens: { id: "mens", name: "Men\u2019s Room", keywords: ["mens", "men", "s", "toilet", "restroom", "wc", "blue", "square", "gender", "male"], skins: [{ unified: "1f6b9", native: "\u{1F6B9}" }], version: 1 }, womens: { id: "womens", name: "Women\u2019s Room", keywords: ["womens", "women", "s", "purple", "square", "woman", "female", "toilet", "loo", "restroom", "gender"], skins: [{ unified: "1f6ba", native: "\u{1F6BA}" }], version: 1 }, restroom: { id: "restroom", name: "Restroom", keywords: ["blue", "square", "toilet", "refresh", "wc", "gender"], skins: [{ unified: "1f6bb", native: "\u{1F6BB}" }], version: 1 }, baby_symbol: { id: "baby_symbol", name: "Baby Symbol", keywords: ["orange", "square", "child"], skins: [{ unified: "1f6bc", native: "\u{1F6BC}" }], version: 1 }, wc: { id: "wc", name: "Water Closet", keywords: ["wc", "toilet", "restroom", "blue", "square"], skins: [{ unified: "1f6be", native: "\u{1F6BE}" }], version: 1 }, passport_control: { id: "passport_control", name: "Passport Control", keywords: ["custom", "blue", "square"], skins: [{ unified: "1f6c2", native: "\u{1F6C2}" }
51763], version: 1 }, customs: { id: "customs", name: "Customs", keywords: ["passport", "border", "blue", "square"], skins: [{ unified: "1f6c3", native: "\u{1F6C3}" }], version: 1 }, baggage_claim: { id: "baggage_claim", name: "Baggage Claim", keywords: ["blue", "square", "airport", "transport"], skins: [{ unified: "1f6c4", native: "\u{1F6C4}" }], version: 1 }, left_luggage: { id: "left_luggage", name: "Left Luggage", keywords: ["blue", "square", "travel"], skins: [{ unified: "1f6c5", native: "\u{1F6C5}" }], version: 1 }, warning: { id: "warning", name: "Warning", keywords: ["exclamation", "wip", "alert", "error", "problem", "issue"], skins: [{ unified: "26a0-fe0f", native: "\u26A0\uFE0F" }], version: 1 }, children_crossing: { id: "children_crossing", name: "Children Crossing", keywords: ["school", "warning", "danger", "sign", "driving", "yellow", "diamond"], skins: [{ unified: "1f6b8", native: "\u{1F6B8}" }], version: 1 }, no_entry: { id: "no_entry", name: "No Entry", keywords: ["limit", "security", "privacy", "bad", "denied", "stop", "circle"], skins: [{ unified: "26d4", native: "\u26D4" }], version: 1 }, no_entry_sign: { id: "no_entry_sign", name: "Prohibited", keywords: ["no", "entry", "sign", "forbid", "stop", "limit", "denied", "disallow", "circle"], skins: [{ unified: "1f6ab", native: "\u{1F6AB}" }], version: 1 }, no_bicycles: { id: "no_bicycles", name: "No Bicycles", keywords: ["bikes", "bicycle", "bike", "cyclist", "prohibited", "circle"], skins: [{ unified: "1f6b3", native: "\u{1F6B3}" }], version: 1 }, no_smoking: { id: "no_smoking", name: "No Smoking", keywords: ["cigarette", "blue", "square", "smell", "smoke"], skins: [{ unified: "1f6ad", native: "\u{1F6AD}" }], version: 1 }, do_not_litter: { id: "do_not_litter", name: "No Littering", keywords: ["do", "not", "litter", "trash", "bin", "garbage", "circle"], skins: [{ unified: "1f6af", native: "\u{1F6AF}" }], version: 1 }, "non-potable_water": { id: "non-potable_water", name: "Non-Potable Water", keywords: ["non", "potable", "drink", "faucet", "tap", "circle"], skins: [{ unified: "1f6b1", native: "\u{1F6B1}" }], version: 1 }, no_pedestrians: { id: "no_pedestrians", name: "No Pedestrians", keywords: ["rules", "crossing", "walking", "circle"], skins: [{ unified: "1f6b7", native: "\u{1F6B7}" }], version: 1 }, no_mobile_phones: { id: "no_mobile_phones", name: "No Mobile Phones", keywords: ["iphone", "mute", "circle"], skins: [{ unified: "1f4f5", native: "\u{1F4F5}" }], version: 1 }, underage: { id: "underage", name: "No One Under Eighteen", keywords: ["underage", "18", "drink", "pub", "night", "minor", "circle"], skins: [{ unified: "1f51e", native: "\u{1F51E}" }], version: 1 }, radioactive_sign: { id: "radioactive_sign", name: "Radioactive", keywords: ["sign", "nuclear", "danger"], skins: [{ unified: "2622-fe0f", native: "\u2622\uFE0F" }], version: 1 }, biohazard_sign: { id: "biohazard_sign", name: "Biohazard", keywords: ["sign", "danger"], skins: [{ unified: "2623-fe0f", native: "\u2623\uFE0F" }], version: 1 }, arrow_up: { id: "arrow_up", name: "Up Arrow", keywords: ["blue", "square", "continue", "top", "direction"], skins: [{ unified: "2b06-fe0f", native: "\u2B06\uFE0F" }], version: 1 }, arrow_upper_right: { id: "arrow_upper_right", name: "Up-Right Arrow", keywords: ["upper", "right", "up", "blue", "square", "point", "direction", "diagonal", "northeast"], skins: [{ unified: "2197-fe0f", native: "\u2197\uFE0F" }], version: 1 }, arrow_right: { id: "arrow_right", name: "Right Arrow", keywords: ["blue", "square", "next"], skins: [{ unified: "27a1-fe0f", native: "\u27A1\uFE0F" }], version: 1 }, arrow_lower_right: { id: "arrow_lower_right", name: "South East Arrow", keywords: ["lower", "right", "down", "blue", "square", "direction", "diagonal", "southeast"], skins: [{ unified: "2198-fe0f", native: "\u2198\uFE0F" }], version: 1 }, arrow_down: { id: "arrow_down", name: "Down Arrow", keywords: ["blue", "square", "direction", "bottom"], skins: [{ unified: "2b07-fe0f", native: "\u2B07\uFE0F" }], version: 1 }, arrow_lower_left: { id: "arrow_lower_left", name: "Down-Left Arrow", keywords: ["lower", "left", "down", "blue", "square", "direction", "diagonal", "southwest"], skins: [{ unified: "2199-fe0f", native: "\u2199\uFE0F" }], version: 1 }, arrow_left: { id: "arrow_left", name: "Left Arrow", keywords: ["blue", "square", "previous", "back"], skins: [{ unified: "2b05-fe0f", native: "\u2B05\uFE0F" }], version: 1 }, arrow_upper_left: { id: "arrow_upper_left", name: "Up-Left Arrow", keywords: ["upper", "left", "up", "blue", "square", "point", "direction", "diagonal", "northwest"], skins: [{ unified: "2196-fe0f", native: "\u2196\uFE0F" }], version: 1 }, arrow_up_down: { id: "arrow_up_down", name: "Up Down Arrow", keywords: ["blue", "square", "direction", "way", "vertical"], skins: [{ unified: "2195-fe0f", native: "\u2195\uFE0F" }], version: 1 }
51763, left_right_arrow: { id: "left_right_arrow", name: "Left Right Arrow", keywords: ["shape", "direction", "horizontal", "sideways"], skins: [{ unified: "2194-fe0f", native: "\u2194\uFE0F" }], version: 1 }, leftwards_arrow_with_hook: { id: "leftwards_arrow_with_hook", name: "Right Arrow Curving Left", keywords: ["leftwards", "with", "hook", "back", "return", "blue", "square", "undo", "enter"], skins: [{ unified: "21a9-fe0f", native: "\u21A9\uFE0F" }], version: 1 }, arrow_right_hook: { id: "arrow_right_hook", name: "Left Arrow Curving Right", keywords: ["hook", "blue", "square", "return", "rotate", "direction"], skins: [{ unified: "21aa-fe0f", native: "\u21AA\uFE0F" }], version: 1 }, arrow_heading_up: { id: "arrow_heading_up", name: "Right Arrow Curving Up", keywords: ["heading", "blue", "square", "direction", "top"], skins: [{ unified: "2934-fe0f", native: "\u2934\uFE0F" }], version: 1 }, arrow_heading_down: { id: "arrow_heading_down", name: "Right Arrow Curving Down", keywords: ["heading", "blue", "square", "direction", "bottom"], skins: [{ unified: "2935-fe0f", native: "\u2935\uFE0F" }], version: 1 }, arrows_clockwise: { id: "arrows_clockwise", name: "Clockwise Vertical Arrows", keywords: ["sync", "cycle", "round", "repeat"], skins: [{ unified: "1f503", native: "\u{1F503}" }], version: 1 }, arrows_counterclockwise: { id: "arrows_counterclockwise", name: "Counterclockwise Arrows Button", keywords: ["blue", "square", "sync", "cycle"], skins: [{ unified: "1f504", native: "\u{1F504}" }], version: 1 }, back: { id: "back", name: "Back Arrow", keywords: ["words", "return"], skins: [{ unified: "1f519", native: "\u{1F519}" }], version: 1 }, end: { id: "end", name: "End Arrow", keywords: ["words"], skins: [{ unified: "1f51a", native: "\u{1F51A}" }], version: 1 }, on: { id: "on", name: "On! Arrow", keywords: ["on", "words"], skins: [{ unified: "1f51b", native: "\u{1F51B}" }], version: 1 }, soon: { id: "soon", name: "Soon Arrow", keywords: ["words"], skins: [{ unified: "1f51c", native: "\u{1F51C}" }], version: 1 }, top: { id: "top", name: "Top Arrow", keywords: ["words", "blue", "square"], skins: [{ unified: "1f51d", native: "\u{1F51D}" }], version: 1 }, place_of_worship: { id: "place_of_worship", name: "Place of Worship", keywords: ["religion", "church", "temple", "prayer"], skins: [{ unified: "1f6d0", native: "\u{1F6D0}" }], version: 1 }, atom_symbol: { id: "atom_symbol", name: "Atom Symbol", keywords: ["science", "physics", "chemistry"], skins: [{ unified: "269b-fe0f", native: "\u269B\uFE0F" }], version: 1 }, om_symbol: { id: "om_symbol", name: "Om", keywords: ["symbol", "hinduism", "buddhism", "sikhism", "jainism"], skins: [{ unified: "1f549-fe0f", native: "\u{1F549}\uFE0F" }], version: 1 }, star_of_david: { id: "star_of_david", name: "Star of David", keywords: ["judaism"], skins: [{ unified: "2721-fe0f", native: "\u2721\uFE0F" }], version: 1 }, wheel_of_dharma: { id: "wheel_of_dharma", name: "Wheel of Dharma", keywords: ["hinduism", "buddhism", "sikhism", "jainism"], skins: [{ unified: "2638-fe0f", native: "\u2638\uFE0F" }], version: 1 }, yin_yang: { id: "yin_yang", name: "Yin Yang", keywords: ["balance"], skins: [{ unified: "262f-fe0f", native: "\u262F\uFE0F" }], version: 1 }, latin_cross: { id: "latin_cross", name: "Latin Cross", keywords: ["christianity"], skins: [{ unified: "271d-fe0f", native: "\u271D\uFE0F" }], version: 1 }, orthodox_cross: { id: "orthodox_cross", name: "Orthodox Cross", keywords: ["suppedaneum", "religion"], skins: [{ unified: "2626-fe0f", native: "\u2626\uFE0F" }], version: 1 }, star_and_crescent: { id: "star_and_crescent", name: "Star and Crescent", keywords: ["islam"], skins: [{ unified: "262a-fe0f", native: "\u262A\uFE0F" }], version: 1 }, peace_symbol: { id: "peace_symbol", name: "Peace Symbol", keywords: ["hippie"], skins: [{ unified: "262e-fe0f", native: "\u262E\uFE0F" }], version: 1 }, menorah_with_nine_branches: { id: "menorah_with_nine_branches", name: "Menorah", keywords: ["with", "nine", "branches", "hanukkah", "candles", "jewish"], skins: [{ unified: "1f54e", native: "\u{1F54E}" }], version: 1 }, six_pointed_star: { id: "six_pointed_star", name: "Dotted Six-Pointed Star", keywords: ["six", "pointed", "purple", "square", "religion", "jewish", "hexagram"], skins: [{ unified: "1f52f", native: "\u{1F52F}" }], version: 1 }, khanda: { id: "khanda", name: "Khanda", keywords: ["Sikhism", "religion"], skins: [{ unified: "1faaf", native: "\u{1FAAF}" }], version: 15 }, aries: { id: "aries", name: "Aries", keywords: ["sign", "purple", "square", "zodiac", "astrology"], skins: [{ unified: "2648", native: "\u2648" }], version: 1 }, taurus: { id: "taurus", name: "Taurus", keywords: ["purple", "square", "sign", "zodiac", "astrology"], skins: [{ unified: "2649", native: "\u2649" }], version: 1 }, gemini: { id: "gemini", name: "Gemini", keywords: ["sign", "zodiac", "purple", "square", "astrology"], skins: [{ unified: "264a", native: "\u264A" }], version: 1 }, cancer: { id: "cancer", name: "Cancer", keywords: ["sign", "zodiac", "purple", "square", "astrology"], skins: [{ unified: "264b", native: "\u264B" }], version: 1 }, leo: { id: "leo", name: "Leo", keywords: ["sign", "purple", "square", "zodiac", "astrology"], skins: [{ unified: "264c", native: "\u264C" }], version: 1 }, virgo: { id: "virgo", name: "Virgo", keywords: ["sign", "zodiac", "purple", "square", "astrology"], skins: [{ unified: "264d", native: "\u264D" }], version: 1 }, libra: { id: "libra", name: "Libra", keywords: ["sign", "purple", "square", "zodiac", "astrology"], skins: [{ unified: "264e", native: "\u264E" }], version: 1 }, scorpius: { id: "scorpius", name: "Scorpio", keywords: ["scorpius", "sign", "zodiac", "purple", "square", "astrology"], skins: [{ unified: "264f", native: "\u264F" }], version: 1 }, sagittarius: { id: "sagittarius", name: "Sagittarius", keywords: ["sign", "zodiac", "purple", "square", "astrology"], skins: [{ unified: "2650", native: "\u2650" }
51763], version: 1 }, capricorn: { id: "capricorn", name: "Capricorn", keywords: ["sign", "zodiac", "purple", "square", "astrology"], skins: [{ unified: "2651", native: "\u2651" }], version: 1 }, aquarius: { id: "aquarius", name: "Aquarius", keywords: ["sign", "purple", "square", "zodiac", "astrology"], skins: [{ unified: "2652", native: "\u2652" }], version: 1 }, pisces: { id: "pisces", name: "Pisces", keywords: ["purple", "square", "sign", "zodiac", "astrology"], skins: [{ unified: "2653", native: "\u2653" }], version: 1 }, ophiuchus: { id: "ophiuchus", name: "Ophiuchus", keywords: ["sign", "purple", "square", "constellation", "astrology"], skins: [{ unified: "26ce", native: "\u26CE" }], version: 1 }, twisted_rightwards_arrows: { id: "twisted_rightwards_arrows", name: "Shuffle Tracks Button", keywords: ["twisted", "rightwards", "arrows", "blue", "square", "music", "random"], skins: [{ unified: "1f500", native: "\u{1F500}" }], version: 1 }, repeat: { id: "repeat", name: "Repeat Button", keywords: ["loop", "record"], skins: [{ unified: "1f501", native: "\u{1F501}" }], version: 1 }, repeat_one: { id: "repeat_one", name: "Repeat Single Button", keywords: ["one", "blue", "square", "loop"], skins: [{ unified: "1f502", native: "\u{1F502}" }], version: 1 }, arrow_forward: { id: "arrow_forward", name: "Play Button", keywords: ["arrow", "forward", "blue", "square", "right", "direction"], skins: [{ unified: "25b6-fe0f", native: "\u25B6\uFE0F" }], version: 1 }, fast_forward: { id: "fast_forward", name: "Fast-Forward Button", keywords: ["fast", "forward", "blue", "square", "play", "speed", "continue"], skins: [{ unified: "23e9", native: "\u23E9" }], version: 1 }, black_right_pointing_double_triangle_with_vertical_bar: { id: "black_right_pointing_double_triangle_with_vertical_bar", name: "Next Track Button", keywords: ["black", "right", "pointing", "double", "triangle", "with", "vertical", "bar", "forward", "blue", "square"], skins: [{ unified: "23ed-fe0f", native: "\u23ED\uFE0F" }], version: 1 }, black_right_pointing_triangle_with_double_vertical_bar: { id: "black_right_pointing_triangle_with_double_vertical_bar", name: "Play or Pause Button", keywords: ["black", "right", "pointing", "triangle", "with", "double", "vertical", "bar", "blue", "square"], skins: [{ unified: "23ef-fe0f", native: "\u23EF\uFE0F" }], version: 1 }, arrow_backward: { id: "arrow_backward", name: "Reverse Button", keywords: ["arrow", "backward", "blue", "square", "left", "direction"], skins: [{ unified: "25c0-fe0f", native: "\u25C0\uFE0F" }], version: 1 }, rewind: { id: "rewind", name: "Fast Reverse Button", keywords: ["rewind", "play", "blue", "square"], skins: [{ unified: "23ea", native: "\u23EA" }], version: 1 }, black_left_pointing_double_triangle_with_vertical_bar: { id: "black_left_pointing_double_triangle_with_vertical_bar", name: "Last Track Button", keywords: ["black", "left", "pointing", "double", "triangle", "with", "vertical", "bar", "backward"], skins: [{ unified: "23ee-fe0f", native: "\u23EE\uFE0F" }], version: 1 }, arrow_up_small: { id: "arrow_up_small", name: "Upwards Button", keywords: ["arrow", "up", "small", "blue", "square", "triangle", "direction", "point", "forward", "top"], skins: [{ unified: "1f53c", native: "\u{1F53C}" }], version: 1 }, arrow_double_up: { id: "arrow_double_up", name: "Fast Up Button", keywords: ["arrow", "double", "blue", "square", "direction", "top"], skins: [{ unified: "23eb", native: "\u23EB" }], version: 1 }, arrow_down_small: { id: "arrow_down_small", name: "Downwards Button", keywords: ["arrow", "down", "small", "blue", "square", "direction", "bottom"], skins: [{ unified: "1f53d", native: "\u{1F53D}" }], version: 1 }, arrow_double_down: { id: "arrow_double_down", name: "Fast Down Button", keywords: ["arrow", "double", "blue", "square", "direction", "bottom"], skins: [{ unified: "23ec", native: "\u23EC" }], version: 1 }, double_vertical_bar: { id: "double_vertical_bar", name: "Pause Button", keywords: ["double", "vertical", "bar", "blue", "square"], skins: [{ unified: "23f8-fe0f", native: "\u23F8\uFE0F" }], version: 1 }, black_square_for_stop: { id: "black_square_for_stop", name: "Stop Button", keywords: ["black", "square", "for", "blue"], skins: [{ unified: "23f9-fe0f", native: "\u23F9\uFE0F" }], version: 1 }, black_circle_for_record: { id: "black_circle_for_record", name: "Record Button", keywords: ["black", "cir
51763cle", "for", "blue", "square"], skins: [{ unified: "23fa-fe0f", native: "\u23FA\uFE0F" }], version: 1 }, eject: { id: "eject", name: "Eject Button", keywords: ["blue", "square"], skins: [{ unified: "23cf-fe0f", native: "\u23CF\uFE0F" }], version: 1 }, cinema: { id: "cinema", name: "Cinema", keywords: ["blue", "square", "record", "film", "movie", "curtain", "stage", "theater"], skins: [{ unified: "1f3a6", native: "\u{1F3A6}" }], version: 1 }, low_brightness: { id: "low_brightness", name: "Dim Button", keywords: ["low", "brightness", "sun", "afternoon", "warm", "summer"], skins: [{ unified: "1f505", native: "\u{1F505}" }], version: 1 }, high_brightness: { id: "high_brightness", name: "Bright Button", keywords: ["high", "brightness", "sun", "light"], skins: [{ unified: "1f506", native: "\u{1F506}" }], version: 1 }, signal_strength: { id: "signal_strength", name: "Antenna Bars", keywords: ["signal", "strength", "blue", "square", "reception", "phone", "internet", "connection", "wifi", "bluetooth"], skins: [{ unified: "1f4f6", native: "\u{1F4F6}" }], version: 1 }, wireless: { id: "wireless", name: "Wireless", keywords: ["wifi", "internet", "contactless", "signal"], skins: [{ unified: "1f6dc", native: "\u{1F6DC}" }], version: 15 }, vibration_mode: { id: "vibration_mode", name: "Vibration Mode", keywords: ["orange", "square", "phone"], skins: [{ unified: "1f4f3", native: "\u{1F4F3}" }], version: 1 }, mobile_phone_off: { id: "mobile_phone_off", name: "Mobile Phone off", keywords: ["mute", "orange", "square", "silence", "quiet"], skins: [{ unified: "1f4f4", native: "\u{1F4F4}" }], version: 1 }, female_sign: { id: "female_sign", name: "Female Sign", keywords: ["woman", "women", "lady", "girl"], skins: [{ unified: "2640-fe0f", native: "\u2640\uFE0F" }], version: 4 }, male_sign: { id: "male_sign", name: "Male Sign", keywords: ["man", "boy", "men"], skins: [{ unified: "2642-fe0f", native: "\u2642\uFE0F" }], version: 4 }, transgender_symbol: { id: "transgender_symbol", name: "Transgender Symbol", keywords: ["lgbtq"], skins: [{ unified: "26a7-fe0f", native: "\u26A7\uFE0F" }], version: 13 }, heavy_multiplication_x: { id: "heavy_multiplication_x", name: "Multiply", keywords: ["heavy", "multiplication", "x", "sign", "math", "calculation"], skins: [{ unified: "2716-fe0f", native: "\u2716\uFE0F" }], version: 1 }, heavy_plus_sign: { id: "heavy_plus_sign", name: "Plus", keywords: ["heavy", "sign", "math", "calculation", "addition", "more", "increase"], skins: [{ unified: "2795", native: "\u2795" }], version: 1 }, heavy_minus_sign: { id: "heavy_minus_sign", name: "Minus", keywords: ["heavy", "sign", "math", "calculation", "subtract", "less"], skins: [{ unified: "2796", native: "\u2796" }], version: 1 }, heavy_division_sign: { id: "heavy_division_sign", name: "Divide", keywords: ["heavy", "division", "sign", "math", "calculation"], skins: [{ unified: "2797", native: "\u2797" }], version: 1 }, heavy_equals_sign: { id: "heavy_equals_sign", name: "Heavy Equals Sign", keywords: ["math"], skins: [{ unified: "1f7f0", native: "\u{1F7F0}" }], version: 14 }, infinity: { id: "infinity", name: "Infinity", keywords: ["forever"], skins: [{ unified: "267e-fe0f", native: "\u267E\uFE0F" }], version: 11 }, bangbang: { id: "bangbang", name: "Double Exclamation Mark", keywords: ["bangbang", "surprise"], skins: [{ unified: "203c-fe0f", native: "\u203C\uFE0F" }], version: 1 }, interrobang: { id: "interrobang", name: "Exclamation Question Mark", keywords: ["interrobang", "wat", "punctuation", "surprise"], skins: [{ unified: "2049-fe0f", native: "\u2049\uFE0F" }], version: 1 }, question: { id: "question", name: "Red Question Mark", keywords: ["doubt", "confused"], skins: [{ unified: "2753", native: "\u2753" }], version: 1 }, grey_question: { id: "grey_question", name: "White Question Mark", keywords: ["grey", "doubts", "gray", "huh", "confused"], skins: [{ unified: "2754", native: "\u2754" }], version: 1 }, grey_exclamation: { id: "grey_exclamation", name: "White Exclamation Mark", keywords: ["grey", "surprise", "punctuation", "gray", "wow", "warning"], skins: [{ unified: "2755", native: "\u27
5176355" }], version: 1 }, exclamation: { id: "exclamation", name: "Red Exclamation Mark", keywords: ["heavy", "danger", "surprise", "punctuation", "wow", "warning"], skins: [{ unified: "2757", native: "\u2757" }], version: 1 }, wavy_dash: { id: "wavy_dash", name: "Wavy Dash", keywords: ["draw", "line", "moustache", "mustache", "squiggle", "scribble"], skins: [{ unified: "3030-fe0f", native: "\u3030\uFE0F" }], version: 1 }, currency_exchange: { id: "currency_exchange", name: "Currency Exchange", keywords: ["money", "sales", "dollar", "travel"], skins: [{ unified: "1f4b1", native: "\u{1F4B1}" }], version: 1 }, heavy_dollar_sign: { id: "heavy_dollar_sign", name: "Heavy Dollar Sign", keywords: ["money", "sales", "payment", "currency", "buck"], skins: [{ unified: "1f4b2", native: "\u{1F4B2}" }], version: 1 }, medical_symbol: { id: "medical_symbol", name: "Medical Symbol", keywords: ["staff", "of", "aesculapius", "health", "hospital"], skins: [{ unified: "2695-fe0f", native: "\u2695\uFE0F" }], version: 4 }, recycle: { id: "recycle", name: "Recycling Symbol", keywords: ["recycle", "arrow", "environment", "garbage", "trash"], skins: [{ unified: "267b-fe0f", native: "\u267B\uFE0F" }], version: 1 }, fleur_de_lis: { id: "fleur_de_lis", name: "Fleur-De-Lis", keywords: ["fleur", "de", "lis", "decorative", "scout"], skins: [{ unified: "269c-fe0f", native: "\u269C\uFE0F" }], version: 1 }, trident: { id: "trident", name: "Trident Emblem", keywords: ["weapon", "spear"], skins: [{ unified: "1f531", native: "\u{1F531}" }], version: 1 }, name_badge: { id: "name_badge", name: "Name Badge", keywords: ["fire", "forbid"], skins: [{ unified: "1f4db", native: "\u{1F4DB}" }], version: 1 }, beginner: { id: "beginner", name: "Japanese Symbol for Beginner", keywords: ["badge", "shield"], skins: [{ unified: "1f530", native: "\u{1F530}" }], version: 1 }, o: { id: "o", name: "Hollow Red Circle", keywords: ["o", "round"], skins: [{ unified: "2b55", native: "\u2B55" }], version: 1 }, white_check_mark: { id: "white_check_mark", name: "Check Mark Button", keywords: ["white", "green", "square", "ok", "agree", "vote", "election", "answer", "tick"], skins: [{ unified: "2705", native: "\u2705" }], version: 1 }, ballot_box_with_check: { id: "ballot_box_with_check", name: "Check Box with Check", keywords: ["ballot", "ok", "agree", "confirm", "black", "square", "vote", "election", "yes", "tick"], skins: [{ unified: "2611-fe0f", native: "\u2611\uFE0F" }], version: 1 }, heavy_check_mark: { id: "heavy_check_mark", name: "Check Mark", keywords: ["heavy", "ok", "nike", "answer", "yes", "tick"], skins: [{ unified: "2714-fe0f", native: "\u2714\uFE0F" }], version: 1 }, x: { id: "x", name: "Cross Mark", keywords: ["x", "no", "delete", "remove", "cancel", "red"], skins: [{ unified: "274c", native: "\u274C" }], version: 1 }, negative_squared_cross_mark: { id: "negative_squared_cross_mark", name: "Cross Mark Button", keywords: ["negative", "squared", "x", "green", "square", "no", "deny"], skins: [{ unified: "274e", native: "\u274E" }], version: 1 }, curly_loop: { id: "curly_loop", name: "Curly Loop", keywords: ["scribble", "draw", "shape", "squiggle"], skins: [{ unified: "27b0", native: "\u27B0" }], version: 1 }, loop: { id: "loop", name: "Double Curly Loop", keywords: ["tape", "cassette"], skins: [{ unified: "27bf", native: "\u27BF" }], version: 1 }, part_alternation_mark: { id: "part_alternation_mark", name: "Part Alternation Mark", keywords: ["graph", "presentation", "stats", "business", "economics", "bad"], skins: [{ unified: "303d-fe0f", native: "\u303D\uFE0F" }], version: 1 }, eight_spoked_asterisk: { id: "eight_spoked_asterisk", name: "Eight Spoked Asterisk", keywords: ["star", "sparkle", "green", "square"], skins: [{ unified: "2733-fe0f", native: "\u2733\uFE0F" }], version: 1 }, eight_pointed_black_star: { id: "eight_pointed_black_star", name: "Eight-Pointed Star", keywords: ["eight", "pointed", "black", "orange", "square", "shape", "polygon"], skins: [{ unified: "2734-fe0f", native: "\u2734\uFE0F" }], version: 1 }, sparkle: { id: "sparkle", name: "Sparkle", keywords: ["stars", "green", "square", "awe
51763some", "good", "fireworks"], skins: [{ unified: "2747-fe0f", native: "\u2747\uFE0F" }], version: 1 }, copyright: { id: "copyright", name: "Copyright", keywords: ["ip", "license", "circle", "law", "legal"], skins: [{ unified: "00a9-fe0f", native: "\xA9\uFE0F" }], version: 1 }, registered: { id: "registered", name: "Registered", keywords: ["alphabet", "circle"], skins: [{ unified: "00ae-fe0f", native: "\xAE\uFE0F" }], version: 1 }, tm: { id: "tm", name: "Trade Mark", keywords: ["tm", "trademark", "brand", "law", "legal"], skins: [{ unified: "2122-fe0f", native: "\u2122\uFE0F" }], version: 1 }, splatter: { id: "splatter", name: "Splatter", keywords: [], skins: [{ unified: "1fadf", native: "\u{1FADF}" }], version: 16 }, hash: { id: "hash", name: "Hash Key", keywords: ["keycap", "", "symbol", "blue", "square", "twitter"], skins: [{ unified: "0023-fe0f-20e3", native: "#\uFE0F\u20E3" }], version: 1 }, keycap_star: { id: "keycap_star", name: "Keycap: *", keywords: ["keycap", "star", ""], skins: [{ unified: "002a-fe0f-20e3", native: "*\uFE0F\u20E3" }], version: 2 }, zero: { id: "zero", name: "Keycap 0", keywords: ["zero", "numbers", "blue", "square", "null"], skins: [{ unified: "0030-fe0f-20e3", native: "0\uFE0F\u20E3" }], version: 1 }, one: { id: "one", name: "Keycap 1", keywords: ["one", "blue", "square", "numbers"], skins: [{ unified: "0031-fe0f-20e3", native: "1\uFE0F\u20E3" }], version: 1 }, two: { id: "two", name: "Keycap 2", keywords: ["two", "numbers", "prime", "blue", "square"], skins: [{ unified: "0032-fe0f-20e3", native: "2\uFE0F\u20E3" }], version: 1 }, three: { id: "three", name: "Keycap 3", keywords: ["three", "numbers", "prime", "blue", "square"], skins: [{ unified: "0033-fe0f-20e3", native: "3\uFE0F\u20E3" }], version: 1 }, four: { id: "four", name: "Keycap 4", keywords: ["four", "numbers", "blue", "square"], skins: [{ unified: "0034-fe0f-20e3", native: "4\uFE0F\u20E3" }], version: 1 }, five: { id: "five", name: "Keycap 5", keywords: ["five", "numbers", "blue", "square", "prime"], skins: [{ unified: "0035-fe0f-20e3", native: "5\uFE0F\u20E3" }], version: 1 }, six: { id: "six", name: "Keycap 6", keywords: ["six", "numbers", "blue", "square"], skins: [{ unified: "0036-fe0f-20e3", native: "6\uFE0F\u20E3" }], version: 1 }, seven: { id: "seven", name: "Keycap 7", keywords: ["seven", "numbers", "blue", "square", "prime"], skins: [{ unified: "0037-fe0f-20e3", native: "7\uFE0F\u20E3" }], version: 1 }, eight: { id: "eight", name: "Keycap 8", keywords: ["eight", "blue", "square", "numbers"], skins: [{ unified: "0038-fe0f-20e3", native: "8\uFE0F\u20E3" }], version: 1 }, nine: { id: "nine", name: "Keycap 9", keywords: ["nine", "blue", "square", "numbers"], skins: [{ unified: "0039-fe0f-20e3", native: "9\uFE0F\u20E3" }], version: 1 }, keycap_ten: { id: "keycap_ten", name: "Keycap 10", keywords: ["ten", "numbers", "blue", "square"], skins: [{ unified: "1f51f", native: "\u{1F51F}" }], version: 1 }, capital_abcd: { id: "capital_abcd", name: "Input Latin Uppercase", keywords: ["capital", "abcd", "alphabet", "words", "letters", "blue", "square"], skins: [{ unified: "1f520", native: "\u{1F520}" }], version: 1 }, abcd: { id: "abcd", name: "Input Latin Lowercase", keywords: ["abcd", "blue", "square", "letters", "alphabet"], skins: [{ unified: "1f521", native: "\u{1F521}" }], version: 1 }, symbols: { id: "symbols", name: "Input Symbols", keywords: ["blue", "square", "music", "note", "ampersand", "percent", "glyphs", "characters"], skins: [{ unified: "1f523", native: "\u{1F523}" }], version: 1 }, abc: { id: "abc", name: "Input Latin Letters", keywords: ["abc", "blue", "square", "alphabet"], skins: [{ unified: "1f524", native: "\u{1F524}" }], version: 1 }, a: { id: "a", name: "A Button (blood Type)", keywords: ["red", "square", "alphabet", "letter"], skins: [{ unified: "1f170-fe0f", native: "\u{1F170}\uFE0F" }], version: 1 }, ab: { id: "ab", name: "Negative Squared Ab", keywords: ["button", "red", "square", "alphabet"], skins: [{ unified: "1f18e", native: "\u{1F18E}" }], version: 1 }, b: { id: "b", name: "B Button (blood Type)", keywords: ["red", "square", "alphabet", "letter"], skins: [{ unified: "1f171-fe0f", native: "\u{1F171}\uFE0F" }], version: 1 }, cl: { id: "cl", name: "Cl Button", keywords: ["alphabet", "words", "red", "square"], skins: [{ unified: "1f191", native: "\u{1F191}" }], version: 1 }, cool: { id: "cool", name: "Cool Button", keywords: ["words", "blue", "square"], skins: [{ unified: "1f192", native: "\u{1F192}" }], version: 1 }, free: { id: "free", name: "Free Button", keywords: ["blue", "square", "words"], skins: [{ unified: "1f193", native: "\u{1F193}" }], version: 1 }, information_source: { id: "information_source", name: "Information", keywords: ["source", "blue", "square", "alphabet", "letter"], skins: [{ unified: "2139-fe0f", native: "\u2139\uFE0F" }], version: 1 }, id: { id: "id", name: "Id Button", keywords: ["purple", "square", "words"], skins: [{ unified: "1f194", native: "\u{1F194}" }], version: 1 }, m: { id: "m", name: "Circled M", keywords: ["alphabet", "blue", "circle", "letter"], skins: [{ unified: "24c2-fe0f", native: "\u24C2\uFE0F" }], version: 1 }, new: { id: "new", name: "New Button", keywords: ["blue", "square", "words", "start"], skins: [{ unified: "1f195", native: "\u{1F195}" }], version: 1 }, ng: { id: "ng", name: "Ng Button", keywords: ["blue", "square", "words", "shape", "icon"], skins: [{ unified: "1f196", native: "\u{1F196}" }], version: 1 }, o2: { id: "o2", name: "O Button (blood Type)", keywords: ["o2", "alphabet", "red", "square", "letter"], skins: [{ unified: "1f17e-fe0f", native: "\u{1F17E}\uFE0F" }], version: 1 }, ok: { id: "ok", name: "Ok Button", keywords: ["good", "agree", "yes", "blue", "square"], skins: [{ unified: "1f197", native: "\u{1F197}" }], version: 1 }
51763, parking: { id: "parking", name: "P Button", keywords: ["parking", "cars", "blue", "square", "alphabet", "letter"], skins: [{ unified: "1f17f-fe0f", native: "\u{1F17F}\uFE0F" }], version: 1 }, sos: { id: "sos", name: "Sos Button", keywords: ["help", "red", "square", "words", "emergency", "911"], skins: [{ unified: "1f198", native: "\u{1F198}" }], version: 1 }, up: { id: "up", name: "Up! Button", keywords: ["up", "blue", "square", "above", "high"], skins: [{ unified: "1f199", native: "\u{1F199}" }], version: 1 }, vs: { id: "vs", name: "Vs Button", keywords: ["words", "orange", "square"], skins: [{ unified: "1f19a", native: "\u{1F19A}" }], version: 1 }, koko: { id: "koko", name: "Squared Katakana Koko", keywords: ["japanese", "here", "button", "blue", "square", "destination"], skins: [{ unified: "1f201", native: "\u{1F201}" }], version: 1 }, sa: { id: "sa", name: "Squared Katakana Sa", keywords: ["japanese", "service", "charge", "button", "blue", "square"], skins: [{ unified: "1f202-fe0f", native: "\u{1F202}\uFE0F" }], version: 1 }, u6708: { id: "u6708", name: "Japanese \u201Cmonthly Amount\u201D Button", keywords: ["u6708", "monthly", "amount", "chinese", "month", "moon", "orange", "square", "kanji"], skins: [{ unified: "1f237-fe0f", native: "\u{1F237}\uFE0F" }], version: 1 }, u6709: { id: "u6709", name: "Squared Cjk Unified Ideograph-6709", keywords: ["u6709", "japanese", "not", "free", "of", "charge", "button", "orange", "square", "chinese", "have", "kanji"], skins: [{ unified: "1f236", native: "\u{1F236}" }], version: 1 }, u6307: { id: "u6307", name: "Japanese \u201Creserved\u201D Button", keywords: ["u6307", "reserved", "chinese", "point", "green", "square", "kanji"], skins: [{ unified: "1f22f", native: "\u{1F22F}" }], version: 1 }, ideograph_advantage: { id: "ideograph_advantage", name: "Japanese \u201Cbargain\u201D Button", keywords: ["ideograph", "advantage", "bargain", "chinese", "kanji", "obtain", "get", "circle"], skins: [{ unified: "1f250", native: "\u{1F250}" }], version: 1 }, u5272: { id: "u5272", name: "Japanese \u201Cdiscount\u201D Button", keywords: ["u5272", "discount", "cut", "divide", "chinese", "kanji", "pink", "square"], skins: [{ unified: "1f239", native: "\u{1F239}" }], version: 1 }, u7121: { id: "u7121", name: "Japanese \u201Cfree of Charge\u201D Button", keywords: ["u7121", "free", "charge", "nothing", "chinese", "kanji", "orange", "square"], skins: [{ unified: "1f21a", native: "\u{1F21A}" }], version: 1 }, u7981: { id: "u7981", name: "Japanese \u201Cprohibited\u201D Button", keywords: ["u7981", "prohibited", "kanji", "chinese", "forbidden", "limit", "restricted", "red", "square"], skins: [{ unified: "1f232", native: "\u{1F232}" }], version: 1 }, accept: { id: "accept", name: "Circled Ideograph Accept", keywords: ["japanese", "acceptable", "button", "ok", "good", "chinese", "kanji", "agree", "yes", "orange", "circle"], skins: [{ unified: "1f251", native: "\u{1F251}" }], version: 1 }, u7533: { id: "u7533", name: "Japanese \u201Capplication\u201D Button", keywords: ["u7533", "application", "chinese", "kanji", "orange", "square"], skins: [{ unified: "1f238", native: "\u{1F238}" }], version: 1 }, u5408: { id: "u5408", name: "Japanese \u201Cpassing Grade\u201D Button", keywords: ["u5408", "passing", "grade", "chinese", "join", "kanji", "red", "square"], skins: [{ unified: "1f234", native: "\u{1F234}" }], version: 1 }, u7a7a: { id: "u7a7a", name: "Japanese \u201Cvacancy\u201D Button", keywords: ["u7a7a", "vacancy", "kanji", "chinese", "empty", "sky", "blue", "square"], skins: [{ unified: "1f233", native: "\u{1F233}" }], version: 1 }, congratulations: { id: "congratulations", name: "Circled Ideograph Congratulation", keywords: ["congratulations", "japanese", "button", "chinese", "kanji", "red", "circle"], skins: [{ unified: "3297-fe0f", native: "\u3297\uFE0F" }], version: 1 }, secret: { id: "secret", name: "Circled Ideograph Secret", keywords: ["japanese", "button", "privacy", "chinese", "sshh", "kanji", "red", "circle"], skins: [{ unified: "3299-fe0f", native: "\u3299\uFE0F" }], version: 1 }, u55b6: { id: "u55b6", name: "Squared Cjk Unified Ideograph-55b6", keywords: ["u55b6", "japanese", "open", "for", "business", "button", "opening", "hours", "orange", "square"], skins: [{ unified: "1f23a", native: "\u{1F23A}" }], version: 1 }, u6e80: { id: "u6e80", name: "Japanese \u201Cno Vacancy\u201D Button", keywords: ["u6e80", "no", "vacancy", "full", "chinese", "red", "square", "kanji"], skins: [{ unified: "1f235", native: "\u{1F235}" }], version: 1 }, red_circle: { id: "red_circle", name: "Red Circle", keywords: ["shape", "error", "danger"], skins: [{ unified: "1f534", native: "\u{1F534}" }], version: 1 }, large_orange_circle: { id: "large_orange_circle", name: "Orange Circle", keywords: ["large", "round"], skins: [{ unified: "1f7e0", native: "\u{1F7E0}" }], version: 12 }, large_yellow_circle: { id: "large_yellow_circle", name: "Yellow Cir
51763cle", keywords: ["large", "round"], skins: [{ unified: "1f7e1", native: "\u{1F7E1}" }], version: 12 }, large_green_circle: { id: "large_green_circle", name: "Green Circle", keywords: ["large", "round"], skins: [{ unified: "1f7e2", native: "\u{1F7E2}" }], version: 12 }, large_blue_circle: { id: "large_blue_circle", name: "Blue Circle", keywords: ["large", "shape", "icon", "button"], skins: [{ unified: "1f535", native: "\u{1F535}" }], version: 1 }, large_purple_circle: { id: "large_purple_circle", name: "Purple Circle", keywords: ["large", "round"], skins: [{ unified: "1f7e3", native: "\u{1F7E3}" }], version: 12 }, large_brown_circle: { id: "large_brown_circle", name: "Brown Circle", keywords: ["large", "round"], skins: [{ unified: "1f7e4", native: "\u{1F7E4}" }], version: 12 }, black_circle: { id: "black_circle", name: "Black Circle", keywords: ["shape", "button", "round"], skins: [{ unified: "26ab", native: "\u26AB" }], version: 1 }, white_circle: { id: "white_circle", name: "White Circle", keywords: ["shape", "round"], skins: [{ unified: "26aa", native: "\u26AA" }], version: 1 }, large_red_square: { id: "large_red_square", name: "Red Square", keywords: ["large"], skins: [{ unified: "1f7e5", native: "\u{1F7E5}" }], version: 12 }, large_orange_square: { id: "large_orange_square", name: "Orange Square", keywords: ["large"], skins: [{ unified: "1f7e7", native: "\u{1F7E7}" }], version: 12 }, large_yellow_square: { id: "large_yellow_square", name: "Yellow Square", keywords: ["large"], skins: [{ unified: "1f7e8", native: "\u{1F7E8}" }], version: 12 }, large_green_square: { id: "large_green_square", name: "Green Square", keywords: ["large"], skins: [{ unified: "1f7e9", native: "\u{1F7E9}" }], version: 12 }, large_blue_square: { id: "large_blue_square", name: "Blue Square", keywords: ["large"], skins: [{ unified: "1f7e6", native: "\u{1F7E6}" }], version: 12 }, large_purple_square: { id: "large_purple_square", name: "Purple Square", keywords: ["large"], skins: [{ unified: "1f7ea", native: "\u{1F7EA}" }], version: 12 }, large_brown_square: { id: "large_brown_square", name: "Brown Square", keywords: ["large"], skins: [{ unified: "1f7eb", native: "\u{1F7EB}" }], version: 12 }, black_large_square: { id: "black_large_square", name: "Black Large Square", keywords: ["shape", "icon", "button"], skins: [{ unified: "2b1b", native: "\u2B1B" }], version: 1 }, white_large_square: { id: "white_large_square", name: "White Large Square", keywords: ["shape", "icon", "stone", "button"], skins: [{ unified: "2b1c", native: "\u2B1C" }], version: 1 }, black_medium_square: { id: "black_medium_square", name: "Black Medium Square", keywords: ["shape", "button", "icon"], skins: [{ unified: "25fc-fe0f", native: "\u25FC\uFE0F" }], version: 1 }, white_medium_square: { id: "white_medium_square", name: "White Medium Square", keywords: ["shape", "stone", "icon"], skins: [{ unified: "25fb-fe0f", native: "\u25FB\uFE0F" }], version: 1 }, black_medium_small_square: { id: "black_medium_small_square", name: "Black Medium Small Square", keywords: ["icon", "shape", "button"], skins: [{ unified: "25fe", native: "\u25FE" }], version: 1 }, white_medium_small_square: { id: "white_medium_small_square", name: "White Medium Small Square", keywords: ["shape", "stone", "icon", "button"], skins: [{ unified: "25fd", native: "\u25FD" }], version: 1 }, black_small_square: { id: "black_small_square", name: "Black Small Square", keywords: ["shape", "icon"], skins: [{ unified: "25aa-fe0f", native: "\u25AA\uFE0F" }], version: 1 }, white_small_square: { id: "white_small_square", name: "White Small Square", keywords: ["shape", "icon"], skins: [{ unified: "25ab-fe0f", native: "\u25AB\uFE0F" }], version: 1 }, large_orange_diamond: { id: "large_orange_diamond", name: "Large Orange Diamond", keywords: ["shape", "jewel", "gem"], skins: [{ unified: "1f536", native: "\u{1F536}" }], version: 1 }, large_blue_diamond: { id: "large_blue_diamond", name: "Large Blue Diamond", keywords: ["shape", "jewel", "gem"], skins: [{ unified: "1f537", native: "\u{1F537}" }], version: 1 }, small_orange_diamond: { id: "small_orange_diamond", name: "Small Orange Diamond", keywords: ["shape", "jewel", "gem"], skins: [{ unified: "1f538", native: "\u{1F538}" }], version: 1 }, small_blue_diamond: { id: "small_blue_diamond", name: "Small Blue Diamond", keywords: ["shape", "jewel", "gem"], skins: [{ unified: "1f539", native: "\u{1F539}" }
51763], version: 1 }, small_red_triangle: { id: "small_red_triangle", name: "Red Triangle Pointed Up", keywords: ["small", "shape", "direction", "top"], skins: [{ unified: "1f53a", native: "\u{1F53A}" }], version: 1 }, small_red_triangle_down: { id: "small_red_triangle_down", name: "Red Triangle Pointed Down", keywords: ["small", "shape", "direction", "bottom"], skins: [{ unified: "1f53b", native: "\u{1F53B}" }], version: 1 }, diamond_shape_with_a_dot_inside: { id: "diamond_shape_with_a_dot_inside", name: "Diamond with a Dot", keywords: ["shape", "inside", "jewel", "blue", "gem", "crystal", "fancy"], skins: [{ unified: "1f4a0", native: "\u{1F4A0}" }], version: 1 }, radio_button: { id: "radio_button", name: "Radio Button", keywords: ["input", "old", "music", "circle"], skins: [{ unified: "1f518", native: "\u{1F518}" }], version: 1 }, white_square_button: { id: "white_square_button", name: "White Square Button", keywords: ["shape", "input"], skins: [{ unified: "1f533", native: "\u{1F533}" }], version: 1 }, black_square_button: { id: "black_square_button", name: "Black Square Button", keywords: ["shape", "input", "frame"], skins: [{ unified: "1f532", native: "\u{1F532}" }], version: 1 }, checkered_flag: { id: "checkered_flag", name: "Chequered Flag", keywords: ["checkered", "contest", "finishline", "race", "gokart"], skins: [{ unified: "1f3c1", native: "\u{1F3C1}" }], version: 1 }, triangular_flag_on_post: { id: "triangular_flag_on_post", name: "Triangular Flag", keywords: ["on", "post", "mark", "milestone", "place"], skins: [{ unified: "1f6a9", native: "\u{1F6A9}" }], version: 1 }, crossed_flags: { id: "crossed_flags", name: "Crossed Flags", keywords: ["japanese", "nation", "country", "border"], skins: [{ unified: "1f38c", native: "\u{1F38C}" }], version: 1 }, waving_black_flag: { id: "waving_black_flag", name: "Black Flag", keywords: ["waving", "pirate"], skins: [{ unified: "1f3f4", native: "\u{1F3F4}" }], version: 1 }, waving_white_flag: { id: "waving_white_flag", name: "White Flag", keywords: ["waving", "losing", "loser", "lost", "surrender", "give", "up", "fail"], skins: [{ unified: "1f3f3-fe0f", native: "\u{1F3F3}\uFE0F" }], version: 1 }, "rainbow-flag": { id: "rainbow-flag", name: "Rainbow Flag", keywords: ["pride", "gay", "lgbt", "queer", "homosexual", "lesbian", "bisexual"], skins: [{ unified: "1f3f3-fe0f-200d-1f308", native: "\u{1F3F3}\uFE0F\u200D\u{1F308}" }], version: 4 }, transgender_flag: { id: "transgender_flag", name: "Transgender Flag", keywords: ["pride", "lgbtq"], skins: [{ unified: "1f3f3-fe0f-200d-26a7-fe0f", native: "\u{1F3F3}\uFE0F\u200D\u26A7\uFE0F" }], version: 13 }, pirate_flag: { id: "pirate_flag", name: "Pirate Flag", keywords: ["skull", "crossbones", "banner"], skins: [{ unified: "1f3f4-200d-2620-fe0f", native: "\u{1F3F4}\u200D\u2620\uFE0F" }], version: 11 }, "flag-ac": { id: "flag-ac", name: "Ascension Island Flag", keywords: ["ac"], skins: [{ unified: "1f1e6-1f1e8", native: "\u{1F1E6}\u{1F1E8}" }], version: 2 }, "flag-ad": { id: "flag-ad", name: "Andorra Flag", keywords: ["ad", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1e9", native: "\u{1F1E6}\u{1F1E9}" }], version: 2 }, "flag-ae": { id: "flag-ae", name: "United Arab Emirates Flag", keywords: ["ae", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1ea", native: "\u{1F1E6}\u{1F1EA}" }], version: 2 }, "flag-af": { id: "flag-af", name: "Afghanistan Flag", keywords: ["af", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1eb", native: "\u{1F1E6}\u{1F1EB}" }], version: 2 }, "flag-ag": { id: "flag-ag", name: "Antigua & Barbuda Flag", keywords: ["ag", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1ec", native: "\u{1F1E6}\u{1F1EC}" }], version: 2 }, "flag-ai": { id: "flag-ai", name: "Anguilla Flag", keywords: ["ai", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1ee", native: "\u{1F1E6}\u{1F1EE}" }], version: 2 }, "flag-al": { id: "flag-al", name: "Albania Flag", keywords: ["al", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1f1", native: "\u{1F1E6}\u{1F1F1}" }], version: 2 }, "flag-am": { id: "flag-am", name: "Armenia Flag", keywords: ["am", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1f2", native: "\u{1F1E6}\u{1F1F2}" }], version: 2 }, "flag-ao": { id: "flag-ao", name: "Angola Flag", keywords: ["ao", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1f4", native: "\u{1F1E6}\u{1F1F4}" }
51763], version: 2 }, "flag-aq": { id: "flag-aq", name: "Antarctica Flag", keywords: ["aq", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1f6", native: "\u{1F1E6}\u{1F1F6}" }], version: 2 }, "flag-ar": { id: "flag-ar", name: "Argentina Flag", keywords: ["ar", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1f7", native: "\u{1F1E6}\u{1F1F7}" }], version: 2 }, "flag-as": { id: "flag-as", name: "American Samoa Flag", keywords: ["as", "ws", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1f8", native: "\u{1F1E6}\u{1F1F8}" }], version: 2 }, "flag-at": { id: "flag-at", name: "Austria Flag", keywords: ["at", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1f9", native: "\u{1F1E6}\u{1F1F9}" }], version: 2 }, "flag-au": { id: "flag-au", name: "Australia Flag", keywords: ["au", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1fa", native: "\u{1F1E6}\u{1F1FA}" }], version: 2 }, "flag-aw": { id: "flag-aw", name: "Aruba Flag", keywords: ["aw", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1fc", native: "\u{1F1E6}\u{1F1FC}" }], version: 2 }, "flag-ax": { id: "flag-ax", name: "\xC5land Islands Flag", keywords: ["ax", "aland", "Aland", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1fd", native: "\u{1F1E6}\u{1F1FD}" }], version: 2 }, "flag-az": { id: "flag-az", name: "Azerbaijan Flag", keywords: ["az", "nation", "country", "banner"], skins: [{ unified: "1f1e6-1f1ff", native: "\u{1F1E6}\u{1F1FF}" }], version: 2 }, "flag-ba": { id: "flag-ba", name: "Bosnia & Herzegovina Flag", keywords: ["ba", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1e6", native: "\u{1F1E7}\u{1F1E6}" }], version: 2 }, "flag-bb": { id: "flag-bb", name: "Barbados Flag", keywords: ["bb", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1e7", native: "\u{1F1E7}\u{1F1E7}" }], version: 2 }, "flag-bd": { id: "flag-bd", name: "Bangladesh Flag", keywords: ["bd", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1e9", native: "\u{1F1E7}\u{1F1E9}" }], version: 2 }, "flag-be": { id: "flag-be", name: "Belgium Flag", keywords: ["be", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1ea", native: "\u{1F1E7}\u{1F1EA}" }], version: 2 }, "flag-bf": { id: "flag-bf", name: "Burkina Faso Flag", keywords: ["bf", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1eb", native: "\u{1F1E7}\u{1F1EB}" }], version: 2 }, "flag-bg": { id: "flag-bg", name: "Bulgaria Flag", keywords: ["bg", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1ec", native: "\u{1F1E7}\u{1F1EC}" }], version: 2 }, "flag-bh": { id: "flag-bh", name: "Bahrain Flag", keywords: ["bh", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1ed", native: "\u{1F1E7}\u{1F1ED}" }], version: 2 }, "flag-bi": { id: "flag-bi", name: "Burundi Flag", keywords: ["bi", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1ee", native: "\u{1F1E7}\u{1F1EE}" }], version: 2 }, "flag-bj": { id: "flag-bj", name: "Benin Flag", keywords: ["bj", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1ef", native: "\u{1F1E7}\u{1F1EF}" }], version: 2 }, "flag-bl": { id: "flag-bl", name: "St. Barth\xE9lemy Flag", keywords: ["bl", "st", "barthelemy", "saint", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1f1", native: "\u{1F1E7}\u{1F1F1}" }], version: 2 }, "flag-bm": { id: "flag-bm", name: "Bermuda Flag", keywords: ["bm", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1f2", native: "\u{1F1E7}\u{1F1F2}" }], version: 2 }, "flag-bn": { id: "flag-bn", name: "Brunei Flag", keywords: ["bn", "darussalam", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1f3", native: "\u{1F1E7}\u{1F1F3}" }], version: 2 }, "flag-bo": { id: "flag-bo", name: "Bolivia Flag", keywords: ["bo", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1f4", native: "\u{1F1E7}\u{1F1F4}" }
51763], version: 2 }, "flag-bq": { id: "flag-bq", name: "Caribbean Netherlands Flag", keywords: ["bq", "bonaire", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1f6", native: "\u{1F1E7}\u{1F1F6}" }], version: 2 }, "flag-br": { id: "flag-br", name: "Brazil Flag", keywords: ["br", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1f7", native: "\u{1F1E7}\u{1F1F7}" }], version: 2 }, "flag-bs": { id: "flag-bs", name: "Bahamas Flag", keywords: ["bs", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1f8", native: "\u{1F1E7}\u{1F1F8}" }], version: 2 }, "flag-bt": { id: "flag-bt", name: "Bhutan Flag", keywords: ["bt", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1f9", native: "\u{1F1E7}\u{1F1F9}" }], version: 2 }, "flag-bv": { id: "flag-bv", name: "Bouvet Island Flag", keywords: ["bv", "norway"], skins: [{ unified: "1f1e7-1f1fb", native: "\u{1F1E7}\u{1F1FB}" }], version: 2 }, "flag-bw": { id: "flag-bw", name: "Botswana Flag", keywords: ["bw", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1fc", native: "\u{1F1E7}\u{1F1FC}" }], version: 2 }, "flag-by": { id: "flag-by", name: "Belarus Flag", keywords: ["by", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1fe", native: "\u{1F1E7}\u{1F1FE}" }], version: 2 }, "flag-bz": { id: "flag-bz", name: "Belize Flag", keywords: ["bz", "nation", "country", "banner"], skins: [{ unified: "1f1e7-1f1ff", native: "\u{1F1E7}\u{1F1FF}" }], version: 2 }, "flag-ca": { id: "flag-ca", name: "Canada Flag", keywords: ["ca", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1e6", native: "\u{1F1E8}\u{1F1E6}" }], version: 2 }, "flag-cc": { id: "flag-cc", name: "Cocos (keeling) Islands Flag", keywords: ["cc", "keeling", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1e8", native: "\u{1F1E8}\u{1F1E8}" }], version: 2 }, "flag-cd": { id: "flag-cd", name: "Congo - Kinshasa Flag", keywords: ["cd", "democratic", "republic", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1e9", native: "\u{1F1E8}\u{1F1E9}" }], version: 2 }, "flag-cf": { id: "flag-cf", name: "Central African Republic Flag", keywords: ["cf", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1eb", native: "\u{1F1E8}\u{1F1EB}" }], version: 2 }, "flag-cg": { id: "flag-cg", name: "Congo - Brazzaville Flag", keywords: ["cg", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1ec", native: "\u{1F1E8}\u{1F1EC}" }], version: 2 }, "flag-ch": { id: "flag-ch", name: "Switzerland Flag", keywords: ["ch", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1ed", native: "\u{1F1E8}\u{1F1ED}" }], version: 2 }, "flag-ci": { id: "flag-ci", name: "C\xF4te D\u2019ivoire Flag", keywords: ["ci", "cote", "d", "ivoire", "ivory", "coast", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1ee", native: "\u{1F1E8}\u{1F1EE}" }], version: 2 }, "flag-ck": { id: "flag-ck", name: "Cook Islands Flag", keywords: ["ck", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1f0", native: "\u{1F1E8}\u{1F1F0}" }], version: 2 }, "flag-cl": { id: "flag-cl", name: "Chile Flag", keywords: ["cl", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1f1", native: "\u{1F1E8}\u{1F1F1}" }], version: 2 }, "flag-cm": { id: "flag-cm", name: "Cameroon Flag", keywords: ["cm", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1f2", native: "\u{1F1E8}\u{1F1F2}" }], version: 2 }, cn: { id: "cn", name: "China Flag", keywords: ["cn", "chinese", "prc", "country", "nation", "banner"], skins: [{ unified: "1f1e8-1f1f3", native: "\u{1F1E8}\u{1F1F3}" }], version: 1 }, "flag-co": { id: "flag-co", name: "Colombia Flag", keywords: ["co", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1f4", native: "\u{1F1E8}\u{1F1F4}" }
51763], version: 2 }, "flag-cp": { id: "flag-cp", name: "Clipperton Island Flag", keywords: ["cp"], skins: [{ unified: "1f1e8-1f1f5", native: "\u{1F1E8}\u{1F1F5}" }], version: 2 }, "flag-sark": { id: "flag-sark", name: "Sark Flag", keywords: [], skins: [{ unified: "1f1e8-1f1f6", native: "\u{1F1E8}\u{1F1F6}" }], version: 16 }, "flag-cr": { id: "flag-cr", name: "Costa Rica Flag", keywords: ["cr", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1f7", native: "\u{1F1E8}\u{1F1F7}" }], version: 2 }, "flag-cu": { id: "flag-cu", name: "Cuba Flag", keywords: ["cu", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1fa", native: "\u{1F1E8}\u{1F1FA}" }], version: 2 }, "flag-cv": { id: "flag-cv", name: "Cape Verde Flag", keywords: ["cv", "cabo", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1fb", native: "\u{1F1E8}\u{1F1FB}" }], version: 2 }, "flag-cw": { id: "flag-cw", name: "Cura\xE7ao Flag", keywords: ["cw", "curacao", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1fc", native: "\u{1F1E8}\u{1F1FC}" }], version: 2 }, "flag-cx": { id: "flag-cx", name: "Christmas Island Flag", keywords: ["cx", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1fd", native: "\u{1F1E8}\u{1F1FD}" }], version: 2 }, "flag-cy": { id: "flag-cy", name: "Cyprus Flag", keywords: ["cy", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1fe", native: "\u{1F1E8}\u{1F1FE}" }], version: 2 }, "flag-cz": { id: "flag-cz", name: "Czechia Flag", keywords: ["cz", "nation", "country", "banner"], skins: [{ unified: "1f1e8-1f1ff", native: "\u{1F1E8}\u{1F1FF}" }], version: 2 }, de: { id: "de", name: "Germany Flag", keywords: ["de", "german", "nation", "country", "banner"], skins: [{ unified: "1f1e9-1f1ea", native: "\u{1F1E9}\u{1F1EA}" }], version: 1 }, "flag-dg": { id: "flag-dg", name: "Diego Garcia Flag", keywords: ["dg"], skins: [{ unified: "1f1e9-1f1ec", native: "\u{1F1E9}\u{1F1EC}" }], version: 2 }, "flag-dj": { id: "flag-dj", name: "Djibouti Flag", keywords: ["dj", "nation", "country", "banner"], skins: [{ unified: "1f1e9-1f1ef", native: "\u{1F1E9}\u{1F1EF}" }], version: 2 }, "flag-dk": { id: "flag-dk", name: "Denmark Flag", keywords: ["dk", "nation", "country", "banner"], skins: [{ unified: "1f1e9-1f1f0", native: "\u{1F1E9}\u{1F1F0}" }], version: 2 }, "flag-dm": { id: "flag-dm", name: "Dominica Flag", keywords: ["dm", "nation", "country", "banner"], skins: [{ unified: "1f1e9-1f1f2", native: "\u{1F1E9}\u{1F1F2}" }], version: 2 }, "flag-do": { id: "flag-do", name: "Dominican Republic Flag", keywords: ["do", "nation", "country", "banner"], skins: [{ unified: "1f1e9-1f1f4", native: "\u{1F1E9}\u{1F1F4}" }
51763], version: 2 }, "flag-dz": { id: "flag-dz", name: "Algeria Flag", keywords: ["dz", "nation", "country", "banner"], skins: [{ unified: "1f1e9-1f1ff", native: "\u{1F1E9}\u{1F1FF}" }], version: 2 }, "flag-ea": { id: "flag-ea", name: "Ceuta & Melilla Flag", keywords: ["ea"], skins: [{ unified: "1f1ea-1f1e6", native: "\u{1F1EA}\u{1F1E6}" }], version: 2 }, "flag-ec": { id: "flag-ec", name: "Ecuador Flag", keywords: ["ec", "nation", "country", "banner"], skins: [{ unified: "1f1ea-1f1e8", native: "\u{1F1EA}\u{1F1E8}" }], version: 2 }, "flag-ee": { id: "flag-ee", name: "Estonia Flag", keywords: ["ee", "nation", "country", "banner"], skins: [{ unified: "1f1ea-1f1ea", native: "\u{1F1EA}\u{1F1EA}" }], version: 2 }, "flag-eg": { id: "flag-eg", name: "Egypt Flag", keywords: ["eg", "nation", "country", "banner"], skins: [{ unified: "1f1ea-1f1ec", native: "\u{1F1EA}\u{1F1EC}" }], version: 2 }, "flag-eh": { id: "flag-eh", name: "Western Sahara Flag", keywords: ["eh", "nation", "country", "banner"], skins: [{ unified: "1f1ea-1f1ed", native: "\u{1F1EA}\u{1F1ED}" }], version: 2 }, "flag-er": { id: "flag-er", name: "Eritrea Flag", keywords: ["er", "nation", "country", "banner"], skins: [{ unified: "1f1ea-1f1f7", native: "\u{1F1EA}\u{1F1F7}" }], version: 2 }, es: { id: "es", name: "Spain Flag", keywords: ["es", "nation", "country", "banner"], skins: [{ unified: "1f1ea-1f1f8", native: "\u{1F1EA}\u{1F1F8}" }], version: 1 }, "flag-et": { id: "flag-et", name: "Ethiopia Flag", keywords: ["et", "nation", "country", "banner"], skins: [{ unified: "1f1ea-1f1f9", native: "\u{1F1EA}\u{1F1F9}" }], version: 2 }, "flag-eu": { id: "flag-eu", name: "European Union Flag", keywords: ["eu", "banner"], skins: [{ unified: "1f1ea-1f1fa", native: "\u{1F1EA}\u{1F1FA}" }], version: 2 }, "flag-fi": { id: "flag-fi", name: "Finland Flag", keywords: ["fi", "nation", "country", "banner"], skins: [{ unified: "1f1eb-1f1ee", native: "\u{1F1EB}\u{1F1EE}" }], version: 2 }, "flag-fj": { id: "flag-fj", name: "Fiji Flag", keywords: ["fj", "nation", "country", "banner"], skins: [{ unified: "1f1eb-1f1ef", native: "\u{1F1EB}\u{1F1EF}" }], version: 2 }, "flag-fk": { id: "flag-fk", name: "Falkland Islands Flag", keywords: ["fk", "malvinas", "nation", "country", "banner"], skins: [{ unified: "1f1eb-1f1f0", native: "\u{1F1EB}\u{1F1F0}" }], version: 2 }, "flag-fm": { id: "flag-fm", name: "Micronesia Flag", keywords: ["fm", "federated", "states", "nation", "country", "banner"], skins: [{ unified: "1f1eb-1f1f2", native: "\u{1F1EB}\u{1F1F2}" }], version: 2 }, "flag-fo": { id: "flag-fo", name: "Faroe Islands Flag", keywords: ["fo", "nation", "country", "banner"], skins: [{ unified: "1f1eb-1f1f4", native: "\u{1F1EB}\u{1F1F4}" }
51763], version: 2 }, fr: { id: "fr", name: "France Flag", keywords: ["fr", "banner", "nation", "french", "country"], skins: [{ unified: "1f1eb-1f1f7", native: "\u{1F1EB}\u{1F1F7}" }], version: 1 }, "flag-ga": { id: "flag-ga", name: "Gabon Flag", keywords: ["ga", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1e6", native: "\u{1F1EC}\u{1F1E6}" }], version: 2 }, gb: { id: "gb", name: "United Kingdom Flag", keywords: ["gb", "uk", "great", "britain", "northern", "ireland", "nation", "country", "banner", "british", "UK", "english", "england", "union", "jack"], skins: [{ unified: "1f1ec-1f1e7", native: "\u{1F1EC}\u{1F1E7}" }], version: 1 }, "flag-gd": { id: "flag-gd", name: "Grenada Flag", keywords: ["gd", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1e9", native: "\u{1F1EC}\u{1F1E9}" }], version: 2 }, "flag-ge": { id: "flag-ge", name: "Georgia Flag", keywords: ["ge", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1ea", native: "\u{1F1EC}\u{1F1EA}" }], version: 2 }, "flag-gf": { id: "flag-gf", name: "French Guiana Flag", keywords: ["gf", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1eb", native: "\u{1F1EC}\u{1F1EB}" }], version: 2 }, "flag-gg": { id: "flag-gg", name: "Guernsey Flag", keywords: ["gg", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1ec", native: "\u{1F1EC}\u{1F1EC}" }], version: 2 }, "flag-gh": { id: "flag-gh", name: "Ghana Flag", keywords: ["gh", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1ed", native: "\u{1F1EC}\u{1F1ED}" }], version: 2 }, "flag-gi": { id: "flag-gi", name: "Gibraltar Flag", keywords: ["gi", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1ee", native: "\u{1F1EC}\u{1F1EE}" }], version: 2 }, "flag-gl": { id: "flag-gl", name: "Greenland Flag", keywords: ["gl", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1f1", native: "\u{1F1EC}\u{1F1F1}" }], version: 2 }, "flag-gm": { id: "flag-gm", name: "Gambia Flag", keywords: ["gm", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1f2", native: "\u{1F1EC}\u{1F1F2}" }], version: 2 }, "flag-gn": { id: "flag-gn", name: "Guinea Flag", keywords: ["gn", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1f3", native: "\u{1F1EC}\u{1F1F3}" }], version: 2 }, "flag-gp": { id: "flag-gp", name: "Guadeloupe Flag", keywords: ["gp", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1f5", native: "\u{1F1EC}\u{1F1F5}" }], version: 2 }, "flag-gq": { id: "flag-gq", name: "Equatorial Guinea Flag", keywords: ["gq", "gn", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1f6", native: "\u{1F1EC}\u{1F1F6}" }], version: 2 }, "flag-gr": { id: "flag-gr", name: "Greece Flag", keywords: ["gr", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1f7", native: "\u{1F1EC}\u{1F1F7}" }], version: 2 }, "flag-gs": { id: "flag-gs", name: "South Georgia & South Sandwich Islands Flag", keywords: ["gs", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1f8", native: "\u{1F1EC}\u{1F1F8}" }], version: 2 }, "flag-gt": { id: "flag-gt", name: "Guatemala Flag", keywords: ["gt", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1f9", native: "\u{1F1EC}\u{1F1F9}" }], version: 2 }, "flag-gu": { id: "flag-gu", name: "Guam Flag", keywords: ["gu", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1fa", native: "\u{1F1EC}\u{1F1FA}" }], version: 2 }, "flag-gw": { id: "flag-gw", name: "Guinea-Bissau Flag", keywords: ["gw", "guinea", "bissau", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1fc", native: "\u{1F1EC}\u{1F1FC}" }], version: 2 }, "flag-gy": { id: "flag-gy", name: "Guyana Flag", keywords: ["gy", "nation", "country", "banner"], skins: [{ unified: "1f1ec-1f1fe", native: "\u{1F1EC}\u{1F1FE}" }], version: 2 }, "flag-hk": { id: "flag-hk", name: "Hong Kong Sar China Flag", keywords: ["hk", "nation", "country", "banner"], skins: [{ unified: "1f1ed-1f1f0", native: "\u{1F1ED}\u{1F1F0}" }], version: 2 }, "flag-hm": { id: "flag-hm", name: "Heard & Mcdonald Islands Flag", keywords: ["hm"], skins: [{ unified: "1f1ed-1f1f2", native: "\u{1F1ED}\u{1F1F2}" }], version: 2 }, "flag-hn": { id: "flag-hn", name: "Honduras Flag", keywords: ["hn", "nation", "country", "banner"], skins: [{ unified: "1f1ed-1f1f3", native: "\u{1F1ED}\u{1F1F3}" }], version: 2 }, "flag-hr": { id: "flag-hr", name: "Croatia Flag", keywords: ["hr", "nation", "country", "banner"], skins: [{ unified: "1f1ed-1f1f7", native: "\u{1F1ED}\u{1F1F7}" }], version: 2 }, "flag-ht": { id: "flag-ht", name: "Haiti Flag", keywords: ["ht", "n
51763ation", "country", "banner"], skins: [{ unified: "1f1ed-1f1f9", native: "\u{1F1ED}\u{1F1F9}" }], version: 2 }, "flag-hu": { id: "flag-hu", name: "Hungary Flag", keywords: ["hu", "nation", "country", "banner"], skins: [{ unified: "1f1ed-1f1fa", native: "\u{1F1ED}\u{1F1FA}" }], version: 2 }, "flag-ic": { id: "flag-ic", name: "Canary Islands Flag", keywords: ["ic", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1e8", native: "\u{1F1EE}\u{1F1E8}" }], version: 2 }, "flag-id": { id: "flag-id", name: "Indonesia Flag", keywords: ["id", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1e9", native: "\u{1F1EE}\u{1F1E9}" }], version: 2 }, "flag-ie": { id: "flag-ie", name: "Ireland Flag", keywords: ["ie", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1ea", native: "\u{1F1EE}\u{1F1EA}" }], version: 2 }, "flag-il": { id: "flag-il", name: "Israel Flag", keywords: ["il", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1f1", native: "\u{1F1EE}\u{1F1F1}" }], version: 2 }, "flag-im": { id: "flag-im", name: "Isle of Man Flag", keywords: ["im", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1f2", native: "\u{1F1EE}\u{1F1F2}" }], version: 2 }, "flag-in": { id: "flag-in", name: "India Flag", keywords: ["in", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1f3", native: "\u{1F1EE}\u{1F1F3}" }], version: 2 }, "flag-io": { id: "flag-io", name: "British Indian Ocean Territory Flag", keywords: ["io", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1f4", native: "\u{1F1EE}\u{1F1F4}" }
51763], version: 2 }, "flag-iq": { id: "flag-iq", name: "Iraq Flag", keywords: ["iq", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1f6", native: "\u{1F1EE}\u{1F1F6}" }], version: 2 }, "flag-ir": { id: "flag-ir", name: "Iran Flag", keywords: ["ir", "islamic", "republic", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1f7", native: "\u{1F1EE}\u{1F1F7}" }], version: 2 }, "flag-is": { id: "flag-is", name: "Iceland Flag", keywords: ["is", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1f8", native: "\u{1F1EE}\u{1F1F8}" }], version: 2 }, it: { id: "it", name: "Italy Flag", keywords: ["it", "nation", "country", "banner"], skins: [{ unified: "1f1ee-1f1f9", native: "\u{1F1EE}\u{1F1F9}" }], version: 1 }, "flag-je": { id: "flag-je", name: "Jersey Flag", keywords: ["je", "nation", "country", "banner"], skins: [{ unified: "1f1ef-1f1ea", native: "\u{1F1EF}\u{1F1EA}" }], version: 2 }, "flag-jm": { id: "flag-jm", name: "Jamaica Flag", keywords: ["jm", "nation", "country", "banner"], skins: [{ unified: "1f1ef-1f1f2", native: "\u{1F1EF}\u{1F1F2}" }], version: 2 }, "flag-jo": { id: "flag-jo", name: "Jordan Flag", keywords: ["jo", "nation", "country", "banner"], skins: [{ unified: "1f1ef-1f1f4", native: "\u{1F1EF}\u{1F1F4}" }
51763], version: 2 }, jp: { id: "jp", name: "Japan Flag", keywords: ["jp", "japanese", "nation", "country", "banner", "ja"], skins: [{ unified: "1f1ef-1f1f5", native: "\u{1F1EF}\u{1F1F5}" }], version: 1 }, "flag-ke": { id: "flag-ke", name: "Kenya Flag", keywords: ["ke", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1ea", native: "\u{1F1F0}\u{1F1EA}" }], version: 2 }, "flag-kg": { id: "flag-kg", name: "Kyrgyzstan Flag", keywords: ["kg", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1ec", native: "\u{1F1F0}\u{1F1EC}" }], version: 2 }, "flag-kh": { id: "flag-kh", name: "Cambodia Flag", keywords: ["kh", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1ed", native: "\u{1F1F0}\u{1F1ED}" }], version: 2 }, "flag-ki": { id: "flag-ki", name: "Kiribati Flag", keywords: ["ki", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1ee", native: "\u{1F1F0}\u{1F1EE}" }], version: 2 }, "flag-km": { id: "flag-km", name: "Comoros Flag", keywords: ["km", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1f2", native: "\u{1F1F0}\u{1F1F2}" }], version: 2 }, "flag-kn": { id: "flag-kn", name: "St. Kitts & Nevis Flag", keywords: ["kn", "st", "saint", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1f3", native: "\u{1F1F0}\u{1F1F3}" }], version: 2 }, "flag-kp": { id: "flag-kp", name: "North Korea Flag", keywords: ["kp", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1f5", native: "\u{1F1F0}\u{1F1F5}" }], version: 2 }, kr: { id: "kr", name: "South Korea Flag", keywords: ["kr", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1f7", native: "\u{1F1F0}\u{1F1F7}" }], version: 1 }, "flag-kw": { id: "flag-kw", name: "Kuwait Flag", keywords: ["kw", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1fc", native: "\u{1F1F0}\u{1F1FC}" }], version: 2 }, "flag-ky": { id: "flag-ky", name: "Cayman Islands Flag", keywords: ["ky", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1fe", native: "\u{1F1F0}\u{1F1FE}" }], version: 2 }, "flag-kz": { id: "flag-kz", name: "Kazakhstan Flag", keywords: ["kz", "nation", "country", "banner"], skins: [{ unified: "1f1f0-1f1ff", native: "\u{1F1F0}\u{1F1FF}" }], version: 2 }, "flag-la": { id: "flag-la", name: "Laos Flag", keywords: ["la", "lao", "democratic", "republic", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1e6", native: "\u{1F1F1}\u{1F1E6}" }], version: 2 }, "flag-lb": { id: "flag-lb", name: "Lebanon Flag", keywords: ["lb", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1e7", native: "\u{1F1F1}\u{1F1E7}" }], version: 2 }, "flag-lc": { id: "flag-lc", name: "St. Lucia Flag", keywords: ["lc", "st", "saint", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1e8", native: "\u{1F1F1}\u{1F1E8}" }], version: 2 }, "flag-li": { id: "flag-li", name: "Liechtenstein Flag", keywords: ["li", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1ee", native: "\u{1F1F1}\u{1F1EE}" }], version: 2 }, "flag-lk": { id: "flag-lk", name: "Sri Lanka Flag", keywords: ["lk", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1f0", native: "\u{1F1F1}\u{1F1F0}" }], version: 2 }, "flag-lr": { id: "flag-lr", name: "Liberia Flag", keywords: ["lr", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1f7", native: "\u{1F1F1}\u{1F1F7}" }], version: 2 }, "flag-ls": { id: "flag-ls", name: "Lesotho Flag", keywords: ["ls", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1f8", native: "\u{1F1F1}\u{1F1F8}" }], version: 2 }, "flag-lt": { id: "flag-lt", name: "Lithuania Flag", keywords: ["lt", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1f9", native: "\u{1F1F1}\u{1F1F9}" }], version: 2 }, "flag-lu": { id: "flag-lu", name: "Luxembourg Flag", keywords: ["lu", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1fa", native: "\u{1F1F1}\u{1F1FA}" }], version: 2 }, "flag-lv": { id: "flag-lv", name: "Latvia Flag", keywords: ["lv", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1fb", native: "\u{1F1F1}\u{1F1FB}" }], version: 2 }, "flag-ly": { id: "flag-ly", name: "Libya Flag", keywords: ["ly", "nation", "country", "banner"], skins: [{ unified: "1f1f1-1f1fe", native: "\u{1F1F1}\u{1F1FE}" }], version: 2 }, "flag-ma": { id: "flag-ma", name: "Morocco Flag", keywords: ["ma", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1e6", native: "\u{1F1F2}\u{1F1E6}" }], version: 2 }, "flag-mc": { id: "flag-mc", name: "Monaco Flag", keywords: ["mc", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1e8", native: "\u{1F1F2}\u{1F1E8}" }], version: 2 }, "flag-md": { id: "flag-md", name: "Moldova Flag", keywords: ["md", "republic", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1e9", native: "\u{1F1F2}\u{1F1E9}" }], version: 2 }, "flag-me": { id: "flag-me", name: "Montenegro Flag", keywords: ["me", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1ea", native: "\u{1F1F2}\u{1F1EA}" }], version: 2 }, "flag-mf": { id: "flag-mf", name: "St. Martin Flag", keywords: ["mf", "st"], skins: [{ unified: "1f1f2-1f1eb", native: "\u{1F1F2}\u{1F1EB}" }], version: 2 }, "flag-mg": { id: "flag-mg", name: "Madagascar Flag", keywords: ["mg", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1ec", native: "\u{1F1F2}\u{1F1EC}" }], version: 2 }, "flag-mh": { id: "flag-mh", name: "Marshall Islands Flag", keywords: ["mh", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1ed", native: "\u{1F1F2}\u{1F1ED}" }], version: 2 }, "flag-mk": { id: "flag-mk", name: "North Macedonia Flag", keywords: ["mk", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1f0", native: "\u{1F1F2}\u{1F1F0}" }], version: 2 }, "flag-ml": { id: "flag-ml", name: "Mali Flag", keywords: ["ml", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1f1", native: "\u{1F1F2}\u{1F1F1}" }], version: 2 }, "flag-mm": { id: "flag-mm", name: "Myanmar (burma) Flag", keywords: ["mm", "n
51763ation", "country", "banner"], skins: [{ unified: "1f1f2-1f1f2", native: "\u{1F1F2}\u{1F1F2}" }], version: 2 }, "flag-mn": { id: "flag-mn", name: "Mongolia Flag", keywords: ["mn", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1f3", native: "\u{1F1F2}\u{1F1F3}" }], version: 2 }, "flag-mo": { id: "flag-mo", name: "Macao Sar China Flag", keywords: ["mo", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1f4", native: "\u{1F1F2}\u{1F1F4}" }], version: 2 }, "flag-mp": { id: "flag-mp", name: "Northern Mariana Islands Flag", keywords: ["mp", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1f5", native: "\u{1F1F2}\u{1F1F5}" }], version: 2 }, "flag-mq": { id: "flag-mq", name: "Martinique Flag", keywords: ["mq", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1f6", native: "\u{1F1F2}\u{1F1F6}" }], version: 2 }, "flag-mr": { id: "flag-mr", name: "Mauritania Flag", keywords: ["mr", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1f7", native: "\u{1F1F2}\u{1F1F7}" }], version: 2 }, "flag-ms": { id: "flag-ms", name: "Montserrat Flag", keywords: ["ms", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1f8", native: "\u{1F1F2}\u{1F1F8}" }], version: 2 }, "flag-mt": { id: "flag-mt", name: "Malta Flag", keywords: ["mt", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1f9", native: "\u{1F1F2}\u{1F1F9}" }], version: 2 }, "flag-mu": { id: "flag-mu", name: "Mauritius Flag", keywords: ["mu", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1fa", native: "\u{1F1F2}\u{1F1FA}" }], version: 2 }, "flag-mv": { id: "flag-mv", name: "Maldives Flag", keywords: ["mv", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1fb", native: "\u{1F1F2}\u{1F1FB}" }], version: 2 }, "flag-mw": { id: "flag-mw", name: "Malawi Flag", keywords: ["mw", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1fc", native: "\u{1F1F2}\u{1F1FC}" }], version: 2 }, "flag-mx": { id: "flag-mx", name: "Mexico Flag", keywords: ["mx", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1fd", native: "\u{1F1F2}\u{1F1FD}" }], version: 2 }, "flag-my": { id: "flag-my", name: "Malaysia Flag", keywords: ["my", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1fe", native: "\u{1F1F2}\u{1F1FE}" }], version: 2 }, "flag-mz": { id: "flag-mz", name: "Mozambique Flag", keywords: ["mz", "nation", "country", "banner"], skins: [{ unified: "1f1f2-1f1ff", native: "\u{1F1F2}\u{1F1FF}" }], version: 2 }, "flag-na": { id: "flag-na", name: "Namibia Flag", keywords: ["na", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1e6", native: "\u{1F1F3}\u{1F1E6}" }], version: 2 }, "flag-nc": { id: "flag-nc", name: "New Caledonia Flag", keywords: ["nc", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1e8", native: "\u{1F1F3}\u{1F1E8}" }], version: 2 }, "flag-ne": { id: "flag-ne", name: "Niger Flag", keywords: ["ne", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1ea", native: "\u{1F1F3}\u{1F1EA}" }], version: 2 }, "flag-nf": { id: "flag-nf", name: "Norfolk Island Flag", keywords: ["nf", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1eb", native: "\u{1F1F3}\u{1F1EB}" }], version: 2 }, "flag-ng": { id: "flag-ng", name: "Nigeria Flag", keywords: ["ng", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1ec", native: "\u{1F1F3}\u{1F1EC}" }], version: 2 }, "flag-ni": { id: "flag-ni", name: "Nicaragua Flag", keywords: ["ni", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1ee", native: "\u{1F1F3}\u{1F1EE}" }], version: 2 }, "flag-nl": { id: "flag-nl", name: "Netherlands Flag", keywords: ["nl", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1f1", native: "\u{1F1F3}\u{1F1F1}" }], version: 2 }, "flag-no": { id: "flag-no", name: "Norway Flag", keywords: ["no", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1f4", native: "\u{1F1F3}\u{1F1F4}" }
51763], version: 2 }, "flag-np": { id: "flag-np", name: "Nepal Flag", keywords: ["np", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1f5", native: "\u{1F1F3}\u{1F1F5}" }], version: 2 }, "flag-nr": { id: "flag-nr", name: "Nauru Flag", keywords: ["nr", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1f7", native: "\u{1F1F3}\u{1F1F7}" }], version: 2 }, "flag-nu": { id: "flag-nu", name: "Niue Flag", keywords: ["nu", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1fa", native: "\u{1F1F3}\u{1F1FA}" }], version: 2 }, "flag-nz": { id: "flag-nz", name: "New Zealand Flag", keywords: ["nz", "nation", "country", "banner"], skins: [{ unified: "1f1f3-1f1ff", native: "\u{1F1F3}\u{1F1FF}" }], version: 2 }, "flag-om": { id: "flag-om", name: "Oman Flag", keywords: ["om", "symbol", "nation", "country", "banner"], skins: [{ unified: "1f1f4-1f1f2", native: "\u{1F1F4}\u{1F1F2}" }], version: 2 }, "flag-pa": { id: "flag-pa", name: "Panama Flag", keywords: ["pa", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1e6", native: "\u{1F1F5}\u{1F1E6}" }], version: 2 }, "flag-pe": { id: "flag-pe", name: "Peru Flag", keywords: ["pe", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1ea", native: "\u{1F1F5}\u{1F1EA}" }], version: 2 }, "flag-pf": { id: "flag-pf", name: "French Polynesia Flag", keywords: ["pf", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1eb", native: "\u{1F1F5}\u{1F1EB}" }], version: 2 }, "flag-pg": { id: "flag-pg", name: "Papua New Guinea Flag", keywords: ["pg", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1ec", native: "\u{1F1F5}\u{1F1EC}" }], version: 2 }, "flag-ph": { id: "flag-ph", name: "Philippines Flag", keywords: ["ph", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1ed", native: "\u{1F1F5}\u{1F1ED}" }], version: 2 }, "flag-pk": { id: "flag-pk", name: "Pakistan Flag", keywords: ["pk", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1f0", native: "\u{1F1F5}\u{1F1F0}" }], version: 2 }, "flag-pl": { id: "flag-pl", name: "Poland Flag", keywords: ["pl", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1f1", native: "\u{1F1F5}\u{1F1F1}" }], version: 2 }, "flag-pm": { id: "flag-pm", name: "St. Pierre & Miquelon Flag", keywords: ["pm", "st", "saint", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1f2", native: "\u{1F1F5}\u{1F1F2}" }], version: 2 }, "flag-pn": { id: "flag-pn", name: "Pitcairn Islands Flag", keywords: ["pn", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1f3", native: "\u{1F1F5}\u{1F1F3}" }], version: 2 }, "flag-pr": { id: "flag-pr", name: "Puerto Rico Flag", keywords: ["pr", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1f7", native: "\u{1F1F5}\u{1F1F7}" }], version: 2 }, "flag-ps": { id: "flag-ps", name: "Palestinian Territories Flag", keywords: ["ps", "palestine", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1f8", native: "\u{1F1F5}\u{1F1F8}" }], version: 2 }, "flag-pt": { id: "flag-pt", name: "Portugal Flag", keywords: ["pt", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1f9", native: "\u{1F1F5}\u{1F1F9}" }], version: 2 }, "flag-pw": { id: "flag-pw", name: "Palau Flag", keywords: ["pw", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1fc", native: "\u{1F1F5}\u{1F1FC}" }], version: 2 }, "flag-py": { id: "flag-py", name: "Paraguay Flag", keywords: ["py", "nation", "country", "banner"], skins: [{ unified: "1f1f5-1f1fe", native: "\u{1F1F5}\u{1F1FE}" }], version: 2 }, "flag-qa": { id: "flag-qa", name: "Qatar Flag", keywords: ["qa", "nation", "country", "banner"], skins: [{ unified: "1f1f6-1f1e6", native: "\u{1F1F6}\u{1F1E6}" }], version: 2 }, "flag-re": { id: "flag-re", name: "R\xE9union Flag", keywords: ["re", "reunion", "nation", "country", "banner"], skins: [{ unified: "1f1f7-1f1ea", native: "\u{1F1F7}\u{1F1EA}" }], version: 2 }, "flag-ro": { id: "flag-ro", name: "Romania Flag", keywords: ["ro", "nation", "country", "banner"], skins: [{ unified: "1f1f7-1f1f4", native: "\u{1F1F7}\u{1F1F4}" }
51763], version: 2 }, "flag-rs": { id: "flag-rs", name: "Serbia Flag", keywords: ["rs", "nation", "country", "banner"], skins: [{ unified: "1f1f7-1f1f8", native: "\u{1F1F7}\u{1F1F8}" }], version: 2 }, ru: { id: "ru", name: "Russia Flag", keywords: ["ru", "russian", "federation", "nation", "country", "banner"], skins: [{ unified: "1f1f7-1f1fa", native: "\u{1F1F7}\u{1F1FA}" }], version: 1 }, "flag-rw": { id: "flag-rw", name: "Rwanda Flag", keywords: ["rw", "nation", "country", "banner"], skins: [{ unified: "1f1f7-1f1fc", native: "\u{1F1F7}\u{1F1FC}" }], version: 2 }, "flag-sa": { id: "flag-sa", name: "Saudi Arabia Flag", keywords: ["sa", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1e6", native: "\u{1F1F8}\u{1F1E6}" }], version: 2 }, "flag-sb": { id: "flag-sb", name: "Solomon Islands Flag", keywords: ["sb", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1e7", native: "\u{1F1F8}\u{1F1E7}" }], version: 2 }, "flag-sc": { id: "flag-sc", name: "Seychelles Flag", keywords: ["sc", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1e8", native: "\u{1F1F8}\u{1F1E8}" }], version: 2 }, "flag-sd": { id: "flag-sd", name: "Sudan Flag", keywords: ["sd", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1e9", native: "\u{1F1F8}\u{1F1E9}" }], version: 2 }, "flag-se": { id: "flag-se", name: "Sweden Flag", keywords: ["se", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1ea", native: "\u{1F1F8}\u{1F1EA}" }], version: 2 }, "flag-sg": { id: "flag-sg", name: "Singapore Flag", keywords: ["sg", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1ec", native: "\u{1F1F8}\u{1F1EC}" }], version: 2 }, "flag-sh": { id: "flag-sh", name: "St. Helena Flag", keywords: ["sh", "st", "saint", "ascension", "tristan", "cunha", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1ed", native: "\u{1F1F8}\u{1F1ED}" }], version: 2 }, "flag-si": { id: "flag-si", name: "Slovenia Flag", keywords: ["si", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1ee", native: "\u{1F1F8}\u{1F1EE}" }], version: 2 }, "flag-sj": { id: "flag-sj", name: "Svalbard & Jan Mayen Flag", keywords: ["sj"], skins: [{ unified: "1f1f8-1f1ef", native: "\u{1F1F8}\u{1F1EF}" }], version: 2 }, "flag-sk": { id: "flag-sk", name: "Slovakia Flag", keywords: ["sk", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1f0", native: "\u{1F1F8}\u{1F1F0}" }], version: 2 }, "flag-sl": { id: "flag-sl", name: "Sierra Leone Flag", keywords: ["sl", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1f1", native: "\u{1F1F8}\u{1F1F1}" }], version: 2 }, "flag-sm": { id: "flag-sm", name: "San Marino Flag", keywords: ["sm", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1f2", native: "\u{1F1F8}\u{1F1F2}" }], version: 2 }, "flag-sn": { id: "flag-sn", name: "Senegal Flag", keywords: ["sn", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1f3", native: "\u{1F1F8}\u{1F1F3}" }], version: 2 }, "flag-so": { id: "flag-so", name: "Somalia Flag", keywords: ["so", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1f4", native: "\u{1F1F8}\u{1F1F4}" }
51763], version: 2 }, "flag-sr": { id: "flag-sr", name: "Suriname Flag", keywords: ["sr", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1f7", native: "\u{1F1F8}\u{1F1F7}" }], version: 2 }, "flag-ss": { id: "flag-ss", name: "South Sudan Flag", keywords: ["ss", "sd", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1f8", native: "\u{1F1F8}\u{1F1F8}" }], version: 2 }, "flag-st": { id: "flag-st", name: "S\xE3o Tom\xE9 & Pr\xEDncipe Flag", keywords: ["st", "sao", "tome", "principe", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1f9", native: "\u{1F1F8}\u{1F1F9}" }], version: 2 }, "flag-sv": { id: "flag-sv", name: "El Salvador Flag", keywords: ["sv", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1fb", native: "\u{1F1F8}\u{1F1FB}" }], version: 2 }, "flag-sx": { id: "flag-sx", name: "Sint Maarten Flag", keywords: ["sx", "dutch", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1fd", native: "\u{1F1F8}\u{1F1FD}" }], version: 2 }, "flag-sy": { id: "flag-sy", name: "Syria Flag", keywords: ["sy", "syrian", "arab", "republic", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1fe", native: "\u{1F1F8}\u{1F1FE}" }], version: 2 }, "flag-sz": { id: "flag-sz", name: "Eswatini Flag", keywords: ["sz", "nation", "country", "banner"], skins: [{ unified: "1f1f8-1f1ff", native: "\u{1F1F8}\u{1F1FF}" }], version: 2 }, "flag-ta": { id: "flag-ta", name: "Tristan Da Cunha Flag", keywords: ["ta"], skins: [{ unified: "1f1f9-1f1e6", native: "\u{1F1F9}\u{1F1E6}" }], version: 2 }, "flag-tc": { id: "flag-tc", name: "Turks & Caicos Islands Flag", keywords: ["tc", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1e8", native: "\u{1F1F9}\u{1F1E8}" }], version: 2 }, "flag-td": { id: "flag-td", name: "Chad Flag", keywords: ["td", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1e9", native: "\u{1F1F9}\u{1F1E9}" }], version: 2 }, "flag-tf": { id: "flag-tf", name: "French Southern Territories Flag", keywords: ["tf", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1eb", native: "\u{1F1F9}\u{1F1EB}" }], version: 2 }, "flag-tg": { id: "flag-tg", name: "Togo Flag", keywords: ["tg", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1ec", native: "\u{1F1F9}\u{1F1EC}" }], version: 2 }, "flag-th": { id: "flag-th", name: "Thailand Flag", keywords: ["th", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1ed", native: "\u{1F1F9}\u{1F1ED}" }], version: 2 }, "flag-tj": { id: "flag-tj", name: "Tajikistan Flag", keywords: ["tj", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1ef", native: "\u{1F1F9}\u{1F1EF}" }], version: 2 }, "flag-tk": { id: "flag-tk", name: "Tokelau Flag", keywords: ["tk", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1f0", native: "\u{1F1F9}\u{1F1F0}" }], version: 2 }, "flag-tl": { id: "flag-tl", name: "Timor-Leste Flag", keywords: ["tl", "timor", "leste", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1f1", native: "\u{1F1F9}\u{1F1F1}" }], version: 2 }, "flag-tm": { id: "flag-tm", name: "Turkmenistan Flag", keywords: ["tm", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1f2", native: "\u{1F1F9}\u{1F1F2}" }], version: 2 }, "flag-tn": { id: "flag-tn", name: "Tunisia Flag", keywords: ["tn", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1f3", native: "\u{1F1F9}\u{1F1F3}" }], version: 2 }, "flag-to": { id: "flag-to", name: "Tonga Flag", keywords: ["to", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1f4", native: "\u{1F1F9}\u{1F1F4}" }
51763], version: 2 }, "flag-tr": { id: "flag-tr", name: "Flag Turkey", keywords: ["tr", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1f7", native: "\u{1F1F9}\u{1F1F7}" }], version: 2 }, "flag-tt": { id: "flag-tt", name: "Trinidad & Tobago Flag", keywords: ["tt", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1f9", native: "\u{1F1F9}\u{1F1F9}" }], version: 2 }, "flag-tv": { id: "flag-tv", name: "Tuvalu Flag", keywords: ["tv", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1fb", native: "\u{1F1F9}\u{1F1FB}" }], version: 2 }, "flag-tw": { id: "flag-tw", name: "Taiwan Flag", keywords: ["tw", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1fc", native: "\u{1F1F9}\u{1F1FC}" }], version: 2 }, "flag-tz": { id: "flag-tz", name: "Tanzania Flag", keywords: ["tz", "united", "republic", "nation", "country", "banner"], skins: [{ unified: "1f1f9-1f1ff", native: "\u{1F1F9}\u{1F1FF}" }], version: 2 }, "flag-ua": { id: "flag-ua", name: "Ukraine Flag", keywords: ["ua", "nation", "country", "banner"], skins: [{ unified: "1f1fa-1f1e6", native: "\u{1F1FA}\u{1F1E6}" }], version: 2 }, "flag-ug": { id: "flag-ug", name: "Uganda Flag", keywords: ["ug", "nation", "country", "banner"], skins: [{ unified: "1f1fa-1f1ec", native: "\u{1F1FA}\u{1F1EC}" }], version: 2 }, "flag-um": { id: "flag-um", name: "U.s. Outlying Islands Flag", keywords: ["um", "u", "s"], skins: [{ unified: "1f1fa-1f1f2", native: "\u{1F1FA}\u{1F1F2}" }], version: 2 }, "flag-un": { id: "flag-un", name: "United Nations Flag", keywords: ["un", "banner"], skins: [{ unified: "1f1fa-1f1f3", native: "\u{1F1FA}\u{1F1F3}" }], version: 4 }, us: { id: "us", name: "United States Flag", keywords: ["us", "america", "nation", "country", "banner"], skins: [{ unified: "1f1fa-1f1f8", native: "\u{1F1FA}\u{1F1F8}" }], version: 1 }, "flag-uy": { id: "flag-uy", name: "Uruguay Flag", keywords: ["uy", "nation", "country", "banner"], skins: [{ unified: "1f1fa-1f1fe", native: "\u{1F1FA}\u{1F1FE}" }], version: 2 }, "flag-uz": { id: "flag-uz", name: "Uzbekistan Flag", keywords: ["uz", "nation", "country", "banner"], skins: [{ unified: "1f1fa-1f1ff", native: "\u{1F1FA}\u{1F1FF}" }], version: 2 }, "flag-va": { id: "flag-va", name: "Vatican City Flag", keywords: ["va", "nation", "country", "banner"], skins: [{ unified: "1f1fb-1f1e6", native: "\u{1F1FB}\u{1F1E6}" }], version: 2 }, "flag-vc": { id: "flag-vc", name: "St. Vincent & Grenadines Flag", keywords: ["vc", "st", "saint", "nation", "country", "banner"], skins: [{ unified: "1f1fb-1f1e8", native: "\u{1F1FB}\u{1F1E8}" }], version: 2 }, "flag-ve": { id: "flag-ve", name: "Venezuela Flag", keywords: ["ve", "bolivarian", "republic", "nation", "country", "banner"], skins: [{ unified: "1f1fb-1f1ea", native: "\u{1F1FB}\u{1F1EA}" }], version: 2 }, "flag-vg": { id: "flag-vg", name: "British Virgin Islands Flag", keywords: ["vg", "bvi", "nation", "country", "banner"], skins: [{ unified: "1f1fb-1f1ec", native: "\u{1F1FB}\u{1F1EC}" }], version: 2 }, "flag-vi": { id: "flag-vi", name: "U.s. Virgin Islands Flag", keywords: ["vi", "u", "s", "us", "nation", "country", "banner"], skins: [{ unified: "1f1fb-1f1ee", native: "\u{1F1FB}\u{1F1EE}" }], version: 2 }, "flag-vn": { id: "flag-vn", name: "Vietnam Flag", keywords: ["vn", "viet", "nam", "nation", "country", "banner"], skins: [{ unified: "1f1fb-1f1f3", native: "\u{1F1FB}\u{1F1F3}" }], version: 2 }, "flag-vu": { id: "flag-vu", name: "Vanuatu Flag", keywords: ["vu", "nation", "country", "banner"], skins: [{ unified: "1f1fb-1f1fa", native: "\u{1F1FB}\u{1F1FA}" }], version: 2 }, "flag-wf": { id: "flag-wf", name: "Wallis & Futuna Flag", keywords: ["wf", "nation", "country", "banner"], skins: [{ unified: "1f1fc-1f1eb", native: "\u{1F1FC}\u{1F1EB}" }], version: 2 }, "flag-ws": { id: "flag-ws", name: "Samoa Flag", keywords: ["ws", "nation", "country", "banner"], skins: [{ unified: "1f1fc-1f1f8", native: "\u{1F1FC}\u{1F1F8}" }], version: 2 }, "flag-xk": { id: "flag-xk", name: "Kosovo Flag", keywords: ["xk", "nation", "country", "banner"], skins: [{ unified: "1f1fd-1f1f0", native: "\u{1F1FD}\u{1F1F0}" }], version: 2 }, "flag-ye": { id: "flag-ye", name: "Yemen Flag", keywords: ["ye", "nation", "country", "banner"], skins: [{ unified: "1f1fe-1f1ea", native: "\u{1F1FE}
51763\u{1F1EA}" }], version: 2 }, "flag-yt": { id: "flag-yt", name: "Mayotte Flag", keywords: ["yt", "nation", "country", "banner"], skins: [{ unified: "1f1fe-1f1f9", native: "\u{1F1FE}\u{1F1F9}" }], version: 2 }, "flag-za": { id: "flag-za", name: "South Africa Flag", keywords: ["za", "nation", "country", "banner"], skins: [{ unified: "1f1ff-1f1e6", native: "\u{1F1FF}\u{1F1E6}" }], version: 2 }, "flag-zm": { id: "flag-zm", name: "Zambia Flag", keywords: ["zm", "nation", "country", "banner"], skins: [{ unified: "1f1ff-1f1f2", native: "\u{1F1FF}\u{1F1F2}" }], version: 2 }, "flag-zw": { id: "flag-zw", name: "Zimbabwe Flag", keywords: ["zw", "nation", "country", "banner"], skins: [{ unified: "1f1ff-1f1fc", native: "\u{1F1FF}\u{1F1FC}" }], version: 2 }, "flag-england": { id: "flag-england", name: "England Flag", keywords: ["english"], skins: [{ unified: "1f3f4-e0067-e0062-e0065-e006e-e0067-e007f", native: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0065}\u{E006E}\u{E0067}\u{E007F}" }], version: 5 }, "flag-scotland": { id: "flag-scotland", name: "Scotland Flag", keywords: ["scottish"], skins: [{ unified: "1f3f4-e0067-e0062-e0073-e0063-e0074-e007f", native: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0073}\u{E0063}\u{E0074}\u{E007F}" }], version: 5 }, "flag-wales": { id: "flag-wales", name: "Wales Flag", keywords: ["welsh"], skins: [{ unified: "1f3f4-e0067-e0062-e0077-e006c-e0073-e007f", native: "\u{1F3F4}\u{E0067}\u{E0062}\u{E0077}\u{E006C}\u{E0073}\u{E007F}" }], version: 5 }, distorted_face: { id: "distorted_face", name: "Distorted Face", keywords: ["anxiety", "bloated", "panic", "shocked", "surprised", "vulnerable"], skins: [{ unified: "1faea", native: "\u{1FAEA}" }], version: 17 }, fight_cloud: { id: "fight_cloud", name: "Fight Cloud", keywords: ["argument", "brawl", "debate", "disagreement", "ruckus", "wrestle"], skins: [{ unified: "1faef", native: "\u{1FAEF}" }], version: 17 }, hairy_creature: { id: "hairy_creature", name: "Hairy Creature", keywords: ["bigfoot", "cryptid", "forest", "giant", "sasquatch", "woodwose", "yeti"], skins: [{ unified: "1fac8", native: "\u{1FAC8}" }], version: 17 }, ballet_dancer: { id: "ballet_dancer", name: "Ballet Dancer", keywords: [], skins: [{ unified: "1f9d1-200d-1fa70", native: "\u{1F9D1}\u200D\u{1FA70}" }, { unified: "1f9d1-1f3fb-200d-1fa70", native: "\u{1F9D1}\u{1F3FB}\u200D\u{1FA70}" }, { unified: "1f9d1-1f3fc-200d-1fa70", native: "\u{1F9D1}\u{1F3FC}\u200D\u{1FA70}" }, { unified: "1f9d1-1f3fd-200d-1fa70", native: "\u{1F9D1}\u{1F3FD}\u200D\u{1FA70}" }, { unified: "1f9d1-1f3fe-200d-1fa70", native: "\u{1F9D1}\u{1F3FE}\u200D\u{1FA70}" }, { unified: "1f9d1-1f3ff-200d-1fa70", native: "\u{1F9D1}\u{1F3FF}\u200D\u{1FA70}" }], version: 17 }, orca: { id: "orca", name: "Orca", keywords: ["marine", "ocean", "whale"], skins: [{ unified: "1facd", native: "\u{1FACD}" }], version: 17 }, landslide: { id: "landslide", name: "Landslide", keywords: ["avalanche", "danger", "disaster", "earthquake", "mountain", "mudslide", "rocks"], skins: [{ unified: "1f6d8", native: "\u{1F6D8}" }], version: 17 }, trombone: { id: "trombone", name: "Trombone", keywords: ["brass", "instrument", "jazz", "music", "sad", "slide"], skins: [{ unified: "1fa8a", native: "\u{1FA8A}" }], version: 17 }, treasure_chest: { id: "treasure_chest", name: "Treasure Chest", keywords: ["gem", "gold", "jewels", "loot", "money", "prize", "silver", "valuables", "wealth"], skins: [{ unified: "1fa8e", native: "\u{1FA8E}" }], version: 17 } }, aliases: { satisfied: "laughing", grinning_face_with_star_eyes: "star-struck", grinning_face_with_one_large_and_one_small_eye: "zany_face", smiling_face_with_smiling_eyes_and_hand_covering_mouth: "face_with_hand_over_mouth", face_with_finger_covering_closed_lips: "shushing_face", face_with_one_eyebrow_raised: "face_with_raised_eyebrow", face_with_open_mouth_vomiting: "face_vomiting", shocked_face_with_exploding_head: "exploding_head", serious_face_with_symbols_covering_mouth: "face_with_symbols_on_mouth", poop: "hankey", shit: "hankey", collision: "boom", raised_hand: "hand", hand_with_index_and_middle_fingers_crossed: "crossed_fingers", sign_of_the_horns: "the_horns", reversed_hand_with_middle_finger_extended: "middle_finger", thumbsup: "+1", thumbsdown: "-1", punch: "facepunch", mother_christmas: "mrs_claus", running: "runner", "man-with-bunny-ears-partying": "men-with-bunny-ears-partying", "woman-with-bunny-ears-partying": "women-with-bunny-ears-partying", women_holding_hands: "two_women_holding_hands", woman_and_man_holding_hands: "man_and_woman_holding_hands", couple: "man_and_woman_holding_hands", men_holding_hands: "two_men_holding_hands", paw_prints: "feet", flipper: "dolphin", honeybee: "bee", lady_beetle: "ladybug", cooking: "fried_egg", knife: "hocho", red_car: "car", sailboat: "boat", waxing_gibbous_moon: "moon", sun_small_cloud: "mostly_sunny", sun_behind_cloud: "barely_sunny", sun_behind_rain_cloud: "partly_sunny_rain", lightning_cloud: "lightning", tornado_cloud: "tornado", tshirt: "shirt", shoe: "mans_shoe", telephone: "phone", lantern: "izakaya_lantern", open_book: "book", envelope: "email", pencil: "memo", heavy_exclamation_mark: "exclamation", staff_of_aesculapius: "medical_symbol", "flag-cn": "cn", "flag-de": "de", "flag-es": "es", "flag-fr": "fr", uk: "gb", "flag-gb": "gb", "flag-it": "it", "flag-jp": "jp", "flag-kr": "kr", "flag-ru": "ru", "flag-us": "us" }, sheet: { cols: 61, rows: 61 } }; 51764 51765
51765// app/javascript/src/emoji_mart/data.js 51766 var EMOJI_MART_DATA = native_default; 51767 var EMOJI_MART_VERSION = 17; 51768 51769
51769// app/javascript/src/emoji_mart/theme.js 51770 function emojiMartTheme() { 51771 return document.documentElement.classList.contains("dark") ? "dark" : "light"; 51772 } 51773 function watchEmojiMartTheme(picker) { 51774 const syncTheme = () => { 51775 picker.update?.({ theme: emojiMartTheme() }); 51776 }; 51777 const observer = new MutationObserver(syncTheme); 51778 observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] }); 51779 return () => observer.disconnect(); 51780 } 51781 51782
51782// app/javascript/src/lexxy/callout_emoji_picker.js 51783 function createCalloutEmojiPicker(container, { onSelect, pickerOptions = {} }) { 51784 const picker = new $efa000751917694d$export$2e2bcd8739ae039({ 51785 data: EMOJI_MART_DATA, 51786 onEmojiSelect: onSelect, 51787 dynamicWidth: true, 51788 emojiButtonColors: ["rgba(128, 128, 128, 0.22)"], 51789 emojiVersion: EMOJI_MART_VERSION, 51790 navPosition: "bottom", 51791 previewPosition: "none", 51792 theme: emojiMartTheme(), 51793 ...pickerOptions 51794 }); 51795 picker._unwatchTheme = watchEmojiMartTheme(picker); 51796 container.replaceChildren(picker); 51797 return picker; 51798 } 51799 function applyCalloutEmojiPickerStyles(root) { 51800 if (root.querySelector("[data-callout-emoji-styles]")) return; 51801 const style = document.createElement("style"); 51802 style.dataset.calloutEmojiStyles = ""; 51803 style.textContent = ` 51804 #root { 51805 border-radius: 0 !important; 51806 } 51807 51808 * { 51809 scrollbar-color: #d6d6d6 transparent !important; 51810 scrollbar-width: thin !important; 51811 } 51812 51813 *::-webkit-scrollbar {
51814 height: 6px !important; 51815 width: 6px !important; 51816 } 51817 51818 *::-webkit-scrollbar-track { 51819 background: transparent !important; 51820 } 51821 51822 *::-webkit-scrollbar-thumb { 51823 background-color: #d6d6d6 !important; 51824 } 51825 51826 [data-theme="dark"] * { 51827 scrollbar-color: #5c5c5c transparent !important; 51828 } 51829 51830 [data-theme="dark"] *::-webkit-scrollbar-thumb { 51831 background-color: #5c5c5c !important; 51832 } 51833 51834 .search { 51835 align-items: center !important; 51836 background-color: var(--callout-tools-control-bg, rgb(var(--em-rgb-background))) !important; 51837 border: 1px solid var(--callout-tools-control-border, var(--color-border)) !important; 51838 border-radius: 8px !important; 51839 block-size: 37.5px !important; 51840 box-sizing: border-box !important; 51841 box-shadow: none !important; 51842 color: var(--callout-tools-control-muted, rgba(var(--em-rgb-color), 0.52)) !important; 51843 min-block-size: 37.5px !important; 51844 } 51845 51846 .search:focus-within { 51847 border-color: var(--callout-tools-control-border-focus, rgba(var(--em-rgb-color), 0.78)) !important; 51848 box-shadow: none !important; 51849 } 51850 51851 .search input { 51852 background: transparent !important; 51853 border: 0 !important; 51854 box-shadow: none !important; 51855 color: var(--callout-tools-control-text, rgb(var(--em-rgb-color))) !important; 51856 appearance: none !important; 51857 -webkit-appearance: none !important; 51858 font: inherit !important; 51859 font-size: 0.95rem !important; 51860 block-size: 100% !important; 51861 min-inline-size: 0 !important; 51862 outline: none !important; 51863 padding-block: 0 !important; 51864 padding-inline: 2.2rem !important; 51865 } 51866 51867 .search input::placeholder { 51868 color: var(--callout-tools-control-muted, rgba(var(--em-rgb-color), 0.52)) !important; 51869 opacity: 1 !important; 51870 } 51871 51872 .search .icon { 51873 color: var(--callout-tools-control-muted, rgba(var(--em-rgb-color), 0.52)) !important; 51874 height: 1.05rem !important; 51875 width: 1.05rem !important; 51876 } 51877 51878 .search .loupe { 51879 left: 0.65rem !important; 51880 pointer-events: none !important; 51881 right: auto !important; 51882 } 51883 51884 .search .delete { 51885 align-items: center !important; 51886 background-color: #6c7280 !important; 51887 background-image: none !important; 51888 block-size: 1rem !important; 51889 inline-size: 1rem !important; 51890 justify-content: center !important; 51891 left: auto !important; 51892 mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'%3E%3Cpath stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 18 18 6M6 6l12 12'/%3E%3C/svg%3E") !important; 51893 mask-position: center !important; 51894 mask-repeat: no-repeat !important; 51895 mask-size: 1rem 1rem !important; 51896 -webkit-mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'%3E%3Cpath stroke='%23000' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M6 18 18 6M6 6l12 12'/%3E%3C/svg%3E") !important; 51897 -webkit-mask-position: center !important; 51898 -webkit-mask-repeat: no-repeat !important; 51899 -webkit-mask-size: 1rem 1rem !important; 51900 right: 0.85rem !important; 51901 } 51902 51903 .search .delete:hover { 51904 background-color: #374151 !important; 51905 } 51906 51907 [data-theme="dark"] .search .delete { 51908 background-color: #d1d5dc !important; 51909 } 51910 51911 [data-theme="dark"] .search .delete:hover { 51912 background-color: #f3f4f6 !important; 51913 } 51914 51915 .search .delete svg { 51916 display: none !important; 51917 } 51918 51919 [dir="rtl"] .search .loupe { 51920 left: auto !important; 51921 right: 0.65rem !important; 51922 } 51923 51924 [dir="rtl"] .search .delete { 51925 left: 0.85rem !important; 51926 right: auto !important; 51927 } 51928 51929 .search .icon svg { 51930 fill: currentColor !important; 51931 height: 1.05rem !important; 51932 width: 1.05rem !important; 51933 } 51934 51935 .spacer { 51936 height: 8px !important; 51937 } 51938 51939 button:focus, 51940 button:focus-visible { 51941 box-shadow: none !important; 51942 outline: none !important; 51943 } 51944 51945 button:focus .background, 51946 button:focus-visible .background { 51947 border-radius: 30% !important; 51948 } 51949 51950 .background { 51951 border-radius: 30% !important; 51952 } 51953 51954 .skin-tone-button, 51955 .skin-tone-button:focus, 51956 .skin-tone-button:focus-visible { 51957 border-radius: 0 !important; 51958 } 51959 51960 button[data-callout-selected-emoji="true"] .background { 51961 opacity: 1 !important; 51962 border-radius: 30% !important; 51963 } 51964 51965 button[data-callout-selected-emoji="true"] { 51966 box-shadow: inset 0 0 0 1px rgba(var(--em-rgb-color), 0.78); 51967 border-radius: 30%; 51968 } 51969 `; 51970 root.append(style); 51971 } 51972 51973
51973// app/javascript/src/lexxy/callout_tools.js 51974 var { $getNearestNodeFromDOMNode: $getNearestNodeFromDOMNode3, $getNodeByKey: $getNodeByKey3, $getSelection: $getSelection4, $isElementNode: $isElementNode5, $isRangeSelection: $isRangeSelection4 } = Lexical_exports; 51975 var ICON_GRID_BATCH_SIZE = 240; 51976 var ICON_GRID_COLUMNS = 10; 51977 var SEARCH_ICON_SVG = ` 51978 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" aria-hidden="true" focusable="false"> 51979 <path d="M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z"></path> 51980 </svg> 51981`; 51982 var SHUFFLE_ICON_SVG = ` 51983 <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"> 51984 <path d="m18 14 4 4-4 4"></path> 51985 <path d="m18 2 4 4-4 4"></path> 51986 <path d="M2 18h1.4c1.3 0 2.5-.6 3.3-1.6L14 7.6C14.8 6.6 16 6 17.3 6H22"></path> 51987 <path d="M2 6h1.4c1.3 0 2.5.6 3.3 1.6l1.2 1.5"></path> 51988 <path d="m13.9 14.9.1.1c.8 1.2 2.1 3 3.3 3H22"></path> 51989 </svg> 51990`; 51991 var IMAGE_ICON_SVG = ` 51992 <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"> 51993 <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect> 51994 <circle cx="9" cy="9" r="2"></circle> 51995 <path d="m21 15-3.1-3.1a2 2 0 0 0-2.8 0L6 21"></path> 51996 </svg> 51997`; 51998 var TRASH_ICON_SVG = ` 51999 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 52000 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 52001 <path d="M2.75 4.75H15.25"></path> 52002 <path d="M6.75 4.75V2.75C6.75 2.2 7.198 1.75 7.75 1.75H10.25C10.802 1.75 11.25 2.2 11.25 2.75V4.75"></path> 52003 <path d="M7.375 8.75L7.59219 13.25"></path> 52004 <path d="M10.625 8.75L10.4078 13.25"></path> 52005 <path d="M13.6977 7.75L13.35 14.35C13.294 15.4201 12.416 16.25 11.353 16.25H6.64804C5.58404 16.25 4.70703 15.42 4.65103 14.35L4.30334 7.75"></path> 52006 </g> 52007 </svg> 52008`; 52009 var SWATCH_CHECK_SVG = ` 52010 <svg class="lexxy-callout-tools__swatch-check" viewBox="0 0 12 12" aria-hidden="true" focusable="false"> 52011 <path d="M1.75391 6.41392L4.4001 9.24985L10.2467 2.98532" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path> 52012 </svg> 52013`; 52014 var SWATCH_NONE_ICON_SVG = ` 52015 <svg class="lexxy-callout-tools__swatch-none-icon" viewBox="0 0 12 12" aria-hidden="true" focusable="false"> 52016 <g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"> 52017 <path d="M9.35876 2.64124C8.49918 1.78166 7.31168 1.25 6 1.25C3.37665 1.25 1.25 3.37665 1.25 6C1.25 7.31168 1.78166 8.49918 2.64124 9.35876"></path> 52018 <path d="M10.6832 5.20337C10.7269 5.46236 10.7496 5.72846 10.7496 5.99989C10.7496 8.62324 8.623 10.7499 5.99965 10.7499C5.72822 10.7499 5.46211 10.7271 5.20312 10.6834"></path> 52019 <path d="M1.25 10.75L10.75 1.25"></path> 52020 </g> 52021 </svg> 52022`; 52023 function $getCalloutInSelection() { 52024 const selection = $getSelection4(); 52025 if (!$isRangeSelection4(selection)) return null; 52026 return $findMatchingParent3(selection.anchor.getNode(), $isCalloutNode); 52027 } 52028 function $getCalloutByKey(activeCalloutKey) { 52029 if (!activeCalloutKey) return null; 52030 const callout = $getNodeByKey3(activeCalloutKey); 52031 return $isCalloutNode(callout) ? callout : null; 52032 } 52033 function $getToolbarCallout(activeCalloutKey) { 52034 return $getCalloutByKey(activeCalloutKey) || $getCalloutInSelection(); 52035 } 52036 function escapeHtml(value) { 52037 return String(value).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); 52038 } 52039 var CalloutToolsElement = class extends HTMLElement { 52040 #updateListener = null; 52041 #fileInput = null; 52042 #emojiPicker = null; 52043 #lucideIcons = null; 52044 #outsideClickHandler = null; 52045 #escapeHandler = null; 52046 #pasteHandler = null; 52047 #activeIconTab = "emoji"; 52048 #uploadFile = null; 52049 #uploadUrl = null; 52050 #uploadPreviewObjectUrl = null; 52051 #uploadSaving = false; 52052 #uploadUrlValidationId = 0; 52053 #activeCalloutKey = null; 52054 #iconPopover = null; 52055 #popoverPositionCleanup = null; 52056 #selectedSymbol = null; 52057 #selectedEmoji = null; 52058 #emojiPickerObserver = null; 52059 #visibleIconCount = ICON_GRID_BATCH_SIZE; 52060 #iconSearchQuery = ""; 52061 #iconKeyboardIndex = -1; 52062 #iconSearchNavigated = false;
52063 #inlineIconMouseDownHandler = null; 52064 #inlineIconClickHandler = null; 52065 #editorFocusOutHandler = null; 52066 #pendingCalloutSyncFrame = null; 52067 connectedCallback() { 52068 this.editorElement = this.closest("lexxy-editor"); 52069 this.editor = this.editorElement.editor; 52070 this.classList.add("lexxy-floating-controls", "ph-no-autocapture"); 52071 this.setAttribute("data-ph-no-autocapture", ""); 52072 this.#buildUI(); 52073 this.#hide(); 52074 this.#monitorSelection(); 52075 this.#bindInlineIconTriggerEvents(); 52076 this.#bindEditorFocusEvents(); 52077 } 52078 disconnectedCallback() { 52079 this.#updateListener?.(); 52080 this.#unbindInlineIconTriggerEvents(); 52081 this.#unbindEditorFocusEvents(); 52082 this.#fileInput?.remove(); 52083 this.#closeIconPopover(); 52084 this.#teardownIconPopoverPortal(); 52085 this.#removeGlobalListeners(); 52086 if (this.#pendingCalloutSyncFrame) { 52087 cancelAnimationFrame(this.#pendingCalloutSyncFrame); 52088 this.#pendingCalloutSyncFrame = null; 52089 } 52090 this.#emojiPickerObserver?.disconnect(); 52091 this.#emojiPickerObserver = null; 52092 this.#emojiPicker?._unwatchTheme?.(); 52093 this.#revokeUploadPreview(); 52094 this.#emojiPicker = null; 52095 this.#iconPopover = null; 52096 } 52097 #buildUI() { 52098 this.innerHTML = ` 52099 <div class="lexxy-floating-controls__group lexxy-callout-tools__bar"> 52100 <div class="lexxy-callout-tools__tool-row"> 52101 <div class="lexxy-callout-tools__icon-section"> 52102 <button 52103 type="button" 52104 class="lexxy-callout-tools__icon-trigger" 52105 data-callout-icon-toggle 52106 aria-label="Callout icon" 52107 aria-expanded="false" 52108 aria-haspopup="dialog" 52109 > 52110 <span data-callout-icon-preview>\u{1F4A1}</span> 52111 </button> 52112 52113 <div 52114 class="lexxy-callout-tools__icon-popover ph-no-autocapture hidden" 52115 data-icon-popover 52116 data-ph-no-autocapture 52117 hidden 52118 role="dialog" 52119 aria-label="Callout icon" 52120 > 52121 <div class="lexxy-callout-tools__tab-bar"> 52122 <div class="lexxy-callout-tools__tabs" role="tablist" aria-label="Callout icon type"> 52123 <button type="button" role="tab" data-icon-tab="emoji" aria-selected="true">Emoji</button> 52124 <button type="button" role="tab" data-icon-tab="icons" aria-selected="false">Icons</button> 52125 <button type="button" role="tab" data-icon-tab="upload" aria-selected="false">Upload</button> 52126 </div> 52127 <button 52128 type="button" 52129 class="lexxy-callout-tools__remove-button" 52130 data-callout-remove 52131 aria-label="Remove" 52132 > 52133 <span class="lexxy-callout-tools__remove-label">Remove</span> 52134 <span class="lexxy-callout-tools__remove-icon">${TRASH_ICON_SVG}</span> 52135 </button> 52136 </div> 52137 52138 <div class="lexxy-callout-tools__tab-panel" data-icon-tab-panel="emoji"> 52139 <div class="lexxy-callout-tools__emoji-picker" data-emoji-picker-container></div> 52140 </div> 52141 52142 <div class="lexxy-callout-tools__tab-panel hidden" data-icon-tab-panel="icons"> 52143 <div class="lexxy-callout-tools__icons-panel"> 52144 <div class="lexxy-callout-tools__search-row"> 52145 <label class="lexxy-callout-tools__search"> 52146 ${SEARCH_ICON_SVG} 52147 <input type="search" placeholder="Search" autocomplete="off" data-icon-search> 52148 </label> 52149 <button type="button" class="lexxy-callout-tools__icon-random" data-callout-random-icon title="Random icon" aria-label="Random icon"> 52150 ${SHUFFLE_ICON_SVG} 52151 </button> 52152 </div> 52153 <div class="lexxy-callout-tools__icon-status" data-icon-status role="status" aria-live="polite" hidden></div> 52154 <div class="lexxy-callout-tools__icon-grid small-scrollbar" data-icon-grid></div> 52155 </div> 52156 </div> 52157 52158 <div class="lexxy-callout-tools__tab-panel hidden" data-icon-tab-panel="upload"> 52159 <div class="lexxy-callout-tools__upload-panel"> 52160 <button type="button" class="lexxy-callout-tools__upload-dropzone" data-callout-upload>
52161 <span class="lexxy-callout-tools__upload-empty" data-upload-empty> 52162 <span class="lexxy-callout-tools__upload-empty-icon">${IMAGE_ICON_SVG}</span> 52163 <span>Upload an image</span> 52164 </span> 52165 <span class="lexxy-callout-tools__upload-preview hidden" data-upload-preview></span> 52166 </button> 52167 <label class="lexxy-callout-tools__upload-url"> 52168 <span>Image link</span> 52169 <input type="url" placeholder="https://example.com/image.png" data-upload-url> 52170 </label> 52171 <p class="lexxy-callout-tools__upload-hint" data-upload-hint> 52172 or 52173 <button type="button" class="lexxy-callout-tools__upload-inline-action" data-upload-paste-clipboard>paste an image</button> 52174 from your clipboard 52175 </p> 52176 <p class="lexxy-callout-tools__upload-status" data-upload-status role="status" aria-live="polite" hidden></p> 52177 <div class="lexxy-callout-tools__upload-actions"> 52178 <button type="button" class="lexxy-callout-tools__upload-cancel" data-upload-cancel>Cancel</button> 52179 <button type="button" class="lexxy-callout-tools__upload-save" data-upload-save disabled>Save</button> 52180 </div> 52181 </div> 52182 </div> 52183 </div> 52184 </div> 52185 52186 <div class="lexxy-callout-tools__color-section lexxy-callout-tools__color-section--border"> 52187 <div class="lexxy-callout-tools__swatch-row" data-color-target="border"> 52188 ${this.#swatchButtons("border")} 52189 </div> 52190 </div> 52191 </div> 52192 52193 <div class="lexxy-callout-tools__tool-row lexxy-callout-tools__secondary-row"> 52194 <div class="lexxy-callout-tools__delete-section"> 52195 <button 52196 type="button" 52197 class="lexxy-callout-tools__delete-button" 52198 data-callout-delete 52199 aria-label="Delete callout" 52200 title="Delete callout" 52201 > 52202 ${TRASH_ICON_SVG} 52203 </button> 52204 </div> 52205 52206 <div class="lexxy-callout-tools__color-section lexxy-callout-tools__color-section--background"> 52207 <div class="lexxy-callout-tools__swatch-row" data-color-target="background"> 52208 ${this.#swatchButtons("background")} 52209 </div> 52210 </div> 52211 </div> 52212 </div> 52213 `; 52214 this.#fileInput = document.createElement("input"); 52215 this.#fileInput.type = "file"; 52216 this.#fileInput.accept = "image/png,image/jpeg,image/webp,image/gif"; 52217 this.#fileInput.hidden = true; 52218 this.appendChild(this.#fileInput); 52219 this.addEventListener("mousedown", (event) => { 52220 if (event.target.closest("button, input, label, [data-callout-upload]")) event.preventDefault(); 52221 }); 52222 this.addEventListener("click", (event) => this.#handleClick(event)); 52223 this.addEventListener("input", (event) => this.#handleInput(event)); 52224 this.addEventListener("dragenter", (event) => this.#handleUploadDrag(event)); 52225 this.addEventListener("dragover", (event) => this.#handleUploadDrag(event)); 52226 this.addEventListener("dragleave", (event) => this.#handleUploadDragLeave(event)); 52227 this.addEventListener("drop", (event) => this.#handleUploadDrop(event)); 52228 this.#fileInput.addEventListener("change", (event) => this.#handleFileSelected(event)); 52229 this.#iconPopover = this.querySelector("[data-icon-popover]"); 52230 this.#setupIconPopoverPortal(); 52231 } 52232 #setupIconPopoverPortal() { 52233 if (!this.#iconPopover) return; 52234 this.#iconPopover.classList.add("lexxy-callout-tools__icon-popover--portaled"); 52235 this.#iconPopover.addEventListener("mousedown", (event) => { 52236 if (event.target.closest("button, input, label, [data-callout-upload]")) event.preventDefault(); 52237 }); 52238 this.#iconPopover.addEventListener("click", (event) => this.#handleClick(event)); 52239 this.#iconPopover.addEventListener("input", (event) => this.#handleInput(event)); 52240 this.#iconPopover.addEventListener("dragenter", (event) => this.#handleUploadDrag(event)); 52241 this.#iconPopover.addEventListener("dragover", (event) => this.#handleUploadDrag(event)); 52242 this.#iconPopover.addEventListener("dragleave", (event) => this.#handleUploadDragLeave(event)); 52243 this.#iconPopover.addEventListener("drop", (event) => this.#handleUploadDrop(event)); 52244 this.#iconPopover.addEventListener("scroll", (event) => this.#handleIconGridScroll(event), true); 52245 this.#iconPopover.addEventListener("keydown", (event) => this.#handleIconSearchKeydown(event)); 52246 this.#iconPopover.addEventListener("pointerover", (event) => this.#handleIconGridPointerOver(event)); 52247 } 52248 #teardownIconPopoverPortal() { 52249 this.#iconPopover?.remove(); 52250 } 52251 #iconPopoverToggle() { 52252 return this.querySelector("[data-callout-icon-toggle]"); 52253 } 52254 #popoverQuery(selector) { 52255 return this.#iconPopover?.querySelector(selector) ?? null; 52256 } 52257 #popoverQueryAll(selector) { 52258 return this.#iconPopover ? [...this.#iconPopover.querySelectorAll(selector)] : []; 52259 } 52260 #iconPopoverAnchor() { 52261 return this.querySelector(".lexxy-callout-tools__bar"); 52262 } 52263 #clickedEditorCalloutElement(path) { 52264 for (const node of path) { 52265 const element = node instanceof Element ? node : node instanceof Node ? node.parentElement : null; 52266 const callout = element?.closest(".lexxy-callout"); 52267 if (callout && this.editorElement.contains(callout)) return callout; 52268 } 52269 return null; 52270 } 52271 #syncToolbarForCalloutElement(calloutElement) { 52272 this.editor.getEditorState().read(() => { 52273 const node = $getNearestNodeFromDOMNode3(calloutElement); 52274 const callout = $isCalloutNode(node) ? node : $findMatchingParent3(node, $isCalloutNode); 52275 if (!callout) return; 52276 this.#syncUI(callout); 52277 this.#show(callout); 52278 }); 52279 } 52280 #scheduleToolbarSyncForCalloutElement(calloutElement) { 52281 if (this.#pendingCalloutSyncFrame) { 52282 cancelAnimationFrame(this.#pendingCalloutSyncFrame); 52283 } 52284 this.#pendingCalloutSyncFrame = requestAnimationFrame(() => { 52285 this.#pendingCalloutSyncFrame = null; 52286 if (!calloutElement.isConnected) return; 52287 this.#syncToolbarForCalloutElement(calloutElement); 52288 }); 52289 } 52290 #startPopoverPositioning() { 52291 const popover = this.#iconPopover; 52292 const anchor = this.#iconPopoverAnchor(); 52293 if (!popover || !anchor) return; 52294 this.#stopPopoverPositioning(); 52295 const updatePosition = () => { 52296 computePosition2(anchor, popover, { 52297 strategy: "fixed", 52298 placement: "bottom", 52299 middleware: [offset2(6), flip2(), shift2({ padding: 8 })] 52300 }).then(({ x: x3, y: y3 }) => { 52301 Object.assign(popover.style, { 52302 position: "fixed", 52303 left: `${x3}px`, 52304 top: `${y3}px` 52305 }); 52306 }); 52307 }; 52308 this.#popoverPositionCleanup = autoUpdate(anchor, popover, updatePosition); 52309 updatePosition(); 52310 } 52311 #stopPopoverPositioning() { 52312 this.#popoverPositionCleanup?.(); 52313 this.#popoverPositionCleanup = null; 52314 } 52315 #showIconPopoverLayer() { 52316 if (this.#iconPopover && this.#iconPopover.parentElement !== document.body) { 52317 document.body.appendChild(this.#iconPopover); 52318 } 52319 } 52320 #swatchButtons(target) { 52321 const noneButton = ` 52322 <button 52323 type="button" 52324 class="lexxy-callout-tools__swatch lexxy-callout-tools__swatch--none" 52325 data-color-target="${target}" 52326 data-variant="${CALLOUT_VARIANT_NONE}" 52327 title="None" 52328 aria-label="None" 52329 >${SWATCH_NONE_ICON_SVG}${SWATCH_CHECK_SVG}</button> 52330 `; 52331 const colorButtons = HIGHLIGHT_VARIANTS.map( 52332 ({ id: id3, label }) => ` 52333 <button 52334 type="button" 52335 class="lexxy-callout-tools__swatch" 52336 data-color-target="${target}" 52337 data-variant="${id3}" 52338 style="--swatch-color: var(--callout-${target === "background" ? "bg" : "border"}-${id3}); --swatch-solid: var(--callout-border-${id3});" 52339 title="${label}" 52340 aria-label="${label}" 52341 >${SWATCH_CHECK_SVG}</button> 52342 ` 52343 ).join(""); 52344 return noneButton + colorButtons; 52345 } 52346 #handleClick(event) { 52347 const uploadCancel = event.target.closest("[data-upload-cancel]"); 52348 if (uploadCancel) { 52349 event.preventDefault();
52350 this.#resetUploadPanel(); 52351 this.#closeIconPopover(); 52352 return; 52353 } 52354 const uploadSave = event.target.closest("[data-upload-save]"); 52355 if (uploadSave) { 52356 event.preventDefault(); 52357 this.#saveUploadSelection(); 52358 return; 52359 } 52360 const uploadPasteClipboard = event.target.closest("[data-upload-paste-clipboard]"); 52361 if (uploadPasteClipboard) { 52362 event.preventDefault(); 52363 this.#pasteUploadFromClipboard(); 52364 return; 52365 } 52366 const deleteButton = event.target.closest("[data-callout-delete]"); 52367 if (deleteButton) { 52368 event.preventDefault(); 52369 this.#deleteCallout(); 52370 return; 52371 } 52372 const iconToggle = event.target.closest("[data-callout-icon-toggle]"); 52373 if (iconToggle) { 52374 event.preventDefault(); 52375 event.stopPropagation(); 52376 this.#toggleIconPopover(); 52377 return; 52378 } 52379 const tab = event.target.closest("[data-icon-tab]"); 52380 if (tab) { 52381 event.preventDefault(); 52382 this.#setIconTab(tab.dataset.iconTab); 52383 return; 52384 } 52385 const removeButton = event.target.closest("[data-callout-remove]"); 52386 if (removeButton) { 52387 event.preventDefault(); 52388 this.#setNoIcon(); 52389 this.#closeIconPopover(); 52390 return; 52391 } 52392 const randomIconButton = event.target.closest("[data-callout-random-icon]"); 52393 if (randomIconButton) { 52394 event.preventDefault(); 52395 this.#setRandomSymbolIcon(); 52396 return; 52397 } 52398 const symbolButton = event.target.closest("[data-callout-symbol]"); 52399 if (symbolButton) { 52400 event.preventDefault(); 52401 this.#setSymbolIcon(symbolButton.dataset.calloutSymbol, symbolButton.dataset.calloutSymbolSvg); 52402 this.#closeIconPopover(); 52403 return; 52404 } 52405 const swatch = event.target.closest("[data-variant][data-color-target]"); 52406 if (swatch) { 52407 event.preventDefault(); 52408 this.#setColor(swatch.dataset.colorTarget, Number(swatch.dataset.variant)); 52409 return; 52410 } 52411 const uploadButton = event.target.closest("[data-callout-upload]"); 52412 if (uploadButton) { 52413 event.preventDefault(); 52414 this.#fileInput.click(); 52415 return; 52416 } 52417 } 52418 #handleInput(event) { 52419 if (event.target.matches("[data-icon-search]")) { 52420 this.#visibleIconCount = ICON_GRID_BATCH_SIZE; 52421 this.#resetIconKeyboardNavigation(); 52422 this.#renderIconGrid(); 52423 } else if (event.target.matches("[data-upload-url]")) { 52424 this.#stageUploadInputUrl(event.target.value); 52425 } 52426 } 52427 #readActiveCalloutState() { 52428 let state = null; 52429 this.editor.getEditorState().read(() => { 52430 const callout = $getToolbarCallout(this.#activeCalloutKey); 52431 if (callout) { 52432 state = { 52433 iconType: callout.getIconType(), 52434 iconSrc: callout.getIconSrc() 52435 }; 52436 } 52437 }); 52438 return state; 52439 } 52440 #iconTabForIconType(iconType) { 52441 if (iconType === "symbol") return "icons"; 52442 if (iconType === "image") return "upload"; 52443 return "emoji"; 52444 } 52445 #syncUploadPanelFromCalloutState(calloutState) { 52446 const imageUrl = calloutState?.iconType === "image" ? safeImageUrl(calloutState.iconSrc) : null; 52447 if (imageUrl) { 52448 const uploadUrlInput = this.#popoverQuery("[data-upload-url]"); 52449 if (uploadUrlInput) uploadUrlInput.value = imageUrl; 52450 this.#stageUploadUrl(imageUrl); 52451 return; 52452 } 52453 this.#resetUploadPanel(); 52454 } 52455 #bindInlineIconTriggerEvents() { 52456 if (!this.editorElement) return; 52457 this.#inlineIconMouseDownHandler = (event) => { 52458 if (!event.target.closest("[data-callout-inline-icon-toggle]")) return; 52459 event.preventDefault(); 52460 }; 52461 this.#inlineIconClickHandler = (event) => { 52462 const trigger = event.target.closest("[data-callout-inline-icon-toggle]"); 52463 if (!trigger) return; 52464 event.preventDefault(); 52465 event.stopPropagation(); 52466 this.editor.update( 52467 () => { 52468 const node = $getNearestNodeFromDOMNode3(trigger); 52469 const callout = $findMatchingParent3(node, $isCalloutNode); 52470 callout?.selectStart(); 52471 }, 52472 { onUpdate: () => this.#openIconPopover() } 52473 ); 52474 }; 52475 this.editorElement.addEventListener("mousedown", this.#inlineIconMouseDownHandler); 52476 this.editorElement.addEventListener("click", this.#inlineIconClickHandler); 52477 } 52478 #unbindInlineIconTriggerEvents() { 52479 if (!this.editorElement) return; 52480 if (this.#inlineIconMouseDownHandler) { 52481 this.editorElement.removeEventListener("mousedown", this.#inlineIconMouseDownHandler); 52482 this.#inlineIconMouseDownHandler = null; 52483 } 52484 if (this.#inlineIconClickHandler) { 52485 this.editorElement.removeEventListener("click", this.#inlineIconClickHandler); 52486 this.#inlineIconClickHandler = null; 52487 } 52488 } 52489 #bindEditorFocusEvents() { 52490 if (!this.editorElement) return; 52491 this.#editorFocusOutHandler = (event) => { 52492 if (this.#iconPopoverOpen()) return; 52493 const relatedTarget = event.relatedTarget; 52494 if (relatedTarget instanceof Node) { 52495 const stayingInToolbar = this.contains(relatedTarget) || this.#iconPopover?.contains(relatedTarget); 52496 if (stayingInToolbar) return; 52497 } 52498 this.#activeCalloutKey = null; 52499 this.#hide(); 52500 }; 52501 this.editorElement.addEventListener("focusout", this.#editorFocusOutHandler); 52502 } 52503 #unbindEditorFocusEvents() { 52504 if (!this.editorElement || !this.#editorFocusOutHandler) return; 52505 this.editorElement.removeEventListener("focusout", this.#editorFocusOutHandler); 52506 this.#editorFocusOutHandler = null; 52507 } 52508 #openIconPopover() { 52509 if (this.#iconPopoverOpen()) return; 52510 this.#toggleIconPopover(); 52511 } 52512 #toggleIconPopover() { 52513 const popover = this.#iconPopover; 52514 const toggle = this.#iconPopoverToggle(); 52515 if (!popover || !toggle) return; 52516 const willOpen = popover.hidden || popover.classList.contains("hidden"); 52517 if (willOpen) { 52518 const calloutState = this.#readActiveCalloutState(); 52519 this.#setIconTab(this.#iconTabForIconType(calloutState?.iconType)); 52520 popover.hidden = false;
52521 popover.classList.remove("hidden"); 52522 toggle.setAttribute("aria-expanded", "true"); 52523 this.#showIconPopoverLayer(); 52524 this.#startPopoverPositioning(); 52525 requestAnimationFrame(() => this.#addGlobalListeners()); 52526 this.#afterPopoverPaint(() => { 52527 if (this.#activeIconTab === "emoji") this.#ensureEmojiPicker(); 52528 }); 52529 } else { 52530 this.#closeIconPopover(); 52531 } 52532 } 52533 #setIconTab(tab) { 52534 this.#activeIconTab = tab; 52535 this.#popoverQueryAll("[data-icon-tab]").forEach((button) => { 52536 const isActive = button.dataset.iconTab === tab; 52537 button.setAttribute("aria-selected", String(isActive)); 52538 }); 52539 this.#popoverQueryAll("[data-icon-tab-panel]").forEach((panel) => { 52540 panel.classList.toggle("hidden", panel.dataset.iconTabPanel !== tab); 52541 }); 52542 if (tab === "emoji") { 52543 this.#afterPopoverPaint(() => { 52544 this.#ensureEmojiPicker(); 52545 this.#focusEmojiSearch(); 52546 }); 52547 } else if (tab === "icons") { 52548 this.#resetIconKeyboardNavigation(); 52549 this.#ensureIconGrid(); 52550 requestAnimationFrame(() => this.#popoverQuery("[data-icon-search]")?.focus()); 52551 } else if (tab === "upload") { 52552 this.#syncUploadPanelFromCalloutState(this.#readActiveCalloutState()); 52553 } 52554 } 52555 #afterPopoverPaint(callback) { 52556 requestAnimationFrame(() => requestAnimationFrame(callback)); 52557 } 52558 #closeIconPopover() { 52559 const popover = this.#iconPopover; 52560 const toggle = this.#iconPopoverToggle(); 52561 this.#stopPopoverPositioning(); 52562 if (popover) popover.hidden = true; 52563 popover?.classList.add("hidden"); 52564 toggle?.setAttribute("aria-expanded", "false"); 52565 this.#resetIconKeyboardNavigation(); 52566 this.#removeGlobalListeners(); 52567 } 52568 #iconPopoverOpen() { 52569 const popover = this.#iconPopover; 52570 return Boolean(popover && !popover.hidden && !popover.classList.contains("hidden")); 52571 } 52572 #ensureEmojiPicker() { 52573 if (this.#emojiPicker) { 52574 this.#afterPopoverPaint(() => this.#highlightSelectedEmoji()); 52575 return; 52576 } 52577 const container = this.#popoverQuery("[data-emoji-picker-container]"); 52578 if (!container) return; 52579 this.#emojiPicker = createCalloutEmojiPicker(container, { 52580 onSelect: (emoji) => { 52581 this.#afterPopoverPaint(() => { 52582 this.#setEmojiIcon(emoji.native); 52583 this.#closeIconPopover(); 52584 }); 52585 } 52586 }); 52587 this.#watchEmojiPicker(); 52588 this.#afterPopoverPaint(() => { 52589 this.#highlightSelectedEmoji(); 52590 this.#focusEmojiSearch(); 52591 }); 52592 } 52593 #focusEmojiSearch(attempts = 4) { 52594 if (this.#activeIconTab !== "emoji") return; 52595 const root = this.#popoverQuery("em-emoji-picker")?.shadowRoot; 52596 const searchInput = root?.querySelector( 52597 'input[type="search"], input[placeholder*="Search" i], input[aria-label*="Search" i], input' 52598 ); 52599 if (searchInput instanceof HTMLElement) { 52600 searchInput.focus({ preventScroll: true }); 52601 return; 52602 } 52603 if (attempts > 0) this.#afterPopoverPaint(() => this.#focusEmojiSearch(attempts - 1)); 52604 } 52605 #watchEmojiPicker() { 52606 this.#emojiPickerObserver?.disconnect(); 52607 this.#emojiPickerObserver = null; 52608 const picker = this.#popoverQuery("em-emoji-picker"); 52609 const root = picker?.shadowRoot; 52610 if (!root) { 52611 this.#afterPopoverPaint(() => this.#watchEmojiPicker()); 52612 return; 52613 } 52614 this.#ensureEmojiPickerStyles(root); 52615 this.#emojiPickerObserver = new MutationObserver(() => this.#highlightSelectedEmoji()); 52616 this.#emojiPickerObserver.observe(root, { childList: true, subtree: true }); 52617 } 52618 #ensureEmojiPickerStyles(root) { 52619 applyCalloutEmojiPickerStyles(root); 52620 } 52621 #highlightSelectedEmoji() { 52622 const root = this.#popoverQuery("em-emoji-picker")?.shadowRoot; 52623 if (!root) return; 52624 root.querySelectorAll("[data-callout-selected-emoji]").forEach((button) => { 52625 if (button.getAttribute("aria-label") === this.#selectedEmoji) return; 52626 button.removeAttribute("data-callout-selected-emoji"); 52627 if (button.getAttribute("aria-current") === "true") button.removeAttribute("aria-current"); 52628 }); 52629 if (!this.#selectedEmoji) return; 52630 root.querySelectorAll("button[aria-label]").forEach((button) => { 52631 if (button.getAttribute("aria-label") !== this.#selectedEmoji) return; 52632 if (button.dataset.calloutSelectedEmoji === "true" && button.getAttribute("aria-current") === "true") return; 52633 button.dataset.calloutSelectedEmoji = "true"; 52634 button.setAttribute("aria-current", "true"); 52635 }); 52636 } 52637 #ensureIconGrid() { 52638 if (this.#lucideIcons) { 52639 this.#visibleIconCount = ICON_GRID_BATCH_SIZE; 52640 this.#renderIconGrid(); 52641 return; 52642 } 52643 this.#setIconStatus("Loading icons..."); 52644 loadLucideCalloutIcons().then((icons) => { 52645 this.#lucideIcons = icons; 52646 this.#renderIconGrid(); 52647 }).catch((error) => { 52648 console.error(error); 52649 this.#setIconStatus("Could not load icons."); 52650 }); 52651 } 52652 #renderIconGrid() { 52653 const grid = this.#popoverQuery("[data-icon-grid]"); 52654 const status = this.#popoverQuery("[data-icon-status]"); 52655 const query = this.#popoverQuery("[data-icon-search]")?.value || ""; 52656 if (!grid || !status || !this.#lucideIcons) return; 52657 if (query !== this.#iconSearchQuery) { 52658 this.#iconSearchQuery = query; 52659 this.#visibleIconCount = ICON_GRID_BATCH_SIZE; 52660 } 52661 const icons = this.#lucideIcons.search(query, this.#visibleIconCount + 1); 52662 const visibleIcons = icons.slice(0, this.#visibleIconCount); 52663 const hasMoreIcons = icons.length > visibleIcons.length;
52664 this.#setIconStatus(icons.length ? "" : "No icons found."); 52665 grid.dataset.hasMoreIcons = String(hasMoreIcons); 52666 grid.innerHTML = visibleIcons.map( 52667 ({ id: id3, label, svg: svg2 }) => ` 52668 <button 52669 type="button" 52670 class="lexxy-callout-tools__icon-button" 52671 data-callout-symbol="${escapeHtml(id3)}" 52672 data-callout-symbol-svg="${escapeHtml(svg2)}" 52673 ${this.#selectedSymbol === id3 ? 'aria-selected="true"' : ""} 52674 title="${escapeHtml(label)}" 52675 aria-label="${escapeHtml(label)}" 52676 >${svg2}</button> 52677 ` 52678 ).join(""); 52679 this.#updateIconKeyboardHighlight(); 52680 } 52681 #iconButtons() { 52682 return Array.from(this.#popoverQuery("[data-icon-grid]")?.querySelectorAll("[data-callout-symbol]") || []); 52683 } 52684 #iconGridColumns() { 52685 const grid = this.#popoverQuery("[data-icon-grid]"); 52686 if (!grid) return ICON_GRID_COLUMNS; 52687 const template = getComputedStyle(grid).gridTemplateColumns; 52688 if (!template || template === "none") return ICON_GRID_COLUMNS; 52689 return template.split(" ").length || ICON_GRID_COLUMNS; 52690 } 52691 #resetIconKeyboardNavigation() { 52692 this.#iconKeyboardIndex = -1; 52693 this.#iconSearchNavigated = false; 52694 this.#setIconGridKeyboardNav(false); 52695 this.#updateIconKeyboardHighlight(); 52696 } 52697 #setIconGridKeyboardNav(active) { 52698 const grid = this.#popoverQuery("[data-icon-grid]"); 52699 if (!grid) return; 52700 grid.toggleAttribute("data-keyboard-nav", active); 52701 if (active) this.#clearStuckIconHover(grid); 52702 } 52703 #clearStuckIconHover(grid) { 52704 grid.style.pointerEvents = "none"; 52705 requestAnimationFrame(() => { 52706 grid.style.pointerEvents = ""; 52707 }); 52708 } 52709 #highlightedIconButton() { 52710 if (!this.#iconSearchNavigated || this.#iconKeyboardIndex < 0) return null; 52711 return this.#iconButtons()[this.#iconKeyboardIndex] || null; 52712 } 52713 #updateIconKeyboardHighlight() { 52714 this.#iconButtons().forEach((button, index) => { 52715 const isHighlighted = this.#iconSearchNavigated && index === this.#iconKeyboardIndex; 52716 button.toggleAttribute("data-highlighted", isHighlighted); 52717 }); 52718 } 52719 #moveIconKeyboardHighlight(direction) { 52720 const buttons = this.#iconButtons(); 52721 if (!buttons.length) return; 52722 const columns = this.#iconGridColumns(); 52723 let index = this.#iconKeyboardIndex; 52724 if (!this.#iconSearchNavigated || index < 0) { 52725 index = direction === "down" || direction === "right" ? 0 : buttons.length - 1; 52726 this.#iconSearchNavigated = true; 52727 this.#setIconGridKeyboardNav(true); 52728 } else { 52729 switch (direction) { 52730 case "down": 52731 index = Math.min(index + columns, buttons.length - 1); 52732 break; 52733 case "up": 52734 index = Math.max(index - columns, 0); 52735 break; 52736 case "right": 52737 index = Math.min(index + 1, buttons.length - 1); 52738 break; 52739 case "left": 52740 index = Math.max(index - 1, 0); 52741 break; 52742 } 52743 } 52744 const grid = this.#popoverQuery("[data-icon-grid]"); 52745 if (index >= buttons.length - columns && grid?.dataset.hasMoreIcons === "true") { 52746 this.#visibleIconCount += ICON_GRID_BATCH_SIZE; 52747 this.#renderIconGrid(); 52748 index = Math.min(index, this.#iconButtons().length - 1); 52749 } 52750 this.#iconKeyboardIndex = index; 52751 this.#updateIconKeyboardHighlight(); 52752 this.#scrollToOption(this.#iconButtons()[index], grid); 52753 } 52754 #handleIconGridPointerOver(event) { 52755 if (this.#activeIconTab !== "icons" || !this.#iconSearchNavigated) return; 52756 const button = event.target.closest("[data-callout-symbol]"); 52757 if (!button) return; 52758 const index = this.#iconButtons().indexOf(button); 52759 if (index < 0 || index === this.#iconKeyboardIndex) return; 52760 this.#iconKeyboardIndex = index; 52761 this.#updateIconKeyboardHighlight(); 52762 } 52763 #shouldNavigateIconGrid(event, direction) { 52764 if (this.#iconSearchNavigated) return true; 52765 const input = event.target; 52766 const start3 = input.selectionStart; 52767 const end = input.selectionEnd; 52768 if (start3 === null || end === null) return true; 52769 if (direction === "down" || direction === "up") return true; 52770 if (direction === "left") return start3 === 0 && end === 0; 52771 if (direction === "right") return start3 === input.value.length && end === input.value.length; 52772 return false;
52773 } 52774 #handleIconSearchKeydown(event) { 52775 if (!event.target.matches("[data-icon-search]")) return; 52776 if (this.#activeIconTab !== "icons") return; 52777 const buttons = this.#iconButtons(); 52778 if (!buttons.length) return; 52779 if (event.key === "Enter") { 52780 const highlighted = this.#highlightedIconButton(); 52781 if (!highlighted) return; 52782 event.preventDefault(); 52783 this.#setSymbolIcon(highlighted.dataset.calloutSymbol, highlighted.dataset.calloutSymbolSvg); 52784 this.#closeIconPopover(); 52785 return; 52786 } 52787 const direction = { 52788 ArrowDown: "down", 52789 ArrowUp: "up", 52790 ArrowLeft: "left", 52791 ArrowRight: "right" 52792 }[event.key]; 52793 if (!direction) return; 52794 if (!this.#shouldNavigateIconGrid(event, direction)) return; 52795 event.preventDefault(); 52796 event.stopPropagation(); 52797 const searchInput = event.target; 52798 const selectionStart = searchInput.selectionStart; 52799 const selectionEnd = searchInput.selectionEnd; 52800 this.#moveIconKeyboardHighlight(direction); 52801 requestAnimationFrame(() => { 52802 searchInput.focus({ preventScroll: true }); 52803 if (selectionStart === null || selectionEnd === null) return; 52804 searchInput.setSelectionRange(selectionStart, selectionEnd); 52805 }); 52806 } 52807 #handleIconGridScroll(event) { 52808 const grid = event.target; 52809 if (!grid?.matches?.("[data-icon-grid]") || grid.dataset.hasMoreIcons !== "true") return; 52810 const remainingScroll = grid.scrollHeight - grid.scrollTop - grid.clientHeight; 52811 if (remainingScroll > 80) return; 52812 this.#visibleIconCount += ICON_GRID_BATCH_SIZE; 52813 this.#renderIconGrid(); 52814 } 52815 #scrollToOption(optionEl, content = this.#popoverQuery("[data-icon-grid]")) { 52816 if (!optionEl || !content) return; 52817 const contentRect = content.getBoundingClientRect(); 52818 const optionRect = optionEl.getBoundingClientRect(); 52819 const optionRelativeTop = optionRect.top - contentRect.top; 52820 const optionRelativeBottom = optionRelativeTop + optionRect.height; 52821 const contentScrollTop = content.scrollTop; 52822 const contentHeight = contentRect.height; 52823 const scrollPadding = optionRect.height + 6; 52824 if (optionRelativeBottom > contentHeight - scrollPadding) { 52825 content.scrollTop = contentScrollTop + (optionRelativeBottom - contentHeight + scrollPadding); 52826 } else if (optionRelativeTop < scrollPadding) { 52827 content.scrollTop = contentScrollTop + (optionRelativeTop - scrollPadding); 52828 } 52829 } 52830 #setIconStatus(message) { 52831 const status = this.#popoverQuery("[data-icon-status]"); 52832 if (!status) return; 52833 status.textContent = message; 52834 status.hidden = !message; 52835 } 52836 #setRandomSymbolIcon() { 52837 if (!this.#lucideIcons) return; 52838 const query = this.#popoverQuery("[data-icon-search]")?.value || ""; 52839 const icons = this.#lucideIcons.search(query, Number.MAX_SAFE_INTEGER); 52840 const icon = icons[Math.floor(Math.random() * icons.length)]; 52841 if (!icon) return; 52842 this.#setSymbolIcon(icon.id, icon.svg); 52843 this.#closeIconPopover(); 52844 } 52845 #addGlobalListeners() { 52846 if (this.#outsideClickHandler) return; 52847 this.#outsideClickHandler = (event) => { 52848 const popover = this.#iconPopover; 52849 const toggle = this.#iconPopoverToggle(); 52850 if (!popover || popover.classList.contains("hidden")) return; 52851 const path = event.composedPath?.() || [event.target]; 52852 const clickedInside = path.some((node) => { 52853 if (!(node instanceof Node)) return false; 52854 return popover.contains(node) || toggle?.contains(node) || this.contains(node); 52855 }); 52856 if (clickedInside) return; 52857 const clickedCalloutElement = this.#clickedEditorCalloutElement(path); 52858 this.#closeIconPopover(); 52859 if (clickedCalloutElement) { 52860 this.#scheduleToolbarSyncForCalloutElement(clickedCalloutElement); 52861 } else { 52862 this.#activeCalloutKey = null; 52863 this.#hide(); 52864 } 52865 }; 52866 this.#escapeHandler = (event) => { 52867 if (event.key === "Escape") this.#closeIconPopover(); 52868 }; 52869 this.#pasteHandler = (event) => this.#handleUploadPaste(event); 52870 document.addEventListener("mousedown", this.#outsideClickHandler, true); 52871 document.addEventListener("keydown", this.#escapeHandler); 52872 document.addEventListener("paste", this.#pasteHandler); 52873 } 52874 #removeGlobalListeners() { 52875 if (this.#outsideClickHandler) { 52876 document.removeEventListener("mousedown", this.#outsideClickHandler, true); 52877 this.#outsideClickHandler = null; 52878 } 52879 if (this.#escapeHandler) { 52880 document.removeEventListener("keydown", this.#escapeHandler); 52881 this.#escapeHandler = null; 52882 } 52883 if (this.#pasteHandler) { 52884 document.removeEventListener("paste", this.#pasteHandler); 52885 this.#pasteHandler = null; 52886 } 52887 } 52888 #handleFileSelected(event) { 52889 const file = event.target.files?.[0]; 52890 event.target.value = ""; 52891 if (file) this.#stageUploadFile(file); 52892 } 52893 #handleUploadPaste(event) { 52894 if (this.#activeIconTab !== "upload") return; 52895 const file = Array.from(event.clipboardData?.files || []).find((item) => item.type.startsWith("image/")); 52896 if (file) { 52897 event.preventDefault(); 52898 this.#stageUploadFile(file); 52899 return; 52900 } 52901 const text2 = event.clipboardData?.getData("text/plain")?.trim(); 52902 if (!text2 || event.target?.matches?.("[data-upload-url]")) return; 52903 const url = safeImageUrl(text2); 52904 event.preventDefault(); 52905 if (url) { 52906 this.#validateAndStageUploadUrl(url); 52907 } else {
52908 this.#rejectUploadUrl(); 52909 } 52910 } 52911 async #pasteUploadFromClipboard() { 52912 if (!navigator.clipboard) { 52913 this.#setUploadStatus("Clipboard access is not available in this browser."); 52914 return; 52915 } 52916 try { 52917 if (navigator.clipboard.read) { 52918 const items = await navigator.clipboard.read(); 52919 for (const item of items) { 52920 const imageType = item.types.find((type) => type.startsWith("image/")); 52921 if (!imageType) continue; 52922 const blob = await item.getType(imageType); 52923 const extension = imageType.split("/")[1] || "png"; 52924 this.#stageUploadFile(new File([blob], `clipboard-image.${extension}`, { type: imageType })); 52925 return; 52926 } 52927 } 52928 const text2 = await navigator.clipboard.readText(); 52929 const url = safeImageUrl(text2.trim()); 52930 if (url) { 52931 this.#validateAndStageUploadUrl(url); 52932 } else { 52933 this.#rejectUploadUrl("Clipboard does not contain an image or image URL."); 52934 } 52935 } catch (error) { 52936 console.error(error); 52937 this.#setUploadStatus("Allow clipboard access to paste an image."); 52938 } 52939 } 52940 #handleUploadDrag(event) { 52941 if (this.#activeIconTab !== "upload") return; 52942 if (!event.dataTransfer?.types?.includes("Files")) return; 52943 event.preventDefault(); 52944 this.#popoverQuery("[data-callout-upload]")?.classList.add("is-dragging"); 52945 } 52946 #handleUploadDragLeave(event) { 52947 if (!event.target.closest("[data-callout-upload]")) return; 52948 this.#popoverQuery("[data-callout-upload]")?.classList.remove("is-dragging"); 52949 } 52950 #handleUploadDrop(event) { 52951 if (this.#activeIconTab !== "upload") return; 52952 const file = Array.from(event.dataTransfer?.files || []).find((item) => item.type.startsWith("image/")); 52953 if (!file) return; 52954 event.preventDefault(); 52955 this.#popoverQuery("[data-callout-upload]")?.classList.remove("is-dragging"); 52956 this.#stageUploadFile(file); 52957 } 52958 #stageUploadFile(file) { 52959 if (!isCalloutIconFile(file)) { 52960 this.#setUploadStatus("Choose a PNG, JPG, WEBP, or GIF under 1MB."); 52961 return; 52962 } 52963 this.#uploadUrlValidationId += 1; 52964 this.#revokeUploadPreview(); 52965 this.#uploadFile = file; 52966 this.#uploadUrl = null; 52967 this.#uploadPreviewObjectUrl = URL.createObjectURL(file); 52968 this.#renderUploadPreview(this.#uploadPreviewObjectUrl, file.name); 52969 this.#setUploadStatus(""); 52970 } 52971 #stageUploadUrl(url) { 52972 this.#revokeUploadPreview(); 52973 this.#uploadFile = null; 52974 this.#uploadUrl = url; 52975 this.#renderUploadPreview(url, "Image preview"); 52976 this.#setUploadStatus(""); 52977 } 52978 #stageUploadInputUrl(value) { 52979 this.#uploadUrlValidationId += 1; 52980 const url = safeImageUrl(value.trim()); 52981 if (url) { 52982 this.#validateAndStageUploadUrl(url); 52983 } else if (!value.trim() && this.#uploadUrl) { 52984 this.#resetUploadPanel(); 52985 } else if (value.trim()) { 52986 this.#rejectUploadUrl(); 52987 } else { 52988 this.#setUploadStatus(""); 52989 } 52990 } 52991 #validateAndStageUploadUrl(url) { 52992 const validationId = ++this.#uploadUrlValidationId; 52993 this.#clearUploadSelection(); 52994 this.#setUploadStatus("Checking image..."); 52995 this.#loadUploadPreview(url).then((loaded) => { 52996 if (validationId !== this.#uploadUrlValidationId) return; 52997 if (loaded) { 52998 this.#stageUploadUrl(url); 52999 } else { 53000 this.#rejectUploadUrl("Use a direct image URL that can be previewed."); 53001 } 53002 }); 53003 } 53004 #loadUploadPreview(url) { 53005 return new Promise((resolve) => { 53006 const image = new Image(); 53007 let settled = false; 53008 const finish = (loaded) => { 53009 if (settled) return; 53010 settled = true; 53011 resolve(loaded); 53012 }; 53013 image.onload = () => finish(image.naturalWidth > 0 && image.naturalHeight > 0); 53014 image.onerror = () => finish(false); 53015 image.src = url; 53016 setTimeout(() => finish(false), 5e3); 53017 }); 53018 } 53019 #rejectUploadUrl(message = "Use a direct image URL or paste an image file.") { 53020 this.#uploadUrlValidationId += 1; 53021 this.#clearUploadSelection(); 53022 this.#setUploadStatus(message); 53023 } 53024 #renderUploadPreview(src, label) { 53025 const empty = this.#popoverQuery("[data-upload-empty]"); 53026 const preview = this.#popoverQuery("[data-upload-preview]"); 53027 const saveButton = this.#popoverQuery("[data-upload-save]"); 53028 if (!empty || !preview || !saveButton) return; 53029 empty.classList.add("hidden"); 53030 preview.classList.remove("hidden"); 53031 preview.innerHTML = ` 53032 <img src="${escapeHtml(src)}" alt="">
53033 <span>${escapeHtml(label)}</span> 53034 `; 53035 saveButton.disabled = false; 53036 } 53037 #resetUploadPanel() { 53038 this.#uploadUrlValidationId += 1; 53039 this.#clearUploadSelection(); 53040 const uploadUrlInput = this.#popoverQuery("[data-upload-url]"); 53041 if (uploadUrlInput) uploadUrlInput.value = ""; 53042 this.#setUploadStatus(""); 53043 } 53044 #clearUploadSelection() { 53045 this.#uploadFile = null; 53046 this.#uploadUrl = null; 53047 this.#uploadSaving = false; 53048 this.#revokeUploadPreview(); 53049 const empty = this.#popoverQuery("[data-upload-empty]"); 53050 const preview = this.#popoverQuery("[data-upload-preview]"); 53051 const saveButton = this.#popoverQuery("[data-upload-save]"); 53052 const uploadButton = this.#popoverQuery("[data-callout-upload]"); 53053 empty?.classList.remove("hidden"); 53054 preview?.classList.add("hidden"); 53055 preview?.replaceChildren(); 53056 uploadButton?.classList.remove("is-dragging"); 53057 if (saveButton) saveButton.disabled = true; 53058 } 53059 #revokeUploadPreview() { 53060 if (this.#uploadPreviewObjectUrl) { 53061 URL.revokeObjectURL(this.#uploadPreviewObjectUrl); 53062 this.#uploadPreviewObjectUrl = null; 53063 } 53064 } 53065 #setUploadStatus(message) { 53066 const status = this.#popoverQuery("[data-upload-status]"); 53067 if (!status) return; 53068 status.textContent = message; 53069 status.hidden = !message; 53070 } 53071 async #saveUploadSelection() { 53072 if (this.#uploadSaving || !this.#uploadFile && !this.#uploadUrl) return; 53073 this.#uploadSaving = true; 53074 const saveButton = this.#popoverQuery("[data-upload-save]"); 53075 if (saveButton) { 53076 saveButton.disabled = true; 53077 saveButton.textContent = "Saving..."; 53078 } 53079 this.#setUploadStatus(""); 53080 try { 53081 const imageUrl = this.#uploadFile ? await uploadCalloutIcon(this.editorElement, this.#uploadFile) : this.#uploadUrl; 53082 this.#setImageIcon(imageUrl); 53083 this.#resetUploadPanel(); 53084 this.#closeIconPopover(); 53085 } catch (error) { 53086 console.error(error); 53087 this.#setUploadStatus(error.message || "Could not save the image."); 53088 if (saveButton) saveButton.disabled = false; 53089 } finally { 53090 this.#uploadSaving = false; 53091 if (saveButton) saveButton.textContent = "Save"; 53092 } 53093 } 53094 #setEmojiIcon(emoji) { 53095 this.editor.update(() => { 53096 const callout = $getToolbarCallout(this.#activeCalloutKey); 53097 callout?.setIconType("emoji").setIcon(emoji).setIconSrc(null); 53098 }); 53099 this.editor.focus(); 53100 } 53101 #setSymbolIcon(iconId, svg2 = null) { 53102 this.editor.update(() => { 53103 const callout = $getToolbarCallout(this.#activeCalloutKey); 53104 callout?.setIconType("symbol").setIcon(iconId).setIconSrc(svg2); 53105 }); 53106 this.editor.focus(); 53107 } 53108 #setImageIcon(url) { 53109 this.editor.update(() => { 53110 const callout = $getToolbarCallout(this.#activeCalloutKey); 53111 callout?.setIconType("image").setIconSrc(url); 53112 }); 53113 this.editor.focus(); 53114 } 53115 #setNoIcon() { 53116 this.editor.update(() => { 53117 const callout = $getToolbarCallout(this.#activeCalloutKey); 53118 callout?.setIconType("none").setIcon("").setIconSrc(null); 53119 }); 53120 this.editor.focus(); 53121 } 53122 #deleteCallout() { 53123 const targetKey = this.#activeCalloutKey; 53124 this.editor.update(() => { 53125 const callout = $getToolbarCallout(targetKey); 53126 if (!callout) return; 53127 const nextSibling = callout.getNextSibling(); 53128 const previousSibling = callout.getPreviousSibling(); 53129 callout.remove(); 53130 if ($isElementNode5(nextSibling)) { 53131 nextSibling.selectStart(); 53132 } else if ($isElementNode5(previousSibling)) { 53133 previousSibling.selectEnd(); 53134 } 53135 }); 53136 this.#activeCalloutKey = null; 53137 this.#hide(); 53138 this.editor.focus(); 53139 } 53140 #setColor(target, variant) { 53141 this.editor.update(() => { 53142 const callout = $getToolbarCallout(this.#activeCalloutKey); 53143 if (!callout) return; 53144 if (target === "border") { 53145 callout.setBorderVariant(variant); 53146 } else { 53147 callout.setBgVariant(variant); 53148 } 53149 }); 53150 this.editor.focus(); 53151 } 53152 #monitorSelection() { 53153 this.#updateListener = this.editor.registerUpdateListener(({ editorState }) => { 53154 editorState.read(() => { 53155 const callout = $getCalloutInSelection(); 53156 if (callout) { 53157 this.#syncUI(callout); 53158 this.#show(callout); 53159 } else if (this.#iconPopoverOpen()) { 53160 return; 53161 } else { 53162 this.#activeCalloutKey = null; 53163 this.#hide(); 53164 } 53165 }); 53166 }); 53167 } 53168 #syncUI(callout) { 53169 this.#activeCalloutKey = callout.getKey(); 53170 const preview = this.querySelector("[data-callout-icon-preview]"); 53171 if (preview) { 53172 this.#syncIconPreview(preview, callout); 53173 } 53174 this.querySelectorAll("[data-color-target='border'][data-variant]").forEach((button) => { 53175 const isSelected = Number(button.dataset.variant) === callout.getBorderVariant(); 53176 if (isSelected) { 53177 button.setAttribute("aria-selected", "true"); 53178 } else { 53179 button.removeAttribute("aria-selected"); 53180 } 53181 }); 53182 this.querySelectorAll("[data-color-target='background'][data-variant]").forEach((button) => { 53183 const isSelected = Number(button.dataset.variant) === callout.getBgVariant(); 53184 if (isSelected) { 53185 button.setAttribute("aria-selected", "true"); 53186 } else { 53187 button.removeAttribute("aria-selected"); 53188 } 53189 }); 53190 this.#popoverQueryAll("[data-callout-symbol]").forEach((button) => { 53191 button.toggleAttribute( 53192 "aria-selected", 53193 callout.getIconType() === "symbol" && button.dataset.calloutSymbol === callout.getIcon() 53194 ); 53195 }); 53196 this.#selectedSymbol = callout.getIconType() === "symbol" ? callout.getIcon() : null; 53197 this.#selectedEmoji = callout.getIconType() === "emoji" ? callout.getIcon() : null; 53198 this.#activeIconTab = this.#iconTabForIconType(callout.getIconType()); 53199 this.#highlightSelectedEmoji(); 53200 } 53201 #syncIconPreview(preview, callout) { 53202 preview.replaceChildren(); 53203 if (callout.getIconType() === "none") { 53204 preview.innerHTML = `<span class="lexxy-callout-tools__icon-none lexxy-callout-tools__icon-empty" aria-hidden="true">-</span>`;
53205 } else if (callout.getIconType() === "image" && callout.getIconSrc()) { 53206 const image = document.createElement("img"); 53207 image.src = callout.getIconSrc(); 53208 image.alt = ""; 53209 image.className = "lexxy-callout-tools__icon-image"; 53210 preview.append(image); 53211 } else if (callout.getIconType() === "symbol") { 53212 const svg2 = sanitizedSvgElement(callout.getIconSrc()) || sanitizedSvgElement(calloutIconById(callout.getIcon())?.svg); 53213 if (svg2) { 53214 preview.append(svg2); 53215 } else { 53216 preview.innerHTML = `<span class="lexxy-callout-tools__icon-none lexxy-callout-tools__icon-empty">-</span>`; 53217 } 53218 } else { 53219 preview.textContent = callout.getIcon() || "\u{1F4A1}"; 53220 } 53221 } 53222 #show(callout) { 53223 const dom = this.editor.getElementByKey(callout.getKey()); 53224 if (!dom) return; 53225 const calloutRect = dom.getBoundingClientRect(); 53226 const editorRect = this.editorElement.getBoundingClientRect(); 53227 const relativeTop = calloutRect.top - editorRect.top; 53228 const relativeCenter = (calloutRect.left + calloutRect.right) / 2 - editorRect.left; 53229 this.style.display = "flex"; 53230 this.style.top = `${relativeTop}px`; 53231 this.style.left = `${relativeCenter}px`; 53232 } 53233 #hide() { 53234 this.style.display = "none"; 53235 this.#closeIconPopover(); 53236 } 53237 }; 53238 if (!customElements.get("lexxy-callout-tools")) { 53239 customElements.define("lexxy-callout-tools", CalloutToolsElement); 53240 } 53241 53242
53242// app/javascript/src/lexxy/toolbar_icons.js 53243 var ICONS2 = { 53244 audio: ` 53245 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53246 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53247 <path d="M5,5.75H2.25c-.828,0-1.5,.672-1.5,1.5v3.5c0,.828,.672,1.5,1.5,1.5h2.75l5.48,3.508c.333,.213,.77-.026,.77-.421V2.664c0-.395-.437-.634-.77-.421l-5.48,3.508Z"></path> 53248 <path d="M13.914,7.586c.781,.781,.781,2.047,0,2.828"></path> 53249 <path d="M15.859,5.641c1.855,1.855,1.855,4.863,0,6.718"></path> 53250 </g> 53251 </svg> 53252 `, 53253 attachment: ` 53254 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53255 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53256 <path d="M10.985,5.422l-4.773,4.773c-.586,.586-.586,1.536,0,2.121h0c.586,.586,1.536,.586,2.121,0l4.95-4.95c1.172-1.172,1.172-3.071,0-4.243h0c-1.172-1.172-3.071-1.172-4.243,0l-4.95,4.95c-1.757,1.757-1.757,4.607,0,6.364h0c1.757,1.757,4.607,1.757,6.364,0l4.773-4.773"></path> 53257 </g> 53258 </svg> 53259 `, 53260 bold: ` 53261 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53262 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53263 <path d="M6.75 2.25H10C11.795 2.25 13.25 3.71 13.25 5.5C13.25 7.29 11.795 8.75 10 8.75H6.75"></path> 53264 <path d="M6.75 8.75H10.75C12.683 8.75 14.25 10.3199 14.25 12.25C14.25 14.1801 12.683 15.75 10.75 15.75H6.75"></path> 53265 <path d="M6.75 15.75H4.75C4.198 15.75 3.75 15.3 3.75 14.75V3.25C3.75 2.7 4.198 2.25 4.75 2.25H6.75V15.75Z"></path> 53266 </g> 53267 </svg> 53268 `, 53269 bulletList: ` 53270 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53271 <g fill="currentColor"> 53272 <path d="M15.75,9.75h-7.5c-.414,0-.75-.336-.75-.75s.336-.75,.75-.75h7.5c.414,0,.75,.336,.75,.75s-.336,.75-.75,.75Z"></path> 53273 <path d="M15.75,4.5h-7.5c-.414,0-.75-.336-.75-.75s.336-.75,.75-.75h7.5c.414,0,.75,.336,.75,.75s-.336,.75-.75,.75Z"></path> 53274 <circle cx="3.75" cy="9" r="1.75"></circle> 53275 <circle cx="3.75" cy="3.75" r="1.75"></circle> 53276 <circle cx="3.75" cy="14.25" r="1.75"></circle> 53277 <path d="M15.75,15h-7.5c-.414,0-.75-.336-.75-.75s.336-.75,.75-.75h7.5c.414,0,.75,.336,.75,.75s-.336,.75-.75,.75Z"></path> 53278 </g> 53279 </svg> 53280 `, 53281 callout: ` 53282 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53283 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53284 <line x1="6.75" y1="13.25" x2="11.25" y2="13.25"></line> 53285 <path d="M14,6.75c0-3.113-2.846-5.562-6.078-4.887-1.932,.403-3.475,1.993-3.834,3.933-.434,2.344,.771,4.459,2.662,5.415v3.039c0,1.105,.895,2,2,2h.5c1.105,0,2-.895,2-2v-3.039c1.63-.824,2.7
532855-2.51,2.75-4.461Z"></path> 53286 </g> 53287 </svg> 53288 `, 53289 checklist: ` 53290 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53291 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53292 <line x1="10.25" y1="5.25" x2="16.25" y2="5.25"></line> 53293 <line x1="10.25" y1="12.75" x2="16.25" y2="12.75"></line> 53294 <polyline points="2.244 5.641 3.603 7 7 2.583"></polyline> 53295 <rect x="2.25" y="10.75" width="4.5" height="4.5" rx="1" ry="1"></rect> 53296 </g> 53297 </svg> 53298 `, 53299 toggleList: ` 53300 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53301 <g fill="currentColor"> 53302 <path d="M4.8 2.75a.55.55 0 0 1 .825-.476l2.1 1.45a.55.55 0 0 1 0 .952l-2.1 1.45A.55.55 0 0 1 4.8 5.65v-2.9Z"></path> 53303 <path d="M4.8 7.55a.55.55 0 0 1 .825-.476l2.1 1.45a.55.55 0 0 1 0 .952l-2.1 1.45A.55.55 0 0 1 4.8 10.45v-2.9Z"></path> 53304 <path d="M4.8 12.35a.55.55 0 0 1 .825-.476l2.1 1.45a.55.55 0 0 1 0 .952l-2.1 1.45a.55.55 0 0 1-.825-.476v-2.9Z"></path> 53305 <path d="M15.75 4.95h-5.5a.75.75 0 0 1 0-1.5h5.5a.75.75 0 0 1 0 1.5Z"></path> 53306 <path d="M15.75 9.75h-5.5a.75.75 0 0 1 0-1.5h5.5a.75.75 0 0 1 0 1.5Z"></path> 53307 <path d="M15.75 14.55h-5.5a.75.75 0 0 1 0-1.5h5.5a.75.75 0 0 1 0 1.5Z"></path> 53308 </g> 53309 </svg> 53310 `, 53311 clearFormatting: ` 53312 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53313 <g fill="currentColor"> 53314 <path d="M16,16h-7.374c-.414,0-.75-.336-.75-.75s.336-.75,.75-.75h7.374c.414,0,.75,.336,.75,.75s-.336,.75-.75,.75Z"></path> 53315 <path d="M16.056,5.691l-3.712-3.713c-.851-.85-2.333-.848-3.182,0L1.944,9.197c-.425,.425-.659,.99-.659,1.591s.234,1.167,.659,1.591l3.401,3.402c.141,.141,.331,.22,.53,.22h2.743c.199,0,.39-.079,.53-.22l6.906-6.907c.425-.425,.659-.99,.659-1.591s-.234-1.167-.659-1.591Zm-7.747,8.809h-2.122l-3.182-3.183c-.142-.141-.22-.33-.22-.53s.078-.389,.22-.53l3.078-3.078,4.773,4.773-2.548,2.548Z"></path> 53316 </g> 53317 </svg> 53318 `, 53319 code: ` 53320 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53321 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53322 <path d="M14 6.25L16.25 4L14 1.75"></path> 53323 <path d="M6.0225 2.75H4.75C3.645 2.75 2.75 3.646 2.75 4.75V13.25C2.75 14.354 3.645 15.25 4.75 15.25H13.25C14.355 15.25 15.25 14.354 15.25 13.25V8.97748"></path> 53324 <path d="M11 6.25L8.75 4L11 1.75"></path> 53325 </g> 53326 </svg> 53327 `, 53328 format: ` 53329 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53330 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53331 <path d="M6.75 2.75V15.25"></path> 53332 <path d="M11.75 2.75H1.75"></path> 53333 <path d="M13.25 7.75V15.25"></path> 53334 <path d="M16.25 7.75H10.25"></path> 53335 </g> 53336 </svg> 53337 `, 53338 heading1: ` 53339 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53340 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53341 <line x1="2.75" y1="4.75" x2="2.75" y2="13.25"></line> 53342 <line x1="8.75" y1="4.75" x2="8.75" y2="13.25"></line> 53343 <line x1="2.75" y1="9" x2="8.75" y2="9"></line> 53344 <path d="M14.75,13.25V4.75s-.974,1.713-3.04,2.108"></path> 53345 </g> 53346 </svg> 53347 `, 53348 heading2: ` 53349 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53350 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53351 <line x1="1.25" y1="4.75" x2="1.25" y2="13.25"></line> 53352 <line x1="7.25" y1="4.75" x2="7.25" y2="13.25"></line> 53353 <line x1="1.25" y1="9" x2="7.25" y2="9"></line> 53354 <path d="M10.5,6.931c.384-1.424,1.707-2.203,3.137-2.181,1.43,.022,2.774,.69,2.86,2.181s-1.43,2.492-2.998,3.16c-1.569,.668-2.87,1.291-2.998,3.16h6"></path> 53355 </g> 53356 </svg> 53357 `, 53358 heading3: `
53359 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53360 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53361 <line x1="1.75" y1="4.75" x2="1.75" y2="13.25"></line> 53362 <line x1="7.75" y1="4.75" x2="7.75" y2="13.25"></line> 53363 <line x1="1.75" y1="9" x2="7.75" y2="9"></line> 53364 <path d="M10.75,4.75h5.542l-4.005,3.462c1.322-.342,2.672-.141,3.505,.744,1.022,1.086,.868,2.597-.012,3.505s-3.515,1.436-5.029-.727"></path> 53365 </g> 53366 </svg> 53367 `, 53368 heading4: ` 53369 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53370 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53371 <line x1="1.75" y1="4.75" x2="1.75" y2="13.25"></line> 53372 <line x1="7.75" y1="4.75" x2="7.75" y2="13.25"></line> 53373 <line x1="1.75" y1="9" x2="7.75" y2="9"></line> 53374 <polyline points="16.691 10.75 10.25 10.75 10.25 10.641 15 4.75 15 13.25"></polyline> 53375 </g> 53376 </svg> 53377 `, 53378 highlight: ` 53379 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53380 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53381 <path d="m8.3034,16.217c-3.7776-.3601-6.7098-3.619-6.5469-7.5271.157-3.7659,3.3501-6.8755,7.1188-6.9388,4.0612-.0683,7.3747,3.2034,7.3747,7.2489h0c0,1.5188-1.2312,2.75-2.75,2.75h-2.963c-1.0336,0-1.6928,1.1036-1.2027,2.0137l.2374.4409c.2597.4823.2062,1.0732-.1361,1.501h0c-.2736.342-.6962.553-1.1322.5115Z"></path> 53382 <circle cx="9" cy="5" r="1" fill="currentColor" stroke-width="0"></circle> 53383 <circle cx="6.1716" cy="6.1716" r="1" fill="currentColor" stroke-width="0"></circle> 53384 <circle cx="11.8284" cy="6.1716" r="1" fill="currentColor" stroke-width="0"></circle> 53385 <circle cx="5" cy="9" r="1" fill="currentColor" stroke-width="0"></circle> 53386 </g> 53387 </svg> 53388 `, 53389 image: ` 53390 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53391 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53392 <path d="M3.762,14.989l6.074-6.075c.781-.781,2.047-.781,2.828,0l2.586,2.586"></path> 53393 <rect x="2.75" y="2.75" width="12.5" height="12.5" rx="2" ry="2"></rect> 53394 <circle cx="6.25" cy="7.25" r="1.25" fill="currentColor" data-stroke="none" stroke="none"></circle> 53395 </g> 53396 </svg> 53397 `, 53398 indentDecrease: ` 53399 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53400 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53401 <path d="M15.25 6.75L13 9L15.25 11.25"></path> 53402 <path d="M2.75 14.25H15.25"></path> 53403 <path d="M2.75 10.75H10.25"></path> 53404 <path d="M2.75 7.25H10.25"></path> 53405 <path d="M2.75 3.75H15.25"></path> 53406 </g> 53407 </svg> 53408 `, 53409 indentIncrease: ` 53410 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53411 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53412 <path d="M2.75 11.25L5 9L2.75 6.75"></path> 53413 <path d="M15.25 3.75H2.75"></path> 53414 <path d="M15.25 7.25H7.75"></path> 53415 <path d="M15.25 10.75H7.75"></path> 53416 <path d="M15.25 14.25H2.75"></path> 53417 </g> 53418 </svg> 53419 `, 53420 italic: ` 53421 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" aria-hidden="true" focusable="false"> 53422 <g stroke-linejoin="round" stroke-linecap="round" stroke-width="1.75" fill="none" stroke="currentColor"> 53423 <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> 53424 <path d="M11 5l6 0"></path> 53425 <path d="M7 19l6 0"></path> 53426 <path d="M14 5l-4 14"></path> 53427 </g> 53428 </svg> 53429 `, 53430 link: ` 53431 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53432 <g fill="currentColor"> 53433 <path fill-rule="evenodd" clip-rule="evenodd" d="M9.03166 6.54197C9.22575 6.9079 9.08644 7.36188 8.72052 7.55597C8.47184 7.68787 8.24717 7.85851 8.04832 8.05733C6.96021 9.14544 6.96021 10.9086 8.04832 11.9967L10.2233 14.1717C11.3114 15.2598 13.0746 15.2598 14.1627 14.1717C15.2507 13.0836 15.2608 11.3104 14.1727 10.2223L13.4103 9.45993C13.1174 9.16703 13.1174 8.69216 13.4103 8.39927C13.7032 8.10638 14.178 8.10638 14.4709 8.39927L15.2333 9.16167C16.9072 10.8356 16.9
53433072 13.5484 15.2333 15.2223C13.5594 16.8962 10.8365 16.9062 9.16266 15.2323L6.98766 13.0573C5.31377 11.3834 5.31377 8.67056 6.98766 6.99667C7.29576 6.68747 7.64975 6.42597 8.01766 6.23083C8.38359 6.03674 8.83757 6.17604 9.03166 6.54197Z"></path> 53434 <path fill-rule="evenodd" clip-rule="evenodd" d="M2.77868 2.76766C4.45257 1.09376 7.16544 1.09376 8.83934 2.76766L11.0143 4.94266C12.6882 6.61655 12.6882 9.32942 11.0143 11.0033C10.7101 11.3075 10.3647 11.5674 9.98433 11.7692C9.6184 11.9633 9.16442 11.824 8.97033 11.458C8.77624 11.0921 8.91554 10.6381 9.28147 10.444C9.53006 10.3122 9.7549 10.1414 9.95368 9.94267C11.0418 8.85455 11.0418 7.09142 9.95368 6.00332L7.77868 3.82832C6.69057 2.74021 4.92744 2.74021 3.83934 3.82832C2.76193 4.90573 2.74775 6.69607 3.82934 7.77766L4.59174 8.54006C4.88463 8.83295 4.88463 9.30782 4.59174 9.60072C4.29884 9.89361 3.82397 9.89361 3.53108 9.60072L2.76868 8.83832C1.10903 7.17867 1.1232 4.42314 2.77868 2.76766Z"></path> 53435 </g> 53436 </svg> 53437 `, 53438 numberList: ` 53439 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53440 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53441 <line x1="9.25" y1="9" x2="15.75" y2="9"></line> 53442 <line x1="9.25" y1="3.75" x2="15.75" y2="3.75"></line> 53443 <line x1="9.25" y1="14.25" x2="15.75" y2="14.25"></line> 53444 <path d="M2.5,11.661c.259-.921,1.152-1.425,2.116-1.411,.965,.014,1.872,.446,1.929,1.411s-.965,1.612-2.023,2.044c-1.058,.432-1.936,.835-2.023,2.044H6.548"></path> 53445 <path d="M4.75,7.5V2s-.63,1.108-1.967,1.364"></path> 53446 </g> 53447 </svg> 53448 `, 53449 pdf: ` 53450 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53451 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53452 <line x1="10.25" y1="6.25" x2="12.25" y2="6.25"></line> 53453 <line x1="5.75" y1="9.25" x2="12.25" y2="9.25"></line> 53454 <line x1="5.75" y1="12.25" x2="12.25" y2="12.25"></line> 53455 <rect x="1.75" y="2.75" width="14.5" height="12.5" rx="2" ry="2" transform="translate(18 0) rotate(90)"></rect> 53456 <rect x="5.75" y="4.75" width="1.5" height="1.5" fill="currentColor"></rect> 53457 </g> 53458 </svg> 53459 `, 53460 paragraph: ` 53461 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53462 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53463 <line x1="6.75" y1="15.25" x2="11.25" y2="15.25"></line> 53464 <line x1="9" y1="2.75" x2="9" y2="15.25"></line> 53465 <polyline points="14.75 4.25 14 2.75 4 2.75 3.25 4.25"></polyline> 53466 </g> 53467 </svg> 53468 `, 53469 text: ` 53470 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53471 <g fill="currentColor"> 53472 <path d="M11.25,14.5h-1.5V2.75c0-.414-.336-.75-.75-.75s-.75,.336-.75,.75V14.5h-1.5c-.414,0-.75,.336-.75,.75s.336,.75,.75,.75h4.5c.414,0,.75-.336,.75-.75s-.336-.75-.75-.75Z"></path> 53473 <path d="M14.751,5c-.275,0-.54-.152-.672-.415l-.543-1.085H4.464l-.543,1.085c-.185,.37-.635,.521-1.006,.335s-.521-.636-.336-1.006l.75-1.5c.127-.254,.387-.415,.671-.415H14c.284,0,.544,.161,.671,.415l.75,1.5c.186,.371,.035,.821-.336,1.006-.107,.054-.222,.079-.334,.079Z"></path> 53474 </g> 53475 </svg> 53476 `, 53477 quote: ` 53478 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53479 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53480 <path d="M2.75 14.25H15.25"></path> 53481 <path d="M2.75 10.75H15.25"></path> 53482 <path d="M12.25 7.25H15.25"></path> 53483 <path d="M12.25 3.75H15.25"></path> 53484 <path d="M2.75 5.75H4.75V7.25H2.75V5.75ZM2.75 5.75C2.75 3.957 3.348 3.168 4.424 2.75"></path> 53485 <path d="M7.25 5.75H9.25V7.25H7.25V5.75ZM7.25 5.75C7.25 3.957 7.848 3.168 8.924 2.75"></path> 53486 </g> 53487 </svg> 53488 `, 53489 redo: ` 53490 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53491 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53492 <path d="M15.75 6.25H6C3.929 6.25 2.25 7.929 2.25 10C2.25 12.071 3.929 13.75 6 13.75H9.75"></path> 53493 <path d="M12.25 9.75L15.75 6.25L12.25 2.75"></path> 53494 </g> 53495 </svg> 53496 `, 53497 separator: ` 53498 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53499 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53500 <path d="m2.75,2.25v1.5c0,1.105.895,2,2,2h8.5c1.105,0,2-.895,2-2v-1.5"></path> 53501 <path d="m2.75,15.75v-1.5c0-1.105.895-2,2-2h8.5c1.105,0,2,.895,2,2v1.5"></path> 53502 <line x1="16" y1="9" x2="2" y2="9"></line> 53503 </g> 53504 </svg> 53505 `, 53506 strike: ` 53507 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53508 <g fill="currentColor"> 53509 <path d="M9.67402 9.75C9.61902 9.75 9.56302 9.744 9.50702 9.731C9.28001 9.679 9.05902 9.636 8.84902 9.599C5.44502 8.991 4.57202 7.218 4.43902 5.837C4.33202 4.728 4.63202 3.749 5.30802 3.006C6.63702 1.543 8.83402 1.5 9.08002 1.5C10.27 1.5 12.423 1.868 13.465 4.334C13.626 4.715 13.447 5.155 13.066 5.317C12.685 5.478 12.244 5.299 12.083 4.918C11.545 3.645 10.535 3 9.08002 3C8.47801 3 7.14601 3.212 6.41701 4.014C6.02302 4.448 5.86502 4.996 5.93202 5.693C5.97702 6.161 6.11502 7.587 9.11202 8.122C9.34302 8.163 9.58902 8.211 9.84101 8.268C10.245 8.36 10.497 8.763 10.405 9.166C10.325 9.514 10.016 9.749 9.67402 9.749V9.75Z"></path> 53510 <path d="M16 9.75H2C1.586 9.75 1.25 9.414 1.25 9C1.25 8.586 1.586 8.25 2 8.25H16C16.414 8.25 16.75 8.586 16.75 9C16.75 9.414 16.414 9.75 16 9.75Z"></path> 53511 <path fill-rule="evenodd" clip-rule="evenodd" d="M13.0672 11.2532C13.4796 11.214 13.8457 11.5165 13.8849 11.9288C13.8943 12.0276 13.9004 12.1288 13.9028 12.2325C13.9676 14.8775 11.598 16.5 9.079 16.5C7.90939 16.5 6.8445 16.2729 5.97294 15.7286C5.08701 15.1753 4.46415 14.3331 4.12756 13.2286C4.00681 12.8324 4.23014 12.4133 4.62636 12.2925C
535115.02258 12.1718 5.44167 12.3951 5.56241 12.7913C5.80482 13.5868 6.22047 14.1147 6.76754 14.4563C7.32899 14.807 8.0916 15 9.079 15C11.074 15 12.4404 13.7834 12.4032 12.2684C12.4016 12.2003 12.3977 12.1339 12.3917 12.0709C12.3524 11.6586 12.6549 11.2925 13.0672 11.2532Z"></path> 53512 </g> 53513 </svg> 53514 `, 53515 table: ` 53516 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53517 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53518 <line x1="15.25" y1="6.75" x2="2.75" y2="6.75"></line> 53519 <line x1="15.25" y1="11.25" x2="2.75" y2="11.25"></line> 53520 <line x1="7.25" y1="2.75" x2="7.25" y2="15.25"></line> 53521 <rect x="2.75" y="2.75" width="12.5" height="12.5" rx="2" ry="2"></rect> 53522 </g> 53523 </svg> 53524 `, 53525 trash: ` 53526 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53527 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53528 <path d="M2.75 4.75H15.25"></path> 53529 <path d="M6.75 4.75V2.75C6.75 2.2 7.198 1.75 7.75 1.75H10.25C10.802 1.75 11.25 2.2 11.25 2.75V4.75"></path> 53530 <path d="M7.375 8.75L7.59219 13.25"></path> 53531 <path d="M10.625 8.75L10.4078 13.25"></path> 53532 <path d="M13.6977 7.75L13.35 14.35C13.294 15.4201 12.416 16.25 11.353 16.25H6.64804C5.58404 16.25 4.70703 15.42 4.65103 14.35L4.30334 7.75"></path> 53533 </g> 53534 </svg> 53535 `, 53536 undo: ` 53537 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53538 <g fill="currentColor"> 53539 <path d="M12,14.5h-3.75c-.414,0-.75-.336-.75-.75s.336-.75,.75-.75h3.75c1.654,0,3-1.346,3-3s-1.346-3-3-3H2.5c-.414,0-.75-.336-.75-.75s.336-.75,.75-.75H12c2.481,0,4.5,2.019,4.5,4.5s-2.019,4.5-4.5,4.5Z"></path> 53540 <path d="M5.75,10.5c-.192,0-.384-.073-.53-.22L1.72,6.78c-.293-.293-.293-.768,0-1.061l3.5-3.5c.293-.293,.768-.293,1.061,0s.293,.768,0,1.061l-2.97,2.97,2.97,2.97c.293,.293,.293,.768,0,1.061-.146,.146-.338,.22-.53,.22Z"></path> 53541 </g> 53542 </svg> 53543 `, 53544 underline: ` 53545 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"> 53546 <g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" stroke="currentColor"> 53547 <path d="M12.75,2.75v5.75c0,2.071-1.679,3.75-3.75,3.75h0c-2.071,0-3.75-1.679-3.75-3.75V2.75"></path> 53548 <line id="color" x1="2.75" y1="15.25" x2="15.25" y2="15.25"></line> 53549 </g> 53550 </svg> 53551 ` 53552 }; 53553 var TOOLBAR_ICON_ALIASES = { 53554 attachment: ICONS2.attachment, 53555 audio: ICONS2.audio, 53556 blockquote: ICONS2.quote, 53557 bold: ICONS2.bold, 53558 "bullet-list": ICONS2.bulletList, 53559 callout: ICONS2.callout, 53560 checklist: ICONS2.checklist, 53561 "clear-formatting": ICONS2.clearFormatting, 53562 clearFormatting: ICONS2.clearFormatting, 53563 code: ICONS2.code, 53564 "code-block": ICONS2.code, 53565 delete: ICONS2.trash, 53566 divider: ICONS2.separator, 53567 file: ICONS2.attachment, 53568 format: ICONS2.format, 53569 h1: ICONS2.heading1, 53570 h2: ICONS2.heading2, 53571 h3: ICONS2.heading3, 53572 h4: ICONS2.heading4, 53573 "heading-1": ICONS2.heading1, 53574 "heading-2": ICONS2.heading2, 53575 "heading-3": ICONS2.heading3, 53576 "heading-4": ICONS2.heading4, 53577 "heading-large": ICONS2.heading2, 53578 "heading-medium": ICONS2.heading3, 53579 "heading-small": ICONS2.heading4, 53580 heading1: ICONS2.heading1, 53581 heading2: ICONS2.heading2, 53582 heading3: ICONS2.heading3, 53583 heading4: ICONS2.heading4, 53584 highlight: ICONS2.highlight, 53585 image: ICONS2.image, 53586 indent: ICONS2.indentIncrease, 53587 italic: ICONS2.italic, 53588 link: ICONS2.link, 53589 "number-list": ICONS2.numberList, 53590 "ordered-list": ICONS2.numberList, 53591 outdent: ICONS2.indentDecrease, 53592 paragraph: ICONS2.paragraph, 53593 pdf: ICONS2.pdf, 53594 quote: ICONS2.quote, 53595 redo: ICONS2.redo, 53596 remove: ICONS2.trash, 53597 separator: ICONS2.separator, 53598 strike: ICONS2.strike, 53599 strikethrough: ICONS2.strike, 53600 table: ICONS2.table, 53601 "toggle-list": ICONS2.toggleList, 53602 toggleList: ICONS2.toggleList, 53603 trash: ICONS2.trash, 53604 undo: ICONS2.undo, 53605 underline: ICONS2.underline, 53606 "unordered-list": ICONS2.bulletList 53607 }; 53608 var FLOATING_DROPDOWN_OFFSET = 4;
53609 var FLOATING_DROPDOWN_MARGIN = 8; 53610 var FLOATING_DROPDOWN_SELECTOR = "lexxy-toolbar-dropdown, lexxy-highlight-dropdown, lexxy-link-dropdown"; 53611 var LEXXY_TOOLBAR_ICONS = Object.freeze(ICONS2); 53612 function iconForToolbarButtonName(name) { 53613 return TOOLBAR_ICON_ALIASES[name] || null; 53614 } 53615 function enhanceLexxyToolbarIcons(root = document) { 53616 root.querySelectorAll("lexxy-toolbar button[name]").forEach((button) => { 53617 const command = button.name; 53618 const icon = iconForToolbarButtonName(command); 53619 if (!icon) return; 53620 const label = button.querySelector("span"); 53621 if (label) { 53622 button.querySelector("svg")?.remove(); 53623 button.insertAdjacentHTML("afterbegin", `${icon} `); 53624 } else { 53625 button.innerHTML = icon; 53626 } 53627 button.dataset.lexxyIcon = command; 53628 }); 53629 root.querySelectorAll("lexxy-node-delete-button .lexxy-node-delete").forEach((button) => { 53630 button.querySelector("svg")?.remove(); 53631 button.insertAdjacentHTML("afterbegin", `${ICONS2.trash} `); 53632 button.dataset.lexxyIcon = "trash"; 53633 }); 53634 root.querySelectorAll("lexxy-toolbar").forEach((toolbar) => { 53635 disableLexxyToolbarOverflow(toolbar); 53636 installFloatingToolbarDropdowns(toolbar); 53637 }); 53638 } 53639 function disableLexxyToolbarOverflow(toolbar) { 53640 const overflowMenu = toolbar.querySelector(".lexxy-editor__toolbar-overflow"); 53641 const overflowPanel = overflowMenu?.querySelector(":scope > [data-dropdown-panel]"); 53642 if (overflowMenu && overflowPanel) { 53643 restoreToolbarOverflow(toolbar, overflowMenu, overflowPanel); 53644 setOverflowMenuState(toolbar, overflowMenu, overflowPanel, false); 53645 } 53646 toolbar.querySelectorAll(":scope > button").forEach((button) => { 53647 button.dataset.preventOverflow = "true"; 53648 }); 53649 toolbar.requestOverflowRefresh?.(); 53650 } 53651 function restoreToolbarOverflow(toolbar, overflowMenu, overflowPanel) { 53652 Array.from(overflowPanel.children).sort((a2, b3) => itemPosition(b3) - itemPosition(a2)).forEach((item) => {
53653 const nextItem = toolbar.querySelector(`[data-position="${itemPosition(item) + 1}"]`) || overflowMenu; 53654 item.removeAttribute("role"); 53655 toolbar.insertBefore(item, nextItem); 53656 }); 53657 } 53658 function setOverflowMenuState(toolbar, overflowMenu, overflowPanel, isOverflowing) { 53659 toolbar.toggleAttribute("overflowing", isOverflowing); 53660 overflowMenu.style.display = isOverflowing ? "block" : "none"; 53661 overflowPanel.toggleAttribute("disabled", !isOverflowing); 53662 if (!isOverflowing) overflowPanel.hidden = true; 53663 } 53664 function itemPosition(item) { 53665 return parseInt(item.dataset.position || "999", 10); 53666 } 53667 function installFloatingToolbarDropdowns(toolbar) { 53668 if (toolbar.dataset.lexxyFloatingDropdownsInstalled === "true") return; 53669 toolbar.dataset.lexxyFloatingDropdownsInstalled = "true"; 53670 toolbar.querySelectorAll(FLOATING_DROPDOWN_SELECTOR).forEach((dropdown) => { 53671 const panel = dropdown.querySelector(":scope > [data-dropdown-panel]"); 53672 if (!panel) return; 53673 const updatePosition = () => updateFloatingDropdownPosition(toolbar, dropdown, panel); 53674 const togglePositioning = () => { 53675 if (panel.hidden) { 53676 panel.removeAttribute("data-lexxy-floating-dropdown"); 53677 panel.style.removeProperty("--lexxy-dropdown-inline-size"); 53678 panel.style.removeProperty("--lexxy-dropdown-inline-start"); 53679 panel.style.removeProperty("--lexxy-dropdown-block-start"); 53680 return; 53681 } 53682 updatePosition(); 53683 }; 53684 new MutationObserver(togglePositioning).observe(panel, { 53685 attributes: true, 53686 attributeFilter: ["hidden"] 53687 }); 53688 dropdown.querySelector("[data-dropdown-trigger]")?.addEventListener("click", () => { 53689 requestAnimationFrame(togglePositioning); 53690 }); 53691 toolbar.addEventListener("scroll", updatePosition, { passive: true }); 53692 window.addEventListener("resize", updatePosition, { passive: true }); 53693 window.addEventListener("scroll", updatePosition, { passive: true }); 53694 togglePositioning(); 53695 }); 53696 } 53697 function updateFloatingDropdownPosition(toolbar, dropdown, panel) { 53698 if (panel.hidden) return; 53699 const trigger = dropdown.querySelector(":scope > [data-dropdown-trigger]"); 53700 if (!trigger) return; 53701 panel.setAttribute("data-lexxy-floating-dropdown", ""); 53702 if (dropdown.matches("lexxy-link-dropdown")) { 53703 panel.style.setProperty("--lexxy-dropdown-inline-size", `${floatingDropdownWidth(toolbar)}px`); 53704 } else { 53705 panel.style.removeProperty("--lexxy-dropdown-inline-size"); 53706 } 53707 const triggerRect = trigger.getBoundingClientRect(); 53708 const panelRect = panel.getBoundingClientRect(); 53709 const top = triggerRect.bottom + FLOATING_DROPDOWN_OFFSET; 53710 const left = dropdown.matches("lexxy-link-dropdown") ? centeredFloatingDropdownLeft(toolbar, panelRect.width) : clampedFloatingDropdownLeft(triggerRect.left, panelRect.width); 53711 panel.style.setProperty("--lexxy-dropdown-inline-start", `${left}px`); 53712 panel.style.setProperty("--lexxy-dropdown-block-start", `${top}px`); 53713 } 53714 function floatingDropdownWidth(toolbar) { 53715 return Math.min( 53716 toolbar.getBoundingClientRect().width - FLOATING_DROPDOWN_MARGIN * 2, 53717 window.innerWidth - FLOATING_DROPDOWN_MARGIN * 2 53718 ); 53719 } 53720 function centeredFloatingDropdownLeft(toolbar, panelWidth) { 53721 const toolbarRect = toolbar.getBoundingClientRect(); 53722 return clampedFloatingDropdownLeft(toolbarRect.left + (toolbarRect.width - panelWidth) / 2, panelWidth); 53723 } 53724 function clampedFloatingDropdownLeft(preferredLeft, panelWidth) { 53725 return Math.min( 53726 Math.max(FLOATING_DROPDOWN_MARGIN, preferredLeft), 53727 Math.max(FLOATING_DROPDOWN_MARGIN, window.innerWidth - panelWidth - FLOATING_DROPDOWN_MARGIN) 53728 ); 53729 } 53730 53731
53731// app/javascript/src/lexxy/callout_extension.js 53732 var { 53733 $createParagraphNode: $createParagraphNode5, 53734 $findMatchingParent: $findMatchingParent5, 53735 $getSelection: $getSelection5, 53736 $isElementNode: $isElementNode6, 53737 $isParagraphNode: $isParagraphNode4, 53738 $isRangeSelection: $isRangeSelection5, 53739 $isTextNode: $isTextNode3, 53740 COMMAND_PRIORITY_LOW: COMMAND_PRIORITY_LOW3, 53741 COMMAND_PRIORITY_EDITOR: COMMAND_PRIORITY_EDITOR3, 53742 INTERNAL_$isBlock: INTERNAL_$isBlock4, 53743 KEY_ARROW_DOWN_COMMAND: KEY_ARROW_DOWN_COMMAND3, 53744 KEY_ENTER_COMMAND: KEY_ENTER_COMMAND3 53745 } = Lexical_exports; 53746 function $emptyParagraphInCallout() { 53747 const selection = $getSelection5(); 53748 if (!$isRangeSelection5(selection) || !selection.isCollapsed()) return null; 53749 const anchorNode = selection.anchor.getNode(); 53750 const paragraph = $isParagraphNode4(anchorNode) ? anchorNode : $findMatchingParent5(anchorNode, $isParagraphNode4); 53751 if (!$isParagraphNode4(paragraph) || paragraph.getTextContent() !== "") return null; 53752 const callout = $findMatchingParent5(paragraph, $isCalloutNode); 53753 if (!$isCalloutNode(callout)) return null; 53754 return { callout, paragraph }; 53755 } 53756 function $exitCalloutFromEmptyParagraph() { 53757 const context = $emptyParagraphInCallout(); 53758 if (!context) return false; 53759 const nextParagraph = $createParagraphNode5(); 53760 context.callout.insertAfter(nextParagraph); 53761 context.paragraph.remove(); 53762 if (context.callout.getChildrenSize() === 0) { 53763 context.callout.remove(); 53764 } 53765 nextParagraph.select(); 53766 return true; 53767 } 53768 function $selectionBlock(selection) { 53769 const anchorNode = selection.anchor.getNode(); 53770 if ($isElementNode6(anchorNode) && INTERNAL_$isBlock4(anchorNode)) return anchorNode; 53771 const block = $findMatchingParent5( 53772 anchorNode, 53773 (node) => $isElementNode6(node) && INTERNAL_$isBlock4(node) 53774 ); 53775 return $isElementNode6(block) ? block : null; 53776 } 53777 function $isSelectionAtBlockEnd(selection, block) { 53778 const anchor = selection.anchor; 53779 const anchorNode = anchor.getNode(); 53780 if (anchor.type === "element" && anchorNode.is(block)) { 53781 return anchor.offset === block.getChildrenSize(); 53782 } 53783 if (!$isTextNode3(anchorNode)) return false; 53784 const lastDescendant = block.getLastDescendant(); 53785 return anchorNode.is(lastDescendant) && anchor.offset === anchorNode.getTextContentSize(); 53786 } 53787 function $selectStartOfCalloutAfterCurrentBlock() { 53788 const selection = $getSelection5(); 53789 if (!$isRangeSelection5(selection) || !selection.isCollapsed()) return false; 53790 const block = $selectionBlock(selection); 53791 if (!block || !$isSelectionAtBlockEnd(selection, block)) return false; 53792 const nextBlock = block.getNextSibling(); 53793 if (!$isCalloutNode(nextBlock)) return false; 53794 const firstContentBlock = nextBlock.getFirstChild(); 53795 if (!firstContentBlock?.selectStart) return false; 53796 firstContentBlock.selectStart(); 53797 return true; 53798 } 53799 var CalloutExtension = class extends LexxyExtension { 53800 #button = null; 53801 #updateListener = null; 53802 get enabled() { 53803 return this.editorElement.supportsRichText; 53804 } 53805 get allowedElements() { 53806 return [ 53807 { 53808 tag: "aside", 53809 attributes: [ 53810 "class", 53811 "data-border-variant", 53812 "data-bg-variant", 53813 "data-icon", 53814 "data-icon-id", 53815 "data-icon-type", 53816 "data-icon-src" 53817 ] 53818 }, 53819 { 53820 tag: "div", 53821 attributes: [ 53822 "class", 53823 "data-border-variant", 53824 "data-bg-variant", 53825 "data-icon", 53826 "data-icon-id", 53827 "data-icon-type", 53828 "data-icon-src" 53829 ] 53830 } 53831 ]; 53832 } 53833 get lexicalExtension() { 53834 return this.defineExtension({ 53835 name: "lexxy/callout", 53836 nodes: [CalloutNode], 53837 register: (editor) => mergeRegister3( 53838 editor.registerNodeTransform(CalloutNode, (callout) => { 53839 $normalizeCalloutContent(callout); 53840 }), 53841 editor.registerCommand( 53842 KEY_ARROW_DOWN_COMMAND3, 53843 (event) => { 53844 if (event?.shiftKey || event?.altKey || event?.ctrlKey || event?.metaKey) return false;
53845 if (!$selectStartOfCalloutAfterCurrentBlock()) return false; 53846 event?.preventDefault(); 53847 return true; 53848 }, 53849 COMMAND_PRIORITY_EDITOR3 53850 ), 53851 editor.registerCommand( 53852 KEY_ENTER_COMMAND3, 53853 (event) => { 53854 if (!$exitCalloutFromEmptyParagraph()) return false; 53855 event?.preventDefault(); 53856 return true; 53857 }, 53858 COMMAND_PRIORITY_LOW3 53859 ) 53860 ) 53861 }); 53862 } 53863 initializeToolbar(toolbar) { 53864 this.#ensureCalloutTools(); 53865 const dividerButton = toolbar.querySelector('[name="divider"]'); 53866 if (!dividerButton || toolbar.querySelector('[name="callout"]')) return; 53867 const button = document.createElement("button"); 53868 button.type = "button"; 53869 button.className = "lexxy-editor__toolbar-button"; 53870 button.name = "callout"; 53871 button.title = "Callout"; 53872 button.innerHTML = LEXXY_TOOLBAR_ICONS.callout; 53873 button.addEventListener("click", (event) => { 53874 event.preventDefault(); 53875 this.#toggleCallout(); 53876 }); 53877 dividerButton.insertAdjacentElement("beforebegin", button); 53878 this.#button = button; 53879 const editor = this.editorElement.editor; 53880 if (!editor) return; 53881 this.#updateListener = editor.registerUpdateListener(({ editorState }) => { 53882 editorState.read(() => { 53883 const active = this.#selectionIsInsideCallout(); 53884 button.classList.toggle("lexxy-editor__toolbar-button--pressed", active); 53885 button.setAttribute("aria-pressed", active ? "true" : "false"); 53886 }); 53887 }); 53888 } 53889 dispose() { 53890 this.#updateListener?.(); 53891 this.#button = null; 53892 } 53893 #ensureCalloutTools() { 53894 if (this.editorElement.querySelector("lexxy-callout-tools")) return; 53895 this.editorElement.appendChild(document.createElement("lexxy-callout-tools")); 53896 } 53897 #toggleCallout() { 53898 const editor = this.editorElement.editor; 53899 if (!editor) return; 53900 editor.update(() => { 53901 $insertCallout(); 53902 }); 53903 editor.focus(); 53904 } 53905 #selectionIsInsideCallout() { 53906 return this.#calloutForSelection() !== null; 53907 } 53908 #calloutForSelection() { 53909 const selection = $getSelection5(); 53910 if (!$isRangeSelection5(selection)) return null; 53911 const anchorNode = selection.anchor.getNode(); 53912 return $findMatchingParent5(anchorNode, $isCalloutNode); 53913 } 53914 #unwrapCallout(callout) { 53915 const children = [...callout.getChildren()]; 53916 if (children.length === 0) { 53917 callout.remove(); 53918 return; 53919 } 53920 children.forEach((child) => callout.insertBefore(child)); 53921 callout.remove(); 53922 } 53923 }; 53924 53925
53925// app/javascript/src/lexxy/checklist_extension.js 53926 var { 53927 $getSelection: $getSelection6, 53928 $isRangeSelection: $isRangeSelection6, 53929 $isTextNode: $isTextNode4, 53930 COMMAND_PRIORITY_HIGH: COMMAND_PRIORITY_HIGH3, 53931 INPUT_COMMAND: INPUT_COMMAND3, 53932 KEY_ENTER_COMMAND: KEY_ENTER_COMMAND4, 53933 KEY_SPACE_COMMAND: KEY_SPACE_COMMAND3, 53934 KEY_TAB_COMMAND: KEY_TAB_COMMAND3 53935 } = Lexical_exports; 53936 var ChecklistExtension = class extends LexxyExtension { 53937 #button = null; 53938 #updateListener = null; 53939 #shortcutListener = null; 53940 #tabListener = null; 53941 #enterListener = null; 53942 get enabled() { 53943 return this.editorElement.supportsRichText; 53944 } 53945 get allowedElements() { 53946 return [ 53947 { tag: "ul", attributes: ["class"] }, 53948 { tag: "li", attributes: ["role", "aria-checked", "tabindex", "class"] } 53949 ]; 53950 } 53951 get lexicalExtension() { 53952 return this.defineExtension({ 53953 name: "lexxy/checklist", 53954 register: (editor) => registerCheckList2(editor, { disableTakeFocusOnClick: true }) 53955 }); 53956 } 53957 initializeToolbar(toolbar) { 53958 const orderedListButton = toolbar.querySelector('[name="ordered-list"]'); 53959 if (!orderedListButton || toolbar.querySelector('[name="checklist"]')) return; 53960 orderedListButton.classList.remove("lexxy-editor__toolbar-group-end"); 53961 const button = document.createElement("button"); 53962 button.type = "button"; 53963 button.className = "lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end"; 53964 button.name = "checklist"; 53965 button.title = "Checklist"; 53966 button.innerHTML = LEXXY_TOOLBAR_ICONS.checklist; 53967 button.addEventListener("click", (event) => { 53968 event.preventDefault(); 53969 this.#toggleChecklist(); 53970 }); 53971 orderedListButton.insertAdjacentElement("afterend", button); 53972 this.#button = button; 53973 const editor = this.editorElement.editor; 53974 if (!editor) return; 53975 this.#updateListener = editor.registerUpdateListener(({ editorState }) => { 53976 editorState.read(() => { 53977 const format = this.editorElement.selection?.getFormat?.(); 53978 const active = format?.isInList && format?.listType === "check"; 53979 button.classList.toggle("lexxy-editor__toolbar-button--pressed", active); 53980 button.setAttribute("aria-pressed", active ? "true" : "false"); 53981 }); 53982 }); 53983 this.#shortcutListener = this.#registerChecklistShortcut(editor); 53984 this.#tabListener = this.#registerChecklistTabHandler(editor); 53985 this.#enterListener = this.#registerChecklistEnterHandler(editor); 53986 } 53987 dispose() { 53988 this.#updateListener?.(); 53989 this.#shortcutListener?.(); 53990 this.#tabListener?.(); 53991 this.#enterListener?.(); 53992 this.#button = null; 53993 } 53994 #toggleChecklist() { 53995 const editor = this.editorElement.editor; 53996 const contents = this.editorElement.contents; 53997 if (!editor || !contents) return; 53998 editor.update(() => { 53999 const selection = $getSelection6(); 54000 if (!$isRangeSelection6(selection)) return; 54001 const format = this.editorElement.selection?.getFormat?.(); 54002 if (format?.isInList && format?.listType === "check") { 54003 contents.applyParagraphFormat(); 54004 } else { 54005 editor.dispatchCommand(INSERT_CHECK_LIST_COMMAND2, void 0); 54006 } 54007 }); 54008 editor.focus(); 54009 } 54010 #registerChecklistShortcut(editor) { 54011 const handleShortcut = (event) => { 54012 if (!this.#selectionHasChecklistShortcut()) return false; 54013 event?.preventDefault(); 54014 editor.update(() => { 54015 this.#removeChecklistShortcutText(); 54016 editor.dispatchCommand(INSERT_CHECK_LIST_COMMAND2, void 0); 54017 }); 54018 return true; 54019 }; 54020 const removeSpaceCommand = editor.registerCommand( 54021 KEY_SPACE_COMMAND3, 54022 handleShortcut, 54023 COMMAND_PRIORITY_HIGH3 54024 ); 54025 const removeInputCommand = editor.registerCommand( 54026 INPUT_COMMAND3, 54027 (event) => { 54028 if (event.inputType !== "insertText" || event.data !== " ") return false; 54029 return handleShortcut(event); 54030 }, 54031 COMMAND_PRIORITY_HIGH3 54032 ); 54033 return () => { 54034 removeSpaceCommand(); 54035 removeInputCommand(); 54036 }; 54037 } 54038 #selectionHasChecklistShortcut() { 54039 if (this.editorElement.selection?.isInsideCodeBlock) return false;
54040 const selection = $getSelection6(); 54041 if (!$isRangeSelection6(selection) || !selection.isCollapsed()) return false; 54042 const anchorNode = selection.anchor.getNode(); 54043 if (!$isTextNode4(anchorNode)) return false; 54044 const textBeforeCursor = anchorNode.getTextContent().slice(0, selection.anchor.offset); 54045 return /(?:^|\n)\[\]\s?$/.test(textBeforeCursor); 54046 } 54047 #removeChecklistShortcutText() { 54048 const selection = $getSelection6(); 54049 if (!$isRangeSelection6(selection) || !selection.isCollapsed()) return; 54050 const anchorNode = selection.anchor.getNode(); 54051 if (!$isTextNode4(anchorNode)) return; 54052 const offset3 = selection.anchor.offset; 54053 const textBeforeCursor = anchorNode.getTextContent().slice(0, offset3); 54054 const shortcutIndex = textBeforeCursor.lastIndexOf("[]"); 54055 if (shortcutIndex === -1) return; 54056 const textBeforeShortcut = textBeforeCursor.slice(0, shortcutIndex); 54057 if (textBeforeShortcut && !textBeforeShortcut.endsWith("\n")) return; 54058 anchorNode.spliceText(shortcutIndex, offset3 - shortcutIndex, "", true); 54059 } 54060 #registerChecklistTabHandler(editor) { 54061 return editor.registerCommand( 54062 KEY_TAB_COMMAND3, 54063 (event) => { 54064 const listItem = editor.getEditorState().read(() => this.#checklistListItemForSelection()); 54065 if (!listItem) return false; 54066 const indentTarget = this.#resolveChecklistIndentTarget(listItem); 54067 if (indentTarget !== listItem) { 54068 event.preventDefault(); 54069 editor.update(() => { 54070 const currentIndent = indentTarget.getIndent(); 54071 indentTarget.setIndent(event.shiftKey ? Math.max(0, currentIndent - 1) : currentIndent + 1); 54072 }); 54073 return true; 54074 } 54075 return false; 54076 }, 54077 COMMAND_PRIORITY_HIGH3 54078 ); 54079 } 54080 #registerChecklistEnterHandler(editor) { 54081 return editor.registerCommand( 54082 KEY_ENTER_COMMAND4, 54083 (event) => { 54084 if (!event?.metaKey && !event?.ctrlKey) return false; 54085 const listItem = editor.getEditorState().read(() => this.#checklistListItemForSelection()); 54086 if (!listItem) return false; 54087 event.preventDefault(); 54088 editor.update(() => { 54089 this.#checklistListItemForSelection()?.toggleChecked(); 54090 }); 54091 return true; 54092 }, 54093 COMMAND_PRIORITY_HIGH3 54094 ); 54095 } 54096 #checklistListItemForSelection() { 54097 const selection = $getSelection6(); 54098 if (!$isRangeSelection6(selection)) return null; 54099 return $findMatchingParent3(selection.anchor.getNode(), (node) => { 54100 if (!$isListItemNode2(node)) return false; 54101 const parent = node.getParent(); 54102 return $isListNode2(parent) && parent.getListType() === "check"; 54103 }); 54104 } 54105 #resolveChecklistIndentTarget(listItem) { 54106 const firstChild = listItem.getFirstChild(); 54107 if ($isListNode2(firstChild) && listItem.getChildrenSize() === 1) { 54108 const innerItem = firstChild.getFirstChild(); 54109 if ($isListItemNode2(innerItem)) return innerItem; 54110 } 54111 return listItem; 54112 } 54113 }; 54114 54115
54115// app/javascript/src/lexxy/desktop_prompts.js 54116 function supportsDesktopPrompts() { 54117 return window.matchMedia("(hover: hover) and (pointer: fine)").matches; 54118 } 54119 54120
54120// app/javascript/src/lexxy/popover_scroll_lock.js 54121 var lockCount = 0; 54122 var scrollPosition = 0; 54123 var previousBodyPosition = ""; 54124 var previousBodyTop = ""; 54125 var previousBodyWidth = ""; 54126 function lockPopoverScroll() { 54127 let unlocked = false; 54128 if (lockCount === 0) { 54129 scrollPosition = window.pageYOffset || document.documentElement.scrollTop; 54130 previousBodyPosition = document.body.style.position; 54131 previousBodyTop = document.body.style.top; 54132 previousBodyWidth = document.body.style.width; 54133 document.body.style.position = "fixed"; 54134 document.body.style.top = `-${scrollPosition}px`; 54135 document.body.style.width = "100%"; 54136 } 54137 lockCount += 1; 54138 return () => { 54139 if (unlocked) return; 54140 unlocked = true; 54141 lockCount = Math.max(0, lockCount - 1); 54142 if (lockCount === 0) { 54143 document.body.style.position = previousBodyPosition; 54144 document.body.style.top = previousBodyTop; 54145 document.body.style.width = previousBodyWidth; 54146 window.scrollTo(0, scrollPosition); 54147 } 54148 }; 54149 } 54150 54151
54151// app/javascript/src/lexxy/emoji_prompt_extension.js 54152 var { 54153 $getNodeByKey: $getNodeByKey4, 54154 $getSelection: $getSelection7, 54155 $isRangeSelection: $isRangeSelection7, 54156 $isTextNode: $isTextNode5, 54157 COMMAND_PRIORITY_CRITICAL: COMMAND_PRIORITY_CRITICAL3, 54158 KEY_ARROW_DOWN_COMMAND: KEY_ARROW_DOWN_COMMAND4, 54159 KEY_ARROW_LEFT_COMMAND: KEY_ARROW_LEFT_COMMAND3, 54160 KEY_ARROW_RIGHT_COMMAND: KEY_ARROW_RIGHT_COMMAND3, 54161 KEY_ARROW_UP_COMMAND: KEY_ARROW_UP_COMMAND3, 54162 KEY_ENTER_COMMAND: KEY_ENTER_COMMAND5, 54163 KEY_ESCAPE_COMMAND: KEY_ESCAPE_COMMAND3, 54164 KEY_TAB_COMMAND: KEY_TAB_COMMAND4 54165 } = Lexical_exports; 54166 var EmojiPromptExtension = class extends LexxyExtension { 54167 #popover = null; 54168 #emojiPicker = null; 54169 #popoverListeners = []; 54170 #triggerListener = null; 54171 #open = false; 54172 #showId = 0; 54173 #activeTrigger = null; 54174 #dismissedTrigger = null; 54175 #searchId = 0; 54176 #unlockScroll = null; 54177 get enabled() { 54178 return this.editorElement.supportsRichText && supportsDesktopPrompts(); 54179 } 54180 initializeToolbar(_toolbar) { 54181 this.#attachTriggerListener(); 54182 } 54183 dispose() { 54184 this.#disposePopoverListeners(); 54185 this.#unlockPopoverScroll(); 54186 this.#triggerListener?.(); 54187 this.#emojiPicker?._unwatchTheme?.(); 54188 this.#popover?.remove(); 54189 this.#emojiPicker = null; 54190 this.#popover = null; 54191 } 54192 #attachTriggerListener() { 54193 const editor = this.editorElement.editor; 54194 if (!editor) return; 54195 this.#triggerListener = editor.registerUpdateListener(({ editorState }) => { 54196 editorState.read(() => { 54197 if (this.editorElement.selection?.isInsideCodeBlock) return; 54198 const trigger = this.#readTriggerContext(); 54199 if (!trigger) { 54200 this.#dismissedTrigger = null; 54201 if (this.#open) this.#hidePopover(); 54202 return; 54203 } 54204 if (this.#isDismissedTrigger(trigger)) return; 54205 this.#activeTrigger = trigger; 54206 if (!this.#open) { 54207 this.#showPopover(trigger); 54208 return; 54209 } 54210 this.#syncEmojiSearch(trigger.query); 54211 this.#positionPopover(); 54212 }); 54213 }); 54214 } 54215 #readTriggerContext() { 54216 const selection = $getSelection7(); 54217 if (!$isRangeSelection7(selection) || !selection.isCollapsed()) return null; 54218 const anchorNode = selection.anchor.getNode(); 54219 if (!$isTextNode5(anchorNode)) return null; 54220 const offset3 = selection.anchor.offset; 54221 const textBeforeCursor = anchorNode.getTextContent().slice(0, offset3); 54222 const lastColon = textBeforeCursor.lastIndexOf(":"); 54223 if (lastColon === -1) return null; 54224 const charBeforeColon = lastColon > 0 ? textBeforeCursor[lastColon - 1] : ""; 54225 if (charBeforeColon && !/[\s\n]/.test(charBeforeColon)) return null; 54226 const query = textBeforeCursor.slice(lastColon + 1); 54227 if (!query || /\s/.test(query)) return null; 54228 return { 54229 key: anchorNode.getKey(), 54230 offset: lastColon, 54231 query 54232 }; 54233 } 54234 #isDismissedTrigger(trigger) { 54235 return this.#dismissedTrigger?.key === trigger.key && this.#dismissedTrigger?.offset === trigger.offset; 54236 } 54237 async #showPopover(trigger) { 54238 const showId = ++this.#showId; 54239 this.#open = true; 54240 this.#popover ??= this.#buildPopover(); 54241 if (this.#showId !== showId) return; 54242 this.#ensureEmojiPicker(); 54243 this.#syncEmojiSearch(trigger.query); 54244 this.#popover.classList.remove("hidden"); 54245 this.#popover.classList.add("lexxy-prompt-menu--visible"); 54246 this.#positionPopover(); 54247 this.#unlockScroll ??= lockPopoverScroll(); 54248 this.#registerPopoverListeners(); 54249 } 54250 #buildPopover() { 54251 const popover = document.createElement("div"); 54252 popover.className = "lexxy-callout-tools__icon-popover lexxy-callout-tools__icon-popover--portaled lexxy-emoji-menu lexxy-emoji-menu--p
54252ortaled lexxy-emoji-prompt-menu ph-no-autocapture hidden"; 54253 popover.hidden = true; 54254 popover.setAttribute("role", "dialog"); 54255 popover.setAttribute("aria-label", "Emoji"); 54256 popover.setAttribute("data-ph-no-autocapture", ""); 54257 popover.innerHTML = `<div class="lexxy-callout-tools__emoji-picker" data-emoji-picker-container></div>`; 54258 document.body.appendChild(popover); 54259 return popover; 54260 } 54261 #ensureEmojiPicker() { 54262 if (this.#emojiPicker) { 54263 this.#afterPopoverPaint(() => { 54264 this.#ensureEmojiPickerStyles(); 54265 this.#focusEmojiSearch(); 54266 }); 54267 return; 54268 } 54269 const container = this.#popover?.querySelector("[data-emoji-picker-container]"); 54270 if (!container) return; 54271 this.#emojiPicker = createCalloutEmojiPicker(container, { 54272 onSelect: (emoji) => this.#executeEmoji(emoji.native), 54273 pickerOptions: { 54274 autoFocus: true, 54275 navPosition: "none", 54276 previewPosition: "bottom", 54277 searchPosition: "none" 54278 } 54279 }); 54280 this.#afterPopoverPaint(() => { 54281 this.#ensureEmojiPickerStyles(); 54282 this.#focusEmojiSearch(); 54283 }); 54284 } 54285 #registerPopoverListeners() { 54286 this.#disposePopoverListeners(); 54287 const editor = this.editorElement.editor; 54288 const register = (command, handler) => { 54289 this.#popoverListeners.push(editor.registerCommand(command, handler, COMMAND_PRIORITY_CRITICAL3)); 54290 }; 54291 register(KEY_ARROW_UP_COMMAND3, (event) => { 54292 this.#navigateEmojiPicker(event, "up"); 54293 return true; 54294 }); 54295 register(KEY_ARROW_DOWN_COMMAND4, (event) => { 54296 this.#navigateEmojiPicker(event, "down"); 54297 return true; 54298 }); 54299 register(KEY_ARROW_LEFT_COMMAND3, (event) => { 54300 this.#navigateEmojiPicker(event, "left"); 54301 return true; 54302 }); 54303 register(KEY_ARROW_RIGHT_COMMAND3, (event) => { 54304 this.#navigateEmojiPicker(event, "right"); 54305 return true; 54306 }); 54307 register(KEY_ENTER_COMMAND5, (event) => { 54308 this.#executeSelectedEmoji(event); 54309 return true; 54310 }); 54311 register(KEY_TAB_COMMAND4, (event) => { 54312 this.#executeSelectedEmoji(event); 54313 return true; 54314 }); 54315 register(KEY_ESCAPE_COMMAND3, (event) => { 54316 event.preventDefault(); 54317 this.#dismissCurrentTrigger(); 54318 this.#hidePopover(); 54319 editor.focus(); 54320 return true; 54321 }); 54322 const onKeyDown2 = (event) => { 54323 if (event.key !== "Escape") return; 54324 event.preventDefault(); 54325 event.stopPropagation(); 54326 this.#dismissCurrentTrigger(); 54327 this.#hidePopover(); 54328 this.editorElement.editor.focus(); 54329 }; 54330 this.#popover.addEventListener("keydown", onKeyDown2, true); 54331 this.#popoverListeners.push(() => this.#popover?.removeEventListener("keydown", onKeyDown2, true)); 54332 this.#popoverListeners.push(this.#bindViewportRepositioning()); 54333 } 54334 #bindViewportRepositioning() { 54335 const reposition = () => this.#positionPopover(); 54336 window.addEventListener("scroll", reposition, true); 54337 window.addEventListener("resize", reposition); 54338 return () => { 54339 window.removeEventListener("scroll", reposition, true); 54340 window.removeEventListener("resize", reposition); 54341 }; 54342 } 54343 #disposePopoverListeners() { 54344 this.#popoverListeners.forEach((dispose) => dispose()); 54345 this.#popoverListeners = []; 54346 } 54347 #unlockPopoverScroll() { 54348 this.#unlockScroll?.(); 54349 this.#unlockScroll = null; 54350 } 54351 #emojiPickerComponent() { 54352 return this.#emojiPicker?.component; 54353 } 54354 #emojiNavigationInput() { 54355 const query = this.#activeTrigger?.query || ""; 54356 return { 54357 selectionStart: query.length, 54358 value: query 54359 }; 54360 } 54361 #navigateEmojiPicker(event, direction) { 54362 const component = this.#emojiPickerComponent(); 54363 if (!component?.navigate) return; 54364 component.navigate({ 54365 e: event, 54366 input: this.#emojiNavigationInput(), 54367 [direction]: true 54368 }); 54369 } 54370 #executeSelectedEmoji(event) { 54371 event.preventDefault(); 54372 const component = this.#emojiPickerComponent(); 54373 if (!component?.handleEmojiClick) return; 54374 let pos = component.state?.pos; 54375 if (!Array.isArray(pos) || pos[0] < 0) pos = [0, 0]; 54376 component.handleEmojiClick({ e: event, pos }); 54377 } 54378 #executeEmoji(emoji) { 54379 const editor = this.editorElement.editor; 54380 const trigger = this.#activeTrigger; 54381 if (!trigger) return; 54382 editor.update(() => { 54383 const node = $getNodeByKey4(trigger.key); 54384 if (!$isTextNode5(node)) return; 54385 const text2 = node.getTextContent(); 54386 const queryEnd = trigger.offset + trigger.query.length + 1; 54387 node.setTextContent(`${text2.slice(0, trigger.offset)}${emoji}${text2.slice(queryEnd)}`); 54388 node.select(trigger.offset + emoji.length, trigger.offset + emoji.length); 54389 }); 54390 this.#dismissedTrigger = null; 54391 this.#hidePopover(); 54392 editor.focus(); 54393 } 54394 #dismissCurrentTrigger() { 54395 this.editorElement.editor.getEditorState().read(() => { 54396 this.#dismissedTrigger = this.#readTriggerContext(); 54397 }); 54398 } 54399 #hidePopover() { 54400 this.#showId++; 54401 this.#open = false;
54402 this.#activeTrigger = null; 54403 this.#disposePopoverListeners(); 54404 this.#unlockPopoverScroll(); 54405 this.#popover?.classList.remove("lexxy-prompt-menu--visible"); 54406 this.#popover?.classList.add("hidden"); 54407 this.#popover?.removeAttribute("data-anchored"); 54408 if (this.#popover) this.#popover.hidden = true; 54409 } 54410 #afterPopoverPaint(callback) { 54411 requestAnimationFrame(() => requestAnimationFrame(callback)); 54412 } 54413 #ensureEmojiPickerStyles(attempts = 6) { 54414 const root = this.#popover?.querySelector("em-emoji-picker")?.shadowRoot; 54415 if (root) { 54416 applyCalloutEmojiPickerStyles(root); 54417 return; 54418 } 54419 if (attempts > 0) this.#afterPopoverPaint(() => this.#ensureEmojiPickerStyles(attempts - 1)); 54420 } 54421 #emojiSearchInput() { 54422 const root = this.#popover?.querySelector("em-emoji-picker")?.shadowRoot; 54423 return root?.querySelector( 54424 'input[type="search"], input[placeholder*="Search" i], input[aria-label*="Search" i], input' 54425 ); 54426 } 54427 #focusEmojiSearch(attempts = 6) { 54428 const searchInput = this.#emojiSearchInput(); 54429 if (searchInput instanceof HTMLElement) { 54430 searchInput.focus({ preventScroll: true }); 54431 return; 54432 } 54433 if (attempts > 0) this.#afterPopoverPaint(() => this.#focusEmojiSearch(attempts - 1)); 54434 } 54435 #syncEmojiSearch(query, attempts = 6) { 54436 const component = this.#emojiPickerComponent(); 54437 if (component) { 54438 this.#applyEmojiSearch(component, query); 54439 return; 54440 } 54441 if (attempts > 0) this.#afterPopoverPaint(() => this.#syncEmojiSearch(query, attempts - 1)); 54442 } 54443 async #applyEmojiSearch(component, query) { 54444 const searchId = ++this.#searchId; 54445 const normalizedQuery = query.trim(); 54446 if (!normalizedQuery) { 54447 component.setState?.({ 54448 pos: [-1, -1], 54449 searchResults: null 54450 }); 54451 return; 54452 } 54453 const searchResults = await this.#searchEmojis(normalizedQuery); 54454 if (searchId !== this.#searchId) return; 54455 if (!searchResults) { 54456 component.setState?.({ 54457 pos: [-1, -1], 54458 searchResults 54459 }); 54460 return; 54461 } 54462 const grid = []; 54463 grid.setsize = searchResults.length; 54464 let row = null; 54465 for (const emoji of searchResults) { 54466 if (!grid.length || row.length === component.getPerLine()) { 54467 row = []; 54468 row.__categoryId = "search"; 54469 row.__index = grid.length; 54470 grid.push(row); 54471 } 54472 row.push(emoji); 54473 } 54474 component.ignoreMouse?.(); 54475 component.setState?.( 54476 { 54477 pos: grid.length ? [0, 0] : [-1, -1], 54478 searchResults: grid 54479 }, 54480 () => { 54481 if (component.refs?.scroll?.current) component.refs.scroll.current.scrollTop = 0; 54482 } 54483 ); 54484 } 54485 async #searchEmojis(query) { 54486 const colonPrefixedQuery = `:${query}`; 54487 const [afterColonResults, emoticonResults] = await Promise.all([ 54488 $c4d155af13ad4d4b$export$2e2bcd8739ae039.search(query), 54489 $c4d155af13ad4d4b$export$2e2bcd8739ae039.search(colonPrefixedQuery) 54490 ]); 54491 return this.#mergeEmojiSearchResults(emoticonResults, afterColonResults); 54492 } 54493 #mergeEmojiSearchResults(...resultSets) { 54494 const merged = []; 54495 const seen = /* @__PURE__ */ new Set(); 54496 for (const results of resultSets) { 54497 if (!results?.length) continue; 54498 for (const emoji of results) { 54499 const id3 = emoji?.id; 54500 if (!id3 || seen.has(id3)) continue; 54501 seen.add(id3); 54502 merged.push(emoji); 54503 } 54504 } 54505 return merged.length ? merged : null; 54506 } 54507 #positionPopover() { 54508 if (!this.#popover) return; 54509 const anchorRect = this.#triggerAnchorRect(); 54510 const cursorPosition = this.editorElement.selection?.cursorPosition; 54511 const contentRect = this.editorElement.editorContentElement?.getBoundingClientRect(); 54512 if (!anchorRect && (!cursorPosition || !contentRect)) return; 54513 const x3 = anchorRect ? anchorRect.left : contentRect.left + cursorPosition.x; 54514 const y3 = anchorRect ? anchorRect.bottom : contentRect.top + curs
54514orPosition.y + (cursorPosition.fontSize || 16); 54515 this.#popover.hidden = false; 54516 this.#popover.style.setProperty("--lexxy-prompt-offset-x", `${x3}px`); 54517 this.#popover.style.setProperty("--lexxy-prompt-offset-y", `${y3}px`); 54518 this.#popover.removeAttribute("data-clipped-at-right"); 54519 this.#popover.removeAttribute("data-clipped-at-bottom"); 54520 this.#popover.toggleAttribute("data-anchored", true); 54521 const popoverRect = this.#popover.getBoundingClientRect(); 54522 if (popoverRect.right > window.innerWidth) { 54523 this.#popover.style.setProperty( 54524 "--lexxy-prompt-offset-x", 54525 `${Math.max(8, window.innerWidth - popoverRect.width - 8)}px` 54526 ); 54527 } 54528 if (popoverRect.bottom > window.innerHeight) { 54529 const fallbackTop = anchorRect ? anchorRect.top : contentRect.top + cursorPosition.y; 54530 this.#popover.style.setProperty( 54531 "--lexxy-prompt-offset-y", 54532 `${Math.max(8, fallbackTop - popoverRect.height - 6)}px` 54533 ); 54534 this.#popover.toggleAttribute("data-clipped-at-bottom", true); 54535 } 54536 } 54537 #triggerAnchorRect() { 54538 const trigger = this.#activeTrigger; 54539 if (!trigger) return null; 54540 const textElement = this.editorElement.editor.getElementByKey(trigger.key); 54541 if (!textElement) return null; 54542 const position = this.#textNodePosition(textElement, trigger.offset); 54543 if (!position) return textElement.getBoundingClientRect(); 54544 const range2 = document.createRange(); 54545 range2.setStart(position.node, position.offset); 54546 range2.collapse(true); 54547 const rect = range2.getClientRects()[0] || range2.getBoundingClientRect(); 54548 range2.detach(); 54549 return rect && (rect.width || rect.height) ? rect : textElement.getBoundingClientRect(); 54550 } 54551 #textNodePosition(element, offset3) { 54552 const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT); 54553 let remaining = offset3; 54554 let node = walker.nextNode(); 54555 while (node) { 54556 const length = node.textContent.length; 54557 if (remaining <= length) return { node, offset: remaining }; 54558 remaining -= length; 54559 node = walker.nextNode(); 54560 } 54561 return null; 54562 } 54563 }; 54564 54565
54565// app/javascript/src/lexxy/hex_color_extension.js 54566 var { 54567 $createTextNode: $createTextNode3, 54568 $findMatchingParent: $findMatchingParent6, 54569 $getSelection: $getSelection8, 54570 $isElementNode: $isElementNode7, 54571 $isRangeSelection: $isRangeSelection8, 54572 $isTextNode: $isTextNode6, 54573 COMMAND_PRIORITY_HIGH: COMMAND_PRIORITY_HIGH4, 54574 COMMAND_PRIORITY_LOW: COMMAND_PRIORITY_LOW4, 54575 KEY_ARROW_RIGHT_COMMAND: KEY_ARROW_RIGHT_COMMAND4, 54576 SELECTION_CHANGE_COMMAND: SELECTION_CHANGE_COMMAND3, 54577 TextNode: TextNode4 54578 } = Lexical_exports; 54579 var CARET_ANCHOR = "\u200B"; 54580 function $shouldSkipHexColor(node) { 54581 if (!node.isSimpleText() || node.hasFormat("code")) return true; 54582 return $findMatchingParent6(node, $isCodeNode3) != null; 54583 } 54584 function $transformTextNodeToHexColor(node) { 54585 if ($isHexColorNode(node) || $shouldSkipHexColor(node)) return; 54586 const text2 = node.getTextContent().replaceAll(CARET_ANCHOR, ""); 54587 const match = getHexColorMatch(text2); 54588 if (!match) return; 54589 const rawText = node.getTextContent(); 54590 const rawMatch = getHexColorMatch(rawText); 54591 if (!rawMatch) return; 54592 let targetNode; 54593 if (rawMatch.start === 0) { 54594 [targetNode] = node.splitText(rawMatch.end); 54595 } else { 54596 [, targetNode] = node.splitText(rawMatch.start, rawMatch.end); 54597 } 54598 if (!targetNode) return; 54599 const hexNode = $createHexColorNode(targetNode.getTextContent()); 54600 hexNode.setFormat(targetNode.getFormat()); 54601 targetNode.replace(hexNode); 54602 $ensureTextAnchorBefore(hexNode); 54603 const next = hexNode.getNextSibling(); 54604 if ($isTextNode6(next) && !$isHexColorNode(next)) { 54605 next.selectEnd(); 54606 } else { 54607 hexNode.selectEnd(); 54608 } 54609 } 54610 function $reverseInvalidHexColor(node) { 54611 if (!$isHexColorNode(node)) return; 54612 const text2 = node.getTextContent(); 54613 if (isHexColorValue(text2)) return; 54614 const textNode = $createTextNode3(text2); 54615 textNode.setFormat(node.getFormat()); 54616 node.replace(textNode); 54617 } 54618 function $isCaretAnchorText(node) { 54619 return $isTextNode6(node) && !$isHexColorNode(node); 54620 } 54621 function $ensureTextAnchorBefore(node) { 54622 const prev = node.getPreviousSibling(); 54623 if ($isCaretAnchorText(prev)) { 54624 if (prev.getTextContent() === "") { 54625 prev.setTextContent(CARET_ANCHOR); 54626 } 54627 return prev; 54628 } 54629 const spacer = $createTextNode3(CARET_ANCHOR); 54630 node.insertBefore(spacer); 54631 return spacer; 54632 } 54633 function $selectBeforeHexColor(node) { 54634 $ensureTextAnchorBefore(node).selectEnd(); 54635 } 54636 function $stripConsumedCaretAnchors(node) { 54637 if ($isHexColorNode(node) || !$isTextNode6(node)) return; 54638 const text2 = node.getTextContent(); 54639 if (!text2.includes(CARET_ANCHOR)) return; 54640 if (text2 === CARET_ANCHOR) { 54641 const next = node.getNextSibling(); 54642 if ($isHexColorNode(next)) return; 54643 node.remove(); 54644 return; 54645 } 54646 const cleaned = text2.replaceAll(CARET_ANCHOR, ""); 54647 if (cleaned === text2) return; 54648 if (cleaned === "") { 54649 node.setTextContent(CARET_ANCHOR); 54650 return; 54651 } 54652 const selection = $getSelection8(); 54653 const hadFocus = $isRangeSelection8(selection) && selection.anchor.key === node.getKey(); 54654 const anchorOffset = hadFocus ? selection.anchor.offset : null; 54655 const removedBefore = hadFocus && anchorOffset != null ? (text2.slice(0, anchorOffset).match(new RegExp(CARET_ANCHOR, "g")) || []).length : 0; 54656 node.setTextContent(cleaned); 54657 if (hadFocus && anchorOffset != null) { 54658 const nextOffset = Math.max( 54659 0, 54660 Math.min(anchorOffset - removedBefore, cleaned.length) 54661 ); 54662 node.select(nextOffset, nextOffset); 54663 } 54664 } 54665 function $moveCaretBeforeHexColorAtStart() { 54666 const selection = $getSelection8(); 54667 if (!$isRangeSelection8(selection) || !selection.isCollapsed()) return false; 54668 const anchorNode = selection.anchor.getNode(); 54669 if ($isHexColorNode(anchorNode) && selection.anchor.offset === 0) { 54670 $selectBeforeHexColor(anchorNode); 54671 return true; 54672 } 54673 if ($isElementNode7(anchorNode)) { 54674 const child = anchorNode.getChildAtIndex(selection.anchor.offset); 54675 if ($isHexColorNode(child)) { 54676 $selectBeforeHexColor(child); 54677 return true; 54678 } 54679 } 54680 return false;
54681 } 54682 function $enterHexColorFromLeft(event) { 54683 const selection = $getSelection8(); 54684 if (!$isRangeSelection8(selection) || !selection.isCollapsed()) return false; 54685 const anchorNode = selection.anchor.getNode(); 54686 if ($isHexColorNode(anchorNode) && selection.anchor.offset === 0) { 54687 event.preventDefault(); 54688 const size2 = anchorNode.getTextContentSize(); 54689 anchorNode.select(Math.min(1, size2), Math.min(1, size2)); 54690 return true; 54691 } 54692 if ($isTextNode6(anchorNode) && !$isHexColorNode(anchorNode)) { 54693 const atEnd = selection.anchor.offset === anchorNode.getTextContentSize(); 54694 const next = atEnd ? anchorNode.getNextSibling() : null; 54695 if ($isHexColorNode(next)) { 54696 event.preventDefault(); 54697 const size2 = next.getTextContentSize(); 54698 next.select(Math.min(1, size2), Math.min(1, size2)); 54699 return true; 54700 } 54701 } 54702 if ($isElementNode7(anchorNode)) { 54703 const child = anchorNode.getChildAtIndex(selection.anchor.offset); 54704 if ($isHexColorNode(child)) { 54705 event.preventDefault(); 54706 const size2 = child.getTextContentSize(); 54707 child.select(Math.min(1, size2), Math.min(1, size2)); 54708 return true; 54709 } 54710 } 54711 return false; 54712 } 54713 var HexColorExtension = class extends LexxyExtension { 54714 get enabled() { 54715 return this.editorElement.supportsRichText; 54716 } 54717 get allowedElements() { 54718 return [ 54719 { 54720 tag: "span", 54721 attributes: ["class", "style"] 54722 } 54723 ]; 54724 } 54725 get lexicalExtension() { 54726 return this.defineExtension({ 54727 name: "lexxy/hex-color", 54728 nodes: [HexColorNode], 54729 register: (editor) => mergeRegister3( 54730 editor.registerNodeTransform(TextNode4, $transformTextNodeToHexColor), 54731 editor.registerNodeTransform(TextNode4, $stripConsumedCaretAnchors), 54732 editor.registerNodeTransform(HexColorNode, $reverseInvalidHexColor), 54733 editor.registerCommand( 54734 SELECTION_CHANGE_COMMAND3, 54735 () => $moveCaretBeforeHexColorAtStart(), 54736 COMMAND_PRIORITY_HIGH4 54737 ), 54738 editor.registerCommand( 54739 KEY_ARROW_RIGHT_COMMAND4, 54740 (event) =>
54740 $enterHexColorFromLeft(event), 54741 COMMAND_PRIORITY_LOW4 54742 ) 54743 ) 54744 }); 54745 } 54746 }; 54747 54748
54748// app/javascript/src/lexxy/image_layout.js 54749 var IMAGE_LAYOUT_CONTENT_KEY = "lexxyImage"; 54750 var IMAGE_SIZE_OPTIONS = [ 54751 { value: "auto", label: "Auto" }, 54752 { value: "small", label: "Small" }, 54753 { value: "medium", label: "Medium" }, 54754 { value: "full", label: "Full" } 54755 ]; 54756 var IMAGE_ALIGN_OPTIONS = [ 54757 { value: "left", label: "Left" }, 54758 { value: "center", label: "Center" }, 54759 { value: "right", label: "Right" } 54760 ]; 54761 function parseLayoutContent(content) { 54762 if (!content) return {}; 54763 if (typeof content === "object") return content; 54764 return JSON.parse(content); 54765 } 54766 function parseImageLayout(content) { 54767 if (!content) return defaultImageLayout(); 54768 try { 54769 const parsed = parseLayoutContent(content); 54770 const layout = parsed?.[IMAGE_LAYOUT_CONTENT_KEY] || {}; 54771 return { 54772 size: validValue(layout.size, IMAGE_SIZE_OPTIONS, "auto"), 54773 align: validValue(layout.align, IMAGE_ALIGN_OPTIONS, "center") 54774 }; 54775 } catch { 54776 return defaultImageLayout(); 54777 } 54778 } 54779 function serializeImageLayout(content, layout) { 54780 let parsed = {}; 54781 try { 54782 parsed = content ? parseLayoutContent(content) : {}; 54783 } catch { 54784 parsed = {}; 54785 } 54786 const normalized = { 54787 size: validValue(layout.size, IMAGE_SIZE_OPTIONS, "auto"), 54788 align: validValue(layout.align, IMAGE_ALIGN_OPTIONS, "center") 54789 }; 54790 if (normalized.size === "auto" && normalized.align === "center") { 54791 delete parsed[IMAGE_LAYOUT_CONTENT_KEY]; 54792 } else { 54793 parsed[IMAGE_LAYOUT_CONTENT_KEY] = normalized; 54794 } 54795 return Object.keys(parsed).length ? JSON.stringify(parsed) : null; 54796 } 54797 function defaultImageLayout() { 54798 return { size: "auto", align: "center" }; 54799 } 54800 function validValue(value, options, fallback) { 54801 return options.some((option) => option.value === value) ? value : fallback; 54802 } 54803 54804
54804// app/javascript/src/lexxy/image_tools.js 54805 var { 54806 $getNodeByKey: $getNodeByKey5, 54807 $getSelection: $getSelection9, 54808 $isNodeSelection: $isNodeSelection3 54809 } = Lexical_exports; 54810 var SIZE_ICONS = { 54811 auto: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 12v-6a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v6"></path><path d="M10 18h-7"></path><path d="M21 18h-7"></path><path d="M6 15l-3 3l3 3"></path><path d="M18 15l3 3l-3 3"></path></g></svg>`, 54812 small: `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" class="!size-3" aria-hidden="true" focusable="false"><g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.25" stroke="currentColor"><rect x="1.25" y="1.25" width="9.5" height="9.5" rx="2" ry="2"></rect></g></svg>`, 54813 medium: `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"><g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.25" stroke="currentColor"><rect x="2.75" y="2.75" width="12.5" height="12.5" rx="2" ry="2"></rect></g></svg>`, 54814 full: `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" aria-hidden="true" focusable="false"><g fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.25" stroke="currentColor"><rect x="2.75" y="2.75" width="12.5" height="12.5" rx="2" ry="2"></rect><polyline points="12.25 8.75 12.25 5.75 9.25 5.75"></polyline><polyline points="8.75 12.25 5.75 12.25 5.75 9.25"></polyline></g></svg>` 54815 }; 54816 var ALIGN_ICONS = { 54817 left: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 6l16 0"></path><path d="M4 12l10 0"></path><path d="M4 18l14 0"></path></g></svg>`, 54818 center: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 6l16 0"></path><path d="M8 12l8 0"></path><path d="M6 18l12 0"></path></g></svg>`, 54819 right: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><g stroke-linejoin="round" stroke-linecap="round" stroke-width="2" fill="none" stroke="currentColor"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 6l16 0"></path><path d="M10 12l10 0"></path><path d="M6 18l14 0"></path></g></svg>` 54820 }; 54821 var ImageToolsElement = class extends HTMLElement { 54822 #updateListener = null; 54823 #activeImageKey = null; 54824 connectedCallback() { 54825 this.editorElement = this.closest("lexxy-editor"); 54826 this.editor = this.editorElement.editor; 54827 this.classList.add("lexxy-floating-controls", "lexxy-image-tools"); 54828 this.#buildUI(); 54829 this.#hide(); 54830 this.#monitorSelection(); 54831 } 54832 disconnectedCallback() { 54833 this.#updateListener?.(); 54834 this.#updateListener = null; 54835 this.editor = null; 54836 this.editorElement = null; 54837 } 54838 #buildUI() { 54839 this.innerHTML = ` 54840 <div class="lexxy-floating-controls__group lexxy-image-tools__bar" role="toolbar" aria-label="Image options"> 54841 <div class="lexxy-image-tools__section" aria-label="Image width"> 54842 ${IMAGE_SIZE_OPTIONS.map((option) => this.#button("size", option, SIZE_ICONS[option.value])).join("")} 54843 </div> 54844 <div class="lexxy-image-tools__section" aria-label="Image alignment"> 54845 ${IMAGE_ALIGN_OPTIONS.map((option) => this.#button("align", option, ALIGN_ICONS[option.value])).join("")} 54846 </div> 54847 </div> 54848 `; 54849 this.addEventListener("mousedown", (event) => { 54850 if (event.target.closest("button")) event.preventDefault(); 54851 }); 54852 this.addEventListener("click", (event) => this.#handleClick(event)); 54853 } 54854 #button(type, option, icon) { 54855 return ` 54856 <button 54857 type="button" 54858 data-image-${type}="${option.value}" 54859 aria-label="${option.label}" 54860 title="${option.label}" 54861 > 54862 ${icon}
54863 <span>${option.label}</span> 54864 </button> 54865 `; 54866 } 54867 #handleClick(event) { 54868 const sizeButton = event.target.closest("[data-image-size]"); 54869 if (sizeButton) { 54870 event.preventDefault(); 54871 this.#setLayout({ size: sizeButton.dataset.imageSize }); 54872 return; 54873 } 54874 const alignButton = event.target.closest("[data-image-align]"); 54875 if (alignButton) { 54876 event.preventDefault(); 54877 this.#setLayout({ align: alignButton.dataset.imageAlign }); 54878 } 54879 } 54880 #setLayout(patch2) { 54881 const imageKey = this.#activeImageKey; 54882 if (!imageKey) return; 54883 let content = null; 54884 let imageFound = false; 54885 this.editor.getEditorState().read(() => { 54886 const image = $getNodeByKey5(imageKey); 54887 if (!$isResizableImageNode(image)) return; 54888 imageFound = true; 54889 const layout = { ...parseImageLayout(image.content), ...patch2 }; 54890 content = serializeImageLayout(image.content, layout); 54891 }); 54892 if (!imageFound) return; 54893 this.editor.dispatchCommand(REWRITE_HISTORY_COMMAND, { 54894 [imageKey]: { patch: { content } } 54895 }); 54896 this.editor.focus(); 54897 } 54898 #monitorSelection() { 54899 this.#updateListener = this.editor.registerUpdateListener(({ editorState }) => { 54900 editorState.read(() => { 54901 const image = $getSelectedImageNode(); 54902 if (image) { 54903 this.#activeImageKey = image.getKey(); 54904 this.#syncUI(image); 54905 this.#show(image); 54906 } else { 54907 this.#activeImageKey = null; 54908 this.#hide(); 54909 } 54910 }); 54911 }); 54912 } 54913 #syncUI(image) { 54914 const layout = parseImageLayout(image.content); 54915 this.querySelectorAll("[data-image-size]").forEach((button) => { 54916 button.toggleAttribute("aria-selected", button.dataset.imageSize === layout.size); 54917 }); 54918 this.querySelectorAll("[data-image-align]").forEach((button) => { 54919 button.toggleAttribute("aria-selected", button.dataset.imageAlign === layout.align); 54920 }); 54921 } 54922 #show(image) { 54923 const imageElement = this.editor.getElementByKey(image.getKey()); 54924 if (!imageElement) return; 54925 const imageRect = imageElement.getBoundingClientRect(); 54926 const editorRect = this.editorElement.getBoundingClientRect(); 54927 const top = imageRect.top - editorRect.top; 54928 const left = imageRect.left - editorRect.left + imageRect.width / 2; 54929 this.style.top = `${top}px`; 54930 this.style.left = `${left}px`; 54931 this.hidden = false; 54932 } 54933 #hide() { 54934 this.hidden = true; 54935 } 54936 }; 54937 function $getSelectedImageNode() { 54938 const selection = $getSelection9(); 54939 if (!$isNodeSelection3(selection)) return null; 54940 return selection.getNodes().find($isResizableImageNode) || null; 54941 } 54942 function $isResizableImageNode(node) { 54943 return $isActionTextAttachmentNode(node) && (node.isPreviewableImage || node.fileName?.toLowerCase().endsWith(".avif")); 54944 } 54945 if (!customElements.get("lexxy-image-tools")) { 54946 customElements.define("lexxy-image-tools", ImageToolsElement); 54947 } 54948 54949
54949// app/javascript/src/lexxy/image_extension.js 54950 var ImageExtension = class extends LexxyExtension { 54951 get enabled() { 54952 return this.editorElement.supportsRichText && this.editorElement.supportsAttachments; 54953 } 54954 initializeToolbar(_toolbar) { 54955 this.#ensureImageTools(); 54956 } 54957 #ensureImageTools() { 54958 if (this.editorElement.querySelector("lexxy-image-tools")) return; 54959 this.editorElement.appendChild(document.createElement("lexxy-image-tools")); 54960 } 54961 }; 54962 54963
54963// app/javascript/src/lexxy/toggle_list_node.js 54964 var { 54965 $applyNodeReplacement: $applyNodeReplacement5, 54966 $createParagraphNode: $createParagraphNode6, 54967 $findMatchingParent: $findMatchingParent7, 54968 $getSelection: $getSelection10, 54969 $isElementNode: $isElementNode8, 54970 $isParagraphNode: $isParagraphNode5, 54971 $isRangeSelection: $isRangeSelection9, 54972 ElementNode: ElementNode4, 54973 INTERNAL_$isBlock: INTERNAL_$isBlock5 54974 } = Lexical_exports; 54975 var TOGGLE_LIST_CLASS = "lexxy-toggle-list"; 54976 var TOGGLE_LIST_BUTTON_CLASS = "lexxy-toggle-list__button"; 54977 var ToggleListNode = class _ToggleListNode extends ElementNode4 { 54978 __open = true; 54979 static getType() { 54980 return "lexxy-toggle-list"; 54981 } 54982 static clone(node) { 54983 return new _ToggleListNode(node.__open, node.__key); 54984 } 54985 constructor(open = true, key) { 54986 super(key); 54987 this.__open = open !== false; 54988 } 54989 createDOM() { 54990 const element = document.createElement("div"); 54991 element.className = TOGGLE_LIST_CLASS; 54992 element.dataset.lexxyToggleKey = this.getKey(); 54993 const button = document.createElement("button"); 54994 button.type = "button"; 54995 button.className = TOGGLE_LIST_BUTTON_CLASS; 54996 button.contentEditable = "false"; 54997 button.tabIndex = -1; 54998 button.setAttribute("aria-label", "Toggle list contents"); 54999 button.innerHTML = ` 55000 <svg aria-hidden="true" focusable="false" viewBox="0 0 12 12"> 55001 <path d="M1.5 2.31061C1.5 0.943037 2.99801 0.103919 4.16406 0.818427L10.1855 4.50788C11.2997 5.19065 11.2997 6.80949 10.1855 7.49226L4.16406 11.1817C2.99802 11.8962 1.5 11.0571 1.5 9.68952V2.31061Z" fill="currentColor"></path> 55002 </svg> 55003 `; 55004 element.append(button); 55005 this.#syncDom(element); 55006 return element; 55007 } 55008 updateDOM(prevNode, dom) { 55009 dom.dataset.lexxyToggleKey = this.getKey(); 55010 if (prevNode.__open !== this.__open) { 55011 this.#syncDom(dom); 55012 } 55013 return false; 55014 } 55015 #syncDom(element) { 55016 const open = this.__open ? "true" : "false"; 55017 element.dataset.open = open; 55018 element.setAttribute("aria-expanded", open); 55019 element.querySelector(`.${TOGGLE_LIST_BUTTON_CLASS}`)?.setAttribute("aria-expanded", open); 55020 } 55021 static importDOM() { 55022 const convert = (domNode) => { 55023 if (!domNode.classList.contains(TOGGLE_LIST_CLASS)) return null; 55024 return { 55025 conversion: () => ({ 55026 node: $createToggleListNode(domNode.dataset.open !== "false") 55027 }), 55028 priority: 2 55029 }; 55030 }; 55031 return { div: convert }; 55032 } 55033 exportDOM(editor) { 55034 const { element } = super.exportDOM(editor); 55035 if (element) { 55036 element.className = TOGGLE_LIST_CLASS; 55037 this.#syncDom(element); 55038 element.removeAttribute("data-lexxy-toggle-key"); 55039 element.querySelector(`.${TOGGLE_LIST_BUTTON_CLASS}`)?.remove(); 55040 } 55041 return { element }; 55042 } 55043 static importJSON(serializedNode) { 55044 return $createToggleListNode(serializedNode.open !== false); 55045 } 55046 exportJSON() { 55047 return { 55048 ...super.exportJSON(), 55049 type: "lexxy-toggle-list", 55050 open: this.__open, 55051 version: 1 55052 }; 55053 } 55054 insertNewAfter(_selection, restoreSelection) { 55055 const paragraph = $createParagraphNode6(); 55056 this.insertAfter(paragraph, restoreSelection); 55057 return paragraph; 55058 } 55059 collapseAtStart() { 55060 const children = [...this.getChildren()]; 55061 const firstChild = children[0]; 55062 if (!firstChild) { 55063 const paragraph = $createParagraphNode6(); 55064 this.replace(paragraph); 55065 paragraph.selectStart(); 55066 return true; 55067 } 55068 children.forEach((child) => this.insertBefore(child)); 55069 this.remove(); 55070 firstChild.selectStart?.(); 55071 return true; 55072 } 55073 canBeEmpty() { 55074 return false; 55075 } 55076 isShadowRoot() { 55077 return true; 55078 } 55079 canIndent() { 55080 return false; 55081 } 55082 canMergeWhenEmpty() { 55083 return true; 55084 } 55085 setOpen(open) { 55086 const self2 = this.getWritable(); 55087 self2.__open = open !== false; 55088 return self2; 55089 } 55090 toggleOpen() { 55091 return this.setOpen(!this.getOpen()); 55092 } 55093 getOpen() { 55094 return this.getLatest().__open; 55095 } 55096 }; 55097 function $createToggleListNode(open = true) { 55098 return $applyNodeReplacement5(new ToggleListNode(open)); 55099 } 55100 function $isToggleListNode(node) { 55101 return node instanceof ToggleListNode; 55102 } 55103 function $isToggleTitleBlock(node) { 55104 return $isParagraphNode5(node) || $isHeadingNode2(node); 55105 } 55106 function $selectionBlock2(selection) { 55107 const anchorNode = selection.anchor.getNode(); 55108 if ($isElementNode8(anchorNode) && INTERNAL_$isBlock5(anchorNode)) return anchorNode; 55109 const block = $findMatchingParent7( 55110 anchorNode, 55111 (node) => $isElementNode8(node) && INTERNAL_$isBlock5(node) 55112 ); 55113 if ($isElementNode8(block)) return block; 55114 if ($isElementNode8(anchorNode) && anchorNode.isShadowRoot() && selection.anchor.type === "element") { 55115 const index = selection.anchor.offset; 55116 const child = anchorNode.getChildAtIndex(index) || anchorNode.getChildAtIndex(Math.max(0, index - 1)); 55117 if ($isElementNode8(child) && INTERNAL_$isBlock5(child)) return child; 55118 } 55119 return null; 55120 } 55121 function $selectionListItem(selection) { 55122 return $findMatchingParent7(selection.anchor.getNode(), $isListItemNode2); 55123 } 55124 function $normalizeToggleListBody(toggleList) { 55125 const children = [...toggleList.getLatest().getChildren()]; 55126 if (children.length <= 1) return; 55127 let inlineRun = []; 55128 const flushInlineRun = () => { 55129 if (inlineRun.length === 0) return; 55130 const paragraph = $createParagraphNode6(); 55131 inlineRun[0].insertBefore(paragraph);
55132 inlineRun.forEach((node) => paragraph.append(node)); 55133 inlineRun = []; 55134 }; 55135 for (let index = 1; index < children.length; index += 1) { 55136 const child = children[index]; 55137 if ($isValidContainerContentNode(child)) { 55138 flushInlineRun(); 55139 } else { 55140 inlineRun.push(child); 55141 } 55142 } 55143 flushInlineRun(); 55144 } 55145 function $normalizeToggleListTitle(toggleList) { 55146 const children = [...toggleList.getLatest().getChildren()]; 55147 if (children.length === 0) return; 55148 if ($isToggleTitleBlock(children[0])) return; 55149 let inlineRun = []; 55150 const flushInlineRun = () => { 55151 if (inlineRun.length === 0) return; 55152 const paragraph = $createParagraphNode6(); 55153 inlineRun[0].insertBefore(paragraph); 55154 inlineRun.forEach((node) => paragraph.append(node)); 55155 inlineRun = []; 55156 }; 55157 for (const child of children) { 55158 if ($isToggleTitleBlock(child)) { 55159 flushInlineRun(); 55160 break; 55161 } 55162 if ($isValidContainerContentNode(child)) { 55163 flushInlineRun(); 55164 break; 55165 } 55166 inlineRun.push(child); 55167 } 55168 flushInlineRun(); 55169 } 55170 function $extractToggleTitleAttachments(toggleList) { 55171 const title = toggleList.getFirstChild(); 55172 if (!$isToggleTitleBlock(title)) return; 55173 const attachments = title.getChildren().filter($isCustomActionTextAttachmentNode); 55174 let insertionPoint = toggleList; 55175 attachments.forEach((attachment) => { 55176 const paragraph = $createParagraphNode6(); 55177 insertionPoint.insertAfter(paragraph); 55178 paragraph.append(attachment); 55179 insertionPoint = paragraph; 55180 }); 55181 } 55182 function $extractToggleTitleAttachment(attachment) { 55183 const title = $findMatchingParent7(attachment, $isToggleTitleBlock); 55184 if (!$isToggleTitleBlock(title)) return; 55185 const toggleList = $findMatchingParent7(title, $isToggleListNode); 55186 if (!$isToggleListNode(toggleList) || !toggleList.getFirstChild()?.is(title)) return; 55187 $extractToggleTitleAttachments(toggleList); 55188 } 55189 function $normalizeToggleListContent(toggleList) { 55190 if (toggleList.getLatest().getChildrenSize() === 0) { 55191 toggleList.append($createParagraphNode6()); 55192 return; 55193 } 55194 $normalizeToggleListTitle(toggleList); 55195 $normalizeToggleListBody(toggleList); 55196 } 55197 function $insertToggleList() { 55198 const selection = $getSelection10(); 55199 if (!$isRangeSelection9(selection)) return; 55200 const listItem = $selectionListItem(selection); 55201 if ($isListItemNode2(listItem)) { 55202 $insertToggleListFromListItem(listItem); 55203 return; 55204 } 55205 const toggleList = $createToggleListNode(false); 55206 const block = $selectionBlock2(selection); 55207 if (!block || $isToggleListNode(block)) return; 55208 block.insertBefore(toggleList); 55209 toggleList.append(block); 55210 block.selectStart(); 55211 } 55212 function $insertToggleListFromListItem(listItem) { 55213 const toggleList = $createToggleListNode(false); 55214 const title = $createParagraphNode6(); 55215 const children = [...listItem.getChildren()]; 55216 const bodyChildren = []; 55217 children.forEach((child) => { 55218 if ($isListNode2(child)) { 55219 bodyChildren.push(child); 55220 } else if ($isElementNode8(child) && INTERNAL_$isBlock5(child)) { 55221 title.append(...child.getChildren()); 55222 child.remove(); 55223 } else { 55224 title.append(child); 55225 } 55226 }); 55227 toggleList.append(title, ...bodyChildren); 55228 listItem.insertAfter(toggleList); 55229 listItem.remove(); 55230 title.selectStart(); 55231 } 55232 55233
55233// app/javascript/src/lexxy/toggle_list_content_blocks.js 55234 var { $isElementNode: $isElementNode9, $isParagraphNode: $isParagraphNode6, $isTextNode: $isTextNode7 } = Lexical_exports; 55235 var TOGGLE_BODY_STRUCTURE_SELECTOR = ".lexxy-toggle-list, .lexxy-callout, .lexxy-content__table-wrapper, table, ul, ol, blockquote, pre, figure.horizontal-divider, figure, action-text-attachment, .attachment, .attachment-gallery, hr, h1, h2, h3, h4, h5, h6"; 55236 function domToggleBlockHasContent(block) { 55237 if (!block?.matches) return false; 55238 if (block.matches(TOGGLE_BODY_STRUCTURE_SELECTOR)) return true; 55239 if (block.querySelector(TOGGLE_BODY_STRUCTURE_SELECTOR)) return true; 55240 if (block.textContent.trim() !== "") return true; 55241 if (block.matches("figure, action-text-attachment, .attachment, .attachment-gallery")) return true; 55242 if (block.querySelector("img, video, iframe, figure, action-text-attachment, .attachment, .attachment-gallery")) { 55243 return true; 55244 } 55245 return Array.from(block.childNodes).some((child) => { 55246 if (child.nodeType === Node.TEXT_NODE) return child.textContent.trim() !== ""; 55247 if (child.nodeName === "BR") return false; 55248 return child.nodeType === Node.ELEMENT_NODE && child.textContent.trim() !== ""; 55249 }); 55250 } 55251 function $lexicalToggleBlockHasContent(node) { 55252 if (node.getTextContent().trim() !== "") return true; 55253 if ($isToggleListNode(node) || $isCalloutNode(node)) return true; 55254 if (!$isElementNode9(node)) return false; 55255 if (!$isParagraphNode6(node)) return true; 55256 return node.getChildren().some((child) => !$isTextNode7(child)); 55257 } 55258 55259
55259// app/javascript/src/lexxy/toggle_list_title_commands.js 55260 var { 55261 $createNodeSelection: $createNodeSelection3, 55262 $createParagraphNode: $createParagraphNode7, 55263 $createTextNode: $createTextNode4, 55264 $findMatchingParent: $findMatchingParent8, 55265 $getSelection: $getSelection11, 55266 $isElementNode: $isElementNode10, 55267 $isParagraphNode: $isParagraphNode7, 55268 $isRangeSelection: $isRangeSelection10, 55269 $isTextNode: $isTextNode8, 55270 $setSelection: $setSelection3 55271 } = Lexical_exports; 55272 var CONVERTIBLE_KINDS = /* @__PURE__ */ new Set(["toggle", "bullet", "number", "check", "quote", "callout", "code"]); 55273 var TITLE_FORMAT_KINDS = /* @__PURE__ */ new Set(["paragraph", "h1", "h2", "h3", "h4"]); 55274 function $toggleTitleContext(selection) { 55275 const anchorNode = selection.anchor.getNode(); 55276 const block = $isToggleTitleBlock(anchorNode) ? anchorNode : $findMatchingParent8(anchorNode, $isToggleTitleBlock); 55277 if (!block) return null; 55278 const toggleList = $findMatchingParent8(block, $isToggleListNode); 55279 if (!$isToggleListNode(toggleList) || !toggleList.getFirstChild()?.is(block)) return null; 55280 return { toggleList, title: block }; 55281 } 55282 function $isToggleListFullyEmpty(context) { 55283 if (context.title.getTextContent().trim() !== "") return false; 55284 const bodyChildren = context.toggleList.getChildren().filter((child) => !child.is(context.title)); 55285 return bodyChildren.every((child) => !$lexicalToggleBlockHasContent(child)); 55286 } 55287 function $routeToggleTitleCommand(kind, { editor } = {}) { 55288 const selection = $getSelection11(); 55289 if (!$isRangeSelection10(selection)) return false; 55290 const context = $toggleTitleContext(selection); 55291 if (!context) return false; 55292 if (TITLE_FORMAT_KINDS.has(kind)) { 55293 return $formatToggleTitle(context, kind); 55294 } 55295 const fullyEmpty = $isToggleListFullyEmpty(context); 55296 if (fullyEmpty && CONVERTIBLE_KINDS.has(kind)) { 55297 return $convertToggleTitleByKind(context, kind); 55298 } 55299 return $insertAfterToggleByKind(context, kind, { editor }); 55300 } 55301 function $removeToggleTitleShortcutText(marker) { 55302 const selection = $getSelection11(); 55303 if (!$isRangeSelection10(selection) || !selection.isCollapsed()) return; 55304 const anchorNode = selection.anchor.getNode(); 55305 if (!$isTextNode8(anchorNode)) return; 55306 const offset3 = selection.anchor.offset; 55307 const textBeforeCursor = anchorNode.getTextContent().slice(0, offset3); 55308 const markerText = typeof marker === "string" ? marker : marker.source; 55309 const shortcutIndex = typeof marker === "string" ? textBeforeCursor.lastIndexOf(marker) : (() => { 55310 const match = textBeforeCursor.match(marker); 55311 if (!match || match.index === void 0) return -1; 55312 return match.index; 55313 })(); 55314 if (shortcutIndex === -1) return; 55315 const textBeforeShortcut = textBeforeCursor.slice(0, shortcutIndex); 55316 if (textBeforeShortcut && !textBeforeShortcut.endsWith("\n")) return; 55317 anchorNode.spliceText(shortcutIndex, offset3 - shortcutIndex, "", true); 55318 } 55319 function $replaceToggleWithNode(context, replacement) { 55320 const body = context.toggleList.getChildren().filter((child) => !child.is(context.title)); 55321 context.toggleList.insertBefore(replacement); 55322 let previous = replacement; 55323 body.forEach((child) => { 55324 previous.insertAfter(child); 55325 previous = child; 55326 }); 55327 context.toggleList.remove(); 55328 $selectInsertedNode(replacement); 55329 return true; 55330 } 55331 function $moveTitleChildrenInto(node, title) { 55332 const children = [...title.getChildren()]; 55333 if (children.length > 0) { 55334 node.append(...children); 55335 return; 55336 } 55337 if ($isParagraphNode7(node) || $isElementNode10(node)) { 55338 node.append($createParagraphNode7()); 55339 } 55340 } 55341 function $formatToggleTitle(context, kind) { 55342 const replacement = kind === "paragraph" ? $createParagraphNode7() : $createHeadingNode2(kind); 55343 context.title.replace(replacement, true); 55344 return true; 55345 } 55346 function $convertToggleTitleByKind(context, kind) { 55347 switch (kind) { 55348 case "toggle": 55349 return $convertEmptyToggleToParagraph(context); 55350 case "bullet": 55351 return $convertToggleToList(context, "bullet"); 55352 case "number": 55353 return $convertToggleToList(context, "number"); 55354 case "check": 55355 return $convertToggleToList(context, "check"); 55356 case "quote": 55357 return $convertToggleToQuote(context); 55358 case "callout": 55359 return $convertToggleToCallout(context); 55360 case "code": 55361 return $convertToggleToCode(context); 55362 default: 55363 return false;
55364 } 55365 } 55366 function $convertEmptyToggleToParagraph(context) { 55367 const paragraph = $createParagraphNode7(); 55368 $moveTitleChildrenInto(paragraph, context.title); 55369 return $replaceToggleWithNode(context, paragraph); 55370 } 55371 function $convertToggleToList(context, listType) { 55372 const list = $createListNode2(listType); 55373 const item = $createListItemNode2(listType === "check" ? false : void 0); 55374 $moveTitleChildrenInto(item, context.title); 55375 list.append(item); 55376 return $replaceToggleWithNode(context, list); 55377 } 55378 function $convertToggleToQuote(context) { 55379 const quote = $createQuoteNode2(); 55380 $moveTitleChildrenInto(quote, context.title); 55381 return $replaceToggleWithNode(context, quote); 55382 } 55383 function $convertToggleToCallout(context) { 55384 const callout = $createCalloutNode(); 55385 $moveTitleChildrenInto(callout, context.title); 55386 return $replaceToggleWithNode(context, callout); 55387 } 55388 function $convertToggleToCode(context) { 55389 const code = $createCodeNode3(); 55390 const titleText = context.title.getTextContent(); 55391 if (titleText) code.append($createTextNode4(titleText)); 55392 return $replaceToggleWithNode(context, code); 55393 } 55394 function $insertAfterToggleByKind(context, kind, { editor } = {}) { 55395 switch (kind) { 55396 case "toggle": 55397 return $insertToggleListAfterToggle(context); 55398 case "bullet": 55399 return $insertListAfterToggle(context, "bullet"); 55400 case "number": 55401 return $insertListAfterToggle(context, "number"); 55402 case "check": 55403 return $insertListAfterToggle(context, "check"); 55404 case "quote": 55405 return $insertQuoteAfterToggle(context); 55406 case "callout": 55407 return $insertCalloutAfterToggle(context); 55408 case "code": 55409 return $insertCodeAfterToggle(context); 55410 case "table": 55411 return $insertTableAfterToggle(context, editor); 55412 case "divider": 55413 return $insertDividerAfterToggle(context); 55414 default: 55415 return false; 55416 } 55417 } 55418 function $insertToggleListAfterToggle(context) { 55419 const toggleList = $createToggleListNode(false); 55420 const title = $createParagraphNode7(); 55421 toggleList.append(title); 55422 context.toggleList.insertAfter(toggleList); 55423 title.selectStart(); 55424 return true; 55425 } 55426 function $insertListAfterToggle(context, listType) { 55427 const list = $createListNode2(listType); 55428 const item = $createListItemNode2(listType === "check" ? false : void 0); 55429 list.append(item); 55430 context.toggleList.insertAfter(list); 55431 item.selectStart(); 55432 return true; 55433 } 55434 function $insertQuoteAfterToggle(context) { 55435 const quote = $createQuoteNode2(); 55436 const paragraph = $createParagraphNode7(); 55437 quote.append(paragraph); 55438 context.toggleList.insertAfter(quote); 55439 paragraph.selectStart(); 55440 return true; 55441 } 55442 function $insertCalloutAfterToggle(context) { 55443 const callout = $createCalloutNode(); 55444 const paragraph = $createParagraphNode7(); 55445 callout.append(paragraph); 55446 context.toggleList.insertAfter(callout); 55447 paragraph.selectStart(); 55448 return true; 55449 } 55450 function $insertCodeAfterToggle(context) { 55451 const code = $createCodeNode3(); 55452 context.toggleList.insertAfter(code); 55453 code.selectStart(); 55454 return true; 55455 } 55456 function $insertDividerAfterToggle(context) { 55457 const divider = new HorizontalDividerNode(); 55458 context.toggleList.insertAfter(divider); 55459 const selection = $createNodeSelection3(); 55460 selection.add(divider.getKey()); 55461 $setSelection3(selection); 55462 return true; 55463 } 55464 function $insertTableAfterToggle(context, editor) { 55465 if (!editor) return false; 55466 const paragraph = $createParagraphNode7(); 55467 context.toggleList.insertAfter(paragraph); 55468 paragraph.selectStart(); 55469 editor.dispatchCommand(INSERT_TABLE_COMMAND2, { rows: 3, columns: 3, includeHeaders: true }); 55470 const table = context.toggleList.getNextSibling() instanceof TableNode2 && context.toggleList.getNextSibling() || $findMatchingParent8(paragraph, (node) => node instanceof TableNode2); 55471 if (table instanceof TableNode2) $selectFirstTableCell(table); 55472 return true; 55473 } 55474 function $selectFirstTableCell(table) { 55475 const firstCell = table?.getFirstChild()?.getFirstChild(); 55476 const firstCellContent = firstCell?.getFirstChild(); 55477 if (firstCellContent?.selectStart) { 55478 firstCellContent.selectStart(); 55479 } else { 55480 firstCell?.selectStart?.(); 55481 } 55482 } 55483 function $selectInsertedNode(node) { 55484 if (node.selectStart) { 55485 node.selectStart(); 55486 return; 55487 } 55488 const firstChild = node.getFirstChild(); 55489 if (firstChild?.selectStart) { 55490 firstChild.selectStart(); 55491 return; 55492 } 55493 node.selectEnd?.(); 55494 } 55495 var TOGGLE_TITLE_MARKDOWN_SHORTCUTS = [ 55496 { kind: "toggle", pattern: /(?:^|\n)>\s?$/, marker: ">" }, 55497 { kind: "bullet", pattern: /(?:^|\n)-\s?$/, marker: "-" }, 55498 { kind: "number", pattern: /(?:^|\n)\d+\.\s?$/, marker: /\d+\.$/ }, 55499 { kind: "check", pattern: /(?:^|\n)\[\]\s?$/, marker: "[]" }, 55500 { kind: "quote", pattern: /(?:^|\n)"\s?$/, marker: '"' }, 55501 { kind: "divider", pattern: /(?:^|\n)---\s?$/, marker: "---" }, 55502 { kind: "code", pattern: /(?:^|\n)```\s?$/, marker: "```" } 55503 ]; 55504 function $toggleTitleMarkdownShortcutMatch() { 55505 const selection = $getSelection11(); 55506 if (!$isRangeSelection10(selection) || !selection.isCollapsed()) return null; 55507 if (!$toggleTitleContext(selection)) return null; 55508 const anchorNode = selection.anchor.getNode(); 55509 if (!$isTextNode8(anchorNode)) return null; 55510 const textBeforeCursor = anchorNode.getTextContent().slice(0, selection.anchor.offset); 55511 return TOGGLE_TITLE_MARKDOWN_SHORTCUTS.find((shortcut) => shortcut.pattern.test(textBeforeCursor)) || null; 55512 } 55513 var TOGGLE_TITLE_TOOLBAR_ACTIONS = { 55514 "toggle-list": "toggle", 55515 "bullet-list": "bullet", 55516 "unordered-list": "bullet", 55517 "number-list": "number", 55518 "ordered-list": "number", 55519 checklist: "check", 55520 quote: "quote", 55521 blockquote: "quote", 55522 callout: "callout", 55523 code: "code", 55524 "code-block": "code", 55525 divider: "divider", 55526 separator: "divider", 55527 table: "table" 55528 }; 55529 55530
55530// app/javascript/src/lexxy/toggle_list_extension.js 55531 var { 55532 $createParagraphNode: $createParagraphNode8, 55533 $getNodeByKey: $getNodeByKey6, 55534 $getSelection: $getSelection12, 55535 $isParagraphNode: $isParagraphNode8, 55536 $isRangeSelection: $isRangeSelection11, 55537 $isTextNode: $isTextNode9, 55538 COMMAND_PRIORITY_CRITICAL: COMMAND_PRIORITY_CRITICAL4, 55539 INPUT_COMMAND: INPUT_COMMAND4, 55540 KEY_ENTER_COMMAND: KEY_ENTER_COMMAND6, 55541 KEY_SPACE_COMMAND: KEY_SPACE_COMMAND4 55542 } = Lexical_exports; 55543 var ToggleListExtension = class extends LexxyExtension { 55544 #button = null; 55545 #emptyMarkerFrame = null; 55546 #interactionListener = null; 55547 #toolbarCommandListener = null; 55548 #updateListener = null; 55549 get enabled() { 55550 return this.editorElement.supportsRichText; 55551 } 55552 get allowedElements() { 55553 return [ 55554 { 55555 tag: "div", 55556 attributes: ["class", "data-open", "aria-expanded"] 55557 } 55558 ]; 55559 } 55560 get lexicalExtension() { 55561 return this.defineExtension({ 55562 name: "lexxy/toggle-list", 55563 nodes: [ToggleListNode], 55564 register: (editor) => mergeRegister3( 55565 editor.registerNodeTransform(ToggleListNode, (toggleList) => { 55566 $normalizeToggleListContent(toggleList); 55567 }), 55568 editor.registerNodeTransform(CustomActionTextAttachmentNode, $extractToggleTitleAttachment), 55569 registerToggleTitleMarkdownShortcuts(editor), 55570 registerToggleTitleListTransforms(editor), 55571 editor.registerCommand( 55572 KEY_ENTER_COMMAND6, 55573 (event) => { 55574 if (this.editorElement.hasAttribute("data-lexxy-slash-menu-open")) return false; 55575 if ((event?.metaKey || event?.ctrlKey) && $toggleTitleOpenState()) { 55576 event?.preventDefault(); 55577 return true; 55578 } 55579 if ($insertToggleListAfterCollapsedTitle()) { 55580 event?.preventDefault(); 55581 return true; 55582 } 55583 if (!$exitToggleListFromEmptyParagraph()) return false; 55584 event?.preventDefault(); 55585 return true; 55586 }, 55587 COMMAND_PRIORITY_CRITICAL4 55588 ) 55589 ) 55590 }); 55591 } 55592 initializeToolbar(toolbar) { 55593 this.#bindToggleButtonClicks(); 55594 const checklistButton = toolbar.querySelector('[name="checklist"]'); 55595 if (!checklistButton || toolbar.querySelector('[name="toggle-list"]')) return; 55596 checklistButton.classList.remove("lexxy-editor__toolbar-group-end"); 55597 const button = document.createElement("button"); 55598 button.type = "button"; 55599 button.className = "lexxy-editor__toolbar-button lexxy-editor__toolbar-group-end"; 55600 button.name = "toggle-list"; 55601 button.title = "Toggle list"; 55602 button.innerHTML = LEXXY_TOOLBAR_ICONS.toggleList; 55603 button.addEventListener("click", (event) => { 55604 event.preventDefault(); 55605 this.#toggleToggleList(); 55606 }); 55607 checklistButton.insertAdjacentElement("afterend", button); 55608 this.#button = button; 55609 this.#bindTitleToolbarCommands(toolbar); 55610 const editor = this.editorElement.editor; 55611 if (!editor) return; 55612 this.#updateListener = editor.registerUpdateListener(({ editorState }) => { 55613 editorState.read(() => { 55614 const active = this.#selectionIsInToggleTitle(); 55615 button.classList.toggle("lexxy-editor__toolbar-button--pressed", active); 55616 button.setAttribute("aria-pressed", active ? "true" : "false"); 55617 this.#scheduleEmptyContentMarkerSync(); 55618 }); 55619 }); 55620 this.#scheduleEmptyContentMarkerSync(); 55621 } 55622 dispose() { 55623 if (this.#emptyMarkerFrame) cancelAnimationFrame(this.#emptyMarkerFrame); 55624 this.#interactionListener?.(); 55625 this.#toolbarCommandListener?.(); 55626 this.#updateListener?.(); 55627 this.#button = null; 55628 } 55629 #bindTitleToolbarCommands(toolbar) { 55630 if (this.#toolbarCommandListener) return; 55631 const handleClick2 = (event) => { 55632 const button = event.target?.closest?.("button[name]"); 55633 if (!button || !toolbar.contains(button)) return;
55634 const kind = TOGGLE_TITLE_TOOLBAR_ACTIONS[button.name]; 55635 if (!kind) return; 55636 const editor = this.editorElement.editor; 55637 if (!editor) return; 55638 let handled = false; 55639 editor.update(() => { 55640 handled = $routeToggleTitleCommand(kind, { editor }); 55641 }); 55642 if (!handled) return; 55643 event.preventDefault(); 55644 event.stopPropagation(); 55645 editor.focus(); 55646 }; 55647 toolbar.addEventListener("click", handleClick2, true); 55648 this.#toolbarCommandListener = () => toolbar.removeEventListener("click", handleClick2, true); 55649 } 55650 #bindToggleButtonClicks() { 55651 if (this.#interactionListener) return; 55652 const handlePointerDown = (event) => { 55653 const button = event.target?.closest?.(".lexxy-toggle-list__button"); 55654 if (!button || !this.editorElement.contains(button)) { 55655 this.#handleEmptyPlaceholderPointerDown(event); 55656 return; 55657 } 55658 const toggleListElement = button.closest(".lexxy-toggle-list"); 55659 const key = toggleListElement?.dataset.lexxyToggleKey; 55660 if (!key) return; 55661 event.preventDefault(); 55662 event.stopPropagation(); 55663 const open = toggleListElement.dataset.open === "false"; 55664 this.#syncToggleListElement(toggleListElement, open); 55665 this.#persistToggleState(key, open); 55666 }; 55667 const handlePointerMove = (event) => { 55668 this.editorElement.querySelectorAll(".lexxy-toggle-list[data-empty-content='true'][data-open='true']").forEach((toggleListElement) => { 55669 const hovered = this.#eventTargetsEmptyPlaceholder(event, toggleListElement); 55670 const next = hovered ? "true" : "false"; 55671 if (toggleListElement.dataset.emptyContentHover !== next) { 55672 toggleListElement.dataset.emptyContentHover = next; 55673 } 55674 }); 55675 }; 55676 const clearEmptyContentHover = () => { 55677 this.editorElement.querySelectorAll(".lexxy-toggle-list[data-empty-content-hover]").forEach((toggleListElement) => { 55678 delete toggleListElement.dataset.emptyContentHover; 55679 }); 55680 }; 55681 this.editorElement.addEventListener("pointerdown", handlePointerDown); 55682 this.editorElement.addEventListener("pointermove", handlePointerMove); 55683 this.editorElement.addEventListener("pointerleave", clearEmptyContentHover); 55684 this.#interactionListener = () => { 55685 this.editorElement.removeEventListener("pointerdown", handlePointerDown); 55686 this.editorElement.removeEventListener("pointermove", handlePointerMove); 55687 this.editorElement.removeEventListener("pointerleave", clearEmptyContentHover); 55688 }; 55689 } 55690 #handleEmptyPlaceholderPointerDown(event) { 55691 const toggleListElement = event.target?.closest?.( 55692 ".lexxy-toggle-list[data-empty-content='true'][data-open='true']" 55693 ); 55694 if (!toggleListElement || !this.editorElement.contains(toggleListElement)) return; 55695 if (!this.#eventTargetsEmptyPlaceholder(event, toggleListElement)) return; 55696 const key = toggleListElement.dataset.lexxyToggleKey; 55697 if (!key) return; 55698 event.preventDefault(); 55699 event.stopPropagation(); 55700 const editor = this.editorElement.editor; 55701 editor.update(() => { 55702 const node = $getNodeByKey6(key); 55703 if (!$isToggleListNode(node)) return; 55704 const title = node.getFirstChild(); 55705 const paragraph = title?.getNextSibling() || $createParagraphNode8(); 55706 if (!paragraph.getParent()) { 55707 if (title) title.insertAfter(paragraph); 55708 else node.append(paragraph); 55709 } 55710 paragraph.selectStart(); 55711 }); 55712 editor.focus(); 55713 } 55714 #eventTargetsEmptyPlaceholder(event, toggleListElement) { 55715 const [titleElement, ...bodyElements] = this.#toggleContentBlocks(toggleListElement); 55716 if (bodyElements.length > 0 && toggleListElement.dataset.hasBodyBlock === "true" && toggleListElement.dataset.emptyContentFocused !== "true") { 55717 return bodyElements.some((bodyElement) => this.#pointerIsOverElement(event, bodyElement)); 55718 } 55719 if (!titleElement) return true; 55720 const titleRect = titleElement.getBoundingClientRect(); 55721 const lineHeight = parseFloat(getComputedStyle(titleElement).lineHeight) || titleRect.height; 55722 if (event.clientY <= titleRect.top + lineHeight) return false;
55723 const toggleRect = toggleListElement.getBoundingClientRect(); 55724 return event.clientY <= toggleRect.bottom && event.clientX >= toggleRect.left && event.clientX <= toggleRect.right; 55725 } 55726 #pointerIsOverElement(event, element) { 55727 const rect = element.getBoundingClientRect(); 55728 return event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom; 55729 } 55730 #syncToggleListElement(toggleListElement, open) { 55731 const value = open ? "true" : "false"; 55732 toggleListElement.dataset.open = value; 55733 toggleListElement.setAttribute("aria-expanded", value); 55734 toggleListElement.querySelector(".lexxy-toggle-list__button")?.setAttribute("aria-expanded", value); 55735 } 55736 #persistToggleState(key, open) { 55737 const editor = this.editorElement.editor; 55738 if (!editor) return; 55739 editor.update(() => { 55740 const node = $getNodeByKey6(key); 55741 if ($isToggleListNode(node)) node.setOpen(open); 55742 }); 55743 } 55744 #scheduleEmptyContentMarkerSync() { 55745 if (this.#emptyMarkerFrame) return; 55746 this.#emptyMarkerFrame = requestAnimationFrame(() => { 55747 this.#emptyMarkerFrame = null; 55748 this.#syncEmptyContentMarkers(); 55749 }); 55750 } 55751 #syncEmptyContentMarkers() { 55752 const selectedBlock = this.#selectedToggleContentBlock(); 55753 this.editorElement.querySelectorAll(".lexxy-toggle-list").forEach((toggleListElement) => { 55754 const blocks = this.#toggleContentBlocks(toggleListElement); 55755 const titleBlock = blocks[0]; 55756 const bodyBlocks = blocks.slice(1); 55757 const hasBodyContent = bodyBlocks.some((block) => domToggleBlockHasContent(block)); 55758 toggleListElement.dataset.emptyTitle = titleBlock?.textContent.trim() ? "false" : "true"; 55759 toggleListElement.dataset.emptyContent = hasBodyContent ? "false" : "true"; 55760 toggleListElement.dataset.hasBodyBlock = bodyBlocks.length > 0 ? "true" : "false"; 55761 toggleListElement.dataset.emptyContentFocused = !hasBodyContent && bodyBlocks.includes(selectedBlock) ? "true" : "false"; 55762 if (toggleListElement.dataset.emptyContent !== "true" || toggleListElement.dataset.open !== "true") { 55763 delete toggleListElement.dataset.emptyContentHover; 55764 } 55765 }); 55766 } 55767 #toggleContentBlocks(toggleListElement) { 55768 return Array.from(toggleListElement.children).filter( 55769 (child) => !child.classList.contains("lexxy-toggle-list__button") 55770 ); 55771 } 55772 #selectedToggleContentBlock() { 55773 const selection = window.getSelection(); 55774 const anchorNode = selection?.anchorNode;
55775 const anchorElement = anchorNode?.nodeType === Node.ELEMENT_NODE ? anchorNode : anchorNode?.parentElement; 55776 return anchorElement?.closest?.(".lexxy-toggle-list > :not(.lexxy-toggle-list__button)") || null; 55777 } 55778 #toggleToggleList() { 55779 const editor = this.editorElement.editor; 55780 if (!editor) return; 55781 editor.update(() => { 55782 if ($routeToggleTitleCommand("toggle", { editor })) return; 55783 $insertToggleList(); 55784 }); 55785 editor.focus(); 55786 } 55787 #selectionIsInToggleTitle() { 55788 return this.#toggleTitleContextForSelection() !== null; 55789 } 55790 #toggleTitleContextForSelection() { 55791 const selection = $getSelection12(); 55792 if (!$isRangeSelection11(selection)) return null; 55793 return $toggleTitleContext(selection); 55794 } 55795 }; 55796 function registerToggleTitleMarkdownShortcuts(editor) { 55797 const handleShortcut = (event) => { 55798 let toggleTitleShortcut = null; 55799 let hasToggleShortcut = false; 55800 editor.getEditorState().read(() => { 55801 toggleTitleShortcut = $toggleTitleMarkdownShortcutMatch(); 55802 if (!toggleTitleShortcut) hasToggleShortcut = $selectionHasToggleListShortcut(); 55803 }); 55804 if (toggleTitleShortcut) { 55805 event?.preventDefault(); 55806 editor.update(() => { 55807 $removeToggleTitleShortcutText(toggleTitleShortcut.marker); 55808 $routeToggleTitleCommand(toggleTitleShortcut.kind, { editor }); 55809 }); 55810 return true; 55811 } 55812 if (!hasToggleShortcut) return false; 55813 event?.preventDefault(); 55814 editor.update(() => { 55815 $removeToggleTitleShortcutText(">"); 55816 $insertToggleList(); 55817 }); 55818 return true; 55819 }; 55820 const removeSpaceCommand = editor.registerCommand(KEY_SPACE_COMMAND4, handleShortcut, COMMAND_PRIORITY_CRITICAL4); 55821 const removeInputCommand = editor.registerCommand( 55822 INPUT_COMMAND4, 55823 (event) => { 55824 if (event.inputType !== "insertText" || event.data !== " ") return false; 55825 return handleShortcut(event); 55826 }, 55827 COMMAND_PRIORITY_CRITICAL4 55828 ); 55829 return () => { 55830 removeSpaceCommand(); 55831 removeInputCommand(); 55832 }; 55833 } 55834 function registerToggleTitleListTransforms(editor) { 55835 return mergeRegister3( 55836 editor.registerCommand( 55837 INSERT_UNORDERED_LIST_COMMAND2, 55838 () => $routeToggleTitleCommand("bullet"), 55839 COMMAND_PRIORITY_CRITICAL4 55840 ), 55841 editor.registerCommand( 55842 INSERT_ORDERED_LIST_COMMAND2, 55843 () => $routeToggleTitleCommand("number"), 55844 COMMAND_PRIORITY_CRITICAL4 55845 ), 55846 editor.registerCommand( 55847 INSERT_CHECK_LIST_COMMAND2, 55848 () => $routeToggleTitleCommand("check"), 55849 COMMAND_PRIORITY_CRITICAL4 55850 ) 55851 ); 55852 } 55853 function $selectionHasToggleListShortcut() { 55854 const selection = $getSelection12(); 55855 if (!$isRangeSelection11(selection) || !selection.isCollapsed()) return false; 55856 const anchorNode = selection.anchor.getNode(); 55857 if (!$isTextNode9(anchorNode)) return false; 55858 const textBeforeCursor = anchorNode.getTextContent().slice(0, selection.anchor.offset); 55859 return /(?:^|\n)>\s?$/.test(textBeforeCursor); 55860 } 55861 function $exitToggleListFromEmptyParagraph() { 55862 const selection = $getSelection12(); 55863 if (!$isRangeSelection11(selection) || !selection.isCollapsed()) return false; 55864 const anchorNode = selection.anchor.getNode(); 55865 const paragraph = $isParagraphNode8(anchorNode) ? anchorNode : $findMatchingParent3(anchorNode, $isParagraphNode8); 55866 if (!$isParagraphNode8(paragraph) || paragraph.getTextContent() !== "") return false; 55867 const toggleList = $findMatchingParent3(paragraph, $isToggleListNode); 55868 if (!$isToggleListNode(toggleList)) return false; 55869 if (toggleList.getFirstChild()?.is(paragraph)) return false; 55870 const nextParagraph = $createParagraphNode8(); 55871 toggleList.insertAfter(nextParagraph); 55872 paragraph.remove(); 55873 if (toggleList.getChildrenSize() === 0) toggleList.remove(); 55874 nextParagraph.select(); 55875 return true; 55876 } 55877 function $toggleTitleOpenState() { 55878 const selection = $getSelection12(); 55879 if (!$isRangeSelection11(selection) || !selection.isCollapsed()) return false;
55880 const context = $toggleTitleContext(selection); 55881 if (!context) return false; 55882 context.toggleList.toggleOpen(); 55883 return true; 55884 } 55885 function $insertToggleListAfterCollapsedTitle() { 55886 const selection = $getSelection12(); 55887 if (!$isRangeSelection11(selection) || !selection.isCollapsed()) return false; 55888 const context = $toggleTitleContext(selection); 55889 if (!context || context.toggleList.getOpen()) return false; 55890 if (context.title.getTextContent() === "") { 55891 const paragraph = $createParagraphNode8(); 55892 context.toggleList.replace(paragraph); 55893 paragraph.selectStart(); 55894 return true; 55895 } 55896 if (!$isSelectionAtBlockEnd2(selection, context.title)) return false; 55897 const nextToggleList = $createToggleListNode(false); 55898 const nextTitle = $createParagraphNode8(); 55899 nextToggleList.append(nextTitle); 55900 context.toggleList.insertAfter(nextToggleList); 55901 nextTitle.selectStart(); 55902 return true; 55903 } 55904 function $isSelectionAtBlockEnd2(selection, block) { 55905 const anchor = selection.anchor; 55906 const anchorNode = anchor.getNode(); 55907 if (anchor.type === "element" && anchorNode.is(block)) { 55908 return anchor.offset === block.getChildrenSize(); 55909 } 55910 if (!$isTextNode9(anchorNode)) return false; 55911 const lastDescendant = block.getLastDescendant(); 55912 return anchorNode.is(lastDescendant) && anchor.offset === anchorNode.getTextContentSize(); 55913 } 55914 55915
55915// app/javascript/src/lexxy/slash_commands_extension.js 55916 var { 55917 COMMAND_PRIORITY_CRITICAL: COMMAND_PRIORITY_CRITICAL5, 55918 INPUT_COMMAND: INPUT_COMMAND5, 55919 KEY_ARROW_DOWN_COMMAND: KEY_ARROW_DOWN_COMMAND5, 55920 KEY_ARROW_UP_COMMAND: KEY_ARROW_UP_COMMAND4, 55921 KEY_ENTER_COMMAND: KEY_ENTER_COMMAND7, 55922 KEY_ESCAPE_COMMAND: KEY_ESCAPE_COMMAND4, 55923 KEY_SPACE_COMMAND: KEY_SPACE_COMMAND5, 55924 KEY_TAB_COMMAND: KEY_TAB_COMMAND5, 55925 $createNodeSelection: $createNodeSelection4, 55926 $findMatchingParent: $findMatchingParent9, 55927 $getSelection: $getSelection13, 55928 $isRangeSelection: $isRangeSelection12, 55929 $isTextNode: $isTextNode10, 55930 $setSelection: $setSelection4 55931 } = Lexical_exports; 55932 var SLASH_COMMANDS = [ 55933 { 55934 id: "text", 55935 label: "Text", 55936 description: "Plain paragraph", 55937 icon: LEXXY_TOOLBAR_ICONS.text, 55938 shortcut: "", 55939 keywords: "text paragraph plain", 55940 run: ({ contents, editor }) => { 55941 if ($routeToggleTitleCommand("paragraph", { editor })) return; 55942 contents.applyParagraphFormat(); 55943 } 55944 }, 55945 { 55946 id: "h1", 55947 label: "Heading 1", 55948 description: "Large page heading", 55949 icon: LEXXY_TOOLBAR_ICONS.heading1, 55950 shortcut: "#", 55951 keywords: "heading h1 title", 55952 run: ({ contents, editor }) => { 55953 if ($routeToggleTitleCommand("h1", { editor })) return; 55954 contents.applyHeadingFormat("h1"); 55955 } 55956 }, 55957 { 55958 id: "h2", 55959 label: "Heading 2", 55960 description: "Large section heading", 55961 icon: LEXXY_TOOLBAR_ICONS.heading2, 55962 shortcut: "##", 55963 keywords: "heading h2 title", 55964 run: ({ contents, editor }) => { 55965 if ($routeToggleTitleCommand("h2", { editor })) return; 55966 contents.applyHeadingFormat("h2"); 55967 } 55968 }, 55969 { 55970 id: "h3", 55971 label: "Heading 3", 55972 description: "Medium section heading", 55973 icon: LEXXY_TOOLBAR_ICONS.heading3, 55974 shortcut: "###", 55975 keywords: "heading h3 subtitle", 55976 run: ({ contents, editor }) => { 55977 if ($routeToggleTitleCommand("h3", { editor })) return; 55978 contents.applyHeadingFormat("h3"); 55979 } 55980 }, 55981 { 55982 id: "h4", 55983 label: "Heading 4", 55984 description: "Small section heading", 55985 icon: LEXXY_TOOLBAR_ICONS.heading4, 55986 shortcut: "####", 55987 keywords: "heading h4", 55988 run: ({ contents, editor }) => { 55989 if ($routeToggleTitleCommand("h4", { editor })) return; 55990 contents.applyHeadingFormat("h4"); 55991 } 55992 }, 55993 { 55994 id: "bullet", 55995 label: "Bullet list", 55996 description: "Unordered list", 55997 icon: LEXXY_TOOLBAR_ICONS.bulletList, 55998 shortcut: "-", 55999 keywords: "bullet unordered list ul", 56000 run: ({ contents, editor }) => { 56001 if ($routeToggleTitleCommand("bullet", { editor })) return; 56002 contents.applyUnorderedListFormat(); 56003 } 56004 }, 56005 { 56006 id: "number", 56007 label: "Numbered list", 56008 description: "Ordered list", 56009 icon: LEXXY_TOOLBAR_ICONS.numberList, 56010 shortcut: "1.", 56011 keywords: "numbered ordered list ol num", 56012 run: ({ contents, editor }) => { 56013 if ($routeToggleTitleCommand("number", { editor })) return; 56014 contents.applyOrderedListFormat(); 56015 } 56016 }, 56017 { 56018 id: "checklist", 56019 label: "Checklist", 56020 description: "Task list with checkboxes", 56021 icon: LEXXY_TOOLBAR_ICONS.checklist, 56022 shortcut: "[]", 56023 keywords: "checklist todo task checkbox", 56024 run: ({ editor }) => { 56025 if ($routeToggleTitleCommand("check", { editor })) return; 56026 editor.dispatchCommand(INSERT_CHECK_LIST_COMMAND2, void 0); 56027 } 56028 }, 56029 { 56030 id: "toggle-list", 56031 label: "Toggle list", 56032 description: "Collapsible section", 56033 icon: LEXXY_TOOLBAR_ICONS.toggleList, 56034 shortcut: ">", 56035 keywords: "toggle list collapsible disclosure details fold", 56036 run: ({ editor }) => { 56037 if ($routeToggleTitleCommand("toggle", { editor })) return; 56038 $insertToggleList(); 56039 } 56040 }, 56041 { 56042 id: "quote", 56043 label: "Quote", 56044 description: "Block quote", 56045 icon: LEXXY_TOOLBAR_ICONS.quote, 56046 shortcut: '"', 56047 keywords: "quote blockquote", 56048 run: ({ contents, editor }) => { 56049 if ($routeToggleTitleCommand("quote", { editor })) return; 56050 contents.toggleBlockquote(); 56051 } 56052 }, 56053 { 56054 id: "callout", 56055 label: "Callout", 56056 description: "Tip or callout block", 56057 icon: LEXXY_TOOLBAR_ICONS.callout, 56058 shortcut: "",
56059 keywords: "callout tip note info warning", 56060 run: ({ editor }) => { 56061 if ($routeToggleTitleCommand("callout", { editor })) return; 56062 $insertCallout(); 56063 } 56064 }, 56065 { 56066 id: "code", 56067 label: "Code", 56068 description: "Code block", 56069 icon: LEXXY_TOOLBAR_ICONS.code, 56070 shortcut: "```", 56071 keywords: "code snippet pre", 56072 run: ({ contents, editor }) => { 56073 if ($routeToggleTitleCommand("code", { editor })) return; 56074 contents.toggleCodeBlock(); 56075 } 56076 }, 56077 { 56078 id: "divider", 56079 label: "Divider", 56080 description: "Horizontal divider", 56081 icon: LEXXY_TOOLBAR_ICONS.separator, 56082 shortcut: "---", 56083 keywords: "divider hr line separator", 56084 run: ({ contents, editor }) => { 56085 if ($routeToggleTitleCommand("divider", { editor })) return; 56086 $insertDividerAndSelect(contents); 56087 } 56088 }, 56089 { 56090 id: "table", 56091 label: "Table", 56092 description: "Insert a table", 56093 icon: LEXXY_TOOLBAR_ICONS.table, 56094 shortcut: "", 56095 keywords: "table grid", 56096 run: ({ editor }) => { 56097 if ($routeToggleTitleCommand("table", { editor })) return; 56098 $insertTableAndFocusFirstCell(editor); 56099 } 56100 }, 56101 { 56102 id: "image", 56103 label: "Media (image or video)", 56104 description: "Upload an image or video file", 56105 icon: LEXXY_TOOLBAR_ICONS.image, 56106 shortcut: "", 56107 keywords: "image photo video upload", 56108 run: ({ contents, editorElement }) => $triggerFileUpload({ contents, editorElement, accept: "image/*,video/*" }) 56109 }, 56110 { 56111 id: "audio", 56112 label: "Audio", 56113 description: "Upload an audio file", 56114 icon: LEXXY_TOOLBAR_ICONS.audio, 56115 shortcut: "", 56116 keywords: "audio sound music mp3 wav upload", 56117 run: ({ contents, editorElement }) => $triggerFileUpload({ contents, editorElement, accept: "audio/*" }) 56118 }, 56119 { 56120 id: "pdf", 56121 label: "PDF", 56122 description: "Upload a PDF document", 56123 icon: LEXXY_TOOLBAR_ICONS.pdf, 56124 shortcut: "", 56125 keywords: "pdf document file upload", 56126 run: ({ contents, editorElement }) => $triggerFileUpload({ contents, editorElement, accept: "application/pdf,.pdf" }) 56127 }, 56128 { 56129 id: "attachment", 56130 label: "Attachment", 56131 description: "Upload a file", 56132 icon: LEXXY_TOOLBAR_ICONS.attachment, 56133 shortcut: "", 56134 keywords: "attachment attachement file upload document", 56135 run: ({ editorElement }) => editorElement.querySelector('[name="file"]')?.click() 56136 } 56137 ]; 56138 function $triggerFileUpload({ contents, editorElement, accept }) { 56139 const input = document.createElement("input"); 56140 input.type = "file"; 56141 input.multiple = true; 56142 input.accept = accept; 56143 input.style.display = "none"; 56144 input.addEventListener("change", () => { 56145 if (input.files?.length) contents.uploadFiles(input.files, { selectLast: true }); 56146 }); 56147 editorElement.appendChild(input); 56148 input.click(); 56149 setTimeout(() => input.remove(), 1e3); 56150 } 56151 function $insertDividerAndSelect(contents) { 56152 const divider = new HorizontalDividerNode(); 56153 contents.insertAtCursor(divider); 56154 const selection = $createNodeSelection4(); 56155 selection.add(divider.getKey()); 56156 $setSelection4(selection); 56157 } 56158 function $insertTableAndFocusFirstCell(editor) { 56159 editor.dispatchCommand(INSERT_TABLE_COMMAND2, { rows: 3, columns: 3, includeHeaders: true }); 56160 const selection = $getSelection13(); 56161 if (!$isRangeSelection12(selection)) return; 56162 const table = $findMatchingParent9(selection.anchor.getNode(), (node) => node instanceof TableNode2); 56163 $selectFirstTableCell2(table); 56164 } 56165 function $selectFirstTableCell2(table) { 56166 const firstCell = table?.getFirstChild()?.getFirstChild(); 56167 const firstCellContent = firstCell?.getFirstChild(); 56168 if (firstCellContent?.selectStart) { 56169 firstCellContent.selectStart(); 56170 } else { 56171 firstCell?.selectStart?.(); 56172 } 56173 } 56174 function shouldDismissSlashQuery(query) { 56175 if (!query) return false; 56176 if (/^\s/.test(query)) return true; 56177 if (/\s{2,}/.test(query)) return true; 56178 return !query.trim(); 56179 } 56180 function matchCommands(query) { 56181 const normalized = query.trim().toLowerCase(); 56182 if (!normalized) return SLASH_COMMANDS;
56183 const tokens = normalized.split(/\s+/).filter(Boolean); 56184 return SLASH_COMMANDS.filter((command) => { 56185 const haystack = `${command.label} ${command.description} ${command.shortcut} ${command.keywords}`.toLowerCase(); 56186 const words = haystack.split(/\s+/); 56187 return tokens.every((token) => { 56188 if (haystack.includes(token)) return true; 56189 return words.some((word) => word.startsWith(token)); 56190 }); 56191 }); 56192 } 56193 var SlashCommandsExtension = class extends LexxyExtension { 56194 #popover = null; 56195 #popoverListeners = []; 56196 #triggerListener = null; 56197 #open = false; 56198 #selectedIndex = 0; 56199 #closeMenuFocused = false; 56200 #showId = 0; 56201 #unlockScroll = null; 56202 #activeTrigger = null; 56203 #dismissedTrigger = null; 56204 #slashJustTyped = false; 56205 #noResultsCharacterCount = 0; 56206 #lastNoResultsQuery = null; 56207 #isOptionsScrolling = false; 56208 #optionsScrollEndTimer = null; 56209 #lastPointerPosition = null; 56210 #isUserOptionsScroll = false; 56211 get enabled() { 56212 return this.editorElement.supportsRichText && supportsDesktopPrompts(); 56213 } 56214 initializeToolbar(_toolbar) { 56215 this.#attachTriggerListener(); 56216 } 56217 dispose() { 56218 this.editorElement.removeAttribute("data-lexxy-slash-menu-open"); 56219 this.#disposePopoverListeners(); 56220 this.#unlockPopoverScroll(); 56221 this.#triggerListener?.(); 56222 this.#popover?.remove(); 56223 this.#popover = null; 56224 } 56225 #attachTriggerListener() { 56226 const editor = this.editorElement.editor; 56227 if (!editor) return; 56228 const markSlashTyped = (event) => { 56229 if (event.inputType?.startsWith("insert") && event.data === "/") { 56230 this.#slashJustTyped = true; 56231 } 56232 }; 56233 this.editorElement.addEventListener("beforeinput", markSlashTyped, true); 56234 const disposeInputListener = editor.registerCommand( 56235 INPUT_COMMAND5, 56236 (event) => { 56237 if (event.inputType?.startsWith("insert") && event.data === "/") { 56238 this.#slashJustTyped = true; 56239 } 56240 return false; 56241 }, 56242 COMMAND_PRIORITY_CRITICAL5 56243 ); 56244 const disposeUpdateListener = editor.registerUpdateListener(({ editorState }) => { 56245 if (this.#open) return; 56246 editorState.read(() => { 56247 if (!this.#slashJustTyped) return; 56248 this.#slashJustTyped = false; 56249 this.#dismissedTrigger = null; 56250 this.#showPopoverForSlashQuery(); 56251 }); 56252 }); 56253 this.#triggerListener = () => { 56254 this.editorElement.removeEventListener("beforeinput", markSlashTyped, true); 56255 disposeInputListener(); 56256 disposeUpdateListener(); 56257 }; 56258 } 56259 #showPopoverForSlashQuery() { 56260 if (this.#open || this.editorElement.selection?.isInsideCodeBlock) return; 56261 const trigger = this.#readTriggerContext(); 56262 if (!trigger) return; 56263 if (this.#isDismissedTrigger(trigger)) return; 56264 this.#activeTrigger = trigger; 56265 this.#showPopover(trigger.query); 56266 } 56267 #readTriggerContext() { 56268 const selection = $getSelection13(); 56269 if (!$isRangeSelection12(selection) || !selection.isCollapsed()) return null; 56270 const anchorNode = selection.anchor.getNode(); 56271 if (!$isTextNode10(anchorNode)) return null; 56272 const offset3 = selection.anchor.offset; 56273 const textBeforeCursor = anchorNode.getTextContent().slice(0, offset3); 56274 const lastSlash = textBeforeCursor.lastIndexOf("/"); 56275 if (lastSlash === -1) return null; 56276 const charBeforeSlash = lastSlash > 0 ? textBeforeCursor[lastSlash - 1] : ""; 56277 if (charBeforeSlash && !/[\s\n]/.test(charBeforeSlash)) return null; 56278 const query = textBeforeCursor.slice(lastSlash + 1); 56279 if (shouldDismissSlashQuery(query)) return null; 56280 return { 56281 key: anchorNode.getKey(), 56282 offset: lastSlash, 56283 query 56284 }; 56285 } 56286 #isDismissedTrigger(trigger) { 56287 return this.#dismissedTrigger?.key === trigger.key && this.#dismissedTrigger?.offset === trigger.offset; 56288 } 56289 async #showPopover(query) { 56290 const showId = ++this.#showId; 56291 this.#open = true;
56292 this.editorElement.setAttribute("data-lexxy-slash-menu-open", ""); 56293 this.#resetNoResultsCounter(); 56294 this.#popover ??= this.#buildPopover(); 56295 if (this.#showId !== showId) return; 56296 this.#renderOptions(query); 56297 if (this.#showId !== showId) return; 56298 this.#selectedIndex = 0; 56299 this.#closeMenuFocused = false; 56300 this.#setKeyboardNavigation(true); 56301 this.#highlightSelection(); 56302 this.#positionPopover(); 56303 this.#popover.classList.add("lexxy-prompt-menu--visible"); 56304 this.#unlockScroll ??= lockPopoverScroll(); 56305 this.#registerPopoverListeners(); 56306 } 56307 #buildPopover() { 56308 const popover = document.createElement("div"); 56309 popover.className = "lexxy-prompt-menu lexxy-prompt-menu--portaled lexxy-slash-menu lexxy-slash-menu--portaled ph-no-autocapture"; 56310 popover.hidden = true; 56311 popover.setAttribute("data-ph-no-autocapture", ""); 56312 popover.innerHTML = ` 56313 <div class="lexxy-slash-menu__options" data-slash-menu-options role="listbox"></div> 56314 <div class="lexxy-slash-menu__footer"> 56315 <button type="button" class="lexxy-slash-menu__close" data-slash-menu-close> 56316 <span class="lexxy-slash-menu__close-label">Close menu</span> 56317 <kbd class="lexxy-slash-menu__shortcut">esc</kbd> 56318 </button> 56319 </div> 56320 `; 56321 const options = popover.querySelector("[data-slash-menu-options]"); 56322 options?.addEventListener("wheel", (event) => { 56323 this.#trackPointerPosition(event); 56324 this.#isUserOptionsScroll = true; 56325 }); 56326 options?.addEventListener("scroll", () => this.#handleOptionsScroll()); 56327 popover.querySelector("[data-slash-menu-close]")?.addEventListener("click", () => this.#hidePopover()); 56328 popover.querySelector("[data-slash-menu-close]")?.addEventListener("pointermove", (event) => { 56329 this.#trackPointerPosition(event); 56330 if (this.#isOptionsScrolling) return; 56331 this.#setKeyboardNavigation(false); 56332 this.#highlightCloseMenu(); 56333 }); 56334 document.body.appendChild(popover); 56335 return popover; 56336 } 56337 #optionsList() { 56338 return this.#popover?.querySelector("[data-slash-menu-options]"); 56339 } 56340 #renderOptions(query) { 56341 const matches = matchCommands(query); 56342 const options = this.#optionsList(); 56343 if (!options) return; 56344 if (matches.length === 0) { 56345 options.innerHTML = ""; 56346 options.hidden = true; 56347 this.#clearOptionsOverflow(); 56348 this.#trackNoResultsQuery(query); 56349 } else { 56350 options.hidden = false; 56351 options.innerHTML = matches.map( 56352 (command) => ` 56353 <div class="lexxy-prompt-menu__item lexxy-slash-menu__item" role="option" data-command-id="${command.id}"> 56354 <span class="lexxy-slash-menu__icon" aria-hidden="true">${command.icon}</span> 56355 <span class="lexxy-slash-menu__content"> 56356 <span class="lexxy-slash-menu__label">${command.label}</span> 56357 <span class="lexxy-slash-menu__description">${command.description}</span> 56358 </span> 56359 <span class="lexxy-slash-menu__shortcut" aria-hidden="true">${command.shortcut || ""}</span> 56360 </div> 56361 ` 56362 ).join(""); 56363 this.#resetNoResultsCounter(); 56364 } 56365 this.#popover.dataset.matches = String(matches.length); 56366 options.querySelectorAll("[data-command-id]").forEach((item, index) => { 56367 item.addEventListener("pointermove", (event) => { 56368 this.#trackPointerPosition(event); 56369 if (this.#isOptionsScrolling) return; 56370 this.#setKeyboardNavigation(false); 56371 this.#closeMenuFocused = false; 56372 this.#selectedIndex = index; 56373 this.#highlightSelection({ scroll: false }); 56374 }); 56375 item.addEventListener("click", () => { 56376 this.#selectedIndex = index; 56377 this.#executeSelected(); 56378 }); 56379 }); 56380 requestAnimationFrame(() => this.#updateOptionsOverflow()); 56381 } 56382 #trackNoResultsQuery(query) { 56383 if (this.#lastNoResultsQuery === null) { 56384 this.#lastNoResultsQuery = query; 56385 this.#noResultsCharacterCount = 0; 56386 return; 56387 } 56388 if (query === this.#lastNoResultsQuery) return; 56389 if (query.length > this.#lastNoResultsQuery.length) { 56390 this.#noResultsCharacterCount += query.length - this.#lastNoResultsQuery.length; 56391 } 56392 this.#lastNoResultsQuery = query; 56393 if (this.#noResultsCharacterCount > 4) { 56394 requestAnimationFrame(() => this.#hidePopover()); 56395 } 56396 } 56397 #resetNoResultsCounter() { 56398 this.#noResultsCharacterCount = 0; 56399 this.#lastNoResultsQuery = null; 56400 } 56401 #registerPopoverListeners() { 56402 this.#disposePopoverListeners(); 56403 const editor = this.editorElement.editor; 56404 const register = (command, handler) => { 56405 this.#popoverListeners.push(editor.registerCommand(command, handler, COMMAND_PRIORITY_CRITICAL5)); 56406 }; 56407 register(KEY_ARROW_DOWN_COMMAND5, (event) => { 56408 event.preventDefault(); 56409 this.#moveSelection(1); 56410 return true; 56411 }); 56412 register(KEY_ARROW_UP_COMMAND4, (event) => { 56413 event.preventDefault(); 56414 this.#moveSelection(-1); 56415 return true; 56416 }); 56417 register(KEY_ENTER_COMMAND7, (event) => { 56418 event.preventDefault(); 56419 if (this.#closeMenuFocused) { 56420 this.#hidePopover(); 56421 } else { 56422 this.#executeSelected(); 56423 } 56424 return true; 56425 }); 56426 register(KEY_TAB_COMMAND5, (event) => { 56427 event.preventDefault(); 56428 if (this.#closeMenuFocused) { 56429 this.#hidePopover(); 56430 } else { 56431 this.#executeSelected(); 56432 } 56433 return true; 56434 }); 56435 register(KEY_SPACE_COMMAND5, (event) => { 56436 const query = this.editorElement.contents.textBackUntil("/"); 56437 const command = this.#commandForSpaceShortcut(query); 56438 if (command) { 56439 event.preventDefault(); 56440 this.#executeCommand(command); 56441 return true; 56442 } 56443 if (this.#shouldDismissOnSpace(query)) { 56444 this.#hidePopover(); 56445 } 56446 return false;
56447 }); 56448 register(KEY_ESCAPE_COMMAND4, () => { 56449 this.#hidePopover(); 56450 return true; 56451 }); 56452 register(INPUT_COMMAND5, (event) => { 56453 if (event.inputType !== "insertText" || event.data !== " ") return false; 56454 const query = this.editorElement.contents.textBackUntil("/"); 56455 const command = this.#commandForSpaceShortcut(query); 56456 if (command) { 56457 event.preventDefault(); 56458 this.#executeCommand(command); 56459 return true; 56460 } 56461 if (this.#shouldDismissOnSpace(query)) { 56462 this.#hidePopover(); 56463 } 56464 return false; 56465 }); 56466 const filterListener = editor.registerUpdateListener(({ editorState }) => { 56467 editorState.read(() => { 56468 const trigger = this.#readTriggerContext(); 56469 if (!trigger) { 56470 this.#hidePopover(); 56471 return; 56472 } 56473 this.#activeTrigger = trigger; 56474 this.#renderOptions(trigger.query); 56475 this.#selectedIndex = 0; 56476 this.#closeMenuFocused = false; 56477 this.#setKeyboardNavigation(true); 56478 this.#highlightSelection(); 56479 requestAnimationFrame(() => this.#positionPopover()); 56480 }); 56481 }); 56482 this.#popoverListeners.push(filterListener); 56483 this.#popoverListeners.push(this.#bindViewportRepositioning()); 56484 } 56485 #bindViewportRepositioning() { 56486 let frame = null; 56487 const reposition = () => { 56488 if (frame) cancelAnimationFrame(frame); 56489 frame = requestAnimationFrame(() => { 56490 frame = null; 56491 if (this.#open) this.#positionPopover(); 56492 }); 56493 }; 56494 window.addEventListener("scroll", reposition, true); 56495 window.addEventListener("resize", reposition); 56496 const editorContent = this.editorElement.editorContentElement; 56497 const resizeObserver = new ResizeObserver(reposition); 56498 if (editorContent) resizeObserver.observe(editorContent); 56499 if (this.#popover) resizeObserver.observe(this.#popover); 56500 const onImageLoad = (event) => { 56501 if (event.target?.tagName === "IMG") reposition(); 56502 }; 56503 this.editorElement.addEventListener("load", onImageLoad, true); 56504 return () => { 56505 if (frame) cancelAnimationFrame(frame); 56506 window.removeEventListener("scroll", reposition, true); 56507 window.removeEventListener("resize", reposition); 56508 resizeObserver.disconnect(); 56509 this.editorElement.removeEventListener("load", onImageLoad, true); 56510 }; 56511 } 56512 #disposePopoverListeners() { 56513 this.#clearOptionsScrollEndTimer(); 56514 this.#isOptionsScrolling = false; 56515 this.#isUserOptionsScroll = false; 56516 this.#popoverListeners.forEach((dispose) => dispose()); 56517 this.#popoverListeners = []; 56518 } 56519 #unlockPopoverScroll() { 56520 this.#unlockScroll?.(); 56521 this.#unlockScroll = null; 56522 } 56523 #listItems() { 56524 return Array.from(this.#popover?.querySelectorAll("[data-command-id]") || []); 56525 } 56526 #closeButton() { 56527 return this.#popover?.querySelector("[data-slash-menu-close]"); 56528 } 56529 #moveSelection(delta) { 56530 const items = this.#listItems(); 56531 if (!items.length) { 56532 this.#highlightCloseMenu(); 56533 return; 56534 } 56535 this.#setKeyboardNavigation(true); 56536 const count = items.length + 1; 56537 let position = this.#closeMenuFocused ? items.length : this.#selectedIndex; 56538 position = (position + delta + count) % count; 56539 if (position === items.length) { 56540 this.#highlightCloseMenu(); 56541 return; 56542 } 56543 this.#selectedIndex = position; 56544 this.#highlightSelection(); 56545 } 56546 #highlightCloseMenu() { 56547 this.#closeMenuFocused = true;
56548 this.#listItems().forEach((item) => item.removeAttribute("aria-selected")); 56549 this.#closeButton()?.setAttribute("aria-selected", "true"); 56550 this.#setKeyboardNavigation(true); 56551 } 56552 #highlightSelection({ scroll = true } = {}) { 56553 const items = this.#listItems(); 56554 if (!items.length) { 56555 this.#highlightCloseMenu(); 56556 return; 56557 } 56558 this.#closeMenuFocused = false; 56559 this.#closeButton()?.removeAttribute("aria-selected"); 56560 items.forEach((item, index) => { 56561 item.toggleAttribute("aria-selected", index === this.#selectedIndex); 56562 }); 56563 if (scroll) this.#scrollToOption(items[this.#selectedIndex]); 56564 } 56565 #setKeyboardNavigation(active) { 56566 if (!this.#popover) return; 56567 this.#popover.toggleAttribute("data-keyboard-nav", active); 56568 if (active) this.#clearStuckHover(); 56569 } 56570 #clearStuckHover() { 56571 if (!this.#popover) return; 56572 this.#popover.style.pointerEvents = "none"; 56573 requestAnimationFrame(() => { 56574 if (this.#popover) this.#popover.style.pointerEvents = ""; 56575 }); 56576 } 56577 #trackPointerPosition(event) { 56578 this.#lastPointerPosition = { x: event.clientX, y: event.clientY }; 56579 } 56580 #handleOptionsScroll() { 56581 this.#updateOptionsOverflow(); 56582 if (!this.#isUserOptionsScroll) return; 56583 if (!this.#isOptionsScrolling) { 56584 this.#isOptionsScrolling = true; 56585 this.#setKeyboardNavigation(true); 56586 } 56587 this.#clearOptionsScrollEndTimer(); 56588 this.#optionsScrollEndTimer = setTimeout(() => { 56589 this.#isOptionsScrolling = false; 56590 this.#isUserOptionsScroll = false; 56591 this.#optionsScrollEndTimer = null; 56592 this.#selectOptionAtPointer(); 56593 }, 120); 56594 } 56595 #clearOptionsScrollEndTimer() { 56596 if (!this.#optionsScrollEndTimer) return; 56597 clearTimeout(this.#optionsScrollEndTimer); 56598 this.#optionsScrollEndTimer = null; 56599 } 56600 #selectOptionAtPointer() { 56601 if (!this.#open || !this.#lastPointerPosition) return; 56602 const { x: x3, y: y3 } = this.#lastPointerPosition; 56603 const element = document.elementFromPoint(x3, y3); 56604 if (!element || !this.#popover?.contains(element)) return; 56605 const closeButton = element.closest("[data-slash-menu-close]"); 56606 if (closeButton) { 56607 this.#setKeyboardNavigation(false); 56608 this.#highlightCloseMenu(); 56609 return; 56610 } 56611 const item = element.closest("[data-command-id]"); 56612 if (!item) return; 56613 const index = this.#listItems().indexOf(item); 56614 if (index === -1) return; 56615 this.#setKeyboardNavigation(false); 56616 this.#closeMenuFocused = false; 56617 this.#selectedIndex = index; 56618 this.#highlightSelection({ scroll: false }); 56619 } 56620 #scrollToOption(optionEl) { 56621 const content = this.#optionsList(); 56622 if (!optionEl || !content) return; 56623 const contentRect = content.getBoundingClientRect(); 56624 const optionRect = optionEl.getBoundingClientRect(); 56625 const optionRelativeTop = optionRect.top - contentRect.top; 56626 const optionRelativeBottom = optionRelativeTop + optionRect.height; 56627 const contentScrollTop = content.scrollTop; 56628 const contentHeight = contentRect.height; 56629 const scrollPadding = optionRect.height + 6; 56630 if (optionRelativeBottom > contentHeight - scrollPadding) { 56631 content.scrollTop = contentScrollTop + (optionRelativeBottom - contentHeight + scrollPadding); 56632 } else if (optionRelativeTop < scrollPadding) { 56633 content.scrollTop = contentScrollTop + (optionRelativeTop - scrollPadding); 56634 } 56635 this.#updateOptionsOverflow(); 56636 } 56637 #updateOptionsOverflow() { 56638 const options = this.#optionsList(); 56639 if (!options || options.hidden) return; 56640 const maxScrollTop = Math.max(0, options.scrollHeight - options.clientHeight); 56641 const hasOverflowAtStart = options.scrollTop > 1; 56642 const hasOverflowAtEnd = options.scrollTop < maxScrollTop - 1; 56643 options.toggleAttribute("data-overflow-y-start", hasOverflowAtStart); 56644 options.toggleAttribute("data-overflow-y-end", hasOverflowAtEnd); 56645 this.#popover?.toggleAttribute("data-overflow-y-start", hasOverflowAtStart); 56646 this.#popover?.toggleAttribute("data-overflow-y-end", hasOverflowAtEnd); 56647 } 56648 #clearOptionsOverflow() { 56649 const options = this.#optionsList(); 56650 options?.removeAttribute("data-overflow-y-start"); 56651 options?.removeAttribute("data-overflow-y-end"); 56652 this.#popover?.removeAttribute("data-overflow-y-start"); 56653 this.#popover?.removeAttribute("data-overflow-y-end"); 56654 } 56655 #shouldDismissOnSpace(query) { 56656 return shouldDismissSlashQuery(query) || shouldDismissSlashQuery(`${query} `); 56657 } 56658 #commandForSpaceShortcut(query = this.editorElement.contents.textBackUntil("/")) { 56659 if (!query || /\s/.test(query)) return null; 56660 const normalized = query.trim().toLowerCase(); 56661 if (!normalized) return null; 56662 return SLASH_COMMANDS.find((command) => this.#shortcutTermsFor(command).includes(normalized)) || null; 56663 } 56664 #shortcutTermsFor(command) { 56665 return [command.shortcut].map((term) =>
56665 term.trim().toLowerCase()).filter(Boolean); 56666 } 56667 #selectedCommand() { 56668 const item = this.#listItems()[this.#selectedIndex]; 56669 if (!item) return null; 56670 return SLASH_COMMANDS.find((entry) => entry.id === item.dataset.commandId) || null; 56671 } 56672 #executeSelected() { 56673 const command = this.#selectedCommand(); 56674 if (!command) { 56675 this.#hidePopover(); 56676 return; 56677 } 56678 this.#executeCommand(command); 56679 } 56680 #executeCommand(command) { 56681 const editor = this.editorElement.editor; 56682 const contents = this.editorElement.contents; 56683 editor.update(() => { 56684 this.#removeSlashTriggerText(); 56685 command.run({ editor, contents, editorElement: this.editorElement }); 56686 }); 56687 this.#hidePopover(); 56688 editor.focus(); 56689 } 56690 #removeSlashTriggerText() { 56691 const selection = $getSelection13(); 56692 if (!$isRangeSelection12(selection) || !selection.isCollapsed()) return; 56693 const anchorNode = selection.anchor.getNode(); 56694 if (!$isTextNode10(anchorNode)) return; 56695 const offset3 = selection.anchor.offset; 56696 const textBeforeCursor = anchorNode.getTextContent().slice(0, offset3); 56697 const slashIndex = textBeforeCursor.lastIndexOf("/"); 56698 if (slashIndex === -1) return; 56699 anchorNode.spliceText(slashIndex, offset3 - slashIndex, "", true); 56700 } 56701 #hidePopover() { 56702 this.#showId++; 56703 this.#open = false; 56704 this.editorElement.removeAttribute("data-lexxy-slash-menu-open"); 56705 if (this.#activeTrigger) { 56706 this.#dismissedTrigger = { 56707 key: this.#activeTrigger.key, 56708 offset: this.#activeTrigger.offset 56709 }; 56710 } 56711 this.#activeTrigger = null; 56712 this.#closeMenuFocused = false; 56713 this.#resetNoResultsCounter(); 56714 this.#disposePopoverListeners(); 56715 this.#unlockPopoverScroll(); 56716 this.#popover?.classList.remove("lexxy-prompt-menu--visible"); 56717 this.#popover?.removeAttribute("data-anchored"); 56718 this.#popover?.removeAttribute("data-keyboard-nav"); 56719 if (this.#popover) this.#popover.hidden = true; 56720 this.#closeButton()?.removeAttribute("aria-selected"); 56721 } 56722 #positionPopover() { 56723 if (!this.#popover || !this.#open) return; 56724 const anchorRect = this.#triggerAnchorRect(); 56725 if (!anchorRect) return; 56726 const x3 = anchorRect.left; 56727 const y3 = anchorRect.bottom; 56728 this.#popover.hidden = false; 56729 this.#popover.style.setProperty("--lexxy-prompt-offset-x", `${x3}px`); 56730 this.#popover.style.setProperty("--lexxy-prompt-offset-y", `${y3}px`); 56731 this.#popover.removeAttribute("data-clipped-at-right"); 56732 this.#popover.removeAttribute("data-clipped-at-bottom"); 56733 this.#popover.toggleAttribute("data-anchored", true); 56734 const popoverRect = this.#popover.getBoundingClientRect(); 56735 if (popoverRect.right > window.innerWidth) { 56736 this.#popover.style.setProperty( 56737 "--lexxy-prompt-offset-x", 56738 `${Math.max(8, window.innerWidth - popoverRect.width - 8)}px` 56739 ); 56740 } 56741 if (popoverRect.bottom > window.innerHeight) { 56742 this.#popover.style.setProperty( 56743 "--lexxy-prompt-offset-y", 56744 `${Math.max(8, anchorRect.top - popoverRect.height - 6)}px` 56745 ); 56746 } 56747 this.#updateOptionsOverflow(); 56748 } 56749 #triggerAnchorRect(offset3 = this.#activeTrigger?.offset) { 56750 const trigger = this.#activeTrigger; 56751 if (!trigger || offset3 == null) return null; 56752 const textElement = this.editorElement.editor.getElementByKey(trigger.key); 56753 if (!textElement) return null; 56754 const position = this.#textNodePosition(textElement, offset3); 56755 if (!position) return null; 56756 const range2 = document.createRange(); 56757 range2.setStart(position.node, position.offset); 56758 range2.collapse(true); 56759 const rect = range2.getClientRects()[0] || range2.getBoundingClientRect(); 56760 range2.detach(); 56761 return rect || null; 56762 } 56763 #textNodePosition(element, offset3) { 56764 const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT); 56765 let remaining = offset3; 56766 let node = walker.nextNode(); 56767 while (node) { 56768 const length = node.textContent.length; 56769 if (remaining <= length) return { node, offset: remaining }; 56770 remaining -= length; 56771 node = walker.nextNode(); 56772 } 56773 return null; 56774 } 56775 }; 56776 56777
56777// app/javascript/src/lexxy/typography_rules.js 56778 var RULES = [ 56779 { pattern: /\.\.\./, replacement: "\u2026" }, 56780 // Multi-character arrows / comparisons 56781 { pattern: /<=>/, replacement: "\u21D4" }, 56782 { pattern: /<->/, replacement: "\u2194" }, 56783 { pattern: /<--/, replacement: "\u2190" }, 56784 { pattern: /-->/, replacement: "\u2192" }, 56785 // Recover when a short rule already ran mid-sequence 56786 { pattern: /â=>/, replacement: "\u21D4" }, 56787 { pattern: /â>/, replacement: "\u2194" }, 56788 { pattern: /â¤>/, replacement: "\u21D4" }, 56789 { pattern: /â>/, replacement: "\u2192" }, 56790 { pattern: /<â/, replacement: "\u2190" }, 56791 { pattern: /â =/, replacement: "\u2262" }, 56792 // Short forms that can still grow: require a following char that isn't a 56793 // continuation (so "<->" / "<=>" / "-->" / "!==" can be typed fully). 56794 { pattern: /<=(?=[^>])/, replacement: "\u2264" }, 56795 { pattern: />=/, replacement: "\u2265" }, 56796 { pattern: /<-(?=[^-=])/, replacement: "\u2190" }, 56797 { pattern: /->/, replacement: "\u2192" }, 56798 { pattern: /--(?=[^>])/, replacement: "\u2014" }, 56799 { pattern: /!==/, replacement: "\u2262" }, 56800 { pattern: /!=(?=[^=])/, replacement: "\u2260" }, 56801 { pattern: /\(c\)/i, replacement: "\xA9" }, 56802 { pattern: /\(tm\)/i, replacement: "\u2122" }, 56803 { pattern: /\(sm\)/i, replacement: "\u2120" }, 56804 { pattern: /\(r\)/i, replacement: "\xAE" }, 56805 { pattern: /(?:^|\s)(1\/2)(?=\s|$)/d, replacement: "\xBD", group: 1 }, 56806 { pattern: /(?:^|\s)(1\/4)(?=\s|$)/d, replacement: "\xBC", group: 1 }, 56807 { pattern: /(?:^|\s)(3\/4)(?=\s|$)/d, replacement: "\xBE", group: 1 }, 56808 { pattern: /\+\/-/, replacement: "\xB1" }, 56809 { pattern: /<</, replacement: "\xAB" }, 56810 { pattern: />>/, replacement: "\xBB" }, 56811 { pattern: /\^2/, replacement: "\xB2" }, 56812 { pattern: /\^3/, replacement: "\xB3" }, 56813 { pattern: /\d+\s?([*x])\s?\d+/id, replacement: "\xD7", group: 1 }, 56814 { 56815 pattern: /(?:^|[\s{[(<'"\u2018\u201C])(")/d, 56816 replacement: "\u201C", 56817 group: 1 56818 }, 56819 { pattern: /"/, replacement: "\u201D" }, 56820 { 56821 pattern: /(?:^|[\s{[(<'"\u2018\u201C])(')/d, 56822 replacement: "\u2018", 56823 group: 1 56824 }, 56825 { pattern: /'/, replacement: "\u2019" } 56826 ]; 56827 function matchFromRule(text2, rule) { 56828 const match = rule.pattern.exec(text2); 56829 if (!match) return null; 56830 if (rule.group != null) { 56831 const indices = match.indices?.[rule.group]; 56832 if (!indices) return null; 56833 return { 56834 start: indices[0], 56835 end: indices[1], 56836 replacement: rule.replacement 56837 }; 56838 } 56839 return { 56840 start: match.index, 56841 end: match.index + match[0].length, 56842 replacement: rule.replacement 56843 }; 56844 } 56845 function isBetterMatch(candidate, current) { 56846 if (!current) return true; 56847 if (candidate.start !== current.start) return candidate.start < current.start; 56848 return candidate.end > current.end; 56849 } 56850 function findTypographyMatch(text2) { 56851 if (!text2) return null; 56852 let best = null; 56853 for (const rule of RULES) { 56854 const candidate = matchFromRule(text2, rule); 56855 if (candidate && isBetterMatch(candidate, best)) { 56856 best = candidate; 56857 } 56858 } 56859 return best; 56860 } 56861 56862
56862// app/javascript/src/lexxy/typography_extension.js 56863 var { 56864 $findMatchingParent: $findMatchingParent10, 56865 $getSelection: $getSelection14, 56866 $isRangeSelection: $isRangeSelection13, 56867 $isTextNode: $isTextNode11, 56868 TextNode: TextNode5 56869 } = Lexical_exports; 56870 function $shouldSkipTypography(node) { 56871 if (!$isTextNode11(node) || !node.isSimpleText() || node.isTextEntity()) return true; 56872 if (node.hasFormat("code")) return true; 56873 return $findMatchingParent10(node, $isCodeNode3) != null; 56874 } 56875 function $applyTypographyTransform(node) { 56876 if ($shouldSkipTypography(node)) return; 56877 const text2 = node.getTextContent(); 56878 const match = findTypographyMatch(text2); 56879 if (!match) return; 56880 const nextText = text2.slice(0, match.start) + match.replacement + text2.slice(match.end); 56881 if (nextText === text2) return; 56882 const selection = $getSelection14(); 56883 const hadFocus = $isRangeSelection13(selection) && selection.anchor.key === node.getKey(); 56884 const anchorOffset = hadFocus ? selection.anchor.offset : null; 56885 node.setTextContent(nextText); 56886 if (hadFocus && anchorOffset != null) { 56887 const delta = match.replacement.length - (match.end - match.start); 56888 const nextOffset = anchorOffset <= match.start ? anchorOffset : anchorOffset >= match.end ? anchorOffset + delta : match.start + match.replacement.length; 56889 const latest = node.getLatest(); 56890 const size2 = latest.getTextContentSize(); 56891 latest.select(Math.max(0, Math.min(nextOffset, size2))); 56892 } 56893 } 56894 var TypographyExtension = class extends LexxyExtension { 56895 get enabled() { 56896 return this.editorElement.supportsRichText; 56897 } 56898 get lexicalExtension() { 56899 return this.defineExtension({ 56900 name: "lexxy/typography", 56901 register: (editor) => editor.registerNodeTransform(TextNode5, $applyTypographyTransform) 56902 }); 56903 } 56904 }; 56905 56906
56906// app/javascript/src/lexxy/caption_editor.js 56907 var CAPTION_SELECTOR = "[data-lexxy-caption-editor]"; 56908 function isCaptionEditorEmpty(input) { 56909 return !input.textContent?.trim(); 56910 } 56911 function placeCaptionEditorCaret(input) { 56912 const selection = window.getSelection(); 56913 if (!selection || document.activeElement !== input) return; 56914 const range2 = document.createRange(); 56915 range2.selectNodeContents(input); 56916 range2.collapse(true); 56917 selection.removeAllRanges(); 56918 selection.addRange(range2); 56919 } 56920 function syncCaptionEditor(input, { placeCaret = false } = {}) { 56921 if (isCaptionEditorEmpty(input)) { 56922 input.dataset.captionEmpty = "true"; 56923 if (document.activeElement === input && !input.querySelector("br")) { 56924 input.innerHTML = "<br>"; 56925 } 56926 } else { 56927 delete input.dataset.captionEmpty; 56928 } 56929 if (placeCaret && isCaptionEditorEmpty(input)) { 56930 requestAnimationFrame(() => placeCaptionEditorCaret(input)); 56931 } 56932 } 56933 function finalizeCaptionEditor(input) { 56934 if (isCaptionEditorEmpty(input)) { 56935 input.dataset.captionEmpty = "true"; 56936 input.innerHTML = ""; 56937 } else { 56938 delete input.dataset.captionEmpty; 56939 } 56940 } 56941 function handleCaptionEditorFocusIn(event) { 56942 const input = event.target.closest?.(CAPTION_SELECTOR); 56943 if (!input) return; 56944 syncCaptionEditor(input, { placeCaret: true }); 56945 } 56946 function handleCaptionEditorFocusOut(event) { 56947 const input = event.target.closest?.(CAPTION_SELECTOR); 56948 if (!input) return; 56949 finalizeCaptionEditor(input); 56950 } 56951 function handleCaptionEditorInput(event) { 56952 const input = event.target.closest?.(CAPTION_SELECTOR); 56953 if (!input) return; 56954 syncCaptionEditor(input); 56955 } 56956 var installed = false; 56957 function installCaptionEditorSupport() { 56958 if (installed) return; 56959 installed = true; 56960 document.addEventListener("focusin", handleCaptionEditorFocusIn, true); 56961 document.addEventListener("focusout", handleCaptionEditorFocusOut, true); 56962 document.addEventListener("input", handleCaptionEditorInput, true); 56963 } 56964 function scheduleCaptionEditorSync(root = document) { 56965 root.querySelectorAll(CAPTION_SELECTOR).forEach((input) => syncCaptionEditor(input)); 56966 } 56967 56968
56968// app/javascript/src/lexxy/toggle_list_content.js 56969 var READONLY_TOGGLE_LIST_SELECTOR = ":is(.trix-content, .lexxy-content) .lexxy-toggle-list"; 56970 var TOGGLE_LIST_BUTTON_CLASS2 = "lexxy-toggle-list__button"; 56971 function readOnlyToggleLists(root = document) { 56972 return root.querySelectorAll(READONLY_TOGGLE_LIST_SELECTOR); 56973 } 56974 function isReadOnlyToggleList(toggleList) { 56975 return toggleList && !toggleList.closest("lexxy-editor"); 56976 } 56977 function createReadOnlyToggleButton(toggleList) { 56978 const button = document.createElement("button"); 56979 button.type = "button"; 56980 button.className = TOGGLE_LIST_BUTTON_CLASS2; 56981 button.tabIndex = 0; 56982 button.setAttribute("aria-label", "Toggle list contents"); 56983 button.innerHTML = ` 56984 <svg aria-hidden="true" focusable="false" viewBox="0 0 12 12"> 56985 <path d="M1.5 2.31061C1.5 0.943037 2.99801 0.103919 4.16406 0.818427L10.1855 4.50788C11.2997 5.19065 11.2997 6.80949 10.1855 7.49226L4.16406 11.1817C2.99802 11.8962 1.5 11.0571 1.5 9.68952V2.31061Z" fill="currentColor"></path> 56986 </svg> 56987 `; 56988 button.setAttribute("aria-expanded", toggleList.getAttribute("aria-expanded") || "true"); 56989 return button; 56990 } 56991 function hydrateReadOnlyToggleList(toggleList) { 56992 if (!isReadOnlyToggleList(toggleList)) return; 56993 if (toggleList.querySelector(`.${TOGGLE_LIST_BUTTON_CLASS2}`)) return; 56994 toggleList.insertBefore(createReadOnlyToggleButton(toggleList), toggleList.firstChild); 56995 } 56996 function restoreReadOnlyToggleLists(root = document) { 56997 readOnlyToggleLists(root).forEach((toggleList) => { 56998 if (!isReadOnlyToggleList(toggleList)) return; 56999 toggleList.querySelector(`.${TOGGLE_LIST_BUTTON_CLASS2}`)?.remove(); 57000 }); 57001 } 57002 function syncToggleList(toggleList) { 57003 const open = toggleList.dataset.open !== "false"; 57004 toggleList.dataset.open = open ? "true" : "false"; 57005 toggleList.setAttribute("aria-expanded", open ? "true" : "false"); 57006 toggleList.querySelector(`.${TOGGLE_LIST_BUTTON_CLASS2}`)?.setAttribute("aria-expanded", open ? "true" : "false"); 57007 } 57008 function toggleReadOnlyToggleList(toggleList) { 57009 toggleList.dataset.open = toggleList.dataset.open === "false" ? "true" : "false"; 57010 syncToggleList(toggleList); 57011 } 57012 function readOnlyToggleListForButton(target) { 57013 if (!(target instanceof Element)) return null; 57014 const button = target.closest(`.${TOGGLE_LIST_BUTTON_CLASS2}`); 57015 if (!button) return null; 57016 const toggleList = button.closest(READONLY_TOGGLE_LIST_SELECTOR); 57017 return isReadOnlyToggleList(toggleList) ? toggleList : null; 57018 } 57019 function handleReadOnlyToggleListClick(event) { 57020 const toggleList = readOnlyToggleListForButton(event.target); 57021 if (!toggleList) return; 57022 event.preventDefault(); 57023 toggleReadOnlyToggleList(toggleList); 57024 } 57025 function handleReadOnlyToggleListKeydown(event) { 57026 if (event.key !== " " && event.key !== "Enter") return; 57027 const toggleList = readOnlyToggleListForButton(event.target); 57028 if (!toggleList) return; 57029 event.preventDefault(); 57030 toggleReadOnlyToggleList(toggleList); 57031 } 57032 function prepareReadOnlyToggleLists(root = document) { 57033 readOnlyToggleLists(root).forEach((toggleList) => { 57034 if (!isReadOnlyToggleList(toggleList)) return; 57035 hydrateReadOnlyToggleList(toggleList); 57036 syncToggleList(toggleList); 57037 }); 57038 } 57039 document.addEventListener("click", handleReadOnlyToggleListClick); 57040 document.addEventListener("keydown", handleReadOnlyToggleListKeydown); 57041 document.addEventListener("turbo:load", () => prepareReadOnlyToggleLists()); 57042 document.addEventListener("turbo:render", () => prepareReadOnlyToggleLists()); 57043 document.addEventListener("turbo:frame-load", (event) => prepareReadOnlyToggleLists(event.target)); 57044 document.addEventListener("turbo:before-cache", () => restoreReadOnlyToggleLists()); 57045 if (document.readyState === "complete" || document.readyState === "interactive") { 57046 prepareReadOnlyToggleLists(); 57047 } else { 57048 document.addEventListener("DOMContentLoaded", () => prepareReadOnlyToggleLists(), { once: true }); 57049 } 57050 57051
57051// app/javascript/src/actiontext.js 57052 installCaptionEditorSupport(); 57053 configure({ 57054 global: { 57055 extensions: [ 57056 CalloutExtension, 57057 ChecklistExtension, 57058 EmojiPromptExtension, 57059 HexColorExtension, 57060 ImageExtension, 57061 SlashCommandsExtension, 57062 ToggleListExtension, 57063 TypographyExtension 57064 ] 57065 }, 57066 default: { 57067 toolbar: { 57068 upload: "both" 57069 } 57070 } 57071 }); 57072 Promise.resolve().then(() => init_actiontext_esm()); 57073 function refreshRichEmbeds() { 57074 highlightCode(); 57075 scheduleCodeBlockCopyButtons(); 57076 scheduleCalloutHydration(); 57077 scheduleHexColorHydration(); 57078 renderTwitterEmbeds(); 57079 renderInstagramEmbeds(); 57080 renderTikTokEmbeds(); 57081 renderFacebookEmbeds(); 57082 renderAirtableEmbeds(); 57083 renderResponsiveEmbeds(); 57084 decorateEmbedBadges(); 57085 } 57086 function refreshLexxyToolbarIcons(root = document) { 57087 requestAnimationFrame(() => enhanceLexxyToolbarIcons(root)); 57088 } 57089 document.addEventListener("turbo:load", refreshRichEmbeds); 57090 document.addEventListener("turbo:load", () => refreshLexxyToolbarIcons()); 57091 document.addEventListener("turbo:render", refreshRichEmbeds); 57092 document.addEventListener("turbo:render", () => refreshLexxyToolbarIcons()); 57093 document.addEventListener("turbo:morph", refreshRichEmbeds); 57094 document.addEventListener("turbo:morph", () => refreshLexxyToolbarIcons()); 57095 document.addEventListener("lexxy:initialize", (event) => { 57096 scheduleCaptionEditorSync(event.target); 57097 scheduleCalloutHydration(event.target); 57098 scheduleHexColorHydration(event.target); 57099 scheduleTwitterEmbeds(event.target); 57100 scheduleInstagramEmbeds(event.target); 57101 scheduleTikTokEmbeds(event.target); 57102 scheduleFacebookEmbeds(event.target); 57103 scheduleAirtableEmbeds(event.target); 57104 scheduleResponsiveEmbeds(event.target); 57105 decorateEmbedBadges(event.target); 57106 refreshLexxyToolbarIcons(event.target); 57107 }); 57108 document.addEventListener("lexxy:editor-initialized", (event) => { 57109 scheduleCaptionEditorSync(event.target); 57110 scheduleCalloutHydration(event.target); 57111 scheduleHexColorHydration(event.target); 57112 scheduleTwitterEmbeds(event.target); 57113 scheduleInstagramEmbeds(event.target); 57114 scheduleTikTokEmbeds(event.target); 57115 scheduleFacebookEmbeds(event.target); 57116 scheduleAirtableEmbeds(event.target); 57117 scheduleResponsiveEmbeds(event.target); 57118 decorateEmbedBadges(event.target); 57119 refreshLexxyToolbarIcons(event.target); 57120 }); 57121 document.addEventListener("lexxy:change", (event) => { 57122 if (event.target?.matches?.("lexxy-editor")) { 57123 scheduleCalloutHydration(event.target); 57124 scheduleHexColorHydration(event.target); 57125 scheduleTwitterEmbeds(event.target); 57126 scheduleInstagramEmbeds(event.target); 57127 scheduleTikTokEmbeds(event.target); 57128 scheduleFacebookEmbeds(event.target); 57129 scheduleAirtableEmbeds(event.target); 57130 scheduleResponsiveEmbeds(event.target); 57131 decorateEmbedBadges(event.target); 57132 refreshLexxyToolbarIcons(event.target); 57133 } 57134 }); 57135 57136
vendor: 16,768 bytes, lines 57136-57614
57136// node_modules/@hotwired/stimulus/dist/stimulus.js 57137 function camelize(value) { 57138 return value.replace(/(?:[_-])([a-z0-9])/g, (_3, char) => char.toUpperCase()); 57139 } 57140 function namespaceCamelize(value) { 57141 return camelize(value.replace(/--/g, "-").replace(/__/g, "_")); 57142 } 57143 function capitalize2(value) { 57144 return value.charAt(0).toUpperCase() + value.slice(1); 57145 } 57146 function dasherize2(value) { 57147 return value.replace(/([A-Z])/g, (_3, char) => `-${char.toLowerCase()}`); 57148 } 57149 function isSomething(object) { 57150 return object !== null && object !== void 0; 57151 } 57152 function hasProperty(object, property) { 57153 return Object.prototype.hasOwnProperty.call(object, property); 57154 } 57155 function readInheritableStaticArrayValues(constructor, propertyName) { 57156 const ancestors = getAncestorsForConstructor(constructor); 57157 return Array.from(ancestors.reduce((values, constructor2) => { 57158 getOwnStaticArrayValues(constructor2, propertyName).forEach((name) => values.add(name)); 57159 return values; 57160 }, /* @__PURE__ */ new Set())); 57161 } 57162 function readInheritableStaticObjectPairs(constructor, propertyName) { 57163 const ancestors = getAncestorsForConstructor(constructor); 57164 return ancestors.reduce((pairs, constructor2) => { 57165 pairs.push(...getOwnStaticObjectPairs(constructor2, propertyName)); 57166 return pairs; 57167 }, []); 57168 } 57169 function getAncestorsForConstructor(constructor) { 57170 const ancestors = []; 57171 while (constructor) { 57172 ancestors.push(constructor); 57173 constructor = Object.getPrototypeOf(constructor); 57174 } 57175 return ancestors.reverse(); 57176 } 57177 function getOwnStaticArrayValues(constructor, propertyName) { 57178 const definition = constructor[propertyName]; 57179 return Array.isArray(definition) ? definition : []; 57180 } 57181 function getOwnStaticObjectPairs(constructor, propertyName) { 57182 const definition = constructor[propertyName]; 57183 return definition ? Object.keys(definition).map((key) => [key, definition[key]]) : []; 57184 } 57185 var getOwnKeys = (() => { 57186 if (typeof Object.getOwnPropertySymbols == "function") { 57187 return (object) => [...Object.getOwnPropertyNames(object), ...Object.getOwnPropertySymbols(object)]; 57188 } else { 57189 return Object.getOwnPropertyNames; 57190 } 57191 })(); 57192 var extend = (() => { 57193 function extendWithReflect(constructor) { 57194 function extended() { 57195 return Reflect.construct(constructor, arguments, new.target); 57196 } 57197 extended.prototype = Object.create(constructor.prototype, { 57198 constructor: { value: extended } 57199 }); 57200 Reflect.setPrototypeOf(extended, constructor); 57201 return extended; 57202 } 57203 function testReflectExtension() { 57204 const a2 = function() { 57205 this.a.call(this); 57206 }; 57207 const b3 = extendWithReflect(a2); 57208 b3.prototype.a = function() { 57209 }; 57210 return new b3(); 57211 } 57212 try { 57213 testReflectExtension(); 57214 return extendWithReflect; 57215 } catch (error) { 57216 return (constructor) => class extended extends constructor { 57217 }; 57218 } 57219 })(); 57220 var defaultSchema = { 57221 controllerAttribute: "data-controller", 57222 actionAttribute: "data-action", 57223 targetAttribute: "data-target", 57224 targetAttributeForScope: (identifier) => `data-${identifier}-target`, 57225 outletAttributeForScope: (identifier, outlet) => `data-${identifier}-${outlet}-outlet`, 57226 keyMappings: Object.assign(Object.assign({ enter: "Enter", tab: "Tab", esc: "Escape", space: " ", up: "ArrowUp", down: "ArrowDown", left: "ArrowLeft", right: "ArrowRight", home: "Home", end: "End", page_up: "PageUp", page_down: "PageDown" }, objectFromEntries("abcdefghijklmnopqrstuvwxyz".split("").map((c2) => [c2, c2]))), objectFromEntries("0123456789".split("").map((n2) => [n2, n2]))) 57227 }; 57228 function objectFromEntries(array) { 57229 return array.reduce((memo, [k2, v3]) => Object.assign(Object.assign({}, memo), { [k2]: v3 }), {}); 57230 } 57231 function ClassPropertiesBlessing(constructor) { 57232 const classes = readInheritableStaticArrayValues(constructor, "classes"); 57233 return classes.reduce((properties, classDefinition) => { 57234 return Object.assign(properties, propertiesForClassDefinition(classDefinition)); 57235 }, {}); 57236 } 57237 function propertiesForClassDefinition(key) { 57238 return { 57239 [`${key}Class`]: { 57240 get() { 57241 const { classes } = this; 57242 if (classes.has(key)) { 57243 return classes.get(key); 57244 } else { 57245 const attribute = classes.getAttributeName(key); 57246 throw new Error(`Missing attribute "${attribute}"`); 57247 } 57248 } 57249 }, 57250 [`${key}Classes`]: { 57251 get() { 57252 return this.classes.getAll(key); 57253 } 57254 }, 57255 [`has${capitalize2(key)}Class`]: { 57256 get() { 57257 return this.classes.has(key); 57258 } 57259 } 57260 }; 57261 } 57262 function OutletPropertiesBlessing(constructor) { 57263 const outlets = readInheritableStaticArrayValues(constructor, "outlets"); 57264 return outlets.reduce((properties, outletDefinition) => { 57265 return Object.assign(properties, propertiesForOutletDefinition(outletDefinition)); 57266 }, {}); 57267 } 57268 function getOutletController(controller, element, identifier) { 57269 return controller.application.getControllerForElementAndIdentifier(element, identifier); 57270 } 57271 function getControllerAndEnsureConnectedScope(controller, element, outletName) { 57272 let outletController = getOutletController(controller, element, outletName); 57273 if (outletController) 57274 return outletController; 57275 controller.application.router.proposeToConnectScopeForElementAndIdentifier(element, outletName); 57276 outletController = getOutletController(controller, element, outletName); 57277 if (outletController) 57278 return outletController; 57279 } 57280 function propertiesForOutletDefinition(name) { 57281 const camelizedName = namespaceCamelize(name); 57282 return { 57283 [`${camelizedName}Outlet`]: { 57284 get() { 57285 const outletElement = this.outlets.find(name); 57286 const selector = this.outlets.getSelectorForOutletName(name); 57287 if (outletElement) { 57288 const outletController = getControllerAndEnsureConnectedScope(this, outletElement, name); 57289 if (outletController) 57290 return outletController; 57291 throw new Error(`The provided outlet element is missing an outlet controller "${name}" instance for host controller "${this.identifier}"`); 57292 } 57293 throw new Error(`Missing outlet element "${name}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${selector}".`); 57294 } 57295 }, 57296 [`${camelizedName}Outlets`]: { 57297 get() { 57298 const outlets = this.outlets.findAll(name); 57299 if (outlets.length > 0) { 57300 return outlets.map((outletElement) => { 57301 const outletController = getControllerAndEnsureConnectedScope(this, outletElement, name); 57302 if (outletController) 57303 return outletController; 57304 console.warn(`The provided outlet element is missing an outlet controller "${name}" instance for host controller "${this.identifier}"`, outletElement); 57305 }).filter((controller) => controller); 57306 } 57307 return []; 57308 } 57309 }, 57310 [`${camelizedName}OutletElement`]: { 57311 get() { 57312 const outletElement = this.outlets.find(name); 57313 const selector = this.outlets.getSelectorForOutletName(name); 57314 if (outletElement) { 57315 return outletElement; 57316 } else { 57317 throw new Error(`Missing outlet element "${name}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${selector}".`); 57318 } 57319 } 57320 }, 57321 [`${camelizedName}OutletElements`]: { 57322 get() { 57323 return this.outlets.findAll(name); 57324 } 57325 }, 57326 [`has${capitalize2(camelizedName)}Outlet`]: { 57327 get() { 57328 return this.outlets.has(name); 57329 } 57330 } 57331 }; 57332 } 57333 function TargetPropertiesBlessing(constructor) { 57334 const targets = readInheritableStaticArrayValues(constructor, "targets"); 57335 return targets.reduce((properties, targetDefinition) => { 57336 return Object.assign(properties, propertiesForTargetDefinition(targetDefinition)); 57337 }, {}); 57338 } 57339 function propertiesForTargetDefinition(name) { 57340 return { 57341 [`${name}Target`]: { 57342 get() { 57343 const target = this.targets.find(name); 57344 if (target) { 57345 return target; 57346 } else { 57347 throw new Error(`Missing target element "${name}" for "${this.identifier}" controller`); 57348 } 57349 } 57350 }, 57351 [`${name}Targets`]: { 57352 get() { 57353 return this.targets.findAll(name); 57354 } 57355 }, 57356 [`has${capitalize2(name)}Target`]: { 57357 get() { 57358 return this.targets.has(name); 57359 } 57360 } 57361 }; 57362 } 57363 function ValuePropertiesBlessing(constructor) { 57364 const valueDefinitionPairs = readInheritableStaticObjectPairs(constructor, "values"); 57365 const propertyDescriptorMap = { 57366 valueDescriptorMap: { 57367 get() { 57368 return valueDefinitionPairs.reduce((result, valueDefinitionPair) => { 57369 const valueDescriptor = parseValueDefinitionPair(valueDefinitionPair, this.identifier); 57370 const attributeName = this.data.getAttributeNameForKey(valueDescriptor.key); 57371 return Object.assign(result, { [attributeName]: valueDescriptor }); 57372 }, {}); 57373 } 57374 } 57375 }; 57376 return valueDefinitionPairs.reduce((properties, valueDefinitionPair) => { 57377 return Object.assign(properties, propertiesForValueDefinitionPair(valueDefinitionPair)); 57378 }, propertyDescriptorMap); 57379 } 57380 function propertiesForValueDefinitionPair(valueDefinitionPair, controller) { 57381 const definition = parseValueDefinitionPair(valueDefinitionPair, controller); 57382 const { key, name, reader: read, writer: write } = definition; 57383 return { 57384 [name]: { 57385 get() { 57386 const value = this.data.get(key); 57387 if (value !== null) { 57388 return read(value); 57389 } else { 57390 return definition.defaultValue; 57391 } 57392 }, 57393 set(value) { 57394 if (value === void 0) { 57395 this.data.delete(key); 57396 } else { 57397 this.data.set(key, write(value)); 57398 } 57399 } 57400 }, 57401 [`has${capitalize2(name)}`]: { 57402 get() { 57403 return this.data.has(key) || definition.hasCustomDefaultValue; 57404 } 57405 } 57406 }; 57407 } 57408 function parseValueDefinitionPair([token, typeDefinition], controller) { 57409 return valueDescriptorForTokenAndTypeDefinition({ 57410 controller, 57411 token, 57412 typeDefinition 57413 }); 57414 } 57415 function parseValueTypeConstant(constant) { 57416 switch (constant) { 57417 case Array: 57418 return "array"; 57419 case Boolean: 57420 return "boolean"; 57421 case Number: 57422 return "number"; 57423 case Object: 57424 return "object"; 57425 case String: 57426 return "string"; 57427 } 57428 } 57429 function parseValueTypeDefault(defaultValue) { 57430 switch (typeof defaultValue) { 57431 case "boolean": 57432 return "boolean"; 57433 case "number": 57434 return "number"; 57435 case "string": 57436 return "string"; 57437 } 57438 if (Array.isArray(defaultValue)) 57439 return "array"; 57440 if (Object.prototype.toString.call(defaultValue) === "[object Object]") 57441 return "object"; 57442 } 57443 function parseValueTypeObject(payload) { 57444 const { controller, token, typeObject } = payload; 57445 const hasType = isSomething(typeObject.type); 57446 const hasDefault = isSomething(typeObject.default); 57447 const fullObject = hasType && hasDefault; 57448 const onlyType = hasType && !hasDefault; 57449 const onlyDefault = !hasType && hasDefault; 57450 const typeFromObject = parseValueTypeConstant(typeObject.type); 57451 const typeFromDefaultValue = parseValueTypeDefault(payload.typeObject.default); 57452 if (onlyType) 57453 return typeFromObject; 57454 if (onlyDefault) 57455 return typeFromDefaultValue; 57456 if (typeFromObject !== typeFromDefaultValue) { 57457 const propertyPath = controller ? `${controller}.${token}` : token; 57458 throw new Error(`The specified default value for the Stimulus Value "${propertyPath}" must match the defined type "${typeFromObject}". The provided default value of "${typeObject.default}" is of type "${typeFromDefaultValue}".`); 57459 } 57460 if (fullObject) 57461 return typeFromObject; 57462 } 57463 function parseValueTypeDefinition(payload) { 57464 const { controller, token, typeDefinition } = payload; 57465 const typeObject = { controller, token, typeObject: typeDefinition }; 57466 const typeFromObject = parseValueTypeObject(typeObject); 57467 const typeFromDefaultValue = parseValueTypeDefault(typeDefinition); 57468 const typeFromConstant = parseValueTypeConstant(typeDefinition); 57469 const type = typeFromObject || typeFromDefaultValue || typeFromConstant; 57470 if (type) 57471 return type; 57472 const propertyPath = controller ? `${controller}.${typeDefinition}` : token; 57473 throw new Error(`Unknown value type "${propertyPath}" for "${token}" value`); 57474 } 57475 function defaultValueForDefinition(typeDefinition) { 57476 const constant = parseValueTypeConstant(typeDefinition); 57477 if (constant) 57478 return defaultValuesByType[constant]; 57479 const hasDefault = hasProperty(typeDefinition, "default"); 57480 const hasType = hasProperty(typeDefinition, "type"); 57481 const typeObject = typeDefinition; 57482 if (hasDefault) 57483 return typeObject.default; 57484 if (hasType) { 57485 const { type } = typeObject; 57486 const constantFromType = parseValueTypeConstant(type); 57487 if (constantFromType) 57488 return defaultValuesByType[constantFromType]; 57489 } 57490 return typeDefinition; 57491 } 57492 function valueDescriptorForTokenAndTypeDefinition(payload) { 57493 const { token, typeDefinition } = payload; 57494 const key = `${dasherize2(token)}-value`; 57495 const type = parseValueTypeDefinition(payload); 57496 return { 57497 type, 57498 key, 57499 name: camelize(key), 57500 get defaultValue() { 57501 return defaultValueForDefinition(typeDefinition); 57502 }, 57503 get hasCustomDefaultValue() { 57504 return parseValueTypeDefault(typeDefinition) !== void 0; 57505 }, 57506 reader: readers[type], 57507 writer: writers[type] || writers.default 57508 }; 57509 } 57510 var defaultValuesByType = { 57511 get array() { 57512 return []; 57513 }, 57514 boolean: false, 57515 number: 0, 57516 get object() { 57517 return {}; 57518 }, 57519 string: "" 57520 }; 57521 var readers = { 57522 array(value) { 57523 const array = JSON.parse(value); 57524 if (!Array.isArray(array)) { 57525 throw new TypeError(`expected value of type "array" but instead got value "${value}" of type "${parseValueTypeDefault(array)}"`); 57526 } 57527 return array; 57528 }, 57529 boolean(value) { 57530 return !(value == "0" || String(value).toLowerCase() == "false"); 57531 }, 57532 number(value) { 57533 return Number(value.replace(/_/g, "")); 57534 }, 57535 object(value) { 57536 const object = JSON.parse(value); 57537 if (object === null || typeof object != "object" || Array.isArray(object)) { 57538 throw new TypeError(`expected value of type "object" but instead got value "${value}" of type "${parseValueTypeDefault(object)}"`); 57539 } 57540 return object; 57541 }, 57542 string(value) { 57543 return value; 57544 } 57545 }; 57546 var writers = { 57547 default: writeString, 57548 array: writeJSON, 57549 object: writeJSON 57550 }; 57551 function writeJSON(value) { 57552 return JSON.stringify(value); 57553 } 57554 function writeString(value) { 57555 return `${value}`; 57556 } 57557 var Controller = class { 57558 constructor(context) { 57559 this.context = context; 57560 } 57561 static get shouldLoad() { 57562 return true; 57563 } 57564 static afterLoad(_identifier, _application) { 57565 return; 57566 } 57567 get application() { 57568 return this.context.application; 57569 } 57570 get scope() { 57571 return this.context.scope; 57572 } 57573 get element() { 57574 return this.scope.element; 57575 } 57576 get identifier() { 57577 return this.scope.identifier; 57578 } 57579 get targets() { 57580 return this.scope.targets; 57581 } 57582 get outlets() { 57583 return this.scope.outlets; 57584 } 57585 get classes() { 57586 return this.scope.classes; 57587 } 57588 get data() { 57589 return this.scope.data; 57590 } 57591 initialize() { 57592 } 57593 connect() { 57594 } 57595 disconnect() { 57596 } 57597 dispatch(eventName, { target = this.element, detail = {}, prefix = this.identifier, bubbles = true, cancelable = true } = {}) { 57598 const type = prefix ? `${prefix}:${eventName}` : eventName; 57599 const event = new CustomEvent(type, { detail, bubbles, cancelable }); 57600 target.dispatchEvent(event); 57601 return event; 57602 } 57603 }; 57604 Controller.blessings = [ 57605 ClassPropertiesBlessing, 57606 TargetPropertiesBlessing, 57607 ValuePropertiesBlessing, 57608 OutletPropertiesBlessing 57609 ]; 57610 Controller.targets = []; 57611 Controller.outlets = []; 57612 Controller.values = {}; 57613 57614
vendor: 2,678 bytes, lines 57614-57694
57614// node_modules/@rails/request.js/src/fetch_response.js 57615 var FetchResponse = class { 57616 constructor(response) { 57617 this.response = response; 57618 } 57619 get statusCode() { 57620 return this.response.status; 57621 } 57622 get redirected() { 57623 return this.response.redirected; 57624 } 57625 get ok() { 57626 return this.response.ok; 57627 } 57628 get unauthenticated() { 57629 return this.statusCode === 401; 57630 } 57631 get unprocessableEntity() { 57632 return this.statusCode === 422; 57633 } 57634 get authenticationURL() { 57635 return this.response.headers.get("WWW-Authenticate"); 57636 } 57637 get contentType() { 57638 const contentType = this.response.headers.get("Content-Type") || ""; 57639 return contentType.replace(/;.*$/, ""); 57640 } 57641 get headers() { 57642 return this.response.headers; 57643 } 57644 get html() { 57645 if (this.contentType.match(/^(application|text)\/(html|xhtml\+xml)$/)) { 57646 return this.text; 57647 } 57648 return Promise.reject(new Error(`Expected an HTML response but got "${this.contentType}" instead`)); 57649 } 57650 get json() { 57651 if (this.contentType.match(/^application\/.*json$/)) { 57652 return this.responseJson || (this.responseJson = this.response.json()); 57653 } 57654 return Promise.reject(new Error(`Expected a JSON response but got "${this.contentType}" instead`)); 57655 } 57656 get text() { 57657 return this.responseText || (this.responseText = this.response.text()); 57658 } 57659 get isTurboStream() { 57660 return this.contentType.match(/^text\/vnd\.turbo-stream\.html/); 57661 } 57662 get isScript() { 57663 return this.contentType.match(/\b(?:java|ecma)script\b/); 57664 } 57665 async renderTurboStream() { 57666 if (this.isTurboStream) { 57667 if (window.Turbo) { 57668 await window.Turbo.renderStreamMessage(await this.text); 57669 } else { 57670 console.warn("You must set `window.Turbo = Turbo` to automatically process Turbo Stream events with request.js"); 57671 } 57672 } else { 57673 return Promise.reject(new Error(`Expected a Turbo Stream response but got "${this.contentType}" instead`)); 57674 } 57675 } 57676 async activeScript() { 57677 if (this.isScript) { 57678 const script = document.createElement("script"); 57679 const metaTag = document.querySelector("meta[name=csp-nonce]"); 57680 if (metaTag) { 57681 const nonce = metaTag.nonce === "" ? metaTag.content : metaTag.nonce; 57682 if (nonce) { 57683 script.setAttribute("nonce", nonce); 57684 } 57685 } 57686 script.innerHTML = await this.text; 57687 document.body.appendChild(script); 57688 } else { 57689 return Promise.reject(new Error(`Expected a Script response but got "${this.contentType}" instead`)); 57690 } 57691 } 57692 }; 57693 57694
vendor: 299 bytes, lines 57694-57707
57694// node_modules/@rails/request.js/src/request_interceptor.js 57695 var RequestInterceptor = class { 57696 static register(interceptor) { 57697 this.interceptor = interceptor; 57698 } 57699 static get() { 57700 return this.interceptor; 57701 } 57702 static reset() { 57703 this.interceptor = void 0; 57704 } 57705 }; 57706 57707
vendor: 1,356 bytes, lines 57707-57750
57707// node_modules/@rails/request.js/src/lib/utils.js 57708 function getCookie(name) { 57709 const cookies = document.cookie ? document.cookie.split("; ") : []; 57710 const prefix = `${encodeURIComponent(name)}=`; 57711 const cookie = cookies.find((cookie2) => cookie2.startsWith(prefix)); 57712 if (cookie) { 57713 const value = cookie.split("=").slice(1).join("="); 57714 if (value) { 57715 return decodeURIComponent(value); 57716 } 57717 } 57718 } 57719 function compact(object) { 57720 const result = {}; 57721 for (const key in object) { 57722 const value = object[key]; 57723 if (value !== void 0) { 57724 result[key] = value; 57725 } 57726 } 57727 return result; 57728 } 57729 function metaContent(name) { 57730 const element = document.head.querySelector(`meta[name="${name}"]`); 57731 return element && element.content; 57732 } 57733 function stringEntriesFromFormData(formData) { 57734 return [...formData].reduce((entries2, [name, value]) => { 57735 return entries2.concat(typeof value === "string" ? [[name, value]] : []); 57736 }, []); 57737 } 57738 function mergeEntries(searchParams, entries2) { 57739 for (const [name, value] of entries2) { 57740 if (value instanceof window.File) continue; 57741 if (searchParams.has(name) && !name.includes("[]")) { 57742 searchParams.delete(name); 57743 searchParams.set(name, value); 57744 } else { 57745 searchParams.append(name, value); 57746 } 57747 } 57748 } 57749 57750
vendor: 4,748 bytes, lines 57750-57895
57750// node_modules/@rails/request.js/src/fetch_request.js 57751 var FetchRequest = class { 57752 constructor(method, url, options = {}) { 57753 this.method = method; 57754 this.options = options; 57755 this.originalUrl = url.toString(); 57756 } 57757 async perform() { 57758 try { 57759 const requestInterceptor = RequestInterceptor.get(); 57760 if (requestInterceptor) { 57761 await requestInterceptor(this); 57762 } 57763 } catch (error) { 57764 console.error(error); 57765 } 57766 const fetch2 = this.responseKind === "turbo-stream" && window.Turbo ? window.Turbo.fetch : window.fetch; 57767 const response = new FetchResponse(await fetch2(this.url, this.fetchOptions)); 57768 if (response.unauthenticated && response.authenticationURL) { 57769 return Promise.reject(window.location.href = response.authenticationURL); 57770 } 57771 if (response.isScript) { 57772 await response.activeScript(); 57773 } 57774 const responseStatusIsTurboStreamable = response.ok || response.unprocessableEntity; 57775 if (responseStatusIsTurboStreamable && response.isTurboStream) { 57776 await response.renderTurboStream(); 57777 } 57778 return response; 57779 } 57780 addHeader(key, value) { 57781 const headers = this.additionalHeaders; 57782 headers[key] = value; 57783 this.options.headers = headers; 57784 } 57785 sameHostname() { 57786 if (!this.originalUrl.startsWith("http:") && !this.originalUrl.startsWith("https:")) { 57787 return true; 57788 } 57789 try { 57790 return new URL(this.originalUrl).hostname === window.location.hostname; 57791 } catch (_3) { 57792 return true; 57793 } 57794 } 57795 get fetchOptions() { 57796 return { 57797 method: this.method.toUpperCase(), 57798 headers: this.headers, 57799 body: this.formattedBody, 57800 signal: this.signal, 57801 credentials: this.credentials, 57802 redirect: this.redirect, 57803 keepalive: this.keepalive 57804 }; 57805 } 57806 get headers() { 57807 const baseHeaders = { 57808 "X-Requested-With": "XMLHttpRequest", 57809 "Content-Type": this.contentType, 57810 Accept: this.accept 57811 }; 57812 if (this.sameHostname()) { 57813 baseHeaders["X-CSRF-Token"] = this.csrfToken; 57814 } 57815 return compact( 57816 Object.assign(baseHeaders, this.additionalHeaders) 57817 ); 57818 } 57819 get csrfToken() { 57820 return getCookie(metaContent("csrf-param")) || metaContent("csrf-token"); 57821 } 57822 get contentType() { 57823 if (this.options.contentType) { 57824 return this.options.contentType; 57825 } else if (this.body == null || this.body instanceof window.FormData) { 57826 return void 0; 57827 } else if (this.body instanceof window.File) { 57828 return this.body.type; 57829 } 57830 return "application/json"; 57831 } 57832 get accept() { 57833 switch (this.responseKind) { 57834 case "html": 57835 return "text/html, application/xhtml+xml"; 57836 case "turbo-stream": 57837 return "text/vnd.turbo-stream.html, text/html, application/xhtml+xml"; 57838 case "json": 57839 return "application/json, application/vnd.api+json"; 57840 case "script": 57841 return "text/javascript, application/javascript"; 57842 default: 57843 return "*/*"; 57844 } 57845 } 57846 get body() { 57847 return this.options.body; 57848 } 57849 get query() { 57850 const originalQuery = (this.originalUrl.split("?")[1] || "").split("#")[0]; 57851 const params = new URLSearchParams(originalQuery); 57852 let requestQuery = this.options.query; 57853 if (requestQuery instanceof window.FormData) { 57854 requestQuery = stringEntriesFromFormData(requestQuery); 57855 } else if (requestQuery instanceof window.URLSearchParams) { 57856 requestQuery = requestQuery.entries(); 57857 } else { 57858 requestQuery = Object.entries(requestQuery || {}); 57859 } 57860 mergeEntries(params, requestQuery); 57861 const query = params.toString(); 57862 return query.length > 0 ? `?${query}` : ""; 57863 } 57864 get url() { 57865 return this.originalUrl.split("?")[0].split("#")[0] + this.query; 57866 } 57867 get responseKind() { 57868 return this.options.responseKind || "html"; 57869 } 57870 get signal() { 57871 return this.options.signal; 57872 } 57873 get redirect() { 57874 return this.options.redirect || "follow"; 57875 } 57876 get credentials() { 57877 return this.options.credentials || "same-origin"; 57878 } 57879 get keepalive() { 57880 return this.options.keepalive || false; 57881 } 57882 get additionalHeaders() { 57883 return this.options.headers || {}; 57884 } 57885 get formattedBody() { 57886 const bodyIsAString = Object.prototype.toString.call(this.body) === "[object String]"; 57887 const contentTypeIsJson = this.headers["Content-Type"] === "application/json"; 57888 if (contentTypeIsJson && !bodyIsAString) { 57889 return JSON.stringify(this.body); 57890 } 57891 return this.body; 57892 } 57893 }; 57894 57895
vendor: 312 bytes, lines 57895-57905
57895// node_modules/@rails/request.js/src/verbs.js 57896 async function get(url, options) { 57897 const request = new FetchRequest("get", url, options); 57898 return request.perform(); 57899 } 57900 async function post(url, options) { 57901 const request = new FetchRequest("post", url, options); 57902 return request.perform(); 57903 } 57904 57905
57905// app/javascript/src/unfurl_link_controller.js 57906 var unfurl_link_controller_default = class extends Controller { 57907 static values = { 57908 url: { type: String, default: "/action_text/embeds" } 57909 }; 57910 connect() { 57911 this.patterns = void 0; 57912 this.currentEmbed = null; 57913 this.embedRequestId = 0; 57914 this.installEmbedPrompt = this.installEmbedPrompt.bind(this); 57915 this.element.addEventListener("lexxy:initialize", this.installEmbedPrompt); 57916 this.element.addEventListener("lexxy:editor-initialized", this.installEmbedPrompt); 57917 queueMicrotask(this.installEmbedPrompt); 57918 } 57919 disconnect() { 57920 this.element.removeEventListener("lexxy:initialize", this.installEmbedPrompt); 57921 this.element.removeEventListener("lexxy:editor-initialized", this.installEmbedPrompt); 57922 } 57923 unfurl(event) { 57924 this.#unfurlLink(event.detail.url, event.detail); 57925 } 57926 installEmbedPrompt() { 57927 const dropdown = this.element.querySelector("lexxy-link-dropdown"); 57928 const panel = dropdown?.querySelector("[data-dropdown-panel]"); 57929 const input = dropdown?.querySelector("input[type='url']"); 57930 if (!dropdown || !panel || !input || panel.querySelector("[data-unfurl-link-embed-hint]")) return; 57931 const hint = document.createElement("div"); 57932 hint.dataset.unfurlLinkEmbedHint = ""; 57933 hint.className = "link_to_embed link_to_embed--hint"; 57934 hint.innerHTML = ` 57935 <p class="link_to_embed__label">Paste a link, or embed using a url from</p> 57936 <div class="link_to_embed__providers" role="group" aria-label="Supported embed providers"> 57937 ${EMBED_PROVIDERS.map((provider) => embedProviderPill(provider)).join("")} 57938 </div> 57939 `; 57940 const container = document.createElement("div"); 57941 container.dataset.unfurlLinkEmbedContainer = ""; 57942 container.dataset.behavior = "embed_container"; 57943 container.className = "link_to_embed link_to_embed--offer"; 57944 container.hidden = true; 57945 container.setAttribute("aria-hidden", "true"); 57946 container.innerHTML = ` 57947 <div class="link_to_embed__card"> 57948 <div class="link_to_embed__details"> 57949 <span class="link_to_embed__provider" data-unfurl-link-embed-provider></span> 57950 <span class="link_to_embed__title" data-unfurl-link-embed-title hidden></span> 57951 </div> 57952 <button type="button" class="link_to_embed__embed-button lexxy-editor__toolbar-button" data-behavior="embed_url" data-unfurl-link-embed-button> 57953 Embed 57954 </button> 57955 </div> 57956 `; 57957 panel.append(hint, container); 57958 const card = container.querySelector(".link_to_embed__card"); 57959 const providerElement = container.querySelector("[data-unfurl-link-embed-provider]"); 57960 const titleElement = container.querySelector("[data-unfurl-link-embed-title]"); 57961 const embedButton = container.querySelector("[data-unfurl-link-embed-button]"); 57962 this.#resetEmbedPrompt(hint, container, providerElement, titleElement, card); 57963 new MutationObserver(() => { 57964 if (panel.hidden) this.#resetEmbedPrompt(hint, container, providerElement, titleElement, card); 57965 }).observe(panel, { attributes: true, attributeFilter: ["hidden"] }); 57966 input.addEventListener( 57967 "input", 57968 () => this.#didInputUrl(input, hint, container, providerElement, titleElement, card) 57969 ); 57970 input.addEventListener( 57971 "focusin", 57972 () => this.#didInputUrl(input, hint, container, providerElement, titleElement, card) 57973 ); 57974 dropdown.querySelector("[data-dropdown-trigger]")?.addEventListener("click", () => { 57975 requestAnimationFrame(() => { 57976 this.#resetEmbedPrompt(hint, container, providerElement, titleElement, card); 57977 this.#didInputUrl(input, hint, container, providerElement, titleElement, card); 57978 }); 57979 }); 57980 embedButton.addEventListener("click", (event) => this.#embedFromPrompt(event, dropdown)); 57981 } 57982 #didInputUrl(input, hint, container, providerElement, titleElement, card) { 57983 const value = input.value.trim(); 57984 if (!value || !input.validity.valid) { 57985 this.#resetEmbedPrompt(hint, container, providerElement, titleElement, card); 57986 return; 57987 } 57988 if (this.patterns === void 0) { 57989 this.#loadPatterns(value, hint, container, providerElement, titleElement, card); 57990 } else if (this.#matchesPattern(value)) { 57991 this.#fetchAndShowEmbed(value, hint, container, providerElement, titleElement, card); 57992 } else { 57993 this.#resetEmbedPrompt(hint, container, providerElement, titleElement, card); 57994 } 57995 } 57996 async #loadPatterns(value, hint, container, providerElement, titleElement, card) { 57997 const response = await get(`${this.urlValue}/patterns.json`, { responseKind: "json" }); 57998 if (response.ok) { 57999 const patterns = await response.json; 58000 this.patterns = patterns.map((pattern) => new RegExp(pattern.source, pattern.options)); 58001 } else { 58002 this.patterns = []; 58003 } 58004 if (this.#matchesPattern(value)) { 58005 this.#fetchAndShowEmbed(value, hint, container, providerElement, titleElement, card); 58006 } else { 58007 this.#resetEmbedPrompt(hint, container, providerElement, titleElement, card); 58008 } 58009 } 58010 #matchesPattern(value) { 58011 return this.patterns?.some((pattern) => pattern.test(value)) ?? false; 58012 } 58013 async #fetchAndShowEmbed(url, hint, container, providerElement, titleElement, card) { 58014 const requestId = ++this.embedRequestId; 58015 const metadata = await this.#fetchEmbedMetadata(url); 58016 if (requestId !== this.embedRequestId) return; 58017 if (metadata) { 58018 this.#showEmbedPrompt(metadata, hint, container, providerElement, titleElement, card, requestId); 58019 } else { 58020 this.#resetEmbedPrompt(hint, container, providerElement, titleElement, card); 58021 } 58022 } 58023 #showEmbedPrompt(metadata, hint, container, providerElement, titleElement, card, requestId) { 58024 this.currentEmbed = metadata; 58025 const providerName = embedProviderDisplayName(metadata.provider_name || "this site");
58026 const providerIcon = embedProviderIconForName(providerName); 58027 providerElement.innerHTML = `${providerIcon}<span>${providerName}</span>`; 58028 if (metadata.title) { 58029 titleElement.textContent = metadata.title; 58030 titleElement.hidden = false; 58031 } else { 58032 titleElement.textContent = ""; 58033 titleElement.hidden = true; 58034 } 58035 this.#setThumbnail(card, metadata.thumbnail_url, requestId); 58036 hint.hidden = true; 58037 hint.setAttribute("aria-hidden", "true"); 58038 container.hidden = false; 58039 container.removeAttribute("aria-hidden"); 58040 } 58041 #clearThumbnail(card) { 58042 card.querySelector("[data-unfurl-link-embed-thumbnail]")?.remove(); 58043 card.classList.remove("link_to_embed--has-thumbnail"); 58044 } 58045 #setThumbnail(card, url, requestId) { 58046 this.#clearThumbnail(card); 58047 const thumbnailUrl = url?.trim(); 58048 if (!thumbnailUrl || ["undefined", "null"].includes(thumbnailUrl)) return; 58049 const thumbnail = document.createElement("img"); 58050 thumbnail.className = "link_to_embed__thumbnail"; 58051 thumbnail.alt = ""; 58052 thumbnail.dataset.unfurlLinkEmbedThumbnail = ""; 58053 const isCurrentRequest = () => requestId === this.embedRequestId; 58054 thumbnail.addEventListener( 58055 "load", 58056 () => { 58057 if (!isCurrentRequest()) return; 58058 if (thumbnail.naturalWidth === 0) { 58059 this.#clearThumbnail(card); 58060 return; 58061 } 58062 card.classList.add("link_to_embed--has-thumbnail"); 58063 card.prepend(thumbnail); 58064 }, 58065 { once: true } 58066 ); 58067 thumbnail.addEventListener( 58068 "error", 58069 () => { 58070 if (!isCurrentRequest()) return; 58071 this.#clearThumbnail(card); 58072 }, 58073 { once: true } 58074 ); 58075 thumbnail.src = thumbnailUrl; 58076 } 58077 #resetEmbedPrompt(hint, container, providerElement, titleElement, card) { 58078 this.embedRequestId += 1; 58079 hint.hidden = false; 58080 hint.removeAttribute("aria-hidden"); 58081 container.hidden = true; 58082 container.setAttribute("aria-hidden", "true"); 58083 this.currentEmbed = null; 58084 providerElement.innerHTML = ""; 58085 titleElement.textContent = ""; 58086 titleElement.hidden = true; 58087 this.#clearThumbnail(card); 58088 } 58089 async #unfurlLink(url, callbacks) { 58090 if (!url || !callbacks?.insertBelowLink) return; 58091 const metadata = await this.#fetchEmbedMetadata(url); 58092 if (!metadata) return; 58093 this.#insertUnfurledLink(metadata, callbacks); 58094 } 58095 #insertUnfurledLink(metadata, callbacks) { 58096 callbacks.insertBelowLink(metadata.content, { 58097 attachment: { 58098 sgid: metadata.sgid, 58099 contentType: metadata.content_type 58100 } 58101 }); 58102 } 58103 async #embedFromPrompt(event, dropdown) { 58104 event.preventDefault(); 58105 event.stopPropagation(); 58106 if (!this.currentEmbed) return; 58107 const metadata = this.currentEmbed; 58108 this.#closeDropdown(dropdown); 58109 await new Promise((resolve) => requestAnimationFrame(resolve)); 58110 this.#insertEmbedAttachment(metadata); 58111 this.currentEmbed = null; 58112 } 58113 #insertEmbedAttachment(metadata) { 58114 const attachment = document.createElement("action-text-attachment"); 58115 attachment.setAttribute("sgid", metadata.sgid); 58116 attachment.setAttribute("content-type", metadata.content_type); 58117 attachment.setAttribute("content", metadata.content); 58118 const doc = document.implementation.createHTMLDocument(""); 58119 doc.body.appendChild(attachment); 58120 this.element.contents?.insertDOM(doc); 58121 scheduleTwitterEmbeds(this.element); 58122 scheduleInstagramEmbeds(this.element); 58123 scheduleTikTokEmbeds(this.element); 58124 scheduleFacebookEmbeds(this.element); 58125 scheduleAirtableEmbeds(this.element); 58126 scheduleResponsiveEmbeds(this.element); 58127 } 58128 async #fetchEmbedMetadata(url) { 58129 const response = await post(this.urlValue, { 58130 body: { id: url }, 58131 responseKind: "json" 58132 }); 58133 if (!response.ok) return null; 58134 return response.json; 58135 } 58136 #closeDropdown(dropdown) { 58137 if (typeof dropdown.close === "function") { 58138 dropdown.close(); 58139 return; 58140 } 58141 dropdown.querySelector("[data-dropdown-trigger]")?.setAttribute("aria-expanded", "false"); 58142 const panel = dropdown.querySelector("[data-dropdown-panel]"); 58143 if (panel) panel.hidden = true; 58144 this.element.focus(); 58145 } 58146 }; 58147 58148
58148// app/javascript/lexxy_extensions.js 58149 var unfurlLinkRegistered = false; 58150 function registerUnfurlLinkController() { 58151 if (unfurlLinkRegistered || !window.Stimulus) return; 58152 window.Stimulus.register("unfurl-link", unfurl_link_controller_default); 58153 unfurlLinkRegistered = true; 58154 } 58155 queueMicrotask(registerUnfurlLinkController); 58156 document.addEventListener("DOMContentLoaded", registerUnfurlLinkController); 58157 document.addEventListener("turbo:load", registerUnfurlLinkController); 58158})(); 58159/*! Bundled license information: 58160 58161prismjs/prism.js: 58162 (** 58163 * Prism: Lightweight, robust, elegant syntax highlighting 58164 * 58165 * @license MIT <https://opensource.org/licenses/MIT> 58166 * @author Lea Verou <https://lea.verou.me> 58167 * @namespace 58168 * @public 58169 *) 58170 58171dompurify/dist/purify.es.mjs: 58172 (*! @license DOMPurify 3.4.11 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.11/LICENSE *) 58173*/ 58174;
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.