Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React, { createRef, useState, useEffect, useCallback } from "react";
- import PropTypes from "prop-types";
- import styled, { css } from "styled-components";
- import { MdChevronRight } from "react-icons/md";
- const InlineBlockContainer = styled.div`
- width: ${({ width }) => width || "100%"};
- display: inline-block;
- `;
- const ClickHandler = ({ children, handleChange, width }) => {
- const wrapperRef = createRef();
- const [isVisible, setVisible] = useState(false);
- const handleClickOutside = useCallback(
- ({ target }) => {
- if (isVisible && wrapperRef && !wrapperRef.current.contains(target)) {
- setVisible(false);
- }
- },
- [isVisible, wrapperRef]
- );
- const handleSelectClick = () => {
- setVisible(visible => !visible);
- };
- const handleOptionSelect = e => {
- setVisible(false);
- handleChange(e);
- };
- useEffect(
- () => {
- document.addEventListener("mousedown", handleClickOutside);
- return () => {
- document.removeEventListener("mousedown", handleClickOutside);
- };
- },
- [handleClickOutside]
- );
- return (
- <InlineBlockContainer width={width} ref={wrapperRef}>
- {children({
- isVisible,
- handleSelectClick,
- handleOptionSelect
- })}
- </InlineBlockContainer>
- );
- };
- ClickHandler.propTypes = {
- handleChange: PropTypes.func.isRequired,
- children: PropTypes.func.isRequired,
- width: PropTypes.string
- };
- const focused = ({ isVisible }) =>
- isVisible
- ? `outline: -webkit-focus-ring-color auto 1px;
- box-shadow: 0 0 0 1px #2684ff;
- `
- : null;
- const SelectionContainer = styled.div`
- cursor: pointer;
- display: inline-block;
- height: 40px;
- width: 100%;
- background-color: white;
- display: flex;
- min-height: 38px;
- box-sizing: border-box;
- border-radius: 4px;
- border: 1px solid #bdbdbd;
- transition: all 100ms ease 0s;
- ${props => focused(props)};
- `;
- const StyledSelectText = ({ className, children, handleSelectClick }) => (
- <div className={className} onClick={handleSelectClick}>
- {children}
- </div>
- );
- StyledSelectText.propTypes = {
- className: PropTypes.string.isRequired,
- children: PropTypes.node.isRequired,
- handleSelectClick: PropTypes.func.isRequired
- };
- const SelectText = styled(StyledSelectText)`
- -webkit-box-align: center;
- align-items: center;
- display: flex;
- flex-wrap: wrap;
- position: relative;
- box-sizing: border-box;
- flex: 1 1 0%;
- overflow: hidden;
- `;
- const DisplayOption = styled.div`
- color: #bbb;
- font-size: 16px;
- font-family: "Arial", sans-serif;
- -webkit-box-align: center;
- align-items: center;
- display: flex;
- flex-wrap: wrap;
- position: relative;
- box-sizing: border-box;
- flex: 1 1 0%;
- padding: 2px 8px;
- overflow: hidden;
- ${({ value }) => (value ? "color: #484848 !important;" : null)};
- `;
- const StyledChevron = ({ className }) => (
- <div className={className}>
- <MdChevronRight />
- </div>
- );
- StyledChevron.propTypes = {
- className: PropTypes.string.isRequired
- };
- const Chevron = styled(StyledChevron)`
- display: flex;
- box-sizing: border-box;
- padding: 10px;
- svg {
- vertical-align: middle;
- transform: ${({ isVisible }) =>
- isVisible ? "rotate(90deg)" : "rotate(270deg)"};
- transition: 0.2s ease-in-out;
- transition-property: transform;
- }
- `;
- const Selection = ({
- handleSelectClick,
- isVisible,
- placeholder,
- value,
- width
- }) => (
- <SelectionContainer isVisible={isVisible} width={width}>
- <SelectText handleSelectClick={handleSelectClick}>
- <DisplayOption value={value}>
- {!value ? placeholder : value}
- </DisplayOption>
- <ChevronIcon isVisible={isVisible} />
- </SelectText>
- </SelectionContainer>
- );
- Selection.propTypes = {
- handleSelectClick: PropTypes.func.isRequired,
- isVisible: PropTypes.bool.isRequired,
- value: PropTypes.string,
- placeholder: PropTypes.string,
- width: PropTypes.string
- };
- const SelectBox = styled.div`
- position: relative;
- box-sizing: border-box;
- width: 100%;
- `;
- const DropContainer = styled.div`
- position: absolute;
- width: 100%;
- z-index: 1000;
- top: 100%;
- background-color: hsl(0, 0%, 100%);
- border-radius: 4px;
- box-shadow: 0 0 0 1px hsla(0, 0%, 0%, 0.1), 0 4px 11px hsla(0, 0%, 0%, 0.1);
- margin-top: 1px;
- box-sizing: border-box;
- `;
- const OptionsContainer = styled.div`
- top: 100%;
- background-color: hsl(0, 0%, 100%);
- border-radius: 4px;
- box-shadow: 0 0 0 1px hsla(0, 0%, 0%, 0.1), 0 4px 11px hsla(0, 0%, 0%, 0.1);
- position: absolute;
- width: 100%;
- z-index: 1000000;
- box-sizing: border-box;
- `;
- const StyledOption = ({ className, onClick, name, value }) => (
- <div
- className={className}
- data-name={name}
- data-value={value}
- onClick={onClick}
- >
- {value}
- </div>
- );
- StyledOption.propTypes = {
- className: PropTypes.string.isRequired,
- onClick: PropTypes.func.isRequired,
- name: PropTypes.string.isRequired,
- value: PropTypes.string.isRequired
- };
- const Option = styled(StyledOption)`
- cursor: pointer;
- color: #282c34;
- display: block;
- word-break: break-all;
- font-size: 16px;
- padding: 8px 12px;
- width: 100%;
- font-weight: normal;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
- box-sizing: border-box;
- border-bottom: 1px dotted pink;
- text-align: left;
- ${({ selected, value }) =>
- selected === value ? `background-color: #dedede; color: #0f7ae5;` : null};
- &:hover {
- color: #0f7ae5 !important;
- ${({ selected, value }) =>
- selected !== value ? "background: #eee !important;" : null};
- }
- `;
- const Options = ({
- handleOptionSelect,
- isVisible,
- name,
- selected,
- selectOptions
- }) => {
- const onOptionSelect = ({
- target: {
- dataset: { name, value }
- }
- }) => {
- const e = {
- target: {
- name,
- value
- }
- };
- handleOptionSelect(e);
- };
- return (
- isVisible && (
- <DropContainer>
- <OptionsContainer>
- {selectOptions.map((value, key) => (
- <Option
- key={key}
- name={name}
- value={value}
- onClick={onOptionSelect}
- selected={selected}
- />
- ))}
- </OptionsContainer>
- </DropContainer>
- )
- );
- };
- Options.propTypes = {
- handleOptionSelect: PropTypes.func.isRequired,
- isVisible: PropTypes.bool.isRequired,
- name: PropTypes.string.isRequired,
- selected: PropTypes.string,
- selectOptions: PropTypes.arrayOf(PropTypes.string.isRequired)
- };
- const Select = ({ name, selectOptions, value, ...props }) => (
- <ClickHandler selectOptions={selectOptions} {...props}>
- {handlers => (
- <SelectContainer>
- <SelectBox>
- <Selection {...handlers} {...props} value={value} />
- <Options
- {...handlers}
- name={name}
- selectOptions={selectOptions}
- selected={value}
- />
- </SelectBox>
- </SelectContainer>
- )}
- </ClickHandler>
- );
- Select.propTypes = {
- name: PropTypes.string.isRequired,
- placeholder: PropTypes.string,
- selectOptions: PropTypes.arrayOf(PropTypes.string.isRequired),
- value: PropTypes.string
- };
- export default Select;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement