@postrun/react 2.12.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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { createContext, memo, useMemo, useState, useEffect, Fragment as Fragment$1, useRef, useLayoutEffect, useCallback, createElement, useContext, useId } from 'react';
2
+ import { createContext, memo, useMemo, useState, Fragment as Fragment$1, useRef, useLayoutEffect, useCallback, useEffect, createElement, useContext, useId } from 'react';
3
3
  import { useInfiniteQuery, useQuery, useMutation, QueryClient } from '@tanstack/react-query';
4
4
  import { xPollDurationLabel, linkedinPollDurationLabel, createPostrunClient, profilesList, profilesGet, profilesCreate, profilesUpdate, profilesDelete, connectionsConnect, connectionsListByProfile, connectionsGet, connectionsListAccounts, connectionsSelect, connectionsDelete, mediaGet, mediaList, mediaUpdate, mediaDelete, postsList, postsGet, postsCreate, buildCreatePost, isPostPlatform, failedVariants, isPublished, postsValidate, postsUpdate, postsDelete, tiktokCreatorInfo, audiencePrivacyOptions, audienceUnselected, tiktokPrivacyLabel, parsePrivacyLevel, TIKTOK_AUDIENCE_REQUIRED_HINT, captionMaxFor, commercialLabelNotice, commercialDisclosureIncomplete, setCommercialDisclosure, setBrandKind, TIKTOK_DISCLOSURE_REQUIRED_HINT, TIKTOK_BRANDED_CONTENT_POLICY_URL, TIKTOK_MUSIC_CONFIRMATION_URL, interactionRows, interactionValueKey, toggleInteraction, tiktokOptionsReady, TIKTOK_PROCESSING_NOTICE, brandedContentDeclared, mediaCreate, uploadToTarget, PostrunError } from '@postrun/js';
5
5
  export { TIKTOK_CAPTION_MAX, UploadError, captionMaxFor } from '@postrun/js';
@@ -920,96 +920,93 @@ function useTikTokCreatorInfo(connectionId) {
920
920
  );
921
921
  }
922
922
 
923
- // src/preview/from-upload.ts
924
- function previewKind(item) {
925
- const detected = item.media?.kind;
926
- if (detected) {
927
- return detected === "document" ? null : detected;
928
- }
929
- const mime = item.file.type;
930
- if (mime === "image/gif") {
931
- return "gif";
932
- }
933
- if (mime.startsWith("video/")) {
934
- return "video";
935
- }
936
- if (mime.startsWith("image/")) {
937
- return "image";
923
+ // src/preview/media-resolver.ts
924
+ function previewKind(kind) {
925
+ return kind === "image" || kind === "video" || kind === "gif" ? kind : null;
926
+ }
927
+ function resourceFor(ref, fallback) {
928
+ if ("media" in ref && ref.media) {
929
+ return ref.media;
938
930
  }
939
- return null;
931
+ return fallback?.find((asset) => asset.id === ref.media_id);
940
932
  }
941
- function toPreviewMedia(items) {
942
- return items.flatMap((item) => {
943
- const kind = previewKind(item);
933
+ function renditionFor(asset, target) {
934
+ return asset.per_platform[target];
935
+ }
936
+ function resolveVariantMedia(refs, target, fallback) {
937
+ return (refs ?? []).flatMap((ref) => {
938
+ const asset = resourceFor(ref, fallback);
939
+ if (!asset) {
940
+ return [];
941
+ }
942
+ const kind = previewKind(asset.kind);
944
943
  if (!kind) {
945
944
  return [];
946
945
  }
947
- return [
948
- {
949
- kind,
950
- file: item.file,
951
- width: item.media?.source?.width ?? void 0,
952
- height: item.media?.source?.height ?? void 0,
953
- alt: item.media?.alt_text ?? void 0
954
- }
955
- ];
956
- });
957
- }
958
- function fileKey(file) {
959
- return file ? `${file.name}:${file.size}:${file.lastModified}` : "";
960
- }
961
- function mediaSignature(media) {
962
- return (media ?? []).map((item) => {
963
- const source = item.url ?? fileKey(item.file);
964
- const size = `${item.width ?? ""}x${item.height ?? ""}`;
965
- return `${item.kind}|${source}|${item.posterUrl ?? ""}|${size}|${item.alt ?? ""}`;
966
- }).join("\xA7");
967
- }
968
- function altSignatureOf(media) {
969
- return (media ?? []).map((m) => m?.alt_text_override ?? "").join("\xA7");
970
- }
971
- function useResolvedMedia(media, altFallbacks, altSignature) {
972
- const signature = mediaSignature(media);
973
- const [objectUrls, setObjectUrls] = useState({});
974
- useEffect(() => {
975
- const created = [];
976
- const next = {};
977
- (media ?? []).forEach((item, index) => {
978
- if (!item.url && item.file) {
979
- const url = URL.createObjectURL(item.file);
980
- created.push(url);
981
- next[index] = url;
982
- }
983
- });
984
- setObjectUrls(next);
985
- return () => {
986
- for (const url of created) {
987
- URL.revokeObjectURL(url);
988
- }
989
- };
990
- }, [signature]);
991
- return useMemo(
992
- () => (media ?? []).flatMap((item, index) => {
993
- const src = item.url ?? objectUrls[index];
994
- if (!src) {
995
- return [];
996
- }
946
+ const alt = ref.alt_text_override ?? asset.alt_text ?? void 0;
947
+ const width = asset.source?.width ?? void 0;
948
+ const height = asset.source?.height ?? void 0;
949
+ const rendition = renditionFor(asset, target);
950
+ if (asset.status === "ready" && rendition?.status === "ready" && rendition.url) {
997
951
  return [
998
952
  {
999
- kind: item.kind,
1000
- src,
1001
- width: item.width,
1002
- height: item.height,
1003
- alt: item.alt ?? altFallbacks?.[index]?.alt_text_override ?? void 0,
1004
- posterSrc: item.posterUrl
953
+ kind,
954
+ state: "ready",
955
+ src: rendition.url,
956
+ width: rendition.width ?? width,
957
+ height: rendition.height ?? height,
958
+ alt
1005
959
  }
1006
960
  ];
1007
- }),
1008
- // `signature` + `altSignature` capture the content; `objectUrls` flips once
1009
- // File blobs resolve. Referencing `media`/`altFallbacks` directly is safe.
1010
- // eslint-disable-next-line react-hooks/exhaustive-deps
1011
- [signature, altSignature, objectUrls]
1012
- );
961
+ }
962
+ return [{ kind, state: "processing", width, height, alt }];
963
+ });
964
+ }
965
+ function MediaPlaceholder({
966
+ label,
967
+ color,
968
+ background,
969
+ shimmer = false
970
+ }) {
971
+ return /* @__PURE__ */ jsxs("div", { style: { ...fillStyle, background, color }, children: [
972
+ shimmer ? /* @__PURE__ */ jsxs(Fragment, { children: [
973
+ /* @__PURE__ */ jsx("style", { children: SHIMMER_KEYFRAME }),
974
+ /* @__PURE__ */ jsx("div", { style: shimmerStyle })
975
+ ] }) : null,
976
+ /* @__PURE__ */ jsx("span", { style: labelStyle, children: label })
977
+ ] });
978
+ }
979
+ var SHIMMER_KEYFRAME = "@keyframes pr-media-shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}}";
980
+ var fillStyle = {
981
+ position: "absolute",
982
+ inset: 0,
983
+ display: "flex",
984
+ alignItems: "center",
985
+ justifyContent: "center",
986
+ overflow: "hidden"
987
+ };
988
+ var labelStyle = {
989
+ position: "relative",
990
+ zIndex: 1,
991
+ fontSize: 13,
992
+ letterSpacing: 0.1
993
+ };
994
+ var shimmerStyle = {
995
+ position: "absolute",
996
+ inset: 0,
997
+ background: "linear-gradient(90deg, transparent 0%, color-mix(in srgb, currentColor 12%, transparent) 50%, transparent 100%)",
998
+ backgroundSize: "200% 100%",
999
+ animation: "pr-media-shimmer 1.4s ease-in-out infinite"
1000
+ };
1001
+
1002
+ // src/preview/types.ts
1003
+ function isReadyMedia(item) {
1004
+ return item.state === "ready";
1005
+ }
1006
+
1007
+ // src/preview/author.ts
1008
+ function authorName(connection) {
1009
+ return connection.external_account_name ?? connection.username ?? "";
1013
1010
  }
1014
1011
  function XPoll({ poll }) {
1015
1012
  return /* @__PURE__ */ jsxs("div", { style: wrapStyle, children: [
@@ -1078,9 +1075,7 @@ function rawSrcLookup(...lists) {
1078
1075
  const map = /* @__PURE__ */ new Map();
1079
1076
  for (const list of lists) {
1080
1077
  for (const item of list) {
1081
- const poster = item.posterSrc ?? item.src;
1082
1078
  map.set(twitterMediaUrl(item.src), item.src);
1083
- map.set(twitterMediaUrl(poster), poster);
1084
1079
  }
1085
1080
  }
1086
1081
  return map;
@@ -1175,7 +1170,7 @@ function buildPhoto(media) {
1175
1170
  };
1176
1171
  }
1177
1172
  function buildVideo(media) {
1178
- const poster = media.posterSrc ?? media.src;
1173
+ const poster = media.src;
1179
1174
  const videoInfo = {
1180
1175
  aspect_ratio: [media.width ?? 16, media.height ?? 9],
1181
1176
  variants: [{ content_type: "video/mp4", url: media.src }]
@@ -1271,8 +1266,9 @@ function toTweet(input) {
1271
1266
  }
1272
1267
  function XPostPreviewImpl({
1273
1268
  variant,
1274
- author,
1269
+ connection,
1275
1270
  media,
1271
+ verified,
1276
1272
  quotedTweet,
1277
1273
  replyToHandle,
1278
1274
  theme = "auto",
@@ -1281,45 +1277,53 @@ function XPostPreviewImpl({
1281
1277
  style,
1282
1278
  components: componentsProp
1283
1279
  }) {
1284
- const resolvedMedia = useResolvedMedia(
1285
- media,
1286
- variant.media,
1287
- altSignatureOf(variant.media)
1280
+ const resolved = useMemo(
1281
+ () => resolveVariantMedia(variant.media, "x", media),
1282
+ [variant.media, media]
1283
+ );
1284
+ const readyMedia = useMemo(() => resolved.filter(isReadyMedia), [resolved]);
1285
+ const readyQuotedMedia = useMemo(
1286
+ () => (quotedTweet?.media ?? []).filter(isReadyMedia),
1287
+ [quotedTweet?.media]
1288
+ );
1289
+ const mediaPending = resolved.length > 0 && readyMedia.length === 0;
1290
+ const author = useMemo(
1291
+ () => ({
1292
+ name: authorName(connection),
1293
+ username: connection.username,
1294
+ avatar_url: connection.avatar_url,
1295
+ verified
1296
+ }),
1297
+ [connection, verified]
1288
1298
  );
1289
- const resolvedQuotedMedia = useResolvedMedia(quotedTweet?.media, void 0, "");
1290
1299
  const components = useMemo(
1291
1300
  () => ({
1292
- MediaImg: makeRawMediaImg(
1293
- rawSrcLookup(resolvedMedia, resolvedQuotedMedia)
1294
- ),
1301
+ MediaImg: makeRawMediaImg(rawSrcLookup(readyMedia, readyQuotedMedia)),
1295
1302
  ...componentsProp
1296
1303
  }),
1297
- [resolvedMedia, resolvedQuotedMedia, componentsProp]
1304
+ [readyMedia, readyQuotedMedia, componentsProp]
1298
1305
  );
1299
1306
  const tweet = useMemo(() => {
1300
1307
  const resolvedQuoted = quotedTweet ? {
1301
- author: quotedTweet.author,
1308
+ author: {
1309
+ name: quotedTweet.name,
1310
+ username: quotedTweet.username,
1311
+ avatar_url: quotedTweet.avatar_url
1312
+ },
1302
1313
  body: quotedTweet.body,
1303
- media: resolvedQuotedMedia
1314
+ media: readyQuotedMedia
1304
1315
  } : void 0;
1305
1316
  return enrichTweet(
1306
1317
  toTweet({
1307
1318
  variant,
1308
1319
  author,
1309
- media: resolvedMedia,
1320
+ media: readyMedia,
1310
1321
  quotedTweet: resolvedQuoted,
1311
1322
  replyToHandle
1312
1323
  })
1313
1324
  );
1314
- }, [
1315
- variant,
1316
- author,
1317
- resolvedMedia,
1318
- quotedTweet,
1319
- resolvedQuotedMedia,
1320
- replyToHandle
1321
- ]);
1322
- const isEmpty = !variant.body && resolvedMedia.length === 0 && !variant.settings?.poll && !tweet.quoted_tweet;
1325
+ }, [variant, author, readyMedia, quotedTweet, readyQuotedMedia, replyToHandle]);
1326
+ const isEmpty = !variant.body && resolved.length === 0 && !variant.settings?.poll && !tweet.quoted_tweet;
1323
1327
  return /* @__PURE__ */ jsx(
1324
1328
  "div",
1325
1329
  {
@@ -1331,6 +1335,7 @@ function XPostPreviewImpl({
1331
1335
  tweet.in_reply_to_screen_name ? /* @__PURE__ */ jsx(TweetInReplyTo, { tweet }) : null,
1332
1336
  isEmpty ? /* @__PURE__ */ jsx(EmptyBody, {}) : /* @__PURE__ */ jsx(TweetBody, { tweet }),
1333
1337
  tweet.mediaDetails?.length ? /* @__PURE__ */ jsx(TweetMedia, { tweet, components }) : null,
1338
+ mediaPending ? /* @__PURE__ */ jsx(ProcessingTile, {}) : null,
1334
1339
  variant.settings?.poll ? /* @__PURE__ */ jsx(XPoll, { poll: variant.settings.poll }) : null,
1335
1340
  tweet.quoted_tweet ? /* @__PURE__ */ jsx(QuotedTweet, { tweet: tweet.quoted_tweet }) : null,
1336
1341
  showActions ? /* @__PURE__ */ jsx(XPreviewActions, {}) : null
@@ -1338,6 +1343,26 @@ function XPostPreviewImpl({
1338
1343
  }
1339
1344
  );
1340
1345
  }
1346
+ function ProcessingTile() {
1347
+ return /* @__PURE__ */ jsx("div", { style: processingFrameStyle, children: /* @__PURE__ */ jsx(
1348
+ MediaPlaceholder,
1349
+ {
1350
+ label: "Processing media\u2026",
1351
+ color: "var(--tweet-font-color-secondary, #536471)",
1352
+ background: "color-mix(in srgb, currentColor 6%, transparent)",
1353
+ shimmer: true
1354
+ }
1355
+ ) });
1356
+ }
1357
+ var processingFrameStyle = {
1358
+ position: "relative",
1359
+ width: "100%",
1360
+ aspectRatio: "16 / 9",
1361
+ marginTop: "var(--tweet-body-margin, 12px)",
1362
+ borderRadius: 16,
1363
+ overflow: "hidden",
1364
+ border: "1px solid var(--tweet-color-gray-secondary, rgba(15,20,25,0.1))"
1365
+ };
1341
1366
  function EmptyBody() {
1342
1367
  return /* @__PURE__ */ jsx("p", { style: emptyBodyStyle, children: "What's happening?" });
1343
1368
  }
@@ -1665,7 +1690,6 @@ function VideoTile({ item }) {
1665
1690
  "video",
1666
1691
  {
1667
1692
  src: item.src,
1668
- poster: item.posterSrc,
1669
1693
  controls: true,
1670
1694
  style: { width: "100%", display: "block", background: "#000" }
1671
1695
  }
@@ -1853,18 +1877,30 @@ var BODY_COLORS = {
1853
1877
  };
1854
1878
  function LinkedInPostPreviewImpl({
1855
1879
  variant,
1856
- author,
1880
+ connection,
1857
1881
  media,
1882
+ headline,
1883
+ verified,
1858
1884
  theme = "auto",
1859
1885
  time,
1860
1886
  showActions = true,
1861
1887
  className,
1862
1888
  style
1863
1889
  }) {
1864
- const resolvedMedia = useResolvedMedia(
1865
- media,
1866
- variant.media,
1867
- altSignatureOf(variant.media)
1890
+ const resolved = useMemo(
1891
+ () => resolveVariantMedia(variant.media, "linkedin", media),
1892
+ [variant.media, media]
1893
+ );
1894
+ const readyMedia = useMemo(() => resolved.filter(isReadyMedia), [resolved]);
1895
+ const mediaPending = resolved.length > 0 && readyMedia.length === 0;
1896
+ const author = useMemo(
1897
+ () => ({
1898
+ name: authorName(connection),
1899
+ avatar_url: connection.avatar_url,
1900
+ headline,
1901
+ verified
1902
+ }),
1903
+ [connection, headline, verified]
1868
1904
  );
1869
1905
  const visibility = variant.settings?.visibility ?? "PUBLIC";
1870
1906
  const mentionNames = useMemo(
@@ -1878,8 +1914,6 @@ function LinkedInPostPreviewImpl({
1878
1914
  color: varRef(LI_VAR.text),
1879
1915
  border: `1px solid ${varRef(LI_VAR.border)}`,
1880
1916
  borderRadius: 10,
1881
- // Pin the width (see InstagramPostPreview): without it the card shrinks to its
1882
- // content, so an empty post collapses to a fraction of a populated card's width.
1883
1917
  width: "100%",
1884
1918
  maxWidth: 552,
1885
1919
  boxSizing: "border-box",
@@ -1887,9 +1921,18 @@ function LinkedInPostPreviewImpl({
1887
1921
  fontFamily: FONT_STACK,
1888
1922
  ...style
1889
1923
  };
1890
- const hasContent = Boolean(variant.body) || resolvedMedia.length > 0 || Boolean(variant.settings?.content_kind && variant.settings.content_kind !== "text");
1924
+ const hasContent = Boolean(variant.body) || resolved.length > 0 || Boolean(
1925
+ variant.settings?.content_kind && variant.settings.content_kind !== "text"
1926
+ );
1891
1927
  return /* @__PURE__ */ jsxs("div", { className, style: cardStyle5, children: [
1892
- /* @__PURE__ */ jsx(Header, { author, visibility, time }),
1928
+ /* @__PURE__ */ jsx(
1929
+ Header,
1930
+ {
1931
+ author,
1932
+ visibility,
1933
+ time
1934
+ }
1935
+ ),
1893
1936
  variant.body ? /* @__PURE__ */ jsx("div", { style: { padding: "8px 16px 0" }, children: /* @__PURE__ */ jsx(
1894
1937
  PostBody,
1895
1938
  {
@@ -1898,7 +1941,7 @@ function LinkedInPostPreviewImpl({
1898
1941
  colors: BODY_COLORS
1899
1942
  }
1900
1943
  ) }) : null,
1901
- renderContent(variant, resolvedMedia),
1944
+ renderContent(variant, readyMedia, mediaPending),
1902
1945
  hasContent ? null : /* @__PURE__ */ jsx("p", { style: { ...emptyBodyStyle2, color: BODY_COLORS.muted }, children: "What do you want to talk about?" }),
1903
1946
  showActions ? /* @__PURE__ */ jsx(EngagementBar, {}) : null
1904
1947
  ] });
@@ -1909,7 +1952,7 @@ var emptyBodyStyle2 = {
1909
1952
  fontSize: 14,
1910
1953
  lineHeight: 1.4
1911
1954
  };
1912
- function renderContent(variant, media) {
1955
+ function renderContent(variant, media, pending) {
1913
1956
  const settings = variant.settings;
1914
1957
  const kind = settings?.content_kind;
1915
1958
  const [firstMedia] = media;
@@ -1922,9 +1965,29 @@ function renderContent(variant, media) {
1922
1965
  if (kind === "document" && settings?.document) {
1923
1966
  return /* @__PURE__ */ jsx("div", { style: INSET, children: /* @__PURE__ */ jsx(DocumentCard, { document: settings.document, cover: firstMedia }) });
1924
1967
  }
1925
- return media.length > 0 ? /* @__PURE__ */ jsx("div", { style: { marginTop: 12 }, children: /* @__PURE__ */ jsx(Media, { media }) }) : null;
1968
+ if (media.length > 0) {
1969
+ return /* @__PURE__ */ jsx("div", { style: { marginTop: 12 }, children: /* @__PURE__ */ jsx(Media, { media }) });
1970
+ }
1971
+ if (pending) {
1972
+ return /* @__PURE__ */ jsx("div", { style: processingFrameStyle2, children: /* @__PURE__ */ jsx(
1973
+ MediaPlaceholder,
1974
+ {
1975
+ label: "Processing media\u2026",
1976
+ color: varRef(LI_VAR.muted),
1977
+ background: varRef(LI_VAR.border),
1978
+ shimmer: true
1979
+ }
1980
+ ) });
1981
+ }
1982
+ return null;
1926
1983
  }
1927
1984
  var INSET = { padding: "12px 16px 0" };
1985
+ var processingFrameStyle2 = {
1986
+ position: "relative",
1987
+ width: "100%",
1988
+ height: 272,
1989
+ marginTop: 12
1990
+ };
1928
1991
  var LinkedInPostPreview = memo(LinkedInPostPreviewImpl);
1929
1992
 
1930
1993
  // src/preview/instagram/theme.ts
@@ -2065,42 +2128,6 @@ var wrapStyle3 = {
2065
2128
  lineHeight: 1.4,
2066
2129
  color: varRef2(IG_VAR.text)
2067
2130
  };
2068
- function MediaPlaceholder({
2069
- label,
2070
- color,
2071
- background,
2072
- shimmer = false
2073
- }) {
2074
- return /* @__PURE__ */ jsxs("div", { style: { ...fillStyle, background, color }, children: [
2075
- shimmer ? /* @__PURE__ */ jsxs(Fragment, { children: [
2076
- /* @__PURE__ */ jsx("style", { children: SHIMMER_KEYFRAME }),
2077
- /* @__PURE__ */ jsx("div", { style: shimmerStyle })
2078
- ] }) : null,
2079
- /* @__PURE__ */ jsx("span", { style: labelStyle, children: label })
2080
- ] });
2081
- }
2082
- var SHIMMER_KEYFRAME = "@keyframes pr-media-shimmer{0%{background-position:-200% 0}100%{background-position:200% 0}}";
2083
- var fillStyle = {
2084
- position: "absolute",
2085
- inset: 0,
2086
- display: "flex",
2087
- alignItems: "center",
2088
- justifyContent: "center",
2089
- overflow: "hidden"
2090
- };
2091
- var labelStyle = {
2092
- position: "relative",
2093
- zIndex: 1,
2094
- fontSize: 13,
2095
- letterSpacing: 0.1
2096
- };
2097
- var shimmerStyle = {
2098
- position: "absolute",
2099
- inset: 0,
2100
- background: "linear-gradient(90deg, transparent 0%, color-mix(in srgb, currentColor 12%, transparent) 50%, transparent 100%)",
2101
- backgroundSize: "200% 100%",
2102
- animation: "pr-media-shimmer 1.4s ease-in-out infinite"
2103
- };
2104
2131
  function FeedMedia({
2105
2132
  media,
2106
2133
  pending = false
@@ -2121,7 +2148,7 @@ function FeedMedia({
2121
2148
  }
2122
2149
  function Tile2({ item }) {
2123
2150
  if (item.kind === "video") {
2124
- return /* @__PURE__ */ jsx("video", { src: item.src, poster: item.posterSrc, controls: true, style: mediaStyle });
2151
+ return /* @__PURE__ */ jsx("video", { src: item.src, controls: true, style: mediaStyle });
2125
2152
  }
2126
2153
  return /* @__PURE__ */ jsx("img", { src: item.src, alt: item.alt ?? "", style: mediaStyle });
2127
2154
  }
@@ -2291,7 +2318,6 @@ function ReelPreview({
2291
2318
  "video",
2292
2319
  {
2293
2320
  src: first.src,
2294
- poster: first.posterSrc,
2295
2321
  autoPlay: true,
2296
2322
  muted: true,
2297
2323
  loop: true,
@@ -2398,27 +2424,32 @@ var railStyle = {
2398
2424
  };
2399
2425
  function InstagramPostPreviewImpl({
2400
2426
  variant,
2401
- author,
2427
+ connection,
2402
2428
  media,
2429
+ verified,
2403
2430
  theme = "auto",
2404
2431
  className,
2405
2432
  style
2406
2433
  }) {
2407
- const resolvedMedia = useResolvedMedia(
2408
- media,
2409
- variant.media,
2410
- altSignatureOf(variant.media)
2434
+ const resolved = useMemo(
2435
+ () => resolveVariantMedia(variant.media, "instagram", media),
2436
+ [variant.media, media]
2437
+ );
2438
+ const readyMedia = useMemo(() => resolved.filter(isReadyMedia), [resolved]);
2439
+ const pending = resolved.length > 0 && readyMedia.length === 0;
2440
+ const author = useMemo(
2441
+ () => ({ username: connection.username, avatar_url: connection.avatar_url, verified }),
2442
+ [connection, verified]
2411
2443
  );
2412
2444
  const settings = variant.settings;
2413
2445
  const isReel = variant.post_type === "reel";
2414
- const pending = (media?.length ?? 0) > 0 && resolvedMedia.length === 0;
2415
2446
  if (isReel) {
2416
2447
  return /* @__PURE__ */ jsx(
2417
2448
  ReelPreview,
2418
2449
  {
2419
2450
  author,
2420
2451
  body: variant.body ?? "",
2421
- media: resolvedMedia,
2452
+ media: readyMedia,
2422
2453
  pending,
2423
2454
  audioName: settings?.audio_name,
2424
2455
  className,
@@ -2434,10 +2465,6 @@ function InstagramPostPreviewImpl({
2434
2465
  color: varRef2(IG_VAR.text),
2435
2466
  border: `1px solid ${varRef2(IG_VAR.border)}`,
2436
2467
  borderRadius: 8,
2437
- // Fill the container up to IG's feed width. WITHOUT an explicit width the card
2438
- // shrinks to its content, so an empty post (no caption/media to widen it) would
2439
- // collapse to a fraction of a populated card's width — a jarring size change as
2440
- // you type. Pinning width keeps every state the SAME size (zero layout shift).
2441
2468
  width: "100%",
2442
2469
  maxWidth: 470,
2443
2470
  boxSizing: "border-box",
@@ -2447,7 +2474,7 @@ function InstagramPostPreviewImpl({
2447
2474
  };
2448
2475
  return /* @__PURE__ */ jsxs("div", { className, style: cardStyle5, children: [
2449
2476
  /* @__PURE__ */ jsx(Header2, { author, collaborators }),
2450
- /* @__PURE__ */ jsx(FeedMedia, { media: resolvedMedia, pending }),
2477
+ /* @__PURE__ */ jsx(FeedMedia, { media: readyMedia, pending }),
2451
2478
  /* @__PURE__ */ jsx(Actions, {}),
2452
2479
  variant.body ? /* @__PURE__ */ jsx("div", { style: { paddingBottom: 12 }, children: /* @__PURE__ */ jsx(Caption, { username: author.username, body: variant.body }) }) : null
2453
2480
  ] });
@@ -2487,7 +2514,6 @@ function Media2({
2487
2514
  "video",
2488
2515
  {
2489
2516
  src: first.src,
2490
- poster: first.posterSrc,
2491
2517
  autoPlay: true,
2492
2518
  muted: true,
2493
2519
  loop: true,
@@ -2627,19 +2653,19 @@ function TikTokPostPreviewImpl({
2627
2653
  className,
2628
2654
  style
2629
2655
  }) {
2630
- const resolvedMedia = useResolvedMedia(
2631
- media,
2632
- variant.media,
2633
- altSignatureOf(variant.media)
2656
+ const resolved = useMemo(
2657
+ () => resolveVariantMedia(variant.media, "tiktok", media),
2658
+ [variant.media, media]
2634
2659
  );
2660
+ const readyMedia = useMemo(() => resolved.filter(isReadyMedia), [resolved]);
2635
2661
  const { creator } = creatorInfo;
2636
2662
  const handle = creator.username || creator.nickname;
2637
2663
  const label = commercialLabel(variant.settings);
2638
2664
  const isAigc = Boolean(variant.settings?.is_aigc);
2639
- const pending = (media?.length ?? 0) > 0 && resolvedMedia.length === 0;
2665
+ const pending = resolved.length > 0 && readyMedia.length === 0;
2640
2666
  return /* @__PURE__ */ jsxs("div", { className, style: { ...cardStyle4, ...style }, children: [
2641
2667
  /* @__PURE__ */ jsx("style", { children: KEYFRAMES }),
2642
- /* @__PURE__ */ jsx(Media2, { media: resolvedMedia, pending }),
2668
+ /* @__PURE__ */ jsx(Media2, { media: readyMedia, pending }),
2643
2669
  /* @__PURE__ */ jsx("div", { style: scrimStyle2 }),
2644
2670
  /* @__PURE__ */ jsxs("div", { style: infoStyle2, children: [
2645
2671
  /* @__PURE__ */ jsx("div", { style: usernameStyle, children: handle }),
@@ -3327,6 +3353,6 @@ var postButtonStyle = {
3327
3353
  transition: "opacity 160ms ease"
3328
3354
  };
3329
3355
 
3330
- export { ArticleCard, AudienceSelect, CommercialDisclosure, Connect, Declaration, DocumentCard, InstagramPostPreview, InteractionToggles, LinkedInPostPreview, Poll, PostrunProvider, ReelPreview, TikTokCaptionField, TikTokPostPreview, TikTokPublishPanel, XPoll, XPostPreview, connectionKeys, mediaKeys, postKeys, profileKeys, tiktokKeys, toPreviewMedia, useCalendar, useConnect, useConnection, useConnections, useCreatePost, useCreateProfile, useDeleteMedia, useDeletePost, useDeleteProfile, useDisconnect, useDiscoverableAccounts, useInfiniteList, useMedia, useMediaInfinite, useMediaList, useMediaUpload, usePost, usePostrun, usePosts, usePostsInfinite, useProfile, useProfiles, useProfilesInfinite, useSelectAccount, useTikTokCreatorInfo, useUpdateMedia, useUpdatePost, useUpdateProfile, useValidatePost };
3356
+ export { ArticleCard, AudienceSelect, CommercialDisclosure, Connect, Declaration, DocumentCard, InstagramPostPreview, InteractionToggles, LinkedInPostPreview, Poll, PostrunProvider, ReelPreview, TikTokCaptionField, TikTokPostPreview, TikTokPublishPanel, XPoll, XPostPreview, connectionKeys, isReadyMedia, mediaKeys, postKeys, profileKeys, resolveVariantMedia, tiktokKeys, useCalendar, useConnect, useConnection, useConnections, useCreatePost, useCreateProfile, useDeleteMedia, useDeletePost, useDeleteProfile, useDisconnect, useDiscoverableAccounts, useInfiniteList, useMedia, useMediaInfinite, useMediaList, useMediaUpload, usePost, usePostrun, usePosts, usePostsInfinite, useProfile, useProfiles, useProfilesInfinite, useSelectAccount, useTikTokCreatorInfo, useUpdateMedia, useUpdatePost, useUpdateProfile, useValidatePost };
3331
3357
  //# sourceMappingURL=index.js.map
3332
3358
  //# sourceMappingURL=index.js.map