@intility/bifrost-react-select
Version:
React select component for Intility's design system, Bifrost.
509 lines (498 loc) • 14.5 kB
JavaScript
/* eslint-disable @typescript-eslint/ban-ts-comment */
"use client";
import { c as _c } from "react-compiler-runtime";
import { forwardRef, useState } from "react";
import ReactSelectDefaultExport, { components as originalComponents } from "react-select";
import AsyncReactSelect from "react-select/async";
import CreatableReactSelect from "react-select/creatable";
import AsyncCreatableReactSelect from "react-select/async-creatable";
import classNames from "classnames";
import Description from "@intility/bifrost-react/Description";
import Feedback from "@intility/bifrost-react/Feedback";
import Label from "@intility/bifrost-react/Label";
import useUniqueId from "@intility/bifrost-react/hooks/useUniqueId";
import useLocale from "@intility/bifrost-react/hooks/useLocale";
import DropdownIndicator from "./overrides/DropdownIndicator.internal.js";
import CustomMenuList from "./overrides/CustomMenuList.internal.js";
import ClearIndicator from "./overrides/ClearIndicator.internal.js";
import CustomOption from "./overrides/CustomOption.internal.js";
import LoadingIndicator from "./overrides/LoadingIndicator.internal.js";
import Menu, { SelectRefCtx } from "./overrides/Menu.internal.js";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
const ReactSelect = ReactSelectDefaultExport.default ?? ReactSelectDefaultExport;
export const selectStyles = {
container: provided => ({
...provided,
".bf-label-description + &, .bf-label + &": {
marginTop: "var(--bfs4)" // add margin-top only when label or description is direct sibling with select
}
}),
control: (provided, state) => ({
...provided,
"&:hover": {
borderColor: "var(--bfc-base-c-inverted)",
// Change color of dropdown icon when hover on Select
".bf-select__dropdown-indicator": {
color: "var(--bfc-base-c)"
}
},
".bf-select-small &": {
minHeight: "var(--rem32)"
},
".bf-select-alert &": {
borderColor: state.isFocused ? "var(--bfc-base-c-inverted)" : state.isDisabled ? "transparent" : "var(--bfc-base-c-alert)"
},
".bf-select-alert &:hover": {
borderColor: state.isFocused ? undefined : state.isDisabled ? "transparent" : "var(--bfc-alert-2)"
},
".bf-fieldgroup &": {
borderRadius: 0
},
".bf-fieldgroup > :first-of-type &": {
borderTopLeftRadius: "var(--bf-radius-s)",
borderBottomLeftRadius: "var(--bf-radius-s)"
},
".bf-fieldgroup > :last-child &": {
borderTopRightRadius: "var(--bf-radius-s)",
borderBottomRightRadius: "var(--bf-radius-s)"
},
backgroundColor: state.isDisabled ? "var(--bfc-base)" : "var(--bfc-base-3)",
borderWidth: 1,
borderStyle: "solid",
borderColor: state.isFocused ? "var(--bfc-base-c-inverted)" : state.isDisabled ? "var(--bfc-base-c-dimmed)" : "var(--bfc-base-c-wcag)",
boxShadow: state.isFocused ? "inset 0 0 0 1px var(--bfc-base-c-inverted)" : "none",
borderRadius: "var(--bf-radius-s)",
minHeight: "var(--rem40)",
cursor: "text"
}),
indicatorSeparator: () => ({
display: "none"
}),
indicatorsContainer: provided => ({
...provided,
".bf-select-small &": {
paddingBlock: "0.2187rem" // 3.5px
},
padding: "0.469rem 0",
// 7.5px
alignItems: "flex-start"
}),
clearIndicator: provided => ({
...provided,
"&:hover": {
color: "var(--bfc-base-c)"
},
color: "var(--bfc-base-c-2)",
cursor: "pointer",
padding: 4,
margin: "1px 4px 0px 0px"
}),
dropdownIndicator: (provided, state) => ({
...provided,
".bf-select-small &": {
marginRight: 4
},
color: state.isDisabled ? "var(--bfc-base-c-disabled)" : state.isFocused ? "var(--bfc-base-c)" : "var(--bfc-base-c-2)",
cursor: "pointer",
padding: 4,
marginRight: 8
}),
input: provided => ({
...provided,
color: "var(--bfc-base-c)",
fontFamily: "inherit",
fontSize: "var(--bf-font-size-l)",
margin: 0,
padding: 0
}),
menu: provided => ({
...provided,
position: "static",
margin: 0,
backgroundColor: "transparent",
boxShadow: "none",
borderRadius: "none"
}),
menuList: provided => ({
...provided,
backgroundColor: "var(--bfc-base-3)",
padding: 0,
border: "1px solid var(--bfc-base-c-wcag)",
borderRadius: "var(--bf-radius-s)"
}),
placeholder: (provided, state) => ({
...provided,
color: state.isDisabled ? "var(--bfc-base-c-disabled)" : "var(--bfc-base-c-2)",
fontSize: "var(--bf-font-size-l)"
}),
valueContainer: provided => ({
...provided,
".bf-select-small &": {
padding: "0 8px"
},
padding: "var(--rem2) 12px"
}),
singleValue: (provided, state) => ({
...provided,
color: state.selectProps.menuIsOpen ? "var(--bfc-base-c-2)" : state.isDisabled ? "var(--bfc-base-c-disabled)" : "var(--bfc-base-c)",
fontSize: "var(--bf-font-size-l)"
}),
option: (provided, state) => ({
...provided,
display: "flex",
justifyContent: !state.isMulti ? "space-between" : "normal",
alignItems: "baseline",
padding: "7px 12px",
backgroundColor: state.isDisabled ? "var(--bfc-base-dimmed)" : state.isFocused ? "var(--bfc-base)" : "var(--bfc-base-3)",
color: state.isDisabled ? "var(--bfc-base-c-2)" : "var(--bfc-base-c)",
"& .bf-select-selected-icon": {
color: "var(--bfc-base-c)",
marginLeft: 4
},
"&:hover": {
backgroundColor: state.isDisabled ? "var(--bfc-base-dimmed)" : "var(--bfc-base)",
cursor: state.isDisabled ? "default" : "pointer"
},
fontSize: "var(--bf-font-size-l)",
fontWeight: state.isSelected ? 600 : 400,
wordBreak: "break-word",
whiteSpace: "normal"
}),
multiValue: (provided, state) => ({
...provided,
backgroundColor: "var(--bfc-base)",
borderRadius: "var(--bf-radius-xs)",
border: state.isDisabled ? "1px solid var(--bfc-base-c-disabled)" : "var(--bf-border)",
opacity: state.isDisabled ? 0.5 : 1,
maxWidth: "calc(100% - 10px)" // leave space for cursor
}),
multiValueLabel: provided => ({
...provided,
fontSize: "var(--bf-font-size-m)",
padding: "1.5px 4px 1.5px 8px",
color: "inherit"
}),
multiValueRemove: (provided, state) => ({
...provided,
color: "var(--bfc-base-c-2)",
paddingLeft: 5,
paddingRight: 5,
background: state.isFocused ? "var(--bfc-theme-2)" : undefined,
"&:hover": {
color: "var(--bfc-base-c)",
cursor: "pointer",
background: "var(--bfc-base-2)"
},
"&:active": {
background: "var(--bfc-base-3)"
},
svg: {
marginTop: 1
}
}),
group: provided => ({
...provided,
padding: "6px 0",
"&:first-of-type": {
marginTop: 4
}
}),
groupHeading: provided => ({
...provided,
textTransform: "capitalize",
color: "var(--bfc-base-c-2)",
fontSize: "var(--bf-font-size-s)",
marginBottom: 2
})
};
export const selectComponents = {
...originalComponents,
DropdownIndicator,
MenuList: CustomMenuList,
// @ts-ignore
Menu,
ClearIndicator,
Option: CustomOption,
LoadingIndicator
};
/**
* Select HOC
*/
const SelectHOC = Selector => {
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-explicit-any, react/display-name
const GeneratedSelect = /*#__PURE__*/forwardRef((t0, ref) => {
const $ = _c(61);
let className;
let components;
let description;
let feedback;
let inputId;
let label;
let props;
let state;
let style;
let t1;
let t2;
let t3;
let t4;
let t5;
let t6;
let t7;
if ($[0] !== t0) {
({
label,
hideLabel: t1,
isDisabled: t2,
state,
feedback,
required: t3,
description,
requiredNoLabel: t4,
optional: t5,
inputId,
className,
style,
loading: t6,
components,
small: t7,
...props
} = t0);
$[0] = t0;
$[1] = className;
$[2] = components;
$[3] = description;
$[4] = feedback;
$[5] = inputId;
$[6] = label;
$[7] = props;
$[8] = state;
$[9] = style;
$[10] = t1;
$[11] = t2;
$[12] = t3;
$[13] = t4;
$[14] = t5;
$[15] = t6;
$[16] = t7;
} else {
className = $[1];
components = $[2];
description = $[3];
feedback = $[4];
inputId = $[5];
label = $[6];
props = $[7];
state = $[8];
style = $[9];
t1 = $[10];
t2 = $[11];
t3 = $[12];
t4 = $[13];
t5 = $[14];
t6 = $[15];
t7 = $[16];
}
const hideLabel = t1 === undefined ? false : t1;
const isDisabled = t2 === undefined ? false : t2;
const required = t3 === undefined ? false : t3;
const requiredNoLabel = t4 === undefined ? false : t4;
const optional = t5 === undefined ? false : t5;
const loading = t6 === undefined ? false : t6;
const small = t7 === undefined ? false : t7;
const selectId = useUniqueId(inputId);
const locale = useLocale();
const [controlElement, setControlElement] = useState(null);
const t8 = !isDisabled && state === "alert";
let t9;
if ($[17] !== className || $[18] !== isDisabled || $[19] !== small || $[20] !== t8) {
t9 = classNames(className, "bf-select-container", "bf-open-sans", {
"bf-select-disabled": isDisabled,
"bf-select-alert": t8,
"bf-select-small": small
});
$[17] = className;
$[18] = isDisabled;
$[19] = small;
$[20] = t8;
$[21] = t9;
} else {
t9 = $[21];
}
let t10;
if ($[22] !== hideLabel || $[23] !== isDisabled || $[24] !== label || $[25] !== optional || $[26] !== required || $[27] !== requiredNoLabel || $[28] !== selectId) {
t10 = !hideLabel && /*#__PURE__*/_jsx(Label, {
htmlFor: selectId,
required: !isDisabled && required && !requiredNoLabel,
optional: optional,
disabled: isDisabled,
children: label
});
$[22] = hideLabel;
$[23] = isDisabled;
$[24] = label;
$[25] = optional;
$[26] = required;
$[27] = requiredNoLabel;
$[28] = selectId;
$[29] = t10;
} else {
t10 = $[29];
}
let t11;
if ($[30] !== description) {
t11 = /*#__PURE__*/_jsx(Description, {
children: description
});
$[30] = description;
$[31] = t11;
} else {
t11 = $[31];
}
let t12;
if ($[32] !== ref) {
t12 = r => {
setControlElement(r?.controlRef ?? null);
if (typeof ref === "function") {
ref(r);
} else {
if (ref != null) {
ref.current = r;
}
}
};
$[32] = ref;
$[33] = t12;
} else {
t12 = $[33];
}
let t13;
if ($[34] !== components) {
t13 = {
...selectComponents,
...components
};
$[34] = components;
$[35] = t13;
} else {
t13 = $[35];
}
const t14 = !isDisabled && (required || requiredNoLabel);
const t15 = props.isMulti ? false : true;
const t16 = loading ?? props.isLoading;
let t17;
if ($[36] !== locale.loading) {
t17 = () => locale.loading + "...";
$[36] = locale.loading;
$[37] = t17;
} else {
t17 = $[37];
}
let t18;
if ($[38] !== isDisabled || $[39] !== label || $[40] !== props || $[41] !== selectId || $[42] !== t12 || $[43] !== t13 || $[44] !== t14 || $[45] !== t15 || $[46] !== t16 || $[47] !== t17) {
t18 = /*#__PURE__*/_jsx(Selector, {
ref: t12,
inputId: selectId,
placeholder: "",
components: t13,
styles: selectStyles,
isDisabled: isDisabled,
classNamePrefix: "bf-select",
required: t14,
"aria-label": label,
hideSelectedOptions: false,
closeMenuOnSelect: t15,
isLoading: t16,
loadingMessage: t17,
...props
});
$[38] = isDisabled;
$[39] = label;
$[40] = props;
$[41] = selectId;
$[42] = t12;
$[43] = t13;
$[44] = t14;
$[45] = t15;
$[46] = t16;
$[47] = t17;
$[48] = t18;
} else {
t18 = $[48];
}
let t19;
if ($[49] !== feedback) {
t19 = /*#__PURE__*/_jsx(Feedback, {
children: feedback
});
$[49] = feedback;
$[50] = t19;
} else {
t19 = $[50];
}
let t20;
if ($[51] !== style || $[52] !== t10 || $[53] !== t11 || $[54] !== t18 || $[55] !== t19 || $[56] !== t9) {
t20 = /*#__PURE__*/_jsxs("div", {
className: t9,
style: style,
"data-testid": "bf-select-container",
children: [t10, t11, t18, t19]
});
$[51] = style;
$[52] = t10;
$[53] = t11;
$[54] = t18;
$[55] = t19;
$[56] = t9;
$[57] = t20;
} else {
t20 = $[57];
}
let t21;
if ($[58] !== controlElement || $[59] !== t20) {
t21 = /*#__PURE__*/_jsx(SelectRefCtx.Provider, {
value: controlElement,
children: t20
});
$[58] = controlElement;
$[59] = t20;
$[60] = t21;
} else {
t21 = $[60];
}
return t21;
});
return GeneratedSelect;
};
// this is somewhat useless on its own
// has to be combined with one of the Select's props
// Each select get its own type which uses the correctly imported props
// And calls the HOC
// The resulting component should be correctly typed
// Plain Select
/**
* Select component - dropdown list
*
* @see https://bifrost.intility.com/react/select
*
* @example
* <Select
* label="Select a country"
* options={countries} // [{ value: countryData, label: "Norway" }, ...]
* value={selected}
* onChange={(item) => setSelected(item)}
* />
*/
export const Select = SelectHOC(ReactSelect);
Select.displayName = "Select";
// Async Select
const AsyncSelect = SelectHOC(AsyncReactSelect);
AsyncSelect.displayName = "AsyncSelect";
// Creatable Select
const CreatableSelect = SelectHOC(CreatableReactSelect);
CreatableSelect.displayName = "CreatableSelect";
// Async Creatable Select
const AsyncCreatableSelect = SelectHOC(AsyncCreatableReactSelect);
AsyncCreatableSelect.displayName = "AsyncCreatableSelect";
export { AsyncSelect, CreatableSelect, AsyncCreatableSelect };
export default Select;