@coin-voyage/paykit
Version:
Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.
108 lines (106 loc) • 3.86 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { motion } from "framer-motion";
import { useEffect } from "react";
import { keyframes } from "styled-components";
import styled from "../../../styles/styled";
import usePayContext from "../../contexts/pay";
import { ScrollArea } from "../ScrollArea";
import { OptionButton, OptionIcon, OptionLabel, OptionSubtitle, OptionTitle, OptionsContainer } from "./styles";
export default function OptionsList({ options, isLoading, requiredSkeletons }) {
const { triggerResize } = usePayContext();
const optionsLength = options.length;
useEffect(() => {
if (optionsLength > 0) {
triggerResize();
}
}, [optionsLength, triggerResize]);
if (isLoading) {
const skeletonCount = requiredSkeletons ? Math.max(requiredSkeletons - optionsLength, 0) : 0;
return (_jsxs(OptionsContainer, { "$totalResults": options.length, children: [options.map((option) => (_jsx(OptionItem, { option: option }, option.id))), isLoading && Array.from({ length: skeletonCount }).map((_, index) => _jsx(SkeletonOptionItem, {}, index))] }));
}
return (_jsx(ScrollArea, { mobileDirection: "vertical", height: 300, children: _jsx(OptionsContainer, { "$totalResults": options.length, children: options.map((option) => (_jsx(OptionItem, { option: option }, option.id))) }) }));
}
const SkeletonOptionItem = () => {
return (_jsxs(OptionButton, { type: "button", children: [_jsx(SkeletonIcon, {}), _jsx(SkeletonLabel, {})] }));
};
const pulse = keyframes `
0% {
opacity: 0.6;
}
50% {
opacity: 1;
}
100% {
opacity: 0.6;
}
`;
const SkeletonIcon = styled.div `
position: absolute;
right: 20px;
width: 32px;
height: 32px;
border-radius: 22.5%;
background-color: rgba(0, 0, 0, 0.1);
animation: ${pulse} 1.5s ease-in-out infinite;
`;
const SkeletonLabel = styled.div `
width: 100px;
height: 16px;
border-radius: 8px;
background-color: rgba(0, 0, 0, 0.1);
animation: ${pulse} 1.5s ease-in-out infinite;
`;
const OptionItem = ({ option }) => {
const hydratedIcons = option.icons.map((icon) => {
if (typeof icon === "string") {
return _jsx("img", { src: icon, alt: "" }, icon);
}
return icon;
});
const iconContent = (() => {
if (hydratedIcons.length === 1) {
return _jsx(OptionIcon, { "data-shape": option.iconShape, children: hydratedIcons[0] });
}
return (_jsx(IconStackContainer, { children: hydratedIcons.map((icon, index) => (_jsx(IconStackItem, { "data-shape": option.iconShape, "$marginRight": index !== hydratedIcons.length - 1 ? -12 : 0, "$zIndex": hydratedIcons.length - index, children: icon }, index))) }));
})();
return (_jsxs(OptionButton, { type: "button", onClick: option.onClick, disabled: option.disabled, children: [iconContent, _jsxs(OptionLabel, { children: [_jsx(OptionTitle, { children: option.title }), option.subtitle && _jsx(OptionSubtitle, { children: option.subtitle })] })] }));
};
const IconStackContainer = styled(motion.div) `
position: absolute;
right: 20px;
display: flex;
align-items: center;
justify-content: center;
`;
const IconStackItem = styled(motion.div) `
display: block;
overflow: hidden;
user-select: none;
display: flex;
align-items: center;
justify-content: center;
margin-right: ${(props) => props.$marginRight || 0}px;
z-index: ${(props) => props.$zIndex || 2};
width: 32px;
height: 32px;
overflow: hidden;
svg,
img {
display: block;
position: relative;
pointer-events: none;
overflow: hidden;
width: 100%;
height: 100%;
}
border-radius: 22.5%;
&[data-shape="squircle"] {
border-radius: 22.5%;
}
&[data-shape="circle"] {
border-radius: 100%;
}
&[data-shape="square"] {
border-radius: 0;
}
`;