@flamingo-stack/openframe-frontend-core 0.0.239-snapshot.20260609201008 → 0.0.240
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/{chunk-DV3YZWGN.cjs → chunk-3TDLFCCS.cjs} +33 -20
- package/dist/chunk-3TDLFCCS.cjs.map +1 -0
- package/dist/{chunk-ORJREQ2W.js → chunk-4XLJWX2N.js} +4 -4
- package/dist/{chunk-SZ3BBI6H.cjs → chunk-5JTDFOYB.cjs} +12 -12
- package/dist/{chunk-SZ3BBI6H.cjs.map → chunk-5JTDFOYB.cjs.map} +1 -1
- package/dist/{chunk-G6YZ7O27.js → chunk-7BWJF43J.js} +6 -6
- package/dist/{chunk-7LLS3TWN.js → chunk-B3NI3KT4.js} +5 -5
- package/dist/{chunk-MTROCWO4.cjs → chunk-CDLMGHSB.cjs} +7 -7
- package/dist/{chunk-MTROCWO4.cjs.map → chunk-CDLMGHSB.cjs.map} +1 -1
- package/dist/{chunk-APGMNHPY.js → chunk-MKVKVJQQ.js} +32 -19
- package/dist/chunk-MKVKVJQQ.js.map +1 -0
- package/dist/{chunk-5VU66BD2.cjs → chunk-NE2DYD6K.cjs} +494 -461
- package/dist/chunk-NE2DYD6K.cjs.map +1 -0
- package/dist/chunk-POZHDJSK.js +276 -0
- package/dist/chunk-POZHDJSK.js.map +1 -0
- package/dist/{chunk-FSS2MIEA.cjs → chunk-SGJBUL2Y.cjs} +20 -3
- package/dist/chunk-SGJBUL2Y.cjs.map +1 -0
- package/dist/{chunk-IJOJWBME.cjs → chunk-SI4LEFLR.cjs} +27 -27
- package/dist/{chunk-IJOJWBME.cjs.map → chunk-SI4LEFLR.cjs.map} +1 -1
- package/dist/chunk-TE6LSK2X.cjs +276 -0
- package/dist/chunk-TE6LSK2X.cjs.map +1 -0
- package/dist/{chunk-LJGBFD52.js → chunk-VAUI3CND.js} +18 -1
- package/dist/chunk-VAUI3CND.js.map +1 -0
- package/dist/{chunk-OB45JHDY.cjs → chunk-VFKQMAUF.cjs} +3 -3
- package/dist/{chunk-OB45JHDY.cjs.map → chunk-VFKQMAUF.cjs.map} +1 -1
- package/dist/{chunk-Y6463TD6.js → chunk-XWUA273B.js} +2 -2
- package/dist/{chunk-Y7DCQUNL.js → chunk-YH6KPNIH.js} +87 -54
- package/dist/chunk-YH6KPNIH.js.map +1 -0
- package/dist/{chunk-ELMYRGWG.cjs → chunk-YY6S4T67.cjs} +12 -12
- package/dist/{chunk-ELMYRGWG.cjs.map → chunk-YY6S4T67.cjs.map} +1 -1
- package/dist/{chunk-PN64LWNT.js → chunk-ZYPOIFBS.js} +8 -8
- package/dist/components/chat/hooks/use-chat-card-item.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +6 -6
- package/dist/components/chat/index.js +5 -5
- package/dist/components/chat/types/entities/content-ref.d.ts +5 -20
- package/dist/components/chat/types/entities/content-ref.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +7 -7
- package/dist/components/contact/index.js +6 -6
- package/dist/components/faq/faq-section.d.ts +7 -1
- package/dist/components/faq/faq-section.d.ts.map +1 -1
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/index.cjs +6 -6
- package/dist/components/features/index.js +5 -5
- package/dist/components/index.cjs +89 -85
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +31 -27
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/index.cjs +6 -6
- package/dist/components/navigation/index.js +5 -5
- package/dist/components/onboarding-guides/index.cjs +30 -30
- package/dist/components/onboarding-guides/index.cjs.map +1 -1
- package/dist/components/onboarding-guides/index.js +11 -11
- package/dist/components/related-content/index.cjs +26 -0
- package/dist/components/related-content/index.cjs.map +1 -0
- package/dist/components/related-content/index.d.ts +2 -0
- package/dist/components/related-content/index.d.ts.map +1 -0
- package/dist/components/related-content/index.js +26 -0
- package/dist/components/related-content/index.js.map +1 -0
- package/dist/components/related-content/related-content-section.d.ts +135 -0
- package/dist/components/related-content/related-content-section.d.ts.map +1 -0
- package/dist/components/tickets/index.cjs +73 -73
- package/dist/components/tickets/index.cjs.map +1 -1
- package/dist/components/tickets/index.js +15 -15
- package/dist/components/ui/index.cjs +11 -11
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +13 -13
- package/dist/embed-shims/index.cjs +3 -3
- package/dist/embed-shims/index.cjs.map +1 -1
- package/dist/embed-shims/index.js +5 -5
- package/dist/index.cjs +25 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +53 -39
- package/dist/types/content-ref.d.ts +35 -0
- package/dist/types/content-ref.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/content-ref-groups.d.ts +58 -0
- package/dist/utils/content-ref-groups.d.ts.map +1 -0
- package/dist/utils/extract-items.d.ts +18 -0
- package/dist/utils/extract-items.d.ts.map +1 -0
- package/dist/utils/index.cjs +77 -0
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +71 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/suggestion-url.d.ts +26 -0
- package/dist/utils/suggestion-url.d.ts.map +1 -0
- package/package.json +7 -1
- package/src/components/chat/hooks/use-chat-card-item.ts +3 -38
- package/src/components/chat/types/entities/content-ref.ts +5 -21
- package/src/components/faq/faq-section.tsx +69 -24
- package/src/components/index.ts +1 -0
- package/src/components/related-content/index.ts +9 -0
- package/src/components/related-content/related-content-section.tsx +585 -0
- package/src/types/content-ref.ts +34 -0
- package/src/types/index.ts +1 -0
- package/src/utils/content-ref-groups.ts +89 -0
- package/src/utils/extract-items.ts +48 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/suggestion-url.ts +39 -0
- package/dist/chunk-5VU66BD2.cjs.map +0 -1
- package/dist/chunk-APGMNHPY.js.map +0 -1
- package/dist/chunk-DV3YZWGN.cjs.map +0 -1
- package/dist/chunk-FSS2MIEA.cjs.map +0 -1
- package/dist/chunk-LJGBFD52.js.map +0 -1
- package/dist/chunk-Y7DCQUNL.js.map +0 -1
- /package/dist/{chunk-ORJREQ2W.js.map → chunk-4XLJWX2N.js.map} +0 -0
- /package/dist/{chunk-G6YZ7O27.js.map → chunk-7BWJF43J.js.map} +0 -0
- /package/dist/{chunk-7LLS3TWN.js.map → chunk-B3NI3KT4.js.map} +0 -0
- /package/dist/{chunk-Y6463TD6.js.map → chunk-XWUA273B.js.map} +0 -0
- /package/dist/{chunk-PN64LWNT.js.map → chunk-ZYPOIFBS.js.map} +0 -0
|
@@ -3,13 +3,17 @@ import {
|
|
|
3
3
|
useSelfFetch
|
|
4
4
|
} from "./chunk-L4LAAA5Q.js";
|
|
5
5
|
import {
|
|
6
|
-
ChevronButton
|
|
7
|
-
|
|
6
|
+
ChevronButton,
|
|
7
|
+
buildSuggestionUrl
|
|
8
|
+
} from "./chunk-VAUI3CND.js";
|
|
8
9
|
import {
|
|
9
10
|
cn,
|
|
10
11
|
init_cn
|
|
11
12
|
} from "./chunk-XTCBRQN2.js";
|
|
12
13
|
|
|
14
|
+
// src/components/faq/faq-section.tsx
|
|
15
|
+
import { useMemo } from "react";
|
|
16
|
+
|
|
13
17
|
// src/components/faq-accordion.tsx
|
|
14
18
|
import { useRef, useState, useEffect, useCallback } from "react";
|
|
15
19
|
init_cn();
|
|
@@ -123,12 +127,8 @@ function buildFaqJsonLdFromFaqs(faqs, opts = {}) {
|
|
|
123
127
|
// src/components/faq/faq-section.tsx
|
|
124
128
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
125
129
|
var DEFAULT_HEADING_TEXT = "Frequently Asked Questions";
|
|
126
|
-
function buildFaqsUrl(entityType, entityId) {
|
|
127
|
-
|
|
128
|
-
return "/api/faqs";
|
|
129
|
-
}
|
|
130
|
-
const qs = new URLSearchParams({ entityType, entityId: String(entityId) });
|
|
131
|
-
return `/api/faqs?${qs.toString()}`;
|
|
130
|
+
function buildFaqsUrl(entityType, entityId, minResults, apiBaseUrl = "") {
|
|
131
|
+
return buildSuggestionUrl("/api/faqs", { apiBaseUrl, entityType, entityId, count: minResults });
|
|
132
132
|
}
|
|
133
133
|
function groupBySection(faqs) {
|
|
134
134
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -162,10 +162,15 @@ function FaqSection({
|
|
|
162
162
|
heading,
|
|
163
163
|
emitJsonLd = false,
|
|
164
164
|
jsonLd,
|
|
165
|
-
className
|
|
165
|
+
className,
|
|
166
|
+
minResults,
|
|
167
|
+
apiBaseUrl = ""
|
|
166
168
|
}) {
|
|
167
|
-
const url = buildFaqsUrl(entityType, entityId);
|
|
168
|
-
const initialData =
|
|
169
|
+
const url = buildFaqsUrl(entityType, entityId, minResults, apiBaseUrl);
|
|
170
|
+
const initialData = useMemo(
|
|
171
|
+
() => initialFaqs ? { faqs: initialFaqs } : void 0,
|
|
172
|
+
[initialFaqs]
|
|
173
|
+
);
|
|
169
174
|
const { data, isLoading, error } = useSelfFetch(url, { initialData });
|
|
170
175
|
const faqs = data?.faqs ?? [];
|
|
171
176
|
const showHeading = heading !== null;
|
|
@@ -174,21 +179,29 @@ function FaqSection({
|
|
|
174
179
|
if (error && !showHeading) {
|
|
175
180
|
return null;
|
|
176
181
|
}
|
|
182
|
+
if (!isLoading && !error && faqs.length === 0 && !showHeading) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
177
185
|
if (isLoading && faqs.length === 0) {
|
|
186
|
+
if (!showHeading) {
|
|
187
|
+
return /* @__PURE__ */ jsx2("div", { className, children: /* @__PURE__ */ jsx2(FaqSkeleton, {}) });
|
|
188
|
+
}
|
|
178
189
|
return /* @__PURE__ */ jsx2("main", { className: className ?? "bg-ods-bg", children: /* @__PURE__ */ jsx2("div", { className: "max-w-[1920px] px-6 md:px-20 py-6 md:py-10 mx-auto", children: /* @__PURE__ */ jsx2(FaqSkeleton, {}) }) });
|
|
179
190
|
}
|
|
180
191
|
if (error && faqs.length === 0) {
|
|
181
192
|
return /* @__PURE__ */ jsx2("main", { className: className ?? "bg-ods-bg flex items-center justify-center py-20", children: /* @__PURE__ */ jsx2("p", { className: "text-ods-text-primary font-medium", children: "Failed to load FAQs. Please try again later." }) });
|
|
182
193
|
}
|
|
183
194
|
const schema = emitJsonLd ? buildFaqJsonLdFromFaqs(faqs, jsonLd) : null;
|
|
195
|
+
const groupNodes = groups.map(({ section, items }) => /* @__PURE__ */ jsxs2("div", { className: "space-y-4", children: [
|
|
196
|
+
section && /* @__PURE__ */ jsx2("h2", { className: "text-h2 tracking-[-0.04em] text-ods-text-primary mb-3 md:mb-4", children: section }),
|
|
197
|
+
/* @__PURE__ */ jsx2(FaqAccordion, { items })
|
|
198
|
+
] }, section || "default"));
|
|
199
|
+
const body = showHeading ? /* @__PURE__ */ jsx2("main", { className: className ?? "bg-ods-bg", children: /* @__PURE__ */ jsxs2("div", { className: "max-w-[1920px] px-6 md:px-20 py-6 md:py-10 mx-auto space-y-10", children: [
|
|
200
|
+
headingNode,
|
|
201
|
+
groupNodes
|
|
202
|
+
] }) }) : /* @__PURE__ */ jsx2("section", { className: className ?? "space-y-10", children: groupNodes });
|
|
184
203
|
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
185
|
-
|
|
186
|
-
showHeading && headingNode,
|
|
187
|
-
groups.map(({ section, items }) => /* @__PURE__ */ jsxs2("div", { className: "space-y-4", children: [
|
|
188
|
-
section && /* @__PURE__ */ jsx2("h2", { className: "text-h2 tracking-[-0.04em] text-ods-text-primary mb-3 md:mb-4", children: section }),
|
|
189
|
-
/* @__PURE__ */ jsx2(FaqAccordion, { items })
|
|
190
|
-
] }, section || "default"))
|
|
191
|
-
] }) }),
|
|
204
|
+
body,
|
|
192
205
|
schema && /* @__PURE__ */ jsx2(
|
|
193
206
|
"script",
|
|
194
207
|
{
|
|
@@ -203,4 +216,4 @@ export {
|
|
|
203
216
|
FaqAccordion,
|
|
204
217
|
FaqSection
|
|
205
218
|
};
|
|
206
|
-
//# sourceMappingURL=chunk-
|
|
219
|
+
//# sourceMappingURL=chunk-MKVKVJQQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/faq/faq-section.tsx","../src/components/faq-accordion.tsx","../src/components/faq/json-ld.ts"],"sourcesContent":["\"use client\"\n\nimport React, { useMemo } from 'react'\nimport type { Faq } from '../../types/faq'\nimport { FaqAccordion, type FaqItem } from '../faq-accordion'\nimport { useSelfFetch } from '../../hooks/use-self-fetch'\nimport { buildSuggestionUrl } from '../../utils/suggestion-url'\nimport { buildFaqJsonLdFromFaqs, type FaqSchemaOptions } from './json-ld'\n\nexport interface FaqSectionProps {\n /**\n * SSR hydrate. When provided, the hook skips the first client fetch (per\n * useSelfFetch contract). The consuming server page resolves FAQs then drills\n * them into this prop — the lib never re-fetches what the host already gated on.\n */\n initialFaqs?: Faq[]\n /** Both required together for entity-attached FAQs; partial → bare /api/faqs. */\n entityType?: string\n entityId?: number | string\n /**\n * Page heading. Pass null to render in embedded mode (no <h1>, error branch\n * suppresses any banner). React node so platforms can drill their local\n * <PageHeading> component without the lib referencing platform state.\n */\n heading?: React.ReactNode | null\n /** Inject FAQPage schema.org JSON-LD as a <script>. Off by default so embeds\n * don't emit duplicate schema. */\n emitJsonLd?: boolean\n /** Overrides for the JSON-LD's name/description/url. */\n jsonLd?: FaqSchemaOptions\n className?: string\n /** Maps to /api/faqs `?count=` (the 5-tier fill target). Absent → param\n * not sent (server default applies). */\n minResults?: number\n /** Fetch-URL prefix for third-party embeds / reverse proxies\n * ('' = same-origin relative). */\n apiBaseUrl?: string\n}\n\nconst DEFAULT_HEADING_TEXT = 'Frequently Asked Questions'\n\n/** URL composition shared with RelatedContentSection (`buildSuggestionUrl`)\n * — byte-identical to the historical `buildFaqsUrl` output when\n * `minResults`/`apiBaseUrl` are absent. */\nfunction buildFaqsUrl(\n entityType?: string,\n entityId?: number | string,\n minResults?: number,\n apiBaseUrl = '',\n): string {\n return buildSuggestionUrl('/api/faqs', { apiBaseUrl, entityType, entityId, count: minResults })\n}\n\nfunction groupBySection(faqs: Faq[]): Array<{ section: string | null; items: FaqItem[] }> {\n const map = new Map<string, FaqItem[]>()\n for (const faq of faqs) {\n const key = faq.section || ''\n let arr = map.get(key)\n if (!arr) {\n arr = []\n map.set(key, arr)\n }\n arr.push({ id: faq.id, question: faq.question, answer: faq.answer })\n }\n return Array.from(map.entries()).map(([section, items]) => ({\n section: section || null,\n items,\n }))\n}\n\nfunction FaqSkeleton() {\n return (\n <div className=\"space-y-8 animate-pulse\">\n <div className=\"h-12 md:h-14 w-2/3 rounded bg-ods-border\" />\n <div className=\"rounded-3xl border border-ods-border overflow-hidden bg-ods-card divide-y divide-ods-border w-full\">\n {Array.from({ length: 8 }).map((_, idx) => (\n <div key={idx} className=\"flex items-center justify-between px-6 md:px-8 py-6\">\n <div className=\"h-6 w-5/6 rounded bg-ods-border\" />\n <div className=\"h-10 w-10 rounded-md bg-ods-border\" />\n </div>\n ))}\n </div>\n </div>\n )\n}\n\ninterface FaqsResponse {\n faqs: Faq[]\n}\n\n/**\n * Generic, embeddable FAQ display surface.\n *\n * - Standalone /faqs page: pass `initialFaqs` from the server + `heading` +\n * `emitJsonLd` with `jsonLd` overrides for SEO.\n * - Per-entity embed: pass `entityType` + `entityId` (no `initialFaqs`); the\n * hook self-fetches and the public /api/faqs endpoint picks override-vs-fallback.\n *\n * CONTRACT: the consuming app MUST implement `GET /api/faqs`. Without it,\n * useSelfFetch reports `error:true` (logged once); in embedded mode (heading\n * === null) this component renders nothing so the host page isn't disfigured.\n */\nexport function FaqSection({\n initialFaqs,\n entityType,\n entityId,\n heading,\n emitJsonLd = false,\n jsonLd,\n className,\n minResults,\n apiBaseUrl = '',\n}: FaqSectionProps) {\n const url = buildFaqsUrl(entityType, entityId, minResults, apiBaseUrl)\n // Memoized — useSelfFetch re-syncs on [initialData]; a fresh per-render\n // wrapper object would setState-loop under re-rendering parents.\n const initialData = useMemo<FaqsResponse | undefined>(\n () => (initialFaqs ? { faqs: initialFaqs } : undefined),\n [initialFaqs],\n )\n const { data, isLoading, error } = useSelfFetch<FaqsResponse>(url, { initialData })\n\n const faqs = data?.faqs ?? []\n const showHeading = heading !== null\n const headingNode =\n heading === undefined\n ? <h1 className=\"text-h1 tracking-[-0.04em] text-ods-text-primary\">{DEFAULT_HEADING_TEXT}</h1>\n : heading\n\n const groups = groupBySection(faqs)\n\n // Embedded mode (no heading): degrade silently on error.\n if (error && !showHeading) {\n return null\n }\n\n // Embedded mode, zero FAQs after load: render nothing — an embedded host\n // page (blog/case-study detail) must not show an empty section shell.\n // The standalone /faqs page (heading set) keeps its existing behavior.\n if (!isLoading && !error && faqs.length === 0 && !showHeading) {\n return null\n }\n\n if (isLoading && faqs.length === 0) {\n // Embedded mode renders skeletons WITHOUT the standalone page shell —\n // a host detail page already provides <main> + gutters; nesting them\n // here would emit invalid markup and double padding.\n if (!showHeading) {\n return (\n <div className={className}>\n <FaqSkeleton />\n </div>\n )\n }\n return (\n <main className={className ?? 'bg-ods-bg'}>\n <div className=\"max-w-[1920px] px-6 md:px-20 py-6 md:py-10 mx-auto\">\n <FaqSkeleton />\n </div>\n </main>\n )\n }\n\n if (error && faqs.length === 0) {\n return (\n <main className={className ?? 'bg-ods-bg flex items-center justify-center py-20'}>\n <p className=\"text-ods-text-primary font-medium\">Failed to load FAQs. Please try again later.</p>\n </main>\n )\n }\n\n const schema = emitJsonLd ? buildFaqJsonLdFromFaqs(faqs, jsonLd) : null\n\n const groupNodes = groups.map(({ section, items }) => (\n <div key={section || 'default'} className=\"space-y-4\">\n {section && (\n <h2 className=\"text-h2 tracking-[-0.04em] text-ods-text-primary mb-3 md:mb-4\">\n {section}\n </h2>\n )}\n <FaqAccordion items={items} />\n </div>\n ))\n\n // Embedded mode (heading === null): no <main> page shell, no page gutters —\n // the host page owns layout. Standalone mode keeps the historical markup.\n const body = showHeading ? (\n <main className={className ?? 'bg-ods-bg'}>\n <div className=\"max-w-[1920px] px-6 md:px-20 py-6 md:py-10 mx-auto space-y-10\">\n {headingNode}\n {groupNodes}\n </div>\n </main>\n ) : (\n <section className={className ?? 'space-y-10'}>{groupNodes}</section>\n )\n\n return (\n <>\n {body}\n {schema && (\n <script\n type=\"application/ld+json\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}\n />\n )}\n </>\n )\n}\n","\"use client\"\n\nimport React, { useRef, useState, useEffect, useCallback } from 'react'\nimport { ChevronButton } from './ui/chevron-button'\nimport { cn } from \"../utils/cn\"\n\nexport interface FaqItem {\n id: number | string\n question: string\n answer: string\n}\n\ninterface FaqAccordionProps {\n items: FaqItem[]\n defaultOpenIds?: (number | string)[]\n}\n\n// Utility to measure scrollHeight outside render cycle\nconst useMeasuredHeight = (isOpen: boolean) => {\n const ref = useRef<HTMLDivElement | null>(null)\n const [maxHeight, setMaxHeight] = useState<string>('0px')\n\n const measure = useCallback(() => {\n if (ref.current) {\n const height = ref.current.scrollHeight\n setMaxHeight(`${height}px`)\n }\n }, [])\n\n // Update height only when section is open\n useEffect(() => {\n if (isOpen) {\n measure()\n } else {\n setMaxHeight('0px')\n }\n }, [isOpen, measure])\n\n return { ref, maxHeight }\n}\n\nexport function FaqAccordion({ items, defaultOpenIds = [] }: FaqAccordionProps) {\n const [openSet, setOpenSet] = useState<Set<string | number>>(new Set(defaultOpenIds))\n\n const toggle = (id: string | number) => {\n setOpenSet(prev => {\n const next = new Set(prev)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n return next\n })\n }\n\n return (\n <div className=\"rounded-3xl border border-ods-border divide-y divide-ods-border bg-ods-card overflow-hidden\">\n {items.map(item => {\n const isOpen = openSet.has(item.id)\n const { ref, maxHeight } = useMeasuredHeight(isOpen)\n\n return (\n <div\n key={item.id}\n className={cn('group transition-colors hover:bg-[#1E1E1E]', isOpen ? 'bg-ods-bg' : 'bg-transparent')}\n >\n {/* Header */}\n <div\n role=\"button\"\n tabIndex={0}\n onClick={() => toggle(item.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n toggle(item.id);\n }\n }}\n aria-expanded={isOpen}\n className=\"flex w-full items-center justify-between px-6 md:px-8 py-6 text-left focus:outline-none transition-colors cursor-pointer\"\n >\n <h3>\n {item.question}\n </h3>\n <div className=\"flex-shrink-0\">\n <ChevronButton\n aria-label={isOpen ? 'Collapse question' : 'Expand question'}\n size=\"md\"\n isExpanded={isOpen}\n backgroundColor=\"transparent\"\n borderColor=\"#3A3A3A\"\n />\n </div>\n </div>\n {/* Content wrapper with max-height animation */}\n <div\n style={{ maxHeight, transition: 'max-height 0.35s ease-in-out, opacity 0.35s ease-in-out', opacity: isOpen ? 1 : 0 }}\n className=\"overflow-hidden group-hover:bg-[#1E1E1E]/30\"\n >\n <div ref={ref} className=\"px-6 md:px-8 pb-6 text-ods-text-primary text-h4\">\n {item.answer}\n </div>\n </div>\n </div>\n )\n })}\n </div>\n )\n} ","/**\n * Pure FAQ JSON-LD builder. No React, no client-only deps — safe to import from\n * Server Components via the `./components/faq` subpath export. (Do NOT import\n * through the root `./components` barrel — that barrel is `\"use client\"` and\n * dragging it into a Server Component would force the client graph into the\n * server.)\n *\n * The hub used to harcode `name`/`description` here for OpenMSP; in the lib we\n * accept overrides so every embedder can supply its own platform branding.\n */\nimport type { Faq } from '../../types/faq'\n\nexport interface FaqSchemaOptions {\n name?: string\n description?: string\n url?: string\n}\n\nconst DEFAULT_NAME = 'Frequently Asked Questions'\nconst DEFAULT_DESCRIPTION =\n 'Answers to common questions.'\n\nexport function baseFaqSchema(opts: FaqSchemaOptions = {}) {\n return {\n '@context': 'https://schema.org',\n '@type': 'FAQPage',\n name: opts.name ?? DEFAULT_NAME,\n description: opts.description ?? DEFAULT_DESCRIPTION,\n ...(opts.url ? { url: opts.url } : {}),\n } as const\n}\n\nexport function buildFaqJsonLdFromFaqs(faqs: Faq[], opts: FaqSchemaOptions = {}) {\n return {\n ...baseFaqSchema(opts),\n mainEntity: faqs.map((faq) => ({\n '@type': 'Question',\n name: faq.question,\n acceptedAnswer: {\n '@type': 'Answer',\n text: faq.answer,\n },\n })),\n } as const\n}\n"],"mappings":"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","names":["jsx","jsxs"]}
|