@coreui/react
Version:
UI Components Library for React.js
254 lines (250 loc) • 10.8 kB
JavaScript
;
var tslib_es6 = require('../../node_modules/tslib/tslib.es6.js');
var React = require('react');
var PropTypes = require('prop-types');
var index = require('../../_virtual/index.js');
var CChip = require('../chip/CChip.js');
var useForkedRef = require('../../hooks/useForkedRef.js');
require('@popperjs/core');
const resolveChipClassName = (chipClassName, value) => {
if (!chipClassName) {
return;
}
if (typeof chipClassName === 'function') {
const resolvedClassName = chipClassName(value);
return typeof resolvedClassName === 'string' ? resolvedClassName : undefined;
}
return chipClassName;
};
const uniqueValues = (values) => [
...new Set(values.map((value) => value.trim()).filter(Boolean)),
];
const CChipInput = React.forwardRef((_a, ref) => {
var { className, chipClassName, createOnBlur = true, defaultValue = [], disabled, id, label, maxChips = null, name, onAdd, onChange, onInput, onRemove, onSelect, placeholder = '', readOnly, removable = true, selectable, separator = ',', size, value } = _a, rest = tslib_es6.__rest(_a, ["className", "chipClassName", "createOnBlur", "defaultValue", "disabled", "id", "label", "maxChips", "name", "onAdd", "onChange", "onInput", "onRemove", "onSelect", "placeholder", "readOnly", "removable", "selectable", "separator", "size", "value"]);
const isControlled = value !== undefined;
const [_values, setValues] = React.useState(() => uniqueValues(defaultValue));
const [inputValue, setInputValue] = React.useState('');
const [selectedValues, setSelectedValues] = React.useState([]);
const rootRef = React.useRef(null);
const inputRef = React.useRef(null);
const forkedRef = useForkedRef.useForkedRef(ref, rootRef);
const values = React.useMemo(() => uniqueValues(isControlled ? value : _values), [isControlled, value, _values]);
React.useEffect(() => {
setSelectedValues((prev) => prev.filter((item) => values.includes(item)));
}, [values]);
const emitValuesChange = (nextValues) => {
if (!isControlled) {
setValues(nextValues);
}
onChange === null || onChange === void 0 ? void 0 : onChange(nextValues);
};
const canAddMore = maxChips === null || values.length < maxChips;
const add = (rawValue) => {
if (disabled || readOnly) {
return false;
}
const normalizedValue = String(rawValue).trim();
if (!normalizedValue || values.includes(normalizedValue) || !canAddMore) {
return false;
}
const nextValues = [...values, normalizedValue];
emitValuesChange(nextValues);
onAdd === null || onAdd === void 0 ? void 0 : onAdd(normalizedValue);
return true;
};
const remove = (valueToRemove) => {
if (disabled || readOnly) {
return false;
}
if (!values.includes(valueToRemove)) {
return false;
}
const nextValues = values.filter((item) => item !== valueToRemove);
emitValuesChange(nextValues);
setSelectedValues((prev) => {
const nextSelected = prev.filter((item) => item !== valueToRemove);
if (nextSelected.length !== prev.length) {
onSelect === null || onSelect === void 0 ? void 0 : onSelect(nextSelected);
}
return nextSelected;
});
onRemove === null || onRemove === void 0 ? void 0 : onRemove(valueToRemove);
return true;
};
const createFromInput = () => {
if (add(inputValue)) {
setInputValue('');
}
};
const focusLastChip = () => {
if (!rootRef.current) {
return;
}
const focusableChips = [
...rootRef.current.querySelectorAll('[data-coreui-chip-focusable="true"]:not(.disabled)'),
];
if (focusableChips.length === 0) {
return;
}
focusableChips[focusableChips.length - 1].focus();
};
const handleInputKeyDown = (event) => {
switch (event.key) {
case 'Enter': {
event.preventDefault();
createFromInput();
break;
}
case 'Backspace':
case 'Delete': {
if (inputValue === '') {
event.preventDefault();
focusLastChip();
}
break;
}
case 'ArrowLeft': {
if (event.currentTarget.selectionStart === 0 && event.currentTarget.selectionEnd === 0) {
event.preventDefault();
focusLastChip();
}
break;
}
case 'Escape': {
setInputValue('');
event.currentTarget.blur();
break;
}
// No default
}
};
const handleInputChange = (value) => {
if (disabled || readOnly) {
return;
}
if (separator && value.includes(separator)) {
const parts = value.split(separator);
const chipsToAdd = uniqueValues(parts.slice(0, -1));
const nextValues = [...values];
for (const chipValue of chipsToAdd) {
if (maxChips !== null && nextValues.length >= maxChips) {
break;
}
if (!nextValues.includes(chipValue)) {
nextValues.push(chipValue);
onAdd === null || onAdd === void 0 ? void 0 : onAdd(chipValue);
}
}
if (nextValues.length !== values.length) {
emitValuesChange(nextValues);
}
const tail = parts[parts.length - 1] || '';
setInputValue(tail);
onInput === null || onInput === void 0 ? void 0 : onInput(tail);
return;
}
setInputValue(value);
onInput === null || onInput === void 0 ? void 0 : onInput(value);
};
const handlePaste = (event) => {
if (disabled || readOnly || !separator) {
return;
}
const pastedData = event.clipboardData.getData('text');
if (!pastedData.includes(separator)) {
return;
}
event.preventDefault();
const chipsToAdd = uniqueValues(pastedData.split(separator));
const nextValues = [...values];
for (const chipValue of chipsToAdd) {
if (maxChips !== null && nextValues.length >= maxChips) {
break;
}
if (!nextValues.includes(chipValue)) {
nextValues.push(chipValue);
onAdd === null || onAdd === void 0 ? void 0 : onAdd(chipValue);
}
}
if (nextValues.length !== values.length) {
emitValuesChange(nextValues);
}
setInputValue('');
onInput === null || onInput === void 0 ? void 0 : onInput('');
};
const handleInputBlur = (event) => {
var _a;
if (!createOnBlur) {
return;
}
if ((_a = event.relatedTarget) === null || _a === void 0 ? void 0 : _a.closest('.chip')) {
return;
}
createFromInput();
};
const handleContainerKeyDown = (event) => {
var _a;
if (event.target === inputRef.current) {
return;
}
if (event.key.length === 1) {
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}
};
const handleContainerClick = (event) => {
var _a;
if (event.target === rootRef.current) {
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}
};
const handleSelectedChange = (chipValue, selected) => {
setSelectedValues((prev) => {
const nextSelected = selected
? uniqueValues([...prev, chipValue])
: prev.filter((value) => value !== chipValue);
onSelect === null || onSelect === void 0 ? void 0 : onSelect(nextSelected);
return nextSelected;
});
};
const inputSize = Math.max(placeholder.length, inputValue.length, 1);
return (React.createElement("div", Object.assign({ className: index.default('chip-input', {
'chip-input-sm': size === 'sm',
'chip-input-lg': size === 'lg',
disabled,
}, className), "aria-disabled": disabled ? true : undefined, "aria-readonly": readOnly ? true : undefined, onClick: handleContainerClick, onKeyDown: handleContainerKeyDown }, rest, { ref: forkedRef }),
label && (React.createElement("label", { className: "chip-input-label", htmlFor: id }, label)),
values.map((chipValue) => (React.createElement(CChip.CChip, { key: chipValue, className: resolveChipClassName(chipClassName, chipValue), removable: Boolean(removable && !disabled && !readOnly), ariaRemoveLabel: `Remove ${chipValue}`, disabled: disabled, onRemove: () => remove(chipValue), selectable: selectable, selected: selectedValues.includes(chipValue), onSelectedChange: (selected) => handleSelectedChange(chipValue, selected) }, chipValue))),
React.createElement("input", { type: "text", id: id, className: "chip-input-field", disabled: disabled, readOnly: Boolean(!disabled && readOnly), placeholder: placeholder, size: inputSize, value: inputValue, onBlur: handleInputBlur, onChange: (event) => handleInputChange(event.target.value), onKeyDown: handleInputKeyDown, onPaste: handlePaste, onFocus: () => {
if (selectedValues.length > 0) {
setSelectedValues([]);
onSelect === null || onSelect === void 0 ? void 0 : onSelect([]);
}
}, ref: inputRef }),
name && React.createElement("input", { type: "hidden", name: name, value: values.join(',') })));
});
CChipInput.propTypes = {
chipClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
className: PropTypes.string,
createOnBlur: PropTypes.bool,
defaultValue: PropTypes.array,
disabled: PropTypes.bool,
id: PropTypes.string,
label: PropTypes.node,
maxChips: PropTypes.number,
name: PropTypes.string,
onAdd: PropTypes.func,
onChange: PropTypes.func,
onInput: PropTypes.func,
onRemove: PropTypes.func,
onSelect: PropTypes.func,
placeholder: PropTypes.string,
readOnly: PropTypes.bool,
removable: PropTypes.bool,
selectable: PropTypes.bool,
separator: PropTypes.string,
size: PropTypes.oneOf(['sm', 'lg']),
value: PropTypes.array,
};
CChipInput.displayName = 'CChipInput';
exports.CChipInput = CChipInput;
//# sourceMappingURL=CChipInput.js.map