-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TypeScript Error TS2740 #165
Comments
I think you will need to type the props of the ValueContainer (or use Also you should NEVER define a component inside another component in React If you want more help on this, please share plain text code (that I can paste into my project) 😉 |
import React, { ReactNode, useRef } from 'react';
import { Box, BoxProps, useStyleConfig, useTheme, useToken } from '@chakra-ui/react';
import type { CSSObject } from '@emotion/react';
import ReactSelect, { GroupBase, Props, components } from 'react-select';
import AsyncReactSelect from 'react-select/async';
import AsyncCreatableReactSelect from 'react-select/async-creatable';
import CreatableReactSelect from 'react-select/creatable';
import { useDarkMode } from '@/hooks/useDarkMode';
const BoxAny: any = Box;
// Tricks for generic forwardRef. Do not move this declaration elsewhere as we
// do not want to apply it everywhere. The duplication is not a problem itself
// as this code won't be in the final bundle.
// https://fettblog.eu/typescript-react-generic-forward-refs/#option-3%3A-augment-forwardref
declare module 'react' {
function forwardRef<T, P = {}>(
render: (props: P, ref: React.Ref<T>) => React.ReactElement | null
): (props: P & React.RefAttributes<T>) => React.ReactElement | null;
}
export type SelectProps<
Option,
IsMulti extends boolean = false,
Group extends GroupBase<Option> = GroupBase<Option>
> = {
isAsync?: boolean;
isCreatable?: boolean;
isError?: boolean;
size?: string;
formatCreateLabel?: (inputValue: string) => ReactNode;
loadOptions?: (input: unknown) => any;
defaultOptions?: unknown | boolean;
debounceDelay?: number;
leftIcon?: any;
} & Props<Option, IsMulti, Group> &
Omit<BoxProps, 'defaultValue'>;
const SelectInner = <Option, IsMulti extends boolean = false, Group extends GroupBase<Option> = GroupBase<Option>>(
props: SelectProps<Option, IsMulti, Group>,
ref: React.ForwardedRef<HTMLElement>
) => {
const {
isAsync,
isCreatable,
isError,
size = 'md',
loadingMessage,
formatCreateLabel,
placeholder,
loadOptions = () => new Promise<void>((resolve) => resolve()),
defaultOptions = true,
debounceDelay = 500,
styles = {},
leftIcon,
...otherProps
} = props;
const theme = useTheme();
const { colorModeValue } = useDarkMode();
const stylesFromTheme: any = useStyleConfig('Select', {
size,
});
const [fieldFontSize] = useToken('fontSizes', [stylesFromTheme.field.fontSize]);
const [fieldTextColor, fieldBg, fieldBorderColor, fieldFocusBorderColor, fieldErrorBorderColor] = useToken('colors', [
stylesFromTheme.field.color,
stylesFromTheme.field.bg,
stylesFromTheme.field.borderColor,
stylesFromTheme.field._focus.borderColor,
stylesFromTheme.field._invalid.borderColor,
]);
const [fieldBorderRadius] = useToken('radii', [stylesFromTheme.field.borderRadius]);
const [fieldHeight] = useToken('sizes', [stylesFromTheme.field.h]);
const Element = (() => {
if (isAsync && isCreatable) return AsyncCreatableReactSelect;
if (isAsync) return AsyncReactSelect;
if (isCreatable) return CreatableReactSelect;
return ReactSelect;
})();
let debounceTimeout = useRef<any>();
const debounce = (func: () => unknown, delay: number) => {
clearTimeout(debounceTimeout.current);
return new Promise((resolve) => {
debounceTimeout.current = setTimeout(async () => {
resolve(func());
}, delay);
});
};
const asyncProps = isAsync
? {
defaultOptions,
cacheOptions: true,
loadOptions: (input: unknown) => debounce(() => loadOptions(input), debounceDelay),
}
: {};
type state = {
isDisabled: boolean;
isFocused: boolean;
isSelected: boolean;
};
const getComponentStyles = (componentName: string, callback: (state: state) => CSSObject) => ({
[componentName]: (provided: CSSObject, state: state) => {
const componentsStyles = callback(state);
const combinedStyles = {
...provided,
...componentsStyles,
};
return styles?.[componentName]?.(combinedStyles, state) ?? combinedStyles;
},
});
const getConditionalStyles = (condition: boolean, conditionalStyles: CSSObject): CSSObject =>
condition ? conditionalStyles : {};
const selectStyle = {
...styles,
...getComponentStyles('input', () => ({
color: fieldTextColor,
})),
...getComponentStyles('singleValue', () => ({
color: fieldTextColor,
})),
...getComponentStyles('valueContainer', () => ({
minHeight: `calc(${fieldHeight} - 2px)`,
padding: '0',
paddingLeft: !!leftIcon ? '33px' : '8px', //预留icon位置
paddingRight: '8px',
})),
...getComponentStyles('indicatorsContainer', () => ({
height: `calc(${fieldHeight} - 2px)`,
})),
...getComponentStyles('multiValue', () => ({
backgroundColor: colorModeValue(theme.colors.brand['100'], theme.colors.brand['300']),
})),
...getComponentStyles('multiValueLabel', () => ({
fontWeight: 'bold',
color: colorModeValue(theme.colors.brand['800'], theme.colors.brand['900']),
})),
...getComponentStyles('multiValueRemove', () => ({
color: colorModeValue(theme.colors.brand['800'], theme.colors.brand['900']),
opacity: 0.5,
'&:hover': {
background: 'transparent',
color: colorModeValue(theme.colors.brand['800'], theme.colors.brand['900']),
opacity: 1,
},
})),
...getComponentStyles('dropdownIndicator', () => ({
paddingLeft: '0',
paddingRight: '0.2rem',
})),
...getComponentStyles('indicatorSeparator', () => ({
display: 'none',
})),
...getComponentStyles('control', ({ isFocused, isDisabled }) => ({
color: fieldTextColor,
fontSize: fieldFontSize,
height: 'fit-content',
minHeight: fieldHeight,
borderRadius: fieldBorderRadius,
borderColor: fieldBorderColor,
backgroundColor: fieldBg,
...getConditionalStyles(isFocused && fieldFocusBorderColor, {
borderColor: fieldFocusBorderColor,
boxShadow: `0 0 0 1px ${fieldFocusBorderColor}`,
'&:hover': {
borderColor: fieldFocusBorderColor,
},
}),
...getConditionalStyles(isError, {
borderColor: fieldErrorBorderColor,
boxShadow: `0 0 0 1px ${fieldErrorBorderColor}`,
'&:hover': {
borderColor: fieldErrorBorderColor,
},
}),
...getConditionalStyles(isDisabled, {
opacity: 0.6,
}),
})),
...getComponentStyles('option', ({ isFocused, isDisabled, isSelected }) => ({
fontSize: fieldFontSize,
':active': {
backgroundColor: colorModeValue(theme.colors.gray['100'], theme.colors.blackAlpha['500']),
},
...getConditionalStyles(isFocused, {
backgroundColor: colorModeValue(theme.colors.gray['100'], theme.colors.blackAlpha['400']),
color: colorModeValue(theme.colors.gray['600'], theme.colors.gray['100']),
}),
...getConditionalStyles(isSelected, {
backgroundColor: colorModeValue(theme.colors.gray['50'], theme.colors.blackAlpha['500']),
color: colorModeValue(theme.colors.gray['700'], 'white'),
borderLeft: `2px solid ${theme.colors.brand['500']}`,
}),
...getConditionalStyles(isFocused && isSelected, {
backgroundColor: colorModeValue(theme.colors.gray['100'], theme.colors.blackAlpha['400']),
color: colorModeValue(theme.colors.gray['600'], theme.colors.gray['100']),
}),
...getConditionalStyles(isDisabled, {
opacity: 0.4,
}),
})),
...getComponentStyles('menu', () => ({
zIndex: 10,
backgroundColor: colorModeValue('white', theme.colors.gray['700']),
})),
...getComponentStyles('menuPortal', () => ({
zIndex: theme.zIndices.select,
})),
};
// add leftIcon
const ValueContainer = ({ children, ...props }) =>
components.ValueContainer && (
<components.ValueContainer {...props}>
{!!children && !!leftIcon && <span style={{position:'absolute' ,left:10}}>{leftIcon}</span>}
{children}
</components.ValueContainer>
);
return (
<BoxAny
as={Element}
styles={selectStyle}
menuPortalTarget={document.body}
{...(loadingMessage ? { loadingMessage: () => loadingMessage } : {})}
{...(formatCreateLabel ? { formatCreateLabel } : {})}
placeholder={placeholder ? String(placeholder) : 'Select...'}
components={{ ValueContainer }}
menuPlacement="auto"
ref={ref}
{...asyncProps}
{...otherProps}
/>
);
};
export const Select = React.forwardRef(SelectInner); |
Thank you very much. |
|
When I try adding leftIcon prop to component
Select
, I need to custom ValueContainer of React-Select.But I ran into a typescript error ts(2740),
err message as follows:
How can I fix this error? Any help would be appreciated! Thanks
The text was updated successfully, but these errors were encountered: