UNPKG

@intility/bifrost-react-select

Version:

React select component for Intility's design system, Bifrost.

509 lines (498 loc) 14.5 kB
/* 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;