UNPKG

@wq/material-web

Version:

Web bindings for @wq/material

190 lines (189 loc) 6.39 kB
import React, { useMemo } from "react"; import { Field, getIn } from "formik"; import { Select as FMuiSelect } from "formik-mui"; import { MenuItem, Checkbox, ListItemText, ListSubheader } from "@mui/material"; import PropTypes from "prop-types"; import { useFormikContext } from "formik"; function ContextCheckbox({ value, field }) { const { values } = useFormikContext(); const checked = (getIn(values, field) || []).some((val) => val === value); return /*#__PURE__*/ React.createElement(Checkbox, { checked: checked, }); } ContextCheckbox.propTypes = { value: PropTypes.string, field: PropTypes.string, }; export default function Select({ choices, label, required, native, placeholder, renderValue, InputLabelProps, ...rest }) { const { name: fieldName, type, hint } = rest, { errors, touched } = useFormikContext(), showError = !!getIn(errors, fieldName) && getIn(touched, fieldName), multiple = type === "select"; if (multiple && !renderValue) { renderValue = (sel) => sel.map(getLabel).join(", "); } if (placeholder && !renderValue) { renderValue = (sel) => getLabel(sel) || sel || placeholder; } const getLabel = useMemo(() => { const labels = {}; choices.forEach(({ name, label }) => { labels[name] = label; }); return (name) => labels[name]; }, [choices]); const choiceGroups = useMemo(() => { const choiceGroups = {}; choices.forEach((choice) => { const group = choice.group || ""; if (!choiceGroups[group]) { choiceGroups[group] = []; } choiceGroups[group].push(choice); }); return choiceGroups; }, [choices]); const Option = useMemo( () => native ? ({ value, children }) => /*#__PURE__*/ React.createElement( "option", { value: value, }, children ) : ({ children, ...rest }) => /*#__PURE__*/ React.createElement( MenuItem, { ...rest, }, multiple && /*#__PURE__*/ React.createElement( ContextCheckbox, { value: rest["data-value"], field: fieldName, } ), /*#__PURE__*/ React.createElement(ListItemText, { primary: children, "data-value": rest["data-value"], primaryTypographyProps: { "data-value": rest["data-value"], }, }) ), [native, multiple, fieldName] ); const renderChoices = (choices) => choices.map(({ name, label }) => /*#__PURE__*/ React.createElement( Option, { key: name, value: name, }, label ) ); const renderGroups = native ? (choiceGroups) => Object.entries(choiceGroups).map(([group, choices]) => group ? /*#__PURE__*/ React.createElement( "optgroup", { key: group, label: group, }, renderChoices(choices) ) : /*#__PURE__*/ React.createElement( React.Fragment, null, renderChoices(choices) ) ) : (choiceGroups) => { const flattened = []; Object.entries(choiceGroups).forEach(([group, choices]) => { if (group) { flattened.push( /*#__PURE__*/ React.createElement( ListSubheader, { style: { backgroundColor: "white", }, }, group ) ); } flattened.push(...renderChoices(choices)); }); return flattened; }; return /*#__PURE__*/ React.createElement( Field, { component: FMuiSelect, formControl: { fullWidth: true, margin: "dense", }, inputLabel: { required, error: showError, ...InputLabelProps, }, formHelperText: { children: hint, }, multiple: multiple, required: required, native: native, label: label, renderValue: renderValue, displayEmpty: !!placeholder, ...(InputLabelProps && InputLabelProps.shrink ? { notched: true, } : {}), ...rest, }, !multiple && /*#__PURE__*/ React.createElement( Option, { value: "", disabled: !!required, }, required ? "Select one..." : "(No Selection)" ), renderGroups(choiceGroups) ); } Select.propTypes = { choices: PropTypes.arrayOf(PropTypes.object), label: PropTypes.string, placeholder: PropTypes.string, required: PropTypes.bool, native: PropTypes.bool, renderValue: PropTypes.func, InputLabelProps: PropTypes.object, };