mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 01:18:23 +00:00
Changed implementation of select all option for key navigation.
This commit is contained in:
parent
eb89ef1eeb
commit
e381c75866
4 changed files with 43 additions and 61 deletions
|
|
@ -3,7 +3,6 @@ import { components } from 'react-select';
|
|||
import SolidIcon from '@/_ui/Icon/SolidIcons';
|
||||
import Loader from '@/ToolJetUI/Loader/Loader';
|
||||
import './dropdownV2.scss';
|
||||
import { FormCheck } from 'react-bootstrap';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||
import cx from 'classnames';
|
||||
|
|
@ -12,20 +11,8 @@ const { MenuList } = components;
|
|||
|
||||
// This Menulist also used in MultiselectV2
|
||||
const CustomMenuList = ({ selectProps, ...props }) => {
|
||||
const {
|
||||
onInputChange,
|
||||
onMenuInputFocus,
|
||||
showAllOption,
|
||||
isSelectAllSelected,
|
||||
optionsLoadingState,
|
||||
darkMode,
|
||||
setSelected,
|
||||
setIsSelectAllSelected,
|
||||
fireEvent,
|
||||
inputValue,
|
||||
menuId,
|
||||
showSearchInput,
|
||||
} = selectProps;
|
||||
const { onInputChange, onMenuInputFocus, optionsLoadingState, darkMode, inputValue, menuId, showSearchInput } =
|
||||
selectProps;
|
||||
|
||||
const parentRef = useRef(null);
|
||||
const virtualizer = useVirtualizer({
|
||||
|
|
@ -35,16 +22,6 @@ const CustomMenuList = ({ selectProps, ...props }) => {
|
|||
overscan: 15,
|
||||
});
|
||||
|
||||
const handleSelectAll = (e) => {
|
||||
e.target.checked && fireEvent();
|
||||
if (e.target.checked) {
|
||||
setSelected(props.options);
|
||||
} else {
|
||||
setSelected([]);
|
||||
}
|
||||
setIsSelectAllSelected(e.target.checked);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const searchInput = document.querySelector('.dropdown-multiselect-widget-search-box');
|
||||
if (searchInput) {
|
||||
|
|
@ -89,17 +66,6 @@ const CustomMenuList = ({ selectProps, ...props }) => {
|
|||
/>
|
||||
</div>
|
||||
)}
|
||||
{showAllOption && !optionsLoadingState && (
|
||||
<label htmlFor="select-all-checkbox" className="multiselect-custom-menulist-select-all">
|
||||
<FormCheck
|
||||
id="select-all-checkbox"
|
||||
checked={isSelectAllSelected}
|
||||
onChange={handleSelectAll}
|
||||
onTouchEnd={handleSelectAll}
|
||||
/>
|
||||
<span style={{ marginLeft: '4px' }}>Select all</span>
|
||||
</label>
|
||||
)}
|
||||
{!optionsLoadingState && (
|
||||
<div
|
||||
ref={parentRef}
|
||||
|
|
@ -112,19 +78,22 @@ const CustomMenuList = ({ selectProps, ...props }) => {
|
|||
style={{
|
||||
height: `${virtualizer.getTotalSize() || 38}px`,
|
||||
position: 'relative',
|
||||
marginTop: '5px',
|
||||
}}
|
||||
>
|
||||
{!virtualizer.getTotalSize() && props.children}
|
||||
{virtualizer.getVirtualItems().map((virtualItem) => {
|
||||
const option = props.options[virtualItem.index];
|
||||
const child = props.children[virtualItem.index];
|
||||
const isSelectAll = option?.value === 'multiselect-custom-menulist-select-all';
|
||||
return (
|
||||
<div
|
||||
key={option.value}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
position: isSelectAll ? 'sticky' : 'absolute',
|
||||
width: '100%',
|
||||
top: 0,
|
||||
zIndex: isSelectAll && 10,
|
||||
transform: `translateY(${virtualItem.start}px)`,
|
||||
}}
|
||||
data-index={virtualItem.index}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.dropdown-multiselect-widget-custom-menu-list-body {
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
padding: 5px 0;
|
||||
padding: 0 0 5px;
|
||||
background-color: var(--surfaces-surface-01) !important;
|
||||
border-radius: 0 0 8px 8px;
|
||||
}
|
||||
|
|
@ -21,7 +21,9 @@ const CustomOption = (props) => {
|
|||
<div className="d-flex multiselct-widget-option">
|
||||
<FormCheck checked={props.isSelected} disabled={props?.isDisabled} />
|
||||
<span style={{ marginLeft: '5px' }}>
|
||||
{highlightText(props.label?.toString(), props.selectProps.inputValue)}
|
||||
{props.label?.includes('Select all')
|
||||
? 'Select all'
|
||||
: highlightText(props.label?.toString(), props.selectProps.inputValue)}
|
||||
</span>
|
||||
</div>
|
||||
</Option>
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ export const MultiselectV2 = ({
|
|||
const [visibility, setVisibility] = useState(properties.visibility);
|
||||
const [isMultiSelectLoading, setIsMultiSelectLoading] = useState(multiSelectLoadingState);
|
||||
const [isMultiSelectDisabled, setIsMultiSelectDisabled] = useState(disabledState);
|
||||
const [isSelectAllSelected, setIsSelectAllSelected] = useState(false);
|
||||
const [searchInputValue, setSearchInputValue] = useState('');
|
||||
const _height = padding === 'default' ? `${height}px` : `${height + 4}px`;
|
||||
const [userInteracted, setUserInteracted] = useState(false);
|
||||
|
|
@ -104,6 +103,17 @@ export const MultiselectV2 = ({
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [advanced, JSON.stringify(schema), JSON.stringify(options), sort]);
|
||||
|
||||
const modifiedSelectOptions = useMemo(() => {
|
||||
// Adding select all option dynamically to the options
|
||||
if (showAllOption && !optionsLoadingState) {
|
||||
return [
|
||||
// Appended search input value so that it is always visible
|
||||
{ label: `Select all ${searchInputValue}`, value: 'multiselect-custom-menulist-select-all' },
|
||||
...selectOptions,
|
||||
];
|
||||
} else return selectOptions;
|
||||
}, [showAllOption, JSON.stringify(selectOptions), optionsLoadingState, searchInputValue]);
|
||||
|
||||
function findDefaultItem(value, isAdvanced, isDefault) {
|
||||
if (isAdvanced) {
|
||||
const foundItem = Array.isArray(schema) ? schema.filter((item) => item?.visible && item?.default) : [];
|
||||
|
|
@ -128,8 +138,28 @@ export const MultiselectV2 = ({
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const onChangeHandler = (items, action) => {
|
||||
setInputValue(items);
|
||||
const SELECT_ALL = 'multiselect-custom-menulist-select-all';
|
||||
|
||||
if (action.option?.value === SELECT_ALL) {
|
||||
// Case 1 - If select all is selected
|
||||
if (action.action === 'select-option') {
|
||||
setInputValue(modifiedSelectOptions);
|
||||
} else {
|
||||
setInputValue([]);
|
||||
}
|
||||
} else if (items?.some((item) => item.value === SELECT_ALL)) {
|
||||
// Case 2 - If select all is not selected but selected options include select all
|
||||
setInputValue(items.filter((item) => item.value !== SELECT_ALL));
|
||||
} else if (selectOptions?.length === items?.length) {
|
||||
// Case 3 - If all options are selected except select all
|
||||
setInputValue(modifiedSelectOptions);
|
||||
} else {
|
||||
// Case 4 - Normal selection
|
||||
setInputValue(items);
|
||||
}
|
||||
|
||||
fireEvent('onSelect');
|
||||
setUserInteracted(true);
|
||||
};
|
||||
|
|
@ -315,15 +345,6 @@ export const MultiselectV2 = ({
|
|||
};
|
||||
}, [isMultiselectOpen, componentName]);
|
||||
|
||||
// Handle Select all logic
|
||||
useEffect(() => {
|
||||
if (selectOptions?.length === selected?.length) {
|
||||
setIsSelectAllSelected(true);
|
||||
} else {
|
||||
setIsSelectAllSelected(false);
|
||||
}
|
||||
}, [selectOptions, selected]);
|
||||
|
||||
const customStyles = {
|
||||
container: (base) => ({
|
||||
...base,
|
||||
|
|
@ -481,7 +502,7 @@ export const MultiselectV2 = ({
|
|||
isDisabled={isMultiSelectDisabled}
|
||||
value={selected}
|
||||
onChange={onChangeHandler}
|
||||
options={selectOptions}
|
||||
options={modifiedSelectOptions}
|
||||
styles={customStyles}
|
||||
// Only show loading when dynamic options are enabled
|
||||
isLoading={isMultiSelectLoading}
|
||||
|
|
@ -521,19 +542,9 @@ export const MultiselectV2 = ({
|
|||
icon={icon}
|
||||
doShowIcon={iconVisibility}
|
||||
containerRef={valueContainerRef}
|
||||
showAllOption={showAllOption}
|
||||
isSelectAllSelected={isSelectAllSelected}
|
||||
setIsSelectAllSelected={(value) => {
|
||||
setIsSelectAllSelected(value);
|
||||
if (!value) {
|
||||
fireEvent('onSelect');
|
||||
}
|
||||
}}
|
||||
setSelected={setInputValue}
|
||||
iconColor={iconColor}
|
||||
optionsLoadingState={optionsLoadingState && advanced}
|
||||
darkMode={darkMode}
|
||||
fireEvent={() => fireEvent('onSelect')}
|
||||
menuPlacement="auto"
|
||||
menuPortalTarget={document.body}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue