@clubmed/trident-ui 2.0.0-beta.75 → 2.0.0-beta.76
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/examples/chapters-demo.d.ts +1 -0
- package/examples/chapters-demo.js +46 -0
- package/examples/chapters-demo.js.map +1 -0
- package/examples/promises-demo.d.ts +1 -0
- package/examples/promises-demo.js +50 -0
- package/examples/promises-demo.js.map +1 -0
- package/examples/sparkle-wrapper-demo.d.ts +1 -0
- package/examples/sparkle-wrapper-demo.js +34 -0
- package/examples/sparkle-wrapper-demo.js.map +1 -0
- package/package.json +1 -1
- package/styles/animate.css +19 -0
- package/styles/theme.css +1 -0
- package/ui/Chapters/Chapter.d.ts +7 -0
- package/ui/Chapters/Chapter.js +36 -0
- package/ui/Chapters/Chapter.js.map +1 -0
- package/ui/Chapters/ChapterTitle.d.ts +14 -0
- package/ui/Chapters/ChapterTitle.js +35 -0
- package/ui/Chapters/ChapterTitle.js.map +1 -0
- package/ui/Chapters/Chapters.d.ts +15 -0
- package/ui/Chapters/Chapters.js +42 -0
- package/ui/Chapters/Chapters.js.map +1 -0
- package/ui/Chapters/Chapters.themes.d.ts +9 -0
- package/ui/Chapters/Chapters.themes.js +65 -0
- package/ui/Chapters/Chapters.themes.js.map +1 -0
- package/ui/Chapters/ChaptersSummary.d.ts +17 -0
- package/ui/Chapters/ChaptersSummary.js +29 -0
- package/ui/Chapters/ChaptersSummary.js.map +1 -0
- package/ui/Promises/Promises.d.ts +26 -0
- package/ui/Promises/Promises.js +42 -0
- package/ui/Promises/Promises.js.map +1 -0
- package/ui/Promises/PromisesMedia.d.ts +12 -0
- package/ui/Promises/PromisesMedia.js +64 -0
- package/ui/Promises/PromisesMedia.js.map +1 -0
- package/ui/Promises/PromisesMenu.d.ts +11 -0
- package/ui/Promises/PromisesMenu.js +154 -0
- package/ui/Promises/PromisesMenu.js.map +1 -0
- package/ui/SparkleWrapper.d.ts +5 -0
- package/ui/SparkleWrapper.js +56 -0
- package/ui/SparkleWrapper.js.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function ChaptersDemo(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Chapters as e } from "../ui/Chapters/Chapters.js";
|
|
3
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
4
|
+
//#region lib/examples/chapters-demo.tsx
|
|
5
|
+
function n() {
|
|
6
|
+
return /* @__PURE__ */ t(e, {
|
|
7
|
+
chapters: [
|
|
8
|
+
{
|
|
9
|
+
title: "All-inclusive experience",
|
|
10
|
+
content: /* @__PURE__ */ t("div", {
|
|
11
|
+
className: "min-h-screen p-40",
|
|
12
|
+
children: /* @__PURE__ */ t("p", {
|
|
13
|
+
className: "text-body max-w-prose",
|
|
14
|
+
children: "From sunrise yoga to late-night entertainment, every moment is included. Fine dining, premium beverages, world-class facilities — yours without a second thought."
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
title: "Sports & activities",
|
|
20
|
+
content: /* @__PURE__ */ t("div", {
|
|
21
|
+
className: "min-h-screen p-40",
|
|
22
|
+
children: /* @__PURE__ */ t("p", {
|
|
23
|
+
className: "text-body max-w-prose",
|
|
24
|
+
children: "Surf, dive, sail, climb — over 60 land and water sports await you. Our certified instructors guide guests of all levels, from first-timers to seasoned athletes."
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
title: "Kids clubs",
|
|
30
|
+
content: /* @__PURE__ */ t("div", {
|
|
31
|
+
className: "min-h-screen p-40",
|
|
32
|
+
children: /* @__PURE__ */ t("p", {
|
|
33
|
+
className: "text-body max-w-prose",
|
|
34
|
+
children: "Dedicated clubs for every age from 4 months to 17 years. Supervised activities, creative workshops, and adventure programmes tailored to each stage of childhood."
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
theme: "coreRange",
|
|
40
|
+
className: "w-full"
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { n as default };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=chapters-demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chapters-demo.js","names":[],"sources":["../../lib/examples/chapters-demo.tsx"],"sourcesContent":["'use client';\n\nimport { Chapters } from '@/ui/Chapters/Chapters';\n\nexport default function ChaptersDemo() {\n return (\n <Chapters\n chapters={[\n {\n title: 'All-inclusive experience',\n content: (\n <div className=\"min-h-screen p-40\">\n <p className=\"text-body max-w-prose\">\n From sunrise yoga to late-night entertainment, every moment is included. Fine\n dining, premium beverages, world-class facilities — yours without a second thought.\n </p>\n </div>\n ),\n },\n {\n title: 'Sports & activities',\n content: (\n <div className=\"min-h-screen p-40\">\n <p className=\"text-body max-w-prose\">\n Surf, dive, sail, climb — over 60 land and water sports await you. Our certified\n instructors guide guests of all levels, from first-timers to seasoned athletes.\n </p>\n </div>\n ),\n },\n {\n title: 'Kids clubs',\n content: (\n <div className=\"min-h-screen p-40\">\n <p className=\"text-body max-w-prose\">\n Dedicated clubs for every age from 4 months to 17 years. Supervised activities,\n creative workshops, and adventure programmes tailored to each stage of childhood.\n </p>\n </div>\n ),\n },\n ]}\n theme=\"coreRange\"\n className=\"w-full\"\n />\n );\n}\n"],"mappings":";;;;AAIA,SAAwB,IAAe;AACrC,QACE,kBAAC,GAAD;EACE,UAAU;GACR;IACE,OAAO;IACP,SACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,KAAD;MAAG,WAAU;gBAAwB;MAGjC,CAAA;KACA,CAAA;IAET;GACD;IACE,OAAO;IACP,SACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,KAAD;MAAG,WAAU;gBAAwB;MAGjC,CAAA;KACA,CAAA;IAET;GACD;IACE,OAAO;IACP,SACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,KAAD;MAAG,WAAU;gBAAwB;MAGjC,CAAA;KACA,CAAA;;GAGX;EACD,OAAM;EACN,WAAU;EACV,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function PromisesDemo(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Promises as e } from "../ui/Promises/Promises.js";
|
|
3
|
+
import { jsx as t } from "react/jsx-runtime";
|
|
4
|
+
//#region lib/examples/promises-demo.tsx
|
|
5
|
+
function n() {
|
|
6
|
+
return /* @__PURE__ */ t(e, {
|
|
7
|
+
className: "min-h-500 w-full",
|
|
8
|
+
items: [
|
|
9
|
+
{
|
|
10
|
+
title: "The most beautiful destinations",
|
|
11
|
+
href: "#",
|
|
12
|
+
image: {
|
|
13
|
+
src: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=400",
|
|
14
|
+
alt: "Beautiful beach destination"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
title: "Kids club starting from 4 months",
|
|
19
|
+
href: "#",
|
|
20
|
+
image: {
|
|
21
|
+
src: "https://images.unsplash.com/photo-1529156069898-49953e39b3ac?w=400",
|
|
22
|
+
alt: "Kids playing at the club"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
title: "The best restaurants on the coast",
|
|
27
|
+
href: "#",
|
|
28
|
+
image: {
|
|
29
|
+
src: "https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=400",
|
|
30
|
+
alt: "Fine dining restaurant"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
labels: {
|
|
35
|
+
anchor: { continue: "Discover" },
|
|
36
|
+
layer: {
|
|
37
|
+
close: "Close menu",
|
|
38
|
+
open: "Open menu"
|
|
39
|
+
},
|
|
40
|
+
scroller: {
|
|
41
|
+
previous: "Previous",
|
|
42
|
+
next: "Next"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { n as default };
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=promises-demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promises-demo.js","names":[],"sources":["../../lib/examples/promises-demo.tsx"],"sourcesContent":["'use client';\n\nimport { Promises } from '@/ui/Promises/Promises';\n\nexport default function PromisesDemo() {\n return (\n <Promises\n className=\"min-h-500 w-full\"\n items={[\n {\n title: 'The most beautiful destinations',\n href: '#',\n image: {\n src: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=400',\n alt: 'Beautiful beach destination',\n },\n },\n {\n title: 'Kids club starting from 4 months',\n href: '#',\n image: {\n src: 'https://images.unsplash.com/photo-1529156069898-49953e39b3ac?w=400',\n alt: 'Kids playing at the club',\n },\n },\n {\n title: 'The best restaurants on the coast',\n href: '#',\n image: {\n src: 'https://images.unsplash.com/photo-1414235077428-338989a2e8c0?w=400',\n alt: 'Fine dining restaurant',\n },\n },\n ]}\n labels={{\n anchor: { continue: 'Discover' },\n layer: { close: 'Close menu', open: 'Open menu' },\n scroller: { previous: 'Previous', next: 'Next' },\n }}\n />\n );\n}\n"],"mappings":";;;;AAIA,SAAwB,IAAe;AACrC,QACE,kBAAC,GAAD;EACE,WAAU;EACV,OAAO;GACL;IACE,OAAO;IACP,MAAM;IACN,OAAO;KACL,KAAK;KACL,KAAK;;IAER;GACD;IACE,OAAO;IACP,MAAM;IACN,OAAO;KACL,KAAK;KACL,KAAK;;IAER;GACD;IACE,OAAO;IACP,MAAM;IACN,OAAO;KACL,KAAK;KACL,KAAK;;;GAGV;EACD,QAAQ;GACN,QAAQ,EAAE,UAAU,YAAY;GAChC,OAAO;IAAE,OAAO;IAAc,MAAM;IAAa;GACjD,UAAU;IAAE,UAAU;IAAY,MAAM;;;EAE1C,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function SparkleWrapperDemo(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { SparkleWrapper as e } from "../ui/SparkleWrapper.js";
|
|
3
|
+
import { useState as t } from "react";
|
|
4
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
5
|
+
//#region lib/examples/sparkle-wrapper-demo.tsx
|
|
6
|
+
function i() {
|
|
7
|
+
let [i, a] = t(0);
|
|
8
|
+
return /* @__PURE__ */ r("div", {
|
|
9
|
+
className: "flex flex-col items-center gap-48 p-48",
|
|
10
|
+
children: [
|
|
11
|
+
/* @__PURE__ */ n(e, {
|
|
12
|
+
count: 3,
|
|
13
|
+
children: /* @__PURE__ */ n("div", {
|
|
14
|
+
className: "bg-saffron text-black font-bold px-20 py-12 rounded-pill text-b3",
|
|
15
|
+
children: "✨ New feature"
|
|
16
|
+
})
|
|
17
|
+
}, i),
|
|
18
|
+
/* @__PURE__ */ n(e, { children: /* @__PURE__ */ n("span", {
|
|
19
|
+
className: "text-h4 font-bold",
|
|
20
|
+
children: "🎉 Congratulations!"
|
|
21
|
+
}) }, `b-${i}`),
|
|
22
|
+
/* @__PURE__ */ n("button", {
|
|
23
|
+
type: "button",
|
|
24
|
+
onClick: () => a((e) => e + 1),
|
|
25
|
+
className: "px-20 py-10 rounded-pill border-2 border-black font-semibold text-b3 hover:bg-black hover:text-white transition-colors cursor-pointer",
|
|
26
|
+
children: "Replay animation"
|
|
27
|
+
})
|
|
28
|
+
]
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
export { i as default };
|
|
33
|
+
|
|
34
|
+
//# sourceMappingURL=sparkle-wrapper-demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sparkle-wrapper-demo.js","names":[],"sources":["../../lib/examples/sparkle-wrapper-demo.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { SparkleWrapper } from '@/ui/SparkleWrapper';\n\nexport default function SparkleWrapperDemo() {\n const [key, setKey] = useState(0);\n\n return (\n <div className=\"flex flex-col items-center gap-48 p-48\">\n <SparkleWrapper count={3} key={key}>\n <div className=\"bg-saffron text-black font-bold px-20 py-12 rounded-pill text-b3\">\n ✨ New feature\n </div>\n </SparkleWrapper>\n\n <SparkleWrapper key={`b-${key}`}>\n <span className=\"text-h4 font-bold\">🎉 Congratulations!</span>\n </SparkleWrapper>\n\n <button\n type=\"button\"\n onClick={() => setKey((k) => k + 1)}\n className=\"px-20 py-10 rounded-pill border-2 border-black font-semibold text-b3 hover:bg-black hover:text-white transition-colors cursor-pointer\"\n >\n Replay animation\n </button>\n </div>\n );\n}\n"],"mappings":";;;;;AAKA,SAAwB,IAAqB;CAC3C,IAAM,CAAC,GAAK,KAAU,EAAS,EAAE;AAEjC,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD;IAAgB,OAAO;cACrB,kBAAC,OAAD;KAAK,WAAU;eAAmE;KAE5E,CAAA;IACS,EAJc,EAId;GAEjB,kBAAC,GAAD,EAAA,UACE,kBAAC,QAAD;IAAM,WAAU;cAAoB;IAA0B,CAAA,EAC/C,EAFI,KAAK,IAET;GAEjB,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,GAAQ,MAAM,IAAI,EAAE;IACnC,WAAU;cACX;IAEQ,CAAA"}
|
package/package.json
CHANGED
package/styles/animate.css
CHANGED
|
@@ -299,3 +299,22 @@
|
|
|
299
299
|
transform: translateX(0px);
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
|
+
|
|
303
|
+
@keyframes sparkle-fly {
|
|
304
|
+
0% {
|
|
305
|
+
opacity: 1;
|
|
306
|
+
transform: translate(
|
|
307
|
+
calc(-50% + var(--sparkle-start-x, 0px)),
|
|
308
|
+
calc(-50% + var(--sparkle-start-y, 0px))
|
|
309
|
+
)
|
|
310
|
+
scale(1);
|
|
311
|
+
}
|
|
312
|
+
100% {
|
|
313
|
+
opacity: 0;
|
|
314
|
+
transform: translate(
|
|
315
|
+
calc(-50% + var(--sparkle-end-x, 0px)),
|
|
316
|
+
calc(-50% + var(--sparkle-end-y, 0px))
|
|
317
|
+
)
|
|
318
|
+
scale(0);
|
|
319
|
+
}
|
|
320
|
+
}
|
package/styles/theme.css
CHANGED
|
@@ -174,4 +174,5 @@
|
|
|
174
174
|
--animate-zoom-in: zoom-in 220ms cubic-bezier(0.2, 0.8, 0.2, 1) forwards; /* NOT IN DCX */
|
|
175
175
|
--animate-zoom-out: zoom-out 180ms cubic-bezier(0.4, 0, 1, 1) forwards; /* NOT IN DCX */
|
|
176
176
|
--animate-wiggle: wiggle 0.75s ease-in-out;
|
|
177
|
+
--animate-sparkle-fly: sparkle-fly 900ms ease-out both;
|
|
177
178
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect as e, useRef as t } from "react";
|
|
3
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
4
|
+
var r = (() => {
|
|
5
|
+
let e = [];
|
|
6
|
+
for (let t = 0; t <= 1; t += .03) e.push(parseFloat(t.toFixed(2)));
|
|
7
|
+
return e;
|
|
8
|
+
})(), i = (e) => {
|
|
9
|
+
let t = e.boundingClientRect.height <= window.innerHeight / 2 && e.intersectionRect.height > window.innerHeight / 3, n = e.boundingClientRect.height <= window.innerHeight / 2 && e.boundingClientRect.height === e.intersectionRect.height, r = e.boundingClientRect.height > window.innerHeight / 2 && e.intersectionRect.height > window.innerHeight / 2;
|
|
10
|
+
return t || n || r;
|
|
11
|
+
}, a = ({ children: a, index: o, setActiveChapter: s }) => {
|
|
12
|
+
let c = t(null);
|
|
13
|
+
return e(() => {
|
|
14
|
+
let e = c.current;
|
|
15
|
+
if (e) {
|
|
16
|
+
let t = new IntersectionObserver(([e]) => {
|
|
17
|
+
i(e) && s(o);
|
|
18
|
+
}, {
|
|
19
|
+
threshold: r,
|
|
20
|
+
rootMargin: "0px 0px 0px 0px"
|
|
21
|
+
});
|
|
22
|
+
return t.observe(e), () => t.unobserve(e);
|
|
23
|
+
}
|
|
24
|
+
}, [
|
|
25
|
+
c,
|
|
26
|
+
o,
|
|
27
|
+
s
|
|
28
|
+
]), /* @__PURE__ */ n("section", {
|
|
29
|
+
ref: c,
|
|
30
|
+
children: a
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { a as Chapter };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=Chapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Chapter.js","names":[],"sources":["../../../lib/ui/Chapters/Chapter.tsx"],"sourcesContent":["'use client';\nimport { useEffect, useRef, type FunctionComponent, type PropsWithChildren } from 'react';\n\ninterface Props {\n index: number;\n setActiveChapter: (index: number) => void;\n}\n\nconst generateThreshold = () => {\n const threshold: number[] = [];\n\n for (let i = 0; i <= 1; i += 0.03) {\n threshold.push(parseFloat(i.toFixed(2)));\n }\n\n return threshold;\n};\n\nconst THRESHOLD = generateThreshold();\n\nconst isChapterActive = (entry: IntersectionObserverEntry) => {\n const isHalfHeightAndOneThirdVisible =\n entry.boundingClientRect.height <= window.innerHeight / 2 &&\n entry.intersectionRect.height > window.innerHeight / 3;\n\n const isHalfHeightAndFullyVisible =\n entry.boundingClientRect.height <= window.innerHeight / 2 &&\n entry.boundingClientRect.height === entry.intersectionRect.height;\n\n const isMoreThanHalfHeightAndHalfVisible =\n entry.boundingClientRect.height > window.innerHeight / 2 &&\n entry.intersectionRect.height > window.innerHeight / 2;\n\n return (\n isHalfHeightAndOneThirdVisible ||\n isHalfHeightAndFullyVisible ||\n isMoreThanHalfHeightAndHalfVisible\n );\n};\n\nexport const Chapter: FunctionComponent<PropsWithChildren<Props>> = ({\n children,\n index,\n setActiveChapter,\n}) => {\n const element = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const current = element.current;\n\n if (current) {\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (isChapterActive(entry)) {\n setActiveChapter(index);\n }\n },\n {\n threshold: THRESHOLD,\n rootMargin: '0px 0px 0px 0px',\n },\n );\n\n observer.observe(current);\n\n return () => observer.unobserve(current);\n }\n }, [element, index, setActiveChapter]);\n\n return <section ref={element}>{children}</section>;\n};\n"],"mappings":";;;AAkBA,IAAM,WAV0B;CAC9B,IAAM,IAAsB,EAAE;AAE9B,MAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK,IAC3B,GAAU,KAAK,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC;AAG1C,QAAO;IAG4B,EAE/B,KAAmB,MAAqC;CAC5D,IAAM,IACJ,EAAM,mBAAmB,UAAU,OAAO,cAAc,KACxD,EAAM,iBAAiB,SAAS,OAAO,cAAc,GAEjD,IACJ,EAAM,mBAAmB,UAAU,OAAO,cAAc,KACxD,EAAM,mBAAmB,WAAW,EAAM,iBAAiB,QAEvD,IACJ,EAAM,mBAAmB,SAAS,OAAO,cAAc,KACvD,EAAM,iBAAiB,SAAS,OAAO,cAAc;AAEvD,QACE,KACA,KACA;GAIS,KAAwD,EACnE,aACA,UACA,0BACI;CACJ,IAAM,IAAU,EAAuB,KAAK;AAwB5C,QAtBA,QAAgB;EACd,IAAM,IAAU,EAAQ;AAExB,MAAI,GAAS;GACX,IAAM,IAAW,IAAI,sBAClB,CAAC,OAAW;AACX,IAAI,EAAgB,EAAM,IACxB,EAAiB,EAAM;MAG3B;IACE,WAAW;IACX,YAAY;IACb,CACF;AAID,UAFA,EAAS,QAAQ,EAAQ,QAEZ,EAAS,UAAU,EAAQ;;IAEzC;EAAC;EAAS;EAAO;EAAiB,CAAC,EAE/B,kBAAC,WAAD;EAAS,KAAK;EAAU;EAAmB,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ComponentProps, FunctionComponent, PropsWithChildren } from 'react';
|
|
2
|
+
import { Heading } from '../heading/Heading';
|
|
3
|
+
import { Theme } from '../types/Theme';
|
|
4
|
+
interface Props {
|
|
5
|
+
className?: string;
|
|
6
|
+
hasNext?: boolean;
|
|
7
|
+
hLevel?: ComponentProps<typeof Heading>['level'];
|
|
8
|
+
index: number;
|
|
9
|
+
isActive?: boolean;
|
|
10
|
+
onClick?: () => void;
|
|
11
|
+
theme?: Theme;
|
|
12
|
+
}
|
|
13
|
+
export declare const ChapterTitle: FunctionComponent<PropsWithChildren<Props>>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as e } from "../../chunks/clsx.js";
|
|
3
|
+
import { Heading as t } from "../heading/Heading.js";
|
|
4
|
+
import { getTheme as n } from "./Chapters.themes.js";
|
|
5
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
6
|
+
import { Icon as a } from "@clubmed/trident-icons";
|
|
7
|
+
//#region lib/ui/Chapters/ChapterTitle.tsx
|
|
8
|
+
var o = ({ children: o, className: s, hasNext: c = !1, hLevel: l = 2, index: u, isActive: d = !1, onClick: f, theme: p = "coreRange" }) => {
|
|
9
|
+
let { thTitle: m, thTitleUnActive: h } = n(p);
|
|
10
|
+
return /* @__PURE__ */ i(t, {
|
|
11
|
+
className: e("text-h5 @md:text-h2 sticky top-0 z-1 flex justify-between gap-x-8 p-20 font-serif transition-colors duration-300 @md:static @md:bg-transparent @md:p-0", m, s),
|
|
12
|
+
id: `chapter${u}`,
|
|
13
|
+
level: l,
|
|
14
|
+
children: [/* @__PURE__ */ i("a", {
|
|
15
|
+
className: e("flex-1", { [h]: !d }),
|
|
16
|
+
href: `#chapter${u}`,
|
|
17
|
+
onClick: f,
|
|
18
|
+
children: [/* @__PURE__ */ i("span", {
|
|
19
|
+
className: "@md:hidden",
|
|
20
|
+
children: [u + 1, " - "]
|
|
21
|
+
}), o]
|
|
22
|
+
}), c && /* @__PURE__ */ r("a", {
|
|
23
|
+
className: "@md:hidden",
|
|
24
|
+
href: `#chapter${u + 1}`,
|
|
25
|
+
children: /* @__PURE__ */ r(a, {
|
|
26
|
+
name: "ArrowTailDown",
|
|
27
|
+
width: "24px"
|
|
28
|
+
})
|
|
29
|
+
})]
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { o as ChapterTitle };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=ChapterTitle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChapterTitle.js","names":[],"sources":["../../../lib/ui/Chapters/ChapterTitle.tsx"],"sourcesContent":["'use client';\nimport clsx from 'clsx';\nimport type { ComponentProps, FunctionComponent, PropsWithChildren } from 'react';\n\nimport { Icon } from '@clubmed/trident-icons';\nimport { Heading } from '../heading/Heading';\nimport type { Theme } from '../types/Theme';\n\nimport { getTheme } from './Chapters.themes';\n\ninterface Props {\n className?: string;\n hasNext?: boolean;\n hLevel?: ComponentProps<typeof Heading>['level'];\n index: number;\n isActive?: boolean;\n onClick?: () => void;\n theme?: Theme;\n}\n\nexport const ChapterTitle: FunctionComponent<PropsWithChildren<Props>> = ({\n children,\n className,\n hasNext = false,\n hLevel = 2,\n index,\n isActive = false,\n onClick,\n theme = 'coreRange',\n}) => {\n const { thTitle, thTitleUnActive } = getTheme(theme);\n\n return (\n <Heading\n className={clsx(\n 'text-h5 @md:text-h2 sticky top-0 z-1 flex justify-between gap-x-8 p-20 font-serif transition-colors duration-300 @md:static @md:bg-transparent @md:p-0',\n thTitle,\n className,\n )}\n id={`chapter${index}`}\n level={hLevel}\n >\n <a\n className={clsx('flex-1', {\n [thTitleUnActive]: !isActive,\n })}\n href={`#chapter${index}`}\n onClick={onClick}\n >\n <span className=\"@md:hidden\">{index + 1} - </span>\n {children}\n </a>\n {hasNext && (\n <a className=\"@md:hidden\" href={`#chapter${index + 1}`}>\n <Icon name=\"ArrowTailDown\" width=\"24px\" />\n </a>\n )}\n </Heading>\n );\n};\n"],"mappings":";;;;;;;AAoBA,IAAa,KAA6D,EACxE,aACA,cACA,aAAU,IACV,YAAS,GACT,UACA,cAAW,IACX,YACA,WAAQ,kBACJ;CACJ,IAAM,EAAE,YAAS,uBAAoB,EAAS,EAAM;AAEpD,QACE,kBAAC,GAAD;EACE,WAAW,EACT,0JACA,GACA,EACD;EACD,IAAI,UAAU;EACd,OAAO;YAPT,CASE,kBAAC,KAAD;GACE,WAAW,EAAK,UAAU,GACvB,IAAkB,CAAC,GACrB,CAAC;GACF,MAAM,WAAW;GACR;aALX,CAOE,kBAAC,QAAD;IAAM,WAAU;cAAhB,CAA8B,IAAQ,GAAE,MAAA;OACvC,EAAA;MAEF,KACC,kBAAC,KAAD;GAAG,WAAU;GAAa,MAAM,WAAW,IAAQ;aACjD,kBAAC,GAAD;IAAM,MAAK;IAAgB,OAAM;IAAS,CAAA;GACxC,CAAA,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, FunctionComponent, ReactNode } from 'react';
|
|
2
|
+
import { IconicNames } from '@clubmed/trident-icons';
|
|
3
|
+
import { Theme } from '../types/Theme';
|
|
4
|
+
export interface ChapterItem {
|
|
5
|
+
content: ReactNode;
|
|
6
|
+
title: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ChaptersProps extends Omit<ComponentPropsWithoutRef<'section'>, 'onClick' | 'children'> {
|
|
9
|
+
chapters: ChapterItem[];
|
|
10
|
+
hLevel?: 2 | 3 | 4;
|
|
11
|
+
icon?: IconicNames;
|
|
12
|
+
onClick?: (chapter: ChapterItem) => void;
|
|
13
|
+
theme?: Theme;
|
|
14
|
+
}
|
|
15
|
+
export declare const Chapters: FunctionComponent<ChaptersProps>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as e } from "../../chunks/clsx.js";
|
|
3
|
+
import { Chapter as t } from "./Chapter.js";
|
|
4
|
+
import { ChapterTitle as n } from "./ChapterTitle.js";
|
|
5
|
+
import { ChaptersSummary as r } from "./ChaptersSummary.js";
|
|
6
|
+
import { useState as i } from "react";
|
|
7
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
8
|
+
//#region lib/ui/Chapters/Chapters.tsx
|
|
9
|
+
var s = ({ chapters: s, className: c, hLevel: l = 2, icon: u, onClick: d, theme: f = "coreRange", ...p }) => {
|
|
10
|
+
let [m, h] = i(0);
|
|
11
|
+
return /* @__PURE__ */ o("section", {
|
|
12
|
+
...p,
|
|
13
|
+
className: e(c, "flex @container/chapters"),
|
|
14
|
+
children: [/* @__PURE__ */ a(r, {
|
|
15
|
+
activeChapter: m,
|
|
16
|
+
chapters: s,
|
|
17
|
+
className: "hidden w-3/10 @md:block @xl:w-[calc(50%-380px)]",
|
|
18
|
+
icon: u,
|
|
19
|
+
onClick: d,
|
|
20
|
+
theme: f
|
|
21
|
+
}), /* @__PURE__ */ a("div", {
|
|
22
|
+
className: e("relative isolate w-full flex-1 @md:max-w-7/10 @xl:max-w-[calc(50%+380px)]", "@md:ps-20 @lg:ps-40 @xl:ps-120"),
|
|
23
|
+
children: s.map((e, r) => /* @__PURE__ */ o(t, {
|
|
24
|
+
index: r,
|
|
25
|
+
setActiveChapter: h,
|
|
26
|
+
children: [/* @__PURE__ */ a(n, {
|
|
27
|
+
hasNext: r < s.length - 1,
|
|
28
|
+
hLevel: l,
|
|
29
|
+
index: r,
|
|
30
|
+
isActive: r === m,
|
|
31
|
+
onClick: () => d?.(e),
|
|
32
|
+
theme: f,
|
|
33
|
+
children: e.title
|
|
34
|
+
}), e.content]
|
|
35
|
+
}, e.title))
|
|
36
|
+
})]
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { s as Chapters };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=Chapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Chapters.js","names":[],"sources":["../../../lib/ui/Chapters/Chapters.tsx"],"sourcesContent":["'use client';\nimport clsx from 'clsx';\nimport {\n useState,\n type ComponentPropsWithoutRef,\n type FunctionComponent,\n type ReactNode,\n} from 'react';\n\nimport type { IconicNames } from '@clubmed/trident-icons';\nimport type { Theme } from '../types/Theme';\n\nimport { Chapter } from './Chapter';\nimport { ChapterTitle } from './ChapterTitle';\nimport { ChaptersSummary } from './ChaptersSummary';\n\nexport interface ChapterItem {\n content: ReactNode;\n title: string;\n}\n\nexport interface ChaptersProps\n extends Omit<ComponentPropsWithoutRef<'section'>, 'onClick' | 'children'> {\n chapters: ChapterItem[];\n hLevel?: 2 | 3 | 4;\n icon?: IconicNames;\n onClick?: (chapter: ChapterItem) => void;\n theme?: Theme;\n}\n\nexport const Chapters: FunctionComponent<ChaptersProps> = ({\n chapters,\n className,\n hLevel = 2,\n icon,\n onClick,\n theme = 'coreRange',\n ...attrs\n}) => {\n const [activeChapter, setActiveChapter] = useState(0);\n\n return (\n <section {...attrs} className={clsx(className, 'flex @container/chapters')}>\n <ChaptersSummary\n activeChapter={activeChapter}\n chapters={chapters}\n className=\"hidden w-3/10 @md:block @xl:w-[calc(50%-380px)]\"\n icon={icon}\n onClick={onClick}\n theme={theme}\n />\n\n <div\n className={clsx(\n 'relative isolate w-full flex-1 @md:max-w-7/10 @xl:max-w-[calc(50%+380px)]',\n '@md:ps-20 @lg:ps-40 @xl:ps-120',\n )}\n >\n {chapters.map((chapter, index) => (\n <Chapter index={index} key={chapter.title} setActiveChapter={setActiveChapter}>\n <ChapterTitle\n hasNext={index < chapters.length - 1}\n hLevel={hLevel}\n index={index}\n isActive={index === activeChapter}\n onClick={() => onClick?.(chapter)}\n theme={theme}\n >\n {chapter.title}\n </ChapterTitle>\n {chapter.content}\n </Chapter>\n ))}\n </div>\n </section>\n );\n};\n"],"mappings":";;;;;;;;AA8BA,IAAa,KAA8C,EACzD,aACA,cACA,YAAS,GACT,SACA,YACA,WAAQ,aACR,GAAG,QACC;CACJ,IAAM,CAAC,GAAe,KAAoB,EAAS,EAAE;AAErD,QACE,kBAAC,WAAD;EAAS,GAAI;EAAO,WAAW,EAAK,GAAW,2BAA2B;YAA1E,CACE,kBAAC,GAAD;GACiB;GACL;GACV,WAAU;GACJ;GACG;GACF;GACP,CAAA,EAEF,kBAAC,OAAD;GACE,WAAW,EACT,6EACA,iCACD;aAEA,EAAS,KAAK,GAAS,MACtB,kBAAC,GAAD;IAAgB;IAA6C;cAA7D,CACE,kBAAC,GAAD;KACE,SAAS,IAAQ,EAAS,SAAS;KAC3B;KACD;KACP,UAAU,MAAU;KACpB,eAAe,IAAU,EAAQ;KAC1B;eAEN,EAAQ;KACI,CAAA,EACd,EAAQ,QAAA;MAXiB,EAAQ,MAY1B,CAAA;GAER,CAAA,CAAA"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//#region lib/ui/Chapters/Chapters.themes.ts
|
|
2
|
+
var e = {
|
|
3
|
+
BLACK: {
|
|
4
|
+
thSummary: "bg-black text-white",
|
|
5
|
+
thSummaryIcon: "text-white max-w-140",
|
|
6
|
+
thSummaryIconName: "Trident",
|
|
7
|
+
thSummaryIconWidth: "100%",
|
|
8
|
+
thTitle: "bg-black text-white",
|
|
9
|
+
thTitleUnActive: "max-md:text-white/50"
|
|
10
|
+
},
|
|
11
|
+
CORE_RANGE: {
|
|
12
|
+
thSummary: "bg-lightSand text-black",
|
|
13
|
+
thSummaryIcon: "text-sand max-w-140",
|
|
14
|
+
thSummaryIconName: "Trident",
|
|
15
|
+
thSummaryIconWidth: "100%",
|
|
16
|
+
thTitle: "bg-lightSand text-black",
|
|
17
|
+
thTitleUnActive: "max-md:text-black/50"
|
|
18
|
+
},
|
|
19
|
+
EXCLUSIVE_COLLECTION: {
|
|
20
|
+
thSummary: "bg-ultramarine text-white",
|
|
21
|
+
thSummaryIcon: "text-white max-w-220",
|
|
22
|
+
thSummaryIconName: "ExclusiveCollection",
|
|
23
|
+
thSummaryIconWidth: "100%",
|
|
24
|
+
thTitle: "bg-ultramarine text-white md:text-black",
|
|
25
|
+
thTitleUnActive: "max-md:text-white/50"
|
|
26
|
+
},
|
|
27
|
+
HAPPY_TO_CARE: {
|
|
28
|
+
thSummary: "bg-verdigris text-black",
|
|
29
|
+
thSummaryIcon: "text-black max-w-220",
|
|
30
|
+
thSummaryIconName: "HappyToCare",
|
|
31
|
+
thSummaryIconWidth: "100%",
|
|
32
|
+
thTitle: "bg-verdigris text-black",
|
|
33
|
+
thTitleUnActive: "max-md:text-black/50"
|
|
34
|
+
},
|
|
35
|
+
SIENNA: {
|
|
36
|
+
thSummary: "bg-sienna text-white",
|
|
37
|
+
thSummaryIcon: "text-white max-w-140",
|
|
38
|
+
thSummaryIconName: "Trident",
|
|
39
|
+
thSummaryIconWidth: "100%",
|
|
40
|
+
thTitle: "bg-sienna text-white md:text-black",
|
|
41
|
+
thTitleUnActive: "max-md:text-white/50"
|
|
42
|
+
},
|
|
43
|
+
WHITE: {
|
|
44
|
+
thSummary: "bg-white text-black",
|
|
45
|
+
thSummaryIcon: "text-sand max-w-140",
|
|
46
|
+
thSummaryIconName: "Trident",
|
|
47
|
+
thSummaryIconWidth: "100%",
|
|
48
|
+
thTitle: "bg-white text-black",
|
|
49
|
+
thTitleUnActive: "max-md:text-black/50"
|
|
50
|
+
}
|
|
51
|
+
}, t = (t) => {
|
|
52
|
+
switch (t) {
|
|
53
|
+
case "black": return e.BLACK;
|
|
54
|
+
case "dark":
|
|
55
|
+
case "exclusiveCollection": return e.EXCLUSIVE_COLLECTION;
|
|
56
|
+
case "happyToCare": return e.HAPPY_TO_CARE;
|
|
57
|
+
case "sienna": return e.SIENNA;
|
|
58
|
+
case "white": return e.WHITE;
|
|
59
|
+
default: return e.CORE_RANGE;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
//#endregion
|
|
63
|
+
export { t as getTheme };
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=Chapters.themes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Chapters.themes.js","names":[],"sources":["../../../lib/ui/Chapters/Chapters.themes.ts"],"sourcesContent":["import type { Theme } from '../types/Theme';\n\nconst THEMES = {\n BLACK: {\n thSummary: 'bg-black text-white',\n thSummaryIcon: 'text-white max-w-140',\n thSummaryIconName: 'Trident',\n thSummaryIconWidth: '100%',\n thTitle: 'bg-black text-white',\n thTitleUnActive: 'max-md:text-white/50',\n },\n CORE_RANGE: {\n thSummary: 'bg-lightSand text-black',\n thSummaryIcon: 'text-sand max-w-140',\n thSummaryIconName: 'Trident',\n thSummaryIconWidth: '100%',\n thTitle: 'bg-lightSand text-black',\n thTitleUnActive: 'max-md:text-black/50',\n },\n EXCLUSIVE_COLLECTION: {\n thSummary: 'bg-ultramarine text-white',\n thSummaryIcon: 'text-white max-w-220',\n thSummaryIconName: 'ExclusiveCollection',\n thSummaryIconWidth: '100%',\n thTitle: 'bg-ultramarine text-white md:text-black',\n thTitleUnActive: 'max-md:text-white/50',\n },\n HAPPY_TO_CARE: {\n thSummary: 'bg-verdigris text-black',\n thSummaryIcon: 'text-black max-w-220',\n thSummaryIconName: 'HappyToCare',\n thSummaryIconWidth: '100%',\n thTitle: 'bg-verdigris text-black',\n thTitleUnActive: 'max-md:text-black/50',\n },\n SIENNA: {\n thSummary: 'bg-sienna text-white',\n thSummaryIcon: 'text-white max-w-140',\n thSummaryIconName: 'Trident',\n thSummaryIconWidth: '100%',\n thTitle: 'bg-sienna text-white md:text-black',\n thTitleUnActive: 'max-md:text-white/50',\n },\n WHITE: {\n thSummary: 'bg-white text-black',\n thSummaryIcon: 'text-sand max-w-140',\n thSummaryIconName: 'Trident',\n thSummaryIconWidth: '100%',\n thTitle: 'bg-white text-black',\n thTitleUnActive: 'max-md:text-black/50',\n },\n};\n\nexport const getTheme = (theme: Theme) => {\n switch (theme) {\n case 'black':\n return THEMES.BLACK;\n case 'dark':\n case 'exclusiveCollection':\n return THEMES.EXCLUSIVE_COLLECTION;\n case 'happyToCare':\n return THEMES.HAPPY_TO_CARE;\n case 'sienna':\n return THEMES.SIENNA;\n case 'white':\n return THEMES.WHITE;\n case 'light':\n case 'coreRange':\n default:\n return THEMES.CORE_RANGE;\n }\n};\n"],"mappings":";AAEA,IAAM,IAAS;CACb,OAAO;EACL,WAAW;EACX,eAAe;EACf,mBAAmB;EACnB,oBAAoB;EACpB,SAAS;EACT,iBAAiB;EAClB;CACD,YAAY;EACV,WAAW;EACX,eAAe;EACf,mBAAmB;EACnB,oBAAoB;EACpB,SAAS;EACT,iBAAiB;EAClB;CACD,sBAAsB;EACpB,WAAW;EACX,eAAe;EACf,mBAAmB;EACnB,oBAAoB;EACpB,SAAS;EACT,iBAAiB;EAClB;CACD,eAAe;EACb,WAAW;EACX,eAAe;EACf,mBAAmB;EACnB,oBAAoB;EACpB,SAAS;EACT,iBAAiB;EAClB;CACD,QAAQ;EACN,WAAW;EACX,eAAe;EACf,mBAAmB;EACnB,oBAAoB;EACpB,SAAS;EACT,iBAAiB;EAClB;CACD,OAAO;EACL,WAAW;EACX,eAAe;EACf,mBAAmB;EACnB,oBAAoB;EACpB,SAAS;EACT,iBAAiB;EAClB;CACF,EAEY,KAAY,MAAiB;AACxC,SAAQ,GAAR;EACE,KAAK,QACH,QAAO,EAAO;EAChB,KAAK;EACL,KAAK,sBACH,QAAO,EAAO;EAChB,KAAK,cACH,QAAO,EAAO;EAChB,KAAK,SACH,QAAO,EAAO;EAChB,KAAK,QACH,QAAO,EAAO;EAGhB,QACE,QAAO,EAAO"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { FunctionComponent, ReactNode } from 'react';
|
|
2
|
+
import { IconicNames } from '@clubmed/trident-icons';
|
|
3
|
+
import { Theme } from '../types/Theme';
|
|
4
|
+
interface ChapterSummaryItem {
|
|
5
|
+
content: ReactNode;
|
|
6
|
+
title: string;
|
|
7
|
+
}
|
|
8
|
+
interface Props {
|
|
9
|
+
activeChapter: number;
|
|
10
|
+
chapters: ChapterSummaryItem[];
|
|
11
|
+
className?: string;
|
|
12
|
+
icon?: IconicNames;
|
|
13
|
+
onClick?: (chapter: ChapterSummaryItem) => void;
|
|
14
|
+
theme?: Theme;
|
|
15
|
+
}
|
|
16
|
+
export declare const ChaptersSummary: FunctionComponent<Props>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as e } from "../../chunks/clsx.js";
|
|
3
|
+
import { getTheme as t } from "./Chapters.themes.js";
|
|
4
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
5
|
+
import { Icon as i } from "@clubmed/trident-icons";
|
|
6
|
+
//#region lib/ui/Chapters/ChaptersSummary.tsx
|
|
7
|
+
var a = { HappyToCareFRCA: "translate-y-[28px]" }, o = ({ activeChapter: o, chapters: s, className: c, icon: l, onClick: u, theme: d = "coreRange" }) => {
|
|
8
|
+
let { thSummary: f, thSummaryIcon: p, thSummaryIconName: m, thSummaryIconWidth: h } = t(d), g = l ?? m, _ = a[g];
|
|
9
|
+
return /* @__PURE__ */ n("div", {
|
|
10
|
+
className: e("rounded-e-16", f, c),
|
|
11
|
+
children: /* @__PURE__ */ r("nav", {
|
|
12
|
+
className: "sticky top-0 ms-auto flex w-full max-w-380 flex-col gap-y-20 p-40",
|
|
13
|
+
children: [s.map((t, r) => /* @__PURE__ */ n("a", {
|
|
14
|
+
className: e("text-h5 block font-serif", { "opacity-50": r !== o }),
|
|
15
|
+
href: `#chapter${r}`,
|
|
16
|
+
onClick: () => u?.(t),
|
|
17
|
+
children: t.title
|
|
18
|
+
}, t.title)), /* @__PURE__ */ n(i, {
|
|
19
|
+
className: e("mt-90 self-center", p, _),
|
|
20
|
+
name: g,
|
|
21
|
+
width: h
|
|
22
|
+
})]
|
|
23
|
+
})
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { o as ChaptersSummary };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=ChaptersSummary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChaptersSummary.js","names":[],"sources":["../../../lib/ui/Chapters/ChaptersSummary.tsx"],"sourcesContent":["'use client';\nimport clsx from 'clsx';\nimport type { FunctionComponent, ReactNode } from 'react';\n\nimport { Icon, type IconicNames } from '@clubmed/trident-icons';\nimport type { Theme } from '../types/Theme';\n\nimport { getTheme } from './Chapters.themes';\n\nconst ICON_VERTICAL_OFFSET_CLASS: Partial<Record<IconicNames, string>> = {\n // FR-CA asset has an intrinsic Y offset; compensate to match EN-CA visual alignment.\n HappyToCareFRCA: 'translate-y-[28px]',\n};\n\ninterface ChapterSummaryItem {\n content: ReactNode;\n title: string;\n}\n\ninterface Props {\n activeChapter: number;\n chapters: ChapterSummaryItem[];\n className?: string;\n icon?: IconicNames;\n onClick?: (chapter: ChapterSummaryItem) => void;\n theme?: Theme;\n}\n\nexport const ChaptersSummary: FunctionComponent<Props> = ({\n activeChapter,\n chapters,\n className,\n icon,\n onClick,\n theme = 'coreRange',\n}) => {\n const { thSummary, thSummaryIcon, thSummaryIconName, thSummaryIconWidth } = getTheme(theme);\n const summaryIconName = (icon ?? thSummaryIconName) as IconicNames;\n const iconVerticalOffsetClass = ICON_VERTICAL_OFFSET_CLASS[summaryIconName];\n\n return (\n <div className={clsx('rounded-e-16', thSummary, className)}>\n <nav className=\"sticky top-0 ms-auto flex w-full max-w-380 flex-col gap-y-20 p-40\">\n {chapters.map((chapter, index) => (\n <a\n className={clsx('text-h5 block font-serif', {\n 'opacity-50': index !== activeChapter,\n })}\n href={`#chapter${index}`}\n key={chapter.title}\n onClick={() => onClick?.(chapter)}\n >\n {chapter.title}\n </a>\n ))}\n <Icon\n className={clsx('mt-90 self-center', thSummaryIcon, iconVerticalOffsetClass)}\n name={summaryIconName}\n width={thSummaryIconWidth}\n />\n </nav>\n </div>\n );\n};\n"],"mappings":";;;;;;AASA,IAAM,IAAmE,EAEvE,iBAAiB,sBAClB,EAgBY,KAA6C,EACxD,kBACA,aACA,cACA,SACA,YACA,WAAQ,kBACJ;CACJ,IAAM,EAAE,cAAW,kBAAe,sBAAmB,0BAAuB,EAAS,EAAM,EACrF,IAAmB,KAAQ,GAC3B,IAA0B,EAA2B;AAE3D,QACE,kBAAC,OAAD;EAAK,WAAW,EAAK,gBAAgB,GAAW,EAAU;YACxD,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAS,KAAK,GAAS,MACtB,kBAAC,KAAD;IACE,WAAW,EAAK,4BAA4B,EAC1C,cAAc,MAAU,GACzB,CAAC;IACF,MAAM,WAAW;IAEjB,eAAe,IAAU,EAAQ;cAEhC,EAAQ;IACP,EAJG,EAAQ,MAIX,CACJ,EACF,kBAAC,GAAD;IACE,WAAW,EAAK,qBAAqB,GAAe,EAAwB;IAC5E,MAAM;IACN,OAAO;IACP,CAAA,CAAA;;EAEA,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, FunctionComponent } from 'react';
|
|
2
|
+
import { ImageProps } from '../Image';
|
|
3
|
+
export interface PromisesItem {
|
|
4
|
+
href: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
image: ImageProps;
|
|
7
|
+
title: string;
|
|
8
|
+
}
|
|
9
|
+
export interface PromisesLabels {
|
|
10
|
+
anchor: {
|
|
11
|
+
continue: string;
|
|
12
|
+
};
|
|
13
|
+
layer: {
|
|
14
|
+
close: string;
|
|
15
|
+
open: string;
|
|
16
|
+
};
|
|
17
|
+
scroller: {
|
|
18
|
+
previous: string;
|
|
19
|
+
next: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface PromisesProps extends ComponentPropsWithoutRef<'div'> {
|
|
23
|
+
items: PromisesItem[];
|
|
24
|
+
labels: PromisesLabels;
|
|
25
|
+
}
|
|
26
|
+
export declare const Promises: FunctionComponent<PromisesProps>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as e } from "../../chunks/clsx.js";
|
|
3
|
+
import { PromisesMedia as t } from "./PromisesMedia.js";
|
|
4
|
+
import { PromisesMenu as n } from "./PromisesMenu.js";
|
|
5
|
+
import { useCallback as r, useEffect as i, useState as a } from "react";
|
|
6
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
7
|
+
//#region lib/ui/Promises/Promises.tsx
|
|
8
|
+
var c = 1e4, l = ({ className: l, items: u, labels: d, ...f }) => {
|
|
9
|
+
let [p, m] = a(0), [h, g] = a(0), _ = r(() => {
|
|
10
|
+
m((e) => (e - 1 + u.length) % u.length);
|
|
11
|
+
}, [u.length]), v = r(() => {
|
|
12
|
+
m((e) => (e + 1) % u.length);
|
|
13
|
+
}, [u.length]), y = r((e) => {
|
|
14
|
+
m(e), g((e) => e + 1);
|
|
15
|
+
}, []);
|
|
16
|
+
return i(() => {
|
|
17
|
+
let e = setInterval(() => {
|
|
18
|
+
v();
|
|
19
|
+
}, c);
|
|
20
|
+
return () => clearInterval(e);
|
|
21
|
+
}, [v, h]), /* @__PURE__ */ s("div", {
|
|
22
|
+
...f,
|
|
23
|
+
className: e("relative isolate flex gap-x-20 @container/promises", l),
|
|
24
|
+
children: [/* @__PURE__ */ o(t, {
|
|
25
|
+
activeIndex: p,
|
|
26
|
+
items: u,
|
|
27
|
+
labels: d,
|
|
28
|
+
onClickMenu: (e) => m(e),
|
|
29
|
+
onNext: v,
|
|
30
|
+
onPrevious: _
|
|
31
|
+
}), /* @__PURE__ */ o(n, {
|
|
32
|
+
activeIndex: p,
|
|
33
|
+
items: u,
|
|
34
|
+
labels: d,
|
|
35
|
+
onClickMenu: (e) => y(e)
|
|
36
|
+
})]
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { l as Promises };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=Promises.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Promises.js","names":[],"sources":["../../../lib/ui/Promises/Promises.tsx"],"sourcesContent":["'use client';\nimport clsx from 'clsx';\nimport type { ComponentPropsWithoutRef, FunctionComponent } from 'react';\nimport { useCallback, useEffect, useState } from 'react';\n\nimport type { ImageProps } from '../Image';\n\nimport { PromisesMedia } from './PromisesMedia';\nimport { PromisesMenu } from './PromisesMenu';\n\nconst INTERVAL_IN_MS = 10000;\n\nexport interface PromisesItem {\n href: string;\n id?: string;\n image: ImageProps;\n title: string;\n}\n\nexport interface PromisesLabels {\n anchor: { continue: string };\n layer: { close: string; open: string };\n scroller: { previous: string; next: string };\n}\n\nexport interface PromisesProps extends ComponentPropsWithoutRef<'div'> {\n items: PromisesItem[];\n labels: PromisesLabels;\n}\n\nexport const Promises: FunctionComponent<PromisesProps> = ({\n className,\n items,\n labels,\n ...attrs\n}) => {\n const [activeIndex, setActiveIndex] = useState(0);\n const [intervalKey, setIntervalKey] = useState(0);\n\n const previousActiveIndex = useCallback(() => {\n setActiveIndex((state) => (state - 1 + items.length) % items.length);\n }, [items.length]);\n\n const nextActiveIndex = useCallback(() => {\n setActiveIndex((state) => (state + 1) % items.length);\n }, [items.length]);\n\n const goToIndex = useCallback((index: number) => {\n setActiveIndex(index);\n setIntervalKey((k) => k + 1);\n }, []);\n\n useEffect(() => {\n const interval = setInterval(() => {\n nextActiveIndex();\n }, INTERVAL_IN_MS);\n\n return () => clearInterval(interval);\n }, [nextActiveIndex, intervalKey]);\n\n return (\n <div\n {...attrs}\n className={clsx('relative isolate flex gap-x-20 @container/promises', className)}\n >\n <PromisesMedia\n activeIndex={activeIndex}\n items={items}\n labels={labels}\n onClickMenu={(i) => setActiveIndex(i)}\n onNext={nextActiveIndex}\n onPrevious={previousActiveIndex}\n />\n <PromisesMenu\n activeIndex={activeIndex}\n items={items}\n labels={labels}\n onClickMenu={(i) => goToIndex(i)}\n />\n </div>\n );\n};\n"],"mappings":";;;;;;;AAUA,IAAM,IAAiB,KAoBV,KAA8C,EACzD,cACA,UACA,WACA,GAAG,QACC;CACJ,IAAM,CAAC,GAAa,KAAkB,EAAS,EAAE,EAC3C,CAAC,GAAa,KAAkB,EAAS,EAAE,EAE3C,IAAsB,QAAkB;AAC5C,KAAgB,OAAW,IAAQ,IAAI,EAAM,UAAU,EAAM,OAAO;IACnE,CAAC,EAAM,OAAO,CAAC,EAEZ,IAAkB,QAAkB;AACxC,KAAgB,OAAW,IAAQ,KAAK,EAAM,OAAO;IACpD,CAAC,EAAM,OAAO,CAAC,EAEZ,IAAY,GAAa,MAAkB;AAE/C,EADA,EAAe,EAAM,EACrB,GAAgB,MAAM,IAAI,EAAE;IAC3B,EAAE,CAAC;AAUN,QARA,QAAgB;EACd,IAAM,IAAW,kBAAkB;AACjC,MAAiB;KAChB,EAAe;AAElB,eAAa,cAAc,EAAS;IACnC,CAAC,GAAiB,EAAY,CAAC,EAGhC,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,EAAK,sDAAsD,EAAU;YAFlF,CAIE,kBAAC,GAAD;GACe;GACN;GACC;GACR,cAAc,MAAM,EAAe,EAAE;GACrC,QAAQ;GACR,YAAY;GACZ,CAAA,EACF,kBAAC,GAAD;GACe;GACN;GACC;GACR,cAAc,MAAM,EAAU,EAAA;GAC9B,CAAA,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, FunctionComponent } from 'react';
|
|
2
|
+
import { PromisesItem, PromisesLabels } from './Promises';
|
|
3
|
+
interface Props extends ComponentPropsWithoutRef<'div'> {
|
|
4
|
+
activeIndex: number;
|
|
5
|
+
items: PromisesItem[];
|
|
6
|
+
labels: PromisesLabels;
|
|
7
|
+
onClickMenu: (index: number) => void;
|
|
8
|
+
onNext: () => void;
|
|
9
|
+
onPrevious: () => void;
|
|
10
|
+
}
|
|
11
|
+
export declare const PromisesMedia: FunctionComponent<Props>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as e } from "../../chunks/clsx.js";
|
|
3
|
+
import { Arrows as t } from "../arrows/Arrows.js";
|
|
4
|
+
import { Image as n } from "../Image.js";
|
|
5
|
+
import { jsx as r, jsxs as i } from "react/jsx-runtime";
|
|
6
|
+
//#region lib/ui/Promises/PromisesMedia.tsx
|
|
7
|
+
var a = ({ activeIndex: a, items: o, labels: s, onClickMenu: c, onNext: l, onPrevious: u, ...d }) => /* @__PURE__ */ i("div", {
|
|
8
|
+
...d,
|
|
9
|
+
className: "rounded-16 relative isolate w-full shrink-0 overflow-hidden @3xl/promises:max-w-380",
|
|
10
|
+
children: [
|
|
11
|
+
/* @__PURE__ */ r("div", {
|
|
12
|
+
className: "relative isolate grid",
|
|
13
|
+
children: o.map(({ id: t, image: i, title: o }, s) => {
|
|
14
|
+
let c = s === a;
|
|
15
|
+
return /* @__PURE__ */ r("article", {
|
|
16
|
+
"aria-hidden": !c,
|
|
17
|
+
className: e("aspect-vertical-video rounded-16 relative isolate col-start-1 row-start-1 w-full origin-top overflow-hidden opacity-0 transition-opacity duration-500", { "opacity-100": c }),
|
|
18
|
+
inert: !c,
|
|
19
|
+
children: /* @__PURE__ */ r(n, {
|
|
20
|
+
...i,
|
|
21
|
+
className: "size-full object-cover",
|
|
22
|
+
lazyLoad: !0,
|
|
23
|
+
sizes: "(min-width: 768px) 380px, 100vw"
|
|
24
|
+
})
|
|
25
|
+
}, t ?? `${o}-${s}`);
|
|
26
|
+
})
|
|
27
|
+
}),
|
|
28
|
+
/* @__PURE__ */ r(t, {
|
|
29
|
+
iconType: "ArrowDefault",
|
|
30
|
+
isDisabledHidden: !0,
|
|
31
|
+
isNextDisabled: a === o.length - 1,
|
|
32
|
+
isPrevDisabled: a === 0,
|
|
33
|
+
labels: {
|
|
34
|
+
next: s.scroller.next,
|
|
35
|
+
previous: s.scroller.previous
|
|
36
|
+
},
|
|
37
|
+
size: "small",
|
|
38
|
+
className: "absolute inset-0 -mx-12 !w-[calc(100%_+_24px)] @3xl/promises:hidden",
|
|
39
|
+
onNext: l,
|
|
40
|
+
onPrev: u
|
|
41
|
+
}),
|
|
42
|
+
/* @__PURE__ */ r("ul", {
|
|
43
|
+
className: "absolute inset-x-0 top-0 flex list-none gap-2 p-20",
|
|
44
|
+
children: o.map(({ id: t, title: n }, i) => /* @__PURE__ */ r("li", {
|
|
45
|
+
className: "w-full flex items-start",
|
|
46
|
+
children: /* @__PURE__ */ r("button", {
|
|
47
|
+
"aria-current": i === a,
|
|
48
|
+
"aria-label": n,
|
|
49
|
+
className: e("rounded-pill h-4 w-full overflow-hidden", {
|
|
50
|
+
"bg-white": i < a,
|
|
51
|
+
"bg-white/40": i >= a
|
|
52
|
+
}),
|
|
53
|
+
onClick: () => c(i),
|
|
54
|
+
type: "button",
|
|
55
|
+
children: i === a && /* @__PURE__ */ r("span", { className: "animate-filling block h-full w-full origin-left bg-white rtl:origin-right" })
|
|
56
|
+
})
|
|
57
|
+
}, t ?? i))
|
|
58
|
+
})
|
|
59
|
+
]
|
|
60
|
+
});
|
|
61
|
+
//#endregion
|
|
62
|
+
export { a as PromisesMedia };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=PromisesMedia.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromisesMedia.js","names":[],"sources":["../../../lib/ui/Promises/PromisesMedia.tsx"],"sourcesContent":["'use client';\nimport clsx from 'clsx';\nimport type { ComponentPropsWithoutRef, FunctionComponent } from 'react';\n\nimport { Image } from '../Image';\nimport { Arrows } from '../arrows/Arrows';\nimport type { PromisesItem, PromisesLabels } from './Promises';\n\ninterface Props extends ComponentPropsWithoutRef<'div'> {\n activeIndex: number;\n items: PromisesItem[];\n labels: PromisesLabels;\n onClickMenu: (index: number) => void;\n onNext: () => void;\n onPrevious: () => void;\n}\n\nexport const PromisesMedia: FunctionComponent<Props> = ({\n activeIndex,\n items,\n labels,\n onClickMenu,\n onNext,\n onPrevious,\n ...attrs\n}) => {\n return (\n <div\n {...attrs}\n className=\"rounded-16 relative isolate w-full shrink-0 overflow-hidden @3xl/promises:max-w-380\"\n >\n <div className=\"relative isolate grid\">\n {items.map(({ id, image, title }, index) => {\n const isActive = index === activeIndex;\n\n return (\n <article\n aria-hidden={!isActive}\n key={id ?? `${title}-${index}`}\n className={clsx(\n 'aspect-vertical-video rounded-16 relative isolate col-start-1 row-start-1 w-full origin-top overflow-hidden opacity-0 transition-opacity duration-500',\n { 'opacity-100': isActive },\n )}\n inert={!isActive}\n >\n <Image\n {...image}\n className=\"size-full object-cover\"\n lazyLoad\n sizes=\"(min-width: 768px) 380px, 100vw\"\n />\n </article>\n );\n })}\n </div>\n\n <Arrows\n iconType=\"ArrowDefault\"\n isDisabledHidden={true}\n isNextDisabled={activeIndex === items.length - 1}\n isPrevDisabled={activeIndex === 0}\n labels={{\n next: labels.scroller.next,\n previous: labels.scroller.previous,\n }}\n size=\"small\"\n className=\"absolute inset-0 -mx-12 !w-[calc(100%_+_24px)] @3xl/promises:hidden\"\n onNext={onNext}\n onPrev={onPrevious}\n />\n\n <ul className=\"absolute inset-x-0 top-0 flex list-none gap-2 p-20\">\n {items.map(({ id, title }, index) => (\n <li key={id ?? index} className=\"w-full flex items-start\">\n <button\n aria-current={index === activeIndex}\n aria-label={title}\n className={clsx('rounded-pill h-4 w-full overflow-hidden', {\n 'bg-white': index < activeIndex,\n 'bg-white/40': index >= activeIndex,\n })}\n onClick={() => onClickMenu(index)}\n type=\"button\"\n >\n {index === activeIndex && (\n <span className=\"animate-filling block h-full w-full origin-left bg-white rtl:origin-right\" />\n )}\n </button>\n </li>\n ))}\n </ul>\n </div>\n );\n};\n"],"mappings":";;;;;;AAiBA,IAAa,KAA2C,EACtD,gBACA,UACA,WACA,gBACA,WACA,eACA,GAAG,QAGD,kBAAC,OAAD;CACE,GAAI;CACJ,WAAU;WAFZ;EAIE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,EAAE,OAAI,UAAO,YAAS,MAAU;IAC1C,IAAM,IAAW,MAAU;AAE3B,WACE,kBAAC,WAAD;KACE,eAAa,CAAC;KAEd,WAAW,EACT,yJACA,EAAE,eAAe,GAAU,CAC5B;KACD,OAAO,CAAC;eAER,kBAAC,GAAD;MACE,GAAI;MACJ,WAAU;MACV,UAAA;MACA,OAAM;MACN,CAAA;KACM,EAbH,KAAM,GAAG,EAAM,GAAG,IAaf;;GAGV,CAAA;EAEN,kBAAC,GAAD;GACE,UAAS;GACT,kBAAkB;GAClB,gBAAgB,MAAgB,EAAM,SAAS;GAC/C,gBAAgB,MAAgB;GAChC,QAAQ;IACN,MAAM,EAAO,SAAS;IACtB,UAAU,EAAO,SAAS;IAC3B;GACD,MAAK;GACL,WAAU;GACF;GACR,QAAQ;GACR,CAAA;EAEF,kBAAC,MAAD;GAAI,WAAU;aACX,EAAM,KAAK,EAAE,OAAI,YAAS,MACzB,kBAAC,MAAD;IAAsB,WAAU;cAC9B,kBAAC,UAAD;KACE,gBAAc,MAAU;KACxB,cAAY;KACZ,WAAW,EAAK,2CAA2C;MACzD,YAAY,IAAQ;MACpB,eAAe,KAAS;MACzB,CAAC;KACF,eAAe,EAAY,EAAM;KACjC,MAAK;eAEJ,MAAU,KACT,kBAAC,QAAD,EAAM,WAAU,6EAA8E,CAAA;KAEzF,CAAA;IACN,EAfI,KAAM,EAeV,CAAA;GAEJ,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FunctionComponent } from 'react';
|
|
2
|
+
import { PromisesItem, PromisesLabels } from './Promises';
|
|
3
|
+
interface Props {
|
|
4
|
+
activeIndex: number;
|
|
5
|
+
className?: string;
|
|
6
|
+
items: PromisesItem[];
|
|
7
|
+
labels: PromisesLabels;
|
|
8
|
+
onClickMenu: (index: number) => void;
|
|
9
|
+
}
|
|
10
|
+
export declare const PromisesMenu: FunctionComponent<Props>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as e } from "../../chunks/clsx.js";
|
|
3
|
+
import { Button as t } from "../buttons/Button.js";
|
|
4
|
+
import { n } from "../../chunks/Carousel.context.js";
|
|
5
|
+
import { Carousel as r } from "../carousel/Carousel.js";
|
|
6
|
+
import { CarouselBody as i } from "../carousel/CarouselBody.js";
|
|
7
|
+
import { CarouselItem as a } from "../carousel/CarouselItem.js";
|
|
8
|
+
import { useEffect as o, useId as s, useLayoutEffect as c, useMemo as l, useRef as u } from "react";
|
|
9
|
+
import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
|
|
10
|
+
//#region lib/ui/Promises/PromisesMenu.tsx
|
|
11
|
+
var m = ({ anchorLabel: n, anchorName: r, isActive: i, labelNode: a }) => {
|
|
12
|
+
let o = u(null), s = u(null);
|
|
13
|
+
return c(() => {
|
|
14
|
+
if (!o.current || !s.current) return;
|
|
15
|
+
let e = new ResizeObserver(() => {
|
|
16
|
+
s.current && o.current && (s.current.style.height = `${o.current.offsetHeight}px`);
|
|
17
|
+
});
|
|
18
|
+
return e.observe(o.current), () => e.disconnect();
|
|
19
|
+
}, []), /* @__PURE__ */ f("li", {
|
|
20
|
+
className: e("relative isolate transition-[opacity,height,margin-inline-start] ms-0 duration-300 overflow-hidden rounded-32 bg-white p-20", { "@3xl/promises:ms-52": !i }),
|
|
21
|
+
children: /* @__PURE__ */ p("div", {
|
|
22
|
+
ref: s,
|
|
23
|
+
className: "flex justify-between items-start overflow-hidden",
|
|
24
|
+
style: { anchorName: r },
|
|
25
|
+
children: [/* @__PURE__ */ f("div", {
|
|
26
|
+
ref: o,
|
|
27
|
+
className: "pe-40",
|
|
28
|
+
children: a
|
|
29
|
+
}), i && /* @__PURE__ */ f(t, {
|
|
30
|
+
"aria-hidden": !0,
|
|
31
|
+
className: "opacity-0 pointer-events-none",
|
|
32
|
+
icon: "ArrowDefaultRight",
|
|
33
|
+
inert: !0,
|
|
34
|
+
tabIndex: -1,
|
|
35
|
+
variant: "pill",
|
|
36
|
+
children: n
|
|
37
|
+
})]
|
|
38
|
+
})
|
|
39
|
+
});
|
|
40
|
+
}, h = ({ activeIndex: e, onSelect: t }) => {
|
|
41
|
+
let { api: r, snapped: i } = n(), a = u(t);
|
|
42
|
+
a.current = t;
|
|
43
|
+
let s = i[0];
|
|
44
|
+
return o(() => {
|
|
45
|
+
s !== void 0 && a.current(s);
|
|
46
|
+
}, [s]), o(() => {
|
|
47
|
+
r?.scrollTo(e);
|
|
48
|
+
}, [r, e]), null;
|
|
49
|
+
}, g = ({ activeIndex: t, className: n, onSelect: o, sliderItems: s }) => {
|
|
50
|
+
let c = u(t), m = l(() => ({
|
|
51
|
+
active: s.length > 1,
|
|
52
|
+
align: "center",
|
|
53
|
+
startIndex: c.current
|
|
54
|
+
}), [s.length]);
|
|
55
|
+
return /* @__PURE__ */ f(d, { children: /* @__PURE__ */ p(r, {
|
|
56
|
+
className: e("relative isolate flex h-full items-center", n),
|
|
57
|
+
options: m,
|
|
58
|
+
children: [/* @__PURE__ */ f(h, {
|
|
59
|
+
activeIndex: t,
|
|
60
|
+
onSelect: o
|
|
61
|
+
}), /* @__PURE__ */ f(i, {
|
|
62
|
+
className: "w-full px-20",
|
|
63
|
+
scrollClassName: "gap-12 md:gap-40 auto-cols-full",
|
|
64
|
+
children: s.map((t, n) => /* @__PURE__ */ f(a, {
|
|
65
|
+
index: n,
|
|
66
|
+
children: /* @__PURE__ */ f("div", {
|
|
67
|
+
"aria-label": `${n + 1}/${s.length}`,
|
|
68
|
+
className: e("rounded-16 overflow-hidden bg-white"),
|
|
69
|
+
children: t
|
|
70
|
+
})
|
|
71
|
+
}, n))
|
|
72
|
+
})]
|
|
73
|
+
}) });
|
|
74
|
+
}, _ = ({ activeIndex: n, className: r, items: i, labels: a, onClickMenu: o }) => {
|
|
75
|
+
let c = s(), u = c.replace(/[^a-zA-Z0-9_-]/g, ""), { menuItems: h, sliderItems: _ } = l(() => {
|
|
76
|
+
let r = i.map(({ href: t, id: r, title: i }, a) => {
|
|
77
|
+
let s = a === n, l = r ?? `${c}_${a}`;
|
|
78
|
+
return {
|
|
79
|
+
anchorName: `--promises-${u}-${a}`,
|
|
80
|
+
href: t,
|
|
81
|
+
id: r,
|
|
82
|
+
isActive: s,
|
|
83
|
+
itemId: l,
|
|
84
|
+
labelNode: /* @__PURE__ */ f("button", {
|
|
85
|
+
id: l,
|
|
86
|
+
"aria-label": i,
|
|
87
|
+
className: e("text-start hover:underline text-h4 text-center font-serif @3xl/promises:text-h4 @5xl/promises:text-h2 @6xl/promises:text-h1 @3xl/promises:text-start"),
|
|
88
|
+
onClick: () => o(a),
|
|
89
|
+
type: "button",
|
|
90
|
+
children: i
|
|
91
|
+
}),
|
|
92
|
+
title: i
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
menuItems: r,
|
|
97
|
+
sliderItems: r.map(({ labelNode: e, href: n, itemId: r }) => /* @__PURE__ */ p("div", {
|
|
98
|
+
className: "rounded-32 p-16",
|
|
99
|
+
children: [e, /* @__PURE__ */ f(t, {
|
|
100
|
+
"aria-describedby": r,
|
|
101
|
+
"aria-label": a.anchor.continue,
|
|
102
|
+
href: n,
|
|
103
|
+
icon: "ArrowDefaultRight",
|
|
104
|
+
variant: "pill",
|
|
105
|
+
children: a.anchor.continue
|
|
106
|
+
})]
|
|
107
|
+
}))
|
|
108
|
+
};
|
|
109
|
+
}, [
|
|
110
|
+
n,
|
|
111
|
+
i,
|
|
112
|
+
a,
|
|
113
|
+
c,
|
|
114
|
+
o,
|
|
115
|
+
u
|
|
116
|
+
]), v = h[n];
|
|
117
|
+
return /* @__PURE__ */ p(d, { children: [
|
|
118
|
+
/* @__PURE__ */ f("ul", {
|
|
119
|
+
className: e("hidden @3xl/promises:block", "absolute bottom-0 inset-x-0 overflow-hidden @3xl/promises:-ms-52 text-black w-full", "@3xl/promises:pointer-events-auto @3xl/promises:static @3xl/promises:p-0 @3xl/promises:pt-40", r),
|
|
120
|
+
children: h.map(({ anchorName: e, id: t, isActive: n, labelNode: r, title: i }, o) => /* @__PURE__ */ f(m, {
|
|
121
|
+
anchorLabel: a.anchor.continue,
|
|
122
|
+
anchorName: e,
|
|
123
|
+
isActive: n,
|
|
124
|
+
labelNode: r
|
|
125
|
+
}, t ?? `${i}-${o}`))
|
|
126
|
+
}),
|
|
127
|
+
v && /* @__PURE__ */ f(t, {
|
|
128
|
+
"aria-describedby": v.itemId,
|
|
129
|
+
"aria-label": a.anchor.continue,
|
|
130
|
+
className: "hidden @3xl/promises:inline-flex transition-[top] duration-200 ease-out-quad absolute z-1",
|
|
131
|
+
href: v.href,
|
|
132
|
+
icon: "ArrowDefaultRight",
|
|
133
|
+
style: {
|
|
134
|
+
positionAnchor: v.anchorName,
|
|
135
|
+
top: "anchor(top)",
|
|
136
|
+
right: "anchor(right)"
|
|
137
|
+
},
|
|
138
|
+
variant: "pill",
|
|
139
|
+
children: a.anchor.continue
|
|
140
|
+
}),
|
|
141
|
+
/* @__PURE__ */ f("div", {
|
|
142
|
+
className: "@3xl/promises:hidden absolute inset-x-0 bottom-20",
|
|
143
|
+
children: /* @__PURE__ */ f(g, {
|
|
144
|
+
activeIndex: n,
|
|
145
|
+
onSelect: o,
|
|
146
|
+
sliderItems: _
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
] });
|
|
150
|
+
};
|
|
151
|
+
//#endregion
|
|
152
|
+
export { _ as PromisesMenu };
|
|
153
|
+
|
|
154
|
+
//# sourceMappingURL=PromisesMenu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PromisesMenu.js","names":[],"sources":["../../../lib/ui/Promises/PromisesMenu.tsx"],"sourcesContent":["'use client';\nimport clsx from 'clsx';\nimport type { FunctionComponent, ReactNode } from 'react';\nimport { useEffect, useId, useMemo, useRef, useLayoutEffect } from 'react';\nimport { useCarousel } from '../carousel/Carousel.context';\n\nimport { Carousel } from '../carousel/Carousel';\nimport { CarouselBody } from '../carousel/CarouselBody';\nimport { CarouselItem } from '../carousel/CarouselItem';\nimport { Button } from '../buttons/Button';\nimport type { PromisesItem, PromisesLabels } from './Promises';\n\ninterface MenuItemProps {\n anchorLabel: string;\n anchorName: string;\n isActive: boolean;\n labelNode: ReactNode;\n}\n\nconst PromisesMenuItem: FunctionComponent<MenuItemProps> = ({\n anchorLabel,\n anchorName,\n isActive,\n labelNode,\n}) => {\n const labelRef = useRef<HTMLDivElement>(null);\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!labelRef.current || !containerRef.current) return;\n const resizeObserver = new ResizeObserver(() => {\n if (containerRef.current && labelRef.current) {\n containerRef.current.style.height = `${labelRef.current.offsetHeight}px`;\n }\n });\n resizeObserver.observe(labelRef.current);\n return () => resizeObserver.disconnect();\n }, []);\n\n return (\n <li\n className={clsx(\n 'relative isolate transition-[opacity,height,margin-inline-start] ms-0 duration-300 overflow-hidden rounded-32 bg-white p-20',\n { '@3xl/promises:ms-52': !isActive },\n )}\n >\n <div\n ref={containerRef}\n className=\"flex justify-between items-start overflow-hidden\"\n style={{ anchorName } as unknown as React.CSSProperties}\n >\n <div ref={labelRef} className=\"pe-40\">\n {labelNode}\n </div>\n {isActive && (\n <Button\n aria-hidden\n className=\"opacity-0 pointer-events-none\"\n icon=\"ArrowDefaultRight\"\n inert\n tabIndex={-1}\n variant=\"pill\"\n >\n {anchorLabel}\n </Button>\n )}\n </div>\n </li>\n );\n};\n\ninterface Props {\n activeIndex: number;\n className?: string;\n items: PromisesItem[];\n labels: PromisesLabels;\n onClickMenu: (index: number) => void;\n}\n\ninterface PromisesItemSliderProps {\n activeIndex: number;\n className?: string;\n onSelect: (index: number) => void;\n sliderItems: ReactNode[];\n}\n\nconst CarouselSync: FunctionComponent<{\n activeIndex: number;\n onSelect: (index: number) => void;\n}> = ({ activeIndex, onSelect }) => {\n const { api, snapped } = useCarousel();\n const onSelectRef = useRef(onSelect);\n onSelectRef.current = onSelect;\n\n const snappedIndex = snapped[0];\n useEffect(() => {\n if (snappedIndex !== undefined) onSelectRef.current(snappedIndex);\n }, [snappedIndex]);\n\n useEffect(() => {\n api?.scrollTo(activeIndex);\n }, [api, activeIndex]);\n\n return null;\n};\n\nconst PromisesItemSlider: FunctionComponent<PromisesItemSliderProps> = ({\n activeIndex,\n className,\n onSelect,\n sliderItems,\n}) => {\n const initialIndex = useRef(activeIndex);\n const carouselOptions = useMemo(\n () => ({\n active: sliderItems.length > 1,\n align: 'center' as const,\n startIndex: initialIndex.current,\n }),\n [sliderItems.length],\n );\n\n return (\n <>\n <Carousel\n className={clsx('relative isolate flex h-full items-center', className)}\n options={carouselOptions}\n >\n <CarouselSync activeIndex={activeIndex} onSelect={onSelect} />\n <CarouselBody className=\"w-full px-20\" scrollClassName=\"gap-12 md:gap-40 auto-cols-full\">\n {sliderItems.map((item, i) => (\n <CarouselItem index={i} key={i}>\n <div\n aria-label={`${i + 1}/${sliderItems.length}`}\n className={clsx('rounded-16 overflow-hidden bg-white')}\n >\n {item}\n </div>\n </CarouselItem>\n ))}\n </CarouselBody>\n </Carousel>\n </>\n );\n};\n\nexport const PromisesMenu: FunctionComponent<Props> = ({\n activeIndex,\n className,\n items,\n labels,\n onClickMenu,\n}) => {\n const menuId = useId();\n const safeMenuId = menuId.replace(/[^a-zA-Z0-9_-]/g, '');\n\n const { menuItems, sliderItems } = useMemo(() => {\n const mItems = items.map(({ href, id, title }, index) => {\n const isActive = index === activeIndex;\n const itemId = id ?? `${menuId}_${index}`;\n const anchorName = `--promises-${safeMenuId}-${index}`;\n\n const labelNode = (\n <button\n id={itemId}\n aria-label={title}\n className={clsx(\n 'text-start hover:underline text-h4 text-center font-serif @3xl/promises:text-h4 @5xl/promises:text-h2 @6xl/promises:text-h1 @3xl/promises:text-start',\n )}\n onClick={() => onClickMenu(index)}\n type=\"button\"\n >\n {title}\n </button>\n );\n\n return { anchorName, href, id, isActive, itemId, labelNode, title };\n });\n\n const sItems = mItems.map(({ labelNode, href, itemId }) => (\n <div className=\"rounded-32 p-16\">\n {labelNode}\n <Button\n aria-describedby={itemId}\n aria-label={labels.anchor.continue}\n href={href}\n icon=\"ArrowDefaultRight\"\n variant=\"pill\"\n >\n {labels.anchor.continue}\n </Button>\n </div>\n ));\n\n return { menuItems: mItems, sliderItems: sItems };\n }, [activeIndex, items, labels, menuId, onClickMenu, safeMenuId]);\n\n const activeItem = menuItems[activeIndex];\n\n return (\n <>\n <ul\n className={clsx(\n 'hidden @3xl/promises:block',\n 'absolute bottom-0 inset-x-0 overflow-hidden @3xl/promises:-ms-52 text-black w-full',\n '@3xl/promises:pointer-events-auto @3xl/promises:static @3xl/promises:p-0 @3xl/promises:pt-40',\n className,\n )}\n >\n {menuItems.map(({ anchorName, id, isActive, labelNode, title }, index) => (\n <PromisesMenuItem\n anchorLabel={labels.anchor.continue}\n anchorName={anchorName}\n isActive={isActive}\n key={id ?? `${title}-${index}`}\n labelNode={labelNode}\n />\n ))}\n </ul>\n {activeItem && (\n <Button\n aria-describedby={activeItem.itemId}\n aria-label={labels.anchor.continue}\n className=\"hidden @3xl/promises:inline-flex transition-[top] duration-200 ease-out-quad absolute z-1\"\n href={activeItem.href}\n icon=\"ArrowDefaultRight\"\n style={\n {\n positionAnchor: activeItem.anchorName,\n top: 'anchor(top)',\n right: 'anchor(right)',\n } as React.CSSProperties\n }\n variant=\"pill\"\n >\n {labels.anchor.continue}\n </Button>\n )}\n <div className=\"@3xl/promises:hidden absolute inset-x-0 bottom-20\">\n <PromisesItemSlider\n activeIndex={activeIndex}\n onSelect={onClickMenu}\n sliderItems={sliderItems}\n />\n </div>\n </>\n );\n};\n"],"mappings":";;;;;;;;;;AAmBA,IAAM,KAAsD,EAC1D,gBACA,eACA,aACA,mBACI;CACJ,IAAM,IAAW,EAAuB,KAAK,EAEvC,IAAe,EAAuB,KAAK;AAajD,QAXA,QAAsB;AACpB,MAAI,CAAC,EAAS,WAAW,CAAC,EAAa,QAAS;EAChD,IAAM,IAAiB,IAAI,qBAAqB;AAC9C,GAAI,EAAa,WAAW,EAAS,YACnC,EAAa,QAAQ,MAAM,SAAS,GAAG,EAAS,QAAQ,aAAa;IAEvE;AAEF,SADA,EAAe,QAAQ,EAAS,QAAQ,QAC3B,EAAe,YAAY;IACvC,EAAE,CAAC,EAGJ,kBAAC,MAAD;EACE,WAAW,EACT,+HACA,EAAE,uBAAuB,CAAC,GAAU,CACrC;YAED,kBAAC,OAAD;GACE,KAAK;GACL,WAAU;GACV,OAAO,EAAE,eAAY;aAHvB,CAKE,kBAAC,OAAD;IAAK,KAAK;IAAU,WAAU;cAC3B;IACG,CAAA,EACL,KACC,kBAAC,GAAD;IACE,eAAA;IACA,WAAU;IACV,MAAK;IACL,OAAA;IACA,UAAU;IACV,SAAQ;cAEP;IACM,CAAA,CAAA;;EAGV,CAAA;GAmBH,KAGA,EAAE,gBAAa,kBAAe;CAClC,IAAM,EAAE,QAAK,eAAY,GAAa,EAChC,IAAc,EAAO,EAAS;AACpC,GAAY,UAAU;CAEtB,IAAM,IAAe,EAAQ;AAS7B,QARA,QAAgB;AACd,EAAI,MAAiB,KAAA,KAAW,EAAY,QAAQ,EAAa;IAChE,CAAC,EAAa,CAAC,EAElB,QAAgB;AACd,KAAK,SAAS,EAAY;IACzB,CAAC,GAAK,EAAY,CAAC,EAEf;GAGH,KAAkE,EACtE,gBACA,cACA,aACA,qBACI;CACJ,IAAM,IAAe,EAAO,EAAY,EAClC,IAAkB,SACf;EACL,QAAQ,EAAY,SAAS;EAC7B,OAAO;EACP,YAAY,EAAa;EAC1B,GACD,CAAC,EAAY,OAAO,CACrB;AAED,QACE,kBAAA,GAAA,EAAA,UACE,kBAAC,GAAD;EACE,WAAW,EAAK,6CAA6C,EAAU;EACvE,SAAS;YAFX,CAIE,kBAAC,GAAD;GAA2B;GAAuB;GAAY,CAAA,EAC9D,kBAAC,GAAD;GAAc,WAAU;GAAe,iBAAgB;aACpD,EAAY,KAAK,GAAM,MACtB,kBAAC,GAAD;IAAc,OAAO;cACnB,kBAAC,OAAD;KACE,cAAY,GAAG,IAAI,EAAE,GAAG,EAAY;KACpC,WAAW,EAAK,sCAAsC;eAErD;KACG,CAAA;IACO,EAPc,EAOd,CAAA;GAEJ,CAAA,CAAA;KAEhB,CAAA;GAIM,KAA0C,EACrD,gBACA,cACA,UACA,WACA,qBACI;CACJ,IAAM,IAAS,GAAO,EAChB,IAAa,EAAO,QAAQ,mBAAmB,GAAG,EAElD,EAAE,cAAW,mBAAgB,QAAc;EAC/C,IAAM,IAAS,EAAM,KAAK,EAAE,SAAM,OAAI,YAAS,MAAU;GACvD,IAAM,IAAW,MAAU,GACrB,IAAS,KAAM,GAAG,EAAO,GAAG;AAiBlC,UAAO;IAAE,YAhBU,cAAc,EAAW,GAAG;IAgB1B;IAAM;IAAI;IAAU;IAAQ,WAb/C,kBAAC,UAAD;KACE,IAAI;KACJ,cAAY;KACZ,WAAW,EACT,uJACD;KACD,eAAe,EAAY,EAAM;KACjC,MAAK;eAEJ;KACM,CAAA;IAGiD;IAAO;IACnE;AAiBF,SAAO;GAAE,WAAW;GAAQ,aAfb,EAAO,KAAK,EAAE,cAAW,SAAM,gBAC5C,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,GACD,kBAAC,GAAD;KACE,oBAAkB;KAClB,cAAY,EAAO,OAAO;KACpB;KACN,MAAK;KACL,SAAQ;eAEP,EAAO,OAAO;KACR,CAAA,CAAA;;GAIoC;IAChD;EAAC;EAAa;EAAO;EAAQ;EAAQ;EAAa;EAAW,CAAC,EAE3D,IAAa,EAAU;AAE7B,QACE,kBAAA,GAAA,EAAA,UAAA;EACE,kBAAC,MAAD;GACE,WAAW,EACT,8BACA,sFACA,gGACA,EACD;aAEA,EAAU,KAAK,EAAE,eAAY,OAAI,aAAU,cAAW,YAAS,MAC9D,kBAAC,GAAD;IACE,aAAa,EAAO,OAAO;IACf;IACF;IAEC;IACX,EAFK,KAAM,GAAG,EAAM,GAAG,IAEvB,CAAA;GAED,CAAA;EACJ,KACC,kBAAC,GAAD;GACE,oBAAkB,EAAW;GAC7B,cAAY,EAAO,OAAO;GAC1B,WAAU;GACV,MAAM,EAAW;GACjB,MAAK;GACL,OACE;IACE,gBAAgB,EAAW;IAC3B,KAAK;IACL,OAAO;IACR;GAEH,SAAQ;aAEP,EAAO,OAAO;GACR,CAAA;EAEX,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD;IACe;IACb,UAAU;IACG;IACb,CAAA;GACE,CAAA;EACL,EAAA,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { HTMLAttributes, PropsWithChildren } from 'react';
|
|
2
|
+
export interface SparkleWrapperProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
count?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare function SparkleWrapper({ children, className, count, ...props }: PropsWithChildren<SparkleWrapperProps>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as e } from "../chunks/clsx.js";
|
|
3
|
+
import { useLayoutEffect as t, useRef as n, useState as r } from "react";
|
|
4
|
+
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
5
|
+
import { Icon as o } from "@clubmed/trident-icons";
|
|
6
|
+
//#region lib/ui/SparkleWrapper.tsx
|
|
7
|
+
function s(e, t) {
|
|
8
|
+
return e + Math.random() * (t - e);
|
|
9
|
+
}
|
|
10
|
+
function c(e) {
|
|
11
|
+
return Array.from({ length: e }, () => ({
|
|
12
|
+
angle: Math.random() * 360,
|
|
13
|
+
distance: s(60, 110),
|
|
14
|
+
delay: Math.round(s(0, 150)),
|
|
15
|
+
size: Math.round(s(8, 20))
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
function l(e, t, n, r) {
|
|
19
|
+
return Math.abs(e) < 1e-6 ? r / Math.abs(t) : Math.abs(t) < 1e-6 ? n / Math.abs(e) : Math.min(n / Math.abs(e), r / Math.abs(t));
|
|
20
|
+
}
|
|
21
|
+
function u({ children: u, className: d, count: f = 7, ...p }) {
|
|
22
|
+
let m = n(null), [h, g] = r([0, 0]), [_] = r(() => c(Math.round(s(f, f + 3))));
|
|
23
|
+
return t(() => {
|
|
24
|
+
if (!m.current) return;
|
|
25
|
+
let { width: e, height: t } = m.current.getBoundingClientRect();
|
|
26
|
+
g([e / 2, t / 2]);
|
|
27
|
+
}, []), /* @__PURE__ */ a("div", {
|
|
28
|
+
...p,
|
|
29
|
+
className: e("relative inline-flex items-center justify-center", d),
|
|
30
|
+
children: [_.map(({ angle: e, distance: t, delay: n, size: r }, a) => {
|
|
31
|
+
let s = e * Math.PI / 180, c = Math.cos(s), u = Math.sin(s), [d, f] = h, p = d > 0 || f > 0 ? l(c, u, d, f) : 0;
|
|
32
|
+
return /* @__PURE__ */ i(o, {
|
|
33
|
+
name: "Diamond",
|
|
34
|
+
"aria-hidden": "true",
|
|
35
|
+
className: "absolute top-1/2 left-1/2 animate-sparkle-fly pointer-events-none",
|
|
36
|
+
style: {
|
|
37
|
+
"--sparkle-start-x": `${Math.round(c * p)}px`,
|
|
38
|
+
"--sparkle-start-y": `${Math.round(u * p)}px`,
|
|
39
|
+
"--sparkle-end-x": `${Math.round(c * (p + t))}px`,
|
|
40
|
+
"--sparkle-end-y": `${Math.round(u * (p + t))}px`,
|
|
41
|
+
animationDelay: `${n}ms`,
|
|
42
|
+
width: `${r}px`,
|
|
43
|
+
height: `${r}px`
|
|
44
|
+
}
|
|
45
|
+
}, a);
|
|
46
|
+
}), /* @__PURE__ */ i("div", {
|
|
47
|
+
ref: m,
|
|
48
|
+
className: "relative z-10 animate-bounce-enter",
|
|
49
|
+
children: u
|
|
50
|
+
})]
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { u as SparkleWrapper };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=SparkleWrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SparkleWrapper.js","names":[],"sources":["../../lib/ui/SparkleWrapper.tsx"],"sourcesContent":["'use client';\n\nimport { Icon } from '@clubmed/trident-icons';\nimport type { HTMLAttributes, PropsWithChildren } from 'react';\nimport { useLayoutEffect, useRef, useState } from 'react';\nimport clsx from 'clsx';\n\nfunction randomBetween(min: number, max: number) {\n return min + Math.random() * (max - min);\n}\n\nfunction generateSparkles(count: number) {\n return Array.from({ length: count }, () => ({\n angle: Math.random() * 360,\n distance: randomBetween(60, 110),\n delay: Math.round(randomBetween(0, 150)),\n size: Math.round(randomBetween(8, 20)),\n }));\n}\n\nfunction edgeT(cos: number, sin: number, hw: number, hh: number): number {\n if (Math.abs(cos) < 1e-6) return hh / Math.abs(sin);\n if (Math.abs(sin) < 1e-6) return hw / Math.abs(cos);\n return Math.min(hw / Math.abs(cos), hh / Math.abs(sin));\n}\n\nexport interface SparkleWrapperProps extends HTMLAttributes<HTMLDivElement> {\n count?: number;\n}\n\nexport function SparkleWrapper({\n children,\n className,\n count = 7,\n ...props\n}: PropsWithChildren<SparkleWrapperProps>) {\n const childRef = useRef<HTMLDivElement>(null);\n const [halfSize, setHalfSize] = useState<[number, number]>([0, 0]);\n const [sparkles] = useState(() => generateSparkles(Math.round(randomBetween(count, count + 3))));\n\n useLayoutEffect(() => {\n if (!childRef.current) return;\n const { width, height } = childRef.current.getBoundingClientRect();\n setHalfSize([width / 2, height / 2]);\n }, []);\n\n return (\n <div {...props} className={clsx('relative inline-flex items-center justify-center', className)}>\n {sparkles.map(({ angle, distance, delay, size }, i) => {\n const rad = (angle * Math.PI) / 180;\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const [hw, hh] = halfSize;\n const t = hw > 0 || hh > 0 ? edgeT(cos, sin, hw, hh) : 0;\n\n return (\n <Icon\n key={i}\n name=\"Diamond\"\n aria-hidden=\"true\"\n className=\"absolute top-1/2 left-1/2 animate-sparkle-fly pointer-events-none\"\n style={\n {\n '--sparkle-start-x': `${Math.round(cos * t)}px`,\n '--sparkle-start-y': `${Math.round(sin * t)}px`,\n '--sparkle-end-x': `${Math.round(cos * (t + distance))}px`,\n '--sparkle-end-y': `${Math.round(sin * (t + distance))}px`,\n animationDelay: `${delay}ms`,\n width: `${size}px`,\n height: `${size}px`,\n } as React.CSSProperties\n }\n />\n );\n })}\n <div ref={childRef} className=\"relative z-10 animate-bounce-enter\">\n {children}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AAOA,SAAS,EAAc,GAAa,GAAa;AAC/C,QAAO,IAAM,KAAK,QAAQ,IAAI,IAAM;;AAGtC,SAAS,EAAiB,GAAe;AACvC,QAAO,MAAM,KAAK,EAAE,QAAQ,GAAO,SAAS;EAC1C,OAAO,KAAK,QAAQ,GAAG;EACvB,UAAU,EAAc,IAAI,IAAI;EAChC,OAAO,KAAK,MAAM,EAAc,GAAG,IAAI,CAAC;EACxC,MAAM,KAAK,MAAM,EAAc,GAAG,GAAG,CAAA;EACtC,EAAE;;AAGL,SAAS,EAAM,GAAa,GAAa,GAAY,GAAoB;AAGvE,QAFI,KAAK,IAAI,EAAI,GAAG,OAAa,IAAK,KAAK,IAAI,EAAI,GAC/C,KAAK,IAAI,EAAI,GAAG,OAAa,IAAK,KAAK,IAAI,EAAI,GAC5C,KAAK,IAAI,IAAK,KAAK,IAAI,EAAI,EAAE,IAAK,KAAK,IAAI,EAAI,CAAC;;AAOzD,SAAgB,EAAe,EAC7B,aACA,cACA,WAAQ,GACR,GAAG,KACsC;CACzC,IAAM,IAAW,EAAuB,KAAK,EACvC,CAAC,GAAU,KAAe,EAA2B,CAAC,GAAG,EAAE,CAAC,EAC5D,CAAC,KAAY,QAAe,EAAiB,KAAK,MAAM,EAAc,GAAO,IAAQ,EAAE,CAAC,CAAC,CAAC;AAQhG,QANA,QAAsB;AACpB,MAAI,CAAC,EAAS,QAAS;EACvB,IAAM,EAAE,UAAO,cAAW,EAAS,QAAQ,uBAAuB;AAClE,IAAY,CAAC,IAAQ,GAAG,IAAS,EAAE,CAAC;IACnC,EAAE,CAAC,EAGJ,kBAAC,OAAD;EAAK,GAAI;EAAO,WAAW,EAAK,oDAAoD,EAAU;YAA9F,CACG,EAAS,KAAK,EAAE,UAAO,aAAU,UAAO,WAAQ,MAAM;GACrD,IAAM,IAAO,IAAQ,KAAK,KAAM,KAC1B,IAAM,KAAK,IAAI,EAAI,EACnB,IAAM,KAAK,IAAI,EAAI,EACnB,CAAC,GAAI,KAAM,GACX,IAAI,IAAK,KAAK,IAAK,IAAI,EAAM,GAAK,GAAK,GAAI,EAAG,GAAG;AAEvD,UACE,kBAAC,GAAD;IAEE,MAAK;IACL,eAAY;IACZ,WAAU;IACV,OACE;KACE,qBAAqB,GAAG,KAAK,MAAM,IAAM,EAAE,CAAC;KAC5C,qBAAqB,GAAG,KAAK,MAAM,IAAM,EAAE,CAAC;KAC5C,mBAAmB,GAAG,KAAK,MAAM,KAAO,IAAI,GAAU,CAAC;KACvD,mBAAmB,GAAG,KAAK,MAAM,KAAO,IAAI,GAAU,CAAC;KACvD,gBAAgB,GAAG,EAAM;KACzB,OAAO,GAAG,EAAK;KACf,QAAQ,GAAG,EAAK;;IAGpB,EAfK,EAeL;IAEJ,EACF,kBAAC,OAAD;GAAK,KAAK;GAAU,WAAU;GAC3B;GACG,CAAA,CAAA"}
|