UNPKG

orcs-design-system

Version:
644 lines (642 loc) 23 kB
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; const _excluded = ["selectType"]; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import React, { forwardRef } from "react"; import PropTypes from "prop-types"; import styled, { ThemeProvider, useTheme } from "styled-components"; import { default as ReactSelect, components } from "react-select"; import AsyncSelect from "react-select/async"; import CreatableSelect from "react-select/creatable"; import { space, layout, compose } from "styled-system"; import { css } from "@styled-system/css"; import shouldForwardProp from "@styled-system/should-forward-prop"; import { themeGet } from "@styled-system/theme-get"; import { Small } from "../Typography"; import useInputFocus from "../../hooks/useInputFocus"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; const SelectStyles = compose(space, layout); const Wrapper = /*#__PURE__*/styled("div").withConfig({ shouldForwardProp, displayName: "Wrapper", componentId: "sc-bfi43f-0" }).attrs(props => ({ "data-testid": props["data-testid"] ? props["data-testid"] : null }))(css({ display: "inline-block", width: "100%" }), SelectStyles); const Label = /*#__PURE__*/styled("label").withConfig({ shouldForwardProp, displayName: "Label", componentId: "sc-bfi43f-1" }).attrs(props => { var _props$htmlFor; return { htmlFor: (_props$htmlFor = props.htmlFor) !== null && _props$htmlFor !== void 0 ? _props$htmlFor : props.id }; })(props => css({ display: "block", color: props.inverted ? themeGet("colors.white")(props) : props.invalid ? themeGet("colors.dangerDark")(props) : themeGet("colors.greyDarkest")(props), fontSize: themeGet("fontSizes.0")(props), fontWeight: props.bold ? themeGet("fontWeights.2")(props) : themeGet("fontWeights.1")(props), mb: "xs" })); const MultiValueRemove = props => { const { innerProps, data } = props; return /*#__PURE__*/_jsx(components.MultiValueRemove, _objectSpread({}, _objectSpread(_objectSpread({}, props), {}, { innerProps: _objectSpread(_objectSpread({}, innerProps), {}, { "aria-label": "Remove ".concat(data.label) }) }))); }; MultiValueRemove.propTypes = { data: PropTypes.object, innerProps: PropTypes.object }; const SELECT_TYPES = { creatable: CreatableSelect, async: AsyncSelect, default: ReactSelect }; /** * * This component uses React Select: <https://react-select.com/home> * * Usage of this component has changed since we have upgraded to the latest version of `react-select`. For example, field values are now defined as separate objects. for example: * * const options = [ * { value: 'chocolate', label: 'Chocolate' }, * { value: 'strawberry', label: 'Strawberry' }, * { value: 'vanilla', label: 'Vanilla' }, * { value: 'hazelnut', label: 'Hazelnut' }, * { value: 'rocky road', label: 'Rocky Road' } * ] * For a full list of the changes, see <https://react-select.com/upgrade-guide>. * */ const Select = /*#__PURE__*/forwardRef((_ref, ref) => { var _SELECT_TYPES$selectT; let { selectType = "default" } = _ref, props = _objectWithoutProperties(_ref, _excluded); const theme = /*#__PURE__*/useTheme(); const inputRef = useInputFocus(ref, props.focus); const { updateStyles = s => s } = props; const customStyles = updateStyles({ menu: (provided, state) => _objectSpread(_objectSpread({}, provided), {}, { opacity: state.isDisabled ? 0.7 : 1, backgroundColor: props.inverted ? themeGet("colors.greyDarker")({ theme }) : themeGet("colors.white")({ theme }), color: props.inverted ? themeGet("colors.greyLighter") : themeGet("colors.greyDarkest")({ theme }), fontSize: themeGet("fontSizes.0")({ theme }), border: props.inverted ? themeGet("borderWidths.1")({ theme }) + " solid " + themeGet("colors.primaryLight")({ theme }) : themeGet("borderWidths.1")({ theme }) + " solid " + themeGet("colors.primary")({ theme }), borderRadius: themeGet("radii.2")({ theme }), marginBottom: "0", marginTop: themeGet("space.xs")({ theme }), overflow: "hidden", zIndex: 12 }), menuList: provided => _objectSpread(_objectSpread({}, provided), {}, { paddingTop: "0", overflow: "auto", color: props.inverted ? themeGet("colors.greyLightest")({ theme }) : themeGet("colors.greyDarkest")({ theme }) }), control: (provided, state) => _objectSpread(_objectSpread({}, provided), {}, { minHeight: props.height ? props.height : themeGet("appScale.inputHeightDefault")({ theme }), boxShadow: "none", opacity: state.isDisabled ? 0.7 : 1, "&:hover": { borderColor: props.invalid ? themeGet("colors.danger")({ theme }) : themeGet("colors.primary")({ theme }) }, "&:focus-within": { outline: "0", borderColor: props.invalid ? themeGet("colors.danger")({ theme }) : themeGet("colors.primary")({ theme }), boxShadow: props.invalid ? themeGet("shadows.thickOutline")({ theme }) + " " + themeGet("colors.danger30")({ theme }) : themeGet("shadows.thickOutline")({ theme }) + " " + themeGet("colors.primary30")({ theme }) }, borderColor: state.isFocused ? themeGet("colors.primary")({ theme }) : props.inverted ? themeGet("colors.white30")({ theme }) : themeGet("colors.black30")({ theme }), backgroundColor: props.inverted ? themeGet("colors.greyDarker")({ theme }) : themeGet("colors.white")({ theme }), color: props.inverted ? themeGet("colors.greyLighter")({ theme }) : themeGet("colors.greyDarkest")({ theme }), borderRadius: themeGet("radii.2")({ theme }), fontSize: themeGet("fontSizes.0")({ theme }), overflow: "hidden", border: "1px solid ".concat(props.invalid ? themeGet("colors.danger")({ theme }) : themeGet("colors.black30")({ theme })) }), container: (provided, state) => _objectSpread(_objectSpread({}, provided), {}, { opacity: state.isDisabled ? 0.7 : 1, color: props.inverted ? themeGet("colors.greyLighter")({ theme }) : themeGet("colors.grey")({ theme }), fontSize: themeGet("fontSizes.0")({ theme }) }), valueContainer: provided => _objectSpread(_objectSpread({}, provided), {}, { padding: props.padding ? props.padding : "2px 4px", overflow: "visible" }), clearIndicator: (provided, state) => _objectSpread(_objectSpread({}, provided), {}, { opacity: state.isDisabled ? 0.7 : 1, padding: themeGet("space.xxs")({ theme }), color: !state.isFocused && !props.inverted ? themeGet("colors.greyDark")({ theme }) : state.isFocused && !props.inverted ? themeGet("colors.primary")({ theme }) : !state.isFocused && props.inverted ? themeGet("colors.white")({ theme }) : themeGet("colors.primaryLight")({ theme }), "&:hover": { color: themeGet("colors.danger")({ theme }) } }), dropdownIndicator: (provided, state) => _objectSpread(_objectSpread({}, provided), {}, { opacity: state.isDisabled ? 0.7 : 1, padding: themeGet("space.xxs")({ theme }), color: !state.isFocused && !props.inverted ? themeGet("colors.greyDark")({ theme }) : state.isFocused && !props.inverted ? themeGet("colors.primary")({ theme }) : !state.isFocused && props.inverted ? themeGet("colors.white")({ theme }) : themeGet("colors.primaryLight")({ theme }), "&:hover": { color: !state.isFocused && !props.inverted ? themeGet("colors.primary")({ theme }) : state.isFocused && !props.inverted ? themeGet("colors.primaryDarkest")({ theme }) : !state.isFocused && props.inverted ? themeGet("colors.primary")({ theme }) : themeGet("colors.white")({ theme }) } }), groupHeading: provided => _objectSpread(_objectSpread({}, provided), {}, { textTransform: "none", fontSize: themeGet("fontSizes.0")({ theme }), color: themeGet("colors.greyDark")({ theme }) }), multiValue: (provided, state) => _objectSpread(_objectSpread({}, provided), {}, { opacity: state.isDisabled ? 0.7 : 1, backgroundColor: "transparent", color: themeGet("colors.white")({ theme }), alignItems: "center", padding: "0 !important", fontSize: themeGet("fontSizes.1")({ theme }), wordWrap: "break-word" }), multiValueLabel: (provided, state) => _objectSpread(_objectSpread({}, provided), {}, { backgroundColor: themeGet("colors.primary")({ theme }), color: themeGet("colors.white")({ theme }), padding: state.data.isFixed ? "4px 10px 5px 10px !important" : "4px 8px 5px 10px !important", fontSize: "1.3rem", fontWeight: themeGet("fontWeights.2")({ theme }), wordWrap: "break-word", whiteSpace: "break-spaces", borderRadius: state.data.isFixed ? "15px" : "15px 0 0 15px" }), multiValueRemove: (provided, state) => { return _objectSpread(_objectSpread({}, provided), {}, { backgroundColor: themeGet("colors.primary")({ theme }), color: themeGet("colors.white")({ theme }), borderLeft: "solid 1px ".concat(themeGet("colors.primaryDark")({ theme })), padding: "6.5px 6px 6.5px 5px", display: state.data.isFixed ? "none" : provided.display, cursor: "pointer", alignSelf: "stretch", borderRadius: "0 15px 15px 0", transition: themeGet("transition.transitionDefault")({ theme }), "&:hover": { backgroundColor: themeGet("colors.primaryDark")({ theme }), color: themeGet("colors.white")({ theme }) } }); }, option: (provided, state) => _objectSpread(_objectSpread({}, provided), {}, { opacity: state.isDisabled ? 0.7 : 1, paddingTop: themeGet("space.s")({ theme }), paddingBottom: themeGet("space.s")({ theme }), paddingLeft: themeGet("space.s")({ theme }), paddingRight: themeGet("space.s")({ theme }), marginBottom: themeGet("space.xs")({ theme }), backgroundColor: !state.isFocused && !props.inverted ? themeGet("colors.white")({ theme }) : state.isFocused && !props.inverted ? themeGet("colors.primaryLightest")({ theme }) : !state.isFocused && props.inverted ? themeGet("colors.greyDarker")({ theme }) : themeGet("colors.primaryDark")({ theme }), fontSize: themeGet("fontSizes.0")({ theme }), whiteSpace: "break-spaces" }), placeholder: (provided, state) => _objectSpread(_objectSpread({}, provided), {}, { opacity: state.isDisabled ? 0.7 : 1, color: props.inverted ? themeGet("colors.greyLightest")({ theme }) : themeGet("colors.greyDarkest")({ theme }), fontSize: themeGet("fontSizes.0")({ theme }) }) }); const components = _objectSpread({ MultiValueRemove }, (props === null || props === void 0 ? void 0 : props.components) || {}); const SelectComponent = (_SELECT_TYPES$selectT = SELECT_TYPES[selectType]) !== null && _SELECT_TYPES$selectT !== void 0 ? _SELECT_TYPES$selectT : SELECT_TYPES.default; const component = /*#__PURE__*/_jsxs(Wrapper, _objectSpread(_objectSpread({ inverted: props.inverted, "data-testid": props["data-testid"], "data-select-wrapper": "true" }, SelectStyles), {}, { children: [props.label && props.inputId && /*#__PURE__*/_jsxs(Label, { id: "".concat(props.inputId, "-label"), inverted: props.inverted, bold: props.bold, htmlFor: props.inputId, invalid: props.invalid, children: [props.label, props.mandatory && /*#__PURE__*/_jsx(Small, { color: "danger", ml: "xs", children: "*" })] }), /*#__PURE__*/_jsx(SelectComponent, _objectSpread(_objectSpread({ ref: inputRef, styles: customStyles, theme: theme, inputId: props.inputId, inverted: props.inverted, isMulti: props.isMulti, classNamePrefix: props.classNamePrefix, onChange: props.onChange, "aria-label": props.ariaLabel, "aria-labelledby": props.label && props.inputId ? "".concat(props.inputId, "-label") : undefined }, props), {}, { components: components }))] })); return props.theme ? /*#__PURE__*/_jsx(ThemeProvider, { theme: props.theme, children: component }) : component; }); Select.propTypes = { /** Points to options object, see example code above */ options: PropTypes.oneOfType([PropTypes.array, PropTypes.object]), /** Specifies the label for the `Select` */ label: PropTypes.string, // ariaLabel prop must be specified if label is not provided ariaLabel: (props, propName) => { if (!props.label && (props[propName] == null || props[propName] === "")) { return new Error("Missing prop `".concat(propName, "` not specified for Select component. When `label` is not provided, `").concat(propName, "` is required.")); } if (props[propName] && typeof props[propName] !== "string") { return new Error("Invalid propType `".concat(propName, "` supplied to Select component. Expected `string`, received `").concat(typeof props[propName], "`.")); } return null; }, /** Makes label bold */ bold: PropTypes.bool, /** Makes select disabled */ isDisabled: PropTypes.bool, /** Specifies the ID for the rendered Select box. If you use the label prop label will automatically point to this ID, so this is required. */ inputId: (props, propName) => { if (props.label && (props[propName] == null || props[propName] === "")) { return new Error("Missing prop `".concat(propName, "` not specified for Select component. When `label` is provided, `").concat(propName, "` is required.")); } if (props[propName] && typeof props[propName] !== "string") { return new Error("Invalid propType `".concat(propName, "` supplied to Select component. Expected `string`, received `").concat(typeof props[propName], "`.")); } return null; }, /** Specifies the height of the select box control, make sure to include the unit, e.g. px */ height: PropTypes.string, /** Specifies the padding of the value showed in the select box control, make sure to include the unit, e.g. px */ padding: PropTypes.string, /** Specifies if the `Select` component is multi-select. */ isMulti: PropTypes.bool, /** Styling for dark backgrounds. */ inverted: PropTypes.bool, /** Specifies the `data-testid` attribute for testing. */ dataTestId: PropTypes.string, /** Specifies prefix for the `#class` applied to the `Select` structures */ classNamePrefix: PropTypes.string, /** Specifies `data-testid` for testing */ "data-testid": PropTypes.string, /** Specifies `onChange` function for the input */ onChange: PropTypes.func, /** Specifies the system design theme object */ theme: PropTypes.object, /** Specify if you want react-select createable option */ selectType: PropTypes.oneOf(["default", "createable", "async"]), /** Specify if you want to overwrite existing customStyles */ updateStyles: PropTypes.func, /** Applies invalid input styles */ invalid: PropTypes.bool, /** Shows asterisk to denote a mandatory field */ mandatory: PropTypes.bool, /** Focus on input */ focus: PropTypes.bool, /** Allows overrides of react-select components */ components: PropTypes.object }; /** @component */ Select.__docgenInfo = { "description": "This component uses React Select: <https://react-select.com/home>\n\nUsage of this component has changed since we have upgraded to the latest version of `react-select`. For example, field values are now defined as separate objects. for example:\n\n const options = [\n { value: 'chocolate', label: 'Chocolate' },\n { value: 'strawberry', label: 'Strawberry' },\n { value: 'vanilla', label: 'Vanilla' },\n { value: 'hazelnut', label: 'Hazelnut' },\n { value: 'rocky road', label: 'Rocky Road' }\n ]\nFor a full list of the changes, see <https://react-select.com/upgrade-guide>.", "methods": [], "displayName": "Select", "props": { "selectType": { "defaultValue": { "value": "\"default\"", "computed": false }, "description": "Specify if you want react-select createable option", "type": { "name": "enum", "value": [{ "value": "\"default\"", "computed": false }, { "value": "\"createable\"", "computed": false }, { "value": "\"async\"", "computed": false }] }, "required": false }, "options": { "description": "Points to options object, see example code above", "type": { "name": "union", "value": [{ "name": "array" }, { "name": "object" }] }, "required": false }, "label": { "description": "Specifies the label for the `Select`", "type": { "name": "string" }, "required": false }, "ariaLabel": { "description": "", "type": { "name": "custom", "raw": "(props, propName) => {\n if (!props.label && (props[propName] == null || props[propName] === \"\")) {\n return new Error(\n `Missing prop \\`${propName}\\` not specified for Select component. When \\`label\\` is not provided, \\`${propName}\\` is required.`\n );\n }\n if (props[propName] && typeof props[propName] !== \"string\") {\n return new Error(\n `Invalid propType \\`${propName}\\` supplied to Select component. Expected \\`string\\`, received \\`${typeof props[\n propName\n ]}\\`.`\n );\n }\n return null;\n}" }, "required": false }, "bold": { "description": "Makes label bold", "type": { "name": "bool" }, "required": false }, "isDisabled": { "description": "Makes select disabled", "type": { "name": "bool" }, "required": false }, "inputId": { "description": "Specifies the ID for the rendered Select box. If you use the label prop label will automatically point to this ID, so this is required.", "type": { "name": "custom", "raw": "(props, propName) => {\n if (props.label && (props[propName] == null || props[propName] === \"\")) {\n return new Error(\n `Missing prop \\`${propName}\\` not specified for Select component. When \\`label\\` is provided, \\`${propName}\\` is required.`\n );\n }\n if (props[propName] && typeof props[propName] !== \"string\") {\n return new Error(\n `Invalid propType \\`${propName}\\` supplied to Select component. Expected \\`string\\`, received \\`${typeof props[\n propName\n ]}\\`.`\n );\n }\n return null;\n}" }, "required": false }, "height": { "description": "Specifies the height of the select box control, make sure to include the unit, e.g. px", "type": { "name": "string" }, "required": false }, "padding": { "description": "Specifies the padding of the value showed in the select box control, make sure to include the unit, e.g. px", "type": { "name": "string" }, "required": false }, "isMulti": { "description": "Specifies if the `Select` component is multi-select.", "type": { "name": "bool" }, "required": false }, "inverted": { "description": "Styling for dark backgrounds.", "type": { "name": "bool" }, "required": false }, "dataTestId": { "description": "Specifies the `data-testid` attribute for testing.", "type": { "name": "string" }, "required": false }, "classNamePrefix": { "description": "Specifies prefix for the `#class` applied to the `Select` structures", "type": { "name": "string" }, "required": false }, "data-testid": { "description": "Specifies `data-testid` for testing", "type": { "name": "string" }, "required": false }, "onChange": { "description": "Specifies `onChange` function for the input", "type": { "name": "func" }, "required": false }, "theme": { "description": "Specifies the system design theme object", "type": { "name": "object" }, "required": false }, "updateStyles": { "description": "Specify if you want to overwrite existing customStyles", "type": { "name": "func" }, "required": false }, "invalid": { "description": "Applies invalid input styles", "type": { "name": "bool" }, "required": false }, "mandatory": { "description": "Shows asterisk to denote a mandatory field", "type": { "name": "bool" }, "required": false }, "focus": { "description": "Focus on input", "type": { "name": "bool" }, "required": false }, "components": { "description": "Allows overrides of react-select components", "type": { "name": "object" }, "required": false } } }; export default Select;