chore: Монорепо с общими пакетами
This commit is contained in:
141
packages/content-suggestions/dist/angular/index.cjs
vendored
Normal file
141
packages/content-suggestions/dist/angular/index.cjs
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
'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 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
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
exports.AngularContentSuggestionsAdapter = AngularContentSuggestionsAdapter;
|
||||
exports.buildAngularTagHref = buildAngularTagHref;
|
||||
exports.createAngularContentTokens = createAngularContentTokens;
|
||||
//# sourceMappingURL=index.cjs.map
|
||||
//# sourceMappingURL=index.cjs.map
|
||||
1
packages/content-suggestions/dist/angular/index.cjs.map
vendored
Normal file
1
packages/content-suggestions/dist/angular/index.cjs.map
vendored
Normal file
File diff suppressed because one or more lines are too long
33
packages/content-suggestions/dist/angular/index.d.cts
vendored
Normal file
33
packages/content-suggestions/dist/angular/index.d.cts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { C as ContentEntity, M as MentionEntity, T as TagEntity, L as LinkEntity } from '../types-BRt4hd7A.cjs';
|
||||
|
||||
interface AngularTextToken {
|
||||
kind: "text";
|
||||
text: string;
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
interface AngularMentionToken {
|
||||
kind: "mention";
|
||||
entity: MentionEntity;
|
||||
}
|
||||
interface AngularTagToken {
|
||||
kind: "tag";
|
||||
entity: TagEntity;
|
||||
}
|
||||
interface AngularLinkToken {
|
||||
kind: "link";
|
||||
entity: LinkEntity;
|
||||
}
|
||||
type AngularContentToken = AngularTextToken | AngularMentionToken | AngularTagToken | AngularLinkToken;
|
||||
interface AngularContentSnapshot {
|
||||
text: string;
|
||||
entities: ContentEntity[];
|
||||
tokens: AngularContentToken[];
|
||||
}
|
||||
declare const buildAngularTagHref: (entity: TagEntity) => string;
|
||||
declare const createAngularContentTokens: (inputText: string | null | undefined) => AngularContentToken[];
|
||||
declare class AngularContentSuggestionsAdapter {
|
||||
snapshot(inputText: string | null | undefined): AngularContentSnapshot;
|
||||
}
|
||||
|
||||
export { type AngularContentSnapshot, AngularContentSuggestionsAdapter, type AngularContentToken, type AngularLinkToken, type AngularMentionToken, type AngularTagToken, type AngularTextToken, buildAngularTagHref, createAngularContentTokens };
|
||||
33
packages/content-suggestions/dist/angular/index.d.ts
vendored
Normal file
33
packages/content-suggestions/dist/angular/index.d.ts
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
import { C as ContentEntity, M as MentionEntity, T as TagEntity, L as LinkEntity } from '../types-BRt4hd7A.js';
|
||||
|
||||
interface AngularTextToken {
|
||||
kind: "text";
|
||||
text: string;
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
interface AngularMentionToken {
|
||||
kind: "mention";
|
||||
entity: MentionEntity;
|
||||
}
|
||||
interface AngularTagToken {
|
||||
kind: "tag";
|
||||
entity: TagEntity;
|
||||
}
|
||||
interface AngularLinkToken {
|
||||
kind: "link";
|
||||
entity: LinkEntity;
|
||||
}
|
||||
type AngularContentToken = AngularTextToken | AngularMentionToken | AngularTagToken | AngularLinkToken;
|
||||
interface AngularContentSnapshot {
|
||||
text: string;
|
||||
entities: ContentEntity[];
|
||||
tokens: AngularContentToken[];
|
||||
}
|
||||
declare const buildAngularTagHref: (entity: TagEntity) => string;
|
||||
declare const createAngularContentTokens: (inputText: string | null | undefined) => AngularContentToken[];
|
||||
declare class AngularContentSuggestionsAdapter {
|
||||
snapshot(inputText: string | null | undefined): AngularContentSnapshot;
|
||||
}
|
||||
|
||||
export { type AngularContentSnapshot, AngularContentSuggestionsAdapter, type AngularContentToken, type AngularLinkToken, type AngularMentionToken, type AngularTagToken, type AngularTextToken, buildAngularTagHref, createAngularContentTokens };
|
||||
137
packages/content-suggestions/dist/angular/index.js
vendored
Normal file
137
packages/content-suggestions/dist/angular/index.js
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// 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 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
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export { AngularContentSuggestionsAdapter, buildAngularTagHref, createAngularContentTokens };
|
||||
//# sourceMappingURL=index.js.map
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
packages/content-suggestions/dist/angular/index.js.map
vendored
Normal file
1
packages/content-suggestions/dist/angular/index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
97
packages/content-suggestions/dist/core/index.cjs
vendored
Normal file
97
packages/content-suggestions/dist/core/index.cjs
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
'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);
|
||||
};
|
||||
var processContent = (content) => {
|
||||
const processedText = content.replace(mentionLinkRegexp, (match) => {
|
||||
const parsed = parseMention(match);
|
||||
return parsed ? parsed.mention : match;
|
||||
});
|
||||
const tags = findTags(content).map((tag) => tag.tag);
|
||||
return {
|
||||
processedText,
|
||||
tags
|
||||
};
|
||||
};
|
||||
|
||||
exports.findAllEntities = findAllEntities;
|
||||
exports.findLinks = findLinks;
|
||||
exports.findMentions = findMentions;
|
||||
exports.findTags = findTags;
|
||||
exports.mentionLinkRegexp = mentionLinkRegexp;
|
||||
exports.parseMention = parseMention;
|
||||
exports.processContent = processContent;
|
||||
//# sourceMappingURL=index.cjs.map
|
||||
//# sourceMappingURL=index.cjs.map
|
||||
1
packages/content-suggestions/dist/core/index.cjs.map
vendored
Normal file
1
packages/content-suggestions/dist/core/index.cjs.map
vendored
Normal file
File diff suppressed because one or more lines are too long
12
packages/content-suggestions/dist/core/index.d.cts
vendored
Normal file
12
packages/content-suggestions/dist/core/index.d.cts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { C as ContentEntity, L as LinkEntity, M as MentionEntity, T as TagEntity, P as ParsedMention, a as ProcessedContent } from '../types-BRt4hd7A.cjs';
|
||||
export { B as BaseEntity } from '../types-BRt4hd7A.cjs';
|
||||
|
||||
declare const mentionLinkRegexp: RegExp;
|
||||
declare const parseMention: (mention: string) => ParsedMention | null;
|
||||
declare const findMentions: (text: string) => MentionEntity[];
|
||||
declare const findTags: (content: string) => TagEntity[];
|
||||
declare const findLinks: (content: string) => LinkEntity[];
|
||||
declare const findAllEntities: (content: string) => ContentEntity[];
|
||||
declare const processContent: (content: string) => ProcessedContent;
|
||||
|
||||
export { ContentEntity, LinkEntity, MentionEntity, ParsedMention, ProcessedContent, TagEntity, findAllEntities, findLinks, findMentions, findTags, mentionLinkRegexp, parseMention, processContent };
|
||||
12
packages/content-suggestions/dist/core/index.d.ts
vendored
Normal file
12
packages/content-suggestions/dist/core/index.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import { C as ContentEntity, L as LinkEntity, M as MentionEntity, T as TagEntity, P as ParsedMention, a as ProcessedContent } from '../types-BRt4hd7A.js';
|
||||
export { B as BaseEntity } from '../types-BRt4hd7A.js';
|
||||
|
||||
declare const mentionLinkRegexp: RegExp;
|
||||
declare const parseMention: (mention: string) => ParsedMention | null;
|
||||
declare const findMentions: (text: string) => MentionEntity[];
|
||||
declare const findTags: (content: string) => TagEntity[];
|
||||
declare const findLinks: (content: string) => LinkEntity[];
|
||||
declare const findAllEntities: (content: string) => ContentEntity[];
|
||||
declare const processContent: (content: string) => ProcessedContent;
|
||||
|
||||
export { ContentEntity, LinkEntity, MentionEntity, ParsedMention, ProcessedContent, TagEntity, findAllEntities, findLinks, findMentions, findTags, mentionLinkRegexp, parseMention, processContent };
|
||||
89
packages/content-suggestions/dist/core/index.js
vendored
Normal file
89
packages/content-suggestions/dist/core/index.js
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// 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);
|
||||
};
|
||||
var processContent = (content) => {
|
||||
const processedText = content.replace(mentionLinkRegexp, (match) => {
|
||||
const parsed = parseMention(match);
|
||||
return parsed ? parsed.mention : match;
|
||||
});
|
||||
const tags = findTags(content).map((tag) => tag.tag);
|
||||
return {
|
||||
processedText,
|
||||
tags
|
||||
};
|
||||
};
|
||||
|
||||
export { findAllEntities, findLinks, findMentions, findTags, mentionLinkRegexp, parseMention, processContent };
|
||||
//# sourceMappingURL=index.js.map
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
packages/content-suggestions/dist/core/index.js.map
vendored
Normal file
1
packages/content-suggestions/dist/core/index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
396
packages/content-suggestions/dist/react/index.cjs
vendored
Normal file
396
packages/content-suggestions/dist/react/index.cjs
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var react = require('@hublib-web/tach-typography/react');
|
||||
var jsxRuntime = require('react/jsx-runtime');
|
||||
|
||||
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
||||
|
||||
var React__default = /*#__PURE__*/_interopDefault(React);
|
||||
|
||||
// src/react/components/content-text.tsx
|
||||
|
||||
// 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);
|
||||
};
|
||||
var processContent = (content) => {
|
||||
const processedText = content.replace(mentionLinkRegexp, (match) => {
|
||||
const parsed = parseMention(match);
|
||||
return parsed ? parsed.mention : match;
|
||||
});
|
||||
const tags = findTags(content).map((tag) => tag.tag);
|
||||
return {
|
||||
processedText,
|
||||
tags
|
||||
};
|
||||
};
|
||||
var joinClassName = (...values) => values.filter(Boolean).join(" ");
|
||||
var baseSelectableStyle = {
|
||||
whiteSpace: "pre-wrap",
|
||||
WebkitTouchCallout: "default",
|
||||
WebkitUserSelect: "text",
|
||||
KhtmlUserSelect: "text",
|
||||
MozUserSelect: "text",
|
||||
msUserSelect: "text",
|
||||
userSelect: "text"
|
||||
};
|
||||
var blurStyle = {
|
||||
filter: "blur(3px)",
|
||||
WebkitUserSelect: "none",
|
||||
KhtmlUserSelect: "none",
|
||||
MozUserSelect: "none",
|
||||
msUserSelect: "none",
|
||||
userSelect: "none",
|
||||
pointerEvents: "none"
|
||||
};
|
||||
var ReadMoreButton = ({ onClick, symbol = "\u0427\u0438\u0442\u0430\u0442\u044C \u043F\u043E\u043B\u043D\u043E\u0441\u0442\u044C\u044E", expanded = false, TitleComponent }) => /* @__PURE__ */ jsxRuntime.jsx(
|
||||
TitleComponent,
|
||||
{
|
||||
onClick: (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
onClick(event);
|
||||
},
|
||||
weight: "bold",
|
||||
level: 5,
|
||||
children: typeof symbol === "function" ? symbol(expanded) : symbol
|
||||
}
|
||||
);
|
||||
var ContentText = React__default.default.memo(
|
||||
({
|
||||
text,
|
||||
className,
|
||||
ellipsis = false,
|
||||
blur = false,
|
||||
weight = "normal",
|
||||
style,
|
||||
onView,
|
||||
renderMention,
|
||||
renderTag,
|
||||
renderLink,
|
||||
ParagraphComponent = react.TachTypography.Paragraph.Body,
|
||||
TextComponent = react.TachTypography.Text.Body,
|
||||
TitleComponent = react.TachTypography.Title.Body,
|
||||
...props
|
||||
}) => {
|
||||
const containerRef = React.useRef(null);
|
||||
const [expanded, setExpanded] = React.useState(false);
|
||||
const [containerInsideView, setContainerInsideView] = React.useState(false);
|
||||
const [viewed, setViewed] = React.useState(false);
|
||||
const content = text || "";
|
||||
const entities = React.useMemo(() => findAllEntities(content), [content]);
|
||||
const wrapWithKey = (node, key) => {
|
||||
if (React__default.default.isValidElement(node)) {
|
||||
return React__default.default.cloneElement(node, { key });
|
||||
}
|
||||
return /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: node }, key);
|
||||
};
|
||||
const buildMentionNode = (entity, index) => {
|
||||
const defaultNode = /* @__PURE__ */ jsxRuntime.jsx(TextComponent, { color: "link", weight, children: entity.displayText });
|
||||
const customNode = renderMention?.(entity, index) ?? defaultNode;
|
||||
return wrapWithKey(customNode, `mention-${entity.start}-${index}`);
|
||||
};
|
||||
const buildTagNode = (entity, index) => {
|
||||
const defaultNode = /* @__PURE__ */ jsxRuntime.jsx(TextComponent, { color: "link", weight, children: entity.text });
|
||||
const customNode = renderTag?.(entity, index) ?? defaultNode;
|
||||
return wrapWithKey(customNode, `tag-${entity.start}-${index}`);
|
||||
};
|
||||
const buildLinkNode = (entity, index) => {
|
||||
const defaultNode = /* @__PURE__ */ jsxRuntime.jsx(
|
||||
react.TachTypography.Link.Body,
|
||||
{
|
||||
target: "_blank",
|
||||
referrerPolicy: "no-referrer",
|
||||
color: "link",
|
||||
weight,
|
||||
href: entity.url,
|
||||
children: entity.text
|
||||
}
|
||||
);
|
||||
const customNode = renderLink?.(entity, index) ?? defaultNode;
|
||||
return wrapWithKey(customNode, `link-${entity.start}-${index}`);
|
||||
};
|
||||
const buildParts = (upto = null) => {
|
||||
let lastIndex = 0;
|
||||
const nodes = [];
|
||||
for (const [i, 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(content.slice(lastIndex, textEnd));
|
||||
}
|
||||
if (upto === null || entity.end <= upto) {
|
||||
if (entity.type === "mention") {
|
||||
nodes.push(buildMentionNode(entity, i));
|
||||
} else if (entity.type === "tag") {
|
||||
nodes.push(buildTagNode(entity, i));
|
||||
} else if (entity.type === "link") {
|
||||
nodes.push(buildLinkNode(entity, i));
|
||||
}
|
||||
}
|
||||
lastIndex = entity.end;
|
||||
}
|
||||
if (upto === null) {
|
||||
if (lastIndex < content.length) {
|
||||
nodes.push(content.slice(lastIndex));
|
||||
}
|
||||
} else if (lastIndex < upto) {
|
||||
nodes.push(content.slice(lastIndex, upto));
|
||||
}
|
||||
return nodes;
|
||||
};
|
||||
const ellipsisConfig = ellipsis && typeof ellipsis === "object" ? ellipsis : null;
|
||||
const expandedFromProps = ellipsisConfig && typeof ellipsisConfig.expanded === "boolean" ? ellipsisConfig.expanded : void 0;
|
||||
const isExpandedControlled = expandedFromProps !== void 0;
|
||||
const mergedExpanded = isExpandedControlled ? expandedFromProps : expanded;
|
||||
const handleExpand = React.useCallback(
|
||||
(event) => {
|
||||
if (!isExpandedControlled) {
|
||||
setExpanded(true);
|
||||
}
|
||||
ellipsisConfig?.onExpand?.(event, { expanded: true });
|
||||
},
|
||||
[ellipsisConfig, isExpandedControlled]
|
||||
);
|
||||
React.useEffect(() => {
|
||||
if (isExpandedControlled) {
|
||||
return;
|
||||
}
|
||||
if (ellipsisConfig && "count" in ellipsisConfig) {
|
||||
const count = ellipsisConfig.count ?? 0;
|
||||
if (content.length <= count && !expanded) {
|
||||
setExpanded(true);
|
||||
}
|
||||
}
|
||||
}, [content.length, ellipsisConfig, expanded, isExpandedControlled]);
|
||||
React.useEffect(() => {
|
||||
if (mergedExpanded && !viewed && containerInsideView) {
|
||||
setViewed(true);
|
||||
onView?.();
|
||||
}
|
||||
}, [mergedExpanded, viewed, containerInsideView, onView]);
|
||||
React.useEffect(() => {
|
||||
const ref = containerRef.current;
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
const entry = entries[0];
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
if (entry.isIntersecting && !containerInsideView) {
|
||||
setContainerInsideView(true);
|
||||
}
|
||||
}, { threshold: 0.5 });
|
||||
observer.observe(ref);
|
||||
return () => {
|
||||
observer.unobserve(ref);
|
||||
};
|
||||
}, [containerInsideView]);
|
||||
const mergedStyle = {
|
||||
...baseSelectableStyle,
|
||||
...blur ? blurStyle : void 0,
|
||||
...style
|
||||
};
|
||||
if (ellipsisConfig && "count" in ellipsisConfig) {
|
||||
const { count, expandable } = ellipsisConfig;
|
||||
if (!mergedExpanded && count && content.length > count) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
const truncatedNodes = buildParts(cutoff);
|
||||
return /* @__PURE__ */ jsxRuntime.jsxs(
|
||||
ParagraphComponent,
|
||||
{
|
||||
ref: containerRef,
|
||||
weight,
|
||||
className: joinClassName(className),
|
||||
style: mergedStyle,
|
||||
...props,
|
||||
children: [
|
||||
truncatedNodes,
|
||||
"\u2026",
|
||||
expandable && /* @__PURE__ */ jsxRuntime.jsx(
|
||||
ReadMoreButton,
|
||||
{
|
||||
symbol: ellipsisConfig.symbol,
|
||||
onClick: handleExpand,
|
||||
expanded: mergedExpanded,
|
||||
TitleComponent
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
if (ellipsisConfig && "rows" in ellipsisConfig) {
|
||||
const paragraphEllipsis = mergedExpanded ? false : {
|
||||
...ellipsisConfig,
|
||||
symbol: ellipsisConfig.expandable ? /* @__PURE__ */ jsxRuntime.jsx(
|
||||
ReadMoreButton,
|
||||
{
|
||||
symbol: ellipsisConfig.symbol,
|
||||
onClick: handleExpand,
|
||||
expanded: mergedExpanded,
|
||||
TitleComponent
|
||||
}
|
||||
) : ellipsisConfig.symbol
|
||||
};
|
||||
return /* @__PURE__ */ jsxRuntime.jsx(
|
||||
ParagraphComponent,
|
||||
{
|
||||
ref: containerRef,
|
||||
weight,
|
||||
className: joinClassName(className),
|
||||
style: mergedStyle,
|
||||
ellipsis: paragraphEllipsis,
|
||||
...props,
|
||||
children: buildParts()
|
||||
}
|
||||
);
|
||||
}
|
||||
return /* @__PURE__ */ jsxRuntime.jsx(
|
||||
ParagraphComponent,
|
||||
{
|
||||
ref: containerRef,
|
||||
weight,
|
||||
className: joinClassName(className),
|
||||
style: mergedStyle,
|
||||
...props,
|
||||
children: buildParts()
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
ContentText.displayName = "ContentText";
|
||||
var DefaultMention = ({ entity }) => /* @__PURE__ */ jsxRuntime.jsx(react.TachTypography.Text.Body, { color: "link", children: entity.displayText });
|
||||
var DefaultTag = ({ entity }) => /* @__PURE__ */ jsxRuntime.jsx(react.TachTypography.Text.Body, { color: "link", children: entity.text });
|
||||
var ContentTextWithSuggestions = ({
|
||||
renderMention,
|
||||
renderTag,
|
||||
...props
|
||||
}) => {
|
||||
return /* @__PURE__ */ jsxRuntime.jsx(
|
||||
ContentText,
|
||||
{
|
||||
...props,
|
||||
renderMention: (entity, index) => renderMention ? renderMention(entity, index) : /* @__PURE__ */ jsxRuntime.jsx(DefaultMention, { entity }),
|
||||
renderTag: (entity, index) => renderTag ? renderTag(entity, index) : /* @__PURE__ */ jsxRuntime.jsx(DefaultTag, { entity })
|
||||
}
|
||||
);
|
||||
};
|
||||
var ContentTitleWithSuggestions = ({
|
||||
text,
|
||||
ellipsis,
|
||||
blur = false,
|
||||
...rest
|
||||
}) => {
|
||||
const normalizedEllipsis = ellipsis === void 0 ? { rows: 2 } : ellipsis;
|
||||
const textProps = text === void 0 ? {} : { text };
|
||||
return /* @__PURE__ */ jsxRuntime.jsx(
|
||||
ContentTextWithSuggestions,
|
||||
{
|
||||
weight: "bold",
|
||||
blur,
|
||||
ellipsis: normalizedEllipsis,
|
||||
...textProps,
|
||||
...rest
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
exports.ContentText = ContentText;
|
||||
exports.ContentTextWithSuggestions = ContentTextWithSuggestions;
|
||||
exports.ContentTitleWithSuggestions = ContentTitleWithSuggestions;
|
||||
exports.findAllEntities = findAllEntities;
|
||||
exports.findLinks = findLinks;
|
||||
exports.findMentions = findMentions;
|
||||
exports.findTags = findTags;
|
||||
exports.mentionLinkRegexp = mentionLinkRegexp;
|
||||
exports.parseMention = parseMention;
|
||||
exports.processContent = processContent;
|
||||
//# sourceMappingURL=index.cjs.map
|
||||
//# sourceMappingURL=index.cjs.map
|
||||
1
packages/content-suggestions/dist/react/index.cjs.map
vendored
Normal file
1
packages/content-suggestions/dist/react/index.cjs.map
vendored
Normal file
File diff suppressed because one or more lines are too long
48
packages/content-suggestions/dist/react/index.d.cts
vendored
Normal file
48
packages/content-suggestions/dist/react/index.d.cts
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import React, { ComponentProps, ReactNode } from 'react';
|
||||
import { EllipsisConfig } from 'antd/lib/typography/Base';
|
||||
import { M as MentionEntity, T as TagEntity, L as LinkEntity } from '../types-BRt4hd7A.cjs';
|
||||
export { B as BaseEntity, C as ContentEntity, P as ParsedMention, a as ProcessedContent } from '../types-BRt4hd7A.cjs';
|
||||
import { TachTypography } from '@hublib-web/tach-typography/react';
|
||||
import * as react_jsx_runtime from 'react/jsx-runtime';
|
||||
export { findAllEntities, findLinks, findMentions, findTags, mentionLinkRegexp, parseMention, processContent } from '../core/index.cjs';
|
||||
|
||||
type CustomEllipsisConfig = ({
|
||||
count: number;
|
||||
rows?: never;
|
||||
expandable?: boolean;
|
||||
} & Partial<EllipsisConfig>) | ({
|
||||
rows: number;
|
||||
count?: never;
|
||||
expandable?: boolean;
|
||||
} & Partial<EllipsisConfig>) | false;
|
||||
type ParagraphBodyProps = ComponentProps<typeof TachTypography.Paragraph.Body>;
|
||||
type TextBodyProps = ComponentProps<typeof TachTypography.Text.Body>;
|
||||
type TitleBodyProps = ComponentProps<typeof TachTypography.Title.Body>;
|
||||
interface ContentTextProps {
|
||||
className?: string;
|
||||
weight?: TextBodyProps["weight"];
|
||||
text?: string | null;
|
||||
ellipsis?: CustomEllipsisConfig;
|
||||
blur?: boolean;
|
||||
style?: TextBodyProps["style"];
|
||||
onView?: () => void;
|
||||
renderMention?: (entity: MentionEntity, index: number) => ReactNode;
|
||||
renderTag?: (entity: TagEntity, index: number) => ReactNode;
|
||||
renderLink?: (entity: LinkEntity, index: number) => ReactNode;
|
||||
ParagraphComponent?: React.ComponentType<ParagraphBodyProps>;
|
||||
TextComponent?: React.ComponentType<TextBodyProps>;
|
||||
TitleComponent?: React.ComponentType<TitleBodyProps>;
|
||||
}
|
||||
declare const ContentText: React.NamedExoticComponent<ContentTextProps>;
|
||||
|
||||
type BaseContentTextProps = Omit<ComponentProps<typeof ContentText>, "renderMention" | "renderTag"> & {
|
||||
renderMention?: (entity: MentionEntity, index: number) => React.ReactNode;
|
||||
renderTag?: (entity: TagEntity, index: number) => React.ReactNode;
|
||||
};
|
||||
declare const ContentTextWithSuggestions: ({ renderMention, renderTag, ...props }: BaseContentTextProps) => react_jsx_runtime.JSX.Element;
|
||||
|
||||
interface ContentTitleWithSuggestionsProps extends Omit<ComponentProps<typeof ContentTextWithSuggestions>, "weight"> {
|
||||
}
|
||||
declare const ContentTitleWithSuggestions: ({ text, ellipsis, blur, ...rest }: ContentTitleWithSuggestionsProps) => react_jsx_runtime.JSX.Element;
|
||||
|
||||
export { ContentText, type ContentTextProps, ContentTextWithSuggestions, ContentTitleWithSuggestions, LinkEntity, MentionEntity, TagEntity };
|
||||
48
packages/content-suggestions/dist/react/index.d.ts
vendored
Normal file
48
packages/content-suggestions/dist/react/index.d.ts
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import React, { ComponentProps, ReactNode } from 'react';
|
||||
import { EllipsisConfig } from 'antd/lib/typography/Base';
|
||||
import { M as MentionEntity, T as TagEntity, L as LinkEntity } from '../types-BRt4hd7A.js';
|
||||
export { B as BaseEntity, C as ContentEntity, P as ParsedMention, a as ProcessedContent } from '../types-BRt4hd7A.js';
|
||||
import { TachTypography } from '@hublib-web/tach-typography/react';
|
||||
import * as react_jsx_runtime from 'react/jsx-runtime';
|
||||
export { findAllEntities, findLinks, findMentions, findTags, mentionLinkRegexp, parseMention, processContent } from '../core/index.js';
|
||||
|
||||
type CustomEllipsisConfig = ({
|
||||
count: number;
|
||||
rows?: never;
|
||||
expandable?: boolean;
|
||||
} & Partial<EllipsisConfig>) | ({
|
||||
rows: number;
|
||||
count?: never;
|
||||
expandable?: boolean;
|
||||
} & Partial<EllipsisConfig>) | false;
|
||||
type ParagraphBodyProps = ComponentProps<typeof TachTypography.Paragraph.Body>;
|
||||
type TextBodyProps = ComponentProps<typeof TachTypography.Text.Body>;
|
||||
type TitleBodyProps = ComponentProps<typeof TachTypography.Title.Body>;
|
||||
interface ContentTextProps {
|
||||
className?: string;
|
||||
weight?: TextBodyProps["weight"];
|
||||
text?: string | null;
|
||||
ellipsis?: CustomEllipsisConfig;
|
||||
blur?: boolean;
|
||||
style?: TextBodyProps["style"];
|
||||
onView?: () => void;
|
||||
renderMention?: (entity: MentionEntity, index: number) => ReactNode;
|
||||
renderTag?: (entity: TagEntity, index: number) => ReactNode;
|
||||
renderLink?: (entity: LinkEntity, index: number) => ReactNode;
|
||||
ParagraphComponent?: React.ComponentType<ParagraphBodyProps>;
|
||||
TextComponent?: React.ComponentType<TextBodyProps>;
|
||||
TitleComponent?: React.ComponentType<TitleBodyProps>;
|
||||
}
|
||||
declare const ContentText: React.NamedExoticComponent<ContentTextProps>;
|
||||
|
||||
type BaseContentTextProps = Omit<ComponentProps<typeof ContentText>, "renderMention" | "renderTag"> & {
|
||||
renderMention?: (entity: MentionEntity, index: number) => React.ReactNode;
|
||||
renderTag?: (entity: TagEntity, index: number) => React.ReactNode;
|
||||
};
|
||||
declare const ContentTextWithSuggestions: ({ renderMention, renderTag, ...props }: BaseContentTextProps) => react_jsx_runtime.JSX.Element;
|
||||
|
||||
interface ContentTitleWithSuggestionsProps extends Omit<ComponentProps<typeof ContentTextWithSuggestions>, "weight"> {
|
||||
}
|
||||
declare const ContentTitleWithSuggestions: ({ text, ellipsis, blur, ...rest }: ContentTitleWithSuggestionsProps) => react_jsx_runtime.JSX.Element;
|
||||
|
||||
export { ContentText, type ContentTextProps, ContentTextWithSuggestions, ContentTitleWithSuggestions, LinkEntity, MentionEntity, TagEntity };
|
||||
381
packages/content-suggestions/dist/react/index.js
vendored
Normal file
381
packages/content-suggestions/dist/react/index.js
vendored
Normal file
@@ -0,0 +1,381 @@
|
||||
import React, { useRef, useState, useMemo, useCallback, useEffect } from 'react';
|
||||
import { TachTypography } from '@hublib-web/tach-typography/react';
|
||||
import { jsxs, jsx } from 'react/jsx-runtime';
|
||||
|
||||
// src/react/components/content-text.tsx
|
||||
|
||||
// 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);
|
||||
};
|
||||
var processContent = (content) => {
|
||||
const processedText = content.replace(mentionLinkRegexp, (match) => {
|
||||
const parsed = parseMention(match);
|
||||
return parsed ? parsed.mention : match;
|
||||
});
|
||||
const tags = findTags(content).map((tag) => tag.tag);
|
||||
return {
|
||||
processedText,
|
||||
tags
|
||||
};
|
||||
};
|
||||
var joinClassName = (...values) => values.filter(Boolean).join(" ");
|
||||
var baseSelectableStyle = {
|
||||
whiteSpace: "pre-wrap",
|
||||
WebkitTouchCallout: "default",
|
||||
WebkitUserSelect: "text",
|
||||
KhtmlUserSelect: "text",
|
||||
MozUserSelect: "text",
|
||||
msUserSelect: "text",
|
||||
userSelect: "text"
|
||||
};
|
||||
var blurStyle = {
|
||||
filter: "blur(3px)",
|
||||
WebkitUserSelect: "none",
|
||||
KhtmlUserSelect: "none",
|
||||
MozUserSelect: "none",
|
||||
msUserSelect: "none",
|
||||
userSelect: "none",
|
||||
pointerEvents: "none"
|
||||
};
|
||||
var ReadMoreButton = ({ onClick, symbol = "\u0427\u0438\u0442\u0430\u0442\u044C \u043F\u043E\u043B\u043D\u043E\u0441\u0442\u044C\u044E", expanded = false, TitleComponent }) => /* @__PURE__ */ jsx(
|
||||
TitleComponent,
|
||||
{
|
||||
onClick: (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
onClick(event);
|
||||
},
|
||||
weight: "bold",
|
||||
level: 5,
|
||||
children: typeof symbol === "function" ? symbol(expanded) : symbol
|
||||
}
|
||||
);
|
||||
var ContentText = React.memo(
|
||||
({
|
||||
text,
|
||||
className,
|
||||
ellipsis = false,
|
||||
blur = false,
|
||||
weight = "normal",
|
||||
style,
|
||||
onView,
|
||||
renderMention,
|
||||
renderTag,
|
||||
renderLink,
|
||||
ParagraphComponent = TachTypography.Paragraph.Body,
|
||||
TextComponent = TachTypography.Text.Body,
|
||||
TitleComponent = TachTypography.Title.Body,
|
||||
...props
|
||||
}) => {
|
||||
const containerRef = useRef(null);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [containerInsideView, setContainerInsideView] = useState(false);
|
||||
const [viewed, setViewed] = useState(false);
|
||||
const content = text || "";
|
||||
const entities = useMemo(() => findAllEntities(content), [content]);
|
||||
const wrapWithKey = (node, key) => {
|
||||
if (React.isValidElement(node)) {
|
||||
return React.cloneElement(node, { key });
|
||||
}
|
||||
return /* @__PURE__ */ jsx(React.Fragment, { children: node }, key);
|
||||
};
|
||||
const buildMentionNode = (entity, index) => {
|
||||
const defaultNode = /* @__PURE__ */ jsx(TextComponent, { color: "link", weight, children: entity.displayText });
|
||||
const customNode = renderMention?.(entity, index) ?? defaultNode;
|
||||
return wrapWithKey(customNode, `mention-${entity.start}-${index}`);
|
||||
};
|
||||
const buildTagNode = (entity, index) => {
|
||||
const defaultNode = /* @__PURE__ */ jsx(TextComponent, { color: "link", weight, children: entity.text });
|
||||
const customNode = renderTag?.(entity, index) ?? defaultNode;
|
||||
return wrapWithKey(customNode, `tag-${entity.start}-${index}`);
|
||||
};
|
||||
const buildLinkNode = (entity, index) => {
|
||||
const defaultNode = /* @__PURE__ */ jsx(
|
||||
TachTypography.Link.Body,
|
||||
{
|
||||
target: "_blank",
|
||||
referrerPolicy: "no-referrer",
|
||||
color: "link",
|
||||
weight,
|
||||
href: entity.url,
|
||||
children: entity.text
|
||||
}
|
||||
);
|
||||
const customNode = renderLink?.(entity, index) ?? defaultNode;
|
||||
return wrapWithKey(customNode, `link-${entity.start}-${index}`);
|
||||
};
|
||||
const buildParts = (upto = null) => {
|
||||
let lastIndex = 0;
|
||||
const nodes = [];
|
||||
for (const [i, 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(content.slice(lastIndex, textEnd));
|
||||
}
|
||||
if (upto === null || entity.end <= upto) {
|
||||
if (entity.type === "mention") {
|
||||
nodes.push(buildMentionNode(entity, i));
|
||||
} else if (entity.type === "tag") {
|
||||
nodes.push(buildTagNode(entity, i));
|
||||
} else if (entity.type === "link") {
|
||||
nodes.push(buildLinkNode(entity, i));
|
||||
}
|
||||
}
|
||||
lastIndex = entity.end;
|
||||
}
|
||||
if (upto === null) {
|
||||
if (lastIndex < content.length) {
|
||||
nodes.push(content.slice(lastIndex));
|
||||
}
|
||||
} else if (lastIndex < upto) {
|
||||
nodes.push(content.slice(lastIndex, upto));
|
||||
}
|
||||
return nodes;
|
||||
};
|
||||
const ellipsisConfig = ellipsis && typeof ellipsis === "object" ? ellipsis : null;
|
||||
const expandedFromProps = ellipsisConfig && typeof ellipsisConfig.expanded === "boolean" ? ellipsisConfig.expanded : void 0;
|
||||
const isExpandedControlled = expandedFromProps !== void 0;
|
||||
const mergedExpanded = isExpandedControlled ? expandedFromProps : expanded;
|
||||
const handleExpand = useCallback(
|
||||
(event) => {
|
||||
if (!isExpandedControlled) {
|
||||
setExpanded(true);
|
||||
}
|
||||
ellipsisConfig?.onExpand?.(event, { expanded: true });
|
||||
},
|
||||
[ellipsisConfig, isExpandedControlled]
|
||||
);
|
||||
useEffect(() => {
|
||||
if (isExpandedControlled) {
|
||||
return;
|
||||
}
|
||||
if (ellipsisConfig && "count" in ellipsisConfig) {
|
||||
const count = ellipsisConfig.count ?? 0;
|
||||
if (content.length <= count && !expanded) {
|
||||
setExpanded(true);
|
||||
}
|
||||
}
|
||||
}, [content.length, ellipsisConfig, expanded, isExpandedControlled]);
|
||||
useEffect(() => {
|
||||
if (mergedExpanded && !viewed && containerInsideView) {
|
||||
setViewed(true);
|
||||
onView?.();
|
||||
}
|
||||
}, [mergedExpanded, viewed, containerInsideView, onView]);
|
||||
useEffect(() => {
|
||||
const ref = containerRef.current;
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
const entry = entries[0];
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
if (entry.isIntersecting && !containerInsideView) {
|
||||
setContainerInsideView(true);
|
||||
}
|
||||
}, { threshold: 0.5 });
|
||||
observer.observe(ref);
|
||||
return () => {
|
||||
observer.unobserve(ref);
|
||||
};
|
||||
}, [containerInsideView]);
|
||||
const mergedStyle = {
|
||||
...baseSelectableStyle,
|
||||
...blur ? blurStyle : void 0,
|
||||
...style
|
||||
};
|
||||
if (ellipsisConfig && "count" in ellipsisConfig) {
|
||||
const { count, expandable } = ellipsisConfig;
|
||||
if (!mergedExpanded && count && content.length > count) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
const truncatedNodes = buildParts(cutoff);
|
||||
return /* @__PURE__ */ jsxs(
|
||||
ParagraphComponent,
|
||||
{
|
||||
ref: containerRef,
|
||||
weight,
|
||||
className: joinClassName(className),
|
||||
style: mergedStyle,
|
||||
...props,
|
||||
children: [
|
||||
truncatedNodes,
|
||||
"\u2026",
|
||||
expandable && /* @__PURE__ */ jsx(
|
||||
ReadMoreButton,
|
||||
{
|
||||
symbol: ellipsisConfig.symbol,
|
||||
onClick: handleExpand,
|
||||
expanded: mergedExpanded,
|
||||
TitleComponent
|
||||
}
|
||||
)
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
if (ellipsisConfig && "rows" in ellipsisConfig) {
|
||||
const paragraphEllipsis = mergedExpanded ? false : {
|
||||
...ellipsisConfig,
|
||||
symbol: ellipsisConfig.expandable ? /* @__PURE__ */ jsx(
|
||||
ReadMoreButton,
|
||||
{
|
||||
symbol: ellipsisConfig.symbol,
|
||||
onClick: handleExpand,
|
||||
expanded: mergedExpanded,
|
||||
TitleComponent
|
||||
}
|
||||
) : ellipsisConfig.symbol
|
||||
};
|
||||
return /* @__PURE__ */ jsx(
|
||||
ParagraphComponent,
|
||||
{
|
||||
ref: containerRef,
|
||||
weight,
|
||||
className: joinClassName(className),
|
||||
style: mergedStyle,
|
||||
ellipsis: paragraphEllipsis,
|
||||
...props,
|
||||
children: buildParts()
|
||||
}
|
||||
);
|
||||
}
|
||||
return /* @__PURE__ */ jsx(
|
||||
ParagraphComponent,
|
||||
{
|
||||
ref: containerRef,
|
||||
weight,
|
||||
className: joinClassName(className),
|
||||
style: mergedStyle,
|
||||
...props,
|
||||
children: buildParts()
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
ContentText.displayName = "ContentText";
|
||||
var DefaultMention = ({ entity }) => /* @__PURE__ */ jsx(TachTypography.Text.Body, { color: "link", children: entity.displayText });
|
||||
var DefaultTag = ({ entity }) => /* @__PURE__ */ jsx(TachTypography.Text.Body, { color: "link", children: entity.text });
|
||||
var ContentTextWithSuggestions = ({
|
||||
renderMention,
|
||||
renderTag,
|
||||
...props
|
||||
}) => {
|
||||
return /* @__PURE__ */ jsx(
|
||||
ContentText,
|
||||
{
|
||||
...props,
|
||||
renderMention: (entity, index) => renderMention ? renderMention(entity, index) : /* @__PURE__ */ jsx(DefaultMention, { entity }),
|
||||
renderTag: (entity, index) => renderTag ? renderTag(entity, index) : /* @__PURE__ */ jsx(DefaultTag, { entity })
|
||||
}
|
||||
);
|
||||
};
|
||||
var ContentTitleWithSuggestions = ({
|
||||
text,
|
||||
ellipsis,
|
||||
blur = false,
|
||||
...rest
|
||||
}) => {
|
||||
const normalizedEllipsis = ellipsis === void 0 ? { rows: 2 } : ellipsis;
|
||||
const textProps = text === void 0 ? {} : { text };
|
||||
return /* @__PURE__ */ jsx(
|
||||
ContentTextWithSuggestions,
|
||||
{
|
||||
weight: "bold",
|
||||
blur,
|
||||
ellipsis: normalizedEllipsis,
|
||||
...textProps,
|
||||
...rest
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export { ContentText, ContentTextWithSuggestions, ContentTitleWithSuggestions, findAllEntities, findLinks, findMentions, findTags, mentionLinkRegexp, parseMention, processContent };
|
||||
//# sourceMappingURL=index.js.map
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
packages/content-suggestions/dist/react/index.js.map
vendored
Normal file
1
packages/content-suggestions/dist/react/index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
29
packages/content-suggestions/dist/types-BRt4hd7A.d.cts
vendored
Normal file
29
packages/content-suggestions/dist/types-BRt4hd7A.d.cts
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
interface BaseEntity {
|
||||
start: number;
|
||||
end: number;
|
||||
text: string;
|
||||
}
|
||||
interface MentionEntity extends BaseEntity {
|
||||
type: "mention";
|
||||
displayText: string;
|
||||
userId?: string;
|
||||
}
|
||||
interface TagEntity extends BaseEntity {
|
||||
type: "tag";
|
||||
tag: string;
|
||||
}
|
||||
interface LinkEntity extends BaseEntity {
|
||||
type: "link";
|
||||
url: string;
|
||||
}
|
||||
type ContentEntity = MentionEntity | TagEntity | LinkEntity;
|
||||
interface ParsedMention {
|
||||
mention: string;
|
||||
id: string;
|
||||
}
|
||||
interface ProcessedContent {
|
||||
processedText: string;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
export type { BaseEntity as B, ContentEntity as C, LinkEntity as L, MentionEntity as M, ParsedMention as P, TagEntity as T, ProcessedContent as a };
|
||||
29
packages/content-suggestions/dist/types-BRt4hd7A.d.ts
vendored
Normal file
29
packages/content-suggestions/dist/types-BRt4hd7A.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
interface BaseEntity {
|
||||
start: number;
|
||||
end: number;
|
||||
text: string;
|
||||
}
|
||||
interface MentionEntity extends BaseEntity {
|
||||
type: "mention";
|
||||
displayText: string;
|
||||
userId?: string;
|
||||
}
|
||||
interface TagEntity extends BaseEntity {
|
||||
type: "tag";
|
||||
tag: string;
|
||||
}
|
||||
interface LinkEntity extends BaseEntity {
|
||||
type: "link";
|
||||
url: string;
|
||||
}
|
||||
type ContentEntity = MentionEntity | TagEntity | LinkEntity;
|
||||
interface ParsedMention {
|
||||
mention: string;
|
||||
id: string;
|
||||
}
|
||||
interface ProcessedContent {
|
||||
processedText: string;
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
export type { BaseEntity as B, ContentEntity as C, LinkEntity as L, MentionEntity as M, ParsedMention as P, TagEntity as T, ProcessedContent as a };
|
||||
Reference in New Issue
Block a user