feat: usage
This commit is contained in:
@@ -2,7 +2,7 @@ import { createFromIconfontCN } from '@ant-design/icons';
|
||||
// import './iconfont/iconfont.js';
|
||||
|
||||
const IconFont = createFromIconfontCN({
|
||||
scriptUrl: '//at.alicdn.com/t/c/font_4613488_jctdntmi5mf.js'
|
||||
scriptUrl: '//at.alicdn.com/t/c/font_4613488_htxf2x5ewb.js'
|
||||
});
|
||||
|
||||
export default IconFont;
|
||||
|
||||
@@ -43,241 +43,251 @@ const TagWrapper = styled(Tag)`
|
||||
border-radius: 12px;
|
||||
`;
|
||||
|
||||
const SimpleSelect: React.FC<SelectProps & { ref?: any; showTags?: boolean }> =
|
||||
forwardRef((props, ref) => {
|
||||
const intl = useIntl();
|
||||
const { options = [], showTags, ...restProps } = props;
|
||||
const SimpleSelect: React.FC<
|
||||
SelectProps & {
|
||||
ref?: any;
|
||||
showTags?: boolean;
|
||||
styles?: {
|
||||
wrapper?: React.CSSProperties;
|
||||
select?: React.CSSProperties;
|
||||
};
|
||||
}
|
||||
> = forwardRef((props, ref) => {
|
||||
const intl = useIntl();
|
||||
const { options = [], showTags, styles = {}, ...restProps } = props;
|
||||
|
||||
const [allSelection, setAllSelection] = React.useState<{
|
||||
checked: boolean;
|
||||
indeterminate: boolean;
|
||||
}>({
|
||||
checked: false,
|
||||
const [allSelection, setAllSelection] = React.useState<{
|
||||
checked: boolean;
|
||||
indeterminate: boolean;
|
||||
}>({
|
||||
checked: false,
|
||||
indeterminate: false
|
||||
});
|
||||
const [optionsList, setOptionsList] = React.useState<any[]>(options || []);
|
||||
const selectRef = React.useRef<any>(null);
|
||||
const selectorRef = React.useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setOptionsList(options || []);
|
||||
}, [options]);
|
||||
|
||||
const optionRender = (option: any, info: any) => {
|
||||
const { value, label } = option;
|
||||
return (
|
||||
<OptionWrapper>
|
||||
{restProps.value?.includes?.(value) ? (
|
||||
<Checkbox checked></Checkbox>
|
||||
) : (
|
||||
<Checkbox></Checkbox>
|
||||
)}
|
||||
<AutoTooltip ghost>{label}</AutoTooltip>
|
||||
</OptionWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
const handleOnCheckboxChange = (e: CheckboxChangeEvent) => {
|
||||
const isChecked = e.target.checked;
|
||||
const allValues = optionsList?.map((opt: any) => opt.value) || [];
|
||||
|
||||
setAllSelection({
|
||||
checked: isChecked,
|
||||
indeterminate: false
|
||||
});
|
||||
const [optionsList, setOptionsList] = React.useState<any[]>(options || []);
|
||||
const selectRef = React.useRef<any>(null);
|
||||
const selectorRef = React.useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setOptionsList(options || []);
|
||||
}, [options]);
|
||||
let allSelectedValues = [...(restProps.value || [])];
|
||||
|
||||
const optionRender = (option: any, info: any) => {
|
||||
const { value, label } = option;
|
||||
return (
|
||||
<OptionWrapper>
|
||||
{restProps.value?.includes?.(value) ? (
|
||||
<Checkbox checked></Checkbox>
|
||||
) : (
|
||||
<Checkbox></Checkbox>
|
||||
)}
|
||||
<AutoTooltip ghost>{label}</AutoTooltip>
|
||||
</OptionWrapper>
|
||||
if (isChecked) {
|
||||
// Select all options
|
||||
allSelectedValues = Array.from(
|
||||
new Set([...allSelectedValues, ...allValues])
|
||||
);
|
||||
};
|
||||
} else {
|
||||
// Deselect all options
|
||||
allSelectedValues = allSelectedValues.filter(
|
||||
(value) => !allValues.includes(value)
|
||||
);
|
||||
}
|
||||
|
||||
const handleOnCheckboxChange = (e: CheckboxChangeEvent) => {
|
||||
const isChecked = e.target.checked;
|
||||
const allValues = optionsList?.map((opt: any) => opt.value) || [];
|
||||
restProps.onChange?.(allSelectedValues, optionsList || []);
|
||||
};
|
||||
|
||||
const dropdownRender = (originPanel: React.ReactNode) => {
|
||||
return (
|
||||
<DropdownWrapper>
|
||||
{restProps.mode === 'multiple' && (
|
||||
<SelectAllWrapper>
|
||||
<Checkbox
|
||||
checked={allSelection.checked}
|
||||
indeterminate={allSelection.indeterminate}
|
||||
onChange={handleOnCheckboxChange}
|
||||
>
|
||||
{intl.formatMessage({ id: 'common.checkbox.all' })}
|
||||
</Checkbox>
|
||||
</SelectAllWrapper>
|
||||
)}
|
||||
{originPanel}
|
||||
</DropdownWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
const handleOnChange = (value: any, option: any) => {
|
||||
const selectedValues = Array.isArray(value) ? value : [value];
|
||||
const allSelected = optionsList?.map((opt: any) => opt.value) || [];
|
||||
const isAllSelected = selectedValues.length === allSelected?.length;
|
||||
|
||||
setAllSelection({
|
||||
checked: isAllSelected,
|
||||
indeterminate: !isAllSelected && selectedValues.length > 0
|
||||
});
|
||||
|
||||
restProps.onChange?.(selectedValues, option);
|
||||
};
|
||||
|
||||
const filterOption = (inputValue: string, option: any) => {
|
||||
if (!option || !option.label) return false;
|
||||
return option.label.toLowerCase().includes(inputValue.toLowerCase());
|
||||
};
|
||||
|
||||
const checkAllSelection = (list: Global.BaseOption<string | number>[]) => {
|
||||
if (
|
||||
!restProps.value ||
|
||||
!Array.isArray(restProps.value) ||
|
||||
list.length === 0
|
||||
) {
|
||||
setAllSelection({
|
||||
checked: isChecked,
|
||||
checked: false,
|
||||
indeterminate: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
const selectedValues = new Set(restProps.value);
|
||||
const allValues = list?.map((opt: any) => opt.value) || [];
|
||||
|
||||
let allSelectedValues = [...(restProps.value || [])];
|
||||
const isAllSelected = allValues.every((val: any) =>
|
||||
selectedValues.has(val)
|
||||
);
|
||||
|
||||
if (isChecked) {
|
||||
// Select all options
|
||||
allSelectedValues = Array.from(
|
||||
new Set([...allSelectedValues, ...allValues])
|
||||
);
|
||||
} else {
|
||||
// Deselect all options
|
||||
allSelectedValues = allSelectedValues.filter(
|
||||
(value) => !allValues.includes(value)
|
||||
);
|
||||
}
|
||||
const isSomeSelected = allValues.some((val: any) =>
|
||||
selectedValues.has(val)
|
||||
);
|
||||
|
||||
restProps.onChange?.(allSelectedValues, optionsList || []);
|
||||
};
|
||||
setAllSelection({
|
||||
checked: isAllSelected,
|
||||
indeterminate: isSomeSelected && !isAllSelected
|
||||
});
|
||||
};
|
||||
|
||||
const dropdownRender = (originPanel: React.ReactNode) => {
|
||||
return (
|
||||
<DropdownWrapper>
|
||||
{restProps.mode === 'multiple' && (
|
||||
<SelectAllWrapper>
|
||||
<Checkbox
|
||||
checked={allSelection.checked}
|
||||
indeterminate={allSelection.indeterminate}
|
||||
onChange={handleOnCheckboxChange}
|
||||
>
|
||||
{intl.formatMessage({ id: 'common.checkbox.all' })}
|
||||
</Checkbox>
|
||||
</SelectAllWrapper>
|
||||
)}
|
||||
{originPanel}
|
||||
</DropdownWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
const handleOnChange = (value: any, option: any) => {
|
||||
const selectedValues = Array.isArray(value) ? value : [value];
|
||||
const allSelected = optionsList?.map((opt: any) => opt.value) || [];
|
||||
const isAllSelected = selectedValues.length === allSelected?.length;
|
||||
|
||||
setAllSelection({
|
||||
checked: isAllSelected,
|
||||
indeterminate: !isAllSelected && selectedValues.length > 0
|
||||
});
|
||||
|
||||
restProps.onChange?.(selectedValues, option);
|
||||
};
|
||||
|
||||
const filterOption = (inputValue: string, option: any) => {
|
||||
if (!option || !option.label) return false;
|
||||
return option.label.toLowerCase().includes(inputValue.toLowerCase());
|
||||
};
|
||||
|
||||
const checkAllSelection = (list: Global.BaseOption<string | number>[]) => {
|
||||
if (
|
||||
!restProps.value ||
|
||||
!Array.isArray(restProps.value) ||
|
||||
list.length === 0
|
||||
) {
|
||||
setAllSelection({
|
||||
checked: false,
|
||||
indeterminate: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
const selectedValues = new Set(restProps.value);
|
||||
const allValues = list?.map((opt: any) => opt.value) || [];
|
||||
|
||||
const isAllSelected = allValues.every((val: any) =>
|
||||
selectedValues.has(val)
|
||||
);
|
||||
|
||||
const isSomeSelected = allValues.some((val: any) =>
|
||||
selectedValues.has(val)
|
||||
);
|
||||
|
||||
setAllSelection({
|
||||
checked: isAllSelected,
|
||||
indeterminate: isSomeSelected && !isAllSelected
|
||||
});
|
||||
};
|
||||
|
||||
const TagRender = (props: any) => {
|
||||
const { label } = props;
|
||||
const count = props.isMaxTag ? label.slice(0, -3).slice(1) : label;
|
||||
|
||||
return (
|
||||
<TagWrapper
|
||||
variant="filled"
|
||||
closable={props.closable}
|
||||
onClose={props.onClose}
|
||||
style={{
|
||||
height: 22,
|
||||
backgroundColor: 'var(--ant-color-fill-secondary)',
|
||||
fontSize: 'var(--ant-font-size)'
|
||||
}}
|
||||
className="flex-center"
|
||||
>
|
||||
{showTags
|
||||
? label
|
||||
: intl.formatMessage(
|
||||
{ id: 'common.select.count' },
|
||||
{ count: count }
|
||||
)}
|
||||
</TagWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
const handleOnSearch = (value: string) => {
|
||||
if (restProps.showSearch?.onSearch) {
|
||||
restProps.showSearch?.onSearch?.(value);
|
||||
} else {
|
||||
const filteredOptions = options?.filter((option: any) =>
|
||||
option.label.toLowerCase().includes(value.toLowerCase())
|
||||
) as Global.BaseOption<string | number>[];
|
||||
setOptionsList(filteredOptions || []);
|
||||
checkAllSelection(filteredOptions || []);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOnBlur = (e: any) => {
|
||||
restProps.onBlur?.(e);
|
||||
};
|
||||
|
||||
const handleOnFocus = (e: any) => {
|
||||
restProps.onFocus?.(e);
|
||||
};
|
||||
|
||||
const handleOnOpenChange = (open: boolean) => {
|
||||
if (!open) {
|
||||
checkAllSelection(options as Global.BaseOption<string | number>[]);
|
||||
setOptionsList(options || []);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const input = selectRef.current?.querySelector?.('input');
|
||||
|
||||
if (!input) return;
|
||||
|
||||
const handler = (event: KeyboardEvent) => {
|
||||
if (
|
||||
event.key === 'Backspace' &&
|
||||
(input as HTMLInputElement).value === ''
|
||||
) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
input.addEventListener('keydown', handler);
|
||||
|
||||
return () => {
|
||||
input.removeEventListener('keydown', handler);
|
||||
};
|
||||
}, [selectRef.current]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
focus: () => {
|
||||
selectorRef.current?.focus();
|
||||
},
|
||||
blur: () => {
|
||||
selectorRef.current?.blur();
|
||||
}
|
||||
}));
|
||||
const TagRender = (props: any) => {
|
||||
const { label } = props;
|
||||
const count = props.isMaxTag ? label.slice(0, -3).slice(1) : label;
|
||||
|
||||
return (
|
||||
<div ref={selectRef} style={{ width: 'inherit' }}>
|
||||
<BaseSelect
|
||||
{...restProps}
|
||||
ref={selectorRef}
|
||||
options={optionsList}
|
||||
maxTagCount={restProps.maxTagCount || 0}
|
||||
defaultActiveFirstOption={false}
|
||||
popupRender={dropdownRender}
|
||||
optionRender={optionRender}
|
||||
menuItemSelectedIcon={false}
|
||||
onChange={handleOnChange}
|
||||
tagRender={TagRender}
|
||||
onBlur={handleOnBlur}
|
||||
onFocus={handleOnFocus}
|
||||
showSearch={{
|
||||
onSearch: handleOnSearch,
|
||||
filterOption: restProps.showSearch?.filterOption || filterOption
|
||||
}}
|
||||
onOpenChange={handleOnOpenChange}
|
||||
>
|
||||
{props.children}
|
||||
</BaseSelect>
|
||||
</div>
|
||||
<TagWrapper
|
||||
variant="filled"
|
||||
closable={props.closable}
|
||||
onClose={props.onClose}
|
||||
style={{
|
||||
height: 22,
|
||||
backgroundColor: 'var(--ant-color-fill-secondary)',
|
||||
fontSize: 'var(--ant-font-size)'
|
||||
}}
|
||||
className="flex-center"
|
||||
>
|
||||
{showTags
|
||||
? label
|
||||
: intl.formatMessage({ id: 'common.select.count' }, { count: count })}
|
||||
</TagWrapper>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const handleOnSearch = (value: string) => {
|
||||
if (restProps.showSearch?.onSearch) {
|
||||
restProps.showSearch?.onSearch?.(value);
|
||||
} else {
|
||||
const filteredOptions = options?.filter((option: any) =>
|
||||
option.label.toLowerCase().includes(value.toLowerCase())
|
||||
) as Global.BaseOption<string | number>[];
|
||||
setOptionsList(filteredOptions || []);
|
||||
checkAllSelection(filteredOptions || []);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOnBlur = (e: any) => {
|
||||
restProps.onBlur?.(e);
|
||||
};
|
||||
|
||||
const handleOnFocus = (e: any) => {
|
||||
restProps.onFocus?.(e);
|
||||
};
|
||||
|
||||
const handleOnOpenChange = (open: boolean) => {
|
||||
if (!open) {
|
||||
checkAllSelection(options as Global.BaseOption<string | number>[]);
|
||||
setOptionsList(options || []);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const input = selectRef.current?.querySelector?.('input');
|
||||
|
||||
if (!input) return;
|
||||
|
||||
const handler = (event: KeyboardEvent) => {
|
||||
if (
|
||||
event.key === 'Backspace' &&
|
||||
(input as HTMLInputElement).value === ''
|
||||
) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
input.addEventListener('keydown', handler);
|
||||
|
||||
return () => {
|
||||
input.removeEventListener('keydown', handler);
|
||||
};
|
||||
}, [selectRef.current]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
focus: () => {
|
||||
selectorRef.current?.focus();
|
||||
},
|
||||
blur: () => {
|
||||
selectorRef.current?.blur();
|
||||
}
|
||||
}));
|
||||
|
||||
return (
|
||||
<div ref={selectRef} style={{ ...styles.wrapper }}>
|
||||
<BaseSelect
|
||||
{...restProps}
|
||||
style={{
|
||||
width: restProps.style?.width || '100%',
|
||||
...restProps.style,
|
||||
...styles.select
|
||||
}}
|
||||
ref={selectorRef}
|
||||
options={optionsList}
|
||||
maxTagCount={restProps.maxTagCount || 0}
|
||||
defaultActiveFirstOption={false}
|
||||
popupRender={dropdownRender}
|
||||
optionRender={optionRender}
|
||||
menuItemSelectedIcon={false}
|
||||
onChange={handleOnChange}
|
||||
tagRender={TagRender}
|
||||
onBlur={handleOnBlur}
|
||||
onFocus={handleOnFocus}
|
||||
showSearch={{
|
||||
onSearch: handleOnSearch,
|
||||
filterOption: restProps.showSearch?.filterOption || filterOption
|
||||
}}
|
||||
onOpenChange={handleOnOpenChange}
|
||||
>
|
||||
{props.children}
|
||||
</BaseSelect>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default SimpleSelect;
|
||||
|
||||
Reference in New Issue
Block a user