@chayns-components/emoji-input 5.5.66 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,6 +32,9 @@ const serializeSpanElementToText = element => {
32
32
  if (childNodes.length === 0) {
33
33
  return BLOCK_SEPARATOR;
34
34
  }
35
+ if (childNodes.length === 1 && isBreakElement(childNodes[0])) {
36
+ return BLOCK_SEPARATOR;
37
+ }
35
38
  return serializeHTMLToText(childNodes);
36
39
  };
37
40
  const serializeHTMLNodeToText = node => {
@@ -55,6 +58,9 @@ const serializeHTMLNodeToText = node => {
55
58
  };
56
59
  const serializeHTMLToText = nodes => {
57
60
  const serializedNodes = Array.from(nodes);
61
+ if (serializedNodes.length === 1 && isBreakElement(serializedNodes[0])) {
62
+ return '';
63
+ }
58
64
  let result = '';
59
65
  let didSerializeBlockElement = false;
60
66
  serializedNodes.forEach(node => {
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","names":["_regex","require","_emoji","BLOCK_ELEMENT_TAG_NAMES","Set","BLOCK_SEPARATOR","isMeaningfulTextNode","node","_node$textContent","nodeType","Node","TEXT_NODE","textContent","length","isBreakElement","ELEMENT_NODE","tagName","serializeBlockElementToText","element","childNodes","Array","from","filter","serializedText","serializeHTMLToText","startsWith","slice","serializeSpanElementToText","serializeHTMLNodeToText","has","outerHTML","nodes","serializedNodes","result","didSerializeBlockElement","forEach","serializedNode","isBlockElement","exports","convertTextToHTML","text","document","createElement","style","position","opacity","contentEditable","innerText","body","appendChild","innerHTML","removeChild","unescapeHTML","replace","HTML_A_TAG_REGEX","BB_LC_MENTION_REGEX","BB_NER_IGNORE_REGEX","BB_NER_REPLACE_REGEX","_","prefix","type","value","entity","prefixAttr","BB_IGNORE_EMOJI_REGEX","convertHTMLToText","preserveSpaces","shouldSerializeNoEmojiToBBCode","HTML_BOLD_REGEX","HTML_LC_MENTION_REGEX","HTML_NER_IGNORE_REGEX","HTML_NER_REPLACE_REGEX","HTML_NO_EMOJI_REGEX","container","escapeHTML","getElementTextLength","textLength","e","cleanupEmptyIgnoreEmojiSpans","html"],"sources":["../../../src/utils/text.ts"],"sourcesContent":["import {\n BB_LC_MENTION_REGEX,\n BB_NER_IGNORE_REGEX,\n BB_NER_REPLACE_REGEX,\n BB_IGNORE_EMOJI_REGEX,\n HTML_A_TAG_REGEX,\n HTML_BOLD_REGEX,\n HTML_LC_MENTION_REGEX,\n HTML_NER_IGNORE_REGEX,\n HTML_NER_REPLACE_REGEX,\n HTML_NO_EMOJI_REGEX,\n} from '../constants/regex';\nimport { escapeHTML, unescapeHTML } from './emoji';\n\ninterface ConvertHTMLToTextOptions {\n preserveSpaces?: boolean;\n shouldSerializeNoEmojiToBBCode?: boolean;\n}\n\nconst BLOCK_ELEMENT_TAG_NAMES = new Set(['DIV', 'P']);\nconst BLOCK_SEPARATOR = '<br>';\n\nconst isMeaningfulTextNode = (node: ChildNode) =>\n node.nodeType !== Node.TEXT_NODE || (node.textContent?.length ?? 0) > 0;\n\nconst isBreakElement = (node: ChildNode) =>\n node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === 'BR';\n\nconst serializeBlockElementToText = (element: HTMLElement) => {\n const childNodes = Array.from(element.childNodes).filter(isMeaningfulTextNode);\n\n if (childNodes.length === 0) {\n return '';\n }\n\n if (childNodes.length === 1 && isBreakElement(childNodes[0]!)) {\n return '';\n }\n\n let serializedText = serializeHTMLToText(childNodes);\n\n if (\n childNodes.length > 1 &&\n isBreakElement(childNodes[0]!) &&\n serializedText.startsWith(BLOCK_SEPARATOR)\n ) {\n serializedText = serializedText.slice(BLOCK_SEPARATOR.length);\n }\n\n return serializedText;\n};\n\nconst serializeSpanElementToText = (element: HTMLElement) => {\n const childNodes = Array.from(element.childNodes).filter(isMeaningfulTextNode);\n\n if (childNodes.length === 0) {\n return BLOCK_SEPARATOR;\n }\n\n return serializeHTMLToText(childNodes);\n};\n\nconst serializeHTMLNodeToText = (node: ChildNode): string => {\n if (node.nodeType === Node.TEXT_NODE) {\n return node.textContent ?? '';\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n const element = node as HTMLElement;\n\n if (element.tagName === 'BR') {\n return '<br>';\n }\n\n if (element.tagName === 'SPAN') {\n return serializeSpanElementToText(element);\n }\n\n if (BLOCK_ELEMENT_TAG_NAMES.has(element.tagName)) {\n return serializeBlockElementToText(element);\n }\n\n return element.outerHTML;\n};\n\nexport const serializeHTMLToText = (nodes: NodeListOf<ChildNode> | ChildNode[]) => {\n const serializedNodes = Array.from(nodes);\n\n let result = '';\n let didSerializeBlockElement = false;\n\n serializedNodes.forEach((node) => {\n const serializedNode = serializeHTMLNodeToText(node);\n\n const isBlockElement =\n node.nodeType === Node.ELEMENT_NODE &&\n BLOCK_ELEMENT_TAG_NAMES.has((node as HTMLElement).tagName);\n\n if (!serializedNode && !isBlockElement) {\n return;\n }\n\n if (result && (isBlockElement || didSerializeBlockElement)) {\n result += BLOCK_SEPARATOR;\n }\n\n result += serializedNode;\n didSerializeBlockElement = isBlockElement;\n });\n\n return result;\n};\n\nexport const convertTextToHTML = (text: string) => {\n const element = document.createElement('div');\n\n element.style.position = 'absolute';\n element.style.opacity = '0';\n\n element.contentEditable = 'true';\n element.innerText = text;\n\n document.body.appendChild(element);\n\n let result = element.innerHTML;\n\n document.body.removeChild(element);\n\n result = unescapeHTML(result);\n\n result = result\n .replace(HTML_A_TAG_REGEX, '$1')\n .replace(\n BB_LC_MENTION_REGEX,\n '<lc_mention contenteditable=\"false\" id=\"$1\"><span>@</span>$2</lc_mention>\\u200B',\n )\n .replace(BB_NER_IGNORE_REGEX, '<nerIgnore contenteditable=\"false\">$1</nerIgnore>')\n .replace(\n BB_NER_REPLACE_REGEX,\n (_, prefix: string | undefined, type: string, value: string, entity: string) => {\n const prefixAttr = prefix ? `prefix=\"${prefix}\" ` : '';\n\n return `<nerReplace contenteditable=\"false\" ${prefixAttr}type=\"${type}\" value=\"${value}\">${entity}</nerReplace>`;\n },\n )\n .replace(BB_IGNORE_EMOJI_REGEX, '<span class=\"no-emoji-convert\">$1</span>');\n\n return result;\n};\n\nexport const convertHTMLToText = (\n text: string,\n {\n preserveSpaces = false,\n shouldSerializeNoEmojiToBBCode = true,\n }: ConvertHTMLToTextOptions = {},\n) => {\n let result = text;\n\n result = result\n .replace(HTML_A_TAG_REGEX, '$1')\n .replace(HTML_BOLD_REGEX, '[b]$1[/b]')\n .replace(HTML_LC_MENTION_REGEX, '[lc_mention id=\"$1\"]$2[/lc_mention]')\n .replace(HTML_NER_IGNORE_REGEX, '[nerIgnore]$1[/nerIgnore]')\n .replace(\n HTML_NER_REPLACE_REGEX,\n (_, prefix: string | undefined, type: string, value: string, entity: string) => {\n const prefixAttr = prefix ? `prefix=\"${prefix}\" ` : '';\n\n return `[nerReplace ${prefixAttr}type=\"${type}\" value=\"${value}\"]${entity}[/nerReplace]`;\n },\n )\n .replace(\n HTML_NO_EMOJI_REGEX,\n shouldSerializeNoEmojiToBBCode ? '[ignoreEmoji]$1[/ignoreEmoji]' : '$1',\n );\n\n const container = document.createElement('div');\n\n container.innerHTML = result;\n\n result = serializeHTMLToText(container.childNodes);\n\n if (preserveSpaces) {\n return result\n .replace(/&nbsp;/g, '\\u00A0') // non-breaking space\n .replace(/\\u200B/g, '\\u200B'); // zero-width space (sichtbar gemacht)\n }\n\n // eslint-disable-next-line no-irregular-whitespace\n result = result.replace(/\\u200B/g, '');\n result = escapeHTML(result);\n\n const element = document.createElement('div');\n\n element.style.position = 'absolute';\n element.style.opacity = '0';\n\n element.contentEditable = 'true';\n element.innerHTML = result;\n\n document.body.appendChild(element);\n\n result = element.innerText;\n\n document.body.removeChild(element);\n\n return result;\n};\n\nexport const getElementTextLength = (element: Element) => {\n let textLength = 0;\n\n try {\n textLength = convertHTMLToText(element.outerHTML, {\n shouldSerializeNoEmojiToBBCode: false,\n }).length;\n } catch (e) {\n // Do nothing\n }\n\n return textLength;\n};\n\nexport const cleanupEmptyIgnoreEmojiSpans = (html: string) => {\n // Remove empty no-emoji-convert spans that have no text content\n return html.replace(/<span class=\"no-emoji-convert\"><\\/span>/g, '');\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"text.js","names":["_regex","require","_emoji","BLOCK_ELEMENT_TAG_NAMES","Set","BLOCK_SEPARATOR","isMeaningfulTextNode","node","_node$textContent","nodeType","Node","TEXT_NODE","textContent","length","isBreakElement","ELEMENT_NODE","tagName","serializeBlockElementToText","element","childNodes","Array","from","filter","serializedText","serializeHTMLToText","startsWith","slice","serializeSpanElementToText","serializeHTMLNodeToText","has","outerHTML","nodes","serializedNodes","result","didSerializeBlockElement","forEach","serializedNode","isBlockElement","exports","convertTextToHTML","text","document","createElement","style","position","opacity","contentEditable","innerText","body","appendChild","innerHTML","removeChild","unescapeHTML","replace","HTML_A_TAG_REGEX","BB_LC_MENTION_REGEX","BB_NER_IGNORE_REGEX","BB_NER_REPLACE_REGEX","_","prefix","type","value","entity","prefixAttr","BB_IGNORE_EMOJI_REGEX","convertHTMLToText","preserveSpaces","shouldSerializeNoEmojiToBBCode","HTML_BOLD_REGEX","HTML_LC_MENTION_REGEX","HTML_NER_IGNORE_REGEX","HTML_NER_REPLACE_REGEX","HTML_NO_EMOJI_REGEX","container","escapeHTML","getElementTextLength","textLength","e","cleanupEmptyIgnoreEmojiSpans","html"],"sources":["../../../src/utils/text.ts"],"sourcesContent":["import {\n BB_LC_MENTION_REGEX,\n BB_NER_IGNORE_REGEX,\n BB_NER_REPLACE_REGEX,\n BB_IGNORE_EMOJI_REGEX,\n HTML_A_TAG_REGEX,\n HTML_BOLD_REGEX,\n HTML_LC_MENTION_REGEX,\n HTML_NER_IGNORE_REGEX,\n HTML_NER_REPLACE_REGEX,\n HTML_NO_EMOJI_REGEX,\n} from '../constants/regex';\nimport { escapeHTML, unescapeHTML } from './emoji';\n\ninterface ConvertHTMLToTextOptions {\n preserveSpaces?: boolean;\n shouldSerializeNoEmojiToBBCode?: boolean;\n}\n\nconst BLOCK_ELEMENT_TAG_NAMES = new Set(['DIV', 'P']);\nconst BLOCK_SEPARATOR = '<br>';\n\nconst isMeaningfulTextNode = (node: ChildNode) =>\n node.nodeType !== Node.TEXT_NODE || (node.textContent?.length ?? 0) > 0;\n\nconst isBreakElement = (node: ChildNode) =>\n node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === 'BR';\n\nconst serializeBlockElementToText = (element: HTMLElement) => {\n const childNodes = Array.from(element.childNodes).filter(isMeaningfulTextNode);\n\n if (childNodes.length === 0) {\n return '';\n }\n\n if (childNodes.length === 1 && isBreakElement(childNodes[0]!)) {\n return '';\n }\n\n let serializedText = serializeHTMLToText(childNodes);\n\n if (\n childNodes.length > 1 &&\n isBreakElement(childNodes[0]!) &&\n serializedText.startsWith(BLOCK_SEPARATOR)\n ) {\n serializedText = serializedText.slice(BLOCK_SEPARATOR.length);\n }\n\n return serializedText;\n};\n\nconst serializeSpanElementToText = (element: HTMLElement) => {\n const childNodes = Array.from(element.childNodes).filter(isMeaningfulTextNode);\n\n if (childNodes.length === 0) {\n return BLOCK_SEPARATOR;\n }\n\n if (childNodes.length === 1 && isBreakElement(childNodes[0]!)) {\n return BLOCK_SEPARATOR;\n }\n\n return serializeHTMLToText(childNodes);\n};\n\nconst serializeHTMLNodeToText = (node: ChildNode): string => {\n if (node.nodeType === Node.TEXT_NODE) {\n return node.textContent ?? '';\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n const element = node as HTMLElement;\n\n if (element.tagName === 'BR') {\n return '<br>';\n }\n\n if (element.tagName === 'SPAN') {\n return serializeSpanElementToText(element);\n }\n\n if (BLOCK_ELEMENT_TAG_NAMES.has(element.tagName)) {\n return serializeBlockElementToText(element);\n }\n\n return element.outerHTML;\n};\n\nexport const serializeHTMLToText = (nodes: NodeListOf<ChildNode> | ChildNode[]) => {\n const serializedNodes = Array.from(nodes);\n\n if (serializedNodes.length === 1 && isBreakElement(serializedNodes[0]!)) {\n return '';\n }\n\n let result = '';\n let didSerializeBlockElement = false;\n\n serializedNodes.forEach((node) => {\n const serializedNode = serializeHTMLNodeToText(node);\n\n const isBlockElement =\n node.nodeType === Node.ELEMENT_NODE &&\n BLOCK_ELEMENT_TAG_NAMES.has((node as HTMLElement).tagName);\n\n if (!serializedNode && !isBlockElement) {\n return;\n }\n\n if (result && (isBlockElement || didSerializeBlockElement)) {\n result += BLOCK_SEPARATOR;\n }\n\n result += serializedNode;\n didSerializeBlockElement = isBlockElement;\n });\n\n return result;\n};\n\nexport const convertTextToHTML = (text: string) => {\n const element = document.createElement('div');\n\n element.style.position = 'absolute';\n element.style.opacity = '0';\n\n element.contentEditable = 'true';\n element.innerText = text;\n\n document.body.appendChild(element);\n\n let result = element.innerHTML;\n\n document.body.removeChild(element);\n\n result = unescapeHTML(result);\n\n result = result\n .replace(HTML_A_TAG_REGEX, '$1')\n .replace(\n BB_LC_MENTION_REGEX,\n '<lc_mention contenteditable=\"false\" id=\"$1\"><span>@</span>$2</lc_mention>\\u200B',\n )\n .replace(BB_NER_IGNORE_REGEX, '<nerIgnore contenteditable=\"false\">$1</nerIgnore>')\n .replace(\n BB_NER_REPLACE_REGEX,\n (_, prefix: string | undefined, type: string, value: string, entity: string) => {\n const prefixAttr = prefix ? `prefix=\"${prefix}\" ` : '';\n\n return `<nerReplace contenteditable=\"false\" ${prefixAttr}type=\"${type}\" value=\"${value}\">${entity}</nerReplace>`;\n },\n )\n .replace(BB_IGNORE_EMOJI_REGEX, '<span class=\"no-emoji-convert\">$1</span>');\n\n return result;\n};\n\nexport const convertHTMLToText = (\n text: string,\n {\n preserveSpaces = false,\n shouldSerializeNoEmojiToBBCode = true,\n }: ConvertHTMLToTextOptions = {},\n) => {\n let result = text;\n\n result = result\n .replace(HTML_A_TAG_REGEX, '$1')\n .replace(HTML_BOLD_REGEX, '[b]$1[/b]')\n .replace(HTML_LC_MENTION_REGEX, '[lc_mention id=\"$1\"]$2[/lc_mention]')\n .replace(HTML_NER_IGNORE_REGEX, '[nerIgnore]$1[/nerIgnore]')\n .replace(\n HTML_NER_REPLACE_REGEX,\n (_, prefix: string | undefined, type: string, value: string, entity: string) => {\n const prefixAttr = prefix ? `prefix=\"${prefix}\" ` : '';\n\n return `[nerReplace ${prefixAttr}type=\"${type}\" value=\"${value}\"]${entity}[/nerReplace]`;\n },\n )\n .replace(\n HTML_NO_EMOJI_REGEX,\n shouldSerializeNoEmojiToBBCode ? '[ignoreEmoji]$1[/ignoreEmoji]' : '$1',\n );\n\n const container = document.createElement('div');\n\n container.innerHTML = result;\n\n result = serializeHTMLToText(container.childNodes);\n\n if (preserveSpaces) {\n return result\n .replace(/&nbsp;/g, '\\u00A0') // non-breaking space\n .replace(/\\u200B/g, '\\u200B'); // zero-width space (sichtbar gemacht)\n }\n\n // eslint-disable-next-line no-irregular-whitespace\n result = result.replace(/\\u200B/g, '');\n result = escapeHTML(result);\n\n const element = document.createElement('div');\n\n element.style.position = 'absolute';\n element.style.opacity = '0';\n\n element.contentEditable = 'true';\n element.innerHTML = result;\n\n document.body.appendChild(element);\n\n result = element.innerText;\n\n document.body.removeChild(element);\n\n return result;\n};\n\nexport const getElementTextLength = (element: Element) => {\n let textLength = 0;\n\n try {\n textLength = convertHTMLToText(element.outerHTML, {\n shouldSerializeNoEmojiToBBCode: false,\n }).length;\n } catch (e) {\n // Do nothing\n }\n\n return textLength;\n};\n\nexport const cleanupEmptyIgnoreEmojiSpans = (html: string) => {\n // Remove empty no-emoji-convert spans that have no text content\n return html.replace(/<span class=\"no-emoji-convert\"><\\/span>/g, '');\n};\n"],"mappings":"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","ignoreList":[]}
@@ -17,6 +17,7 @@ const serializeHTML = html => {
17
17
  (0, _vitest.expect)(result.match(/<br>/g) ?? []).toHaveLength(1);
18
18
  });
19
19
  (0, _vitest.it)('preserves line breaks, nesting, and block structure inside spans', () => {
20
+ (0, _vitest.expect)(serializeHTML('<br>')).toBe('');
20
21
  (0, _vitest.expect)(serializeHTML('<span><br></span>')).toBe('<br>');
21
22
  (0, _vitest.expect)(serializeHTML('<span>before<span>nested</span>after</span>')).toBe('beforenestedafter');
22
23
  (0, _vitest.expect)(serializeHTML('<span><div>first</div><p>second</p></span>')).toBe('first<br>second');
@@ -1 +1 @@
1
- {"version":3,"file":"text.test.js","names":["_vitest","require","_text","serializeHTML","html","container","document","createElement","innerHTML","serializeHTMLToText","childNodes","describe","it","result","expect","toBe","not","toContain","match","toHaveLength","convertHTMLToText","preserveSpaces"],"sources":["../../../src/utils/text.test.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest';\nimport { convertHTMLToText, serializeHTMLToText } from './text';\n\nconst serializeHTML = (html: string) => {\n const container = document.createElement('div');\n container.innerHTML = html;\n\n return serializeHTMLToText(container.childNodes);\n};\n\ndescribe('serializeHTMLToText', () => {\n it('normalizes Safari styled spans without losing an empty line', () => {\n const result = serializeHTML(\n 'question?<span style=\"font-size: var(--base-font-size, 15px);\"></span><span style=\"font-size: var(--base-font-size, 15px);\">Unsere Logs…</span>',\n );\n\n expect(result).toBe('question?<br>Unsere Logs…');\n expect(result).not.toContain('<span');\n expect(result).not.toContain('</span>');\n expect(result).not.toContain('style=');\n expect(result.match(/<br>/g) ?? []).toHaveLength(1);\n });\n\n it('preserves line breaks, nesting, and block structure inside spans', () => {\n expect(serializeHTML('<span><br></span>')).toBe('<br>');\n expect(serializeHTML('<span>before<span>nested</span>after</span>')).toBe(\n 'beforenestedafter',\n );\n expect(serializeHTML('<span><div>first</div><p>second</p></span>')).toBe('first<br>second');\n });\n\n it('keeps semantic replacements and unsupported-element fallback behavior', () => {\n expect(\n convertHTMLToText('<span><span class=\"no-emoji-convert\">:smile:</span></span>', {\n preserveSpaces: true,\n }),\n ).toBe('[ignoreEmoji]:smile:[/ignoreEmoji]');\n expect(\n convertHTMLToText(\n '<span><lc_mention id=\"user\"><span>@</span>Jane</lc_mention></span>',\n { preserveSpaces: true },\n ),\n ).toBe('[lc_mention id=\"user\"]Jane[/lc_mention]');\n expect(serializeHTML('<mark>highlighted</mark>')).toBe('<mark>highlighted</mark>');\n });\n});\n"],"mappings":";;AAAA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAD,OAAA;AAEA,MAAME,aAAa,GAAIC,IAAY,IAAK;EACpC,MAAMC,SAAS,GAAGC,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;EAC/CF,SAAS,CAACG,SAAS,GAAGJ,IAAI;EAE1B,OAAO,IAAAK,yBAAmB,EAACJ,SAAS,CAACK,UAAU,CAAC;AACpD,CAAC;AAED,IAAAC,gBAAQ,EAAC,qBAAqB,EAAE,MAAM;EAClC,IAAAC,UAAE,EAAC,6DAA6D,EAAE,MAAM;IACpE,MAAMC,MAAM,GAAGV,aAAa,CACxB,iJACJ,CAAC;IAED,IAAAW,cAAM,EAACD,MAAM,CAAC,CAACE,IAAI,CAAC,2BAA2B,CAAC;IAChD,IAAAD,cAAM,EAACD,MAAM,CAAC,CAACG,GAAG,CAACC,SAAS,CAAC,OAAO,CAAC;IACrC,IAAAH,cAAM,EAACD,MAAM,CAAC,CAACG,GAAG,CAACC,SAAS,CAAC,SAAS,CAAC;IACvC,IAAAH,cAAM,EAACD,MAAM,CAAC,CAACG,GAAG,CAACC,SAAS,CAAC,QAAQ,CAAC;IACtC,IAAAH,cAAM,EAACD,MAAM,CAACK,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAACC,YAAY,CAAC,CAAC,CAAC;EACvD,CAAC,CAAC;EAEF,IAAAP,UAAE,EAAC,kEAAkE,EAAE,MAAM;IACzE,IAAAE,cAAM,EAACX,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAACY,IAAI,CAAC,MAAM,CAAC;IACvD,IAAAD,cAAM,EAACX,aAAa,CAAC,6CAA6C,CAAC,CAAC,CAACY,IAAI,CACrE,mBACJ,CAAC;IACD,IAAAD,cAAM,EAACX,aAAa,CAAC,4CAA4C,CAAC,CAAC,CAACY,IAAI,CAAC,iBAAiB,CAAC;EAC/F,CAAC,CAAC;EAEF,IAAAH,UAAE,EAAC,uEAAuE,EAAE,MAAM;IAC9E,IAAAE,cAAM,EACF,IAAAM,uBAAiB,EAAC,4DAA4D,EAAE;MAC5EC,cAAc,EAAE;IACpB,CAAC,CACL,CAAC,CAACN,IAAI,CAAC,oCAAoC,CAAC;IAC5C,IAAAD,cAAM,EACF,IAAAM,uBAAiB,EACb,oEAAoE,EACpE;MAAEC,cAAc,EAAE;IAAK,CAC3B,CACJ,CAAC,CAACN,IAAI,CAAC,yCAAyC,CAAC;IACjD,IAAAD,cAAM,EAACX,aAAa,CAAC,0BAA0B,CAAC,CAAC,CAACY,IAAI,CAAC,0BAA0B,CAAC;EACtF,CAAC,CAAC;AACN,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"text.test.js","names":["_vitest","require","_text","serializeHTML","html","container","document","createElement","innerHTML","serializeHTMLToText","childNodes","describe","it","result","expect","toBe","not","toContain","match","toHaveLength","convertHTMLToText","preserveSpaces"],"sources":["../../../src/utils/text.test.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest';\nimport { convertHTMLToText, serializeHTMLToText } from './text';\n\nconst serializeHTML = (html: string) => {\n const container = document.createElement('div');\n container.innerHTML = html;\n\n return serializeHTMLToText(container.childNodes);\n};\n\ndescribe('serializeHTMLToText', () => {\n it('normalizes Safari styled spans without losing an empty line', () => {\n const result = serializeHTML(\n 'question?<span style=\"font-size: var(--base-font-size, 15px);\"></span><span style=\"font-size: var(--base-font-size, 15px);\">Unsere Logs…</span>',\n );\n\n expect(result).toBe('question?<br>Unsere Logs…');\n expect(result).not.toContain('<span');\n expect(result).not.toContain('</span>');\n expect(result).not.toContain('style=');\n expect(result.match(/<br>/g) ?? []).toHaveLength(1);\n });\n\n it('preserves line breaks, nesting, and block structure inside spans', () => {\n expect(serializeHTML('<br>')).toBe('');\n expect(serializeHTML('<span><br></span>')).toBe('<br>');\n expect(serializeHTML('<span>before<span>nested</span>after</span>')).toBe(\n 'beforenestedafter',\n );\n expect(serializeHTML('<span><div>first</div><p>second</p></span>')).toBe('first<br>second');\n });\n\n it('keeps semantic replacements and unsupported-element fallback behavior', () => {\n expect(\n convertHTMLToText('<span><span class=\"no-emoji-convert\">:smile:</span></span>', {\n preserveSpaces: true,\n }),\n ).toBe('[ignoreEmoji]:smile:[/ignoreEmoji]');\n expect(\n convertHTMLToText(\n '<span><lc_mention id=\"user\"><span>@</span>Jane</lc_mention></span>',\n { preserveSpaces: true },\n ),\n ).toBe('[lc_mention id=\"user\"]Jane[/lc_mention]');\n expect(serializeHTML('<mark>highlighted</mark>')).toBe('<mark>highlighted</mark>');\n });\n});\n"],"mappings":";;AAAA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAD,OAAA;AAEA,MAAME,aAAa,GAAIC,IAAY,IAAK;EACpC,MAAMC,SAAS,GAAGC,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;EAC/CF,SAAS,CAACG,SAAS,GAAGJ,IAAI;EAE1B,OAAO,IAAAK,yBAAmB,EAACJ,SAAS,CAACK,UAAU,CAAC;AACpD,CAAC;AAED,IAAAC,gBAAQ,EAAC,qBAAqB,EAAE,MAAM;EAClC,IAAAC,UAAE,EAAC,6DAA6D,EAAE,MAAM;IACpE,MAAMC,MAAM,GAAGV,aAAa,CACxB,iJACJ,CAAC;IAED,IAAAW,cAAM,EAACD,MAAM,CAAC,CAACE,IAAI,CAAC,2BAA2B,CAAC;IAChD,IAAAD,cAAM,EAACD,MAAM,CAAC,CAACG,GAAG,CAACC,SAAS,CAAC,OAAO,CAAC;IACrC,IAAAH,cAAM,EAACD,MAAM,CAAC,CAACG,GAAG,CAACC,SAAS,CAAC,SAAS,CAAC;IACvC,IAAAH,cAAM,EAACD,MAAM,CAAC,CAACG,GAAG,CAACC,SAAS,CAAC,QAAQ,CAAC;IACtC,IAAAH,cAAM,EAACD,MAAM,CAACK,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAACC,YAAY,CAAC,CAAC,CAAC;EACvD,CAAC,CAAC;EAEF,IAAAP,UAAE,EAAC,kEAAkE,EAAE,MAAM;IACzE,IAAAE,cAAM,EAACX,aAAa,CAAC,MAAM,CAAC,CAAC,CAACY,IAAI,CAAC,EAAE,CAAC;IACtC,IAAAD,cAAM,EAACX,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAACY,IAAI,CAAC,MAAM,CAAC;IACvD,IAAAD,cAAM,EAACX,aAAa,CAAC,6CAA6C,CAAC,CAAC,CAACY,IAAI,CACrE,mBACJ,CAAC;IACD,IAAAD,cAAM,EAACX,aAAa,CAAC,4CAA4C,CAAC,CAAC,CAACY,IAAI,CAAC,iBAAiB,CAAC;EAC/F,CAAC,CAAC;EAEF,IAAAH,UAAE,EAAC,uEAAuE,EAAE,MAAM;IAC9E,IAAAE,cAAM,EACF,IAAAM,uBAAiB,EAAC,4DAA4D,EAAE;MAC5EC,cAAc,EAAE;IACpB,CAAC,CACL,CAAC,CAACN,IAAI,CAAC,oCAAoC,CAAC;IAC5C,IAAAD,cAAM,EACF,IAAAM,uBAAiB,EACb,oEAAoE,EACpE;MAAEC,cAAc,EAAE;IAAK,CAC3B,CACJ,CAAC,CAACN,IAAI,CAAC,yCAAyC,CAAC;IACjD,IAAAD,cAAM,EAACX,aAAa,CAAC,0BAA0B,CAAC,CAAC,CAACY,IAAI,CAAC,0BAA0B,CAAC;EACtF,CAAC,CAAC;AACN,CAAC,CAAC","ignoreList":[]}
@@ -23,6 +23,9 @@ const serializeSpanElementToText = element => {
23
23
  if (childNodes.length === 0) {
24
24
  return BLOCK_SEPARATOR;
25
25
  }
26
+ if (childNodes.length === 1 && isBreakElement(childNodes[0])) {
27
+ return BLOCK_SEPARATOR;
28
+ }
26
29
  return serializeHTMLToText(childNodes);
27
30
  };
28
31
  const serializeHTMLNodeToText = node => {
@@ -46,6 +49,9 @@ const serializeHTMLNodeToText = node => {
46
49
  };
47
50
  export const serializeHTMLToText = nodes => {
48
51
  const serializedNodes = Array.from(nodes);
52
+ if (serializedNodes.length === 1 && isBreakElement(serializedNodes[0])) {
53
+ return '';
54
+ }
49
55
  let result = '';
50
56
  let didSerializeBlockElement = false;
51
57
  serializedNodes.forEach(node => {
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","names":["BB_LC_MENTION_REGEX","BB_NER_IGNORE_REGEX","BB_NER_REPLACE_REGEX","BB_IGNORE_EMOJI_REGEX","HTML_A_TAG_REGEX","HTML_BOLD_REGEX","HTML_LC_MENTION_REGEX","HTML_NER_IGNORE_REGEX","HTML_NER_REPLACE_REGEX","HTML_NO_EMOJI_REGEX","escapeHTML","unescapeHTML","BLOCK_ELEMENT_TAG_NAMES","Set","BLOCK_SEPARATOR","isMeaningfulTextNode","node","nodeType","Node","TEXT_NODE","textContent","length","isBreakElement","ELEMENT_NODE","tagName","serializeBlockElementToText","element","childNodes","Array","from","filter","serializedText","serializeHTMLToText","startsWith","slice","serializeSpanElementToText","serializeHTMLNodeToText","has","outerHTML","nodes","serializedNodes","result","didSerializeBlockElement","forEach","serializedNode","isBlockElement","convertTextToHTML","text","document","createElement","style","position","opacity","contentEditable","innerText","body","appendChild","innerHTML","removeChild","replace","_","prefix","type","value","entity","prefixAttr","convertHTMLToText","preserveSpaces","shouldSerializeNoEmojiToBBCode","container","getElementTextLength","textLength","e","cleanupEmptyIgnoreEmojiSpans","html"],"sources":["../../../src/utils/text.ts"],"sourcesContent":["import {\n BB_LC_MENTION_REGEX,\n BB_NER_IGNORE_REGEX,\n BB_NER_REPLACE_REGEX,\n BB_IGNORE_EMOJI_REGEX,\n HTML_A_TAG_REGEX,\n HTML_BOLD_REGEX,\n HTML_LC_MENTION_REGEX,\n HTML_NER_IGNORE_REGEX,\n HTML_NER_REPLACE_REGEX,\n HTML_NO_EMOJI_REGEX,\n} from '../constants/regex';\nimport { escapeHTML, unescapeHTML } from './emoji';\n\ninterface ConvertHTMLToTextOptions {\n preserveSpaces?: boolean;\n shouldSerializeNoEmojiToBBCode?: boolean;\n}\n\nconst BLOCK_ELEMENT_TAG_NAMES = new Set(['DIV', 'P']);\nconst BLOCK_SEPARATOR = '<br>';\n\nconst isMeaningfulTextNode = (node: ChildNode) =>\n node.nodeType !== Node.TEXT_NODE || (node.textContent?.length ?? 0) > 0;\n\nconst isBreakElement = (node: ChildNode) =>\n node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === 'BR';\n\nconst serializeBlockElementToText = (element: HTMLElement) => {\n const childNodes = Array.from(element.childNodes).filter(isMeaningfulTextNode);\n\n if (childNodes.length === 0) {\n return '';\n }\n\n if (childNodes.length === 1 && isBreakElement(childNodes[0]!)) {\n return '';\n }\n\n let serializedText = serializeHTMLToText(childNodes);\n\n if (\n childNodes.length > 1 &&\n isBreakElement(childNodes[0]!) &&\n serializedText.startsWith(BLOCK_SEPARATOR)\n ) {\n serializedText = serializedText.slice(BLOCK_SEPARATOR.length);\n }\n\n return serializedText;\n};\n\nconst serializeSpanElementToText = (element: HTMLElement) => {\n const childNodes = Array.from(element.childNodes).filter(isMeaningfulTextNode);\n\n if (childNodes.length === 0) {\n return BLOCK_SEPARATOR;\n }\n\n return serializeHTMLToText(childNodes);\n};\n\nconst serializeHTMLNodeToText = (node: ChildNode): string => {\n if (node.nodeType === Node.TEXT_NODE) {\n return node.textContent ?? '';\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n const element = node as HTMLElement;\n\n if (element.tagName === 'BR') {\n return '<br>';\n }\n\n if (element.tagName === 'SPAN') {\n return serializeSpanElementToText(element);\n }\n\n if (BLOCK_ELEMENT_TAG_NAMES.has(element.tagName)) {\n return serializeBlockElementToText(element);\n }\n\n return element.outerHTML;\n};\n\nexport const serializeHTMLToText = (nodes: NodeListOf<ChildNode> | ChildNode[]) => {\n const serializedNodes = Array.from(nodes);\n\n let result = '';\n let didSerializeBlockElement = false;\n\n serializedNodes.forEach((node) => {\n const serializedNode = serializeHTMLNodeToText(node);\n\n const isBlockElement =\n node.nodeType === Node.ELEMENT_NODE &&\n BLOCK_ELEMENT_TAG_NAMES.has((node as HTMLElement).tagName);\n\n if (!serializedNode && !isBlockElement) {\n return;\n }\n\n if (result && (isBlockElement || didSerializeBlockElement)) {\n result += BLOCK_SEPARATOR;\n }\n\n result += serializedNode;\n didSerializeBlockElement = isBlockElement;\n });\n\n return result;\n};\n\nexport const convertTextToHTML = (text: string) => {\n const element = document.createElement('div');\n\n element.style.position = 'absolute';\n element.style.opacity = '0';\n\n element.contentEditable = 'true';\n element.innerText = text;\n\n document.body.appendChild(element);\n\n let result = element.innerHTML;\n\n document.body.removeChild(element);\n\n result = unescapeHTML(result);\n\n result = result\n .replace(HTML_A_TAG_REGEX, '$1')\n .replace(\n BB_LC_MENTION_REGEX,\n '<lc_mention contenteditable=\"false\" id=\"$1\"><span>@</span>$2</lc_mention>\\u200B',\n )\n .replace(BB_NER_IGNORE_REGEX, '<nerIgnore contenteditable=\"false\">$1</nerIgnore>')\n .replace(\n BB_NER_REPLACE_REGEX,\n (_, prefix: string | undefined, type: string, value: string, entity: string) => {\n const prefixAttr = prefix ? `prefix=\"${prefix}\" ` : '';\n\n return `<nerReplace contenteditable=\"false\" ${prefixAttr}type=\"${type}\" value=\"${value}\">${entity}</nerReplace>`;\n },\n )\n .replace(BB_IGNORE_EMOJI_REGEX, '<span class=\"no-emoji-convert\">$1</span>');\n\n return result;\n};\n\nexport const convertHTMLToText = (\n text: string,\n {\n preserveSpaces = false,\n shouldSerializeNoEmojiToBBCode = true,\n }: ConvertHTMLToTextOptions = {},\n) => {\n let result = text;\n\n result = result\n .replace(HTML_A_TAG_REGEX, '$1')\n .replace(HTML_BOLD_REGEX, '[b]$1[/b]')\n .replace(HTML_LC_MENTION_REGEX, '[lc_mention id=\"$1\"]$2[/lc_mention]')\n .replace(HTML_NER_IGNORE_REGEX, '[nerIgnore]$1[/nerIgnore]')\n .replace(\n HTML_NER_REPLACE_REGEX,\n (_, prefix: string | undefined, type: string, value: string, entity: string) => {\n const prefixAttr = prefix ? `prefix=\"${prefix}\" ` : '';\n\n return `[nerReplace ${prefixAttr}type=\"${type}\" value=\"${value}\"]${entity}[/nerReplace]`;\n },\n )\n .replace(\n HTML_NO_EMOJI_REGEX,\n shouldSerializeNoEmojiToBBCode ? '[ignoreEmoji]$1[/ignoreEmoji]' : '$1',\n );\n\n const container = document.createElement('div');\n\n container.innerHTML = result;\n\n result = serializeHTMLToText(container.childNodes);\n\n if (preserveSpaces) {\n return result\n .replace(/&nbsp;/g, '\\u00A0') // non-breaking space\n .replace(/\\u200B/g, '\\u200B'); // zero-width space (sichtbar gemacht)\n }\n\n // eslint-disable-next-line no-irregular-whitespace\n result = result.replace(/\\u200B/g, '');\n result = escapeHTML(result);\n\n const element = document.createElement('div');\n\n element.style.position = 'absolute';\n element.style.opacity = '0';\n\n element.contentEditable = 'true';\n element.innerHTML = result;\n\n document.body.appendChild(element);\n\n result = element.innerText;\n\n document.body.removeChild(element);\n\n return result;\n};\n\nexport const getElementTextLength = (element: Element) => {\n let textLength = 0;\n\n try {\n textLength = convertHTMLToText(element.outerHTML, {\n shouldSerializeNoEmojiToBBCode: false,\n }).length;\n } catch (e) {\n // Do nothing\n }\n\n return textLength;\n};\n\nexport const cleanupEmptyIgnoreEmojiSpans = (html: string) => {\n // Remove empty no-emoji-convert spans that have no text content\n return html.replace(/<span class=\"no-emoji-convert\"><\\/span>/g, '');\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"text.js","names":["BB_LC_MENTION_REGEX","BB_NER_IGNORE_REGEX","BB_NER_REPLACE_REGEX","BB_IGNORE_EMOJI_REGEX","HTML_A_TAG_REGEX","HTML_BOLD_REGEX","HTML_LC_MENTION_REGEX","HTML_NER_IGNORE_REGEX","HTML_NER_REPLACE_REGEX","HTML_NO_EMOJI_REGEX","escapeHTML","unescapeHTML","BLOCK_ELEMENT_TAG_NAMES","Set","BLOCK_SEPARATOR","isMeaningfulTextNode","node","nodeType","Node","TEXT_NODE","textContent","length","isBreakElement","ELEMENT_NODE","tagName","serializeBlockElementToText","element","childNodes","Array","from","filter","serializedText","serializeHTMLToText","startsWith","slice","serializeSpanElementToText","serializeHTMLNodeToText","has","outerHTML","nodes","serializedNodes","result","didSerializeBlockElement","forEach","serializedNode","isBlockElement","convertTextToHTML","text","document","createElement","style","position","opacity","contentEditable","innerText","body","appendChild","innerHTML","removeChild","replace","_","prefix","type","value","entity","prefixAttr","convertHTMLToText","preserveSpaces","shouldSerializeNoEmojiToBBCode","container","getElementTextLength","textLength","e","cleanupEmptyIgnoreEmojiSpans","html"],"sources":["../../../src/utils/text.ts"],"sourcesContent":["import {\n BB_LC_MENTION_REGEX,\n BB_NER_IGNORE_REGEX,\n BB_NER_REPLACE_REGEX,\n BB_IGNORE_EMOJI_REGEX,\n HTML_A_TAG_REGEX,\n HTML_BOLD_REGEX,\n HTML_LC_MENTION_REGEX,\n HTML_NER_IGNORE_REGEX,\n HTML_NER_REPLACE_REGEX,\n HTML_NO_EMOJI_REGEX,\n} from '../constants/regex';\nimport { escapeHTML, unescapeHTML } from './emoji';\n\ninterface ConvertHTMLToTextOptions {\n preserveSpaces?: boolean;\n shouldSerializeNoEmojiToBBCode?: boolean;\n}\n\nconst BLOCK_ELEMENT_TAG_NAMES = new Set(['DIV', 'P']);\nconst BLOCK_SEPARATOR = '<br>';\n\nconst isMeaningfulTextNode = (node: ChildNode) =>\n node.nodeType !== Node.TEXT_NODE || (node.textContent?.length ?? 0) > 0;\n\nconst isBreakElement = (node: ChildNode) =>\n node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).tagName === 'BR';\n\nconst serializeBlockElementToText = (element: HTMLElement) => {\n const childNodes = Array.from(element.childNodes).filter(isMeaningfulTextNode);\n\n if (childNodes.length === 0) {\n return '';\n }\n\n if (childNodes.length === 1 && isBreakElement(childNodes[0]!)) {\n return '';\n }\n\n let serializedText = serializeHTMLToText(childNodes);\n\n if (\n childNodes.length > 1 &&\n isBreakElement(childNodes[0]!) &&\n serializedText.startsWith(BLOCK_SEPARATOR)\n ) {\n serializedText = serializedText.slice(BLOCK_SEPARATOR.length);\n }\n\n return serializedText;\n};\n\nconst serializeSpanElementToText = (element: HTMLElement) => {\n const childNodes = Array.from(element.childNodes).filter(isMeaningfulTextNode);\n\n if (childNodes.length === 0) {\n return BLOCK_SEPARATOR;\n }\n\n if (childNodes.length === 1 && isBreakElement(childNodes[0]!)) {\n return BLOCK_SEPARATOR;\n }\n\n return serializeHTMLToText(childNodes);\n};\n\nconst serializeHTMLNodeToText = (node: ChildNode): string => {\n if (node.nodeType === Node.TEXT_NODE) {\n return node.textContent ?? '';\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n const element = node as HTMLElement;\n\n if (element.tagName === 'BR') {\n return '<br>';\n }\n\n if (element.tagName === 'SPAN') {\n return serializeSpanElementToText(element);\n }\n\n if (BLOCK_ELEMENT_TAG_NAMES.has(element.tagName)) {\n return serializeBlockElementToText(element);\n }\n\n return element.outerHTML;\n};\n\nexport const serializeHTMLToText = (nodes: NodeListOf<ChildNode> | ChildNode[]) => {\n const serializedNodes = Array.from(nodes);\n\n if (serializedNodes.length === 1 && isBreakElement(serializedNodes[0]!)) {\n return '';\n }\n\n let result = '';\n let didSerializeBlockElement = false;\n\n serializedNodes.forEach((node) => {\n const serializedNode = serializeHTMLNodeToText(node);\n\n const isBlockElement =\n node.nodeType === Node.ELEMENT_NODE &&\n BLOCK_ELEMENT_TAG_NAMES.has((node as HTMLElement).tagName);\n\n if (!serializedNode && !isBlockElement) {\n return;\n }\n\n if (result && (isBlockElement || didSerializeBlockElement)) {\n result += BLOCK_SEPARATOR;\n }\n\n result += serializedNode;\n didSerializeBlockElement = isBlockElement;\n });\n\n return result;\n};\n\nexport const convertTextToHTML = (text: string) => {\n const element = document.createElement('div');\n\n element.style.position = 'absolute';\n element.style.opacity = '0';\n\n element.contentEditable = 'true';\n element.innerText = text;\n\n document.body.appendChild(element);\n\n let result = element.innerHTML;\n\n document.body.removeChild(element);\n\n result = unescapeHTML(result);\n\n result = result\n .replace(HTML_A_TAG_REGEX, '$1')\n .replace(\n BB_LC_MENTION_REGEX,\n '<lc_mention contenteditable=\"false\" id=\"$1\"><span>@</span>$2</lc_mention>\\u200B',\n )\n .replace(BB_NER_IGNORE_REGEX, '<nerIgnore contenteditable=\"false\">$1</nerIgnore>')\n .replace(\n BB_NER_REPLACE_REGEX,\n (_, prefix: string | undefined, type: string, value: string, entity: string) => {\n const prefixAttr = prefix ? `prefix=\"${prefix}\" ` : '';\n\n return `<nerReplace contenteditable=\"false\" ${prefixAttr}type=\"${type}\" value=\"${value}\">${entity}</nerReplace>`;\n },\n )\n .replace(BB_IGNORE_EMOJI_REGEX, '<span class=\"no-emoji-convert\">$1</span>');\n\n return result;\n};\n\nexport const convertHTMLToText = (\n text: string,\n {\n preserveSpaces = false,\n shouldSerializeNoEmojiToBBCode = true,\n }: ConvertHTMLToTextOptions = {},\n) => {\n let result = text;\n\n result = result\n .replace(HTML_A_TAG_REGEX, '$1')\n .replace(HTML_BOLD_REGEX, '[b]$1[/b]')\n .replace(HTML_LC_MENTION_REGEX, '[lc_mention id=\"$1\"]$2[/lc_mention]')\n .replace(HTML_NER_IGNORE_REGEX, '[nerIgnore]$1[/nerIgnore]')\n .replace(\n HTML_NER_REPLACE_REGEX,\n (_, prefix: string | undefined, type: string, value: string, entity: string) => {\n const prefixAttr = prefix ? `prefix=\"${prefix}\" ` : '';\n\n return `[nerReplace ${prefixAttr}type=\"${type}\" value=\"${value}\"]${entity}[/nerReplace]`;\n },\n )\n .replace(\n HTML_NO_EMOJI_REGEX,\n shouldSerializeNoEmojiToBBCode ? '[ignoreEmoji]$1[/ignoreEmoji]' : '$1',\n );\n\n const container = document.createElement('div');\n\n container.innerHTML = result;\n\n result = serializeHTMLToText(container.childNodes);\n\n if (preserveSpaces) {\n return result\n .replace(/&nbsp;/g, '\\u00A0') // non-breaking space\n .replace(/\\u200B/g, '\\u200B'); // zero-width space (sichtbar gemacht)\n }\n\n // eslint-disable-next-line no-irregular-whitespace\n result = result.replace(/\\u200B/g, '');\n result = escapeHTML(result);\n\n const element = document.createElement('div');\n\n element.style.position = 'absolute';\n element.style.opacity = '0';\n\n element.contentEditable = 'true';\n element.innerHTML = result;\n\n document.body.appendChild(element);\n\n result = element.innerText;\n\n document.body.removeChild(element);\n\n return result;\n};\n\nexport const getElementTextLength = (element: Element) => {\n let textLength = 0;\n\n try {\n textLength = convertHTMLToText(element.outerHTML, {\n shouldSerializeNoEmojiToBBCode: false,\n }).length;\n } catch (e) {\n // Do nothing\n }\n\n return textLength;\n};\n\nexport const cleanupEmptyIgnoreEmojiSpans = (html: string) => {\n // Remove empty no-emoji-convert spans that have no text content\n return html.replace(/<span class=\"no-emoji-convert\"><\\/span>/g, '');\n};\n"],"mappings":"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","ignoreList":[]}
@@ -15,6 +15,7 @@ describe('serializeHTMLToText', () => {
15
15
  expect(result.match(/<br>/g) ?? []).toHaveLength(1);
16
16
  });
17
17
  it('preserves line breaks, nesting, and block structure inside spans', () => {
18
+ expect(serializeHTML('<br>')).toBe('');
18
19
  expect(serializeHTML('<span><br></span>')).toBe('<br>');
19
20
  expect(serializeHTML('<span>before<span>nested</span>after</span>')).toBe('beforenestedafter');
20
21
  expect(serializeHTML('<span><div>first</div><p>second</p></span>')).toBe('first<br>second');
@@ -1 +1 @@
1
- {"version":3,"file":"text.test.js","names":["describe","expect","it","convertHTMLToText","serializeHTMLToText","serializeHTML","html","container","document","createElement","innerHTML","childNodes","result","toBe","not","toContain","match","toHaveLength","preserveSpaces"],"sources":["../../../src/utils/text.test.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest';\nimport { convertHTMLToText, serializeHTMLToText } from './text';\n\nconst serializeHTML = (html: string) => {\n const container = document.createElement('div');\n container.innerHTML = html;\n\n return serializeHTMLToText(container.childNodes);\n};\n\ndescribe('serializeHTMLToText', () => {\n it('normalizes Safari styled spans without losing an empty line', () => {\n const result = serializeHTML(\n 'question?<span style=\"font-size: var(--base-font-size, 15px);\"></span><span style=\"font-size: var(--base-font-size, 15px);\">Unsere Logs…</span>',\n );\n\n expect(result).toBe('question?<br>Unsere Logs…');\n expect(result).not.toContain('<span');\n expect(result).not.toContain('</span>');\n expect(result).not.toContain('style=');\n expect(result.match(/<br>/g) ?? []).toHaveLength(1);\n });\n\n it('preserves line breaks, nesting, and block structure inside spans', () => {\n expect(serializeHTML('<span><br></span>')).toBe('<br>');\n expect(serializeHTML('<span>before<span>nested</span>after</span>')).toBe(\n 'beforenestedafter',\n );\n expect(serializeHTML('<span><div>first</div><p>second</p></span>')).toBe('first<br>second');\n });\n\n it('keeps semantic replacements and unsupported-element fallback behavior', () => {\n expect(\n convertHTMLToText('<span><span class=\"no-emoji-convert\">:smile:</span></span>', {\n preserveSpaces: true,\n }),\n ).toBe('[ignoreEmoji]:smile:[/ignoreEmoji]');\n expect(\n convertHTMLToText(\n '<span><lc_mention id=\"user\"><span>@</span>Jane</lc_mention></span>',\n { preserveSpaces: true },\n ),\n ).toBe('[lc_mention id=\"user\"]Jane[/lc_mention]');\n expect(serializeHTML('<mark>highlighted</mark>')).toBe('<mark>highlighted</mark>');\n });\n});\n"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,QAAQ;AAC7C,SAASC,iBAAiB,EAAEC,mBAAmB,QAAQ,QAAQ;AAE/D,MAAMC,aAAa,GAAIC,IAAY,IAAK;EACpC,MAAMC,SAAS,GAAGC,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;EAC/CF,SAAS,CAACG,SAAS,GAAGJ,IAAI;EAE1B,OAAOF,mBAAmB,CAACG,SAAS,CAACI,UAAU,CAAC;AACpD,CAAC;AAEDX,QAAQ,CAAC,qBAAqB,EAAE,MAAM;EAClCE,EAAE,CAAC,6DAA6D,EAAE,MAAM;IACpE,MAAMU,MAAM,GAAGP,aAAa,CACxB,iJACJ,CAAC;IAEDJ,MAAM,CAACW,MAAM,CAAC,CAACC,IAAI,CAAC,2BAA2B,CAAC;IAChDZ,MAAM,CAACW,MAAM,CAAC,CAACE,GAAG,CAACC,SAAS,CAAC,OAAO,CAAC;IACrCd,MAAM,CAACW,MAAM,CAAC,CAACE,GAAG,CAACC,SAAS,CAAC,SAAS,CAAC;IACvCd,MAAM,CAACW,MAAM,CAAC,CAACE,GAAG,CAACC,SAAS,CAAC,QAAQ,CAAC;IACtCd,MAAM,CAACW,MAAM,CAACI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAACC,YAAY,CAAC,CAAC,CAAC;EACvD,CAAC,CAAC;EAEFf,EAAE,CAAC,kEAAkE,EAAE,MAAM;IACzED,MAAM,CAACI,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAACQ,IAAI,CAAC,MAAM,CAAC;IACvDZ,MAAM,CAACI,aAAa,CAAC,6CAA6C,CAAC,CAAC,CAACQ,IAAI,CACrE,mBACJ,CAAC;IACDZ,MAAM,CAACI,aAAa,CAAC,4CAA4C,CAAC,CAAC,CAACQ,IAAI,CAAC,iBAAiB,CAAC;EAC/F,CAAC,CAAC;EAEFX,EAAE,CAAC,uEAAuE,EAAE,MAAM;IAC9ED,MAAM,CACFE,iBAAiB,CAAC,4DAA4D,EAAE;MAC5Ee,cAAc,EAAE;IACpB,CAAC,CACL,CAAC,CAACL,IAAI,CAAC,oCAAoC,CAAC;IAC5CZ,MAAM,CACFE,iBAAiB,CACb,oEAAoE,EACpE;MAAEe,cAAc,EAAE;IAAK,CAC3B,CACJ,CAAC,CAACL,IAAI,CAAC,yCAAyC,CAAC;IACjDZ,MAAM,CAACI,aAAa,CAAC,0BAA0B,CAAC,CAAC,CAACQ,IAAI,CAAC,0BAA0B,CAAC;EACtF,CAAC,CAAC;AACN,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"text.test.js","names":["describe","expect","it","convertHTMLToText","serializeHTMLToText","serializeHTML","html","container","document","createElement","innerHTML","childNodes","result","toBe","not","toContain","match","toHaveLength","preserveSpaces"],"sources":["../../../src/utils/text.test.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest';\nimport { convertHTMLToText, serializeHTMLToText } from './text';\n\nconst serializeHTML = (html: string) => {\n const container = document.createElement('div');\n container.innerHTML = html;\n\n return serializeHTMLToText(container.childNodes);\n};\n\ndescribe('serializeHTMLToText', () => {\n it('normalizes Safari styled spans without losing an empty line', () => {\n const result = serializeHTML(\n 'question?<span style=\"font-size: var(--base-font-size, 15px);\"></span><span style=\"font-size: var(--base-font-size, 15px);\">Unsere Logs…</span>',\n );\n\n expect(result).toBe('question?<br>Unsere Logs…');\n expect(result).not.toContain('<span');\n expect(result).not.toContain('</span>');\n expect(result).not.toContain('style=');\n expect(result.match(/<br>/g) ?? []).toHaveLength(1);\n });\n\n it('preserves line breaks, nesting, and block structure inside spans', () => {\n expect(serializeHTML('<br>')).toBe('');\n expect(serializeHTML('<span><br></span>')).toBe('<br>');\n expect(serializeHTML('<span>before<span>nested</span>after</span>')).toBe(\n 'beforenestedafter',\n );\n expect(serializeHTML('<span><div>first</div><p>second</p></span>')).toBe('first<br>second');\n });\n\n it('keeps semantic replacements and unsupported-element fallback behavior', () => {\n expect(\n convertHTMLToText('<span><span class=\"no-emoji-convert\">:smile:</span></span>', {\n preserveSpaces: true,\n }),\n ).toBe('[ignoreEmoji]:smile:[/ignoreEmoji]');\n expect(\n convertHTMLToText(\n '<span><lc_mention id=\"user\"><span>@</span>Jane</lc_mention></span>',\n { preserveSpaces: true },\n ),\n ).toBe('[lc_mention id=\"user\"]Jane[/lc_mention]');\n expect(serializeHTML('<mark>highlighted</mark>')).toBe('<mark>highlighted</mark>');\n });\n});\n"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,QAAQ;AAC7C,SAASC,iBAAiB,EAAEC,mBAAmB,QAAQ,QAAQ;AAE/D,MAAMC,aAAa,GAAIC,IAAY,IAAK;EACpC,MAAMC,SAAS,GAAGC,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;EAC/CF,SAAS,CAACG,SAAS,GAAGJ,IAAI;EAE1B,OAAOF,mBAAmB,CAACG,SAAS,CAACI,UAAU,CAAC;AACpD,CAAC;AAEDX,QAAQ,CAAC,qBAAqB,EAAE,MAAM;EAClCE,EAAE,CAAC,6DAA6D,EAAE,MAAM;IACpE,MAAMU,MAAM,GAAGP,aAAa,CACxB,iJACJ,CAAC;IAEDJ,MAAM,CAACW,MAAM,CAAC,CAACC,IAAI,CAAC,2BAA2B,CAAC;IAChDZ,MAAM,CAACW,MAAM,CAAC,CAACE,GAAG,CAACC,SAAS,CAAC,OAAO,CAAC;IACrCd,MAAM,CAACW,MAAM,CAAC,CAACE,GAAG,CAACC,SAAS,CAAC,SAAS,CAAC;IACvCd,MAAM,CAACW,MAAM,CAAC,CAACE,GAAG,CAACC,SAAS,CAAC,QAAQ,CAAC;IACtCd,MAAM,CAACW,MAAM,CAACI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAACC,YAAY,CAAC,CAAC,CAAC;EACvD,CAAC,CAAC;EAEFf,EAAE,CAAC,kEAAkE,EAAE,MAAM;IACzED,MAAM,CAACI,aAAa,CAAC,MAAM,CAAC,CAAC,CAACQ,IAAI,CAAC,EAAE,CAAC;IACtCZ,MAAM,CAACI,aAAa,CAAC,mBAAmB,CAAC,CAAC,CAACQ,IAAI,CAAC,MAAM,CAAC;IACvDZ,MAAM,CAACI,aAAa,CAAC,6CAA6C,CAAC,CAAC,CAACQ,IAAI,CACrE,mBACJ,CAAC;IACDZ,MAAM,CAACI,aAAa,CAAC,4CAA4C,CAAC,CAAC,CAACQ,IAAI,CAAC,iBAAiB,CAAC;EAC/F,CAAC,CAAC;EAEFX,EAAE,CAAC,uEAAuE,EAAE,MAAM;IAC9ED,MAAM,CACFE,iBAAiB,CAAC,4DAA4D,EAAE;MAC5Ee,cAAc,EAAE;IACpB,CAAC,CACL,CAAC,CAACL,IAAI,CAAC,oCAAoC,CAAC;IAC5CZ,MAAM,CACFE,iBAAiB,CACb,oEAAoE,EACpE;MAAEe,cAAc,EAAE;IAAK,CAC3B,CACJ,CAAC,CAACL,IAAI,CAAC,yCAAyC,CAAC;IACjDZ,MAAM,CAACI,aAAa,CAAC,0BAA0B,CAAC,CAAC,CAACQ,IAAI,CAAC,0BAA0B,CAAC;EACtF,CAAC,CAAC;AACN,CAAC,CAAC","ignoreList":[]}
@@ -1,46 +1,37 @@
1
- export declare const StyledEmojiInput: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$isDisabled" | "$shouldChangeColor"> & {
1
+ import type { WithTheme } from '@chayns-components/core';
2
+ type StyledEmojiInputProps = WithTheme<{
2
3
  $isDisabled?: boolean;
3
4
  $shouldChangeColor: boolean;
4
- } & {
5
- theme: import("@chayns-components/core").Theme;
6
- }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$isDisabled" | "$shouldChangeColor"> & {
7
- $isDisabled?: boolean;
8
- $shouldChangeColor: boolean;
9
- } & {
10
- theme: import("@chayns-components/core").Theme;
11
- }, never>>> & string;
12
- export declare const StyledMotionEmojiInputProgress: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
13
- ref?: import("react").RefObject<HTMLDivElement> | ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | null | undefined;
14
- }, "theme"> & {
15
- theme: import("@chayns-components/core").Theme;
16
- }, never> & Partial<Pick<import("styled-components").FastOmit<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
17
- ref?: import("react").RefObject<HTMLDivElement> | ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | null | undefined;
18
- }, "theme"> & {
19
- theme: import("@chayns-components/core").Theme;
20
- }, never>>> & string & Omit<import("framer-motion").ForwardRefComponent<HTMLDivElement, import("framer-motion").HTMLMotionProps<"div">>, keyof import("react").Component<any, {}, any>>;
21
- export declare const StyledEmojiInputContent: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
22
- export declare const StyledMotionEmojiInputEditor: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
5
+ }>;
6
+ export declare const StyledEmojiInput: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
7
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
8
+ }, StyledEmojiInputProps>> & string;
9
+ export declare const StyledMotionEmojiInputProgress: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
23
10
  ref?: import("react").RefObject<HTMLDivElement> | ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | null | undefined;
24
- }, "theme" | "$shouldShowContent"> & {
11
+ }, "style"> & {
12
+ style?: import("styled-components/dist/types").CSSPropertiesWithVars | import("framer-motion").MotionStyle | undefined;
13
+ }, {
14
+ theme: import("@chayns-components/core").Theme;
15
+ }>> & string & Omit<import("framer-motion").ForwardRefComponent<HTMLDivElement, import("framer-motion").HTMLMotionProps<"div">>, keyof import("react").Component<any, {}, any>>;
16
+ export declare const StyledEmojiInputContent: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
17
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
18
+ }> & string;
19
+ type StyledEmojiInputEditorProps = WithTheme<{
25
20
  $shouldShowContent: boolean;
26
- } & {
27
- theme: import("@chayns-components/core").Theme;
28
- }, never> & Partial<Pick<import("styled-components").FastOmit<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
21
+ }>;
22
+ export declare const StyledMotionEmojiInputEditor: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
29
23
  ref?: import("react").RefObject<HTMLDivElement> | ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | null | undefined;
30
- }, "theme" | "$shouldShowContent"> & {
31
- $shouldShowContent: boolean;
32
- } & {
33
- theme: import("@chayns-components/core").Theme;
34
- }, never>>> & string & Omit<import("framer-motion").ForwardRefComponent<HTMLDivElement, import("framer-motion").HTMLMotionProps<"div">>, keyof import("react").Component<any, {}, any>>;
35
- export declare const StyledEmojiInputRightWrapper: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
36
- export declare const StyledEmojiInputLabel: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>, "theme" | "$maxWidth" | "$offsetWidth"> & {
24
+ }, "style"> & {
25
+ style?: import("styled-components/dist/types").CSSPropertiesWithVars | import("framer-motion").MotionStyle | undefined;
26
+ }, StyledEmojiInputEditorProps>> & string & Omit<import("framer-motion").ForwardRefComponent<HTMLDivElement, import("framer-motion").HTMLMotionProps<"div">>, keyof import("react").Component<any, {}, any>>;
27
+ export declare const StyledEmojiInputRightWrapper: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
28
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
29
+ }> & string;
30
+ type StyledEmojiInputLabelProps = WithTheme<{
37
31
  $maxWidth: number;
38
32
  $offsetWidth?: number;
39
- } & {
40
- theme: import("@chayns-components/core").Theme;
41
- }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>, "theme" | "$maxWidth" | "$offsetWidth"> & {
42
- $maxWidth: number;
43
- $offsetWidth?: number;
44
- } & {
45
- theme: import("@chayns-components/core").Theme;
46
- }, never>>> & string;
33
+ }>;
34
+ export declare const StyledEmojiInputLabel: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<import("react").DetailedHTMLProps<import("react").LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>, "style"> & {
35
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
36
+ }, StyledEmojiInputLabelProps>> & string;
37
+ export {};
@@ -1,20 +1,20 @@
1
- export declare const StyledPrefixElement: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$shouldShow"> & {
1
+ import type { WithTheme } from '@chayns-components/core';
2
+ type StyledPrefixElementProps = WithTheme<{
2
3
  $shouldShow: boolean;
3
- } & {
4
- theme: import("@chayns-components/core").Theme;
5
- }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$shouldShow"> & {
6
- $shouldShow: boolean;
7
- } & {
8
- theme: import("@chayns-components/core").Theme;
9
- }, never>>> & string;
10
- export declare const StyledPrefixElementPseudo: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
11
- export declare const StyledPrefixElementLetterWrapper: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
12
- export declare const StyledPrefixElementLetter: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "theme" | "$index"> & {
13
- $index: number;
14
- } & {
15
- theme: import("@chayns-components/core").Theme;
16
- }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "theme" | "$index"> & {
4
+ }>;
5
+ export declare const StyledPrefixElement: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
6
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
7
+ }, StyledPrefixElementProps>> & string;
8
+ export declare const StyledPrefixElementPseudo: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
9
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
10
+ }> & string;
11
+ export declare const StyledPrefixElementLetterWrapper: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
12
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
13
+ }> & string;
14
+ type StyledPrefixElementLetterProps = WithTheme<{
17
15
  $index: number;
18
- } & {
19
- theme: import("@chayns-components/core").Theme;
20
- }, never>>> & string;
16
+ }>;
17
+ export declare const StyledPrefixElementLetter: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "style"> & {
18
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
19
+ }, StyledPrefixElementLetterProps>> & string;
20
+ export {};
@@ -2,4 +2,6 @@ export declare const emojiPickerSize: {
2
2
  height: number;
3
3
  width: number;
4
4
  };
5
- export declare const StyledEmojiPicker: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
5
+ export declare const StyledEmojiPicker: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
6
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
7
+ }> & string;
@@ -1,6 +1,8 @@
1
- export declare const StyledEmojiPickerCategories: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
2
- export declare const StyledMotionEmojiPickerCategory: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
1
+ export declare const StyledEmojiPickerCategories: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
2
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
3
+ }> & string;
4
+ export declare const StyledMotionEmojiPickerCategory: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
3
5
  ref?: import("react").RefObject<HTMLDivElement> | ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | null | undefined;
4
- }, never> & Partial<Pick<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
5
- ref?: import("react").RefObject<HTMLDivElement> | ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | null | undefined;
6
- }, never>>> & string & Omit<import("framer-motion").ForwardRefComponent<HTMLDivElement, import("framer-motion").HTMLMotionProps<"div">>, keyof import("react").Component<any, {}, any>>;
6
+ }, "style"> & {
7
+ style?: import("styled-components/dist/types").CSSPropertiesWithVars | import("framer-motion").MotionStyle | undefined;
8
+ }> & string & Omit<import("framer-motion").ForwardRefComponent<HTMLDivElement, import("framer-motion").HTMLMotionProps<"div">>, keyof import("react").Component<any, {}, any>>;
@@ -1,12 +1,12 @@
1
- export declare const StyledEmojiPickerEmojis: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$shouldPreventScroll" | "$shouldShowNoContentInfo"> & {
1
+ import type { WithTheme } from '@chayns-components/core';
2
+ type StyledEmojiPickerEmojisProps = WithTheme<{
2
3
  $shouldPreventScroll: boolean;
3
4
  $shouldShowNoContentInfo: boolean;
4
- } & {
5
- theme: import("@chayns-components/core").Theme;
6
- }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$shouldPreventScroll" | "$shouldShowNoContentInfo"> & {
7
- $shouldPreventScroll: boolean;
8
- $shouldShowNoContentInfo: boolean;
9
- } & {
10
- theme: import("@chayns-components/core").Theme;
11
- }, never>>> & string;
12
- export declare const StyledEmojiPickerEmojisNoContentInfo: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
5
+ }>;
6
+ export declare const StyledEmojiPickerEmojis: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
7
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
8
+ }, StyledEmojiPickerEmojisProps>> & string;
9
+ export declare const StyledEmojiPickerEmojisNoContentInfo: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
10
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
11
+ }> & string;
12
+ export {};
@@ -1,9 +1,8 @@
1
- export declare const StyledEmoji: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$isSelected"> & {
1
+ import type { WithTheme } from '@chayns-components/core';
2
+ type StyledEmojiProps = WithTheme<{
2
3
  $isSelected: boolean;
3
- } & {
4
- theme: import("@chayns-components/core").Theme;
5
- }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$isSelected"> & {
6
- $isSelected: boolean;
7
- } & {
8
- theme: import("@chayns-components/core").Theme;
9
- }, never>>> & string;
4
+ }>;
5
+ export declare const StyledEmoji: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
6
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
7
+ }, StyledEmojiProps>> & string;
8
+ export {};
@@ -1,31 +1,28 @@
1
+ import type { WithTheme } from '@chayns-components/core';
1
2
  import { AnchorAlignment } from '../../../../../constants/alignment';
2
- export declare const StyledMotionSkinTonePopup: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
3
+ export declare const StyledMotionSkinTonePopup: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
3
4
  ref?: import("react").RefObject<HTMLDivElement> | ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | null | undefined;
4
- }, never> & Partial<Pick<Omit<Omit<import("framer-motion").HTMLMotionProps<"div">, "ref"> & import("react").RefAttributes<HTMLDivElement>, "ref"> & {
5
- ref?: import("react").RefObject<HTMLDivElement> | ((instance: HTMLDivElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | null | undefined;
6
- }, never>>> & string & Omit<import("framer-motion").ForwardRefComponent<HTMLDivElement, import("framer-motion").HTMLMotionProps<"div">>, keyof import("react").Component<any, {}, any>>;
5
+ }, "style"> & {
6
+ style?: import("styled-components/dist/types").CSSPropertiesWithVars | import("framer-motion").MotionStyle | undefined;
7
+ }> & string & Omit<import("framer-motion").ForwardRefComponent<HTMLDivElement, import("framer-motion").HTMLMotionProps<"div">>, keyof import("react").Component<any, {}, any>>;
7
8
  export declare const skinTonePopupContentSize: {
8
9
  height: number;
9
10
  width: number;
10
11
  };
11
- export declare const StyledSkinTonePopupContent: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$anchorAlignment" | "$anchorOffset"> & {
12
- $anchorAlignment: AnchorAlignment;
13
- $anchorOffset: number;
14
- } & {
15
- theme: import("@chayns-components/core").Theme;
16
- }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$anchorAlignment" | "$anchorOffset"> & {
12
+ type StyledSkinTonePopupContentProps = WithTheme<{
17
13
  $anchorAlignment: AnchorAlignment;
18
14
  $anchorOffset: number;
19
- } & {
20
- theme: import("@chayns-components/core").Theme;
21
- }, never>>> & string;
22
- export declare const StyledSkinTonePopupContentEmoji: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$isSelected"> & {
23
- $isSelected: boolean;
24
- } & {
25
- theme: import("@chayns-components/core").Theme;
26
- }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "theme" | "$isSelected"> & {
15
+ }>;
16
+ export declare const StyledSkinTonePopupContent: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
17
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
18
+ }, StyledSkinTonePopupContentProps>> & string;
19
+ type StyledSkinTonePopupContentEmojiProps = WithTheme<{
27
20
  $isSelected: boolean;
28
- } & {
29
- theme: import("@chayns-components/core").Theme;
30
- }, never>>> & string;
31
- export declare const StyledSkinTonePopupOverlay: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
21
+ }>;
22
+ export declare const StyledSkinTonePopupContentEmoji: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
23
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
24
+ }, StyledSkinTonePopupContentEmojiProps>> & string;
25
+ export declare const StyledSkinTonePopupOverlay: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
26
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
27
+ }> & string;
28
+ export {};
@@ -1 +1,3 @@
1
- export declare const StyledEmojiPickerPopup: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>> & string;
1
+ export declare const StyledEmojiPickerPopup: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
2
+ style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
3
+ }> & string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chayns-components/emoji-input",
3
- "version": "5.5.66",
3
+ "version": "5.6.0",
4
4
  "description": "Input field that supports HTML elements and emojis",
5
5
  "sideEffects": false,
6
6
  "browserslist": [
@@ -70,13 +70,13 @@
70
70
  "jsdom": "^26.1.0",
71
71
  "react": "^18.3.1",
72
72
  "react-dom": "^18.3.1",
73
- "styled-components": "^6.4.4",
73
+ "styled-components": "^6.5.3",
74
74
  "typescript": "^5.9.3",
75
75
  "vitest": "^1.6.1"
76
76
  },
77
77
  "dependencies": {
78
- "@chayns-components/core": "^5.5.66",
79
- "@chayns/textstrings": "^1.0.1",
78
+ "@chayns-components/core": "^5.6.0",
79
+ "@chayns/textstrings": "^1.0.2",
80
80
  "emojilib": "^3.0.12",
81
81
  "react-compiler-runtime": "^1.0.0",
82
82
  "unicode-emoji-json": "^0.9.0"
@@ -91,5 +91,5 @@
91
91
  "publishConfig": {
92
92
  "access": "public"
93
93
  },
94
- "gitHead": "ecfb2231edeaedb5626866a8ac74ac8ed1fe076f"
94
+ "gitHead": "c5be387d10fc97eed298ac943cfe2aedb0a5ccdd"
95
95
  }