core/components/Form/Selects.tsx

74 lines
2.6 KiB
TypeScript

import { ComponentType } from 'react'
import ReactSelect, { components, GroupTypeBase, MultiValueProps, OptionTypeBase } from 'react-select'
import {
SortableContainer,
SortableElement,
SortableHandle,
} from 'react-sortable-hoc'
function arrayMove(array, from, to) {
array = array.slice()
array.splice(to < 0 ? array.length + to : to, 0, array.splice(from, 1)[0])
return array
}
const SortableMultiValue = SortableElement(props => {
// this prevents the menu from being opened/closed when the user clicks
// on a value to begin dragging it. ideally, detecting a click (instead of
// a drag) would still focus the control and toggle the menu, but that
// requires some magic with refs that are out of scope for this example
const onMouseDown = e => {
e.preventDefault()
e.stopPropagation()
}
const innerProps = { ...props.innerProps, onMouseDown }
return <components.MultiValue {...props} innerProps={innerProps} />
})
const SortableMultiValueLabel = SortableHandle(props => (
<components.MultiValueLabel {...props} />
))
const SortableSelect = SortableContainer(ReactSelect)
const Select: React.FC<SelectProps> = ({ placeholder, options, values, setValues, handleChange, handleTouch }) => {
const onSortEnd = ({ oldIndex, newIndex }) => {
const newValue = arrayMove(values, oldIndex, newIndex)
setValues(newValue)
}
return <SortableSelect useDragHandle axis='xy' distance={4} getHelperDimensions={({ node }) => node.getBoundingClientRect()} onSortEnd={onSortEnd}
// select props
styles={{
control: (provided) => {
return { ...provided, border: 'none' }
},
option: (provided) => {
return { ...provided, cursor: 'pointer', ':hover': {
opacity: '0.7'
} }
}
}} isMulti className='border border-grey-light dark:border-transparent rounded' classNamePrefix='outline-none text-black dark:bg-very-black dark:text-white cursor-pointer ' placeholder={placeholder || '선택해주세요.'} options={options} onChange={handleChange} onBlur={handleTouch} noOptionsMessage={() => '검색 결과가 없습니다.'}
value={values.map(el => ({ label: el, value: el}))}
components={{
MultiValue: SortableMultiValue as ComponentType<MultiValueProps<OptionTypeBase, GroupTypeBase<{ label: string, value: string}>>>,
MultiValueLabel: SortableMultiValueLabel,
}}
closeMenuOnSelect={false}
/>
}
interface SelectProps {
placeholder?: string
options: Option[]
values: string[]
setValues: (value: string[]) => void
handleChange: (value: Option[]) => void
handleTouch: () => void
}
interface Option {
value: string
label: string
}
export default Select