/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ import * as React from 'react' import { StyledWrapper, StyledSelect, StyledOptions, StyledOption, StyledSelectWrapper, StyledSelectText, StyledSelectArrow, StyledOptionCheck, StyledOptionText, StyledOptionsOverlay, StyledOptionsModal, StyledSelectTitle, StyledModalContent, StyledRadioOptions } from './style' import { Radio } from '../../' import { CheckIcon, CaratDownIcon } from '../../icons' export type Type = 'dark' | 'light' export interface Props { children: React.ReactNode id?: string title?: string disabled?: boolean floating?: boolean showAllContents?: boolean value?: string onChange?: (value: string, child: React.ReactNode) => void type?: Type } interface State { value: string | number selected: React.ReactNode show: boolean radioShown: boolean } interface RadioOptionsObj { [key: string]: boolean } /* TODO - add tab option movement - add enter key confirm - add autoFocus - add empty first choice? */ export default class Select extends React.PureComponent { constructor (props: Props) { super(props) const obj = this.getDefaultValue(props) this.state = { value: obj.value, selected: obj.selected, show: false, radioShown: false } } static defaultProps = { type: 'light' } componentDidUpdate (prevProps: Props) { if (prevProps.value !== this.props.value) { const obj = this.getDefaultValue(this.props) this.setState({ value: obj.value, selected: obj.selected, show: false }) } } getDefaultValue (props: Props) { const children = React.Children.toArray(props.children) let child: any const value: string = (props.value || '').toString() child = children.find((child: any) => child.props['data-value'] === value) if (child === undefined && children) { child = children.find((child: any) => child && child.props['data-value'] !== undefined) } if (!child || !child.props) { return { value: '', selected: null } } return { value: child.props['data-value'], selected: child.props.children } } getRadioOptions = (value: string | undefined, children: React.ReactNode) => { const currentValue = this.state.value let options: RadioOptionsObj = {} React.Children.map(children, (child: any, i: number) => { if (child.props['data-value'] === undefined) { return null } const value = child.props['data-value'] const selected = value === currentValue return options[value] = selected }) return options } onRadioOptionClick = (key: string, selected: boolean, child: React.ReactNode, all: {[key: string]: boolean}) => { this.setState({ value: key, selected: child, radioShown: false }) if (this.props.onChange) { this.props.onChange(key, child) } } onOverlayClick = (event: any) => { if (event.target.hasAttribute('data-overlay')) { this.setState({ radioShown: false }) } } styledModalOverlay = (value: string | undefined, children: React.ReactNode) => { if (!this.state.radioShown) { return null } return ( { this.props.title ? {this.props.title} : null } {this.props.children} ) } generateOptions = (value: string | undefined, children: React.ReactNode, showAllContents: boolean | undefined) => { const self = this return React.Children.map(children, (child: any, i: number) => { if (child.props['data-value'] === undefined) { return null } const element = child.props.children const value = child.props['data-value'] const selected = value === self.state.value return ( {selected ? : null} {element} ) }) } onOptionClick = (value: string, child: React.ReactNode, element: React.ReactNode) => { this.setState({ value: value, selected: element, show: false }) if (this.props.onChange) { this.props.onChange(value, child) } } isTouchscreen = () => { return 'ontouchstart' in window } onSelectClick = () => { if (!this.isTouchscreen()) { this.setState({ show: !this.state.show }) return } this.setState({ radioShown: true }) } onBlur = () => { this.setState({ show: false }) } render () { const { id, children, disabled, value, type, floating, showAllContents } = this.props const num = React.Children.count(children) let data = null if (num > 0) { data = this.generateOptions(value, children, showAllContents) } return ( { num > 0 ? {this.state.selected} {data} {this.styledModalOverlay(value, children)} : null } ) } }