@automattic/social-previews 3.2.3 → 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 CHANGED
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.2.5] - 2026-06-15
9
+ ### Changed
10
+ - Update package dependencies. [#49273]
11
+
12
+ ### Fixed
13
+ - Render editor hyperlinks as clickable links in Bluesky and Tumblr previews [#49483]
14
+
15
+ ## [3.2.4] - 2026-06-08
16
+ ### Changed
17
+ - Update dependencies. [#49354]
18
+
19
+ ### Fixed
20
+ - Avoid having the Mastodon share preview show post URL twice when the custom message already includes it. [#49338]
21
+
8
22
  ## [3.2.3] - 2026-05-25
9
23
  ### Changed
10
24
  - Update package dependencies. [#48405] [#49012]
@@ -193,6 +207,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
193
207
 
194
208
  - Initial release after extracting from Calypso.
195
209
 
210
+ [3.2.5]: https://github.com/Automattic/social-previews/compare/v3.2.4...v3.2.5
211
+ [3.2.4]: https://github.com/Automattic/social-previews/compare/v3.2.3...v3.2.4
196
212
  [3.2.3]: https://github.com/Automattic/social-previews/compare/v3.2.2...v3.2.3
197
213
  [3.2.2]: https://github.com/Automattic/social-previews/compare/v3.2.1...v3.2.2
198
214
  [3.2.1]: https://github.com/Automattic/social-previews/compare/v3.2.0...v3.2.1
package/SECURITY.md CHANGED
@@ -13,7 +13,6 @@ Our HackerOne program covers the below plugin software, as well as a variety of
13
13
  * [Jetpack](https://jetpack.com/)
14
14
  * Jetpack Backup
15
15
  * Jetpack Boost
16
- * Jetpack CRM
17
16
  * Jetpack Protect
18
17
  * Jetpack Search
19
18
  * Jetpack Social
package/dist/index.d.mts CHANGED
@@ -1,5 +1,28 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
+ /**
4
+ * An editor hyperlink: the visible anchor text and the URL it points to.
5
+ */
6
+ type Hyperlink = {
7
+ text: string;
8
+ href: string;
9
+ /**
10
+ * Zero-based index of this anchor among identical occurrences of `text` in
11
+ * the content, so repeated texts link the right duplicate. Defaults to 0.
12
+ */
13
+ occurrence?: number;
14
+ };
15
+ /**
16
+ * Extracts `(text, href)` pairs from `<a href="…">text</a>` in HTML, skipping
17
+ * autolinks (text already equals the URL) and non-http(s) hrefs. Mirrors the
18
+ * backend `ExtractorUtils::get_anchor_links_from_html` so the preview links the
19
+ * same anchors the published share will.
20
+ *
21
+ * @param html - Raw post content HTML.
22
+ * @return The editor hyperlinks found, in document order.
23
+ */
24
+ declare function parseHyperlinks(html: string): Hyperlink[];
25
+
3
26
  declare const HEADING_LEVELS: readonly [2, 3, 4, 5, 6];
4
27
  type SectionHeadingProps = {
5
28
  className?: string;
@@ -12,6 +35,11 @@ interface SocialPreviewBaseProps {
12
35
  * The URL of the post/page to preview.
13
36
  */
14
37
  url: string;
38
+ /**
39
+ * Editor hyperlinks rendered over the matching body text on the networks
40
+ * that support inline links (Bluesky, Tumblr). Other networks ignore this.
41
+ */
42
+ hyperlinks?: Hyperlink[];
15
43
  /**
16
44
  * The title of the post/page to preview.
17
45
  */
@@ -275,4 +303,4 @@ declare function InstagramPostPreview({ image, media, name, profileImage, captio
275
303
 
276
304
  declare const InstagramPreviews: React.FC<InstagramPreviewsProps>;
277
305
 
278
- export { AUTO_SHARED_LINK_PREVIEW, AUTO_SHARED_SOCIAL_POST_PREVIEW, BlueskyLinkPreview, BlueskyPostPreview, BlueskyPreviews, type BlueskyPreviewsProps, DEFAULT_LINK_PREVIEW, FacebookLinkPreview, type FacebookLinkPreviewProps, FacebookPostPreview, FacebookPreviews, type FacebookPreviewsProps, GoogleSearchPreview, type GoogleSearchPreviewProps, InstagramPostPreview, InstagramPreviews, LANDSCAPE_MODE, LinkedInLinkPreview, type LinkedInLinkPreviewProps, LinkedInPostPreview, LinkedInPreviews, MastodonLinkPreview, MastodonPostPreview, MastodonPreviews, type MastodonPreviewsProps, type MediaItem, NextdoorLinkPreview, type NextdoorLinkPreviewProps, NextdoorPostPreview, NextdoorPreviews, PORTRAIT_MODE, type SocialPreviewBaseProps, type SocialPreviewsBaseProps, TYPE_ARTICLE, TYPE_WEBSITE, ThreadsLinkPreview, ThreadsPostPreview, ThreadsPreviews, TumblrLinkPreview, TumblrPostPreview, TumblrPreviews, type TumblrPreviewsProps, TwitterLinkPreview, TwitterPostPreview, TwitterPreviews };
306
+ export { AUTO_SHARED_LINK_PREVIEW, AUTO_SHARED_SOCIAL_POST_PREVIEW, BlueskyLinkPreview, BlueskyPostPreview, BlueskyPreviews, type BlueskyPreviewsProps, DEFAULT_LINK_PREVIEW, FacebookLinkPreview, type FacebookLinkPreviewProps, FacebookPostPreview, FacebookPreviews, type FacebookPreviewsProps, GoogleSearchPreview, type GoogleSearchPreviewProps, type Hyperlink, InstagramPostPreview, InstagramPreviews, LANDSCAPE_MODE, LinkedInLinkPreview, type LinkedInLinkPreviewProps, LinkedInPostPreview, LinkedInPreviews, MastodonLinkPreview, MastodonPostPreview, MastodonPreviews, type MastodonPreviewsProps, type MediaItem, NextdoorLinkPreview, type NextdoorLinkPreviewProps, NextdoorPostPreview, NextdoorPreviews, PORTRAIT_MODE, type SocialPreviewBaseProps, type SocialPreviewsBaseProps, TYPE_ARTICLE, TYPE_WEBSITE, ThreadsLinkPreview, ThreadsPostPreview, ThreadsPreviews, TumblrLinkPreview, TumblrPostPreview, TumblrPreviews, type TumblrPreviewsProps, TwitterLinkPreview, TwitterPostPreview, TwitterPreviews, parseHyperlinks };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,28 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
 
3
+ /**
4
+ * An editor hyperlink: the visible anchor text and the URL it points to.
5
+ */
6
+ type Hyperlink = {
7
+ text: string;
8
+ href: string;
9
+ /**
10
+ * Zero-based index of this anchor among identical occurrences of `text` in
11
+ * the content, so repeated texts link the right duplicate. Defaults to 0.
12
+ */
13
+ occurrence?: number;
14
+ };
15
+ /**
16
+ * Extracts `(text, href)` pairs from `<a href="…">text</a>` in HTML, skipping
17
+ * autolinks (text already equals the URL) and non-http(s) hrefs. Mirrors the
18
+ * backend `ExtractorUtils::get_anchor_links_from_html` so the preview links the
19
+ * same anchors the published share will.
20
+ *
21
+ * @param html - Raw post content HTML.
22
+ * @return The editor hyperlinks found, in document order.
23
+ */
24
+ declare function parseHyperlinks(html: string): Hyperlink[];
25
+
3
26
  declare const HEADING_LEVELS: readonly [2, 3, 4, 5, 6];
4
27
  type SectionHeadingProps = {
5
28
  className?: string;
@@ -12,6 +35,11 @@ interface SocialPreviewBaseProps {
12
35
  * The URL of the post/page to preview.
13
36
  */
14
37
  url: string;
38
+ /**
39
+ * Editor hyperlinks rendered over the matching body text on the networks
40
+ * that support inline links (Bluesky, Tumblr). Other networks ignore this.
41
+ */
42
+ hyperlinks?: Hyperlink[];
15
43
  /**
16
44
  * The title of the post/page to preview.
17
45
  */
@@ -275,4 +303,4 @@ declare function InstagramPostPreview({ image, media, name, profileImage, captio
275
303
 
276
304
  declare const InstagramPreviews: React.FC<InstagramPreviewsProps>;
277
305
 
278
- export { AUTO_SHARED_LINK_PREVIEW, AUTO_SHARED_SOCIAL_POST_PREVIEW, BlueskyLinkPreview, BlueskyPostPreview, BlueskyPreviews, type BlueskyPreviewsProps, DEFAULT_LINK_PREVIEW, FacebookLinkPreview, type FacebookLinkPreviewProps, FacebookPostPreview, FacebookPreviews, type FacebookPreviewsProps, GoogleSearchPreview, type GoogleSearchPreviewProps, InstagramPostPreview, InstagramPreviews, LANDSCAPE_MODE, LinkedInLinkPreview, type LinkedInLinkPreviewProps, LinkedInPostPreview, LinkedInPreviews, MastodonLinkPreview, MastodonPostPreview, MastodonPreviews, type MastodonPreviewsProps, type MediaItem, NextdoorLinkPreview, type NextdoorLinkPreviewProps, NextdoorPostPreview, NextdoorPreviews, PORTRAIT_MODE, type SocialPreviewBaseProps, type SocialPreviewsBaseProps, TYPE_ARTICLE, TYPE_WEBSITE, ThreadsLinkPreview, ThreadsPostPreview, ThreadsPreviews, TumblrLinkPreview, TumblrPostPreview, TumblrPreviews, type TumblrPreviewsProps, TwitterLinkPreview, TwitterPostPreview, TwitterPreviews };
306
+ export { AUTO_SHARED_LINK_PREVIEW, AUTO_SHARED_SOCIAL_POST_PREVIEW, BlueskyLinkPreview, BlueskyPostPreview, BlueskyPreviews, type BlueskyPreviewsProps, DEFAULT_LINK_PREVIEW, FacebookLinkPreview, type FacebookLinkPreviewProps, FacebookPostPreview, FacebookPreviews, type FacebookPreviewsProps, GoogleSearchPreview, type GoogleSearchPreviewProps, type Hyperlink, InstagramPostPreview, InstagramPreviews, LANDSCAPE_MODE, LinkedInLinkPreview, type LinkedInLinkPreviewProps, LinkedInPostPreview, LinkedInPreviews, MastodonLinkPreview, MastodonPostPreview, MastodonPreviews, type MastodonPreviewsProps, type MediaItem, NextdoorLinkPreview, type NextdoorLinkPreviewProps, NextdoorPostPreview, NextdoorPreviews, PORTRAIT_MODE, type SocialPreviewBaseProps, type SocialPreviewsBaseProps, TYPE_ARTICLE, TYPE_WEBSITE, ThreadsLinkPreview, ThreadsPostPreview, ThreadsPreviews, TumblrLinkPreview, TumblrPostPreview, TumblrPreviews, type TumblrPreviewsProps, TwitterLinkPreview, TwitterPostPreview, TwitterPreviews, parseHyperlinks };
package/dist/index.js 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 = _nullishCoalesce(anchor.getAttribute("href"), () => ( ""));
78
+ const text = collapseWhitespace(_nullishCoalesce(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 (_optionalChain([hyperlinks, 'optionalAccess', _4 => _4.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__ */ _jsxruntime.jsx.call(void 0, "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__ */ _jsxruntime.jsx.call(void 0, "br", {});
103
166
  return _element.createInterpolateElement.call(void 0, result, componentMap);
@@ -387,7 +450,7 @@ var TwitterPostPreview = ({
387
450
  cardType,
388
451
  url
389
452
  }) => {
390
- const hasMedia = !!_optionalChain([media, 'optionalAccess', _4 => _4.length]);
453
+ const hasMedia = !!_optionalChain([media, 'optionalAccess', _5 => _5.length]);
391
454
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "twitter-preview__wrapper", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "twitter-preview__container", children: [
392
455
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Sidebar, { profileImage, showThreadConnector }),
393
456
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "twitter-preview__main", children: [
@@ -449,7 +512,7 @@ var TwitterPreviews = ({
449
512
  hidePostPreview,
450
513
  tweets
451
514
  }) => {
452
- if (!_optionalChain([tweets, 'optionalAccess', _5 => _5.length])) {
515
+ if (!_optionalChain([tweets, 'optionalAccess', _6 => _6.length])) {
453
516
  return null;
454
517
  }
455
518
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "social-preview twitter-preview", children: [
@@ -547,7 +610,7 @@ function LinkedInPostPreview({
547
610
  title,
548
611
  url
549
612
  }) {
550
- const hasMedia = !!_optionalChain([media, 'optionalAccess', _6 => _6.length]);
613
+ const hasMedia = !!_optionalChain([media, 'optionalAccess', _7 => _7.length]);
551
614
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "linkedin-preview__wrapper", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { className: `linkedin-preview__container ${hasMedia ? "has-media" : ""}`, children: [
552
615
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "linkedin-preview__header", children: [
553
616
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "linkedin-preview__header--avatar", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AvatarWithFallback, { src: profileImage }) }),
@@ -784,7 +847,7 @@ var actions_default = TumblrPostActions;
784
847
 
785
848
 
786
849
  var TumblrPostHeader = ({ user }) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tumblr-preview__post-header", children: [
787
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tumblr-preview__post-header-username", children: _optionalChain([user, 'optionalAccess', _7 => _7.displayName]) || // translators: username of a fictional Tumblr User
850
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tumblr-preview__post-header-username", children: _optionalChain([user, 'optionalAccess', _8 => _8.displayName]) || // translators: username of a fictional Tumblr User
788
851
  _i18n.__.call(void 0, "anonymous-user", "social-previews") }),
789
852
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, icons_default, { name: "ellipsis" })
790
853
  ] });
@@ -799,7 +862,7 @@ var TumblrLinkPreview = ({
799
862
  user,
800
863
  url
801
864
  }) => {
802
- const avatarUrl = _optionalChain([user, 'optionalAccess', _8 => _8.avatarUrl]);
865
+ const avatarUrl = _optionalChain([user, 'optionalAccess', _9 => _9.avatarUrl]);
803
866
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tumblr-preview__post", children: [
804
867
  avatarUrl && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { className: "tumblr-preview__avatar", src: avatarUrl, alt: "" }),
805
868
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tumblr-preview__card", children: [
@@ -836,10 +899,11 @@ var TumblrPostPreview = ({
836
899
  image,
837
900
  user,
838
901
  url,
839
- media
902
+ media,
903
+ hyperlinks
840
904
  }) => {
841
- const avatarUrl = _optionalChain([user, 'optionalAccess', _9 => _9.avatarUrl]);
842
- const mediaItem = _optionalChain([media, 'optionalAccess', _10 => _10[0]]);
905
+ const avatarUrl = _optionalChain([user, 'optionalAccess', _10 => _10.avatarUrl]);
906
+ const mediaItem = _optionalChain([media, 'optionalAccess', _11 => _11[0]]);
843
907
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tumblr-preview__post", children: [
844
908
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AvatarWithFallback, { className: "tumblr-preview__avatar", src: avatarUrl }),
845
909
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tumblr-preview__card", children: [
@@ -847,7 +911,8 @@ var TumblrPostPreview = ({
847
911
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tumblr-preview__body", children: [
848
912
  title ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tumblr-preview__title", children: tumblrTitle(title) }) : null,
849
913
  description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tumblr-preview__description", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExpandableText, { text: description, children: (visibleText) => preparePreviewText(tumblrDescription(visibleText), {
850
- platform: "tumblr"
914
+ platform: "tumblr",
915
+ hyperlinks
851
916
  }) }) }),
852
917
  mediaItem ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tumblr-preview__media-item", children: mediaItem.type.startsWith("video/") ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { controls: true, className: "tumblr-preview__media--video", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "source", { src: mediaItem.url, type: mediaItem.type }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { className: "tumblr-preview__image", src: mediaItem.url, alt: "" }) }) : image && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
853
918
  "img",
@@ -873,7 +938,7 @@ var TumblrPreviews = ({
873
938
  hidePostPreview,
874
939
  ...props
875
940
  }) => {
876
- const hasMedia = !!_optionalChain([props, 'access', _11 => _11.media, 'optionalAccess', _12 => _12.length]);
941
+ const hasMedia = !!_optionalChain([props, 'access', _12 => _12.media, 'optionalAccess', _13 => _13.length]);
877
942
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "social-preview tumblr-preview", children: [
878
943
  !hidePostPreview && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { className: "social-preview__section tumblr-preview__section", children: [
879
944
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, SectionHeading, {
@@ -1025,11 +1090,11 @@ var FacebookPostHeader = ({ user, timeElapsed, hideOptions }) => {
1025
1090
  AvatarWithFallback,
1026
1091
  {
1027
1092
  className: "facebook-preview__post-header-avatar",
1028
- src: _optionalChain([user, 'optionalAccess', _13 => _13.avatarUrl])
1093
+ src: _optionalChain([user, 'optionalAccess', _14 => _14.avatarUrl])
1029
1094
  }
1030
1095
  ),
1031
1096
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1032
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "facebook-preview__post-header-name", children: _optionalChain([user, 'optionalAccess', _14 => _14.displayName]) || // translators: name of a fictional Facebook User
1097
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "facebook-preview__post-header-name", children: _optionalChain([user, 'optionalAccess', _15 => _15.displayName]) || // translators: name of a fictional Facebook User
1033
1098
  _i18n.__.call(void 0, "Anonymous User", "social-previews") }),
1034
1099
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "facebook-preview__post-header-share", children: [
1035
1100
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "facebook-preview__post-header-time", children: timeElapsed ? _i18n.__.call(void 0,
@@ -1173,7 +1238,7 @@ var FacebookPreviews = ({
1173
1238
  hidePostPreview,
1174
1239
  ...props
1175
1240
  }) => {
1176
- const hasMedia = !!_optionalChain([props, 'access', _15 => _15.media, 'optionalAccess', _16 => _16.length]);
1241
+ const hasMedia = !!_optionalChain([props, 'access', _16 => _16.media, 'optionalAccess', _17 => _17.length]);
1177
1242
  const hasCustomImage = !!props.customImage;
1178
1243
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "social-preview facebook-preview", children: [
1179
1244
  !hidePostPreview && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { className: "social-preview__section facebook-preview__section", children: [
@@ -1275,8 +1340,6 @@ var DEFAULT_MASTODON_INSTANCE = "mastodon.social";
1275
1340
  // src/mastodon-preview/helpers.ts
1276
1341
  var TITLE_LENGTH4 = 200;
1277
1342
  var BODY_LENGTH = 500;
1278
- var URL_LENGTH2 = 30;
1279
- var BODY_CHAR_LIMIT = BODY_LENGTH - URL_LENGTH2;
1280
1343
  var ADDRESS_PATTERN = /^@([^@]*)@([^@]*)$/i;
1281
1344
  var mastodonTitle = (text) => firstValid(
1282
1345
  shortEnough(TITLE_LENGTH4),
@@ -1286,16 +1349,15 @@ var mastodonBody = (text, options) => {
1286
1349
  const { instance, offset } = options;
1287
1350
  return preparePreviewText(text, {
1288
1351
  platform: "mastodon",
1289
- maxChars: BODY_LENGTH - URL_LENGTH2 - offset,
1352
+ maxChars: BODY_LENGTH - offset,
1290
1353
  hashtagDomain: instance
1291
1354
  });
1292
1355
  };
1293
- var mastodonUrl = (text) => firstValid(shortEnough(URL_LENGTH2), hardTruncation(URL_LENGTH2))(stripHtmlTags(text)) || "";
1294
1356
  var getMastodonAddressDetails = (address) => {
1295
1357
  const matches = address.match(ADDRESS_PATTERN);
1296
1358
  return {
1297
- username: _optionalChain([matches, 'optionalAccess', _17 => _17[1]]) || "",
1298
- instance: _optionalChain([matches, 'optionalAccess', _18 => _18[2]]) || DEFAULT_MASTODON_INSTANCE
1359
+ username: _optionalChain([matches, 'optionalAccess', _18 => _18[1]]) || "",
1360
+ instance: _optionalChain([matches, 'optionalAccess', _19 => _19[2]]) || DEFAULT_MASTODON_INSTANCE
1299
1361
  };
1300
1362
  };
1301
1363
 
@@ -1365,7 +1427,7 @@ var MastodonPostHeader = ({ user }) => {
1365
1427
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1366
1428
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mastodon-preview__post-header-displayname", children: displayName || // translators: username of a fictional Mastodon User
1367
1429
  _i18n.__.call(void 0, "anonymous-user", "social-previews") }),
1368
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mastodon-preview__post-header-username", children: _optionalChain([address, 'optionalAccess', _19 => _19.replace, 'call', _20 => _20(`@${DEFAULT_MASTODON_INSTANCE}`, "")]) || "@username" })
1430
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mastodon-preview__post-header-username", children: _optionalChain([address, 'optionalAccess', _20 => _20.replace, 'call', _21 => _21(`@${DEFAULT_MASTODON_INSTANCE}`, "")]) || "@username" })
1369
1431
  ] })
1370
1432
  ] }),
1371
1433
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mastodon-preview__post-header-audience", children: [
@@ -1393,8 +1455,8 @@ var MastodonLinkPreview = (props) => {
1393
1455
  // src/mastodon-preview/post/body/index.tsx
1394
1456
 
1395
1457
  var MastonPostBody = (props) => {
1396
- const { title, description, customText, url, user, children } = props;
1397
- const instance = _optionalChain([user, 'optionalAccess', _21 => _21.address]) ? getMastodonAddressDetails(user.address).instance : "";
1458
+ const { title, description, customText, user, children } = props;
1459
+ const instance = _optionalChain([user, 'optionalAccess', _22 => _22.address]) ? getMastodonAddressDetails(user.address).instance : "";
1398
1460
  const options = {
1399
1461
  instance,
1400
1462
  offset: 0
@@ -1418,7 +1480,6 @@ var MastonPostBody = (props) => {
1418
1480
  }
1419
1481
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mastodon-preview__body", children: [
1420
1482
  bodyTxt,
1421
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { href: url, target: "_blank", rel: "noreferrer noopener", children: mastodonUrl(url.replace(/^https?:\/\//, "")) }),
1422
1483
  children
1423
1484
  ] });
1424
1485
  };
@@ -1430,7 +1491,7 @@ var MastodonPostPreview = (props) => {
1430
1491
  const { user, media } = props;
1431
1492
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mastodon-preview__post", children: [
1432
1493
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, header_default3, { user }),
1433
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, body_default, { ...props, children: _optionalChain([media, 'optionalAccess', _22 => _22.length]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _clsx2.default.call(void 0, "mastodon-preview__media", { "as-grid": media.length > 1 }), children: media.map((mediaItem, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1494
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, body_default, { ...props, children: _optionalChain([media, 'optionalAccess', _23 => _23.length]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _clsx2.default.call(void 0, "mastodon-preview__media", { "as-grid": media.length > 1 }), children: media.map((mediaItem, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1434
1495
  "div",
1435
1496
  {
1436
1497
  className: "mastodon-preview__media-item",
@@ -1438,7 +1499,7 @@ var MastodonPostPreview = (props) => {
1438
1499
  },
1439
1500
  `mastodon-preview__media-item-${index}`
1440
1501
  )) }) : null }),
1441
- !_optionalChain([media, 'optionalAccess', _23 => _23.length]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, card_default, { ...props }) : null,
1502
+ !_optionalChain([media, 'optionalAccess', _24 => _24.length]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, card_default, { ...props }) : null,
1442
1503
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, actions_default3, {})
1443
1504
  ] });
1444
1505
  };
@@ -1619,7 +1680,7 @@ function NextdoorPostPreview({
1619
1680
  title,
1620
1681
  url
1621
1682
  }) {
1622
- const hasMedia = !!_optionalChain([media, 'optionalAccess', _24 => _24.length]);
1683
+ const hasMedia = !!_optionalChain([media, 'optionalAccess', _25 => _25.length]);
1623
1684
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "nextdoor-preview__wrapper", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "section", { className: `nextdoor-preview__container ${hasMedia ? "has-media" : ""}`, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "nextdoor-preview__content", children: [
1624
1685
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "nextdoor-preview__header", children: [
1625
1686
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "nextdoor-preview__header--avatar", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AvatarWithFallback, { src: profileImage }) }),
@@ -1651,7 +1712,7 @@ function NextdoorPostPreview({
1651
1712
  "div",
1652
1713
  {
1653
1714
  className: "nextdoor-preview__media-item",
1654
- children: _optionalChain([mediaItem, 'optionalAccess', _25 => _25.type, 'optionalAccess', _26 => _26.startsWith, 'call', _27 => _27("video/")]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { controls: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "source", { src: mediaItem.url, type: mediaItem.type }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { alt: mediaItem.alt || "", src: mediaItem.url })
1715
+ children: _optionalChain([mediaItem, 'optionalAccess', _26 => _26.type, 'optionalAccess', _27 => _27.startsWith, 'call', _28 => _28("video/")]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "video", { controls: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "source", { src: mediaItem.url, type: mediaItem.type }) }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "img", { alt: mediaItem.alt || "", src: mediaItem.url })
1655
1716
  },
1656
1717
  `nextdoor-preview__media-item-${index}`
1657
1718
  );
@@ -1817,28 +1878,35 @@ var actions_default4 = BlueskyPostActions;
1817
1878
  // src/bluesky-preview/helpers.ts
1818
1879
  var TITLE_LENGTH5 = 200;
1819
1880
  var BODY_LENGTH2 = 300;
1820
- var URL_LENGTH3 = 40;
1821
- var BODY_CHAR_LIMIT2 = BODY_LENGTH2 - URL_LENGTH3;
1881
+ var URL_LENGTH2 = 40;
1882
+ var BODY_CHAR_LIMIT = BODY_LENGTH2 - URL_LENGTH2;
1822
1883
  var blueskyTitle = (text) => firstValid(
1823
1884
  shortEnough(TITLE_LENGTH5),
1824
1885
  hardTruncation(TITLE_LENGTH5)
1825
1886
  )(stripHtmlTags(text)) || "";
1826
1887
  var blueskyBody = (text, options = {}) => {
1827
- const { offset = 0, reserveUrlSpace = true } = options;
1888
+ const { offset = 0, reserveUrlSpace = true, hyperlinks } = options;
1828
1889
  return preparePreviewText(text, {
1829
1890
  platform: "bluesky",
1830
- maxChars: BODY_LENGTH2 - (reserveUrlSpace ? URL_LENGTH3 : 0) - offset
1891
+ maxChars: BODY_LENGTH2 - (reserveUrlSpace ? URL_LENGTH2 : 0) - offset,
1892
+ hyperlinks
1831
1893
  });
1832
1894
  };
1833
- var blueskyUrl = (text) => firstValid(shortEnough(URL_LENGTH3), hardTruncation(URL_LENGTH3))(stripHtmlTags(text)) || "";
1895
+ var blueskyUrl = (text) => firstValid(shortEnough(URL_LENGTH2), hardTruncation(URL_LENGTH2))(stripHtmlTags(text)) || "";
1834
1896
 
1835
1897
  // src/bluesky-preview/post/body/index.tsx
1836
1898
 
1837
- var BlueskyPostBody = ({ customText, url, children, appendUrl }) => {
1838
- const showUrl = appendUrl && !!url && !_optionalChain([customText, 'optionalAccess', _28 => _28.includes, 'call', _29 => _29(url)]);
1899
+ var BlueskyPostBody = ({
1900
+ customText,
1901
+ url,
1902
+ children,
1903
+ appendUrl,
1904
+ hyperlinks
1905
+ }) => {
1906
+ const showUrl = appendUrl && !!url && !_optionalChain([customText, 'optionalAccess', _29 => _29.includes, 'call', _30 => _30(url)]);
1839
1907
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "bluesky-preview__body", children: [
1840
1908
  customText ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1841
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: blueskyBody(customText, { reserveUrlSpace: showUrl }) }),
1909
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: blueskyBody(customText, { reserveUrlSpace: showUrl, hyperlinks }) }),
1842
1910
  showUrl ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1843
1911
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "br", {}),
1844
1912
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { href: url, target: "_blank", rel: "noreferrer noopener", children: blueskyUrl(url.replace(/^https?:\/\//, "")) })
@@ -1902,7 +1970,7 @@ var BlueskyPostPreview = (props) => {
1902
1970
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlueskyPostSidebar, { user }),
1903
1971
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1904
1972
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, header_default4, { user }),
1905
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, body_default2, { ...props, appendUrl: _nullishCoalesce(appendUrl, () => ( Boolean(_optionalChain([media, 'optionalAccess', _30 => _30.length])))), children: _optionalChain([media, 'optionalAccess', _31 => _31.length]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _clsx2.default.call(void 0, "bluesky-preview__media", { "as-grid": media.length > 1 }), children: media.map((mediaItem, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1973
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, body_default2, { ...props, appendUrl: _nullishCoalesce(appendUrl, () => ( Boolean(_optionalChain([media, 'optionalAccess', _31 => _31.length])))), children: _optionalChain([media, 'optionalAccess', _32 => _32.length]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _clsx2.default.call(void 0, "bluesky-preview__media", { "as-grid": media.length > 1 }), children: media.map((mediaItem, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1906
1974
  "div",
1907
1975
  {
1908
1976
  className: "bluesky-preview__media-item",
@@ -1910,7 +1978,7 @@ var BlueskyPostPreview = (props) => {
1910
1978
  },
1911
1979
  `bluesky-preview__media-item-${index}`
1912
1980
  )) }) : null }),
1913
- !_optionalChain([media, 'optionalAccess', _32 => _32.length]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, card_default2, { ...props }) : null,
1981
+ !_optionalChain([media, 'optionalAccess', _33 => _33.length]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, card_default2, { ...props }) : null,
1914
1982
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, actions_default4, {})
1915
1983
  ] })
1916
1984
  ] });
@@ -2099,7 +2167,7 @@ var ThreadsPostPreview = ({
2099
2167
  title,
2100
2168
  url
2101
2169
  }) => {
2102
- const hasMedia = !!_optionalChain([media, 'optionalAccess', _33 => _33.length]);
2170
+ const hasMedia = !!_optionalChain([media, 'optionalAccess', _34 => _34.length]);
2103
2171
  const displayAsCard = url && image && !hasMedia;
2104
2172
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "threads-preview__wrapper", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "threads-preview__container", children: [
2105
2173
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Sidebar2, { profileImage, showThreadConnector }),
@@ -2146,7 +2214,7 @@ var ThreadsPreviews = ({
2146
2214
  hidePostPreview,
2147
2215
  posts
2148
2216
  }) => {
2149
- if (!_optionalChain([posts, 'optionalAccess', _34 => _34.length])) {
2217
+ if (!_optionalChain([posts, 'optionalAccess', _35 => _35.length])) {
2150
2218
  return null;
2151
2219
  }
2152
2220
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "social-preview threads-preview", children: [
@@ -2351,7 +2419,7 @@ function InstagramPostPreview({
2351
2419
  url
2352
2420
  }) {
2353
2421
  const username = name || "username";
2354
- const mediaItem = _optionalChain([media, 'optionalAccess', _35 => _35[0]]);
2422
+ const mediaItem = _optionalChain([media, 'optionalAccess', _36 => _36[0]]);
2355
2423
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "instagram-preview__wrapper", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "section", { className: "instagram-preview__container", children: [
2356
2424
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "instagram-preview__header", children: [
2357
2425
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "instagram-preview__header--avatar", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AvatarWithFallback, { src: profileImage }) }),
@@ -2446,5 +2514,6 @@ var InstagramPreviews = ({
2446
2514
 
2447
2515
 
2448
2516
 
2449
- exports.AUTO_SHARED_LINK_PREVIEW = AUTO_SHARED_LINK_PREVIEW; exports.AUTO_SHARED_SOCIAL_POST_PREVIEW = AUTO_SHARED_SOCIAL_POST_PREVIEW; exports.BlueskyLinkPreview = BlueskyLinkPreview; exports.BlueskyPostPreview = BlueskyPostPreview; exports.BlueskyPreviews = BlueskyPreviews; exports.DEFAULT_LINK_PREVIEW = DEFAULT_LINK_PREVIEW; exports.FacebookLinkPreview = FacebookLinkPreview; exports.FacebookPostPreview = FacebookPostPreview; exports.FacebookPreviews = FacebookPreviews; exports.GoogleSearchPreview = GoogleSearchPreview; exports.InstagramPostPreview = InstagramPostPreview; exports.InstagramPreviews = InstagramPreviews; exports.LANDSCAPE_MODE = LANDSCAPE_MODE; exports.LinkedInLinkPreview = LinkedInLinkPreview; exports.LinkedInPostPreview = LinkedInPostPreview; exports.LinkedInPreviews = LinkedInPreviews; exports.MastodonLinkPreview = MastodonLinkPreview; exports.MastodonPostPreview = MastodonPostPreview; exports.MastodonPreviews = MastodonPreviews; exports.NextdoorLinkPreview = NextdoorLinkPreview; exports.NextdoorPostPreview = NextdoorPostPreview; exports.NextdoorPreviews = NextdoorPreviews; exports.PORTRAIT_MODE = PORTRAIT_MODE; exports.TYPE_ARTICLE = TYPE_ARTICLE; exports.TYPE_WEBSITE = TYPE_WEBSITE; exports.ThreadsLinkPreview = ThreadsLinkPreview; exports.ThreadsPostPreview = ThreadsPostPreview; exports.ThreadsPreviews = ThreadsPreviews; exports.TumblrLinkPreview = TumblrLinkPreview; exports.TumblrPostPreview = TumblrPostPreview; exports.TumblrPreviews = TumblrPreviews; exports.TwitterLinkPreview = TwitterLinkPreview; exports.TwitterPostPreview = TwitterPostPreview; exports.TwitterPreviews = TwitterPreviews;
2517
+
2518
+ exports.AUTO_SHARED_LINK_PREVIEW = AUTO_SHARED_LINK_PREVIEW; exports.AUTO_SHARED_SOCIAL_POST_PREVIEW = AUTO_SHARED_SOCIAL_POST_PREVIEW; exports.BlueskyLinkPreview = BlueskyLinkPreview; exports.BlueskyPostPreview = BlueskyPostPreview; exports.BlueskyPreviews = BlueskyPreviews; exports.DEFAULT_LINK_PREVIEW = DEFAULT_LINK_PREVIEW; exports.FacebookLinkPreview = FacebookLinkPreview; exports.FacebookPostPreview = FacebookPostPreview; exports.FacebookPreviews = FacebookPreviews; exports.GoogleSearchPreview = GoogleSearchPreview; exports.InstagramPostPreview = InstagramPostPreview; exports.InstagramPreviews = InstagramPreviews; exports.LANDSCAPE_MODE = LANDSCAPE_MODE; exports.LinkedInLinkPreview = LinkedInLinkPreview; exports.LinkedInPostPreview = LinkedInPostPreview; exports.LinkedInPreviews = LinkedInPreviews; exports.MastodonLinkPreview = MastodonLinkPreview; exports.MastodonPostPreview = MastodonPostPreview; exports.MastodonPreviews = MastodonPreviews; exports.NextdoorLinkPreview = NextdoorLinkPreview; exports.NextdoorPostPreview = NextdoorPostPreview; exports.NextdoorPreviews = NextdoorPreviews; exports.PORTRAIT_MODE = PORTRAIT_MODE; exports.TYPE_ARTICLE = TYPE_ARTICLE; exports.TYPE_WEBSITE = TYPE_WEBSITE; exports.ThreadsLinkPreview = ThreadsLinkPreview; exports.ThreadsPostPreview = ThreadsPostPreview; exports.ThreadsPreviews = ThreadsPreviews; exports.TumblrLinkPreview = TumblrLinkPreview; exports.TumblrPostPreview = TumblrPostPreview; exports.TumblrPreviews = TumblrPreviews; exports.TwitterLinkPreview = TwitterLinkPreview; exports.TwitterPostPreview = TwitterPostPreview; exports.TwitterPreviews = TwitterPreviews; exports.parseHyperlinks = parseHyperlinks;
2450
2519
  //# sourceMappingURL=index.js.map