feat: Add fillOptions prop to dropdown (#6908)
* feat: Add fillOptions prop to dropdown - this will make width of dropdown popup same as width the selector * Use dropdown width for option if fillOptions true * Use dropdown width for option if fillOptions true * hotfix: use optionWidth when fillOptions is false * Add 260px as default width of DropdownOptions * fix types * hotfix typescript issue * fix horizontal scrollbar visible * hotfix type issue
This commit is contained in:
parent
4938371566
commit
4a688fd11d
|
|
@ -37,6 +37,7 @@ export interface RenderDropdownOptionType {
|
|||
isSelectedNode?: boolean;
|
||||
extraProps?: any;
|
||||
errorMsg?: string;
|
||||
optionWidth: string;
|
||||
}
|
||||
|
||||
type RenderOption = ({
|
||||
|
|
@ -44,6 +45,7 @@ type RenderOption = ({
|
|||
index,
|
||||
option,
|
||||
optionClickHandler,
|
||||
optionWidth,
|
||||
}: RenderDropdownOptionType) => ReactElement<any, any>;
|
||||
|
||||
export type DropdownProps = CommonComponentProps &
|
||||
|
|
@ -67,6 +69,7 @@ export type DropdownProps = CommonComponentProps &
|
|||
isLoading?: boolean;
|
||||
errorMsg?: string; // If errorMsg is defined, we show dropDown's error state with the message.
|
||||
helperText?: string;
|
||||
fillOptions?: boolean;
|
||||
};
|
||||
export interface DefaultDropDownValueNodeProps {
|
||||
selected: DropdownOption;
|
||||
|
|
@ -74,6 +77,7 @@ export interface DefaultDropDownValueNodeProps {
|
|||
isOpen?: boolean;
|
||||
errorMsg?: string;
|
||||
renderNode?: RenderOption;
|
||||
optionWidth: string;
|
||||
}
|
||||
|
||||
export interface RenderDropdownOptionType {
|
||||
|
|
@ -192,6 +196,7 @@ const DropdownOptionsWrapper = styled.div<{
|
|||
height: ${(props) => props.height};
|
||||
max-height: ${(props) => props.maxHeight};
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
`;
|
||||
|
||||
const OptionWrapper = styled.div<{
|
||||
|
|
@ -339,6 +344,7 @@ const HelperText = styled.span`
|
|||
|
||||
function DefaultDropDownValueNode({
|
||||
errorMsg,
|
||||
optionWidth,
|
||||
renderNode,
|
||||
selected,
|
||||
showLabelOnly,
|
||||
|
|
@ -355,7 +361,12 @@ function DefaultDropDownValueNode({
|
|||
return (
|
||||
<SelectedDropDownHolder>
|
||||
{renderNode ? (
|
||||
renderNode({ isSelectedNode: true, option: selected, errorMsg })
|
||||
renderNode({
|
||||
isSelectedNode: true,
|
||||
option: selected,
|
||||
errorMsg,
|
||||
optionWidth,
|
||||
})
|
||||
) : (
|
||||
<>
|
||||
{selected.icon ? (
|
||||
|
|
@ -378,10 +389,11 @@ interface DropdownOptionsProps extends DropdownProps, DropdownSearchProps {
|
|||
renderOption?: RenderOption;
|
||||
headerLabel?: string;
|
||||
selected: DropdownOption;
|
||||
optionWidth: string;
|
||||
}
|
||||
|
||||
export function RenderDropdownOptions(props: DropdownOptionsProps) {
|
||||
const { onSearch, optionClickHandler, renderOption } = props;
|
||||
const { onSearch, optionClickHandler, optionWidth, renderOption } = props;
|
||||
const [options, setOptions] = useState<Array<DropdownOption>>(props.options);
|
||||
const [searchValue, setSearchValue] = useState<string>("");
|
||||
const onOptionSearch = (searchStr: string) => {
|
||||
|
|
@ -398,10 +410,11 @@ export function RenderDropdownOptions(props: DropdownOptionsProps) {
|
|||
setOptions(filteredOptions);
|
||||
onSearch && onSearch(searchStr);
|
||||
};
|
||||
|
||||
return options.length > 0 ? (
|
||||
<DropdownWrapper
|
||||
className="ads-dropdown-options-wrapper"
|
||||
width={props.optionWidth || "260px"}
|
||||
width={optionWidth}
|
||||
>
|
||||
{props.enableSearch && (
|
||||
<SearchComponent
|
||||
|
|
@ -422,6 +435,7 @@ export function RenderDropdownOptions(props: DropdownOptionsProps) {
|
|||
option,
|
||||
index,
|
||||
optionClickHandler,
|
||||
optionWidth,
|
||||
});
|
||||
}
|
||||
return (
|
||||
|
|
@ -512,16 +526,35 @@ export default function Dropdown(props: DropdownProps) {
|
|||
}
|
||||
};
|
||||
|
||||
const [dropdownWrapperWidth, setDropdownWrapperWidth] = useState<string>(
|
||||
"100%",
|
||||
);
|
||||
|
||||
const dropdownWrapperRef = useCallback(
|
||||
(ref: HTMLDivElement) => {
|
||||
if (ref) {
|
||||
const { width } = ref.getBoundingClientRect();
|
||||
setDropdownWrapperWidth(`${width}px`);
|
||||
}
|
||||
},
|
||||
[setDropdownWrapperWidth],
|
||||
);
|
||||
|
||||
const dropdownOptionWidth = props.fillOptions
|
||||
? dropdownWrapperWidth
|
||||
: props.optionWidth || "260px";
|
||||
|
||||
const dropdownTrigger = props.dropdownTriggerIcon ? (
|
||||
<DropdownTriggerWrapper
|
||||
disabled={props.disabled}
|
||||
isOpen={isOpen}
|
||||
onClick={onClickHandler}
|
||||
ref={dropdownWrapperRef}
|
||||
>
|
||||
{props.dropdownTriggerIcon}
|
||||
</DropdownTriggerWrapper>
|
||||
) : (
|
||||
<DropdownSelect>
|
||||
<DropdownSelect ref={dropdownWrapperRef}>
|
||||
<Selected
|
||||
bgColor={props.bgColor}
|
||||
className={props.className}
|
||||
|
|
@ -534,6 +567,7 @@ export default function Dropdown(props: DropdownProps) {
|
|||
>
|
||||
<SelectedValueNode
|
||||
errorMsg={errorMsg}
|
||||
optionWidth={dropdownOptionWidth}
|
||||
renderNode={renderOption}
|
||||
selected={selected}
|
||||
showLabelOnly={props.showLabelOnly}
|
||||
|
|
@ -557,12 +591,15 @@ export default function Dropdown(props: DropdownProps) {
|
|||
)}
|
||||
</DropdownSelect>
|
||||
);
|
||||
|
||||
const dropdownWidth = props.width || "260px";
|
||||
|
||||
return (
|
||||
<DropdownContainer
|
||||
className={props.containerClassName}
|
||||
data-cy={props.cypressSelector}
|
||||
tabIndex={0}
|
||||
width={props.width || "260px"}
|
||||
width={dropdownWidth}
|
||||
>
|
||||
<Popover
|
||||
boundary="scrollParent"
|
||||
|
|
@ -574,8 +611,9 @@ export default function Dropdown(props: DropdownProps) {
|
|||
>
|
||||
{dropdownTrigger}
|
||||
<RenderDropdownOptions
|
||||
optionClickHandler={optionClickHandler}
|
||||
{...props}
|
||||
optionClickHandler={optionClickHandler}
|
||||
optionWidth={dropdownOptionWidth}
|
||||
/>
|
||||
</Popover>
|
||||
</DropdownContainer>
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ export const CONNECT_TO_GIT_SUBTITLE = () =>
|
|||
"Choose an existing empty repository to host your project and keep it in sync";
|
||||
export const REMOTE_URL_VIA = () => "REMOTE URL VIA";
|
||||
|
||||
export const USER_PROFILE_SETTINGS_TITLE = () => "User Settings";
|
||||
export const USER_PROFILE_SETTINGS_TITLE = () => "USER SETTINGS";
|
||||
|
||||
export const AUTHOR_NAME = () => "AUTHOR NAME";
|
||||
export const AUTHOR_EMAIL = () => "AUTHOR EMAIL";
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ const DatasourceImage = styled.img`
|
|||
|
||||
interface DataSourceOptionType extends RenderDropdownOptionType {
|
||||
cypressSelector: string;
|
||||
optionWidth?: string;
|
||||
optionWidth: string;
|
||||
}
|
||||
|
||||
function DataSourceOption({
|
||||
|
|
|
|||
|
|
@ -48,12 +48,14 @@ const TitleWrapper = styled.div`
|
|||
|
||||
const OptionWrapper = styled.div<{
|
||||
selected: boolean;
|
||||
width: string;
|
||||
}>`
|
||||
padding: ${(props) => props.theme.spaces[2] + 1}px
|
||||
${(props) => props.theme.spaces[5]}px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: ${(props) => props.width};
|
||||
|
||||
background-color: ${(props) =>
|
||||
props.selected ? props.theme.colors.propertyPane.dropdownSelectBg : null};
|
||||
|
|
@ -75,21 +77,23 @@ function AuthConfig({ authType }: AuthConfigProps) {
|
|||
<InputContainer>
|
||||
<Dropdown
|
||||
disabled={SSH_PROFILE_OPTION.length === 0}
|
||||
fillOptions
|
||||
onSelect={() => {
|
||||
//
|
||||
}}
|
||||
// optionWidth="100%"
|
||||
options={SSH_PROFILE_OPTION}
|
||||
renderOption={({
|
||||
isSelectedNode,
|
||||
option,
|
||||
optionClickHandler,
|
||||
optionWidth,
|
||||
}) => (
|
||||
<OptionWrapper
|
||||
onClick={() =>
|
||||
optionClickHandler && optionClickHandler(option)
|
||||
}
|
||||
selected={!!isSelectedNode}
|
||||
width={optionWidth || ""}
|
||||
>
|
||||
<Text type={TextType.P1}>{option.label}</Text>
|
||||
</OptionWrapper>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user