@automattic/social-previews 3.2.4 → 3.2.5
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/CHANGELOG.md +9 -1
- package/dist/index.d.mts +29 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.js +106 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +81 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -50,6 +50,43 @@ var formatMastodonDate = new Intl.DateTimeFormat("en-US", {
|
|
|
50
50
|
day: "numeric",
|
|
51
51
|
year: "numeric"
|
|
52
52
|
}).format;
|
|
53
|
+
var collapseWhitespace = (text) => text.replace(/\s+/g, " ").trim();
|
|
54
|
+
var countOccurrences = (haystack, needle) => {
|
|
55
|
+
let count = 0;
|
|
56
|
+
for (let pos = haystack.indexOf(needle); pos !== -1; pos = haystack.indexOf(needle, pos + 1)) {
|
|
57
|
+
count++;
|
|
58
|
+
}
|
|
59
|
+
return count;
|
|
60
|
+
};
|
|
61
|
+
var nthIndexOf = (haystack, needle, n) => {
|
|
62
|
+
let pos = haystack.indexOf(needle);
|
|
63
|
+
while (pos !== -1 && n > 0) {
|
|
64
|
+
n--;
|
|
65
|
+
pos = haystack.indexOf(needle, pos + 1);
|
|
66
|
+
}
|
|
67
|
+
return pos;
|
|
68
|
+
};
|
|
69
|
+
function parseHyperlinks(html) {
|
|
70
|
+
if (!html) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
const doc = document.implementation.createHTMLDocument("");
|
|
74
|
+
doc.body.innerHTML = html;
|
|
75
|
+
const links = [];
|
|
76
|
+
for (const anchor of Array.from(doc.body.querySelectorAll("a[href]"))) {
|
|
77
|
+
const href = anchor.getAttribute("href") ?? "";
|
|
78
|
+
const text = collapseWhitespace(anchor.textContent ?? "");
|
|
79
|
+
if (!/^https?:\/\//i.test(href) || "" === text || text === href) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const range = doc.createRange();
|
|
83
|
+
range.selectNodeContents(doc.body);
|
|
84
|
+
range.setEndBefore(anchor);
|
|
85
|
+
const occurrence = countOccurrences(collapseWhitespace(range.toString()), text);
|
|
86
|
+
links.push({ text, href, occurrence });
|
|
87
|
+
}
|
|
88
|
+
return links;
|
|
89
|
+
}
|
|
53
90
|
var hashtagUrlMap = {
|
|
54
91
|
twitter: "https://twitter.com/hashtag/%1$s",
|
|
55
92
|
facebook: "https://www.facebook.com/hashtag/%1$s",
|
|
@@ -68,7 +105,8 @@ function preparePreviewText(text, options) {
|
|
|
68
105
|
maxLines,
|
|
69
106
|
hyperlinkHashtags = true,
|
|
70
107
|
// Instagram doesn't support hyperlink URLs at the moment.
|
|
71
|
-
hyperlinkUrls = "instagram" !== platform
|
|
108
|
+
hyperlinkUrls = "instagram" !== platform,
|
|
109
|
+
hyperlinks
|
|
72
110
|
} = options;
|
|
73
111
|
let result = stripHtmlTags(text);
|
|
74
112
|
result = result.replaceAll(/(?:\s*[\n\r]){2,}/g, "\n\n");
|
|
@@ -98,6 +136,31 @@ function preparePreviewText(text, options) {
|
|
|
98
136
|
result = result.replace(fullMatch, `${whitespace}<Hashtag${index} />`);
|
|
99
137
|
});
|
|
100
138
|
}
|
|
139
|
+
if (hyperlinks?.length) {
|
|
140
|
+
const matches = [];
|
|
141
|
+
hyperlinks.forEach(({ text: anchorText, href, occurrence = 0 }, index) => {
|
|
142
|
+
if (!anchorText) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const pos = nthIndexOf(result, anchorText, occurrence);
|
|
146
|
+
if (pos === -1) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const overlaps = matches.some(
|
|
150
|
+
(match) => pos < match.pos + match.text.length && match.pos < pos + anchorText.length
|
|
151
|
+
);
|
|
152
|
+
if (!overlaps) {
|
|
153
|
+
matches.push({ pos, text: anchorText, href, index });
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
matches.sort((a, b) => b.pos - a.pos);
|
|
157
|
+
for (const { pos, text: anchorText, href, index } of matches) {
|
|
158
|
+
const token = `Hyperlink${index}`;
|
|
159
|
+
componentMap[token] = /* @__PURE__ */ jsx("a", { href, rel: "noopener noreferrer", target: "_blank" });
|
|
160
|
+
const wrapped = `<${token}>${anchorText}</${token}>`;
|
|
161
|
+
result = result.slice(0, pos) + wrapped + result.slice(pos + anchorText.length);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
101
164
|
result = result.replace(/\n/g, "<br />");
|
|
102
165
|
componentMap.br = /* @__PURE__ */ jsx("br", {});
|
|
103
166
|
return createInterpolateElement(result, componentMap);
|
|
@@ -836,7 +899,8 @@ var TumblrPostPreview = ({
|
|
|
836
899
|
image,
|
|
837
900
|
user,
|
|
838
901
|
url,
|
|
839
|
-
media
|
|
902
|
+
media,
|
|
903
|
+
hyperlinks
|
|
840
904
|
}) => {
|
|
841
905
|
const avatarUrl = user?.avatarUrl;
|
|
842
906
|
const mediaItem = media?.[0];
|
|
@@ -847,7 +911,8 @@ var TumblrPostPreview = ({
|
|
|
847
911
|
/* @__PURE__ */ jsxs16("div", { className: "tumblr-preview__body", children: [
|
|
848
912
|
title ? /* @__PURE__ */ jsx25("div", { className: "tumblr-preview__title", children: tumblrTitle(title) }) : null,
|
|
849
913
|
description && /* @__PURE__ */ jsx25("div", { className: "tumblr-preview__description", children: /* @__PURE__ */ jsx25(ExpandableText, { text: description, children: (visibleText) => preparePreviewText(tumblrDescription(visibleText), {
|
|
850
|
-
platform: "tumblr"
|
|
914
|
+
platform: "tumblr",
|
|
915
|
+
hyperlinks
|
|
851
916
|
}) }) }),
|
|
852
917
|
mediaItem ? /* @__PURE__ */ jsx25("div", { className: "tumblr-preview__media-item", children: mediaItem.type.startsWith("video/") ? /* @__PURE__ */ jsx25("video", { controls: true, className: "tumblr-preview__media--video", children: /* @__PURE__ */ jsx25("source", { src: mediaItem.url, type: mediaItem.type }) }) : /* @__PURE__ */ jsx25("img", { className: "tumblr-preview__image", src: mediaItem.url, alt: "" }) }) : image && /* @__PURE__ */ jsx25(
|
|
853
918
|
"img",
|
|
@@ -1820,21 +1885,28 @@ var blueskyTitle = (text) => firstValid(
|
|
|
1820
1885
|
hardTruncation(TITLE_LENGTH5)
|
|
1821
1886
|
)(stripHtmlTags(text)) || "";
|
|
1822
1887
|
var blueskyBody = (text, options = {}) => {
|
|
1823
|
-
const { offset = 0, reserveUrlSpace = true } = options;
|
|
1888
|
+
const { offset = 0, reserveUrlSpace = true, hyperlinks } = options;
|
|
1824
1889
|
return preparePreviewText(text, {
|
|
1825
1890
|
platform: "bluesky",
|
|
1826
|
-
maxChars: BODY_LENGTH2 - (reserveUrlSpace ? URL_LENGTH2 : 0) - offset
|
|
1891
|
+
maxChars: BODY_LENGTH2 - (reserveUrlSpace ? URL_LENGTH2 : 0) - offset,
|
|
1892
|
+
hyperlinks
|
|
1827
1893
|
});
|
|
1828
1894
|
};
|
|
1829
1895
|
var blueskyUrl = (text) => firstValid(shortEnough(URL_LENGTH2), hardTruncation(URL_LENGTH2))(stripHtmlTags(text)) || "";
|
|
1830
1896
|
|
|
1831
1897
|
// src/bluesky-preview/post/body/index.tsx
|
|
1832
1898
|
import { Fragment as Fragment6, jsx as jsx54, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
1833
|
-
var BlueskyPostBody = ({
|
|
1899
|
+
var BlueskyPostBody = ({
|
|
1900
|
+
customText,
|
|
1901
|
+
url,
|
|
1902
|
+
children,
|
|
1903
|
+
appendUrl,
|
|
1904
|
+
hyperlinks
|
|
1905
|
+
}) => {
|
|
1834
1906
|
const showUrl = appendUrl && !!url && !customText?.includes(url);
|
|
1835
1907
|
return /* @__PURE__ */ jsxs37("div", { className: "bluesky-preview__body", children: [
|
|
1836
1908
|
customText ? /* @__PURE__ */ jsxs37(Fragment6, { children: [
|
|
1837
|
-
/* @__PURE__ */ jsx54("div", { children: blueskyBody(customText, { reserveUrlSpace: showUrl }) }),
|
|
1909
|
+
/* @__PURE__ */ jsx54("div", { children: blueskyBody(customText, { reserveUrlSpace: showUrl, hyperlinks }) }),
|
|
1838
1910
|
showUrl ? /* @__PURE__ */ jsxs37(Fragment6, { children: [
|
|
1839
1911
|
/* @__PURE__ */ jsx54("br", {}),
|
|
1840
1912
|
/* @__PURE__ */ jsx54("a", { href: url, target: "_blank", rel: "noreferrer noopener", children: blueskyUrl(url.replace(/^https?:\/\//, "")) })
|
|
@@ -2441,6 +2513,7 @@ export {
|
|
|
2441
2513
|
TumblrPreviews,
|
|
2442
2514
|
TwitterLinkPreview,
|
|
2443
2515
|
TwitterPostPreview,
|
|
2444
|
-
TwitterPreviews
|
|
2516
|
+
TwitterPreviews,
|
|
2517
|
+
parseHyperlinks
|
|
2445
2518
|
};
|
|
2446
2519
|
//# sourceMappingURL=index.mjs.map
|