'use strict'; // src/core/parser.ts var mentionLinkRegexp = /@\[[^\]]+]\([0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\)/g; var parseMention = (mention) => { const regex = /@\[([^\]]+)\]\(([\w-]{36})\)/; const match = mention.match(regex); if (!match) { return null; } const mentionText = match[1]; const mentionId = match[2]; if (!mentionText || !mentionId) { return null; } return { mention: `@${mentionText}`, id: mentionId }; }; var findMentions = (text) => { let match; const matches = []; while ((match = mentionLinkRegexp.exec(text)) !== null) { const parsed = parseMention(match[0]); const baseMention = { start: match.index, end: mentionLinkRegexp.lastIndex, text: match[0], type: "mention", displayText: parsed?.mention ?? match[0] }; matches.push(parsed?.id ? { ...baseMention, userId: parsed.id } : baseMention); } return matches; }; var findTags = (content) => { const regex = /#[^\s]{1,201}/g; const results = []; let match; while ((match = regex.exec(content)) !== null) { const value = match[0]; results.push({ start: match.index, end: match.index + value.length, text: value, type: "tag", tag: value.replace("#", "") }); } return results; }; var findLinks = (content) => { const regex = /\b((https?:\/\/)?(?:[\w-]+\.)+[a-z]{2,}(\/[\w\-._~:/?#[\]@!$&'()*+,;=]*)?)/gi; const results = []; let match; while ((match = regex.exec(content)) !== null) { const rawUrl = match[0]; const hasProtocol = /^https?:\/\//i.test(rawUrl); const fullUrl = hasProtocol ? rawUrl : `https://${rawUrl}`; results.push({ start: match.index, end: match.index + rawUrl.length, text: rawUrl, url: fullUrl, type: "link" }); } return results; }; var findAllEntities = (content) => { const mentions = findMentions(content); const tags = findTags(content); const links = findLinks(content); return [...mentions, ...tags, ...links].sort((a, b) => a.start - b.start); }; // src/angular/index.ts var LINK_COLOR = "#1677ff"; var READ_MORE_TEXT = "\u0427\u0438\u0442\u0430\u0442\u044C \u043F\u043E\u043B\u043D\u043E\u0441\u0442\u044C\u044E"; var toKebabCase = (value) => value.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`); var applyStyleObject = (element, styles) => { if (!styles) { return; } for (const [key, rawValue] of Object.entries(styles)) { if (rawValue === null || rawValue === void 0) { continue; } const styleValue = typeof rawValue === "number" ? `${rawValue}px` : String(rawValue); if (key.startsWith("--")) { element.style.setProperty(key, styleValue); continue; } const cssKey = key.includes("-") ? key : toKebabCase(key); element.style.setProperty(cssKey, styleValue); } }; var toNode = (value) => { if (value === null || value === void 0) { return null; } if (value instanceof Node) { return value; } return document.createTextNode(String(value)); }; var resolveEllipsisSymbol = (symbol, expanded) => { if (typeof symbol === "function") { return symbol(expanded); } return symbol ?? READ_MORE_TEXT; }; var buildAngularTagHref = (entity) => { return `/search/?query=${encodeURIComponent(entity.tag.toLowerCase())}`; }; var createAngularContentTokens = (inputText) => { const text = inputText ?? ""; const entities = findAllEntities(text); let cursor = 0; const tokens = []; for (const entity of entities) { if (entity.start > cursor) { tokens.push({ kind: "text", text: text.slice(cursor, entity.start), start: cursor, end: entity.start }); } if (entity.type === "mention") { tokens.push({ kind: "mention", entity }); } else if (entity.type === "tag") { tokens.push({ kind: "tag", entity }); } else { tokens.push({ kind: "link", entity }); } cursor = entity.end; } if (cursor < text.length) { tokens.push({ kind: "text", text: text.slice(cursor), start: cursor, end: text.length }); } return tokens; }; var AngularContentSuggestionsAdapter = class { snapshot(inputText) { const text = inputText ?? ""; const entities = findAllEntities(text); const tokens = createAngularContentTokens(text); return { text, entities, tokens }; } }; var AngularContentTextRenderer = class { host = null; props = {}; expanded = false; viewed = false; hostInsideView = false; observer = null; attach(host, props = {}) { this.destroy(); this.host = host; this.props = { ...props }; this.expanded = false; this.viewed = false; this.hostInsideView = false; this.initObserver(); this.render(); return this.getState(); } update(nextProps) { this.props = { ...this.props, ...nextProps }; this.render(); return this.getState(); } destroy() { if (this.observer && this.host) { this.observer.unobserve(this.host); this.observer.disconnect(); } this.observer = null; if (this.host) { this.host.innerHTML = ""; } this.host = null; this.props = {}; this.expanded = false; this.viewed = false; this.hostInsideView = false; } getState() { return { props: { ...this.props }, snapshot: this.createSnapshot(), expanded: this.getMergedExpanded(this.resolveEllipsisConfig(), this.getText()) }; } getText() { return this.props.text ?? ""; } createSnapshot() { const text = this.getText(); const entities = findAllEntities(text); const tokens = createAngularContentTokens(text); return { text, entities, tokens }; } resolveEllipsisConfig() { const ellipsis = this.props.ellipsis; if (!ellipsis || typeof ellipsis !== "object") { return null; } return ellipsis; } getMergedExpanded(ellipsisConfig, text) { const controlledExpanded = ellipsisConfig && typeof ellipsisConfig.expanded === "boolean" ? ellipsisConfig.expanded : void 0; if (controlledExpanded !== void 0) { return controlledExpanded; } if (ellipsisConfig && "count" in ellipsisConfig) { const count = ellipsisConfig.count ?? 0; if (count <= 0 || text.length <= count) { return true; } } return this.expanded; } createDefaultMentionNode(entity) { const span = document.createElement("span"); span.style.color = LINK_COLOR; span.style.fontWeight = this.props.weight === "bold" ? "700" : "400"; span.textContent = entity.displayText; return span; } createDefaultTagNode(entity) { const span = document.createElement("span"); span.style.color = LINK_COLOR; span.style.fontWeight = this.props.weight === "bold" ? "700" : "400"; span.textContent = entity.text; return span; } createDefaultLinkNode(entity) { const anchor = document.createElement("a"); anchor.href = entity.url; anchor.target = "_blank"; anchor.referrerPolicy = "no-referrer"; anchor.style.color = LINK_COLOR; anchor.style.fontWeight = this.props.weight === "bold" ? "700" : "400"; anchor.textContent = entity.text; return anchor; } renderEntity(entity, index) { if (entity.type === "mention") { const customNode2 = this.props.renderMention?.(entity, index); return toNode(customNode2) ?? this.createDefaultMentionNode(entity); } if (entity.type === "tag") { const customNode2 = this.props.renderTag?.(entity, index); return toNode(customNode2) ?? this.createDefaultTagNode(entity); } const customNode = this.props.renderLink?.(entity, index); return toNode(customNode) ?? this.createDefaultLinkNode(entity); } buildTextNodes(text, entities, upto = null) { let lastIndex = 0; const nodes = []; for (const [index, entity] of entities.entries()) { if (upto !== null && entity.start >= upto) { break; } const textEnd = upto !== null ? Math.min(entity.start, upto) : entity.start; if (entity.start > lastIndex && lastIndex < textEnd) { nodes.push(document.createTextNode(text.slice(lastIndex, textEnd))); } if (upto === null || entity.end <= upto) { const entityNode = this.renderEntity(entity, index); if (entityNode) { nodes.push(entityNode); } } lastIndex = entity.end; } if (upto === null) { if (lastIndex < text.length) { nodes.push(document.createTextNode(text.slice(lastIndex))); } } else if (lastIndex < upto) { nodes.push(document.createTextNode(text.slice(lastIndex, upto))); } return nodes; } applyBaseParagraphStyle(element) { element.style.whiteSpace = "pre-wrap"; element.style.fontWeight = this.props.weight === "bold" ? "700" : "400"; element.style.setProperty("-webkit-touch-callout", "default"); element.style.setProperty("-webkit-user-select", "text"); element.style.setProperty("-khtml-user-select", "text"); element.style.setProperty("-moz-user-select", "text"); element.style.setProperty("-ms-user-select", "text"); element.style.setProperty("user-select", "text"); if (this.props.blur) { element.style.filter = "blur(3px)"; element.style.setProperty("-webkit-user-select", "none"); element.style.setProperty("-khtml-user-select", "none"); element.style.setProperty("-moz-user-select", "none"); element.style.setProperty("-ms-user-select", "none"); element.style.setProperty("user-select", "none"); element.style.pointerEvents = "none"; } applyStyleObject(element, this.props.style); } buildReadMoreButton(symbol) { const button = document.createElement("button"); button.type = "button"; button.textContent = resolveEllipsisSymbol(symbol, this.expanded); button.style.border = "0"; button.style.background = "none"; button.style.padding = "0"; button.style.marginLeft = "6px"; button.style.cursor = "pointer"; button.style.color = LINK_COLOR; button.style.fontWeight = "700"; button.onclick = (event) => { event.preventDefault(); event.stopPropagation(); this.handleExpand(); }; return button; } handleExpand() { const ellipsisConfig = this.resolveEllipsisConfig(); if (!ellipsisConfig) { return; } this.expanded = true; ellipsisConfig.onExpand?.(true); this.render(); } computeEntitySafeCutoff(count, entities) { let cutoff = count; let extended = true; while (extended) { extended = false; for (const entity of entities) { if (entity.start < cutoff && entity.end > cutoff) { cutoff = entity.end; extended = true; } } } return cutoff; } hasVerticalOverflow(element) { return element.scrollHeight - element.clientHeight > 1; } render() { if (!this.host) { return; } const text = this.getText(); const entities = findAllEntities(text); const ellipsisConfig = this.resolveEllipsisConfig(); const mergedExpanded = this.getMergedExpanded(ellipsisConfig, text); const wrapper = document.createElement("div"); const paragraph = document.createElement("div"); if (this.props.className) { paragraph.className = this.props.className; } this.applyBaseParagraphStyle(paragraph); if (ellipsisConfig && "count" in ellipsisConfig) { const count = ellipsisConfig.count ?? 0; const shouldTruncate = !mergedExpanded && count > 0 && text.length > count; if (shouldTruncate) { const cutoff = this.computeEntitySafeCutoff(count, entities); const nodes = this.buildTextNodes(text, entities, cutoff); paragraph.append(...nodes); paragraph.append(document.createTextNode("\u2026")); if (ellipsisConfig.expandable) { paragraph.append(this.buildReadMoreButton(ellipsisConfig.symbol)); } } else { paragraph.append(...this.buildTextNodes(text, entities)); } } else { paragraph.append(...this.buildTextNodes(text, entities)); if (ellipsisConfig && "rows" in ellipsisConfig && !mergedExpanded) { paragraph.style.display = "-webkit-box"; paragraph.style.setProperty("-webkit-box-orient", "vertical"); paragraph.style.setProperty("-webkit-line-clamp", String(ellipsisConfig.rows)); paragraph.style.overflow = "hidden"; wrapper.append(paragraph); this.host.replaceChildren(wrapper); if (ellipsisConfig.expandable && this.hasVerticalOverflow(paragraph)) { wrapper.append(this.buildReadMoreButton(ellipsisConfig.symbol)); } this.emitOnViewIfNeeded(mergedExpanded); return; } } wrapper.append(paragraph); this.host.replaceChildren(wrapper); this.emitOnViewIfNeeded(mergedExpanded); } initObserver() { if (!this.host) { return; } if (typeof IntersectionObserver === "undefined") { this.hostInsideView = true; return; } this.observer = new IntersectionObserver( (entries) => { const entry = entries[0]; if (!entry) { return; } if (entry.isIntersecting && !this.hostInsideView) { this.hostInsideView = true; const ellipsisConfig = this.resolveEllipsisConfig(); const mergedExpanded = this.getMergedExpanded(ellipsisConfig, this.getText()); this.emitOnViewIfNeeded(mergedExpanded); } }, { threshold: 0.5 } ); this.observer.observe(this.host); } emitOnViewIfNeeded(mergedExpanded) { if (!mergedExpanded || this.viewed || !this.hostInsideView) { return; } this.viewed = true; this.props.onView?.(); } }; var AngularContentTextWithSuggestionsRenderer = class extends AngularContentTextRenderer { }; var AngularContentTitleWithSuggestionsRenderer = class { renderer = new AngularContentTextWithSuggestionsRenderer(); attach(host, props = {}) { return this.renderer.attach(host, this.normalizeProps(props)); } update(props) { return this.renderer.update(this.normalizeProps(props)); } destroy() { this.renderer.destroy(); } getState() { return this.renderer.getState(); } normalizeProps(props) { return { ...props, weight: "bold", blur: props.blur ?? false, ellipsis: props.ellipsis === void 0 ? { rows: 2 } : props.ellipsis }; } }; exports.AngularContentSuggestionsAdapter = AngularContentSuggestionsAdapter; exports.AngularContentTextRenderer = AngularContentTextRenderer; exports.AngularContentTextWithSuggestionsRenderer = AngularContentTextWithSuggestionsRenderer; exports.AngularContentTitleWithSuggestionsRenderer = AngularContentTitleWithSuggestionsRenderer; exports.buildAngularTagHref = buildAngularTagHref; exports.createAngularContentTokens = createAngularContentTokens; exports.toKebabCase = toKebabCase; //# sourceMappingURL=index.cjs.map //# sourceMappingURL=index.cjs.map