@select-org/post-components 2.0.0 → 2.1.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.d.ts CHANGED
@@ -47,8 +47,17 @@ interface PostCardProps {
47
47
  priority?: boolean;
48
48
  className?: string;
49
49
  }>;
50
+ /** Author's role in the group — drives the owner crown / admin shield badge. */
50
51
  isAdmin?: boolean;
52
+ /** Author's role in the group — drives the owner crown / admin shield badge. */
51
53
  isOwner?: boolean;
54
+ /**
55
+ * Whether the *viewer* is the post's author. Lets the author preview their own
56
+ * poll results before voting. Distinct from `isOwner` (which is the author's
57
+ * group role, for the badge) — pass it explicitly. When omitted, the author
58
+ * preview is simply off (the author sees results after voting, like anyone).
59
+ */
60
+ isPostOwner?: boolean;
52
61
  isPostPreview?: boolean;
53
62
  isPrivate?: boolean;
54
63
  membersCount?: number;
@@ -75,7 +84,7 @@ interface PostCardProps {
75
84
  onSend: (emoji: string) => void;
76
85
  }) => React.ReactNode;
77
86
  onNavigate?: (href: string, isInternal: boolean) => void;
78
- supportDeepviewDomain?: string;
87
+ supportDeepviewDomain?: string | string[];
79
88
  labels?: {
80
89
  cancelPost?: string;
81
90
  sending?: string;
@@ -122,6 +131,7 @@ interface PostHeaderProps {
122
131
  }) => string;
123
132
  isFeatured?: boolean;
124
133
  isPostPreview?: boolean;
134
+ isPostDetail?: boolean;
125
135
  isAdmin?: boolean;
126
136
  isOwner?: boolean;
127
137
  onErasePress?: () => void;
@@ -155,7 +165,7 @@ interface Props$a {
155
165
  hideEmailDescription?: boolean;
156
166
  isEmailPost?: boolean;
157
167
  onNavigate?: (href: string, isInternal: boolean) => void;
158
- supportDeepviewDomain?: string;
168
+ supportDeepviewDomain?: string | string[];
159
169
  }
160
170
  declare const PostBody: React.FC<Props$a>;
161
171
 
@@ -168,6 +178,17 @@ interface PostFooterProps {
168
178
  footerLinkHref?: string;
169
179
  isSnoozed?: boolean;
170
180
  onSnoozeToggle?: () => void;
181
+ /**
182
+ * Custom link renderer (e.g. Next.js `<Link>`) for the comment and footer
183
+ * links. Falls back to a native `<a>`. Passing this is important inside SPAs:
184
+ * a native `<a>` triggers a full-page reload, whereas the consumer's router
185
+ * link performs a soft client-side navigation.
186
+ */
187
+ linkComponent?: React.ComponentType<{
188
+ href: string;
189
+ children: React.ReactNode;
190
+ className?: string;
191
+ }>;
171
192
  renderReactionTrigger?: (props: {
172
193
  onOpen: () => void;
173
194
  }) => React.ReactNode;
@@ -193,6 +214,8 @@ interface Props$9 {
193
214
  className?: string;
194
215
  }>;
195
216
  mediaItemStatuses?: Record<string, MediaUploadStatus>;
217
+ onNavigate?: (href: string, isInternal: boolean) => void;
218
+ supportDeepviewDomain?: string | string[];
196
219
  }
197
220
  declare const PostItemsView: React.FC<Props$9>;
198
221
 
@@ -220,6 +243,8 @@ interface Props$6 {
220
243
  textItems: TextItemContent['items'];
221
244
  showFullText: boolean;
222
245
  isPostDetail: boolean;
246
+ onNavigate?: (href: string, isInternal: boolean) => void;
247
+ supportDeepviewDomain?: string | string[];
223
248
  }
224
249
  declare const PostTextItem: React.FC<Props$6>;
225
250
 
@@ -227,6 +252,17 @@ interface Props$5 {
227
252
  sections: SectionItem$1[];
228
253
  isPostDetail: boolean;
229
254
  onCardPress: () => void;
255
+ onNavigate?: (href: string, isInternal: boolean) => void;
256
+ supportDeepviewDomain?: string | string[];
257
+ imageComponent?: React.ComponentType<{
258
+ src: string;
259
+ alt: string;
260
+ fill?: boolean;
261
+ placeholder?: 'blur' | 'empty';
262
+ blurDataURL?: string;
263
+ priority?: boolean;
264
+ className?: string;
265
+ }>;
230
266
  }
231
267
  declare const PostSectionsView: React.FC<Props$5>;
232
268
 
@@ -236,6 +272,15 @@ interface Props$4 {
236
272
  username: string;
237
273
  url: string;
238
274
  };
275
+ imageComponent?: React.ComponentType<{
276
+ src: string;
277
+ alt: string;
278
+ fill?: boolean;
279
+ placeholder?: 'blur' | 'empty';
280
+ blurDataURL?: string;
281
+ priority?: boolean;
282
+ className?: string;
283
+ }>;
239
284
  }
240
285
  declare const PostSectionSourceInfoView: React.FC<Props$4>;
241
286
 
@@ -255,7 +300,7 @@ interface PostLinkItemProps {
255
300
  }>;
256
301
  onCloseClick?: () => void;
257
302
  type?: 'preview' | 'display';
258
- supportDeepviewDomain?: string;
303
+ supportDeepviewDomain?: string | string[];
259
304
  }
260
305
  declare const PostLinkItem: React.FC<PostLinkItemProps>;
261
306
 
@@ -306,7 +351,7 @@ interface AutoLinkProps {
306
351
  text: string;
307
352
  mentionData?: MentionData[];
308
353
  onNavigate?: (href: string, isInternal: boolean) => void;
309
- supportDeepviewDomain?: string;
354
+ supportDeepviewDomain?: string | string[];
310
355
  phone?: any;
311
356
  email?: any;
312
357
  stripPrefix?: boolean;
package/dist/index.js CHANGED
@@ -241,6 +241,7 @@ var PostHeader = ({
241
241
  translate,
242
242
  isFeatured = false,
243
243
  isPostPreview = false,
244
+ isPostDetail = false,
244
245
  isAdmin = false,
245
246
  isOwner = false,
246
247
  onErasePress,
@@ -328,7 +329,7 @@ var PostHeader = ({
328
329
  ),
329
330
  /* @__PURE__ */ jsxs("section", { className: "flex flex-1 flex-col justify-center min-w-0", children: [
330
331
  /* @__PURE__ */ jsx2("section", { className: "flex items-baseline justify-between gap-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 min-w-0", children: [
331
- /* @__PURE__ */ jsx2("div", { className: "font-semibold text-foreground truncate", children: authorNameNode }),
332
+ isPostDetail ? /* @__PURE__ */ jsx2("h2", { className: "font-semibold text-foreground truncate", children: authorNameNode }) : /* @__PURE__ */ jsx2("div", { className: "font-semibold text-foreground truncate", children: authorNameNode }),
332
333
  isFeatured && /* @__PURE__ */ jsx2(
333
334
  "svg",
334
335
  {
@@ -479,7 +480,8 @@ var checkMentionDataIndex = (mentionData = [], copyMentionData = [], body = "")
479
480
  };
480
481
  var isLinkInternal = (url, supportDeepviewDomain) => {
481
482
  if (!url) return false;
482
- return supportDeepviewDomain.length > 0 && url.includes(supportDeepviewDomain);
483
+ const domains = Array.isArray(supportDeepviewDomain) ? supportDeepviewDomain : supportDeepviewDomain ? [supportDeepviewDomain] : [];
484
+ return domains.some((d) => d.length > 0 && url.includes(d));
483
485
  };
484
486
  var getUrl = (match, phone) => {
485
487
  const type = match.getType();
@@ -572,7 +574,7 @@ var AutoLink = ({
572
574
  const renderLink = useCallback(
573
575
  (text, match, index) => {
574
576
  const [url] = getUrl(match, phone);
575
- if (supportDeepviewDomain && url.includes(supportDeepviewDomain)) {
577
+ if (isLinkInternal(url, supportDeepviewDomain)) {
576
578
  const internal = true;
577
579
  return /* @__PURE__ */ jsx3(
578
580
  "a",
@@ -1442,7 +1444,7 @@ var MediaView = ({
1442
1444
  return /* @__PURE__ */ jsx8(
1443
1445
  "div",
1444
1446
  {
1445
- onClick: handleLightbox,
1447
+ onClick: onCardPress,
1446
1448
  className: textViewClass,
1447
1449
  style: {
1448
1450
  backgroundColor: item.option_color
@@ -1828,7 +1830,12 @@ var PostPollView_default = PostPollView;
1828
1830
 
1829
1831
  // src/components/PostTextItem.tsx
1830
1832
  import { jsx as jsx14 } from "react/jsx-runtime";
1831
- var PostTextItem = ({ textItems, showFullText }) => {
1833
+ var PostTextItem = ({
1834
+ textItems,
1835
+ showFullText,
1836
+ onNavigate,
1837
+ supportDeepviewDomain
1838
+ }) => {
1832
1839
  return /* @__PURE__ */ jsx14("div", { className: "flex-1", children: /* @__PURE__ */ jsx14("div", { children: textItems.map((item, index) => {
1833
1840
  const text = "text" in item ? item.text ?? "" : "";
1834
1841
  const key = "key" in item ? item.key : index;
@@ -1838,6 +1845,8 @@ var PostTextItem = ({ textItems, showFullText }) => {
1838
1845
  {
1839
1846
  text: showFullText ? text : TruncateText(text, 300),
1840
1847
  mentionData,
1848
+ onNavigate,
1849
+ supportDeepviewDomain,
1841
1850
  className: "whitespace-normal px-4 pb-4 leading-relaxed text-gray-800",
1842
1851
  style: {
1843
1852
  whiteSpace: "pre-wrap",
@@ -1862,7 +1871,8 @@ var getHostFromUrl = (url) => {
1862
1871
  }
1863
1872
  };
1864
1873
  var getLinkRel = (host, supportDeepviewDomain = "") => {
1865
- const isInternal = supportDeepviewDomain.length > 0 && host.includes(supportDeepviewDomain);
1874
+ const domains = Array.isArray(supportDeepviewDomain) ? supportDeepviewDomain : supportDeepviewDomain ? [supportDeepviewDomain] : [];
1875
+ const isInternal = domains.some((d) => d.length > 0 && host.includes(d));
1866
1876
  return isInternal ? "noreferrer" : "noreferrer nofollow";
1867
1877
  };
1868
1878
  var PostLinkItem = ({
@@ -2226,7 +2236,9 @@ var PostItemsView = ({
2226
2236
  parentId,
2227
2237
  isCommentScope,
2228
2238
  imageComponent,
2229
- mediaItemStatuses
2239
+ mediaItemStatuses,
2240
+ onNavigate,
2241
+ supportDeepviewDomain
2230
2242
  }) => {
2231
2243
  if (!primaryContent) return null;
2232
2244
  switch (primaryContent.type) {
@@ -2258,7 +2270,8 @@ var PostItemsView = ({
2258
2270
  type: "linkItem"
2259
2271
  }
2260
2272
  ],
2261
- imageComponent
2273
+ imageComponent,
2274
+ supportDeepviewDomain
2262
2275
  }
2263
2276
  );
2264
2277
  case "media":
@@ -2278,7 +2291,9 @@ var PostItemsView = ({
2278
2291
  {
2279
2292
  textItems: primaryContent.items,
2280
2293
  showFullText: isPostDetail,
2281
- isPostDetail
2294
+ isPostDetail,
2295
+ onNavigate,
2296
+ supportDeepviewDomain
2282
2297
  }
2283
2298
  );
2284
2299
  default:
@@ -2354,20 +2369,27 @@ var contentTypeConstants = {
2354
2369
  };
2355
2370
 
2356
2371
  // src/components/PostSectionSourceInfoView.tsx
2372
+ import { Avatar as Avatar2, AvatarImage as AvatarImage2, AvatarFallback as AvatarFallback2 } from "@select-org/ui";
2357
2373
  import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
2358
- var PostSectionSourceInfoView = ({ sourceInfo }) => {
2374
+ var PostSectionSourceInfoView = ({
2375
+ sourceInfo,
2376
+ imageComponent
2377
+ }) => {
2359
2378
  if (!sourceInfo) {
2360
2379
  return null;
2361
2380
  }
2362
2381
  return /* @__PURE__ */ jsx20("div", { className: "mx-4 mb-3 mt-3 border-b border-gray-100 pb-3", children: /* @__PURE__ */ jsxs11("div", { className: "flex flex-row items-center", children: [
2363
- /* @__PURE__ */ jsx20("div", { className: "size-7 shrink-0 rounded-full overflow-hidden border border-border-subtle bg-muted flex items-center justify-center", children: sourceInfo.avatar ? /* @__PURE__ */ jsx20(
2364
- "img",
2365
- {
2366
- src: sourceInfo.avatar,
2367
- alt: sourceInfo.username,
2368
- className: "size-full object-cover"
2369
- }
2370
- ) : /* @__PURE__ */ jsx20("span", { className: "text-xs font-semibold text-muted-foreground", children: sourceInfo.username?.charAt(0)?.toUpperCase() ?? "?" }) }),
2382
+ /* @__PURE__ */ jsxs11(Avatar2, { size: "sm", className: "shrink-0 ring-1 ring-border-subtle", children: [
2383
+ /* @__PURE__ */ jsx20(
2384
+ AvatarImage2,
2385
+ {
2386
+ src: sourceInfo.avatar,
2387
+ alt: sourceInfo.username,
2388
+ imageComponent
2389
+ }
2390
+ ),
2391
+ /* @__PURE__ */ jsx20(AvatarFallback2, { name: sourceInfo.username, className: "text-xs" })
2392
+ ] }),
2371
2393
  /* @__PURE__ */ jsxs11("div", { className: "ml-2 flex-col justify-center flex", children: [
2372
2394
  /* @__PURE__ */ jsx20("div", { className: "text-sm font-semibold text-foreground leading-none", children: sourceInfo.username }),
2373
2395
  /* @__PURE__ */ jsx20("div", { className: "text-xs text-muted-foreground mt-1 leading-none", children: sourceInfo.url })
@@ -2381,7 +2403,10 @@ import { jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
2381
2403
  var PostSectionsView = ({
2382
2404
  sections,
2383
2405
  isPostDetail,
2384
- onCardPress
2406
+ onCardPress,
2407
+ onNavigate,
2408
+ supportDeepviewDomain,
2409
+ imageComponent
2385
2410
  }) => {
2386
2411
  const renderSectionItem = useCallback3(
2387
2412
  (section, index) => {
@@ -2396,14 +2421,22 @@ var PostSectionsView = ({
2396
2421
  whiteSpace: "pre-wrap",
2397
2422
  wordBreak: "break-word"
2398
2423
  },
2399
- mentionData: data.mentionData
2424
+ mentionData: data.mentionData,
2425
+ onNavigate,
2426
+ supportDeepviewDomain
2400
2427
  },
2401
2428
  `${index} - ${data.body}`
2402
2429
  );
2403
2430
  }
2404
2431
  if (type === contentTypeConstants.NEW_POST_MEDIA) {
2405
2432
  return /* @__PURE__ */ jsxs12("div", { className: "my-3", children: [
2406
- data.sourceInfo && /* @__PURE__ */ jsx21(PostSectionSourceInfoView_default, { sourceInfo: data.sourceInfo }),
2433
+ data.sourceInfo && /* @__PURE__ */ jsx21(
2434
+ PostSectionSourceInfoView_default,
2435
+ {
2436
+ sourceInfo: data.sourceInfo,
2437
+ imageComponent
2438
+ }
2439
+ ),
2407
2440
  data.body && /* @__PURE__ */ jsx21(
2408
2441
  AutoLink_default,
2409
2442
  {
@@ -2413,7 +2446,9 @@ var PostSectionsView = ({
2413
2446
  whiteSpace: "pre-wrap",
2414
2447
  wordBreak: "break-word"
2415
2448
  },
2416
- mentionData: data.mentionData
2449
+ mentionData: data.mentionData,
2450
+ onNavigate,
2451
+ supportDeepviewDomain
2417
2452
  },
2418
2453
  `${index} - ${data.body}`
2419
2454
  ),
@@ -2429,7 +2464,7 @@ var PostSectionsView = ({
2429
2464
  }
2430
2465
  return null;
2431
2466
  },
2432
- [isPostDetail, onCardPress]
2467
+ [isPostDetail, onCardPress, onNavigate, supportDeepviewDomain, imageComponent]
2433
2468
  );
2434
2469
  if (!sections || sections.length === 0) {
2435
2470
  return null;
@@ -2453,6 +2488,7 @@ var PostFooter = ({
2453
2488
  footerLinkHref = "/",
2454
2489
  isSnoozed = false,
2455
2490
  onSnoozeToggle,
2491
+ linkComponent: LinkComponent,
2456
2492
  renderReactionTrigger,
2457
2493
  renderReactionModal
2458
2494
  }) => {
@@ -2512,7 +2548,18 @@ var PostFooter = ({
2512
2548
  }
2513
2549
  }) })
2514
2550
  ] }),
2515
- /* @__PURE__ */ jsx22("div", { className: "relative flex items-center ml-auto", children: postHref ? /* @__PURE__ */ jsxs13(
2551
+ /* @__PURE__ */ jsx22("div", { className: "relative flex items-center ml-auto", children: postHref ? LinkComponent ? /* @__PURE__ */ jsxs13(
2552
+ LinkComponent,
2553
+ {
2554
+ href: postHref,
2555
+ className: cn(commentButtonClass, "no-underline"),
2556
+ children: [
2557
+ /* @__PURE__ */ jsx22(AppIcon, { name: "messageCircleMore", "aria-hidden": "true" }),
2558
+ /* @__PURE__ */ jsx22("span", { className: "sr-only", children: commentAriaLabel }),
2559
+ commentBadge
2560
+ ]
2561
+ }
2562
+ ) : /* @__PURE__ */ jsxs13(
2516
2563
  "a",
2517
2564
  {
2518
2565
  href: postHref,
@@ -2530,14 +2577,10 @@ var PostFooter = ({
2530
2577
  /* @__PURE__ */ jsx22(AppIcon, { name: "messageCircleMore", "aria-hidden": "true" }),
2531
2578
  commentBadge
2532
2579
  ] }) }),
2533
- showFooterLink && /* @__PURE__ */ jsx22("section", { className: "flex justify-center -mx-5 -mb-2.5 mt-2.5", children: /* @__PURE__ */ jsx22(
2534
- "a",
2535
- {
2536
- href: footerLinkHref,
2537
- className: "bg-action-primary/5 hover:bg-action-primary/10 transition-colors w-full text-center py-3 text-sm font-medium text-action-primary no-underline rounded-b-xl border-t border-action-primary/10",
2538
- children: footerLinkLabel
2539
- }
2540
- ) })
2580
+ showFooterLink && /* @__PURE__ */ (() => {
2581
+ const footerLinkClass = "bg-action-primary/5 hover:bg-action-primary/10 transition-colors w-full text-center py-3 text-sm font-medium text-action-primary no-underline rounded-b-xl border-t border-action-primary/10";
2582
+ return /* @__PURE__ */ jsx22("section", { className: "flex justify-center -mx-5 -mb-2.5 mt-2.5", children: LinkComponent ? /* @__PURE__ */ jsx22(LinkComponent, { href: footerLinkHref, className: footerLinkClass, children: footerLinkLabel }) : /* @__PURE__ */ jsx22("a", { href: footerLinkHref, className: footerLinkClass, children: footerLinkLabel }) });
2583
+ })()
2541
2584
  ] });
2542
2585
  };
2543
2586
  var PostFooter_default = PostFooter;
@@ -2758,6 +2801,7 @@ var PostCard = ({
2758
2801
  imageComponent,
2759
2802
  isAdmin,
2760
2803
  isOwner,
2804
+ isPostOwner,
2761
2805
  isPostPreview,
2762
2806
  isPrivate,
2763
2807
  membersCount,
@@ -2891,6 +2935,7 @@ var PostCard = ({
2891
2935
  postType: post.postType,
2892
2936
  isFeatured: post.isFeatured,
2893
2937
  isPostPreview,
2938
+ isPostDetail,
2894
2939
  isAdmin,
2895
2940
  isOwner,
2896
2941
  isPrivate,
@@ -2925,7 +2970,10 @@ var PostCard = ({
2925
2970
  sections: resolvedContent.sections.sections,
2926
2971
  isPostDetail,
2927
2972
  onCardPress: onCardPress ?? (() => {
2928
- })
2973
+ }),
2974
+ onNavigate,
2975
+ supportDeepviewDomain,
2976
+ imageComponent
2929
2977
  }
2930
2978
  ),
2931
2979
  /* @__PURE__ */ jsx25(
@@ -2937,11 +2985,13 @@ var PostCard = ({
2937
2985
  }),
2938
2986
  onVotePress: onVotePress ?? (() => {
2939
2987
  }),
2940
- isPostOwner: isOwner,
2988
+ isPostOwner,
2941
2989
  parentId: post.context_id,
2942
2990
  isCommentScope: false,
2943
2991
  imageComponent,
2944
- mediaItemStatuses
2992
+ mediaItemStatuses,
2993
+ onNavigate,
2994
+ supportDeepviewDomain
2945
2995
  }
2946
2996
  ),
2947
2997
  /* @__PURE__ */ jsx25(
@@ -2966,6 +3016,7 @@ var PostCard = ({
2966
3016
  showFooterLink,
2967
3017
  footerLinkLabel,
2968
3018
  footerLinkHref,
3019
+ linkComponent,
2969
3020
  renderReactionTrigger,
2970
3021
  renderReactionModal
2971
3022
  }