UNPKG

@axeptio/design-system

Version:
307 lines (266 loc) 7.1 kB
/* eslint-disable indent */ import { useContext, useEffect, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import styled, { ThemeContext } from 'styled-components'; import { hrefResolver } from '../../../helpers'; import Icon from '../../Icon'; const Root = styled.div` position: relative; display: flex; `; const Label = styled.span` display: none; margin-left: 8px; position: relative; font-weight: 700; &::after { content: ''; position: absolute; left: 0; bottom: -2px; width: 0; height: 1.5px; background-color: ${props => props.theme.colors.secondary}; transition: width 0.3s; } ${props => props.darkTheme && ` color: #ffffff; &::after { background-color: #ffffff; } `}; @media (min-width: ${props => props.theme.breakpoints.small}px) { display: inline; } `; const LabelWrapper = styled.button` display: flex; align-items: center; justify-content: center; background: none; cursor: pointer; padding: 20px 0; border-radius: 2px; min-width: clamp(38px, 10vw, 44px); &:hover { span:not(.svg-icon)::after { width: 100%; } } `; const Dropdown = styled.div` z-index: 1; position: fixed; left: 0; right: 0; bottom: 0; transition: opacity 0.25s ease, transform 0.3s; ${props => !props.isOpen && 'height: 0;'}; @media (min-width: ${props => props.theme.breakpoints.large}px) { position: absolute; right: auto; bottom: auto; top: 100%; transform-origin: 0 0; ${props => ` left: calc(-${props.rightSpace}px - 10px); `} ${props => !props.isOpen && ` opacity: 0; transform: rotateX(-15deg); visibility: collapse; `}; } `; const LanguageLabel = styled.li` padding: 4px 20px; font-size: 12px; font-weight: 700; text-transform: uppercase; color: ${props => props.theme.colors.grey.v400}; display: inline-block; @media (min-width: ${props => props.theme.breakpoints.large}px) { display: none; } `; const DropdownMenu = styled.div` position: relative; min-width: 200px; min-height: min(250px, 100vh); max-height: 70vh; background: #ffffff; box-shadow: 0 5.5px 2.2px rgba(0, 0, 0, 0.028), 0 18.3px 13.9px rgba(0, 0, 0, 0.042), 0 82px 80px rgba(0, 0, 0, 0.07); border-radius: 0; overflow-y: auto; transform: translateY(100%); transition: all 0.25s ease 0s; > ul { display: block; list-style: none; padding: 0; margin: 20px 4px; } ${props => props.isOpen && ` transform: translateY(0); `}; @media (min-width: ${props => props.theme.breakpoints.large}px) { min-height: auto; border-radius: 8px; transform: none; > ul { margin: 6px 0; } &:hover li { a { opacity: 0.4; } &:hover { a { opacity: 1; } .svg-icon { opacity: 1; transform: translateX(0); } } } } `; const LanguageRow = styled.li` > span, a { display: flex; align-items: center; justify-content: space-between; column-gap: 10px; padding: 10px 30px; font-size: 16px; font-weight: 700; text-decoration: none; > span { display: flex; align-items: center; justify-content: space-between; column-gap: 10px; &:first-child { flex: 1; } } @media (min-width: ${props => props.theme.breakpoints.large}px) { > span { column-gap: 35px; } } } a { color: ${props => props.theme.colors.secondary}; transition: all 0.25s cubic-bezier(0.5, 0, 0, 1); .svg-icon { opacity: 0; transform: translateX(-10px); transition: all 0.25s cubic-bezier(0.5, 0, 0, 1); } } > span { color: ${props => props.theme.colors.primaryPalette.v500}; } `; const Overlay = styled.div` position: fixed; inset: 0; background: rgba(0, 0, 0, 0.2); transition: all 0.25s ease 0s; opacity: 0; pointer-events: none; ${props => props.isOpen && ` opacity: 1; pointer-events: auto; `}; @media (min-width: ${props => props.theme.breakpoints.large}px) { display: none; } `; const LanguageDropdown = ({ darkTheme, currentLang, languages, altLangs }) => { const dropdownRef = useRef(); const [dropdownOpen, setDropdownOpen] = useState(false); const themeContext = useContext(ThemeContext); const [dropdownRightSpace, setDropdownRightSpace] = useState(0); const toggleDropdown = newState => { if (newState) { updateDropdownPos(); } setDropdownOpen(newState); }; const updateDropdownPos = () => { const parentBounds = dropdownRef.current.parentElement.getBoundingClientRect(); const bounds = dropdownRef.current.getBoundingClientRect(); const overflow = Math.ceil(parentBounds.x + bounds.width - document.body.clientWidth); setDropdownRightSpace(Math.max(overflow, 0)); }; useEffect(() => { updateDropdownPos(); }, [dropdownRef]); return ( <Root onMouseLeave={() => toggleDropdown(false)} onBlur={e => { if (e.relatedTarget && !e.currentTarget.contains(e.relatedTarget)) { toggleDropdown(false); } }} > <LabelWrapper onMouseEnter={() => toggleDropdown(true)} onFocus={() => toggleDropdown(true)}> <Icon name="Planet" iconSize={16} strokeColor={darkTheme ? '#ffffff' : '#212121'} /> <Label darkTheme={darkTheme} role="lang"> {currentLang.toUpperCase()} </Label> </LabelWrapper> <Dropdown ref={dropdownRef} isOpen={dropdownOpen} rightSpace={dropdownRightSpace}> <DropdownMenu isOpen={dropdownOpen}> <ul> <LanguageLabel>{languages[currentLang].heading}</LanguageLabel> {Object.values(languages).map(language => ( <LanguageRow key={language.locale}> {language.locale === currentLang ? ( <span onClick={() => toggleDropdown(!dropdownOpen)}> <span>{language.label}</span> <Icon noStroke name="Check" iconSize={20} fillColor={themeContext.colors.primaryPalette.v500} /> </span> ) : ( <a href={hrefResolver(altLangs.find(x => x && x.lang == language.locale))} tabIndex={dropdownOpen ? 0 : -1}> <span onClick={() => toggleDropdown(!dropdownOpen)}> {language.label} <Icon name="ArrowNext" iconSize={20} strokeColor={themeContext.colors.secondary} /> </span> </a> )} </LanguageRow> ))} </ul> </DropdownMenu> </Dropdown> <Overlay isOpen={dropdownOpen} onClick={() => toggleDropdown(false)} /> </Root> ); }; LanguageDropdown.propTypes = { darkTheme: PropTypes.bool, currentLang: PropTypes.string, languages: PropTypes.array, altLangs: PropTypes.array }; export default LanguageDropdown;