@gosalesdeal/blog 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +265 -34
  2. package/dist/client/blogClient.js +79 -13
  3. package/dist/client/blogClient.js.map +1 -1
  4. package/dist/components/BlogPost.d.ts +12 -1
  5. package/dist/components/BlogPost.js +27 -16
  6. package/dist/components/BlogPost.js.map +1 -1
  7. package/dist/components/BlogPostHeader.d.ts +15 -0
  8. package/dist/components/BlogPostHeader.js +41 -0
  9. package/dist/components/BlogPostHeader.js.map +1 -0
  10. package/dist/components/landing/BlogLayoutComponents.d.ts +14 -0
  11. package/dist/components/landing/BlogLayoutComponents.js +198 -0
  12. package/dist/components/landing/BlogLayoutComponents.js.map +1 -0
  13. package/dist/components/landing/FlexibleLayoutComponent.d.ts +40 -0
  14. package/dist/components/landing/FlexibleLayoutComponent.js +352 -0
  15. package/dist/components/landing/FlexibleLayoutComponent.js.map +1 -0
  16. package/dist/components/landing/HeroFeatureBanner.d.ts +36 -0
  17. package/dist/components/landing/HeroFeatureBanner.js +88 -0
  18. package/dist/components/landing/HeroFeatureBanner.js.map +1 -0
  19. package/dist/components/landing/HeroFeatureBannerComponent.d.ts +4 -0
  20. package/dist/components/landing/HeroFeatureBannerComponent.js +100 -0
  21. package/dist/components/landing/HeroFeatureBannerComponent.js.map +1 -0
  22. package/dist/components/landing/HeroFeatureBannerVideo.d.ts +34 -0
  23. package/dist/components/landing/HeroFeatureBannerVideo.js +261 -0
  24. package/dist/components/landing/HeroFeatureBannerVideo.js.map +1 -0
  25. package/dist/components/landing/HeroFeatureBannerVideoComponent.d.ts +5 -0
  26. package/dist/components/landing/HeroFeatureBannerVideoComponent.js +69 -0
  27. package/dist/components/landing/HeroFeatureBannerVideoComponent.js.map +1 -0
  28. package/dist/components/landing/VarietyReviewslistComponent.d.ts +4 -0
  29. package/dist/components/landing/VarietyReviewslistComponent.js +172 -0
  30. package/dist/components/landing/VarietyReviewslistComponent.js.map +1 -0
  31. package/dist/index.d.ts +13 -0
  32. package/dist/index.js +25 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/lib/postUtils.d.ts +3 -0
  35. package/dist/lib/postUtils.js +8 -0
  36. package/dist/lib/postUtils.js.map +1 -0
  37. package/dist/lib/resolveMediaSrc.d.ts +2 -0
  38. package/dist/lib/resolveMediaSrc.js +21 -0
  39. package/dist/lib/resolveMediaSrc.js.map +1 -0
  40. package/dist/render/BlockRenderer.js +5 -0
  41. package/dist/render/BlockRenderer.js.map +1 -1
  42. package/dist/render/LandingPageRenderer.d.ts +5 -0
  43. package/dist/render/LandingPageRenderer.js +50 -0
  44. package/dist/render/LandingPageRenderer.js.map +1 -0
  45. package/dist/render/landingPageHtml.d.ts +28 -0
  46. package/dist/render/landingPageHtml.js +205 -0
  47. package/dist/render/landingPageHtml.js.map +1 -0
  48. package/dist/styles.css +27 -0
  49. package/dist/types/blog.d.ts +8 -2
  50. package/package.json +13 -3
@@ -0,0 +1,100 @@
1
+ "use client";
2
+ import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
+ import React from "react";
4
+ import Link from "next/link";
5
+ import Image from "next/image";
6
+ const HeroFeatureBannerComponent = ({ props }) => {
7
+ const bullets = Array.isArray(props.bullets) ? props.bullets : [];
8
+ let headingNode = props.heading || "";
9
+ if (typeof headingNode === "string" && headingNode.includes("\n")) {
10
+ const parts = headingNode.split("\n");
11
+ headingNode = /* @__PURE__ */ jsx(Fragment, { children: parts.map((part, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
12
+ i > 0 && /* @__PURE__ */ jsx("br", {}),
13
+ part
14
+ ] }, i)) });
15
+ }
16
+ return /* @__PURE__ */ jsx("div", { className: `hero-feature-banner ${props.wrapperClassName || ""}`, children: /* @__PURE__ */ jsxs("div", { className: props.sectionBgClassName || "", children: [
17
+ /* @__PURE__ */ jsx("style", { children: `
18
+ .hfb-tint { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
19
+ .hfb-content { position: relative; z-index: 2; }
20
+ .hfb-bullet i { color: ${props.bulletIconColor || "var(--primary-color, #f97316)"}; font-size: 1.1rem; }
21
+ ` }),
22
+ props.customCSS && /* @__PURE__ */ jsx("style", { children: props.customCSS }),
23
+ /* @__PURE__ */ jsxs(
24
+ "section",
25
+ {
26
+ className: `relative w-full ${props.rounded || ""} overflow-hidden ${props.className || ""}`,
27
+ style: { minHeight: props.height || 560 },
28
+ children: [
29
+ /* @__PURE__ */ jsx(
30
+ Image,
31
+ {
32
+ src: props.bgImageSrc,
33
+ alt: props.bgAlt || "",
34
+ fill: true,
35
+ priority: true,
36
+ quality: 90,
37
+ sizes: "100vw",
38
+ style: {
39
+ objectFit: "cover",
40
+ objectPosition: "center right"
41
+ }
42
+ }
43
+ ),
44
+ props.leftTint && /* @__PURE__ */ jsx("div", { className: "hfb-tint" }),
45
+ /* @__PURE__ */ jsxs("div", { className: "hfb-content w-full h-full container", style: { position: "relative" }, children: [
46
+ /* @__PURE__ */ jsx("div", { className: "p-4 p-md-5", style: { height: "100%", display: "flex", flexDirection: "column", justifyContent: props.ctaPosition === "center" ? "center" : "flex-start" }, children: /* @__PURE__ */ jsxs("div", { style: { maxWidth: props.contentMaxWidth || 720 }, children: [
47
+ /* @__PURE__ */ jsx("h1", { className: props.headingClassName || "m-0 text-900", style: { fontSize: props.headingFontSize || 56, lineHeight: 1.05, fontWeight: 800, color: props.headingColor || void 0 }, children: headingNode }),
48
+ bullets.length > 0 && /* @__PURE__ */ jsx("ul", { className: "list-none m-0 p-0 mt-4", children: bullets.map((b, i) => /* @__PURE__ */ jsxs("li", { className: "flex align-items-center gap-3 mb-3 hfb-bullet", children: [
49
+ /* @__PURE__ */ jsx("span", { className: "flex align-items-center justify-content-center", style: { width: 34, height: 34, background: props.bulletIconBgColor || "rgba(255,100,50,.12)" }, children: /* @__PURE__ */ jsx("i", { className: `pi ${b.icon || "pi-check-circle"}` }) }),
50
+ /* @__PURE__ */ jsx("span", { className: props.bulletTextClassName || "text-800", style: { fontSize: 18, color: props.bulletTextColor || void 0 }, children: b.text })
51
+ ] }, i)) }),
52
+ props.ctaLabel && (!props.ctaPosition || props.ctaPosition === "left") && /* @__PURE__ */ jsx("div", { className: "mt-5", children: /* @__PURE__ */ jsxs(
53
+ Link,
54
+ {
55
+ href: props.ctaHref || "#",
56
+ className: props.ctaClassName || "no-underline inline-flex align-items-center gap-2 bg-primary text-white px-4 py-3 border-round-lg font-semibold",
57
+ style: { fontSize: 16, textDecoration: "none", color: props.ctaColor || void 0, backgroundColor: props.ctaBgColor || void 0 },
58
+ children: [
59
+ props.ctaIcon && /* @__PURE__ */ jsx("i", { className: props.ctaIcon }),
60
+ /* @__PURE__ */ jsx("span", { children: props.ctaLabel })
61
+ ]
62
+ }
63
+ ) })
64
+ ] }) }),
65
+ props.ctaLabel && props.ctaPosition && props.ctaPosition !== "left" && /* @__PURE__ */ jsx(
66
+ "div",
67
+ {
68
+ style: {
69
+ position: "absolute",
70
+ zIndex: 3,
71
+ ...props.ctaPosition === "center" && { top: "50%", left: "50%", transform: "translate(-50%, -50%)" },
72
+ ...props.ctaPosition === "top-left" && { top: "2rem", left: "2rem" },
73
+ ...props.ctaPosition === "top-right" && { top: "2rem", right: "2rem" },
74
+ ...props.ctaPosition === "bottom-left" && { bottom: "2rem", left: "2rem" },
75
+ ...props.ctaPosition === "bottom-right" && { bottom: "2rem", right: "2rem" }
76
+ },
77
+ children: /* @__PURE__ */ jsxs(
78
+ Link,
79
+ {
80
+ href: props.ctaHref || "#",
81
+ className: props.ctaClassName || "no-underline inline-flex align-items-center gap-2 bg-primary text-white px-4 py-3 border-round-lg font-semibold",
82
+ style: { fontSize: 16, textDecoration: "none", color: props.ctaColor || void 0, backgroundColor: props.ctaBgColor || void 0 },
83
+ children: [
84
+ props.ctaIcon && /* @__PURE__ */ jsx("i", { className: props.ctaIcon }),
85
+ /* @__PURE__ */ jsx("span", { children: props.ctaLabel })
86
+ ]
87
+ }
88
+ )
89
+ }
90
+ )
91
+ ] })
92
+ ]
93
+ }
94
+ )
95
+ ] }) });
96
+ };
97
+ export {
98
+ HeroFeatureBannerComponent
99
+ };
100
+ //# sourceMappingURL=HeroFeatureBannerComponent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeroFeatureBannerComponent.js","sources":["../../../src/components/landing/HeroFeatureBannerComponent.tsx"],"sourcesContent":["'use client';\n\nimport React from 'react';\nimport Link from 'next/link';\nimport Image from 'next/image';\n\nexport const HeroFeatureBannerComponent: React.FC<{ props: Record<string, any> }> = ({ props }) => {\n const bullets: any[] = Array.isArray(props.bullets) ? props.bullets : [];\n\n // Transform heading line breaks\n let headingNode: React.ReactNode = props.heading || '';\n if (typeof headingNode === 'string' && headingNode.includes('\\n')) {\n const parts = (headingNode as string).split('\\n');\n headingNode = (\n <>\n {parts.map((part: string, i: number) => (\n <React.Fragment key={i}>\n {i > 0 && <br />}\n {part}\n </React.Fragment>\n ))}\n </>\n );\n }\n\n return (\n <div className={`hero-feature-banner ${props.wrapperClassName || ''}`}>\n <div className={props.sectionBgClassName || ''}>\n <style>{`\n .hfb-tint { position: absolute; inset: 0; pointer-events: none; z-index: 1; }\n .hfb-content { position: relative; z-index: 2; }\n .hfb-bullet i { color: ${props.bulletIconColor || 'var(--primary-color, #f97316)'}; font-size: 1.1rem; }\n `}</style>\n {props.customCSS && <style>{props.customCSS}</style>}\n <section\n className={`relative w-full ${props.rounded || ''} overflow-hidden ${props.className || ''}`}\n style={{ minHeight: props.height || 560 }}\n >\n {/* Background Image using Next.js Image */}\n <Image\n src={props.bgImageSrc}\n alt={props.bgAlt || ''}\n fill\n priority\n quality={90}\n sizes=\"100vw\"\n style={{\n objectFit: 'cover',\n objectPosition: 'center right',\n }}\n />\n\n {props.leftTint && <div className=\"hfb-tint\" />}\n\n <div className=\"hfb-content w-full h-full container\" style={{ position: 'relative' }}>\n <div className=\"p-4 p-md-5\" style={{ height: '100%', display: 'flex', flexDirection: 'column', justifyContent: props.ctaPosition === 'center' ? 'center' : 'flex-start' }}>\n <div style={{ maxWidth: props.contentMaxWidth || 720 }}>\n <h1 className={props.headingClassName || 'm-0 text-900'} style={{ fontSize: props.headingFontSize || 56, lineHeight: 1.05, fontWeight: 800, color: props.headingColor || undefined }}>\n {headingNode}\n </h1>\n\n {bullets.length > 0 && (\n <ul className=\"list-none m-0 p-0 mt-4\">\n {bullets.map((b: any, i: number) => (\n <li key={i} className=\"flex align-items-center gap-3 mb-3 hfb-bullet\">\n <span className=\"flex align-items-center justify-content-center\" style={{ width: 34, height: 34, background: props.bulletIconBgColor || 'rgba(255,100,50,.12)' }}>\n <i className={`pi ${b.icon || 'pi-check-circle'}`} />\n </span>\n <span className={props.bulletTextClassName || 'text-800'} style={{ fontSize: 18, color: props.bulletTextColor || undefined }}>{b.text}</span>\n </li>\n ))}\n </ul>\n )}\n\n {props.ctaLabel && (!props.ctaPosition || props.ctaPosition === 'left') && (\n <div className=\"mt-5\">\n <Link\n href={props.ctaHref || '#'}\n className={props.ctaClassName || 'no-underline inline-flex align-items-center gap-2 bg-primary text-white px-4 py-3 border-round-lg font-semibold'}\n style={{ fontSize: 16, textDecoration: 'none', color: props.ctaColor || undefined, backgroundColor: props.ctaBgColor || undefined }}\n >\n {props.ctaIcon && <i className={props.ctaIcon} />}\n <span>{props.ctaLabel}</span>\n </Link>\n </div>\n )}\n </div>\n </div>\n \n {/* Positioned CTA button */}\n {props.ctaLabel && props.ctaPosition && props.ctaPosition !== 'left' && (\n <div \n style={{\n position: 'absolute',\n zIndex: 3,\n ...(props.ctaPosition === 'center' && { top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }),\n ...(props.ctaPosition === 'top-left' && { top: '2rem', left: '2rem' }),\n ...(props.ctaPosition === 'top-right' && { top: '2rem', right: '2rem' }),\n ...(props.ctaPosition === 'bottom-left' && { bottom: '2rem', left: '2rem' }),\n ...(props.ctaPosition === 'bottom-right' && { bottom: '2rem', right: '2rem' }),\n }}\n >\n <Link\n href={props.ctaHref || '#'}\n className={props.ctaClassName || 'no-underline inline-flex align-items-center gap-2 bg-primary text-white px-4 py-3 border-round-lg font-semibold'}\n style={{ fontSize: 16, textDecoration: 'none', color: props.ctaColor || undefined, backgroundColor: props.ctaBgColor || undefined }}\n >\n {props.ctaIcon && <i className={props.ctaIcon} />}\n <span>{props.ctaLabel}</span>\n </Link>\n </div>\n )}\n </div>\n </section>\n </div>\n </div>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { default as React } from 'react';
2
+ export type HeroBullet = {
3
+ icon?: string;
4
+ text: React.ReactNode;
5
+ };
6
+ export type HeroFeatureBannerVideoProps = {
7
+ bgVideoSrc?: string;
8
+ bgPosterSrc?: string;
9
+ bgPosterAlt?: string;
10
+ videoAutoplay?: boolean;
11
+ videoMuted?: boolean;
12
+ videoLoop?: boolean;
13
+ videoLazyLoad?: boolean;
14
+ /** Prioritize fetch/decode for above-the-fold hero usage */
15
+ videoPriority?: boolean;
16
+ heading: React.ReactNode;
17
+ bullets?: HeroBullet[];
18
+ cta?: {
19
+ label: string;
20
+ href?: string;
21
+ onClick?: () => void;
22
+ icon?: string;
23
+ backgroundColor?: string;
24
+ className?: string;
25
+ };
26
+ ctaPosition?: 'left' | 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
27
+ height?: number;
28
+ rounded?: string;
29
+ leftTint?: boolean;
30
+ contentMaxWidth?: number;
31
+ className?: string;
32
+ };
33
+ declare const HeroFeatureBannerVideo: React.FC<HeroFeatureBannerVideoProps>;
34
+ export default HeroFeatureBannerVideo;
@@ -0,0 +1,261 @@
1
+ "use client";
2
+ import { jsxs, jsx } from "react/jsx-runtime";
3
+ import { useRef, useState, useEffect } from "react";
4
+ function configureMobileVideo(video, muted) {
5
+ video.muted = muted;
6
+ video.defaultMuted = muted;
7
+ video.playsInline = true;
8
+ video.setAttribute("playsinline", "");
9
+ video.setAttribute("webkit-playsinline", "");
10
+ }
11
+ const HeroBackgroundVideo = ({ src, autoplay, muted, loop, lazyLoad, priority }) => {
12
+ const containerRef = useRef(null);
13
+ const videoRef = useRef(null);
14
+ const [shouldLoad, setShouldLoad] = useState(!lazyLoad);
15
+ const [isReady, setIsReady] = useState(false);
16
+ const [reduceMotion, setReduceMotion] = useState(false);
17
+ useEffect(() => {
18
+ const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
19
+ const update = () => setReduceMotion(mq.matches);
20
+ update();
21
+ mq.addEventListener("change", update);
22
+ return () => mq.removeEventListener("change", update);
23
+ }, []);
24
+ useEffect(() => {
25
+ if (!lazyLoad || shouldLoad || reduceMotion) return;
26
+ const node = containerRef.current;
27
+ if (!node || typeof IntersectionObserver === "undefined") {
28
+ setShouldLoad(true);
29
+ return;
30
+ }
31
+ const observer = new IntersectionObserver(
32
+ (entries) => {
33
+ if (entries.some((entry) => entry.isIntersecting)) {
34
+ setShouldLoad(true);
35
+ observer.disconnect();
36
+ }
37
+ },
38
+ { rootMargin: "200px 0px", threshold: 0.01 }
39
+ );
40
+ observer.observe(node);
41
+ return () => observer.disconnect();
42
+ }, [lazyLoad, shouldLoad, reduceMotion]);
43
+ useEffect(() => {
44
+ setIsReady(false);
45
+ }, [src]);
46
+ useEffect(() => {
47
+ const video = videoRef.current;
48
+ if (!video || !shouldLoad || reduceMotion) return;
49
+ configureMobileVideo(video, muted);
50
+ const tryPlay = () => {
51
+ setIsReady(true);
52
+ if (!autoplay) return;
53
+ configureMobileVideo(video, muted);
54
+ void video.play().catch(() => {
55
+ });
56
+ };
57
+ const onLoadedData = () => tryPlay();
58
+ const onCanPlay = () => tryPlay();
59
+ const onVisibilityChange = () => {
60
+ if (!document.hidden && autoplay && video.paused) {
61
+ configureMobileVideo(video, muted);
62
+ void video.play().catch(() => {
63
+ });
64
+ }
65
+ };
66
+ const hardFallback = window.setTimeout(tryPlay, 2e3);
67
+ if (video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
68
+ tryPlay();
69
+ }
70
+ video.addEventListener("loadeddata", onLoadedData);
71
+ video.addEventListener("canplay", onCanPlay);
72
+ document.addEventListener("visibilitychange", onVisibilityChange);
73
+ return () => {
74
+ window.clearTimeout(hardFallback);
75
+ video.removeEventListener("loadeddata", onLoadedData);
76
+ video.removeEventListener("canplay", onCanPlay);
77
+ document.removeEventListener("visibilitychange", onVisibilityChange);
78
+ };
79
+ }, [shouldLoad, autoplay, muted, reduceMotion, src]);
80
+ const setVideoRef = (node) => {
81
+ videoRef.current = node;
82
+ if (node) {
83
+ configureMobileVideo(node, muted);
84
+ }
85
+ };
86
+ if (reduceMotion || !src) {
87
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: "hfbv-media-layer", "aria-hidden": "true" });
88
+ }
89
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: "hfbv-media-layer", "aria-hidden": "true", children: shouldLoad && /* @__PURE__ */ jsx(
90
+ "video",
91
+ {
92
+ ref: setVideoRef,
93
+ className: `hfbv-video${isReady ? " hfbv-video--ready" : ""}`,
94
+ src,
95
+ muted,
96
+ loop,
97
+ autoPlay: autoplay,
98
+ playsInline: true,
99
+ preload: priority ? "auto" : "metadata",
100
+ fetchPriority: priority ? "high" : "auto",
101
+ disablePictureInPicture: true,
102
+ disableRemotePlayback: true,
103
+ tabIndex: -1
104
+ }
105
+ ) });
106
+ };
107
+ const HeroFeatureBannerVideo = ({
108
+ bgVideoSrc,
109
+ videoAutoplay = true,
110
+ videoMuted = true,
111
+ videoLoop = true,
112
+ videoLazyLoad = false,
113
+ videoPriority = true,
114
+ heading,
115
+ bullets = [],
116
+ cta,
117
+ ctaPosition = "left",
118
+ height = 560,
119
+ rounded = "",
120
+ leftTint = true,
121
+ contentMaxWidth = 720,
122
+ className = ""
123
+ }) => {
124
+ return /* @__PURE__ */ jsxs(
125
+ "section",
126
+ {
127
+ className: `relative w-full ${rounded} overflow-hidden ${className}`,
128
+ "aria-label": "Hero feature banner",
129
+ style: { minHeight: height },
130
+ children: [
131
+ /* @__PURE__ */ jsx("style", { children: `
132
+ .hfbv-media-stack { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
133
+ .hfbv-media-layer { position: absolute; inset: 0; width: 100%; height: 100%; }
134
+ .hfbv-video {
135
+ position: absolute;
136
+ inset: 0;
137
+ width: 100%;
138
+ height: 100%;
139
+ object-fit: cover;
140
+ object-position: center right;
141
+ opacity: 0;
142
+ transition: opacity 0.35s ease;
143
+ transform: translate3d(0, 0, 0);
144
+ backface-visibility: hidden;
145
+ -webkit-backface-visibility: hidden;
146
+ }
147
+ .hfbv-video--ready { opacity: 1; }
148
+ .hfbv-tint { position: absolute; inset: 0; pointer-events: none; z-index: 1; }
149
+ .hfbv-content { position: relative; z-index: 2; }
150
+ .hfbv-bullet i { color: var(--primary-color); font-size: 1.1rem; }
151
+ ` }),
152
+ /* @__PURE__ */ jsx("div", { className: "hfbv-media-stack", children: bgVideoSrc && /* @__PURE__ */ jsx(
153
+ HeroBackgroundVideo,
154
+ {
155
+ src: bgVideoSrc,
156
+ autoplay: videoAutoplay,
157
+ muted: videoMuted,
158
+ loop: videoLoop,
159
+ lazyLoad: videoLazyLoad,
160
+ priority: videoPriority
161
+ }
162
+ ) }),
163
+ leftTint && /* @__PURE__ */ jsx("div", { className: "hfbv-tint" }),
164
+ /* @__PURE__ */ jsxs("div", { className: "hfbv-content w-full h-full container", style: { position: "relative" }, children: [
165
+ /* @__PURE__ */ jsx(
166
+ "div",
167
+ {
168
+ className: "p-4 p-md-5",
169
+ style: {
170
+ height: "100%",
171
+ display: "flex",
172
+ flexDirection: "column",
173
+ justifyContent: ctaPosition === "center" ? "center" : "flex-start"
174
+ },
175
+ children: /* @__PURE__ */ jsxs("div", { style: { maxWidth: contentMaxWidth }, children: [
176
+ /* @__PURE__ */ jsx("h1", { className: "m-0 text-900", style: { fontSize: 56, lineHeight: 1.05, fontWeight: 800 }, children: heading }),
177
+ bullets.length > 0 && /* @__PURE__ */ jsx("ul", { className: "list-none m-0 p-0 mt-4", children: bullets.map((b, i) => /* @__PURE__ */ jsxs("li", { className: "flex align-items-center gap-3 mb-3 hfbv-bullet", children: [
178
+ /* @__PURE__ */ jsx(
179
+ "span",
180
+ {
181
+ className: "flex align-items-center justify-content-center",
182
+ style: { width: 34, height: 34, background: "rgba(255,100,50,.12)" },
183
+ children: /* @__PURE__ */ jsx("i", { className: `pi ${b.icon ?? "pi-check-circle"}` })
184
+ }
185
+ ),
186
+ /* @__PURE__ */ jsx("span", { className: "text-800", style: { fontSize: 18 }, children: b.text })
187
+ ] }, i)) }),
188
+ cta && ctaPosition === "left" && /* @__PURE__ */ jsx("div", { className: "mt-5", children: cta.href ? /* @__PURE__ */ jsxs(
189
+ "a",
190
+ {
191
+ href: cta.href,
192
+ className: `p-button p-component p-button-rounded p-button-lg ${cta.className || ""}`,
193
+ style: { textDecoration: "none", backgroundColor: cta.backgroundColor },
194
+ children: [
195
+ /* @__PURE__ */ jsx("span", { className: "p-button-icon p-button-icon-left pi pi-arrow-right" }),
196
+ /* @__PURE__ */ jsx("span", { className: "p-button-label", children: cta.label })
197
+ ]
198
+ }
199
+ ) : /* @__PURE__ */ jsxs(
200
+ "button",
201
+ {
202
+ type: "button",
203
+ className: `p-button p-component p-button-rounded p-button-lg ${cta.className || ""}`,
204
+ onClick: cta.onClick,
205
+ style: { backgroundColor: cta.backgroundColor },
206
+ children: [
207
+ /* @__PURE__ */ jsx("span", { className: "p-button-icon p-button-icon-left pi pi-arrow-right" }),
208
+ /* @__PURE__ */ jsx("span", { className: "p-button-label", children: cta.label })
209
+ ]
210
+ }
211
+ ) })
212
+ ] })
213
+ }
214
+ ),
215
+ cta && ctaPosition !== "left" && /* @__PURE__ */ jsx(
216
+ "div",
217
+ {
218
+ style: {
219
+ position: "absolute",
220
+ zIndex: 3,
221
+ ...ctaPosition === "center" && { top: "50%", left: "50%", transform: "translate(-50%, -50%)" },
222
+ ...ctaPosition === "top-left" && { top: "2rem", left: "2rem" },
223
+ ...ctaPosition === "top-right" && { top: "2rem", right: "2rem" },
224
+ ...ctaPosition === "bottom-left" && { bottom: "2rem", left: "2rem" },
225
+ ...ctaPosition === "bottom-right" && { bottom: "2rem", right: "2rem" }
226
+ },
227
+ children: cta.href ? /* @__PURE__ */ jsxs(
228
+ "a",
229
+ {
230
+ href: cta.href,
231
+ className: `p-button p-component p-button-rounded p-button-lg ${cta.className || ""}`,
232
+ style: { textDecoration: "none", backgroundColor: cta.backgroundColor },
233
+ children: [
234
+ /* @__PURE__ */ jsx("span", { className: "p-button-icon p-button-icon-left pi pi-arrow-right" }),
235
+ /* @__PURE__ */ jsx("span", { className: "p-button-label", children: cta.label })
236
+ ]
237
+ }
238
+ ) : /* @__PURE__ */ jsxs(
239
+ "button",
240
+ {
241
+ type: "button",
242
+ className: `p-button p-component p-button-rounded p-button-lg ${cta.className || ""}`,
243
+ onClick: cta.onClick,
244
+ style: { backgroundColor: cta.backgroundColor },
245
+ children: [
246
+ /* @__PURE__ */ jsx("span", { className: "p-button-icon p-button-icon-left pi pi-arrow-right" }),
247
+ /* @__PURE__ */ jsx("span", { className: "p-button-label", children: cta.label })
248
+ ]
249
+ }
250
+ )
251
+ }
252
+ )
253
+ ] })
254
+ ]
255
+ }
256
+ );
257
+ };
258
+ export {
259
+ HeroFeatureBannerVideo as default
260
+ };
261
+ //# sourceMappingURL=HeroFeatureBannerVideo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeroFeatureBannerVideo.js","sources":["../../../src/components/landing/HeroFeatureBannerVideo.tsx"],"sourcesContent":["'use client';\n\nimport React, { useEffect, useRef, useState } from 'react';\n\nexport type HeroBullet = {\n icon?: string;\n text: React.ReactNode;\n};\n\nexport type HeroFeatureBannerVideoProps = {\n bgVideoSrc?: string;\n bgPosterSrc?: string;\n bgPosterAlt?: string;\n videoAutoplay?: boolean;\n videoMuted?: boolean;\n videoLoop?: boolean;\n videoLazyLoad?: boolean;\n /** Prioritize fetch/decode for above-the-fold hero usage */\n videoPriority?: boolean;\n heading: React.ReactNode;\n bullets?: HeroBullet[];\n cta?: {\n label: string;\n href?: string;\n onClick?: () => void;\n icon?: string;\n backgroundColor?: string;\n className?: string;\n };\n ctaPosition?: 'left' | 'center' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';\n height?: number;\n rounded?: string;\n leftTint?: boolean;\n contentMaxWidth?: number;\n className?: string;\n};\n\nfunction configureMobileVideo(video: HTMLVideoElement, muted: boolean) {\n video.muted = muted;\n video.defaultMuted = muted;\n video.playsInline = true;\n video.setAttribute('playsinline', '');\n video.setAttribute('webkit-playsinline', '');\n}\n\nconst HeroBackgroundVideo: React.FC<{\n src: string;\n autoplay: boolean;\n muted: boolean;\n loop: boolean;\n lazyLoad: boolean;\n priority: boolean;\n}> = ({ src, autoplay, muted, loop, lazyLoad, priority }) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const videoRef = useRef<HTMLVideoElement>(null);\n const [shouldLoad, setShouldLoad] = useState(!lazyLoad);\n const [isReady, setIsReady] = useState(false);\n const [reduceMotion, setReduceMotion] = useState(false);\n\n useEffect(() => {\n const mq = window.matchMedia('(prefers-reduced-motion: reduce)');\n const update = () => setReduceMotion(mq.matches);\n update();\n mq.addEventListener('change', update);\n return () => mq.removeEventListener('change', update);\n }, []);\n\n useEffect(() => {\n if (!lazyLoad || shouldLoad || reduceMotion) return;\n\n const node = containerRef.current;\n if (!node || typeof IntersectionObserver === 'undefined') {\n setShouldLoad(true);\n return;\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n setShouldLoad(true);\n observer.disconnect();\n }\n },\n { rootMargin: '200px 0px', threshold: 0.01 }\n );\n\n observer.observe(node);\n return () => observer.disconnect();\n }, [lazyLoad, shouldLoad, reduceMotion]);\n\n useEffect(() => {\n setIsReady(false);\n }, [src]);\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video || !shouldLoad || reduceMotion) return;\n\n configureMobileVideo(video, muted);\n\n const tryPlay = () => {\n setIsReady(true);\n if (!autoplay) return;\n configureMobileVideo(video, muted);\n void video.play().catch(() => {\n // Autoplay may be blocked until a user gesture on some mobile browsers\n });\n };\n\n const onLoadedData = () => tryPlay();\n const onCanPlay = () => tryPlay();\n\n const onVisibilityChange = () => {\n if (!document.hidden && autoplay && video.paused) {\n configureMobileVideo(video, muted);\n void video.play().catch(() => {});\n }\n };\n\n // iOS Safari often never fires canplaythrough for large files — use loadeddata/canplay instead\n const hardFallback = window.setTimeout(tryPlay, 2000);\n\n if (video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {\n tryPlay();\n }\n\n video.addEventListener('loadeddata', onLoadedData);\n video.addEventListener('canplay', onCanPlay);\n document.addEventListener('visibilitychange', onVisibilityChange);\n\n return () => {\n window.clearTimeout(hardFallback);\n video.removeEventListener('loadeddata', onLoadedData);\n video.removeEventListener('canplay', onCanPlay);\n document.removeEventListener('visibilitychange', onVisibilityChange);\n };\n }, [shouldLoad, autoplay, muted, reduceMotion, src]);\n\n const setVideoRef = (node: HTMLVideoElement | null) => {\n videoRef.current = node;\n if (node) {\n configureMobileVideo(node, muted);\n }\n };\n\n if (reduceMotion || !src) {\n return <div ref={containerRef} className=\"hfbv-media-layer\" aria-hidden=\"true\" />;\n }\n\n return (\n <div ref={containerRef} className=\"hfbv-media-layer\" aria-hidden=\"true\">\n {shouldLoad && (\n <video\n ref={setVideoRef}\n className={`hfbv-video${isReady ? ' hfbv-video--ready' : ''}`}\n src={src}\n muted={muted}\n loop={loop}\n autoPlay={autoplay}\n playsInline\n preload={priority ? 'auto' : 'metadata'}\n // @ts-expect-error fetchPriority is supported in modern browsers\n fetchPriority={priority ? 'high' : 'auto'}\n disablePictureInPicture\n disableRemotePlayback\n tabIndex={-1}\n />\n )}\n </div>\n );\n};\n\nconst HeroFeatureBannerVideo: React.FC<HeroFeatureBannerVideoProps> = ({\n bgVideoSrc,\n videoAutoplay = true,\n videoMuted = true,\n videoLoop = true,\n videoLazyLoad = false,\n videoPriority = true,\n heading,\n bullets = [],\n cta,\n ctaPosition = 'left',\n height = 560,\n rounded = '',\n leftTint = true,\n contentMaxWidth = 720,\n className = '',\n}) => {\n return (\n <section\n className={`relative w-full ${rounded} overflow-hidden ${className}`}\n aria-label=\"Hero feature banner\"\n style={{ minHeight: height }}\n >\n <style>{`\n .hfbv-media-stack { position: absolute; inset: 0; z-index: 0; overflow: hidden; }\n .hfbv-media-layer { position: absolute; inset: 0; width: 100%; height: 100%; }\n .hfbv-video {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n object-position: center right;\n opacity: 0;\n transition: opacity 0.35s ease;\n transform: translate3d(0, 0, 0);\n backface-visibility: hidden;\n -webkit-backface-visibility: hidden;\n }\n .hfbv-video--ready { opacity: 1; }\n .hfbv-tint { position: absolute; inset: 0; pointer-events: none; z-index: 1; }\n .hfbv-content { position: relative; z-index: 2; }\n .hfbv-bullet i { color: var(--primary-color); font-size: 1.1rem; }\n `}</style>\n\n <div className=\"hfbv-media-stack\">\n {bgVideoSrc && (\n <HeroBackgroundVideo\n src={bgVideoSrc}\n autoplay={videoAutoplay}\n muted={videoMuted}\n loop={videoLoop}\n lazyLoad={videoLazyLoad}\n priority={videoPriority}\n />\n )}\n </div>\n\n {leftTint && <div className=\"hfbv-tint\" />}\n\n <div className=\"hfbv-content w-full h-full container\" style={{ position: 'relative' }}>\n <div\n className=\"p-4 p-md-5\"\n style={{\n height: '100%',\n display: 'flex',\n flexDirection: 'column',\n justifyContent: ctaPosition === 'center' ? 'center' : 'flex-start',\n }}\n >\n <div style={{ maxWidth: contentMaxWidth }}>\n <h1 className=\"m-0 text-900\" style={{ fontSize: 56, lineHeight: 1.05, fontWeight: 800 }}>\n {heading}\n </h1>\n\n {bullets.length > 0 && (\n <ul className=\"list-none m-0 p-0 mt-4\">\n {bullets.map((b, i) => (\n <li key={i} className=\"flex align-items-center gap-3 mb-3 hfbv-bullet\">\n <span\n className=\"flex align-items-center justify-content-center\"\n style={{ width: 34, height: 34, background: 'rgba(255,100,50,.12)' }}\n >\n <i className={`pi ${b.icon ?? 'pi-check-circle'}`} />\n </span>\n <span className=\"text-800\" style={{ fontSize: 18 }}>\n {b.text}\n </span>\n </li>\n ))}\n </ul>\n )}\n\n {cta && ctaPosition === 'left' && (\n <div className=\"mt-5\">\n {cta.href ? (\n <a\n href={cta.href}\n className={`p-button p-component p-button-rounded p-button-lg ${cta.className || ''}`}\n style={{ textDecoration: 'none', backgroundColor: cta.backgroundColor }}\n >\n <span className=\"p-button-icon p-button-icon-left pi pi-arrow-right\" />\n <span className=\"p-button-label\">{cta.label}</span>\n </a>\n ) : (\n <button\n type=\"button\"\n className={`p-button p-component p-button-rounded p-button-lg ${cta.className || ''}`}\n onClick={cta.onClick}\n style={{ backgroundColor: cta.backgroundColor }}\n >\n <span className=\"p-button-icon p-button-icon-left pi pi-arrow-right\" />\n <span className=\"p-button-label\">{cta.label}</span>\n </button>\n )}\n </div>\n )}\n </div>\n </div>\n\n {cta && ctaPosition !== 'left' && (\n <div\n style={{\n position: 'absolute',\n zIndex: 3,\n ...(ctaPosition === 'center' && { top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }),\n ...(ctaPosition === 'top-left' && { top: '2rem', left: '2rem' }),\n ...(ctaPosition === 'top-right' && { top: '2rem', right: '2rem' }),\n ...(ctaPosition === 'bottom-left' && { bottom: '2rem', left: '2rem' }),\n ...(ctaPosition === 'bottom-right' && { bottom: '2rem', right: '2rem' }),\n }}\n >\n {cta.href ? (\n <a\n href={cta.href}\n className={`p-button p-component p-button-rounded p-button-lg ${cta.className || ''}`}\n style={{ textDecoration: 'none', backgroundColor: cta.backgroundColor }}\n >\n <span className=\"p-button-icon p-button-icon-left pi pi-arrow-right\" />\n <span className=\"p-button-label\">{cta.label}</span>\n </a>\n ) : (\n <button\n type=\"button\"\n className={`p-button p-component p-button-rounded p-button-lg ${cta.className || ''}`}\n onClick={cta.onClick}\n style={{ backgroundColor: cta.backgroundColor }}\n >\n <span className=\"p-button-icon p-button-icon-left pi pi-arrow-right\" />\n <span className=\"p-button-label\">{cta.label}</span>\n </button>\n )}\n </div>\n )}\n </div>\n </section>\n );\n};\n\nexport default HeroFeatureBannerVideo;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { default as React } from 'react';
2
+ export declare const HeroFeatureBannerVideoComponent: React.FC<{
3
+ props: Record<string, any>;
4
+ isAboveFold?: boolean;
5
+ }>;
@@ -0,0 +1,69 @@
1
+ "use client";
2
+ import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
+ import React, { useEffect } from "react";
4
+ import HeroFeatureBannerVideo from "./HeroFeatureBannerVideo.js";
5
+ import { resolveMediaSrc } from "../../lib/resolveMediaSrc.js";
6
+ function useHeroVideoPreload(src, enabled = true) {
7
+ useEffect(() => {
8
+ if (!src || !enabled) return;
9
+ const existing = document.querySelector(`link[data-hfbv-preload="${src}"]`);
10
+ if (existing) return;
11
+ const link = document.createElement("link");
12
+ link.rel = "preload";
13
+ link.as = "video";
14
+ link.href = src;
15
+ link.setAttribute("fetchpriority", "high");
16
+ link.setAttribute("data-hfbv-preload", src);
17
+ document.head.appendChild(link);
18
+ return () => {
19
+ link.remove();
20
+ };
21
+ }, [src, enabled]);
22
+ }
23
+ const HeroFeatureBannerVideoComponent = ({ props, isAboveFold: _isAboveFold = false }) => {
24
+ const bullets = Array.isArray(props.bullets) ? props.bullets : [];
25
+ let headingNode = props.heading || "";
26
+ if (typeof headingNode === "string" && headingNode.includes("\n")) {
27
+ const parts = headingNode.split("\n");
28
+ headingNode = /* @__PURE__ */ jsx(Fragment, { children: parts.map((part, i) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
29
+ i > 0 && /* @__PURE__ */ jsx("br", {}),
30
+ part
31
+ ] }, i)) });
32
+ }
33
+ const cta = props.ctaLabel ? {
34
+ label: props.ctaLabel,
35
+ href: props.ctaHref,
36
+ icon: props.ctaIcon,
37
+ backgroundColor: props.ctaBgColor,
38
+ className: props.ctaClassName
39
+ } : void 0;
40
+ const bgVideoSrc = resolveMediaSrc(props.bgVideoSrc, props.bgVideoSrcNew);
41
+ useHeroVideoPreload(bgVideoSrc, Boolean(bgVideoSrc));
42
+ return /* @__PURE__ */ jsx("div", { className: `hero-feature-banner-video ${props.wrapperClassName || ""}`, children: /* @__PURE__ */ jsxs("div", { className: props.sectionBgClassName || "", children: [
43
+ props.customCSS && /* @__PURE__ */ jsx("style", { children: props.customCSS }),
44
+ /* @__PURE__ */ jsx(
45
+ HeroFeatureBannerVideo,
46
+ {
47
+ bgVideoSrc,
48
+ videoAutoplay: Boolean(bgVideoSrc),
49
+ videoMuted: true,
50
+ videoLoop: props.videoLoop !== false,
51
+ videoLazyLoad: false,
52
+ videoPriority: true,
53
+ heading: headingNode,
54
+ bullets,
55
+ cta,
56
+ ctaPosition: props.ctaPosition || "left",
57
+ height: props.height || 560,
58
+ rounded: props.rounded || "",
59
+ leftTint: props.leftTint !== false,
60
+ contentMaxWidth: props.contentMaxWidth || 720,
61
+ className: props.className || ""
62
+ }
63
+ )
64
+ ] }) });
65
+ };
66
+ export {
67
+ HeroFeatureBannerVideoComponent
68
+ };
69
+ //# sourceMappingURL=HeroFeatureBannerVideoComponent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeroFeatureBannerVideoComponent.js","sources":["../../../src/components/landing/HeroFeatureBannerVideoComponent.tsx"],"sourcesContent":["'use client';\n\nimport React, { useEffect } from 'react';\nimport HeroFeatureBannerVideo from './HeroFeatureBannerVideo';\nimport { resolveMediaSrc } from '../../lib/resolveMediaSrc';\n\nfunction useHeroVideoPreload(src?: string, enabled = true) {\n useEffect(() => {\n if (!src || !enabled) return;\n\n const existing = document.querySelector<HTMLLinkElement>(`link[data-hfbv-preload=\"${src}\"]`);\n if (existing) return;\n\n const link = document.createElement('link');\n link.rel = 'preload';\n link.as = 'video';\n link.href = src;\n link.setAttribute('fetchpriority', 'high');\n link.setAttribute('data-hfbv-preload', src);\n document.head.appendChild(link);\n\n return () => {\n link.remove();\n };\n }, [src, enabled]);\n}\n\nexport const HeroFeatureBannerVideoComponent: React.FC<{\n props: Record<string, any>;\n isAboveFold?: boolean;\n}> = ({ props, isAboveFold: _isAboveFold = false }) => {\n const bullets: any[] = Array.isArray(props.bullets) ? props.bullets : [];\n\n let headingNode: React.ReactNode = props.heading || '';\n if (typeof headingNode === 'string' && headingNode.includes('\\n')) {\n const parts = (headingNode as string).split('\\n');\n headingNode = (\n <>\n {parts.map((part: string, i: number) => (\n <React.Fragment key={i}>\n {i > 0 && <br />}\n {part}\n </React.Fragment>\n ))}\n </>\n );\n }\n\n const cta =\n props.ctaLabel\n ? {\n label: props.ctaLabel,\n href: props.ctaHref,\n icon: props.ctaIcon,\n backgroundColor: props.ctaBgColor,\n className: props.ctaClassName\n }\n : undefined;\n\n const bgVideoSrc = resolveMediaSrc(props.bgVideoSrc, props.bgVideoSrcNew);\n\n // Hero videos must load immediately — lazy load breaks mobile autoplay (especially iOS Safari)\n useHeroVideoPreload(bgVideoSrc, Boolean(bgVideoSrc));\n\n return (\n <div className={`hero-feature-banner-video ${props.wrapperClassName || ''}`}>\n <div className={props.sectionBgClassName || ''}>\n {props.customCSS && <style>{props.customCSS}</style>}\n <HeroFeatureBannerVideo\n bgVideoSrc={bgVideoSrc}\n videoAutoplay={Boolean(bgVideoSrc)}\n videoMuted\n videoLoop={props.videoLoop !== false}\n videoLazyLoad={false}\n videoPriority\n heading={headingNode}\n bullets={bullets}\n cta={cta}\n ctaPosition={props.ctaPosition || 'left'}\n height={props.height || 560}\n rounded={props.rounded || ''}\n leftTint={props.leftTint !== false}\n contentMaxWidth={props.contentMaxWidth || 720}\n className={props.className || ''}\n />\n </div>\n </div>\n );\n};\n"],"names":[],"mappings":";;;;;AAMA,SAAS,oBAAoB,KAAc,UAAU,MAAM;AACzD,YAAU,MAAM;AACd,QAAI,CAAC,OAAO,CAAC,QAAS;AAEtB,UAAM,WAAW,SAAS,cAA+B,2BAA2B,GAAG,IAAI;AAC3F,QAAI,SAAU;AAEd,UAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,SAAK,MAAM;AACX,SAAK,KAAK;AACV,SAAK,OAAO;AACZ,SAAK,aAAa,iBAAiB,MAAM;AACzC,SAAK,aAAa,qBAAqB,GAAG;AAC1C,aAAS,KAAK,YAAY,IAAI;AAE9B,WAAO,MAAM;AACX,WAAK,OAAA;AAAA,IACP;AAAA,EACF,GAAG,CAAC,KAAK,OAAO,CAAC;AACnB;AAEO,MAAM,kCAGR,CAAC,EAAE,OAAO,aAAa,eAAe,YAAY;AACrD,QAAM,UAAiB,MAAM,QAAQ,MAAM,OAAO,IAAI,MAAM,UAAU,CAAA;AAEtE,MAAI,cAA+B,MAAM,WAAW;AACpD,MAAI,OAAO,gBAAgB,YAAY,YAAY,SAAS,IAAI,GAAG;AACjE,UAAM,QAAS,YAAuB,MAAM,IAAI;AAChD,kBACE,oBAAA,UAAA,EACG,gBAAM,IAAI,CAAC,MAAc,MACxB,qBAAC,MAAM,UAAN,EACE,UAAA;AAAA,MAAA,IAAI,yBAAM,MAAA,CAAA,CAAG;AAAA,MACb;AAAA,IAAA,KAFkB,CAGrB,CACD,GACH;AAAA,EAEJ;AAEA,QAAM,MACJ,MAAM,WACF;AAAA,IACE,OAAO,MAAM;AAAA,IACb,MAAM,MAAM;AAAA,IACZ,MAAM,MAAM;AAAA,IACZ,iBAAiB,MAAM;AAAA,IACvB,WAAW,MAAM;AAAA,EAAA,IAEnB;AAEN,QAAM,aAAa,gBAAgB,MAAM,YAAY,MAAM,aAAa;AAGxE,sBAAoB,YAAY,QAAQ,UAAU,CAAC;AAEnD,SACE,oBAAC,OAAA,EAAI,WAAW,6BAA6B,MAAM,oBAAoB,EAAE,IACvE,UAAA,qBAAC,OAAA,EAAI,WAAW,MAAM,sBAAsB,IACzC,UAAA;AAAA,IAAA,MAAM,aAAa,oBAAC,SAAA,EAAO,UAAA,MAAM,WAAU;AAAA,IAC5C;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,eAAe,QAAQ,UAAU;AAAA,QACjC,YAAU;AAAA,QACV,WAAW,MAAM,cAAc;AAAA,QAC/B,eAAe;AAAA,QACf,eAAa;AAAA,QACb,SAAS;AAAA,QACT;AAAA,QACA;AAAA,QACA,aAAa,MAAM,eAAe;AAAA,QAClC,QAAQ,MAAM,UAAU;AAAA,QACxB,SAAS,MAAM,WAAW;AAAA,QAC1B,UAAU,MAAM,aAAa;AAAA,QAC7B,iBAAiB,MAAM,mBAAmB;AAAA,QAC1C,WAAW,MAAM,aAAa;AAAA,MAAA;AAAA,IAAA;AAAA,EAChC,EAAA,CACF,EAAA,CACF;AAEJ;"}
@@ -0,0 +1,4 @@
1
+ import { default as React } from 'react';
2
+ export declare const ReviewsListRender: React.FC<{
3
+ props: Record<string, any>;
4
+ }>;