UNPKG

@coreui/react

Version:

UI Components Library for React.js

254 lines (250 loc) 10.8 kB
'use strict'; 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