@flamingo-stack/openframe-frontend-core 0.0.255 → 0.0.256

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.
Files changed (147) hide show
  1. package/dist/{chunk-GYKDSPC4.cjs → chunk-3DC6MHW6.cjs} +31 -31
  2. package/dist/{chunk-GYKDSPC4.cjs.map → chunk-3DC6MHW6.cjs.map} +1 -1
  3. package/dist/{chunk-EFIEQ4XD.js → chunk-46DHPQY6.js} +4 -4
  4. package/dist/{chunk-RCW2IL4K.cjs → chunk-6F5CGBVT.cjs} +692 -728
  5. package/dist/chunk-6F5CGBVT.cjs.map +1 -0
  6. package/dist/{chunk-HMFBMVJC.js → chunk-6GBA6YJN.js} +2 -2
  7. package/dist/{chunk-4HHYUEMD.js → chunk-7RLV3U5C.js} +2 -2
  8. package/dist/{chunk-SGJBUL2Y.cjs → chunk-7VMEOFEA.cjs} +45 -2
  9. package/dist/chunk-7VMEOFEA.cjs.map +1 -0
  10. package/dist/{chunk-UGFSMA7K.cjs → chunk-CMWRZECW.cjs} +77 -42
  11. package/dist/chunk-CMWRZECW.cjs.map +1 -0
  12. package/dist/{chunk-D524LJYO.js → chunk-HCMVLEC3.js} +4 -4
  13. package/dist/{chunk-LZL6P7SN.cjs → chunk-IG4QRNYZ.cjs} +10 -10
  14. package/dist/{chunk-LZL6P7SN.cjs.map → chunk-IG4QRNYZ.cjs.map} +1 -1
  15. package/dist/{chunk-CVGZJBHT.cjs → chunk-ISALYOFX.cjs} +19 -19
  16. package/dist/{chunk-CVGZJBHT.cjs.map → chunk-ISALYOFX.cjs.map} +1 -1
  17. package/dist/{chunk-MKVKVJQQ.js → chunk-J3QMPOS6.js} +5 -4
  18. package/dist/chunk-J3QMPOS6.js.map +1 -0
  19. package/dist/{chunk-LHR7MBUY.js → chunk-JK25REDL.js} +48 -13
  20. package/dist/chunk-JK25REDL.js.map +1 -0
  21. package/dist/{chunk-Z4IBEIWD.cjs → chunk-LGLPNWS6.cjs} +3 -3
  22. package/dist/{chunk-Z4IBEIWD.cjs.map → chunk-LGLPNWS6.cjs.map} +1 -1
  23. package/dist/{chunk-VAUI3CND.js → chunk-NR535XIY.js} +44 -1
  24. package/dist/chunk-NR535XIY.js.map +1 -0
  25. package/dist/{chunk-2FCXJTOV.js → chunk-QXSRQVRO.js} +3 -1
  26. package/dist/chunk-QXSRQVRO.js.map +1 -0
  27. package/dist/{chunk-6TB24AUH.js → chunk-S7IX7YU4.js} +154 -190
  28. package/dist/chunk-S7IX7YU4.js.map +1 -0
  29. package/dist/{chunk-6LK4VEXE.cjs → chunk-TSZBJVYK.cjs} +35 -31
  30. package/dist/chunk-TSZBJVYK.cjs.map +1 -0
  31. package/dist/{chunk-TU26IZPO.cjs → chunk-U6UNAC32.cjs} +3 -1
  32. package/dist/chunk-U6UNAC32.cjs.map +1 -0
  33. package/dist/{chunk-265KKBV2.js → chunk-V4IIBNTA.js} +3 -3
  34. package/dist/chunk-V4IIBNTA.js.map +1 -0
  35. package/dist/{chunk-2FAX6LZB.cjs → chunk-V4Q5PIBV.cjs} +30 -30
  36. package/dist/{chunk-2FAX6LZB.cjs.map → chunk-V4Q5PIBV.cjs.map} +1 -1
  37. package/dist/{chunk-LKI3YCAX.js → chunk-V5L4D454.js} +10 -6
  38. package/dist/chunk-V5L4D454.js.map +1 -0
  39. package/dist/{chunk-3TDLFCCS.cjs → chunk-ZJP2BB3E.cjs} +6 -5
  40. package/dist/chunk-ZJP2BB3E.cjs.map +1 -0
  41. package/dist/components/chat/entity-cards/entity-author-card.d.ts +13 -9
  42. package/dist/components/chat/entity-cards/entity-author-card.d.ts.map +1 -1
  43. package/dist/components/chat/index.cjs +9 -7
  44. package/dist/components/chat/index.cjs.map +1 -1
  45. package/dist/components/chat/index.d.ts +1 -0
  46. package/dist/components/chat/index.d.ts.map +1 -1
  47. package/dist/components/chat/index.js +8 -6
  48. package/dist/components/chat/types/entities/onboarding-guide.d.ts +2 -7
  49. package/dist/components/chat/types/entities/onboarding-guide.d.ts.map +1 -1
  50. package/dist/components/contact/index.cjs +8 -8
  51. package/dist/components/contact/index.js +7 -7
  52. package/dist/components/faq/faq-section.d.ts.map +1 -1
  53. package/dist/components/faq/index.cjs +3 -3
  54. package/dist/components/faq/index.js +2 -2
  55. package/dist/components/features/index.cjs +7 -7
  56. package/dist/components/features/index.js +6 -6
  57. package/dist/components/icons/index.cjs +2 -2
  58. package/dist/components/icons/index.js +1 -1
  59. package/dist/components/index.cjs +166 -156
  60. package/dist/components/index.cjs.map +1 -1
  61. package/dist/components/index.js +54 -44
  62. package/dist/components/index.js.map +1 -1
  63. package/dist/components/navigation/index.cjs +7 -7
  64. package/dist/components/navigation/index.js +6 -6
  65. package/dist/components/onboarding-guides/index.cjs +25 -23
  66. package/dist/components/onboarding-guides/index.cjs.map +1 -1
  67. package/dist/components/onboarding-guides/index.js +6 -4
  68. package/dist/components/onboarding-guides/index.js.map +1 -1
  69. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts +4 -1
  70. package/dist/components/onboarding-guides/onboarding-guide-detail-view.d.ts.map +1 -1
  71. package/dist/components/related-content/index.cjs +10 -8
  72. package/dist/components/related-content/index.cjs.map +1 -1
  73. package/dist/components/related-content/index.d.ts +1 -1
  74. package/dist/components/related-content/index.d.ts.map +1 -1
  75. package/dist/components/related-content/index.js +9 -7
  76. package/dist/components/related-content/related-content-section.d.ts +16 -1
  77. package/dist/components/related-content/related-content-section.d.ts.map +1 -1
  78. package/dist/components/shared/product-release/release-detail-page.d.ts +4 -1
  79. package/dist/components/shared/product-release/release-detail-page.d.ts.map +1 -1
  80. package/dist/components/social-icon-row.d.ts +17 -4
  81. package/dist/components/social-icon-row.d.ts.map +1 -1
  82. package/dist/components/tickets/index.cjs +80 -80
  83. package/dist/components/tickets/index.js +8 -8
  84. package/dist/components/ui/button/button.d.ts.map +1 -1
  85. package/dist/components/ui/file-manager/index.cjs +20 -20
  86. package/dist/components/ui/file-manager/index.js +1 -1
  87. package/dist/components/ui/index.cjs +9 -7
  88. package/dist/components/ui/index.cjs.map +1 -1
  89. package/dist/components/ui/index.js +8 -6
  90. package/dist/hooks/index.cjs +3 -3
  91. package/dist/hooks/index.js +2 -2
  92. package/dist/index.cjs +12 -8
  93. package/dist/index.cjs.map +1 -1
  94. package/dist/index.js +16 -12
  95. package/dist/types/blog.d.ts +7 -0
  96. package/dist/types/blog.d.ts.map +1 -1
  97. package/dist/types/entity-author.d.ts +18 -0
  98. package/dist/types/entity-author.d.ts.map +1 -0
  99. package/dist/types/index.cjs.map +1 -1
  100. package/dist/types/index.d.ts +1 -0
  101. package/dist/types/index.d.ts.map +1 -1
  102. package/dist/types/index.js.map +1 -1
  103. package/dist/types/product-release.d.ts +2 -7
  104. package/dist/types/product-release.d.ts.map +1 -1
  105. package/dist/utils/common.d.ts +9 -0
  106. package/dist/utils/common.d.ts.map +1 -1
  107. package/dist/utils/index.cjs +6 -2
  108. package/dist/utils/index.cjs.map +1 -1
  109. package/dist/utils/index.d.ts +1 -1
  110. package/dist/utils/index.d.ts.map +1 -1
  111. package/dist/utils/index.js +6 -3
  112. package/dist/utils/index.js.map +1 -1
  113. package/package.json +1 -1
  114. package/src/components/chat/entity-cards/entity-author-card.tsx +30 -11
  115. package/src/components/chat/index.ts +1 -0
  116. package/src/components/chat/types/entities/onboarding-guide.ts +3 -7
  117. package/src/components/faq/faq-section.tsx +4 -1
  118. package/src/components/icons/x-logo.tsx +2 -2
  119. package/src/components/onboarding-guides/onboarding-guide-detail-view.tsx +5 -0
  120. package/src/components/related-content/index.ts +1 -0
  121. package/src/components/related-content/related-content-section.tsx +84 -8
  122. package/src/components/shared/product-release/release-detail-page.tsx +18 -21
  123. package/src/components/social-icon-row.tsx +51 -22
  124. package/src/components/ui/button/button.tsx +7 -0
  125. package/src/types/blog.ts +9 -1
  126. package/src/types/entity-author.ts +17 -0
  127. package/src/types/index.ts +1 -0
  128. package/src/types/product-release.ts +2 -7
  129. package/src/utils/common.ts +12 -0
  130. package/src/utils/index.ts +1 -1
  131. package/dist/chunk-265KKBV2.js.map +0 -1
  132. package/dist/chunk-2FCXJTOV.js.map +0 -1
  133. package/dist/chunk-3TDLFCCS.cjs.map +0 -1
  134. package/dist/chunk-6LK4VEXE.cjs.map +0 -1
  135. package/dist/chunk-6TB24AUH.js.map +0 -1
  136. package/dist/chunk-LHR7MBUY.js.map +0 -1
  137. package/dist/chunk-LKI3YCAX.js.map +0 -1
  138. package/dist/chunk-MKVKVJQQ.js.map +0 -1
  139. package/dist/chunk-RCW2IL4K.cjs.map +0 -1
  140. package/dist/chunk-SGJBUL2Y.cjs.map +0 -1
  141. package/dist/chunk-TU26IZPO.cjs.map +0 -1
  142. package/dist/chunk-UGFSMA7K.cjs.map +0 -1
  143. package/dist/chunk-VAUI3CND.js.map +0 -1
  144. /package/dist/{chunk-EFIEQ4XD.js.map → chunk-46DHPQY6.js.map} +0 -0
  145. /package/dist/{chunk-HMFBMVJC.js.map → chunk-6GBA6YJN.js.map} +0 -0
  146. /package/dist/{chunk-4HHYUEMD.js.map → chunk-7RLV3U5C.js.map} +0 -0
  147. /package/dist/{chunk-D524LJYO.js.map → chunk-HCMVLEC3.js.map} +0 -0
@@ -18,7 +18,7 @@ import {
18
18
  MiamiCyberGangLogoFaceOnly,
19
19
  OpenFrameLogo,
20
20
  OpenmspLogo
21
- } from "./chunk-265KKBV2.js";
21
+ } from "./chunk-V4IIBNTA.js";
22
22
  import {
23
23
  cn,
24
24
  init_cn
@@ -2939,4 +2939,4 @@ export {
2939
2939
  splitCsvEnv,
2940
2940
  useHumanitySignals
2941
2941
  };
2942
- //# sourceMappingURL=chunk-HMFBMVJC.js.map
2942
+ //# sourceMappingURL=chunk-6GBA6YJN.js.map
@@ -7,7 +7,7 @@ import {
7
7
  resolveExternalNavigation,
8
8
  resolveSourceIcon,
9
9
  stripSameOriginToPath
10
- } from "./chunk-LKI3YCAX.js";
10
+ } from "./chunk-V5L4D454.js";
11
11
  import {
12
12
  useDebounce
13
13
  } from "./chunk-ZXZJSTNV.js";
@@ -386,4 +386,4 @@ export {
386
386
  useDocSearch,
387
387
  DetailPageSkeleton
388
388
  };
389
- //# sourceMappingURL=chunk-4HHYUEMD.js.map
389
+ //# sourceMappingURL=chunk-7RLV3U5C.js.map
@@ -4,6 +4,42 @@
4
4
 
5
5
  var _chunkFIG2RKZFcjs = require('./chunk-FIG2RKZF.cjs');
6
6
 
7
+ // src/utils/common.ts
8
+ var _clsx = require('clsx');
9
+ var _tailwindmerge = require('tailwind-merge');
10
+ function cn2(...inputs) {
11
+ return _tailwindmerge.twMerge.call(void 0, _clsx.clsx.call(void 0, inputs));
12
+ }
13
+ function delay(ms) {
14
+ return new Promise((resolve) => setTimeout(resolve, ms));
15
+ }
16
+ function generateRandomString(length = 8) {
17
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
18
+ let result = "";
19
+ for (let i = 0; i < length; i++) {
20
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
21
+ }
22
+ return result;
23
+ }
24
+ function truncateString(str, maxLength, suffix = "...") {
25
+ if (str.length <= maxLength) return str;
26
+ return str.substring(0, maxLength - suffix.length) + suffix;
27
+ }
28
+ function serializeJsonLd(schema) {
29
+ return JSON.stringify(schema).replace(/</g, "\\u003c");
30
+ }
31
+ function deepClone(obj) {
32
+ return JSON.parse(JSON.stringify(obj));
33
+ }
34
+ function getSlackCommunityJoinUrl() {
35
+ const url = process.env.NEXT_PUBLIC_SLACK_COMMUNITY_JOIN_URL;
36
+ if (!url) {
37
+ console.warn("NEXT_PUBLIC_SLACK_COMMUNITY_JOIN_URL is not defined in environment variables");
38
+ return "https://join.slack.com/t/openmsp/shared_invite/zt-36bl7mx0h-3~U2nFH6nqHqoTPXMaHEHA";
39
+ }
40
+ return url;
41
+ }
42
+
7
43
  // src/utils/suggestion-url.ts
8
44
  function buildSuggestionUrl(path, opts = {}) {
9
45
  const qs = new URLSearchParams();
@@ -57,5 +93,12 @@ ChevronButton.displayName = "ChevronButton";
57
93
 
58
94
 
59
95
 
60
- exports.buildSuggestionUrl = buildSuggestionUrl; exports.ChevronButton = ChevronButton;
61
- //# sourceMappingURL=chunk-SGJBUL2Y.cjs.map
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+ exports.cn = cn2; exports.delay = delay; exports.generateRandomString = generateRandomString; exports.truncateString = truncateString; exports.serializeJsonLd = serializeJsonLd; exports.deepClone = deepClone; exports.getSlackCommunityJoinUrl = getSlackCommunityJoinUrl; exports.buildSuggestionUrl = buildSuggestionUrl; exports.ChevronButton = ChevronButton;
104
+ //# sourceMappingURL=chunk-7VMEOFEA.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-7VMEOFEA.cjs","../src/utils/common.ts","../src/utils/suggestion-url.ts","../src/components/ui/chevron-button.tsx"],"names":["cn"],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-7VMEOFEA.cjs","sourcesContent":[null,"import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\n/**\n * Utility functions for common operations\n */\n\n/**\n * Merge class names with Tailwind CSS\n * @param inputs - Class names to merge\n * @returns Merged class names\n */\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\n/**\n * Delay execution for a specified time\n * @param ms - Milliseconds to delay\n * @returns Promise that resolves after the delay\n */\nexport function delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Generate a random string of specified length\n * @param length - Length of the string\n * @returns Random string\n */\nexport function generateRandomString(length = 8): string {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"\n let result = \"\"\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length))\n }\n return result\n}\n\n/**\n * Truncate a string to a specified length\n * @param str - String to truncate\n * @param maxLength - Maximum length\n * @param suffix - Suffix to add to truncated string\n * @returns Truncated string\n */\nexport function truncateString(str: string, maxLength: number, suffix = \"...\"): string {\n if (str.length <= maxLength) return str\n return str.substring(0, maxLength - suffix.length) + suffix\n}\n\n/**\n * Serialize a JSON-LD schema for a `<script type=\"application/ld+json\">`\n * block — THE one home of the escape rule (the hub re-exports this from\n * lib/utils/breadcrumbs). JSON.stringify does NOT HTML-escape: a stored\n * \"</script>\" inside any admin/user-entered field would terminate the tag\n * early (stored XSS). Every \"<\" becomes the JSON escape sequence\n * backslash-u003c — still valid JSON, inert in HTML.\n */\nexport function serializeJsonLd(schema: unknown): string {\n return JSON.stringify(schema).replace(/</g, \"\\\\u003c\")\n}\n\n/**\n * Deep clone an object\n * @param obj - Object to clone\n * @returns Cloned object\n */\nexport function deepClone<T>(obj: T): T {\n return JSON.parse(JSON.stringify(obj))\n}\n\n/**\n * Get the Slack community join URL from environment variables\n * @returns Slack community join URL or fallback URL\n */\nexport function getSlackCommunityJoinUrl(): string {\n const url = process.env.NEXT_PUBLIC_SLACK_COMMUNITY_JOIN_URL\n if (!url) {\n console.warn('NEXT_PUBLIC_SLACK_COMMUNITY_JOIN_URL is not defined in environment variables')\n return 'https://join.slack.com/t/openmsp/shared_invite/zt-36bl7mx0h-3~U2nFH6nqHqoTPXMaHEHA'\n }\n return url\n}\n\n","/**\n * Shared fetch-URL composer for the two suggestion sections (FaqSection +\n * RelatedContentSection) — ONE owner of the entityType/entityId/count query\n * shape so the sections can never drift. Pure + server-safe.\n *\n * Byte-parity contract with the original `buildFaqsUrl`: when only\n * entityType/entityId are set, the param order is `entityType`, `entityId`;\n * with nothing set, the bare `path` is returned (no `?`).\n */\nexport interface SuggestionUrlOptions {\n /** Fetch-URL prefix for third-party embeds / reverse proxies\n * ('' = same-origin relative). */\n apiBaseUrl?: string\n /** Both required together for entity scope; partial → bare path. */\n entityType?: string\n entityId?: number | string\n /** Maps to the server's `count` param. Undefined → param not sent\n * (server default applies). */\n count?: number\n /** Extra query params appended after the shared trio (e.g. the\n * related-content `excludeTypes` deny-list). Empty/undefined values\n * are skipped. */\n extraParams?: Record<string, string | undefined>\n}\n\nexport function buildSuggestionUrl(path: string, opts: SuggestionUrlOptions = {}): string {\n const qs = new URLSearchParams()\n const { entityType, entityId } = opts\n if (entityType && entityId !== undefined && entityId !== null && entityId !== '') {\n qs.set('entityType', entityType)\n qs.set('entityId', String(entityId))\n }\n if (opts.count !== undefined) qs.set('count', String(opts.count))\n for (const [key, value] of Object.entries(opts.extraParams ?? {})) {\n if (value !== undefined && value !== '') qs.set(key, value)\n }\n const query = qs.toString()\n return `${opts.apiBaseUrl ?? ''}${path}${query ? `?${query}` : ''}`\n}\n","\"use client\"\n\nimport * as React from \"react\"\nimport { ChevronUp, ChevronDown } from \"lucide-react\"\nimport { cn } from \"../../utils/cn\"\n\ninterface ChevronButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n direction?: 'up' | 'down';\n size?: 'sm' | 'md' | 'lg';\n isExpanded?: boolean;\n backgroundColor?: string;\n borderColor?: string;\n}\n\nconst ChevronButton = React.forwardRef<HTMLButtonElement, ChevronButtonProps>(\n ({ className, direction = 'down', size = 'md', isExpanded, backgroundColor, borderColor, ...props }, ref) => {\n const Icon = (isExpanded ? ChevronUp : ChevronDown) || (direction === 'up' ? ChevronUp : ChevronDown);\n const sizeClasses = {\n sm: 'h-4 w-4',\n md: 'h-5 w-5', \n lg: 'h-6 w-6'\n };\n\n return (\n <button\n className={cn(\n \"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n \"h-10 px-4 py-2\",\n className\n )}\n style={{\n backgroundColor: backgroundColor,\n borderColor: borderColor\n }}\n ref={ref}\n {...props}\n >\n <Icon className={sizeClasses[size]} />\n </button>\n )\n }\n)\nChevronButton.displayName = \"ChevronButton\"\n\nexport { ChevronButton }"]}
@@ -25,22 +25,25 @@ var _chunkT7AJBKZPcjs = require('./chunk-T7AJBKZP.cjs');
25
25
 
26
26
 
27
27
 
28
- var _chunkRCW2IL4Kcjs = require('./chunk-RCW2IL4K.cjs');
29
28
 
30
29
 
31
- var _chunkSGJBUL2Ycjs = require('./chunk-SGJBUL2Y.cjs');
30
+ var _chunk6F5CGBVTcjs = require('./chunk-6F5CGBVT.cjs');
32
31
 
33
32
 
33
+ var _chunk7VMEOFEAcjs = require('./chunk-7VMEOFEA.cjs');
34
34
 
35
35
 
36
- var _chunk6LK4VEXEcjs = require('./chunk-6LK4VEXE.cjs');
36
+
37
+
38
+ var _chunkTSZBJVYKcjs = require('./chunk-TSZBJVYK.cjs');
37
39
 
38
40
  // src/components/related-content/related-content-section.tsx
39
41
  var _react = require('react');
42
+ _chunk6F5CGBVTcjs.init_pagination.call(void 0, );
40
43
  var _jsxruntime = require('react/jsx-runtime');
41
44
  function DefaultLinkPropsProvider({ href, targetPlatform, children }) {
42
45
  if (!href) return children(null);
43
- const newTab = _chunk6LK4VEXEcjs.decideNewTab.call(void 0, { href, targetPlatform, currentSource: "" });
46
+ const newTab = _chunkTSZBJVYKcjs.decideNewTab.call(void 0, { href, targetPlatform, currentSource: "" });
44
47
  return children(
45
48
  newTab ? { href, target: "_blank", rel: "noopener noreferrer" } : { href }
46
49
  );
@@ -52,27 +55,27 @@ function renderSkeletonForType(type, size, adminCampaignCard) {
52
55
  const legacySize = size === "sm" ? "sm" : "default";
53
56
  switch (type) {
54
57
  case "blog_post_existing":
55
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.BlogCardSkeleton, { size: legacySize });
58
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.BlogCardSkeleton, { size: legacySize });
56
59
  case "case_study":
57
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.CaseStudyCardSkeleton, { size: legacySize });
60
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.CaseStudyCardSkeleton, { size: legacySize });
58
61
  case "customer_interview":
59
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.CustomerInterviewCardSkeleton, { size: legacySize });
62
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.CustomerInterviewCardSkeleton, { size: legacySize });
60
63
  case "product_release":
61
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.ProductReleaseCardSkeleton, { size: size === "sm" ? "sm" : "lg" });
64
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.ProductReleaseCardSkeleton, { size: size === "sm" ? "sm" : "lg" });
62
65
  case "podcast":
63
66
  case "webinar":
64
67
  case "event":
65
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.ProgramCardSkeleton, { size: legacySize });
68
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.ProgramCardSkeleton, { size: legacySize });
66
69
  case "investor_update":
67
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.InvestorUpdateCardSkeleton, { size: legacySize });
70
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.InvestorUpdateCardSkeleton, { size: legacySize });
68
71
  case "onboarding_guide":
69
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6LK4VEXEcjs.OnboardingGuideCardSkeleton, { size: size === "sm" ? "sm" : "catalog" });
72
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTSZBJVYKcjs.OnboardingGuideCardSkeleton, { size: size === "sm" ? "sm" : "catalog" });
70
73
  case "marketing_campaign":
71
74
  return adminCampaignCard ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, adminCampaignCard.Skeleton, { size: legacySize }) : null;
72
75
  case "roadmap_item":
73
76
  case "delivery_item":
74
77
  case "internal_task":
75
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.RoadmapCardSkeleton, { size: legacySize });
78
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.RoadmapCardSkeleton, { size: legacySize });
76
79
  default:
77
80
  return null;
78
81
  }
@@ -92,17 +95,17 @@ function CardForType({
92
95
  const anchorAttrs = linkProps ? { target: linkProps.target, rel: linkProps.rel } : {};
93
96
  switch (type) {
94
97
  case "blog_post_existing":
95
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.BlogCard, { post: item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs });
98
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.BlogCard, { post: item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs });
96
99
  case "case_study":
97
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.CaseStudyCard, { study: item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs });
100
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.CaseStudyCard, { study: item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs });
98
101
  case "customer_interview":
99
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.CustomerInterviewCard, { interview: item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs });
102
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.CustomerInterviewCard, { interview: item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs });
100
103
  case "product_release": {
101
104
  const releaseSize = size === "sm" ? "sm" : "lg";
102
- const buildReleaseProps = _nullishCoalesce(_optionalChain([extras, 'optionalAccess', _4 => _4.buildProductReleaseCardProps]), () => ( _chunkRCW2IL4Kcjs.buildProductReleaseCardProps));
105
+ const buildReleaseProps = _nullishCoalesce(_optionalChain([extras, 'optionalAccess', _4 => _4.buildProductReleaseCardProps]), () => ( _chunk6F5CGBVTcjs.buildProductReleaseCardProps));
103
106
  const releaseProps = buildReleaseProps(item);
104
107
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
105
- _chunkRCW2IL4Kcjs.ProductReleaseCard,
108
+ _chunk6F5CGBVTcjs.ProductReleaseCard,
106
109
  {
107
110
  size: releaseSize,
108
111
  title: item.title,
@@ -114,22 +117,22 @@ function CardForType({
114
117
  );
115
118
  }
116
119
  case "podcast":
117
- return _optionalChain([extras, 'optionalAccess', _5 => _5.programConfigs, 'optionalAccess', _6 => _6.podcast]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.ProgramCard, { config: extras.programConfigs.podcast, item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs }) : null;
120
+ return _optionalChain([extras, 'optionalAccess', _5 => _5.programConfigs, 'optionalAccess', _6 => _6.podcast]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.ProgramCard, { config: extras.programConfigs.podcast, item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs }) : null;
118
121
  case "webinar":
119
- return _optionalChain([extras, 'optionalAccess', _7 => _7.programConfigs, 'optionalAccess', _8 => _8.webinar]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.ProgramCard, { config: extras.programConfigs.webinar, item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs }) : null;
122
+ return _optionalChain([extras, 'optionalAccess', _7 => _7.programConfigs, 'optionalAccess', _8 => _8.webinar]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.ProgramCard, { config: extras.programConfigs.webinar, item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs }) : null;
120
123
  case "event":
121
- return _optionalChain([extras, 'optionalAccess', _9 => _9.programConfigs, 'optionalAccess', _10 => _10.event]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.ProgramCard, { config: extras.programConfigs.event, item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs }) : null;
124
+ return _optionalChain([extras, 'optionalAccess', _9 => _9.programConfigs, 'optionalAccess', _10 => _10.event]) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.ProgramCard, { config: extras.programConfigs.event, item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs }) : null;
122
125
  case "investor_update":
123
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkRCW2IL4Kcjs.InvestorUpdateCard, { update: item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs });
126
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.InvestorUpdateCard, { update: item, size: legacySize, href, targetPlatform, placeholderUrl, ...anchorAttrs });
124
127
  case "onboarding_guide":
125
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6LK4VEXEcjs.OnboardingGuideCard, { guide: item, size: size === "sm" ? "sm" : "catalog", href, targetPlatform, placeholderUrl, ...anchorAttrs });
128
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTSZBJVYKcjs.OnboardingGuideCard, { guide: item, size: size === "sm" ? "sm" : "catalog", href, targetPlatform, placeholderUrl, ...anchorAttrs });
126
129
  case "marketing_campaign":
127
130
  return adminCampaignCard ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, adminCampaignCard.Card, { campaign: item }) : null;
128
131
  case "roadmap_item":
129
132
  case "delivery_item":
130
133
  case "internal_task":
131
134
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
132
- _chunkRCW2IL4Kcjs.RoadmapCard,
135
+ _chunk6F5CGBVTcjs.RoadmapCard,
133
136
  {
134
137
  item,
135
138
  href: _nullishCoalesce(href, () => ( "")),
@@ -150,20 +153,21 @@ function useGroupItems(type, refs, buildUrl) {
150
153
  const ids = refs.map((r) => r.id);
151
154
  const url = ids.length > 0 ? buildUrl(type, ids) : null;
152
155
  const { data, isLoading } = _chunkT7AJBKZPcjs.useSelfFetch.call(void 0, url);
153
- const items = data != null ? _chunkRCW2IL4Kcjs.extractItems.call(void 0, data) : null;
156
+ const items = data != null ? _chunk6F5CGBVTcjs.extractItems.call(void 0, data) : null;
154
157
  return { items, isLoading };
155
158
  }
156
159
  function gridClassFor(columns) {
157
160
  return columns === 3 ? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6" : "grid grid-cols-1 sm:grid-cols-2 gap-6";
158
161
  }
159
162
  function resolveGroupConfig(type) {
160
- return _nullishCoalesce(_chunkRCW2IL4Kcjs.CONTENT_REF_GROUPS[type], () => ( {
163
+ return _nullishCoalesce(_chunk6F5CGBVTcjs.CONTENT_REF_GROUPS[type], () => ( {
161
164
  label: type,
162
165
  order: 999,
163
166
  layout: "grid",
164
167
  gridSize: "default"
165
168
  }));
166
169
  }
170
+ var GROUP_PAGE_SIZE = 12;
167
171
  function ContentGroup({
168
172
  type,
169
173
  refs,
@@ -179,8 +183,21 @@ function ContentGroup({
179
183
  const config = resolveGroupConfig(type);
180
184
  const isListLayout = config.layout === "list";
181
185
  const cardSize = config.gridSize;
186
+ const [page, setPage] = _react.useState.call(void 0, 1);
187
+ const refsKey = refs.map((r) => r.id).join("|");
188
+ const prevRefsKeyRef = _react.useRef.call(void 0, refsKey);
189
+ _react.useEffect.call(void 0, () => {
190
+ if (prevRefsKeyRef.current !== refsKey) {
191
+ prevRefsKeyRef.current = refsKey;
192
+ setPage(1);
193
+ }
194
+ }, [refsKey]);
195
+ const totalGroupPages = Math.max(1, Math.ceil(refs.length / GROUP_PAGE_SIZE));
196
+ const safePage = Math.min(page, totalGroupPages);
197
+ const visibleGroupRefs = refs.length > GROUP_PAGE_SIZE ? refs.slice((safePage - 1) * GROUP_PAGE_SIZE, safePage * GROUP_PAGE_SIZE) : refs;
198
+ const groupPagination = totalGroupPages > 1 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6F5CGBVTcjs.Pagination, { currentPage: safePage, totalPages: totalGroupPages, onPageChange: setPage }) : null;
182
199
  if (isLoading && !items) {
183
- const skeletons = refs.map((r) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: renderSkeletonForType(type, cardSize, adminCampaignCard) }, r.id));
200
+ const skeletons = visibleGroupRefs.map((r) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { children: renderSkeletonForType(type, cardSize, adminCampaignCard) }, r.id));
184
201
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-4", children: [
185
202
  heading,
186
203
  isListLayout ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "space-y-4", children: skeletons }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: gridClassFor(columns), children: skeletons })
@@ -188,9 +205,9 @@ function ContentGroup({
188
205
  }
189
206
  if (!items || items.length === 0) return null;
190
207
  const itemById = new Map(
191
- items.map((it) => [_nullishCoalesce(_chunkRCW2IL4Kcjs.extractItemId.call(void 0, type, it), () => ( String(_optionalChain([it, 'optionalAccess', _11 => _11.id])))), it])
208
+ items.map((it) => [_nullishCoalesce(_chunk6F5CGBVTcjs.extractItemId.call(void 0, type, it), () => ( String(_optionalChain([it, 'optionalAccess', _11 => _11.id])))), it])
192
209
  );
193
- const cards = refs.map((contentRef) => {
210
+ const cards = visibleGroupRefs.map((contentRef) => {
194
211
  const itemId = String(contentRef.id);
195
212
  const item = itemById.get(itemId);
196
213
  if (!item) return null;
@@ -211,16 +228,26 @@ function ContentGroup({
211
228
  }
212
229
  ) }) }, itemId);
213
230
  }).filter(Boolean);
214
- if (cards.length === 0) return null;
231
+ if (cards.length === 0) {
232
+ if (groupPagination) {
233
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-4", children: [
234
+ heading,
235
+ groupPagination
236
+ ] });
237
+ }
238
+ return null;
239
+ }
215
240
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-4", children: [
216
241
  heading,
217
- isListLayout ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "space-y-4", children: cards }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: gridClassFor(columns), children: cards })
242
+ isListLayout ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "space-y-4", children: cards }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: gridClassFor(columns), children: cards }),
243
+ groupPagination
218
244
  ] });
219
245
  }
220
246
  function RelatedContentSection({
221
247
  contentRefs,
222
248
  entityType,
223
249
  entityId,
250
+ authorId,
224
251
  minResults,
225
252
  sameTypeMinResults,
226
253
  includeTypes,
@@ -236,17 +263,24 @@ function RelatedContentSection({
236
263
  adminCampaignCard
237
264
  }) {
238
265
  const suggestionsDisabled = _optionalChain([includeTypes, 'optionalAccess', _12 => _12.length]) === 0;
239
- const suggestUrl = contentRefs === void 0 && entityType && entityId !== void 0 && entityId !== null && entityId !== "" && !suggestionsDisabled ? _chunkSGJBUL2Ycjs.buildSuggestionUrl.call(void 0, "/api/related-content", {
266
+ const typeFilterParams = {
267
+ types: includeTypes !== void 0 ? includeTypes.join(",") : void 0,
268
+ excludeTypes: excludeTypes && excludeTypes.length > 0 ? excludeTypes.join(",") : void 0
269
+ };
270
+ const authorUrl = contentRefs === void 0 && authorId && !suggestionsDisabled ? _chunk7VMEOFEAcjs.buildSuggestionUrl.call(void 0, "/api/related-content", {
271
+ apiBaseUrl,
272
+ extraParams: { authorId, ...typeFilterParams }
273
+ }) : null;
274
+ const suggestUrl = _nullishCoalesce(authorUrl, () => ( (contentRefs === void 0 && entityType && entityId !== void 0 && entityId !== null && entityId !== "" && !suggestionsDisabled ? _chunk7VMEOFEAcjs.buildSuggestionUrl.call(void 0, "/api/related-content", {
240
275
  apiBaseUrl,
241
276
  entityType,
242
277
  entityId,
243
278
  count: minResults,
244
279
  extraParams: {
245
280
  sameTypeCount: sameTypeMinResults !== void 0 ? String(sameTypeMinResults) : void 0,
246
- types: includeTypes !== void 0 ? includeTypes.join(",") : void 0,
247
- excludeTypes: excludeTypes && excludeTypes.length > 0 ? excludeTypes.join(",") : void 0
281
+ ...typeFilterParams
248
282
  }
249
- }) : null;
283
+ }) : null)));
250
284
  const initialData = _react.useMemo.call(void 0,
251
285
  // An explicitly disabled rail (includeTypes: []) must ignore SSR-hydrated
252
286
  // refs too — otherwise useSelfFetch(null, {initialData}) keeps serving
@@ -256,7 +290,7 @@ function RelatedContentSection({
256
290
  );
257
291
  const { data } = _chunkT7AJBKZPcjs.useSelfFetch.call(void 0, suggestUrl, { initialData });
258
292
  const effectiveBuildListUrl = _react.useMemo.call(void 0,
259
- () => _nullishCoalesce(buildListUrl2, () => ( ((type, ids) => _chunkRCW2IL4Kcjs.buildListUrl.call(void 0, type, ids, apiBaseUrl)))),
293
+ () => _nullishCoalesce(buildListUrl2, () => ( ((type, ids) => _chunk6F5CGBVTcjs.buildListUrl.call(void 0, type, ids, apiBaseUrl)))),
260
294
  [buildListUrl2, apiBaseUrl]
261
295
  );
262
296
  const refs = _nullishCoalesce(_nullishCoalesce(contentRefs, () => ( _optionalChain([data, 'optionalAccess', _13 => _13.refs]))), () => ( []));
@@ -268,12 +302,12 @@ function RelatedContentSection({
268
302
  if (!grouped[ref.type]) grouped[ref.type] = [];
269
303
  grouped[ref.type].push(ref);
270
304
  }
271
- let orderedTypes = _chunkRCW2IL4Kcjs.orderContentRefTypes.call(void 0, Object.keys(grouped));
305
+ let orderedTypes = _chunk6F5CGBVTcjs.orderContentRefTypes.call(void 0, Object.keys(grouped));
272
306
  if (entityType) {
273
- const canonicalEntityType = _chunkRCW2IL4Kcjs.canonicalContentRefType.call(void 0, entityType);
274
- const sameType = orderedTypes.filter((t) => _chunkRCW2IL4Kcjs.canonicalContentRefType.call(void 0, t) === canonicalEntityType);
307
+ const canonicalEntityType = _chunk6F5CGBVTcjs.canonicalContentRefType.call(void 0, entityType);
308
+ const sameType = orderedTypes.filter((t) => _chunk6F5CGBVTcjs.canonicalContentRefType.call(void 0, t) === canonicalEntityType);
275
309
  if (sameType.length > 0) {
276
- orderedTypes = [...sameType, ...orderedTypes.filter((t) => _chunkRCW2IL4Kcjs.canonicalContentRefType.call(void 0, t) !== canonicalEntityType)];
310
+ orderedTypes = [...sameType, ...orderedTypes.filter((t) => _chunk6F5CGBVTcjs.canonicalContentRefType.call(void 0, t) !== canonicalEntityType)];
277
311
  }
278
312
  }
279
313
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "space-y-8", children: [
@@ -289,7 +323,7 @@ function RelatedContentSection({
289
323
  LinkProvider,
290
324
  extras,
291
325
  adminCampaignCard,
292
- heading: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "font-['Azeret_Mono'] text-[14px] font-semibold uppercase text-ods-text-secondary tracking-wider", children: _chunkRCW2IL4Kcjs.getContentRefLabelOrTitleCase.call(void 0, type) })
326
+ heading: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "font-['Azeret_Mono'] text-[14px] font-semibold uppercase text-ods-text-secondary tracking-wider", children: _chunk6F5CGBVTcjs.getContentRefLabelOrTitleCase.call(void 0, type) })
293
327
  },
294
328
  type
295
329
  ))
@@ -298,5 +332,6 @@ function RelatedContentSection({
298
332
 
299
333
 
300
334
 
301
- exports.RelatedContentSection = RelatedContentSection;
302
- //# sourceMappingURL=chunk-UGFSMA7K.cjs.map
335
+
336
+ exports.GROUP_PAGE_SIZE = GROUP_PAGE_SIZE; exports.RelatedContentSection = RelatedContentSection;
337
+ //# sourceMappingURL=chunk-CMWRZECW.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-CMWRZECW.cjs","../src/components/related-content/related-content-section.tsx"],"names":["buildListUrl"],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-CMWRZECW.cjs","sourcesContent":[null,"\"use client\";\n\n/**\n * RelatedContentSection\n *\n * Renders content references grouped by type using the canonical card\n * components. MOVED from the hub (`components/shared/related-content-card.tsx`)\n * so any consuming app can embed it; the hub keeps a thin wrapper that\n * pre-binds its host-specific injections (nav hook, URL recomposition,\n * program configs, admin campaign card).\n *\n * THREE data modes (precedence top-down):\n * 1. CONTROLLED — `contentRefs` provided (even `[]`): render exactly those\n * refs, no suggestion fetch (the original investor-update behavior).\n * 2. SUGGESTION — `entityType` + `entityId` provided: self-fetch\n * `GET {apiBaseUrl}/api/related-content?entityType&entityId[&count][&excludeTypes]`\n * (the generic 5-tier engine's second web service). `minResults` maps to\n * `count`; absent → param not sent (server default applies). Each ref\n * carries a `reason` (data-only — never rendered, matching the\n * FaqSection/FaqWithReason precedent).\n * 3. SSR-HYDRATED suggestion — also pass `initialItems` (the server page\n * called the engine directly); the first client fetch is skipped per the\n * `useSelfFetch` initialData contract.\n *\n * Group layout (list vs grid) + card size (lg vs default) come from\n * `CONTENT_REF_GROUPS` in `../../utils/content-ref-groups` — single source of\n * truth, no per-type logic in this file. Skeletons come from\n * `renderSkeletonForType` so the placeholder height matches the loaded card\n * exactly (zero layout shift on resolve).\n *\n * One API call per content type via the shared list-URL builder\n * (`buildListUrl` — injectable; defaults to the lib's byte-parity-tested\n * builder prefixed with `apiBaseUrl`). Fetching uses `useSelfFetch` (plain\n * fetch, NO react-query) so third-party embedders need no QueryClientProvider;\n * cards are imported via DEEP module paths (not the chat barrel) so this\n * chunk never reaches `@tanstack/react-query`.\n *\n * LOCKSTEP NOTE: this file's per-type card/skeleton dispatch is the SIZED\n * sibling of the chat-side `CHAT_CARD_REGISTRY` (`../chat/entity-cards/\n * dispatch.tsx`), which renders compact `size='sm'` cards wired to the chat\n * runtime. Two dispatchers by design — when registering a new fetch-mode\n * content type, add it BOTH there and here (cards + skeleton + list URL).\n */\n\nimport React, { useEffect, useMemo, useRef, useState } from 'react';\nimport {\n CONTENT_REF_GROUPS,\n getContentRefLabelOrTitleCase,\n orderContentRefTypes,\n type ContentRefGroupConfig,\n} from '../../utils/content-ref-groups';\nimport type { ContentRef, ContentRefWithReason } from '../../types/content-ref';\nimport { useSelfFetch } from '../../hooks/use-self-fetch';\nimport { Pagination } from '../pagination';\nimport { extractItems, extractItemId } from '../../utils/extract-items';\nimport { buildListUrl as libBuildListUrl, canonicalContentRefType } from '../../utils/list-url';\nimport { buildSuggestionUrl } from '../../utils/suggestion-url';\nimport { decideNewTab } from '../chat/utils/decide-new-tab';\n// DEEP card imports — NOT the `../chat` barrel (the barrel statically reaches\n// @tanstack/react-query via embeddable-chat + its hooks). Deep paths keep this\n// component's SOURCE graph react-query-free. Note: tsup's shared-chunk\n// splitting may still colocate the cards with chat hooks in one dist chunk\n// (react-query is a required peerDep, so resolution always succeeds) — the\n// guarantee that matters here is the RUNTIME one: nothing on this path ever\n// instantiates a QueryClient, so embedders need NO QueryClientProvider.\nimport { BlogCard, BlogCardSkeleton } from '../chat/entity-cards/blog-card';\nimport { CaseStudyCard, CaseStudyCardSkeleton } from '../chat/entity-cards/case-study-card';\nimport { CustomerInterviewCard, CustomerInterviewCardSkeleton } from '../chat/entity-cards/customer-interview-card';\nimport { ProductReleaseCard, ProductReleaseCardSkeleton } from '../chat/entity-cards/product-release-card';\nimport { buildProductReleaseCardProps } from '../chat/entity-cards/product-release-card-defaults';\nimport { ProgramCard, ProgramCardSkeleton } from '../chat/entity-cards/program-card';\nimport { InvestorUpdateCard, InvestorUpdateCardSkeleton } from '../chat/entity-cards/investor-update-card';\nimport { OnboardingGuideCard, OnboardingGuideCardSkeleton } from '../chat/entity-cards/onboarding-guide-card';\nimport { RoadmapCard, RoadmapCardSkeleton } from '../chat/entity-cards/roadmap-card';\n// Type-only — erased at build, no runtime dependency on the dispatch module.\nimport type { ChatCardDispatchExtras } from '../chat/entity-cards/dispatch';\n\ntype CardSize = 'lg' | 'default' | 'sm';\n\n/** Anchor prop bundle the per-card link surface receives — same shape the\n * hub's `useNavLink` returns and the chat dispatcher's anchor builders\n * produce. `null` = non-anchor mode (no URL). */\nexport interface CardLinkAnchorProps {\n href: string;\n target?: '_blank';\n rel?: 'noopener noreferrer';\n onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void;\n}\n\n/** Render-prop component injection for the navigation decision — keeps hook\n * calls legal (hooks live INSIDE the injected component; `CardForType`\n * itself calls zero hooks). The hub injects a `useNavLink`-backed provider;\n * the default is hook-free (pure `decideNewTab`). MUST be defined at module\n * scope by hosts — an inline arrow would remount every card each render. */\nexport interface CardLinkProviderProps {\n href: string | null;\n targetPlatform: string | null;\n children: (linkProps: CardLinkAnchorProps | null) => React.ReactElement | null;\n}\nexport type CardLinkProvider = React.ComponentType<CardLinkProviderProps>;\n\n/** Default link provider for standalone embeds: relative/-same-origin hrefs\n * stay same-tab, cross-origin pops a new tab (pure `decideNewTab` with no\n * platform context — `currentSource: ''` falls through to the origin\n * check). No router integration, no hooks. */\nfunction DefaultLinkPropsProvider({ href, targetPlatform, children }: CardLinkProviderProps): React.ReactElement | null {\n if (!href) return children(null);\n const newTab = decideNewTab({ href, targetPlatform, currentSource: '' });\n return children(\n newTab\n ? { href, target: '_blank', rel: 'noopener noreferrer' }\n : { href },\n );\n}\n\n/** Default href resolution: trust the ref's stored url/targetPlatform as the\n * API composed them. The hub overrides this with its `buildContentURL`\n * re-composition so dev gets localhost and prod gets platform domains. */\nfunction defaultResolveHref(ref: ContentRef): { href: string | null; targetPlatform: string | null } {\n return { href: ref.url || null, targetPlatform: ref.targetPlatform ?? null };\n}\n\n/** Host-injected renderer pair for the admin-only `marketing_campaign` type.\n * Absent (every non-hub embed) → the type renders nothing (its list URL\n * hits `/api/admin`, unreachable outside the hub anyway). */\nexport interface AdminCampaignCardSlot {\n Card: React.ComponentType<{ campaign: any }>;\n Skeleton: React.ComponentType<{ size?: 'default' | 'sm' }>;\n}\n\n/**\n * Per-type skeleton dispatch — returns the SAME colocated skeleton the\n * resolved card renders, sized to match (zero layout shift on resolve).\n * The chat-side `CHAT_CARD_REGISTRY` already does this via\n * `entry.skeleton()`; this surface exposes the same discipline to the\n * related-content rail.\n */\nfunction renderSkeletonForType(\n type: string,\n size: CardSize,\n adminCampaignCard?: AdminCampaignCardSlot,\n): React.ReactNode {\n // Most card skeletons accept only `{default, sm}`. `'lg'` collapses to\n // `'default'`. ProductReleaseCardSkeleton uses lg/sm pair.\n const legacySize: 'default' | 'sm' = size === 'sm' ? 'sm' : 'default';\n switch (type) {\n case 'blog_post_existing':\n return <BlogCardSkeleton size={legacySize} />;\n case 'case_study':\n return <CaseStudyCardSkeleton size={legacySize} />;\n case 'customer_interview':\n return <CustomerInterviewCardSkeleton size={legacySize} />;\n case 'product_release':\n return <ProductReleaseCardSkeleton size={size === 'sm' ? 'sm' : 'lg'} />;\n case 'podcast':\n case 'webinar':\n case 'event':\n return <ProgramCardSkeleton size={legacySize} />;\n case 'investor_update':\n return <InvestorUpdateCardSkeleton size={legacySize} />;\n case 'onboarding_guide':\n // The rich catalog variant (hero + author grid, clamped description) —\n // the step-numbered 'default' variant is for the guide detail page's\n // \"More in section\" rail, not this full-width row.\n return <OnboardingGuideCardSkeleton size={size === 'sm' ? 'sm' : 'catalog'} />;\n case 'marketing_campaign':\n return adminCampaignCard ? <adminCampaignCard.Skeleton size={legacySize} /> : null;\n case 'roadmap_item':\n case 'delivery_item':\n case 'internal_task':\n return <RoadmapCardSkeleton size={legacySize} />;\n default:\n return null;\n }\n}\n\n/**\n * Per-type card dispatch — renders the right card with the right size.\n * Sized cards (`'lg'` / `'default'`) are unique to this rail — the chat\n * dispatcher only renders `'sm'`, so we go directly through the per-type\n * cards here.\n *\n * PURE FUNCTION COMPONENT WITH ZERO HOOK CALLS: the placeholder comes from a\n * plain `extras.buildOgPlaceholderUrl` call (the chat `dispatch.tsx`\n * pattern) and the anchor-prop bundle arrives via the `LinkProvider`\n * render-prop from the parent — so per-card hook legality is owned by the\n * injected provider component, not by this switch.\n *\n * `href` comes from the host's `resolveHref(ref)` (hub: live\n * `buildContentURL` recomposition; default: the ref's stored url).\n */\nfunction CardForType({\n type,\n item,\n size,\n href,\n targetPlatform,\n linkProps,\n extras,\n adminCampaignCard,\n}: {\n type: string;\n item: any;\n size: CardSize;\n href: string;\n targetPlatform: string | null;\n linkProps: CardLinkAnchorProps | null;\n extras?: ChatCardDispatchExtras;\n adminCampaignCard?: AdminCampaignCardSlot;\n}): React.ReactNode {\n // Most card variants accept only `{default, sm}`. `'lg'` collapses to\n // `'default'` for those. ProductReleaseCard uses its own lg/sm pair.\n const legacySize: 'default' | 'sm' = size === 'sm' ? 'sm' : 'default';\n // OG placeholder URL — injected into the pure-presentation cards so they\n // render a branded fallback when the row's featured image is null. Plain\n // function call (NOT a hook). Title is the universal field across all card\n // item shapes used here.\n const placeholderUrl =\n extras?.buildOgPlaceholderUrl?.((item?.title as string | undefined) ?? '') ?? undefined;\n\n // Top-level target/rel for cards that take them as separate props\n // (BlogCard, CaseStudyCard, …). ProductReleaseCard takes the bundle as a\n // single `anchorProps={...}` and uses `linkProps` directly. When the host\n // didn't surface a URL, `linkProps` is null and the card stays in\n // non-anchor mode.\n const anchorAttrs: Pick<CardLinkAnchorProps, 'target' | 'rel'> = linkProps\n ? { target: linkProps.target, rel: linkProps.rel }\n : {};\n\n switch (type) {\n case 'blog_post_existing':\n return <BlogCard post={item} size={legacySize} href={href} targetPlatform={targetPlatform} placeholderUrl={placeholderUrl} {...anchorAttrs} />;\n case 'case_study':\n return <CaseStudyCard study={item} size={legacySize} href={href} targetPlatform={targetPlatform} placeholderUrl={placeholderUrl} {...anchorAttrs} />;\n case 'customer_interview':\n return <CustomerInterviewCard interview={item} size={legacySize} href={href} targetPlatform={targetPlatform} placeholderUrl={placeholderUrl} {...anchorAttrs} />;\n case 'product_release': {\n // Anchor-prop pattern: build product-release lg-variant props from the\n // shared `buildProductReleaseCardProps` so this rail and the /releases\n // catalog page render byte-identically. The card wraps in\n // `<a {...anchorProps}>` ONLY when `anchorProps.href` is set — pass\n // `undefined` (not an empty object) when href is empty so the card\n // stays in non-anchor mode without rendering a dead <a> tag.\n const releaseSize = size === 'sm' ? 'sm' : 'lg';\n const buildReleaseProps = extras?.buildProductReleaseCardProps ?? buildProductReleaseCardProps;\n const releaseProps = buildReleaseProps(item);\n return (\n <ProductReleaseCard\n size={releaseSize}\n title={item.title}\n summary={item.summary}\n version={item.version}\n {...releaseProps}\n anchorProps={linkProps ?? undefined}\n />\n );\n }\n case 'podcast':\n return extras?.programConfigs?.podcast\n ? <ProgramCard config={extras.programConfigs.podcast} item={item} size={legacySize} href={href} targetPlatform={targetPlatform} placeholderUrl={placeholderUrl} {...anchorAttrs} />\n : null;\n case 'webinar':\n return extras?.programConfigs?.webinar\n ? <ProgramCard config={extras.programConfigs.webinar} item={item} size={legacySize} href={href} targetPlatform={targetPlatform} placeholderUrl={placeholderUrl} {...anchorAttrs} />\n : null;\n case 'event':\n return extras?.programConfigs?.event\n ? <ProgramCard config={extras.programConfigs.event} item={item} size={legacySize} href={href} targetPlatform={targetPlatform} placeholderUrl={placeholderUrl} {...anchorAttrs} />\n : null;\n case 'investor_update':\n return <InvestorUpdateCard update={item} size={legacySize} href={href} targetPlatform={targetPlatform} placeholderUrl={placeholderUrl} {...anchorAttrs} />;\n case 'onboarding_guide':\n // Catalog variant (see skeleton note) — full-width rich card with a\n // line-clamped description instead of the step-numbered rail card.\n return <OnboardingGuideCard guide={item} size={size === 'sm' ? 'sm' : 'catalog'} href={href} targetPlatform={targetPlatform} placeholderUrl={placeholderUrl} {...anchorAttrs} />;\n case 'marketing_campaign':\n return adminCampaignCard ? <adminCampaignCard.Card campaign={item} /> : null;\n case 'roadmap_item':\n case 'delivery_item':\n case 'internal_task':\n return (\n <RoadmapCard\n item={item}\n href={href ?? ''}\n targetPlatform={targetPlatform}\n userVote={null}\n onVote={() => {}}\n size={legacySize}\n cardType={type as 'roadmap_item' | 'delivery_item' | 'internal_task'}\n {...anchorAttrs}\n />\n );\n default:\n return null;\n }\n}\n\n// =============================================================================\n// Fetch all items for a type in ONE server-sorted call, via the injectable\n// list-URL builder. `useSelfFetch` (URL = cache key) replaces the hub's old\n// react-query usage: `enabled` ≙ `url === null`, `!res.ok`/network error ≙\n// `error → items null → group renders nothing`. Accepted deltas vs\n// react-query: no retry/backoff, no focus refetch, no cross-mount cache.\n// =============================================================================\n\nfunction useGroupItems(\n type: string,\n refs: ContentRef[],\n buildUrl: (type: string, ids: string[]) => string | null,\n) {\n const ids = refs.map((r) => r.id);\n const url = ids.length > 0 ? buildUrl(type, ids) : null;\n const { data, isLoading } = useSelfFetch<unknown>(url);\n const items = data != null ? extractItems(data) : null;\n return { items, isLoading };\n}\n\n// =============================================================================\n// Per-group renderer — one API call, server-sorted, then render cards via the\n// dispatcher with per-type skeletons + per-type layout from CONTENT_REF_GROUPS.\n// =============================================================================\n\n/** Map columns prop → tailwind grid class. Only consulted for grid-layout\n * groups; list-layout groups stack vertically. */\nfunction gridClassFor(columns: 2 | 3): string {\n return columns === 3\n ? 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6'\n : 'grid grid-cols-1 sm:grid-cols-2 gap-6';\n}\n\n/** Resolve the group config for a type, falling back to a grid layout with\n * the default card size for unregistered types so the section still renders\n * rather than silently dropping them. The `label` field on the fallback is\n * intentionally a placeholder — the section heading goes through\n * `getContentRefLabelOrTitleCase(type)` instead so cross-surface labels\n * stay consistent between this rail and the investor-email builder. */\nfunction resolveGroupConfig(type: string): ContentRefGroupConfig {\n return CONTENT_REF_GROUPS[type] ?? {\n label: type,\n order: 999,\n layout: 'grid',\n gridSize: 'default',\n };\n}\n\n/** Items per page within one type group. Groups larger than this paginate\n * with the standard Pagination control (NO nested scrolling — a bounded\n * scrollbox inside the page traps wheel events and hides the sections\n * below it). MUST stay at or above the largest suggestion fill\n * (RELATED_SAME_TYPE_COUNT in the hub's lib/constants/suggestions.ts) so\n * current rails never paginate — only genuinely big groups (author pages)\n * do. Exported through the subpath barrel for the hub's module-load\n * assertion of that relation (entity-suggestion-sections.tsx). */\nexport const GROUP_PAGE_SIZE = 12;\n\nfunction ContentGroup({\n type,\n refs,\n columns,\n buildUrl,\n resolveHref,\n LinkProvider,\n extras,\n adminCampaignCard,\n heading,\n}: {\n type: string;\n refs: ContentRef[];\n columns: 2 | 3;\n buildUrl: (type: string, ids: string[]) => string | null;\n resolveHref: (ref: ContentRef) => { href: string | null; targetPlatform: string | null };\n LinkProvider: CardLinkProvider;\n extras?: ChatCardDispatchExtras;\n adminCampaignCard?: AdminCampaignCardSlot;\n /** Group heading, rendered INSIDE the group so a group that resolves to\n * nothing (fetch miss / unsupported type / missing program config) drops\n * its heading too — no orphaned titles. */\n heading: React.ReactNode;\n}) {\n const { items, isLoading } = useGroupItems(type, refs, buildUrl);\n const config = resolveGroupConfig(type);\n const isListLayout = config.layout === 'list';\n const cardSize = config.gridSize;\n\n // Per-group pagination for big groups (author pages): GROUP_PAGE_SIZE items\n // per page with the standard Pagination control below the group. Client-side\n // slicing — useGroupItems already fetched every row in one batched call, so\n // page flips are instant. Hooks live above every early return (file\n // convention). Page is clamped so a shrinking refs array (suggestion\n // refetch) can never strand the view past the last page, and RESET when the\n // ref set actually changes (shrink→grow must not return to a stale page).\n const [page, setPage] = useState(1);\n const refsKey = refs.map((r) => r.id).join('|');\n const prevRefsKeyRef = useRef(refsKey);\n useEffect(() => {\n if (prevRefsKeyRef.current !== refsKey) {\n prevRefsKeyRef.current = refsKey;\n setPage(1);\n }\n }, [refsKey]);\n const totalGroupPages = Math.max(1, Math.ceil(refs.length / GROUP_PAGE_SIZE));\n const safePage = Math.min(page, totalGroupPages);\n const visibleGroupRefs =\n refs.length > GROUP_PAGE_SIZE\n ? refs.slice((safePage - 1) * GROUP_PAGE_SIZE, safePage * GROUP_PAGE_SIZE)\n : refs;\n const groupPagination =\n totalGroupPages > 1 ? (\n <Pagination currentPage={safePage} totalPages={totalGroupPages} onPageChange={setPage} />\n ) : null;\n\n // Skeleton gate: `isLoading && !items` — SSR HTML and the client's first\n // paint render identical skeletons (useSelfFetch starts isLoading=true on\n // both sides), and once items exist they are never replaced by skeletons.\n if (isLoading && !items) {\n const skeletons = visibleGroupRefs.map((r) => (\n <div key={r.id}>{renderSkeletonForType(type, cardSize, adminCampaignCard)}</div>\n ));\n return (\n <div className=\"space-y-4\">\n {heading}\n {isListLayout ? (\n <div className=\"space-y-4\">{skeletons}</div>\n ) : (\n <div className={gridClassFor(columns)}>{skeletons}</div>\n )}\n </div>\n );\n }\n\n if (!items || items.length === 0) return null;\n\n // Index fetched rows by id, then render in REF order — refs carry the\n // intended sequence (suggestion mode: the engine's tier order, so\n // same-platform/tag-matched items lead; controlled mode: the curated\n // display_order). The list APIs return rows date-sorted, which would\n // otherwise scramble that ordering (same-platform items sinking below\n // newer cross-platform ones).\n // Shared extractor (NOT raw `.id`) — some API shapes key items differently\n // (e.g. external_id types); raw access would silently drop valid items.\n const itemById = new Map(\n (items as any[]).map((it) => [extractItemId(type, it) ?? String((it as any)?.id), it]),\n );\n\n const cards = visibleGroupRefs\n .map((contentRef) => {\n const itemId = String(contentRef.id);\n const item = itemById.get(itemId);\n if (!item) return null;\n // Re-compose the URL via the host's resolver (hub: buildContentURL so\n // dev gets localhost and prod the right platform domain; default: the\n // ref's stored url as the API composed it).\n const resolved = resolveHref(contentRef);\n const href = resolved.href ?? '';\n const targetPlatform = resolved.targetPlatform ?? contentRef.targetPlatform ?? null;\n return (\n <div key={itemId}>\n <LinkProvider href={href || null} targetPlatform={targetPlatform}>\n {(linkProps) => (\n <CardForType\n type={type}\n item={item}\n size={cardSize}\n href={href}\n targetPlatform={targetPlatform}\n linkProps={linkProps}\n extras={extras}\n adminCampaignCard={adminCampaignCard}\n />\n )}\n </LinkProvider>\n </div>\n );\n })\n .filter(Boolean);\n\n if (cards.length === 0) {\n // Current PAGE resolved zero cards (rows deleted between the ref fetch\n // and the group fetch, or a stricter list-API gate dropped them). When a\n // pager exists the user must keep the controls to navigate back —\n // dropping the whole group would strand them. A genuinely empty group\n // (no pager) still vanishes with its heading.\n if (groupPagination) {\n return (\n <div className=\"space-y-4\">\n {heading}\n {groupPagination}\n </div>\n );\n }\n return null;\n }\n\n return (\n <div className=\"space-y-4\">\n {heading}\n {isListLayout ? (\n <div className=\"space-y-4\">{cards}</div>\n ) : (\n <div className={gridClassFor(columns)}>{cards}</div>\n )}\n {groupPagination}\n </div>\n );\n}\n\n// =============================================================================\n// Main component\n// =============================================================================\n\ninterface RelatedContentResponse {\n refs: ContentRefWithReason[];\n}\n\nexport interface RelatedContentSectionProps {\n /** CONTROLLED mode (the original behavior). When defined — even `[]` — no\n * suggestion fetch runs and exactly these refs render. */\n contentRefs?: ContentRef[];\n /** SUGGESTION mode (with `entityId`): self-fetch suggestions for this host\n * entity from `{apiBaseUrl}/api/related-content`. Ignored when\n * `contentRefs` is provided. */\n entityType?: string;\n entityId?: number | string;\n /** AUTHOR mode: self-fetch ALL published content authored by this profile\n * from `{apiBaseUrl}/api/related-content?authorId=…` (grouped per type,\n * endless within each group). Ignored when `contentRefs` is provided;\n * takes precedence over the entityType/entityId suggestion scope.\n * SSR-hydrate via `initialItems`, same as suggestion mode. */\n authorId?: string;\n /** Maps to the suggestion API's `count` param — the PER-TYPE fill target\n * for every candidate type EXCEPT the host's own. Absent → param not sent\n * (server default applies). */\n minResults?: number;\n /** Maps to the suggestion API's `sameTypeCount` param — the budget for the\n * candidate type MATCHING the host's own `entityType` (same-type boost:\n * a blog post's rail leads with more blog posts). Absent → param not\n * sent (host's type uses the server's `count`). */\n sameTypeMinResults?: number;\n /** SSR hydrate for suggestion mode — the server page ran the engine and\n * drills the refs here; the first client fetch is skipped (useSelfFetch\n * initialData contract). */\n initialItems?: ContentRefWithReason[];\n /** Section title (default: \"Related Content\") */\n title?: string;\n /**\n * Grid columns at desktop. 2 = denser cards / wider summary (original\n * investor-update layout); 3 = more cards per row for dashboards.\n * Only consulted for grid-layout groups. Default: 2.\n */\n columns?: 2 | 3;\n /**\n * ContentRef.type values to exclude. Honored in ALL modes — controlled\n * mode post-filters (original behavior); suggestion mode ALSO forwards the\n * list verbatim as the API's `excludeTypes=` param so excluded types never\n * consume engine fill slots (`minResults` stays honored). The subtraction\n * happens SERVER-side — this component never mirrors the hub's candidate\n * list.\n */\n excludeTypes?: string[];\n /**\n * SUGGESTION-mode allow-list (rail vocabulary): which content types\n * participate in this rail. Sent verbatim as the API's `types=` param —\n * the SERVER intersects it with its own allowed candidate set, and\n * platform policy gates (e.g. internal-only types) ALWAYS win: the client\n * cannot request its way past them. Absent → all server-side candidates.\n */\n includeTypes?: string[];\n /** Fetch-URL prefix for third-party embeds / reverse proxies\n * ('' = same-origin). Applied to BOTH the suggestion fetch and the\n * default per-group list fetches. */\n apiBaseUrl?: string;\n /** Host injection bundle — REUSES the chat dispatcher's\n * `ChatCardDispatchExtras` (programConfigs, buildOgPlaceholderUrl,\n * buildProductReleaseCardProps override). Program groups render nothing\n * when their config is absent. */\n extras?: ChatCardDispatchExtras;\n /** Hub injects its `buildContentURL` recomposition; default uses the\n * ref's stored `url`/`targetPlatform` as the API composed them. */\n resolveHref?: (ref: ContentRef) => { href: string | null; targetPlatform: string | null };\n /** Hub injects its registry-driven entity-list-api builder; default = the\n * lib's `buildListUrl(type, ids, apiBaseUrl)`. */\n buildListUrl?: (type: string, ids: string[]) => string | null;\n /** Hub injects a `useNavLink`-backed render-prop provider; default = pure\n * anchor via `decideNewTab`. MUST be a module-scope component. */\n LinkProvider?: CardLinkProvider;\n /** Renderer pair for the admin-only `marketing_campaign` type. Absent →\n * the type renders nothing. */\n adminCampaignCard?: AdminCampaignCardSlot;\n}\n\nexport function RelatedContentSection({\n contentRefs,\n entityType,\n entityId,\n authorId,\n minResults,\n sameTypeMinResults,\n includeTypes,\n initialItems,\n title = 'Related Content',\n columns = 2,\n excludeTypes,\n apiBaseUrl = '',\n extras,\n resolveHref = defaultResolveHref,\n buildListUrl,\n LinkProvider = DefaultLinkPropsProvider,\n adminCampaignCard,\n}: RelatedContentSectionProps) {\n // ── Hooks above EVERY early return (the original `if (!contentRefs.length)\n // return null` guard moved below them). ──\n\n // Suggestion-mode fetch URL — null in controlled mode (contentRefs defined,\n // even []) or when the entity scope is incomplete.\n // `includeTypes: []` is an explicit \"nothing participates\" — skip the fetch\n // entirely (an empty-string `types=` param would be dropped by the URL\n // builder and read server-side as \"all candidates\") AND ignore SSR refs.\n const suggestionsDisabled = includeTypes?.length === 0;\n // Shared type-filter params — one spelling for both fetch modes so a future\n // normalization (trim/dedupe) can't diverge between them.\n const typeFilterParams = {\n types: includeTypes !== undefined ? includeTypes.join(',') : undefined,\n excludeTypes: excludeTypes && excludeTypes.length > 0 ? excludeTypes.join(',') : undefined,\n };\n // AUTHOR mode beats suggestion mode: when `authorId` is set the rail lists\n // everything that profile authored (the server returns ALL, no count).\n const authorUrl =\n contentRefs === undefined && authorId && !suggestionsDisabled\n ? buildSuggestionUrl('/api/related-content', {\n apiBaseUrl,\n extraParams: { authorId, ...typeFilterParams },\n })\n : null;\n const suggestUrl =\n authorUrl ??\n (contentRefs === undefined &&\n entityType &&\n entityId !== undefined &&\n entityId !== null &&\n entityId !== '' &&\n !suggestionsDisabled\n ? buildSuggestionUrl('/api/related-content', {\n apiBaseUrl,\n entityType,\n entityId,\n count: minResults,\n extraParams: {\n sameTypeCount: sameTypeMinResults !== undefined ? String(sameTypeMinResults) : undefined,\n ...typeFilterParams,\n },\n })\n : null);\n // Memoize the initialData wrapper — useSelfFetch re-syncs on [initialData],\n // and a fresh per-render object would loop setState under re-rendering\n // parents (the latent FaqSection bug, fixed there in the same change).\n const initialData = useMemo<RelatedContentResponse | undefined>(\n // An explicitly disabled rail (includeTypes: []) must ignore SSR-hydrated\n // refs too — otherwise useSelfFetch(null, {initialData}) keeps serving\n // initialItems and the \"nothing participates\" contract silently breaks.\n () => (!suggestionsDisabled && initialItems ? { refs: initialItems } : undefined),\n [initialItems, suggestionsDisabled],\n );\n const { data } = useSelfFetch<RelatedContentResponse>(suggestUrl, { initialData });\n\n // Default group fetcher: the lib's byte-parity-tested builder, prefixed for\n // embeds. Memoized so group-fetch URLs stay value-stable across renders.\n const effectiveBuildListUrl = useMemo(\n () => buildListUrl ?? ((type: string, ids: string[]) => libBuildListUrl(type, ids, apiBaseUrl)),\n [buildListUrl, apiBaseUrl],\n );\n\n const refs: ContentRef[] = contentRefs ?? data?.refs ?? [];\n\n // Per-consumer type gating — drops refs whose `type` is in the exclude\n // list. In suggestion mode the server already subtracted these (the param\n // is forwarded above); the client filter stays as an idempotent guard and\n // IS the mechanism in controlled mode (original behavior).\n const exclude = new Set(excludeTypes || []);\n const visibleRefs = exclude.size > 0 ? refs.filter((r) => !exclude.has(r.type)) : refs;\n // Zero refs (still loading in suggestion mode, or genuinely empty) → no\n // empty shell.\n if (!visibleRefs.length) return null;\n\n const grouped: Record<string, ContentRef[]> = {};\n for (const ref of visibleRefs) {\n if (!grouped[ref.type]) grouped[ref.type] = [];\n grouped[ref.type].push(ref);\n }\n\n // Registered types in CONTENT_REF_GROUPS order, then any unregistered\n // types appended (same shape the investor-email builder uses — both\n // consume `orderContentRefTypes` so cross-surface ordering matches).\n // SAME-TYPE FIRST: when a host entityType is known (suggestion / SSR\n // modes), its own content-type group is hoisted to the top — a blog\n // post's rail leads with blog posts. Rail group keys are compared via\n // the shared alias canonicalizer (blog_post_existing ↔ blog_post).\n let orderedTypes = orderContentRefTypes(Object.keys(grouped));\n if (entityType) {\n // Canonicalize BOTH sides — hosts pass registry vocab ('blog_post') but\n // rail-vocab aliases ('blog_post_existing') are also legal inputs; a raw\n // comparison would silently lose the same-type-first hoist for aliases.\n const canonicalEntityType = canonicalContentRefType(entityType);\n const sameType = orderedTypes.filter((t) => canonicalContentRefType(t) === canonicalEntityType);\n if (sameType.length > 0) {\n orderedTypes = [...sameType, ...orderedTypes.filter((t) => canonicalContentRefType(t) !== canonicalEntityType)];\n }\n }\n\n return (\n <div className=\"space-y-8\">\n <h2 className=\"text-2xl font-bold text-ods-text-primary\">{title}</h2>\n {orderedTypes.map((type) => (\n <ContentGroup\n key={type}\n type={type}\n refs={grouped[type]}\n columns={columns}\n buildUrl={effectiveBuildListUrl}\n resolveHref={resolveHref}\n LinkProvider={LinkProvider}\n extras={extras}\n adminCampaignCard={adminCampaignCard}\n heading={\n <h3 className=\"font-['Azeret_Mono'] text-[14px] font-semibold uppercase text-ods-text-secondary tracking-wider\">\n {getContentRefLabelOrTitleCase(type)}\n </h3>\n }\n />\n ))}\n </div>\n );\n}\n"]}
@@ -8,12 +8,12 @@ import {
8
8
  TASK_TYPE_TEXT_COLORS,
9
9
  getStatusColorScheme,
10
10
  init_pagination
11
- } from "./chunk-6TB24AUH.js";
11
+ } from "./chunk-S7IX7YU4.js";
12
12
  import {
13
13
  PageShell,
14
14
  SearchInput,
15
15
  StatusBadge
16
- } from "./chunk-LKI3YCAX.js";
16
+ } from "./chunk-V5L4D454.js";
17
17
  import {
18
18
  init_next_navigation,
19
19
  usePathname,
@@ -23,7 +23,7 @@ import {
23
23
  import {
24
24
  Button,
25
25
  init_button2 as init_button
26
- } from "./chunk-2FCXJTOV.js";
26
+ } from "./chunk-QXSRQVRO.js";
27
27
  import {
28
28
  init_next_link,
29
29
  next_link_default
@@ -450,4 +450,4 @@ export {
450
450
  DevCardRowSkeletonList,
451
451
  DeliveryRow
452
452
  };
453
- //# sourceMappingURL=chunk-D524LJYO.js.map
453
+ //# sourceMappingURL=chunk-HCMVLEC3.js.map
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
 
10
- var _chunk6LK4VEXEcjs = require('./chunk-6LK4VEXE.cjs');
10
+ var _chunkTSZBJVYKcjs = require('./chunk-TSZBJVYK.cjs');
11
11
 
12
12
 
13
13
  var _chunkDAAFVOTLcjs = require('./chunk-DAAFVOTL.cjs');
@@ -34,7 +34,7 @@ function DocSearchResultRow({
34
34
  }) {
35
35
  const docType = _optionalChain([result, 'access', _2 => _2.metadata, 'optionalAccess', _3 => _3.documentType]) || void 0;
36
36
  const sourceRepo = _optionalChain([result, 'access', _4 => _4.metadata, 'optionalAccess', _5 => _5.sourceRepo]) || void 0;
37
- const { Icon: SourceIcon, label: iconLabel } = _chunk6LK4VEXEcjs.resolveSourceIcon.call(void 0, {
37
+ const { Icon: SourceIcon, label: iconLabel } = _chunkTSZBJVYKcjs.resolveSourceIcon.call(void 0, {
38
38
  sourceRepo,
39
39
  documentType: docType
40
40
  });
@@ -77,7 +77,7 @@ function DocSearchBar({
77
77
  renderResult
78
78
  }) {
79
79
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
80
- _chunk6LK4VEXEcjs.SearchInput,
80
+ _chunkTSZBJVYKcjs.SearchInput,
81
81
  {
82
82
  placeholder,
83
83
  value: query,
@@ -186,7 +186,7 @@ function resolveSearchResultAction(result, source, runtimeMode) {
186
186
  const externalUrl = meta.externalUrl;
187
187
  if (externalUrl) {
188
188
  const targetPlatform = meta.targetPlatform;
189
- const isNewTab = _chunk6LK4VEXEcjs.decideNewTab.call(void 0, {
189
+ const isNewTab = _chunkTSZBJVYKcjs.decideNewTab.call(void 0, {
190
190
  href: externalUrl,
191
191
  targetPlatform,
192
192
  surface: "useUnifiedNav",
@@ -287,7 +287,7 @@ function useDocSearch(config) {
287
287
  if (_optionalChain([runtime, 'optionalAccess', _13 => _13.navigation, 'access', _14 => _14.mode]) === "embed") {
288
288
  setKeepOpen(true);
289
289
  const targetPlatform = _nullishCoalesce(_optionalChain([result, 'access', _15 => _15.metadata, 'optionalAccess', _16 => _16.targetPlatform]), () => ( null));
290
- _chunk6LK4VEXEcjs.resolveExternalNavigation.call(void 0, {
290
+ _chunkTSZBJVYKcjs.resolveExternalNavigation.call(void 0, {
291
291
  href: action.href,
292
292
  targetPlatform,
293
293
  runtime
@@ -296,18 +296,18 @@ function useDocSearch(config) {
296
296
  }
297
297
  if (wantsNewTab) {
298
298
  setKeepOpen(true);
299
- window.open(action.href, "_blank", _chunk6LK4VEXEcjs.NEW_TAB_FEATURES);
299
+ window.open(action.href, "_blank", _chunkTSZBJVYKcjs.NEW_TAB_FEATURES);
300
300
  return;
301
301
  }
302
302
  setKeepOpen(false);
303
303
  const path = baseRoute && action.href.startsWith(`${baseRoute}/`) ? action.href.slice(baseRoute.length + 1) : null;
304
304
  if (path && _optionalChain([onInPageSwap, 'optionalCall', _17 => _17(path)])) return;
305
- router.push(_chunk6LK4VEXEcjs.stripSameOriginToPath.call(void 0, action.href));
305
+ router.push(_chunkTSZBJVYKcjs.stripSameOriginToPath.call(void 0, action.href));
306
306
  return;
307
307
  }
308
308
  case "navigate-new-tab":
309
309
  setKeepOpen(true);
310
- window.open(action.href, "_blank", _chunk6LK4VEXEcjs.NEW_TAB_FEATURES);
310
+ window.open(action.href, "_blank", _chunkTSZBJVYKcjs.NEW_TAB_FEATURES);
311
311
  return;
312
312
  case "ask-ai":
313
313
  setKeepOpen(false);
@@ -345,7 +345,7 @@ function DetailPageSkeleton({
345
345
  showImageGallery = true
346
346
  } = {}) {
347
347
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
348
- _chunk6LK4VEXEcjs.PageContainer,
348
+ _chunkTSZBJVYKcjs.PageContainer,
349
349
  {
350
350
  as: "article",
351
351
  backgroundClassName: "bg-ods-bg",
@@ -386,4 +386,4 @@ function DetailPageSkeleton({
386
386
 
387
387
 
388
388
  exports.formatRelativePath = formatRelativePath; exports.DocSearchResultRow = DocSearchResultRow; exports.DocSearchBar = DocSearchBar; exports.mapDocSearchResults = mapDocSearchResults; exports.resolveSearchResultAction = resolveSearchResultAction; exports.useDocSearch = useDocSearch; exports.DetailPageSkeleton = DetailPageSkeleton;
389
- //# sourceMappingURL=chunk-LZL6P7SN.cjs.map
389
+ //# sourceMappingURL=chunk-IG4QRNYZ.cjs.map