import React, { useCallback, useEffect, useState } from "react"; import ReactSelect, { components, GroupBase, Props, InputProps, SingleValue, MultiValue } from "react-select"; import classNames from "@calcom/lib/classNames"; import useTheme from "@calcom/lib/hooks/useTheme"; export type SelectProps< Option, IsMulti extends boolean = false, Group extends GroupBase = GroupBase > = Props; export const InputComponent = >({ inputClassName, ...props }: InputProps) => { return ( ); }; function Select< Option, IsMulti extends boolean = false, Group extends GroupBase = GroupBase >({ className, ...props }: SelectProps) { const { resolvedTheme, forcedTheme, isReady } = useTheme(); const hasDarkTheme = !forcedTheme && resolvedTheme === "dark"; const darkThemeColors = { /** Dark Theme starts */ //primary - Border when selected and Selected Option background primary: "rgb(41 41 41 / var(--tw-border-opacity))", neutral0: "rgb(62 62 62 / var(--tw-bg-opacity))", // Down Arrow hover color neutral5: "white", neutral10: "rgb(41 41 41 / var(--tw-border-opacity))", // neutral20 - border color + down arrow default color neutral20: "rgb(41 41 41 / var(--tw-border-opacity))", // neutral30 - hover border color neutral30: "rgb(41 41 41 / var(--tw-border-opacity))", neutral40: "white", danger: "white", // Cross button in multiselect dangerLight: "rgb(41 41 41 / var(--tw-border-opacity))", // neutral50 - MultiSelect - "Select Text" color neutral50: "white", // neutral60 - Down Arrow color neutral60: "white", neutral70: "red", // neutral80 - Selected option neutral80: "white", neutral90: "blue", primary50: "rgba(209 , 213, 219, var(--tw-bg-opacity))", primary25: "rgba(244, 245, 246, var(--tw-bg-opacity))", /** Dark Theme ends */ }; // Till we know in JS the theme is ready, we can't render react-select as it would render with light theme instead if (!isReady) { return ; } return ( ({ ...theme, borderRadius: 2, colors: { ...theme.colors, ...(hasDarkTheme ? darkThemeColors : { /** Light Theme starts */ primary: "var(--brand-color)", primary50: "rgba(209 , 213, 219, var(--tw-bg-opacity))", primary25: "rgba(244, 245, 246, var(--tw-bg-opacity))", /** Light Theme Ends */ }), }, })} styles={{ option: (provided, state) => ({ ...provided, color: state.isSelected ? "var(--brand-text-color)" : "black", ":active": { backgroundColor: state.isSelected ? "" : "var(--brand-color)", color: "var(--brand-text-color)", }, }), }} components={{ ...components, IndicatorSeparator: () => null, Input: InputComponent, }} className={classNames("text-sm", className)} {...props} /> ); } export function SelectWithValidation< Option extends { label: string; value: string }, isMulti extends boolean = false, Group extends GroupBase = GroupBase >({ required = false, onChange, value, ...remainingProps }: SelectProps & { required?: boolean }) { const [hiddenInputValue, _setHiddenInputValue] = useState(() => { if (value instanceof Array || !value) { return; } return value.value || ""; }); const setHiddenInputValue = useCallback((value: MultiValue | SingleValue) => { let hiddenInputValue = ""; if (value instanceof Array) { hiddenInputValue = value.map((val) => val.value).join(","); } else { hiddenInputValue = value?.value || ""; } _setHiddenInputValue(hiddenInputValue); }, []); useEffect(() => { if (!value) { return; } setHiddenInputValue(value); }, [value, setHiddenInputValue]); return ( { setHiddenInputValue(value); if (onChange) { onChange(value, ...remainingArgs); } }} /> {required && ( {}} // TODO:Not able to get focus to work // onFocus={() => selectRef.current?.focus()} required={required} /> )} ); } export default Select;