orcs-design-system
Version:
TeamForm's Design System, aka: ORCS
644 lines (642 loc) • 23 kB
JavaScript
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;