@automattic/social-previews 3.1.3 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7,13 +7,15 @@ var baseDomain = (url) => {
7
7
  const slashIndex = withoutProtocol.indexOf("/");
8
8
  return slashIndex === -1 ? withoutProtocol : withoutProtocol.substring(0, slashIndex);
9
9
  };
10
- var shortEnough = (limit) => (title) => title.length <= limit ? title : false;
10
+ var codepointLength = (text) => Array.from(text).length;
11
+ var codepointSlice = (text, start, end) => Array.from(text).slice(start, end).join("");
12
+ var shortEnough = (limit) => (title) => codepointLength(title) <= limit ? title : false;
11
13
  var truncatedAtSpace = (lower, upper) => (fullTitle) => {
12
14
  const title = fullTitle.slice(0, upper);
13
15
  const lastSpace = title.lastIndexOf(" ");
14
16
  return lastSpace > lower && lastSpace < upper ? title.slice(0, lastSpace).concat("\u2026") : false;
15
17
  };
16
- var hardTruncation = (limit) => (title) => title.slice(0, limit).concat("\u2026");
18
+ var hardTruncation = (limit) => (title) => codepointSlice(title, 0, limit).concat("\u2026");
17
19
  var firstValid = (...predicates) => (a) => _optionalChain([predicates, 'access', _ => _.find, 'call', _2 => _2((p) => false !== p(a)), 'optionalCall', _3 => _3(a)]);
18
20
  var stripHtmlTags = (description, allowedTags = []) => {
19
21
  const pattern = new RegExp(`(<([^${allowedTags.join("")}>]+)>)`, "gi");
@@ -70,7 +72,7 @@ function preparePreviewText(text, options) {
70
72
  } = options;
71
73
  let result = stripHtmlTags(text);
72
74
  result = result.replaceAll(/(?:\s*[\n\r]){2,}/g, "\n\n");
73
- if (maxChars && result.length > maxChars) {
75
+ if (maxChars && codepointLength(result) > maxChars) {
74
76
  result = hardTruncation(maxChars)(result);
75
77
  }
76
78
  if (maxLines) {
@@ -212,7 +214,7 @@ var GoogleSearchPreview = ({
212
214
  // src/twitter-preview/card.tsx
213
215
  var _clsx = require('clsx'); var _clsx2 = _interopRequireDefault(_clsx);
214
216
 
215
- var DESCRIPTION_LENGTH2 = 200;
217
+ var DESCRIPTION_LENGTH2 = 280;
216
218
  var twitterDescription = firstValid(
217
219
  shortEnough(DESCRIPTION_LENGTH2),
218
220
  hardTruncation(DESCRIPTION_LENGTH2)
@@ -361,12 +363,11 @@ var Sidebar = ({ profileImage, showThreadConnector }) => {
361
363
 
362
364
  // src/twitter-preview/text.tsx
363
365
 
364
- var Text = ({ text, url, retainUrl }) => {
366
+ var Text = ({ text }) => {
365
367
  if (!text) {
366
368
  return null;
367
369
  }
368
- const tweetText = url && !retainUrl && text.endsWith(url) ? text.substring(0, text.lastIndexOf(url)) : text;
369
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "twitter-preview__text", children: preparePreviewText(tweetText, { platform: "twitter" }) });
370
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "twitter-preview__text", children: preparePreviewText(text, { platform: "twitter" }) });
370
371
  };
371
372
 
372
373
  // src/twitter-preview/post-preview.tsx
@@ -392,7 +393,7 @@ var TwitterPostPreview = ({
392
393
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "twitter-preview__main", children: [
393
394
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Header, { name, screenName, date }),
394
395
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "twitter-preview__content", children: [
395
- text ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Text, { text, url: url || "", retainUrl: hasMedia }) : null,
396
+ text ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Text, { text }) : null,
396
397
  hasMedia ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Media, { media }) : null,
397
398
  tweetUrl ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, QuoteTweet, { tweetUrl }) : null,
398
399
  !hasMedia && url && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
@@ -489,8 +490,49 @@ var TwitterPreviews = ({
489
490
  // src/linkedin-preview/post-preview.tsx
490
491
 
491
492
 
493
+ // src/shared/expandable-text/index.tsx
494
+
495
+
496
+
497
+
498
+ var EXPAND_THRESHOLD_CHARS = 400;
499
+ function codepointLength2(text) {
500
+ return Array.from(text).length;
501
+ }
502
+ function truncateAtWordBoundary(text, limit) {
503
+ const codepoints = Array.from(text);
504
+ if (codepoints.length <= limit) {
505
+ return text;
506
+ }
507
+ const slice = codepoints.slice(0, limit).join("");
508
+ const lastSpace = slice.lastIndexOf(" ");
509
+ const cut = lastSpace > limit - 80 ? lastSpace : slice.length;
510
+ return slice.slice(0, cut);
511
+ }
512
+ function ExpandableText(props) {
513
+ const { text, children } = props;
514
+ const [expanded, toggle] = _react.useReducer.call(void 0, (state) => !state, false);
515
+ const stripped = stripHtmlTags(text);
516
+ if (codepointLength2(stripped) <= EXPAND_THRESHOLD_CHARS) {
517
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: children(text) });
518
+ }
519
+ if (expanded) {
520
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
521
+ children(text),
522
+ " ",
523
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _components.Button, { variant: "link", className: "social-previews__expand-toggle", onClick: toggle, children: _i18n.__.call(void 0, "See less", "social-previews") })
524
+ ] });
525
+ }
526
+ const truncated = truncateAtWordBoundary(stripped, EXPAND_THRESHOLD_CHARS);
527
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
528
+ children(truncated),
529
+ "\u2026 ",
530
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _components.Button, { variant: "link", className: "social-previews__expand-toggle", onClick: toggle, children: _i18n.__.call(void 0, "See more", "social-previews") })
531
+ ] });
532
+ }
533
+
492
534
  // src/linkedin-preview/constants.ts
493
- var FEED_TEXT_MAX_LENGTH = 550;
535
+ var FEED_TEXT_MAX_LENGTH = 3e3;
494
536
 
495
537
  // src/linkedin-preview/post-preview.tsx
496
538
 
@@ -532,11 +574,11 @@ function LinkedInPostPreview({
532
574
  ] }),
533
575
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "linkedin-preview__content", children: [
534
576
  description ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "linkedin-preview__caption", children: [
535
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: preparePreviewText(description, {
577
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExpandableText, { text: description, children: (visibleText) => preparePreviewText(visibleText, {
536
578
  platform: "linkedin",
537
579
  maxChars: FEED_TEXT_MAX_LENGTH
538
- }) }),
539
- hasMedia && url && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
580
+ }) }) }),
581
+ hasMedia && url && !description.includes(url) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
540
582
  " - ",
541
583
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { href: url, rel: "nofollow noopener noreferrer", target: "_blank", children: url })
542
584
  ] })
@@ -622,7 +664,7 @@ var LinkedInPreviews = ({
622
664
 
623
665
  // src/tumblr-preview/helpers.ts
624
666
  var TITLE_LENGTH2 = 1e3;
625
- var DESCRIPTION_LENGTH3 = 400;
667
+ var DESCRIPTION_LENGTH3 = 4096;
626
668
  var tumblrTitle = (text) => firstValid(
627
669
  shortEnough(TITLE_LENGTH2),
628
670
  hardTruncation(TITLE_LENGTH2)
@@ -804,9 +846,9 @@ var TumblrPostPreview = ({
804
846
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, header_default, { user }),
805
847
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "tumblr-preview__body", children: [
806
848
  title ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tumblr-preview__title", children: tumblrTitle(title) }) : null,
807
- description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "tumblr-preview__description", children: preparePreviewText(tumblrDescription(description), {
849
+ 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), {
808
850
  platform: "tumblr"
809
- }) }),
851
+ }) }) }),
810
852
  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,
811
853
  "img",
812
854
  {
@@ -875,7 +917,7 @@ var PORTRAIT_MODE = "portrait";
875
917
  // src/facebook-preview/helpers.ts
876
918
  var TITLE_LENGTH3 = 110;
877
919
  var DESCRIPTION_LENGTH4 = 200;
878
- var CUSTOM_TEXT_LENGTH = 440;
920
+ var CUSTOM_TEXT_LENGTH = 63206;
879
921
  var facebookTitle = (text) => firstValid(
880
922
  shortEnough(TITLE_LENGTH3),
881
923
  hardTruncation(TITLE_LENGTH3)
@@ -889,7 +931,8 @@ var facebookDescription = (text) => firstValid(
889
931
 
890
932
  var CustomText = ({ text, url, forceUrlDisplay }) => {
891
933
  let postLink;
892
- if (forceUrlDisplay || hasTag(text, "a")) {
934
+ const showPostLink = hasTag(text, "a") || forceUrlDisplay && !!url && !text.includes(url);
935
+ if (showPostLink) {
893
936
  postLink = /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
894
937
  "a",
895
938
  {
@@ -902,10 +945,10 @@ var CustomText = ({ text, url, forceUrlDisplay }) => {
902
945
  );
903
946
  }
904
947
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "facebook-preview__custom-text", children: [
905
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: preparePreviewText(text, {
948
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExpandableText, { text, children: (visibleText) => preparePreviewText(visibleText, {
906
949
  platform: "facebook",
907
950
  maxChars: CUSTOM_TEXT_LENGTH
908
- }) }),
951
+ }) }) }),
909
952
  postLink
910
953
  ] });
911
954
  };
@@ -1233,6 +1276,7 @@ var DEFAULT_MASTODON_INSTANCE = "mastodon.social";
1233
1276
  var TITLE_LENGTH4 = 200;
1234
1277
  var BODY_LENGTH = 500;
1235
1278
  var URL_LENGTH2 = 30;
1279
+ var BODY_CHAR_LIMIT = BODY_LENGTH - URL_LENGTH2;
1236
1280
  var ADDRESS_PATTERN = /^@([^@]*)@([^@]*)$/i;
1237
1281
  var mastodonTitle = (text) => firstValid(
1238
1282
  shortEnough(TITLE_LENGTH4),
@@ -1357,17 +1401,17 @@ var MastonPostBody = (props) => {
1357
1401
  };
1358
1402
  let bodyTxt;
1359
1403
  if (customText) {
1360
- bodyTxt = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: mastodonBody(customText, options) });
1404
+ bodyTxt = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExpandableText, { text: customText, children: (visibleText) => mastodonBody(visibleText, options) }) });
1361
1405
  } else if (description) {
1362
1406
  if (title) {
1363
1407
  const renderedTitle = stripHtmlTags(title);
1364
1408
  options.offset = renderedTitle.length;
1365
1409
  bodyTxt = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1366
1410
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: renderedTitle }),
1367
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: mastodonBody(description, options) })
1411
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExpandableText, { text: description, children: (visibleText) => mastodonBody(visibleText, options) }) })
1368
1412
  ] });
1369
1413
  } else {
1370
- bodyTxt = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: mastodonBody(description, options) });
1414
+ bodyTxt = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExpandableText, { text: description, children: (visibleText) => mastodonBody(visibleText, options) }) });
1371
1415
  }
1372
1416
  } else {
1373
1417
  bodyTxt = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { children: mastodonBody(title, options) });
@@ -1438,7 +1482,7 @@ var MastodonPreviews = ({
1438
1482
 
1439
1483
 
1440
1484
  // src/nextdoor-preview/constants.ts
1441
- var FEED_TEXT_MAX_LENGTH2 = 500;
1485
+ var FEED_TEXT_MAX_LENGTH2 = 65e3;
1442
1486
 
1443
1487
  // src/nextdoor-preview/footer-actions.tsx
1444
1488
 
@@ -1592,11 +1636,11 @@ function NextdoorPostPreview({
1592
1636
  ] }),
1593
1637
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "nextdoor-preview__body", children: [
1594
1638
  description ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "nextdoor-preview__caption", children: [
1595
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: preparePreviewText(description, {
1639
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExpandableText, { text: description, children: (visibleText) => preparePreviewText(visibleText, {
1596
1640
  platform: "nextdoor",
1597
1641
  maxChars: FEED_TEXT_MAX_LENGTH2
1598
- }) }),
1599
- !hasMedia && url && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1642
+ }) }) }),
1643
+ !hasMedia && url && !description.includes(url) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1600
1644
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "br", {}),
1601
1645
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "br", {}),
1602
1646
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { href: url, rel: "nofollow noopener noreferrer", target: "_blank", children: url })
@@ -1774,15 +1818,16 @@ var actions_default4 = BlueskyPostActions;
1774
1818
  var TITLE_LENGTH5 = 200;
1775
1819
  var BODY_LENGTH2 = 300;
1776
1820
  var URL_LENGTH3 = 40;
1821
+ var BODY_CHAR_LIMIT2 = BODY_LENGTH2 - URL_LENGTH3;
1777
1822
  var blueskyTitle = (text) => firstValid(
1778
1823
  shortEnough(TITLE_LENGTH5),
1779
1824
  hardTruncation(TITLE_LENGTH5)
1780
1825
  )(stripHtmlTags(text)) || "";
1781
1826
  var blueskyBody = (text, options = {}) => {
1782
- const { offset = 0 } = options;
1827
+ const { offset = 0, reserveUrlSpace = true } = options;
1783
1828
  return preparePreviewText(text, {
1784
1829
  platform: "bluesky",
1785
- maxChars: BODY_LENGTH2 - URL_LENGTH3 - offset
1830
+ maxChars: BODY_LENGTH2 - (reserveUrlSpace ? URL_LENGTH3 : 0) - offset
1786
1831
  });
1787
1832
  };
1788
1833
  var blueskyUrl = (text) => firstValid(shortEnough(URL_LENGTH3), hardTruncation(URL_LENGTH3))(stripHtmlTags(text)) || "";
@@ -1790,10 +1835,11 @@ var blueskyUrl = (text) => firstValid(shortEnough(URL_LENGTH3), hardTruncation(U
1790
1835
  // src/bluesky-preview/post/body/index.tsx
1791
1836
 
1792
1837
  var BlueskyPostBody = ({ customText, url, children, appendUrl }) => {
1838
+ const showUrl = appendUrl && !!url && !_optionalChain([customText, 'optionalAccess', _28 => _28.includes, 'call', _29 => _29(url)]);
1793
1839
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "bluesky-preview__body", children: [
1794
1840
  customText ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1795
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: blueskyBody(customText) }),
1796
- appendUrl && url ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1841
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: blueskyBody(customText, { reserveUrlSpace: showUrl }) }),
1842
+ showUrl ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
1797
1843
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "br", {}),
1798
1844
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "a", { href: url, target: "_blank", rel: "noreferrer noopener", children: blueskyUrl(url.replace(/^https?:\/\//, "")) })
1799
1845
  ] }) : null
@@ -1856,7 +1902,7 @@ var BlueskyPostPreview = (props) => {
1856
1902
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BlueskyPostSidebar, { user }),
1857
1903
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1858
1904
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, header_default4, { user }),
1859
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, body_default2, { ...props, appendUrl: _nullishCoalesce(appendUrl, () => ( Boolean(_optionalChain([media, 'optionalAccess', _28 => _28.length])))), children: _optionalChain([media, 'optionalAccess', _29 => _29.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,
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,
1860
1906
  "div",
1861
1907
  {
1862
1908
  className: "bluesky-preview__media-item",
@@ -1864,7 +1910,7 @@ var BlueskyPostPreview = (props) => {
1864
1910
  },
1865
1911
  `bluesky-preview__media-item-${index}`
1866
1912
  )) }) : null }),
1867
- !_optionalChain([media, 'optionalAccess', _30 => _30.length]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, card_default2, { ...props }) : null,
1913
+ !_optionalChain([media, 'optionalAccess', _32 => _32.length]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, card_default2, { ...props }) : null,
1868
1914
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, actions_default4, {})
1869
1915
  ] })
1870
1916
  ] });
@@ -2053,17 +2099,17 @@ var ThreadsPostPreview = ({
2053
2099
  title,
2054
2100
  url
2055
2101
  }) => {
2056
- const hasMedia = !!_optionalChain([media, 'optionalAccess', _31 => _31.length]);
2102
+ const hasMedia = !!_optionalChain([media, 'optionalAccess', _33 => _33.length]);
2057
2103
  const displayAsCard = url && image && !hasMedia;
2058
2104
  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: [
2059
2105
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Sidebar2, { profileImage, showThreadConnector }),
2060
2106
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "threads-preview__main", children: [
2061
2107
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Header2, { name, date }),
2062
2108
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "threads-preview__content", children: [
2063
- caption ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "threads-preview__text", children: preparePreviewText(caption, {
2109
+ caption ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "threads-preview__text", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExpandableText, { text: caption, children: (visibleText) => preparePreviewText(visibleText, {
2064
2110
  platform: "threads",
2065
2111
  maxChars: CAPTION_MAX_CHARS
2066
- }) }) : null,
2112
+ }) }) }) : null,
2067
2113
  hasMedia ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Media2, { media }) : null,
2068
2114
  displayAsCard ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Card2, { image, title: title || "", url }) : null
2069
2115
  ] }),
@@ -2100,7 +2146,7 @@ var ThreadsPreviews = ({
2100
2146
  hidePostPreview,
2101
2147
  posts
2102
2148
  }) => {
2103
- if (!_optionalChain([posts, 'optionalAccess', _32 => _32.length])) {
2149
+ if (!_optionalChain([posts, 'optionalAccess', _34 => _34.length])) {
2104
2150
  return null;
2105
2151
  }
2106
2152
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "social-preview threads-preview", children: [
@@ -2147,7 +2193,7 @@ var ThreadsPreviews = ({
2147
2193
 
2148
2194
 
2149
2195
  // src/instagram-preview/constants.tsx
2150
- var FEED_TEXT_MAX_LENGTH3 = 520;
2196
+ var FEED_TEXT_MAX_LENGTH3 = 2200;
2151
2197
 
2152
2198
  // src/instagram-preview/icons/bookmark.tsx
2153
2199
 
@@ -2305,7 +2351,7 @@ function InstagramPostPreview({
2305
2351
  url
2306
2352
  }) {
2307
2353
  const username = name || "username";
2308
- const mediaItem = _optionalChain([media, 'optionalAccess', _33 => _33[0]]);
2354
+ const mediaItem = _optionalChain([media, 'optionalAccess', _35 => _35[0]]);
2309
2355
  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: [
2310
2356
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "instagram-preview__header", children: [
2311
2357
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "instagram-preview__header--avatar", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AvatarWithFallback, { src: profileImage }) }),
@@ -2328,11 +2374,11 @@ function InstagramPostPreview({
2328
2374
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "instagram-preview__content--name", children: username }),
2329
2375
  "\xA0",
2330
2376
  caption ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "instagram-preview__content--text", children: [
2331
- preparePreviewText(caption, {
2377
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ExpandableText, { text: caption, children: (visibleText) => preparePreviewText(visibleText, {
2332
2378
  platform: "instagram",
2333
2379
  maxChars: FEED_TEXT_MAX_LENGTH3
2334
- }),
2335
- media && url && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2380
+ }) }),
2381
+ media && url && !caption.includes(url) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2336
2382
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "br", {}),
2337
2383
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "br", {}),
2338
2384
  url