@postrun/react 2.13.0 → 2.14.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.cjs CHANGED
@@ -929,96 +929,93 @@ function useTikTokCreatorInfo(connectionId) {
929
929
  );
930
930
  }
931
931
 
932
- // src/preview/from-upload.ts
933
- function previewKind(item) {
934
- const detected = item.media?.kind;
935
- if (detected) {
936
- return detected === "document" ? null : detected;
937
- }
938
- const mime = item.file.type;
939
- if (mime === "image/gif") {
940
- return "gif";
941
- }
942
- if (mime.startsWith("video/")) {
943
- return "video";
944
- }
945
- if (mime.startsWith("image/")) {
946
- return "image";
932
+ // src/preview/media-resolver.ts
933
+ function previewKind(kind) {
934
+ return kind === "image" || kind === "video" || kind === "gif" ? kind : null;
935
+ }
936
+ function resourceFor(ref, fallback) {
937
+ if ("media" in ref && ref.media) {
938
+ return ref.media;
947
939
  }
948
- return null;
940
+ return fallback?.find((asset) => asset.id === ref.media_id);
949
941
  }
950
- function toPreviewMedia(items) {
951
- return items.flatMap((item) => {
952
- const kind = previewKind(item);
942
+ function renditionFor(asset, target) {
943
+ return asset.per_platform[target];
944
+ }
945
+ function resolveVariantMedia(refs, target, fallback) {
946
+ return (refs ?? []).flatMap((ref) => {
947
+ const asset = resourceFor(ref, fallback);
948
+ if (!asset) {
949
+ return [];
950
+ }
951
+ const kind = previewKind(asset.kind);
953
952
  if (!kind) {
954
953
  return [];
955
954
  }
956
- return [
957
- {
958
- kind,
959
- file: item.file,
960
- width: item.media?.source?.width ?? void 0,
961
- height: item.media?.source?.height ?? void 0,
962
- alt: item.media?.alt_text ?? void 0
963
- }
964
- ];
965
- });
966
- }
967
- function fileKey(file) {
968
- return file ? `${file.name}:${file.size}:${file.lastModified}` : "";
969
- }
970
- function mediaSignature(media) {
971
- return (media ?? []).map((item) => {
972
- const source = item.url ?? fileKey(item.file);
973
- const size = `${item.width ?? ""}x${item.height ?? ""}`;
974
- return `${item.kind}|${source}|${item.posterUrl ?? ""}|${size}|${item.alt ?? ""}`;
975
- }).join("\xA7");
976
- }
977
- function altSignatureOf(media) {
978
- return (media ?? []).map((m) => m?.alt_text_override ?? "").join("\xA7");
979
- }
980
- function useResolvedMedia(media, altFallbacks, altSignature) {
981
- const signature = mediaSignature(media);
982
- const [objectUrls, setObjectUrls] = react.useState({});
983
- react.useEffect(() => {
984
- const created = [];
985
- const next = {};
986
- (media ?? []).forEach((item, index) => {
987
- if (!item.url && item.file) {
988
- const url = URL.createObjectURL(item.file);
989
- created.push(url);
990
- next[index] = url;
991
- }
992
- });
993
- setObjectUrls(next);
994
- return () => {
995
- for (const url of created) {
996
- URL.revokeObjectURL(url);
997
- }
998
- };
999
- }, [signature]);
1000
- return react.useMemo(
1001
- () => (media ?? []).flatMap((item, index) => {
1002
- const src = item.url ?? objectUrls[index];
1003
- if (!src) {
1004
- return [];
1005
- }
955
+ const alt = ref.alt_text_override ?? asset.alt_text ?? void 0;
956
+ const width = asset.source?.width ?? void 0;
957
+ const height = asset.source?.height ?? void 0;
958
+ const rendition = renditionFor(asset, target);
959
+ if (asset.status === "ready" && rendition?.status === "ready" && rendition.url) {
1006
960
  return [
1007
961
  {
1008
- kind: item.kind,
1009
- src,
1010
- width: item.width,
1011
- height: item.height,
1012
- alt: item.alt ?? altFallbacks?.[index]?.alt_text_override ?? void 0,
1013
- posterSrc: item.posterUrl
962
+ kind,
963
+ state: "ready",
964
+ src: rendition.url,
965
+ width: rendition.width ?? width,
966
+ height: rendition.height ?? height,
967
+ alt
1014
968
  }
1015
969
  ];
1016
- }),
1017
- // `signature` + `altSignature` capture the content; `objectUrls` flips once
1018
- // File blobs resolve. Referencing `media`/`altFallbacks` directly is safe.
1019
- // eslint-disable-next-line react-hooks/exhaustive-deps
1020
- [signature, altSignature, objectUrls]
1021
- );
970
+ }
971
+ return [{ kind, state: "processing", width, height, alt }];
972
+ });
973
+ }
974
+ function MediaPlaceholder({
975
+ label,
976
+ color,
977
+ background,
978
+ shimmer = false
979
+ }) {
980
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...fillStyle, background, color }, children: [
981
+ shimmer ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
982
+ /* @__PURE__ */ jsxRuntime.jsx("style", { children: SHIMMER_KEYFRAME }),
983
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: shimmerStyle })
984
+ ] }) : null,
985
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelStyle, children: label })
986
+ ] });
987
+ }
988
+ var SHIMMER_KEYFRAME = "@keyframes pr-media-shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}}";
989
+ var fillStyle = {
990
+ position: "absolute",
991
+ inset: 0,
992
+ display: "flex",
993
+ alignItems: "center",
994
+ justifyContent: "center",
995
+ overflow: "hidden"
996
+ };
997
+ var labelStyle = {
998
+ position: "relative",
999
+ zIndex: 1,
1000
+ fontSize: 13,
1001
+ letterSpacing: 0.1
1002
+ };
1003
+ var shimmerStyle = {
1004
+ position: "absolute",
1005
+ inset: 0,
1006
+ background: "linear-gradient(90deg, transparent 0%, color-mix(in srgb, currentColor 12%, transparent) 50%, transparent 100%)",
1007
+ backgroundSize: "200% 100%",
1008
+ animation: "pr-media-shimmer 1.4s ease-in-out infinite"
1009
+ };
1010
+
1011
+ // src/preview/types.ts
1012
+ function isReadyMedia(item) {
1013
+ return item.state === "ready";
1014
+ }
1015
+
1016
+ // src/preview/author.ts
1017
+ function authorName(connection) {
1018
+ return connection.external_account_name ?? connection.username ?? "";
1022
1019
  }
1023
1020
  function XPoll({ poll }) {
1024
1021
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: wrapStyle, children: [
@@ -1087,9 +1084,7 @@ function rawSrcLookup(...lists) {
1087
1084
  const map = /* @__PURE__ */ new Map();
1088
1085
  for (const list of lists) {
1089
1086
  for (const item of list) {
1090
- const poster = item.posterSrc ?? item.src;
1091
1087
  map.set(twitterMediaUrl(item.src), item.src);
1092
- map.set(twitterMediaUrl(poster), poster);
1093
1088
  }
1094
1089
  }
1095
1090
  return map;
@@ -1184,7 +1179,7 @@ function buildPhoto(media) {
1184
1179
  };
1185
1180
  }
1186
1181
  function buildVideo(media) {
1187
- const poster = media.posterSrc ?? media.src;
1182
+ const poster = media.src;
1188
1183
  const videoInfo = {
1189
1184
  aspect_ratio: [media.width ?? 16, media.height ?? 9],
1190
1185
  variants: [{ content_type: "video/mp4", url: media.src }]
@@ -1280,8 +1275,9 @@ function toTweet(input) {
1280
1275
  }
1281
1276
  function XPostPreviewImpl({
1282
1277
  variant,
1283
- author,
1278
+ connection,
1284
1279
  media,
1280
+ verified,
1285
1281
  quotedTweet,
1286
1282
  replyToHandle,
1287
1283
  theme = "auto",
@@ -1290,45 +1286,53 @@ function XPostPreviewImpl({
1290
1286
  style,
1291
1287
  components: componentsProp
1292
1288
  }) {
1293
- const resolvedMedia = useResolvedMedia(
1294
- media,
1295
- variant.media,
1296
- altSignatureOf(variant.media)
1289
+ const resolved = react.useMemo(
1290
+ () => resolveVariantMedia(variant.media, "x", media),
1291
+ [variant.media, media]
1292
+ );
1293
+ const readyMedia = react.useMemo(() => resolved.filter(isReadyMedia), [resolved]);
1294
+ const readyQuotedMedia = react.useMemo(
1295
+ () => (quotedTweet?.media ?? []).filter(isReadyMedia),
1296
+ [quotedTweet?.media]
1297
+ );
1298
+ const mediaPending = resolved.length > 0 && readyMedia.length === 0;
1299
+ const author = react.useMemo(
1300
+ () => ({
1301
+ name: authorName(connection),
1302
+ username: connection.username,
1303
+ avatar_url: connection.avatar_url,
1304
+ verified
1305
+ }),
1306
+ [connection, verified]
1297
1307
  );
1298
- const resolvedQuotedMedia = useResolvedMedia(quotedTweet?.media, void 0, "");
1299
1308
  const components = react.useMemo(
1300
1309
  () => ({
1301
- MediaImg: makeRawMediaImg(
1302
- rawSrcLookup(resolvedMedia, resolvedQuotedMedia)
1303
- ),
1310
+ MediaImg: makeRawMediaImg(rawSrcLookup(readyMedia, readyQuotedMedia)),
1304
1311
  ...componentsProp
1305
1312
  }),
1306
- [resolvedMedia, resolvedQuotedMedia, componentsProp]
1313
+ [readyMedia, readyQuotedMedia, componentsProp]
1307
1314
  );
1308
1315
  const tweet = react.useMemo(() => {
1309
1316
  const resolvedQuoted = quotedTweet ? {
1310
- author: quotedTweet.author,
1317
+ author: {
1318
+ name: quotedTweet.name,
1319
+ username: quotedTweet.username,
1320
+ avatar_url: quotedTweet.avatar_url
1321
+ },
1311
1322
  body: quotedTweet.body,
1312
- media: resolvedQuotedMedia
1323
+ media: readyQuotedMedia
1313
1324
  } : void 0;
1314
1325
  return reactTweet.enrichTweet(
1315
1326
  toTweet({
1316
1327
  variant,
1317
1328
  author,
1318
- media: resolvedMedia,
1329
+ media: readyMedia,
1319
1330
  quotedTweet: resolvedQuoted,
1320
1331
  replyToHandle
1321
1332
  })
1322
1333
  );
1323
- }, [
1324
- variant,
1325
- author,
1326
- resolvedMedia,
1327
- quotedTweet,
1328
- resolvedQuotedMedia,
1329
- replyToHandle
1330
- ]);
1331
- const isEmpty = !variant.body && resolvedMedia.length === 0 && !variant.settings?.poll && !tweet.quoted_tweet;
1334
+ }, [variant, author, readyMedia, quotedTweet, readyQuotedMedia, replyToHandle]);
1335
+ const isEmpty = !variant.body && resolved.length === 0 && !variant.settings?.poll && !tweet.quoted_tweet;
1332
1336
  return /* @__PURE__ */ jsxRuntime.jsx(
1333
1337
  "div",
1334
1338
  {
@@ -1340,6 +1344,7 @@ function XPostPreviewImpl({
1340
1344
  tweet.in_reply_to_screen_name ? /* @__PURE__ */ jsxRuntime.jsx(reactTweet.TweetInReplyTo, { tweet }) : null,
1341
1345
  isEmpty ? /* @__PURE__ */ jsxRuntime.jsx(EmptyBody, {}) : /* @__PURE__ */ jsxRuntime.jsx(reactTweet.TweetBody, { tweet }),
1342
1346
  tweet.mediaDetails?.length ? /* @__PURE__ */ jsxRuntime.jsx(reactTweet.TweetMedia, { tweet, components }) : null,
1347
+ mediaPending ? /* @__PURE__ */ jsxRuntime.jsx(ProcessingTile, {}) : null,
1343
1348
  variant.settings?.poll ? /* @__PURE__ */ jsxRuntime.jsx(XPoll, { poll: variant.settings.poll }) : null,
1344
1349
  tweet.quoted_tweet ? /* @__PURE__ */ jsxRuntime.jsx(reactTweet.QuotedTweet, { tweet: tweet.quoted_tweet }) : null,
1345
1350
  showActions ? /* @__PURE__ */ jsxRuntime.jsx(XPreviewActions, {}) : null
@@ -1347,6 +1352,26 @@ function XPostPreviewImpl({
1347
1352
  }
1348
1353
  );
1349
1354
  }
1355
+ function ProcessingTile() {
1356
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: processingFrameStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
1357
+ MediaPlaceholder,
1358
+ {
1359
+ label: "Processing media\u2026",
1360
+ color: "var(--tweet-font-color-secondary, #536471)",
1361
+ background: "color-mix(in srgb, currentColor 6%, transparent)",
1362
+ shimmer: true
1363
+ }
1364
+ ) });
1365
+ }
1366
+ var processingFrameStyle = {
1367
+ position: "relative",
1368
+ width: "100%",
1369
+ aspectRatio: "16 / 9",
1370
+ marginTop: "var(--tweet-body-margin, 12px)",
1371
+ borderRadius: 16,
1372
+ overflow: "hidden",
1373
+ border: "1px solid var(--tweet-color-gray-secondary, rgba(15,20,25,0.1))"
1374
+ };
1350
1375
  function EmptyBody() {
1351
1376
  return /* @__PURE__ */ jsxRuntime.jsx("p", { style: emptyBodyStyle, children: "What's happening?" });
1352
1377
  }
@@ -1674,7 +1699,6 @@ function VideoTile({ item }) {
1674
1699
  "video",
1675
1700
  {
1676
1701
  src: item.src,
1677
- poster: item.posterSrc,
1678
1702
  controls: true,
1679
1703
  style: { width: "100%", display: "block", background: "#000" }
1680
1704
  }
@@ -1862,18 +1886,30 @@ var BODY_COLORS = {
1862
1886
  };
1863
1887
  function LinkedInPostPreviewImpl({
1864
1888
  variant,
1865
- author,
1889
+ connection,
1866
1890
  media,
1891
+ headline,
1892
+ verified,
1867
1893
  theme = "auto",
1868
1894
  time,
1869
1895
  showActions = true,
1870
1896
  className,
1871
1897
  style
1872
1898
  }) {
1873
- const resolvedMedia = useResolvedMedia(
1874
- media,
1875
- variant.media,
1876
- altSignatureOf(variant.media)
1899
+ const resolved = react.useMemo(
1900
+ () => resolveVariantMedia(variant.media, "linkedin", media),
1901
+ [variant.media, media]
1902
+ );
1903
+ const readyMedia = react.useMemo(() => resolved.filter(isReadyMedia), [resolved]);
1904
+ const mediaPending = resolved.length > 0 && readyMedia.length === 0;
1905
+ const author = react.useMemo(
1906
+ () => ({
1907
+ name: authorName(connection),
1908
+ avatar_url: connection.avatar_url,
1909
+ headline,
1910
+ verified
1911
+ }),
1912
+ [connection, headline, verified]
1877
1913
  );
1878
1914
  const visibility = variant.settings?.visibility ?? "PUBLIC";
1879
1915
  const mentionNames = react.useMemo(
@@ -1887,8 +1923,6 @@ function LinkedInPostPreviewImpl({
1887
1923
  color: varRef(LI_VAR.text),
1888
1924
  border: `1px solid ${varRef(LI_VAR.border)}`,
1889
1925
  borderRadius: 10,
1890
- // Pin the width (see InstagramPostPreview): without it the card shrinks to its
1891
- // content, so an empty post collapses to a fraction of a populated card's width.
1892
1926
  width: "100%",
1893
1927
  maxWidth: 552,
1894
1928
  boxSizing: "border-box",
@@ -1896,9 +1930,18 @@ function LinkedInPostPreviewImpl({
1896
1930
  fontFamily: FONT_STACK,
1897
1931
  ...style
1898
1932
  };
1899
- const hasContent = Boolean(variant.body) || resolvedMedia.length > 0 || Boolean(variant.settings?.content_kind && variant.settings.content_kind !== "text");
1933
+ const hasContent = Boolean(variant.body) || resolved.length > 0 || Boolean(
1934
+ variant.settings?.content_kind && variant.settings.content_kind !== "text"
1935
+ );
1900
1936
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: cardStyle5, children: [
1901
- /* @__PURE__ */ jsxRuntime.jsx(Header, { author, visibility, time }),
1937
+ /* @__PURE__ */ jsxRuntime.jsx(
1938
+ Header,
1939
+ {
1940
+ author,
1941
+ visibility,
1942
+ time
1943
+ }
1944
+ ),
1902
1945
  variant.body ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "8px 16px 0" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1903
1946
  PostBody,
1904
1947
  {
@@ -1907,7 +1950,7 @@ function LinkedInPostPreviewImpl({
1907
1950
  colors: BODY_COLORS
1908
1951
  }
1909
1952
  ) }) : null,
1910
- renderContent(variant, resolvedMedia),
1953
+ renderContent(variant, readyMedia, mediaPending),
1911
1954
  hasContent ? null : /* @__PURE__ */ jsxRuntime.jsx("p", { style: { ...emptyBodyStyle2, color: BODY_COLORS.muted }, children: "What do you want to talk about?" }),
1912
1955
  showActions ? /* @__PURE__ */ jsxRuntime.jsx(EngagementBar, {}) : null
1913
1956
  ] });
@@ -1918,7 +1961,7 @@ var emptyBodyStyle2 = {
1918
1961
  fontSize: 14,
1919
1962
  lineHeight: 1.4
1920
1963
  };
1921
- function renderContent(variant, media) {
1964
+ function renderContent(variant, media, pending) {
1922
1965
  const settings = variant.settings;
1923
1966
  const kind = settings?.content_kind;
1924
1967
  const [firstMedia] = media;
@@ -1931,9 +1974,29 @@ function renderContent(variant, media) {
1931
1974
  if (kind === "document" && settings?.document) {
1932
1975
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style: INSET, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentCard, { document: settings.document, cover: firstMedia }) });
1933
1976
  }
1934
- return media.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 12 }, children: /* @__PURE__ */ jsxRuntime.jsx(Media, { media }) }) : null;
1977
+ if (media.length > 0) {
1978
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 12 }, children: /* @__PURE__ */ jsxRuntime.jsx(Media, { media }) });
1979
+ }
1980
+ if (pending) {
1981
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: processingFrameStyle2, children: /* @__PURE__ */ jsxRuntime.jsx(
1982
+ MediaPlaceholder,
1983
+ {
1984
+ label: "Processing media\u2026",
1985
+ color: varRef(LI_VAR.muted),
1986
+ background: varRef(LI_VAR.border),
1987
+ shimmer: true
1988
+ }
1989
+ ) });
1990
+ }
1991
+ return null;
1935
1992
  }
1936
1993
  var INSET = { padding: "12px 16px 0" };
1994
+ var processingFrameStyle2 = {
1995
+ position: "relative",
1996
+ width: "100%",
1997
+ height: 272,
1998
+ marginTop: 12
1999
+ };
1937
2000
  var LinkedInPostPreview = react.memo(LinkedInPostPreviewImpl);
1938
2001
 
1939
2002
  // src/preview/instagram/theme.ts
@@ -2074,42 +2137,6 @@ var wrapStyle3 = {
2074
2137
  lineHeight: 1.4,
2075
2138
  color: varRef2(IG_VAR.text)
2076
2139
  };
2077
- function MediaPlaceholder({
2078
- label,
2079
- color,
2080
- background,
2081
- shimmer = false
2082
- }) {
2083
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...fillStyle, background, color }, children: [
2084
- shimmer ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2085
- /* @__PURE__ */ jsxRuntime.jsx("style", { children: SHIMMER_KEYFRAME }),
2086
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: shimmerStyle })
2087
- ] }) : null,
2088
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: labelStyle, children: label })
2089
- ] });
2090
- }
2091
- var SHIMMER_KEYFRAME = "@keyframes pr-media-shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}}";
2092
- var fillStyle = {
2093
- position: "absolute",
2094
- inset: 0,
2095
- display: "flex",
2096
- alignItems: "center",
2097
- justifyContent: "center",
2098
- overflow: "hidden"
2099
- };
2100
- var labelStyle = {
2101
- position: "relative",
2102
- zIndex: 1,
2103
- fontSize: 13,
2104
- letterSpacing: 0.1
2105
- };
2106
- var shimmerStyle = {
2107
- position: "absolute",
2108
- inset: 0,
2109
- background: "linear-gradient(90deg, transparent 0%, color-mix(in srgb, currentColor 12%, transparent) 50%, transparent 100%)",
2110
- backgroundSize: "200% 100%",
2111
- animation: "pr-media-shimmer 1.4s ease-in-out infinite"
2112
- };
2113
2140
  function FeedMedia({
2114
2141
  media,
2115
2142
  pending = false
@@ -2130,7 +2157,7 @@ function FeedMedia({
2130
2157
  }
2131
2158
  function Tile2({ item }) {
2132
2159
  if (item.kind === "video") {
2133
- return /* @__PURE__ */ jsxRuntime.jsx("video", { src: item.src, poster: item.posterSrc, controls: true, style: mediaStyle });
2160
+ return /* @__PURE__ */ jsxRuntime.jsx("video", { src: item.src, controls: true, style: mediaStyle });
2134
2161
  }
2135
2162
  return /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.src, alt: item.alt ?? "", style: mediaStyle });
2136
2163
  }
@@ -2300,7 +2327,6 @@ function ReelPreview({
2300
2327
  "video",
2301
2328
  {
2302
2329
  src: first.src,
2303
- poster: first.posterSrc,
2304
2330
  autoPlay: true,
2305
2331
  muted: true,
2306
2332
  loop: true,
@@ -2407,27 +2433,32 @@ var railStyle = {
2407
2433
  };
2408
2434
  function InstagramPostPreviewImpl({
2409
2435
  variant,
2410
- author,
2436
+ connection,
2411
2437
  media,
2438
+ verified,
2412
2439
  theme = "auto",
2413
2440
  className,
2414
2441
  style
2415
2442
  }) {
2416
- const resolvedMedia = useResolvedMedia(
2417
- media,
2418
- variant.media,
2419
- altSignatureOf(variant.media)
2443
+ const resolved = react.useMemo(
2444
+ () => resolveVariantMedia(variant.media, "instagram", media),
2445
+ [variant.media, media]
2446
+ );
2447
+ const readyMedia = react.useMemo(() => resolved.filter(isReadyMedia), [resolved]);
2448
+ const pending = resolved.length > 0 && readyMedia.length === 0;
2449
+ const author = react.useMemo(
2450
+ () => ({ username: connection.username, avatar_url: connection.avatar_url, verified }),
2451
+ [connection, verified]
2420
2452
  );
2421
2453
  const settings = variant.settings;
2422
2454
  const isReel = variant.post_type === "reel";
2423
- const pending = (media?.length ?? 0) > 0 && resolvedMedia.length === 0;
2424
2455
  if (isReel) {
2425
2456
  return /* @__PURE__ */ jsxRuntime.jsx(
2426
2457
  ReelPreview,
2427
2458
  {
2428
2459
  author,
2429
2460
  body: variant.body ?? "",
2430
- media: resolvedMedia,
2461
+ media: readyMedia,
2431
2462
  pending,
2432
2463
  audioName: settings?.audio_name,
2433
2464
  className,
@@ -2443,10 +2474,6 @@ function InstagramPostPreviewImpl({
2443
2474
  color: varRef2(IG_VAR.text),
2444
2475
  border: `1px solid ${varRef2(IG_VAR.border)}`,
2445
2476
  borderRadius: 8,
2446
- // Fill the container up to IG's feed width. WITHOUT an explicit width the card
2447
- // shrinks to its content, so an empty post (no caption/media to widen it) would
2448
- // collapse to a fraction of a populated card's width — a jarring size change as
2449
- // you type. Pinning width keeps every state the SAME size (zero layout shift).
2450
2477
  width: "100%",
2451
2478
  maxWidth: 470,
2452
2479
  boxSizing: "border-box",
@@ -2456,7 +2483,7 @@ function InstagramPostPreviewImpl({
2456
2483
  };
2457
2484
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: cardStyle5, children: [
2458
2485
  /* @__PURE__ */ jsxRuntime.jsx(Header2, { author, collaborators }),
2459
- /* @__PURE__ */ jsxRuntime.jsx(FeedMedia, { media: resolvedMedia, pending }),
2486
+ /* @__PURE__ */ jsxRuntime.jsx(FeedMedia, { media: readyMedia, pending }),
2460
2487
  /* @__PURE__ */ jsxRuntime.jsx(Actions, {}),
2461
2488
  variant.body ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { paddingBottom: 12 }, children: /* @__PURE__ */ jsxRuntime.jsx(Caption, { username: author.username, body: variant.body }) }) : null
2462
2489
  ] });
@@ -2496,7 +2523,6 @@ function Media2({
2496
2523
  "video",
2497
2524
  {
2498
2525
  src: first.src,
2499
- poster: first.posterSrc,
2500
2526
  autoPlay: true,
2501
2527
  muted: true,
2502
2528
  loop: true,
@@ -2636,19 +2662,19 @@ function TikTokPostPreviewImpl({
2636
2662
  className,
2637
2663
  style
2638
2664
  }) {
2639
- const resolvedMedia = useResolvedMedia(
2640
- media,
2641
- variant.media,
2642
- altSignatureOf(variant.media)
2665
+ const resolved = react.useMemo(
2666
+ () => resolveVariantMedia(variant.media, "tiktok", media),
2667
+ [variant.media, media]
2643
2668
  );
2669
+ const readyMedia = react.useMemo(() => resolved.filter(isReadyMedia), [resolved]);
2644
2670
  const { creator } = creatorInfo;
2645
2671
  const handle = creator.username || creator.nickname;
2646
2672
  const label = commercialLabel(variant.settings);
2647
2673
  const isAigc = Boolean(variant.settings?.is_aigc);
2648
- const pending = (media?.length ?? 0) > 0 && resolvedMedia.length === 0;
2674
+ const pending = resolved.length > 0 && readyMedia.length === 0;
2649
2675
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...cardStyle4, ...style }, children: [
2650
2676
  /* @__PURE__ */ jsxRuntime.jsx("style", { children: KEYFRAMES }),
2651
- /* @__PURE__ */ jsxRuntime.jsx(Media2, { media: resolvedMedia, pending }),
2677
+ /* @__PURE__ */ jsxRuntime.jsx(Media2, { media: readyMedia, pending }),
2652
2678
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: scrimStyle2 }),
2653
2679
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: infoStyle2, children: [
2654
2680
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: usernameStyle, children: handle }),
@@ -3366,11 +3392,12 @@ exports.TikTokPublishPanel = TikTokPublishPanel;
3366
3392
  exports.XPoll = XPoll;
3367
3393
  exports.XPostPreview = XPostPreview;
3368
3394
  exports.connectionKeys = connectionKeys;
3395
+ exports.isReadyMedia = isReadyMedia;
3369
3396
  exports.mediaKeys = mediaKeys;
3370
3397
  exports.postKeys = postKeys;
3371
3398
  exports.profileKeys = profileKeys;
3399
+ exports.resolveVariantMedia = resolveVariantMedia;
3372
3400
  exports.tiktokKeys = tiktokKeys;
3373
- exports.toPreviewMedia = toPreviewMedia;
3374
3401
  exports.useCalendar = useCalendar;
3375
3402
  exports.useConnect = useConnect;
3376
3403
  exports.useConnection = useConnection;