react-carousel-latest
Version:
A headless, accessible, tree-shakeable React carousel with a compound-component API (and a backwards-compatible CardSlider preset).
991 lines (980 loc) • 47.3 kB
JavaScript
"use client";
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var react = require('react');
var jsxRuntime = require('react/jsx-runtime');
var framerMotion = require('framer-motion');
// src/components/Carousel.tsx
var CarouselContext = react.createContext(null);
function useCarouselContext() {
const api = react.useContext(CarouselContext);
if (api === null) {
throw new Error(
"Carousel compound components must be rendered inside <Carousel>. Did you forget to wrap them, or import the part from a different package version?"
);
}
return api;
}
// src/utils/clamp.ts
function clamp(value, min, max) {
if (max < min) return min;
return Math.min(Math.max(value, min), max);
}
function wrapIndex(index, count) {
if (count <= 0) return 0;
return (index % count + count) % count;
}
// src/core/carouselReducer.ts
function carouselReducer(state, action) {
const maxIndex = Math.max(0, state.slidesCount - state.slidesPerView);
switch (action.type) {
case "NEXT": {
const target = state.activeIndex + action.step;
const next = action.loop ? wrapIndex(target, state.slidesCount) : clamp(target, 0, maxIndex);
return next === state.activeIndex ? state : { ...state, activeIndex: next };
}
case "PREV": {
const target = state.activeIndex - action.step;
const next = action.loop ? wrapIndex(target, state.slidesCount) : clamp(target, 0, maxIndex);
return next === state.activeIndex ? state : { ...state, activeIndex: next };
}
case "GO_TO": {
const next = clamp(action.index, 0, maxIndex);
return next === state.activeIndex ? state : { ...state, activeIndex: next };
}
case "SET_COUNT": {
if (action.slidesCount === state.slidesCount) return state;
const activeIndex = clamp(state.activeIndex, 0, Math.max(0, action.slidesCount - state.slidesPerView));
return { ...state, slidesCount: action.slidesCount, activeIndex };
}
case "SET_SLIDES_PER_VIEW": {
if (action.slidesPerView === state.slidesPerView) return state;
const activeIndex = clamp(state.activeIndex, 0, Math.max(0, state.slidesCount - action.slidesPerView));
return { ...state, slidesPerView: action.slidesPerView, activeIndex };
}
case "SET_PLAYING": {
return action.isPlaying === state.isPlaying ? state : { ...state, isPlaying: action.isPlaying };
}
default:
return state;
}
}
function useAutoplay({ enabled, interval, onTick, rootRef }) {
const onTickRef = react.useRef(onTick);
onTickRef.current = onTick;
react.useEffect(() => {
if (!enabled || typeof window === "undefined") return;
const prefersReducedMotion = window.matchMedia?.(
"(prefers-reduced-motion: reduce)"
).matches;
if (prefersReducedMotion) return;
const root = rootRef.current;
let paused = false;
const pause = () => paused = true;
const resume = () => paused = false;
const timer = window.setInterval(() => {
if (!paused && !document.hidden) onTickRef.current();
}, interval);
root?.addEventListener("pointerenter", pause);
root?.addEventListener("pointerleave", resume);
root?.addEventListener("focusin", pause);
root?.addEventListener("focusout", resume);
return () => {
window.clearInterval(timer);
root?.removeEventListener("pointerenter", pause);
root?.removeEventListener("pointerleave", resume);
root?.removeEventListener("focusin", pause);
root?.removeEventListener("focusout", resume);
};
}, [enabled, interval, rootRef]);
}
function useBreakpoints(base, breakpoints) {
const [resolved, setResolved] = react.useState(base);
const bpKey = breakpoints ? JSON.stringify(breakpoints) : "";
react.useEffect(() => {
if (!breakpoints || typeof window === "undefined") return;
const resolve = () => {
const next = { ...base };
for (const width of Object.keys(breakpoints).map(Number).sort((a, b) => a - b)) {
if (window.matchMedia(`(min-width: ${width}px)`).matches) {
const over = breakpoints[width];
if (over.slidesPerView != null) next.slidesPerView = over.slidesPerView;
if (over.slidesToScroll != null) next.slidesToScroll = over.slidesToScroll;
}
}
return next;
};
const update = () => setResolved(resolve());
update();
window.addEventListener("resize", update);
return () => window.removeEventListener("resize", update);
}, [bpKey, base.slidesPerView, base.slidesToScroll]);
return breakpoints ? resolved : base;
}
function useKeyboard({
rootRef,
orientation,
onPrev,
onNext,
onFirst,
onLast
}) {
const handlers = react.useRef({ onPrev, onNext, onFirst, onLast });
handlers.current = { onPrev, onNext, onFirst, onLast };
react.useEffect(() => {
const root = rootRef.current;
if (!root) return;
const prevKey = orientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
const nextKey = orientation === "horizontal" ? "ArrowRight" : "ArrowDown";
const onKeyDown = (event) => {
const { onPrev: onPrev2, onNext: onNext2, onFirst: onFirst2, onLast: onLast2 } = handlers.current;
switch (event.key) {
case prevKey:
event.preventDefault();
onPrev2();
break;
case nextKey:
event.preventDefault();
onNext2();
break;
case "Home":
event.preventDefault();
onFirst2();
break;
case "End":
event.preventDefault();
onLast2();
break;
}
};
root.addEventListener("keydown", onKeyDown);
return () => root.removeEventListener("keydown", onKeyDown);
}, [rootRef, orientation]);
}
function useSwipe({
trackRef,
orientation,
onPrev,
onNext,
threshold = 50,
onSwipeStart,
onSwipeEnd
}) {
const handlers = react.useRef({ onPrev, onNext, onSwipeStart, onSwipeEnd });
handlers.current = { onPrev, onNext, onSwipeStart, onSwipeEnd };
react.useEffect(() => {
const track = trackRef.current;
if (!track) return;
const isHorizontal = orientation === "horizontal";
let startPos = 0;
let delta = 0;
let dragging = false;
let frame = 0;
const axis = (event) => isHorizontal ? event.clientX : event.clientY;
const paint = () => {
frame = 0;
track.style.setProperty("--rc-drag", `${delta}px`);
};
const onPointerDown = (event) => {
if (event.button !== 0) return;
dragging = true;
startPos = axis(event);
delta = 0;
track.setAttribute("data-dragging", "true");
track.setPointerCapture(event.pointerId);
handlers.current.onSwipeStart?.();
};
const onPointerMove = (event) => {
if (!dragging) return;
delta = axis(event) - startPos;
if (!frame) frame = window.requestAnimationFrame(paint);
};
const onPointerUp = (event) => {
if (!dragging) return;
dragging = false;
if (frame) window.cancelAnimationFrame(frame), frame = 0;
track.removeAttribute("data-dragging");
track.style.setProperty("--rc-drag", "0px");
if (track.hasPointerCapture(event.pointerId)) {
track.releasePointerCapture(event.pointerId);
}
const committed = Math.abs(delta) > threshold;
handlers.current.onSwipeEnd?.({
delta,
direction: committed ? delta < 0 ? "next" : "prev" : "none"
});
if (committed) {
delta < 0 ? handlers.current.onNext() : handlers.current.onPrev();
}
};
track.addEventListener("pointerdown", onPointerDown);
track.addEventListener("pointermove", onPointerMove);
track.addEventListener("pointerup", onPointerUp);
track.addEventListener("pointercancel", onPointerUp);
return () => {
if (frame) window.cancelAnimationFrame(frame);
track.removeEventListener("pointerdown", onPointerDown);
track.removeEventListener("pointermove", onPointerMove);
track.removeEventListener("pointerup", onPointerUp);
track.removeEventListener("pointercancel", onPointerUp);
};
}, [trackRef, orientation, threshold]);
}
// src/core/useCarousel.ts
function useCarousel(options) {
const {
slidesCount,
initialIndex = 0,
loop = false,
autoplay = false,
autoplayInterval = 4e3,
slidesToScroll = 1,
slidesPerView = 1,
breakpoints,
orientation = "horizontal",
onIndexChange,
onSettle,
onSwipeStart,
onSwipeEnd
} = options;
const effective = useBreakpoints({ slidesPerView, slidesToScroll }, breakpoints);
const trackRef = react.useRef(null);
const rootRef = react.useRef(null);
const [state, dispatch] = react.useReducer(
carouselReducer,
void 0,
() => ({
activeIndex: clamp(initialIndex, 0, Math.max(0, slidesCount - slidesPerView)),
slidesCount,
slidesPerView,
isPlaying: autoplay
})
);
react.useEffect(() => {
dispatch({ type: "SET_COUNT", slidesCount });
}, [slidesCount]);
react.useEffect(() => {
dispatch({ type: "SET_SLIDES_PER_VIEW", slidesPerView: effective.slidesPerView });
}, [effective.slidesPerView]);
const onIndexChangeRef = react.useRef(onIndexChange);
onIndexChangeRef.current = onIndexChange;
react.useEffect(() => {
onIndexChangeRef.current?.(state.activeIndex);
}, [state.activeIndex]);
const onSettleRef = react.useRef(onSettle);
onSettleRef.current = onSettle;
const indexRef = react.useRef(state.activeIndex);
indexRef.current = state.activeIndex;
react.useEffect(() => {
const track = trackRef.current;
if (!track) return;
const handle = (event) => {
if (event.target === track && event.propertyName === "transform") {
onSettleRef.current?.(indexRef.current);
}
};
track.addEventListener("transitionend", handle);
return () => track.removeEventListener("transitionend", handle);
}, []);
const step = effective.slidesToScroll;
const next = react.useCallback(
() => dispatch({ type: "NEXT", step, loop }),
[step, loop]
);
const prev = react.useCallback(
() => dispatch({ type: "PREV", step, loop }),
[step, loop]
);
const goTo = react.useCallback((index) => dispatch({ type: "GO_TO", index }), []);
const play = react.useCallback(() => dispatch({ type: "SET_PLAYING", isPlaying: true }), []);
const pause = react.useCallback(() => dispatch({ type: "SET_PLAYING", isPlaying: false }), []);
const first = react.useCallback(() => dispatch({ type: "GO_TO", index: 0 }), []);
const last = react.useCallback(
() => dispatch({ type: "GO_TO", index: slidesCount - 1 }),
[slidesCount]
);
useKeyboard({ rootRef, orientation, onPrev: prev, onNext: next, onFirst: first, onLast: last });
useSwipe({ trackRef, orientation, onPrev: prev, onNext: next, onSwipeStart, onSwipeEnd });
useAutoplay({
enabled: state.isPlaying,
interval: autoplayInterval,
onTick: next,
rootRef
});
const maxIndex = Math.max(0, state.slidesCount - state.slidesPerView);
const canPrev = loop || state.activeIndex > 0;
const canNext = loop || state.activeIndex < maxIndex;
return react.useMemo(
() => ({
activeIndex: state.activeIndex,
slidesCount: state.slidesCount,
slidesPerView: state.slidesPerView,
isPlaying: state.isPlaying,
canPrev,
canNext,
orientation,
next,
prev,
goTo,
play,
pause,
trackRef,
rootRef
}),
[state, canPrev, canNext, orientation, next, prev, goTo, play, pause]
);
}
// src/utils/cx.ts
function cx(...parts) {
return parts.filter(Boolean).join(" ");
}
var Carousel = react.forwardRef(function Carousel2({
slidesCount,
initialIndex,
loop,
autoplay,
autoplayInterval,
slidesToScroll,
slidesPerView,
breakpoints,
orientation = "horizontal",
onIndexChange,
onSettle,
onSwipeStart,
onSwipeEnd,
label = "Carousel",
className,
style,
children,
...rest
}, ref) {
const api = useCarousel({
slidesCount,
initialIndex,
loop,
autoplay,
autoplayInterval,
slidesToScroll,
slidesPerView,
breakpoints,
orientation,
onIndexChange,
onSettle,
onSwipeStart,
onSwipeEnd
});
react.useImperativeHandle(
ref,
() => ({
activeIndex: api.activeIndex,
canPrev: api.canPrev,
canNext: api.canNext,
next: api.next,
prev: api.prev,
goTo: api.goTo,
play: api.play,
pause: api.pause
}),
[api]
);
const sizedStyle = api.slidesPerView > 1 ? {
...style,
"--rc-slide-size": `calc((100% - ${api.slidesPerView - 1} * var(--rc-slide-gap)) / ${api.slidesPerView})`
} : style;
return /* @__PURE__ */ jsxRuntime.jsx(CarouselContext.Provider, { value: api, children: /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
ref: api.rootRef,
className: cx("rc-root", className),
role: "region",
"aria-roledescription": "carousel",
"aria-label": label,
"data-orientation": orientation,
tabIndex: 0,
style: sizedStyle,
...rest,
children
}
) });
});
function Track({ children, className, style, ...rest }) {
const { activeIndex, isPlaying, orientation, trackRef } = useCarouselContext();
return /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: "rc-viewport",
"data-orientation": orientation,
"aria-live": isPlaying ? "off" : "polite",
children: /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
ref: trackRef,
className: cx("rc-track", className),
"data-orientation": orientation,
style: { "--rc-active-index": activeIndex, ...style },
...rest,
children
}
)
}
);
}
function Slide({ index, children, className, ...rest }) {
const { activeIndex, slidesCount } = useCarouselContext();
const isActive = index === activeIndex;
return /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: cx("rc-slide", isActive && "rc-slide--active", className),
role: "group",
"aria-roledescription": "slide",
"aria-label": `${index + 1} of ${slidesCount}`,
"aria-hidden": !isActive || void 0,
"data-active": isActive || void 0,
...rest,
children
}
);
}
var DEFAULT_LABELS = {
prev: "Previous slide",
next: "Next slide",
first: "First slide",
last: "Last slide"
};
function Icon({ dir }) {
const lines = {
prev: ["15 18 9 12 15 6"],
next: ["9 18 15 12 9 6"],
first: ["18 18 12 12 18 6", "11 18 5 12 11 6"],
last: ["13 18 19 12 13 6", "6 18 12 12 6 6"]
};
return /* @__PURE__ */ jsxRuntime.jsx(
"svg",
{
className: "rc-button__icon",
viewBox: "0 0 24 24",
width: "1em",
height: "1em",
fill: "none",
stroke: "currentColor",
strokeWidth: 2,
strokeLinecap: "round",
strokeLinejoin: "round",
"aria-hidden": "true",
focusable: "false",
children: lines[dir].map((points) => /* @__PURE__ */ jsxRuntime.jsx("polyline", { points }, points))
}
);
}
function Button({
dir,
className,
children,
disabled,
"aria-label": ariaLabel,
...rest
}) {
const { prev, next, goTo, slidesCount, canPrev, canNext } = useCarouselContext();
const actions = {
prev,
next,
first: () => goTo(0),
last: () => goTo(slidesCount - 1)
};
const enabled = dir === "prev" || dir === "first" ? canPrev : canNext;
return /* @__PURE__ */ jsxRuntime.jsx(
"button",
{
type: "button",
className: cx("rc-button", `rc-button--${dir}`, className),
"aria-label": ariaLabel ?? DEFAULT_LABELS[dir],
onClick: actions[dir],
disabled: disabled ?? !enabled,
...rest,
children: children ?? /* @__PURE__ */ jsxRuntime.jsx(Icon, { dir })
}
);
}
function Dots({ className, dotLabel, ...rest }) {
const { slidesCount, activeIndex, goTo } = useCarouselContext();
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx("rc-dots", className), role: "tablist", ...rest, children: Array.from({ length: slidesCount }, (_, index) => {
const isActive = index === activeIndex;
return /* @__PURE__ */ jsxRuntime.jsx(
"button",
{
type: "button",
role: "tab",
"aria-selected": isActive,
"aria-current": isActive || void 0,
"aria-label": dotLabel ? dotLabel(index) : `Go to slide ${index + 1}`,
className: cx("rc-dot", isActive && "rc-dot--active"),
onClick: () => goTo(index)
},
index
);
}) });
}
function Icon2({ playing }) {
return /* @__PURE__ */ jsxRuntime.jsx(
"svg",
{
className: "rc-button__icon",
viewBox: "0 0 24 24",
width: "1em",
height: "1em",
fill: "currentColor",
"aria-hidden": "true",
focusable: "false",
children: playing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "6", y: "5", width: "4", height: "14", rx: "1" }),
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "14", y: "5", width: "4", height: "14", rx: "1" })
] }) : /* @__PURE__ */ jsxRuntime.jsx("polygon", { points: "7 4 20 12 7 20 7 4" })
}
);
}
function PlayPause({ className, children, "aria-label": ariaLabel, ...rest }) {
const { isPlaying, play, pause } = useCarouselContext();
return /* @__PURE__ */ jsxRuntime.jsx(
"button",
{
type: "button",
className: cx("rc-button", "rc-button--playpause", className),
"aria-label": ariaLabel ?? (isPlaying ? "Pause" : "Play"),
"aria-pressed": isPlaying,
onClick: isPlaying ? pause : play,
...rest,
children: children ?? /* @__PURE__ */ jsxRuntime.jsx(Icon2, { playing: isPlaying })
}
);
}
// src/components/index.ts
var Carousel3 = Object.assign(Carousel, {
Track,
Slide,
Button,
Dots,
PlayPause
});
function Icon3({
size = 24,
name,
children,
...rest
}) {
return /* @__PURE__ */ jsxRuntime.jsx(
"svg",
{
xmlns: "http://www.w3.org/2000/svg",
width: size,
height: size,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
strokeWidth: 2,
strokeLinecap: "round",
strokeLinejoin: "round",
className: `lucide lucide-${name}`,
...rest,
children
}
);
}
function ChevronLeft(props) {
return /* @__PURE__ */ jsxRuntime.jsx(Icon3, { name: "chevron-left", ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) });
}
function ChevronRight(props) {
return /* @__PURE__ */ jsxRuntime.jsx(Icon3, { name: "chevron-right", ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) });
}
function ArrowUpRight(props) {
return /* @__PURE__ */ jsxRuntime.jsxs(Icon3, { name: "arrow-up-right", ...props, children: [
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 7h10v10" }),
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 17 17 7" })
] });
}
var shapePaths = {
blob: [
"M53.3,-56.6C68.8,-42.1,81.5,-21.1,78.6,-4.5C75.6,12.1,57,24.2,41.5,38C26,51.8,13,67.3,-1,68.6C-15,69.8,-30,56.8,-41.3,42.7C-52.6,28.6,-60.2,13.3,-61.8,-3.4C-63.3,-20.1,-58.9,-38.2,-47.3,-52.6C-35.7,-67.1,-17.9,-77.9,2,-80.3C21.9,-82.7,43.8,-76.8,53.3,-56.6Z",
"M40.6,-64.2C50.5,-51.2,55.3,-38,61.2,-26C67.2,-14,74.3,-3.1,74.8,8.7C75.3,20.6,69.2,33.4,60.1,41.8C50.9,50.3,38.7,54.5,26.1,63.4C13.4,72.3,0.3,86,-16.3,89.5C-32.8,93,-52.9,86.3,-60.6,71.8C-68.2,57.2,-63.4,34.8,-58,16.6C-52.7,-1.7,-46.7,-15.7,-39.3,-29.6C-31.9,-43.5,-23.1,-57.3,-10.2,-66.4C2.7,-75.5,27.8,-79.8,40.6,-64.2Z",
"M44.7,-61.6C55.7,-52,61.7,-38.4,64.4,-24.9C67.1,-11.4,66.5,2,62.3,14.5C58.2,27,50.6,38.6,40.8,49.2C31,59.8,19,69.3,5.3,71.5C-8.5,73.7,-17,68.7,-29.2,62.5C-41.3,56.2,-57.1,48.7,-65.3,36.2C-73.6,23.6,-74.3,6.1,-68.9,-8.1C-63.5,-22.3,-52,-33.3,-40.3,-43.7C-28.6,-54,-16.8,-63.6,-2.9,-61.3C11,-59,22,-44.9,44.7,-61.6Z",
"M62.1,-47.5C75.2,-32.4,78.7,-8.5,75.7,13.8C72.7,36.1,63.3,56.7,47.3,65.8C31.3,74.9,8.8,72.5,-11.8,66.2C-32.5,60,-51.2,49.8,-61.6,34.5C-72,19.1,-74.1,-1.5,-66.9,-17.5C-59.7,-33.5,-43.3,-44.8,-27.7,-58.2C-12.2,-71.6,2.5,-87.2,20.1,-87.4C37.8,-87.6,58.3,-72.5,62.1,-47.5Z"
],
heart: [
"M60.83,17.18c8-8.35,13.62-15.57,26-17C110-2.46,131.27,21.26,119.57,44.61c-3.33,6.65-10.11,14.56-17.61,22.32-8.23,8.52-17.34,16.87-23.72,23.2l-17.4,17.26L46.46,93.55C29.16,76.89,1,55.92,0,29.94-.63,11.74,13.73.08,30.25.29c14.76.2,21,7.54,30.58,16.89Z"
],
star: [
"M63.09,1.11l16,39.1l42.14,3.13c0.98,0.07,1.72,0.92,1.65,1.9c-0.04,0.52-0.3,0.98-0.68,1.28L90,73.79l10.04,41.05 c0.23,0.95-0.36,1.92-1.31,2.15c-0.5,0.12-1,0.02-1.39-0.24l-35.9-22.21L25.5,116.77c-0.84,0.52-1.93,0.26-2.45-0.58 c-0.26-0.42-0.32-0.91-0.22-1.35l0,0l10.04-41.05L0.63,46.48c-0.75-0.63-0.84-1.76-0.21-2.51c0.32-0.38,0.77-0.59,1.23-0.63v0 l42.14-3.13l16-39.1c0.37-0.91,1.41-1.35,2.31-0.98C62.57,0.32,62.91,0.68,63.09,1.11L63.09,1.11L63.09,1.11z M64.1,39.66 l5.71,13.96l15.05,1.12c0.27,0.02,0.52,0.08,0.76,0.17l29.73-8.43l-37.62-2.8l0-0.01c-0.65-0.05-1.26-0.45-1.52-1.1L63.16,10.66 l0.3,28.08C63.74,39,63.96,39.31,64.1,39.66L64.1,39.66L64.1,39.66z M111.1,51.25l-23.95,6.79c-0.15,0.52-0.47,0.97-0.88,1.29 l-11.45,9.7l3.59,14.67c0.07,0.29,0.09,0.58,0.06,0.86l15.86,21.9L86.3,73.65c-0.2-0.66,0-1.4,0.56-1.87L111.1,51.25L111.1,51.25z M92.21,109.39l-16.3-22.51c-0.51,0-0.99-0.15-1.4-0.42L63.6,79.7v11.17c0,0.25-0.05,0.49-0.15,0.71L92.21,109.39L92.21,109.39z M60.18,91.13c-0.01-0.08-0.02-0.17-0.02-0.25V79.51l-11.28,6.98c-0.34,0.21-0.71,0.33-1.09,0.37L30.65,109.4L60.18,91.13 L60.18,91.13z M28.53,106.54l16.49-21.68c-0.08-0.38-0.08-0.78,0.01-1.15l0,0l3.59-14.67L37.1,59.27c-0.43-0.36-0.7-0.83-0.83-1.33 L8.71,48.66l27.31,23.12l0,0c0.5,0.42,0.74,1.1,0.58,1.78L28.53,106.54L28.53,106.54z M12,46.15l25.65,8.65 c0.08,0.03,0.16,0.06,0.23,0.1c0.22-0.08,0.46-0.13,0.7-0.15l0,0l15.06-1.12l5.71-13.96c0.16-0.39,0.4-0.71,0.69-0.97l-0.3-28.05 l-13.01,31.8c-0.21,0.68-0.82,1.19-1.58,1.25L12,46.15L12,46.15z M60.1,44.59l-4.7,11.48l-16.64,1.24l12.74,10.79l-3.97,16.21 l0.61-0.38l2.88-1.78l10.7-6.62l4.71,2.92l9.11,5.64l0.37,0.23l-3.97-16.21l12.74-10.79l-0.26-0.02v0l-16.38-1.22l-4.51-11.03v0 l-1.81-4.42L60.1,44.59L60.1,44.59z"
],
bear: [
"M101.1,19.08c-0.82,0.09-1.56-0.51-1.64-1.33c-0.09-0.82,0.51-1.56,1.33-1.64c0.8-0.09,1.6-0.06,2.4,0.07 c0.78,0.13,1.56,0.37,2.34,0.71c0.76,0.33,1.1,1.2,0.78,1.96c-0.33,0.76-1.2,1.1-1.96,0.78c-0.55-0.24-1.1-0.4-1.65-0.49 C102.16,19.04,101.63,19.03,101.1,19.08L101.1,19.08z M115.43,17.02c-1.16,0.44-1.55,1.27-1.31,3.62c0.24,2.36,0.36,4.57,2.91,5.48 c0.22,0.08,0.45,0.14,0.69,0.19c-1.2,0.84-2.7,1.21-4.31,1.6c-0.73,0.18-1.47,0.36-2.27,0.6c-0.06,0.01-0.12,0.03-0.18,0.06 L80.61,40.06c0.04-1.42,0-2.75-0.15-3.92c-0.13-1.02-0.31-1.98-0.55-2.89c-0.24-0.92-0.54-1.8-0.89-2.63 c-0.32-0.76-1.2-1.12-1.96-0.8c-0.76,0.32-1.12,1.2-0.8,1.96c0.29,0.7,0.54,1.44,0.75,2.22c0.21,0.8,0.37,1.64,0.48,2.51 c0.18,1.4,0.18,3.08,0.06,4.91c-0.33,0.4-0.44,0.96-0.24,1.47c0.03,0.08,0.06,0.15,0.1,0.22c-0.48,4.95-1.68,10.79-2.7,15.77 c-0.47,2.29-0.9,4.42-1.19,6.02l0,0c-0.01,0.07-0.02,0.15-0.02,0.23c-0.03,1.32,0.03,2.48,0.2,3.49c0.18,1.1,0.48,2.03,0.9,2.78 c0.88,1.55,2.13,1.94,3.4,2.34c0.83,0.26,1.68,0.53,2.06,1.46c0.06,0.15,0.08,0.31,0.05,0.47c-0.03,0.19-0.12,0.4-0.27,0.63 c-2.4,1.55-4.8,2.45-7.03,2.67c-2.19,0.22-4.23-0.21-5.95-1.33c-2.04-1.33-3.14-2.87-3.76-4.6c-0.65-1.84-0.8-3.98-0.91-6.34 l-0.1-2.09c0-0.04,0-0.08,0-0.12c-0.22-2.8-1.08-4.6-2.35-5.76c-0.84-0.77-1.82-1.22-2.88-1.48c0.18-0.74,0.33-1.45,0.43-2.16 c0.18-1.24,0.25-2.43,0.19-3.6c-0.09-1.7-0.43-3.31-1.04-4.85c-0.6-1.52-1.47-3-2.6-4.45c-0.51-0.65-1.45-0.77-2.1-0.26 c-0.65,0.51-0.77,1.45-0.26,2.1c0.94,1.21,1.67,2.43,2.17,3.71c0.37,0.94,0.62,1.91,0.75,2.9c-4.52,2.23-7.53,3.49-10.63,4.3 c-0.64,0.17-1.29,0.31-1.96,0.45c-0.21,0-0.41,0.04-0.61,0.12c-1.71,0.31-3.59,0.55-5.86,0.78c1.43-1.71,2.58-3.59,3.44-5.65 c1.79-4.31,2.29-9.37,1.4-15.24c-0.12-0.82-0.89-1.38-1.7-1.26c-0.82,0.12-1.38,0.89-1.26,1.7c0.81,5.32,0.38,9.85-1.2,13.65 c-1.2,2.88-3.06,5.36-5.56,7.47c-0.05,0.04-0.09,0.07-0.14,0.11c-0.72,0.6-1.49,1.17-2.31,1.71c-0.12,0.07-0.23,0.16-0.33,0.26 c-1.23,1.31-2.31,2.69-3.23,4.16c-0.9,1.45-1.64,2.98-2.2,4.62c-0.11,0.26-0.15,0.56-0.09,0.86c0.36,1.83,1.1,3.1,2.15,3.88 c1.03,0.77,2.29,1.03,3.72,0.88c1.26,0.22,2.07,0.88,2.38,1.64c0.12,0.29,0.16,0.6,0.12,0.91c-0.04,0.29-0.15,0.59-0.35,0.85 c-0.45,0.59-1.29,1.05-2.59,1.2h-3.18c-0.07,0-0.13,0-0.19,0.01H14.08L7.02,64.93c-0.14-1.3-0.04-2.35,0.26-3.21 c0.29-0.86,0.79-1.55,1.43-2.12l0,0c0.18-0.17,0.33-0.38,0.41-0.63c0.71-2.14,0.99-4.78,0.83-7.92c-0.15-3.02-0.71-6.54-1.66-10.53 c-0.03-0.18-0.1-0.36-0.21-0.53c-0.44-0.7-1.36-0.91-2.06-0.47c-1.23,0.77-2.04,1.06-2.4,0.84c-0.43-0.27-0.64-1.27-0.63-3.05 l0-0.01c0.18-4.42,1.2-8.16,2.91-11.32c1.71-3.15,4.12-5.75,7.09-7.89v0c0.04-0.03,0.08-0.06,0.12-0.09 c3.87-3.42,8.86-6,14.87-7.78c6.08-1.8,13.2-2.78,21.29-3.01c0.25,0.01,0.51-0.05,0.75-0.18c4.59-2.49,8.94-4.27,12.58-4 c3.39,0.25,6.28,2.44,8.34,7.82c0.29,0.77,1.16,1.16,1.93,0.87c0.77-0.29,1.16-1.16,0.87-1.93c-0.24-0.64-0.5-1.24-0.77-1.8 l15.8,1.51c0.76,0.11,1.5-0.38,1.67-1.15c0.43-1.9,1.56-3.26,2.89-3.95c0.69-0.36,1.43-0.54,2.14-0.52 c0.68,0.02,1.36,0.22,1.95,0.63c1.04,0.71,1.85,2.08,2.12,4.23h0c0.07,0.58,0.48,1.09,1.08,1.26c3.44,0.99,6.61,2.15,9.38,3.55 C112.04,14.55,113.86,15.71,115.43,17.02L115.43,17.02z M71.43,5.23c0.29-0.23,0.66-0.35,1.06-0.31L87.92,6.4 c0.81-2.16,2.31-3.76,4.04-4.66c1.13-0.59,2.37-0.89,3.6-0.86c1.25,0.03,2.49,0.4,3.56,1.14c1.52,1.04,2.73,2.8,3.24,5.35 c3.25,0.98,6.28,2.12,8.99,3.49c2.97,1.5,5.56,3.28,7.67,5.4c1.85,1.38,2.98,2.86,3.51,4.38c0.61,1.77,0.4,3.51-0.5,5.18 c-1.9,3.54-4.73,4.23-7.91,5c-0.7,0.17-1.43,0.35-2.12,0.55L80.4,43.33c-0.5,5.15-1.71,11.09-2.75,16.15 c-0.43,2.09-0.82,4.02-1.15,5.85c-0.02,1.08,0.04,2.02,0.16,2.82c0.12,0.74,0.3,1.34,0.55,1.77c0.3,0.52,0.99,0.74,1.69,0.96 c1.49,0.47,3.03,0.95,3.94,3.19c0.28,0.68,0.35,1.4,0.21,2.15c-0.12,0.66-0.41,1.32-0.88,1.98c-0.11,0.17-0.25,0.31-0.43,0.43 c-2.89,1.91-5.84,3.03-8.64,3.31c-2.87,0.29-5.56-0.3-7.87-1.8c-2.68-1.75-4.13-3.79-4.95-6.11c-0.78-2.21-0.95-4.59-1.08-7.19 l-0.1-2.08l0-0.05c-0.15-1.94-0.65-3.1-1.38-3.77c-0.7-0.64-1.7-0.89-2.84-0.97c-0.12-0.01-0.25-0.03-0.37-0.07 c-0.79-0.25-1.23-1.08-0.98-1.87c0.37-1.18,0.63-2.3,0.79-3.37c0.03-0.23,0.06-0.46,0.09-0.69c-3.99,1.92-6.86,3.08-9.9,3.86 c-0.67,0.17-1.34,0.33-2.03,0.47l-4.88,5.14c-0.28,0.34-0.5,0.59-0.7,0.83c-1.22,1.4-2.19,2.53-2.04,4.5 c0.03,0.34,0.1,0.66,0.21,0.95c0.02,0.06,0.05,0.12,0.08,0.18c2.88-0.22,5.13,0.91,6.4,2.5c0.7,0.87,1.11,1.88,1.2,2.9 c0.09,1.07-0.17,2.14-0.83,3.09c-1.17,1.66-3.59,2.85-7.53,2.64v0h-6.73c-0.6,0.05-1.24,0.06-1.94,0.01H13.18v0 c-0.53,0-1.05-0.29-1.32-0.79L4.25,66.1l0,0c-0.08-0.16-0.14-0.33-0.17-0.51c-0.26-1.92-0.1-3.5,0.35-4.83 c0.43-1.24,1.1-2.25,1.95-3.09c0.51-1.73,0.7-3.89,0.57-6.49c-0.12-2.39-0.51-5.13-1.18-8.2c-1.48,0.57-2.74,0.55-3.77-0.11 c-1.35-0.86-2.03-2.7-2.01-5.6c0-0.03,0-0.07,0-0.1c0.2-4.92,1.34-9.09,3.26-12.63c1.92-3.53,4.61-6.44,7.92-8.85 c4.21-3.7,9.55-6.46,15.95-8.36c6.25-1.85,13.53-2.87,21.78-3.12c4.92-2.64,9.67-4.5,13.9-4.19C66.15,0.28,69.09,1.81,71.43,5.23 L71.43,5.23z M31.93,59.63c-0.69,0.56-1.42,1.09-2.19,1.6c-1.05,1.13-1.97,2.31-2.75,3.57c-0.73,1.18-1.34,2.41-1.81,3.7 c0.21,0.84,0.52,1.39,0.92,1.68c0.41,0.3,0.99,0.39,1.71,0.3c0.15-0.02,0.3-0.03,0.45-0.01c2.53,0.35,4.21,1.8,4.91,3.51 c0.32,0.77,0.43,1.59,0.34,2.39c-0.07,0.58-0.25,1.16-0.54,1.7h1.43v0c0.03,0,0.06,0,0.09,0c2.79,0.16,4.36-0.47,4.99-1.37 c0.24-0.33,0.33-0.72,0.29-1.11c-0.04-0.44-0.23-0.89-0.55-1.28c-0.81-1-2.38-1.68-4.48-1.32c-0.55,0.13-1.15-0.05-1.52-0.52 c-0.4-0.5-0.72-1.05-0.94-1.62c-0.23-0.58-0.36-1.18-0.41-1.82c-0.25-3.2,1.09-4.75,2.77-6.68c0.24-0.27,0.49-0.56,0.67-0.78 c0.04-0.05,0.08-0.1,0.12-0.14l2.23-2.34C35.98,59.27,34.11,59.44,31.93,59.63L31.93,59.63z"
],
music: [
"M11.7,0h6.19V2.07c15.49,3.54,17.26,11,8.28,22.7.95-11.63-.22-14.12-8.28-14.66v29.4a3.62,3.62,0,0,1,0,.47c0,3.82-4,7.61-8.95,8.47S0,46.9,0,43.07c0-5.21,7.16-9.74,11.7-8.14V0ZM103,0h6.19V2.07c15.48,3.54,17.25,11,8.27,22.7,1-11.63-.22-14.12-8.27-14.66v29.4c0,.15,0,.31,0,.47,0,3.82-4,7.61-9,8.47s-9-1.55-9-5.38c0-5.21,7.16-9.74,11.7-8.14V0ZM70.51,68.64a11.26,11.26,0,0,1,4.5.08V37.13L41.58,46.72q0,18.66,0,37.3c0,5.82-6.42,10.06-11.57,11-6.39,1.1-11.58-2-11.58-7S23.65,78.18,30,77.08a13,13,0,0,1,6.49.42V32.34l43.54-9.91V73.31c.48,5.4-5,9.49-9.56,10.28-5.34.92-9.66-1.68-9.66-5.81s4.32-8.22,9.66-9.14Z"
],
trophy: [
"M89.43,45.54c3.38-1,6.39-2.61,8.84-4.65c4.02-3.35,6.5-7.9,6.5-12.87c0-2.78-0.77-5.42-2.15-7.78l0.01,0 c-0.62-1.06-1.36-2.07-2.21-3.01c-0.44,6.2-1.96,12.08-4.34,17.43C94.32,38.61,92.07,42.27,89.43,45.54L89.43,45.54L89.43,45.54z M56.4,91.21l2.83,7.93l8.42,0.24l-6.67,5.14l2.37,8.08l-6.95-4.76l-6.95,4.76l2.37-8.08l-6.67-5.14l8.42-0.24L56.4,91.21 L56.4,91.21z M20.63,80.94h71.55v41.94H20.63V80.94L20.63,80.94z M60.73,60.07v6.55h0.49v4.58l-12.42,0v-4.58l0.49,0v-6.59 c-7.57-1.17-14.49-4.59-20.14-9.59l-0.67,1.85c-7.79-0.13-14.84-2.82-19.95-7.08C3.26,40.83,0,34.75,0,28.01 c0-3.8,1.05-7.4,2.93-10.63l-0.01-0.01c1.9-3.27,4.66-6.13,8.03-8.37L14,6.97l-3.53,0V0h88.61v6.97h-2.82L99.31,9 c3.36,2.24,6.11,5.1,8.02,8.37h0.01c1.87,3.22,2.92,6.82,2.92,10.64c0,6.74-3.26,12.81-8.54,17.21 c-5.11,4.26-12.16,6.95-19.95,7.08l-0.67-1.86C75.39,55.5,68.39,58.94,60.73,60.07L60.73,60.07L60.73,60.07z M42.16,75.79h25.71 v4.58H42.16V75.79L42.16,75.79z M46.08,71.2h17.87v4.58H46.08V71.2L46.08,71.2z M11.99,40.89c2.45,2.05,5.47,3.65,8.85,4.66 c-2.64-3.27-4.89-6.93-6.66-10.9c-2.38-5.34-3.9-11.23-4.34-17.43c-0.83,0.92-1.57,1.94-2.2,3.01l-0.01,0 c-1.37,2.35-2.14,5-2.14,7.78C5.49,32.99,7.97,37.53,11.99,40.89L11.99,40.89z"
],
ring: [
"M10.94,31.01c-0.05-0.25-0.03-0.51,0.05-0.74l3.48-11.06c0.16-0.53,0.6-0.9,1.1-1l18.7-5.39c0.5-0.14,1.01-0.01,1.37,0.31 l0,0l8.52,7.54c0.15,0.11,0.27,0.26,0.37,0.42c0.23,0.39,0.26,0.86,0.1,1.28l-4.76,13.26c6.32-0.29,12.49,1,18.02,3.61 c2.1-2.01,4.44-3.8,6.99-5.31c2.73-1.61,5.72-2.92,8.93-3.84c10.19-2.94,20.61-1.47,29.2,3.28c8.6,4.75,15.39,12.79,18.33,22.99 c2.94,10.19,1.47,20.61-3.28,29.2c-4.75,8.6-12.79,15.39-22.99,18.33c-9.32,2.69-18.82,1.69-26.95-2.13 c-2.11,2.02-4.46,3.81-7.02,5.32c-2.72,1.61-5.7,2.9-8.9,3.83c-10.19,2.94-20.61,1.47-29.2-3.28c-8.6-4.75-15.39-12.79-18.33-22.99 c-2.94-10.19-1.47-20.61,3.28-29.2c3.4-6.16,8.48-11.39,14.84-14.94l-11.31-8.6C11.19,31.68,11,31.35,10.94,31.01L10.94,31.01z M6.69,31.24l-0.16,0.05C6.13,29.94,5.29,28.92,4,28.2c-1.29-0.71-2.61-0.88-3.95-0.49L0,27.55c1.34-0.39,2.37-1.23,3.09-2.52 c0.71-1.3,0.88-2.61,0.49-3.95l0.16-0.05c0.39,1.34,1.23,2.37,2.52,3.09c1.29,0.71,2.61,0.88,3.95,0.49l0.05,0.16 c-1.34,0.39-2.37,1.23-3.09,2.52C6.46,28.58,6.3,29.9,6.69,31.24L6.69,31.24L6.69,31.24z M17.03,12l-0.16,0.05 c-0.39-1.34-1.23-2.37-2.52-3.09c-1.29-0.71-2.61-0.88-3.95-0.49l-0.05-0.16c1.34-0.39,2.37-1.23,3.09-2.52 c0.71-1.3,0.88-2.61,0.49-3.95l0.16-0.05c0.39,1.34,1.23,2.37,2.52,3.09s2.61,0.88,3.95,0.49l0.05,0.16 c-1.34,0.39-2.37,1.23-3.09,2.52C16.8,9.34,16.64,10.66,17.03,12L17.03,12L17.03,12z M40.83,10.22l-0.16,0.05 c-0.39-1.34-1.23-2.37-2.52-3.09c-1.29-0.71-2.61-0.88-3.95-0.49l-0.05-0.16c1.34-0.39,2.37-1.23,3.09-2.52 c0.71-1.3,0.88-2.61,0.49-3.95L37.89,0c0.39,1.34,1.23,2.37,2.52,3.09c1.29,0.71,2.61,0.88,3.95,0.49l0.05,0.16 c-1.34,0.39-2.37,1.23-3.09,2.52C40.61,7.55,40.45,8.87,40.83,10.22L40.83,10.22L40.83,10.22z M60.66,40.68 c2.31,1.32,4.48,2.88,6.48,4.66c1.26-1,2.61-1.91,4.05-2.69c1.74-0.95,3.61-1.72,5.6-2.29c7.36-2.12,14.88-1.06,21.09,2.37 c6.21,3.43,11.12,9.24,13.24,16.6c2.12,7.36,1.06,14.88-2.37,21.09c-3.43,6.21-9.24,11.12-16.6,13.24 c-3.08,0.89-6.19,1.22-9.22,1.05c-3.14-0.17-6.2-0.89-9.05-2.07c-1.79-0.74-3.5-1.67-5.09-2.75c-1.59-1.09-3.06-2.34-4.41-3.74 c-1.52-1.59-2.86-3.37-3.97-5.32c-1.08-1.88-1.95-3.93-2.59-6.14c-0.93-3.24-1.25-6.5-1.03-9.67c0.22-3.05,0.94-6.01,2.11-8.77 c-1.59-1.55-3.38-2.87-5.31-3.94c-0.37-0.21-0.75-0.4-1.14-0.59c-1.77,3.7-2.9,7.71-3.31,11.86c-0.42,4.34-0.05,8.82,1.23,13.26 c2.71,9.41,8.99,16.83,16.94,21.22c7.95,4.39,17.58,5.75,26.99,3.04c9.41-2.71,16.83-8.99,21.22-16.94 c4.39-7.95,5.75-17.58,3.04-26.99c-2.71-9.41-8.99-16.83-16.94-21.22c-7.95-4.39-17.58-5.75-26.99-3.04 c-2.94,0.85-5.7,2.05-8.24,3.55C64.32,37.68,62.4,39.1,60.66,40.68L60.66,40.68z M69.27,47.38c4.2,4.36,7.43,9.78,9.22,16 c1.39,4.82,1.79,9.68,1.33,14.38c-0.44,4.43-1.64,8.71-3.51,12.67c2.16,0.75,4.44,1.21,6.78,1.34c2.72,0.15,5.5-0.14,8.26-0.94 c6.58-1.9,11.76-6.28,14.83-11.84c3.07-5.56,4.02-12.29,2.13-18.88c-1.9-6.58-6.28-11.76-11.84-14.84 c-5.56-3.07-12.29-4.02-18.88-2.13c-1.77,0.51-3.44,1.2-5,2.05C71.41,45.85,70.3,46.58,69.27,47.38L69.27,47.38z M73.6,89.3 c1.76-3.69,2.9-7.69,3.3-11.83c0.43-4.35,0.05-8.85-1.23-13.3c-2.71-9.41-8.99-16.83-16.94-21.22c-7.07-3.9-15.46-5.41-23.84-3.8 c-1.04,0.23-2.05,0.48-3.05,0.77c-1.34,0.39-2.67,0.84-3.96,1.34c-7.58,3.16-13.59,8.75-17.36,15.58 c-4.39,7.95-5.75,17.58-3.04,26.99c2.71,9.41,8.99,16.83,16.94,21.22c7.95,4.39,17.58,5.75,26.99,3.04 c2.93-0.85,5.68-2.05,8.22-3.54c2.08-1.23,4.01-2.65,5.76-4.23c-2.31-1.32-4.48-2.88-6.48-4.66c-1.27,1.02-2.63,1.93-4.07,2.71 c-1.72,0.93-3.58,1.7-5.57,2.27c-7.36,2.12-14.88,1.06-21.09-2.37c-6.21-3.43-11.12-9.24-13.24-16.6l0-0.01 c-2.12-7.36-1.06-14.87,2.37-21.08c3.43-6.21,9.24-11.12,16.6-13.24l0.01,0c7.36-2.12,14.87-1.06,21.08,2.37 c6.21,3.43,11.12,9.24,13.24,16.6l0,0c0.94,3.25,1.25,6.53,1.02,9.7c-0.22,3.03-0.94,5.98-2.11,8.73c1.02,0.99,2.12,1.89,3.29,2.69 C71.45,88.15,72.51,88.77,73.6,89.3L73.6,89.3z M56.78,93.63c-4.2-4.36-7.43-9.78-9.22-16c-1.38-4.8-1.79-9.65-1.34-14.34 c0.43-4.45,1.64-8.74,3.51-12.71c-4.64-1.62-9.81-1.88-14.9-0.45c-0.08,0.03-0.17,0.06-0.26,0.08c-6.52,1.92-11.66,6.28-14.71,11.8 c-3.05,5.52-4.01,12.2-2.16,18.74c0.03,0.08,0.06,0.17,0.08,0.26c1.92,6.52,6.28,11.66,11.8,14.71c5.56,3.07,12.29,4.02,18.88,2.13 c1.74-0.5,3.41-1.19,4.98-2.04C54.63,95.17,55.74,94.44,56.78,93.63L56.78,93.63z M61.09,58.68c-0.75,2.09-1.22,4.29-1.38,6.54 c-0.2,2.85,0.08,5.77,0.91,8.66c0.56,1.94,1.35,3.78,2.33,5.48c0.6,1.05,1.28,2.05,2.01,2.98c0.74-2.08,1.21-4.26,1.37-6.5 c0.21-2.81-0.06-5.7-0.87-8.56c-0.03-0.08-0.06-0.17-0.08-0.26C64.47,63.89,62.99,61.09,61.09,58.68L61.09,58.68z M27.02,38.48 c1.27-0.52,2.58-0.98,3.93-1.37c1.03-0.3,2.05-0.55,3.08-0.75c0.89-0.2,1.78-0.38,2.68-0.53l4.24-11.81l-25.38,7.32l10.11,7.68 C26.11,38.83,26.56,38.65,27.02,38.48L27.02,38.48z M14.59,28.58l25.72-7.42l-6-5.31l-17.27,4.98L14.59,28.58L14.59,28.58z"
]
};
function Blobs({ seed, shape = "blob" }) {
const blobShapes = shapePaths[shape];
const selectedBlobs = react.useMemo(
() => [
{ shape: blobShapes[Math.floor(Math.random() * blobShapes.length)], top: -Math.random() * 50, left: Math.random(), opacity: 20 },
{ shape: blobShapes[Math.floor(Math.random() * blobShapes.length)], top: Math.random() * 50, left: 50 + Math.random() * 20, opacity: 30 }
],
// Recompute only when the seed (per-card) changes.
[seed, shape]
);
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: selectedBlobs.map((blob, index) => /* @__PURE__ */ jsxRuntime.jsx(
"svg",
{
className: "rc-card__blob",
viewBox: "0 0 300 200",
xmlns: "http://www.w3.org/2000/svg",
style: { top: `${blob.top}%`, left: `${blob.left}%`, opacity: `${blob.opacity}%` },
"aria-hidden": "true",
children: /* @__PURE__ */ jsxRuntime.jsx(
"path",
{
fill: "var(--rc-blob-fill, #ffffff)",
d: blob.shape,
transform: "translate(100 100)"
}
)
},
index
)) });
}
function Card({
title,
category,
description,
from,
to,
shape,
variant = "gradient"
}) {
const seed = react.useMemo(() => Math.random(), []);
return /* @__PURE__ */ jsxRuntime.jsxs(
framerMotion.motion.div,
{
className: `rc-card rc-card--${variant}`,
style: { "--rc-from": from, "--rc-to": to },
whileTap: { scale: 0.95 },
whileHover: { scale: 1.05, boxShadow: "10px 8px 20px rgba(0, 0, 0, 0.35)" },
transition: { type: "spring", stiffness: 200 },
children: [
/* @__PURE__ */ jsxRuntime.jsx(Blobs, { seed, shape }),
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rc-card__tag", children: category }),
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "rc-card__title", children: title }),
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rc-card__progress", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rc-card__progress-fill" }) }),
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "rc-card__desc", children: description }),
/* @__PURE__ */ jsxRuntime.jsx(
framerMotion.motion.button,
{
type: "button",
className: "rc-card__button",
whileHover: { scale: 1.2 },
"aria-hidden": "true",
tabIndex: -1,
children: /* @__PURE__ */ jsxRuntime.jsx(ArrowUpRight, { size: 18 })
}
)
]
}
);
}
// src/utils/shuffle.ts
function shuffle(input) {
const result = input.slice();
for (let i = result.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[result[i], result[j]] = [result[j], result[i]];
}
return result;
}
// src/presets/gradient.ts
var palettes = [
{ from: "#4A90E2", to: "#5F9EE7" },
{ from: "#D35400", to: "#E67E22" },
{ from: "#8E44AD", to: "#9B59B6" },
{ from: "#27AE60", to: "#2ECC71" },
{ from: "#F39C12", to: "#F1C40F" },
{ from: "#E74C3C", to: "#EC7063" },
{ from: "#9B59B6", to: "#8E44AD" },
{ from: "#16A085", to: "#1ABC9C" },
{ from: "#00C9A7", to: "#02AABD" },
{ from: "#FF4E50", to: "#FC913A" },
{ from: "#6A0572", to: "#AB83A1" },
{ from: "#D946EF", to: "#F472B6" },
{ from: "#8E2DE2", to: "#4A00E0" },
{ from: "#FFD700", to: "#FFA500" }
];
function gradientCss({ from, to }) {
return `linear-gradient(135deg, ${from}, ${to})`;
}
function getPalettes(randomBackground) {
return randomBackground ? shuffle(palettes) : palettes.slice();
}
palettes.map(gradientCss);
function CardSlider({
slides,
shape,
randomBackground = false,
variant = "gradient"
}) {
const sliderRef = react.useRef(null);
const scrollByHalf = (direction) => {
const el = sliderRef.current;
if (el) {
el.scrollBy({ left: direction * el.clientWidth / 2, behavior: "smooth" });
}
};
const palettes2 = getPalettes(randomBackground);
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rc-cardslider", children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rc-cardslider__overlay rc-cardslider__overlay--left" }),
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rc-cardslider__overlay rc-cardslider__overlay--right" }),
/* @__PURE__ */ jsxRuntime.jsx(
"button",
{
type: "button",
className: "rc-cardslider__arrow rc-cardslider__arrow--left",
"aria-label": "Scroll left",
onClick: () => scrollByHalf(-1),
children: /* @__PURE__ */ jsxRuntime.jsx(ChevronLeft, {})
}
),
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: sliderRef, className: "rc-cardslider__track", children: slides.map((slide, index) => {
const palette = palettes2[index % palettes2.length];
const card = /* @__PURE__ */ jsxRuntime.jsx(
Card,
{
title: slide.title,
category: slide.category,
description: slide.description,
from: palette.from,
to: palette.to,
shape,
variant
}
);
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rc-cardslider__item", children: slide.link ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: slide.link, target: "_blank", rel: "noreferrer", children: card }) : card }, slide.title + index);
}) }),
/* @__PURE__ */ jsxRuntime.jsx(
"button",
{
type: "button",
className: "rc-cardslider__arrow rc-cardslider__arrow--right",
"aria-label": "Scroll right",
onClick: () => scrollByHalf(1),
children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight, {})
}
)
] });
}
function ImageSlider({
slides,
loop = true,
autoplay = false,
autoplayInterval,
height = 460,
showArrows = true,
showDots = true,
className,
label = "Image carousel"
}) {
return /* @__PURE__ */ jsxRuntime.jsxs(
Carousel3,
{
slidesCount: slides.length,
loop,
autoplay,
autoplayInterval,
label,
className: cx("rc-image", className),
style: {
"--rc-image-height": typeof height === "number" ? `${height}px` : height
},
children: [
showArrows && /* @__PURE__ */ jsxRuntime.jsx(Carousel3.Button, { dir: "prev" }),
/* @__PURE__ */ jsxRuntime.jsx(Carousel3.Track, { children: slides.map((slide, i) => {
const inner = /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: "rc-image__slide",
style: { backgroundImage: `url(${slide.src})` },
role: "img",
"aria-label": slide.alt,
children: slide.caption != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rc-image__caption", children: slide.caption })
}
);
return /* @__PURE__ */ jsxRuntime.jsx(Carousel3.Slide, { index: i, children: slide.href ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "rc-image__link", href: slide.href, target: "_blank", rel: "noreferrer", children: inner }) : inner }, i);
}) }),
showArrows && /* @__PURE__ */ jsxRuntime.jsx(Carousel3.Button, { dir: "next" }),
showDots && /* @__PURE__ */ jsxRuntime.jsx(Carousel3.Dots, {})
]
}
);
}
function SlicerSlider({
slides,
loop = true,
autoplay = false,
autoplayInterval,
height = 460,
slices = 6,
showArrows = true,
showDots = true,
className,
label = "Slicer carousel"
}) {
const api = useCarousel({ slidesCount: slides.length, loop, autoplay, autoplayInterval });
const strips = Array.from({ length: slices }, (_, k) => k);
return /* @__PURE__ */ jsxRuntime.jsx(CarouselContext.Provider, { value: api, children: /* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
ref: api.rootRef,
className: cx("rc-slicer", className),
role: "region",
"aria-roledescription": "carousel",
"aria-label": label,
tabIndex: 0,
style: { "--rc-image-height": `${height}px`, "--rc-slices": slices },
children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: api.trackRef, className: "rc-slicer__viewport", children: slides.map((slide, i) => {
const active = i === api.activeIndex;
return /* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
className: "rc-slicer__slide",
"data-active": active || void 0,
"aria-hidden": !active || void 0,
role: "group",
"aria-roledescription": "slide",
"aria-label": `${i + 1} of ${slides.length}`,
children: [
strips.map((k) => /* @__PURE__ */ jsxRuntime.jsx(
"span",
{
className: "rc-slicer__strip",
style: { "--k": k, backgroundImage: `url(${slide.src})` }
},
k
)),
slide.caption != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rc-slicer__caption", children: slide.caption })
]
},
i
);
}) }),
showArrows && /* @__PURE__ */ jsxRuntime.jsx(Button, { dir: "prev" }),
showArrows && /* @__PURE__ */ jsxRuntime.jsx(Button, { dir: "next" }),
showDots && /* @__PURE__ */ jsxRuntime.jsx(Dots, {})
]
}
) });
}
function CubeSlider({
slides,
loop = true,
autoplay = false,
autoplayInterval,
height = 460,
vertical = false,
shadow = true,
showArrows = true,
showDots = true,
className,
label = "Cube carousel"
}) {
const api = useCarousel({
slidesCount: slides.length,
loop,
autoplay,
autoplayInterval,
orientation: vertical ? "vertical" : "horizontal"
});
const count = slides.length;
const [depth, setDepth] = react.useState(0);
react.useEffect(() => {
const el = api.trackRef.current;
if (!el) return;
const measure = () => setDepth((vertical ? el.clientHeight : el.clientWidth) / 2);
measure();
if (typeof ResizeObserver === "undefined") return;
const observer = new ResizeObserver(measure);
observer.observe(el);
return () => observer.disconnect();
}, [api.trackRef, vertical]);
const offsetOf = (i) => {
let off = i - api.activeIndex;
if (loop && count > 1) {
if (off > count / 2) off -= count;
else if (off < -count / 2) off += count;
}
return off;
};
return /* @__PURE__ */ jsxRuntime.jsx(CarouselContext.Provider, { value: api, children: /* @__PURE__ */ jsxRuntime.jsxs(
"div",
{
ref: api.rootRef,
className: cx("rc-cube", className),
role: "region",
"aria-roledescription": "carousel",
"aria-label": label,
tabIndex: 0,
"data-orientation": vertical ? "vertical" : "horizontal",
"data-shadow": shadow || void 0,
style: {
"--rc-image-height": `${height}px`,
"--rc-cube-depth": `${depth}px`
},
children: [
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: api.trackRef, className: "rc-cube__viewport", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rc-cube__cage", children: slides.map((slide, i) => {
const off = offsetOf(i);
const active = off === 0;
return /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
className: "rc-cube__face",
"data-active": active || void 0,
"aria-hidden": !active || void 0,
role: "group",
"aria-roledescription": "slide",
"aria-label": `${i + 1} of ${count}`,
style: {
"--off": off,
// Only the active face and its two neighbours form the cube.
visibility: Math.abs(off) <= 1 ? void 0 : "hidden",
backgroundImage: `url(${slide.src})`
},
children: slide.caption != null && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rc-cube__caption", children: slide.caption })
},
i
);
}) }) }),
shadow && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rc-cube__shadow", "aria-hidden": "true" }),
showArrows && /* @__PURE__ */ jsxRuntime.jsx(Button, { dir: "prev" }),
showArrows && /* @__PURE__ */ jsxRuntime.jsx(Button, { dir: "next" }),
showDots && /* @__PURE__ */ jsxRuntime.jsx(Dots, {})
]
}
) });
}
exports.Button = Button;
exports.CardSlider = CardSlider;
exports.Carousel = Carousel3;
exports.CubeSlider = CubeSlider;
exports.Dots = Dots;
exports.ImageSlider = ImageSlider;
exports.PlayPause = PlayPause;
exports.SlicerSlider = SlicerSlider;
exports.Slide = Slide;
exports.Track = Track;
exports.default = CardSlider;
exports.useCarousel = useCarousel;
//# sourceMappingURL=index.cjs.map
//# sourceMappingURL=index.cjs.map