@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.
- package/lib/cjs/utils/text.js +6 -0
- package/lib/cjs/utils/text.js.map +1 -1
- package/lib/cjs/utils/text.test.js +1 -0
- package/lib/cjs/utils/text.test.js.map +1 -1
- package/lib/esm/utils/text.js +6 -0
- package/lib/esm/utils/text.js.map +1 -1
- package/lib/esm/utils/text.test.js +1 -0
- package/lib/esm/utils/text.test.js.map +1 -1
- package/lib/types/components/emoji-input/EmojiInput.styles.d.ts +30 -39
- package/lib/types/components/emoji-input/prefix-element/PrefixElement.styles.d.ts +18 -18
- package/lib/types/components/emoji-picker/EmojiPicker.styles.d.ts +3 -1
- package/lib/types/components/emoji-picker/emoji-picker-categories/EmojiPickerCategories.styles.d.ts +7 -5
- package/lib/types/components/emoji-picker/emoji-picker-emojis/EmojiPickerEmojis.styles.d.ts +10 -10
- package/lib/types/components/emoji-picker/emoji-picker-emojis/emoji/Emoji.styles.d.ts +7 -8
- package/lib/types/components/emoji-picker/emoji-picker-emojis/emoji/skin-tone-popup/SkinTonePopup.styles.d.ts +19 -22
- package/lib/types/components/emoji-picker-popup/EmojiPickerPopup.styles.d.ts +3 -1
- package/package.json +5 -5
package/lib/cjs/utils/text.js
CHANGED
|
@@ -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(/ /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(/ /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":[]}
|
package/lib/esm/utils/text.js
CHANGED
|
@@ -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(/ /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(/ /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
|
-
|
|
1
|
+
import type { WithTheme } from '@chayns-components/core';
|
|
2
|
+
type StyledEmojiInputProps = WithTheme<{
|
|
2
3
|
$isDisabled?: boolean;
|
|
3
4
|
$shouldChangeColor: boolean;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
}, "
|
|
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
|
-
|
|
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
|
-
}, "
|
|
31
|
-
|
|
32
|
-
} & {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
1
|
+
import type { WithTheme } from '@chayns-components/core';
|
|
2
|
+
type StyledPrefixElementProps = WithTheme<{
|
|
2
3
|
$shouldShow: boolean;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
export declare const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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",
|
|
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;
|
package/lib/types/components/emoji-picker/emoji-picker-categories/EmojiPickerCategories.styles.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
export declare const StyledEmojiPickerCategories: import("styled-components/dist/types").IStyledComponentBase<"web",
|
|
2
|
-
|
|
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
|
-
},
|
|
5
|
-
|
|
6
|
-
}
|
|
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
|
-
|
|
1
|
+
import type { WithTheme } from '@chayns-components/core';
|
|
2
|
+
type StyledEmojiPickerEmojisProps = WithTheme<{
|
|
2
3
|
$shouldPreventScroll: boolean;
|
|
3
4
|
$shouldShowNoContentInfo: boolean;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
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
|
-
|
|
1
|
+
import type { WithTheme } from '@chayns-components/core';
|
|
2
|
+
type StyledEmojiProps = WithTheme<{
|
|
2
3
|
$isSelected: boolean;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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",
|
|
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
|
-
},
|
|
5
|
-
|
|
6
|
-
}
|
|
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
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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",
|
|
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.
|
|
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.
|
|
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.
|
|
79
|
-
"@chayns/textstrings": "^1.0.
|
|
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": "
|
|
94
|
+
"gitHead": "c5be387d10fc97eed298ac943cfe2aedb0a5ccdd"
|
|
95
95
|
}
|