UNPKG

@boomerang-io/carbon-addons-boomerang-react

Version:
187 lines (180 loc) 12 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var React = require('react'); var react = require('@carbon/react'); var icons = require('@carbon/react/icons'); var core = require('@dnd-kit/core'); var sortable = require('@dnd-kit/sortable'); var utilities = require('@dnd-kit/utilities'); var cx = require('classnames'); var TooltipHover = require('../TooltipHover/TooltipHover.js'); var accessibility = require('../../tools/accessibility.js'); var settings = require('../../internal/settings.js'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var React__default = /*#__PURE__*/_interopDefault(React); var cx__default = /*#__PURE__*/_interopDefault(cx); /* IBM Confidential 694970X, 69497O0 © Copyright IBM Corp. 2022, 2024 */ function CreatableComponent({ buttonClassName = `${settings.prefix}--bmrg-creatable__button`, buttonContent = "Add", buttonProps, createKeyValuePair = false, disabled, id, initialValues: externalInitialValues, invalid, invalidText, helperText, key, keyHelperText, keyLabel, keyLabelText, keyPlaceholder, label, labelText = "", max, nonDeletable = false, onKeyBlur, onValueBlur, onInputBlur, onChange, placeholder, reorderable, tagProps, tagType = "teal", textInputProps, tooltipClassName = `${settings.prefix}--bmrg-creatable__tooltip`, tooltipContent, tooltipProps = { direction: "top" }, type = "text", valueHelperText, valueLabel, valueLabelText, valuePlaceholder, value: externalValues, values, trimInput = false, removeOnlyFirst = false, }) { const [keyValue, setKeyValue] = React.useState(""); const [value, setValue] = React.useState(""); const [input, setInput] = React.useState(""); const inputRef = React__default.default.useRef(null); const inputLabel = labelText || label; const inputKeyLabel = keyLabelText || keyLabel; const inputValueLabel = valueLabelText || valueLabel; const [createdItems, setCreatedItems] = React.useState([]); const createButtonClassName = cx__default.default(buttonClassName, { "--no-label": (!createKeyValuePair && !inputLabel && !tooltipContent) || (createKeyValuePair && !inputKeyLabel && !inputValueLabel), }); /** Add support for csv strings */ let finalValues; let finalExternalValues; let finalExternalInitialValues; if (typeof values === "string") { finalValues = values === "" ? [] : values.split(","); } else { finalValues = values; } if (typeof externalValues === "string") { finalExternalValues = externalValues === "" ? [] : externalValues.split(","); } else { finalExternalValues = externalValues; } if (typeof externalInitialValues === "string") { finalExternalInitialValues = externalInitialValues.split(","); } else { finalExternalInitialValues = externalInitialValues; } const [initialItems] = React.useState(finalValues || finalExternalValues ? finalValues || finalExternalValues : []); const tagItems = (finalValues || finalExternalValues ? finalValues || finalExternalValues : createdItems); // Externally controlled if values props exists const initialTagItems = finalExternalInitialValues || initialItems || []; // Externally controlled if initialValues props exists const existValue = (keyValue && value) || (trimInput ? input?.trim() : input); const hasBothHelperText = keyHelperText && valueHelperText; const hasBothLabelText = inputKeyLabel && inputValueLabel; const tagsToShow = finalExternalInitialValues ? [...initialTagItems, ...tagItems] : [...tagItems]; const disableInputs = disabled || (max && tagsToShow.length >= max && max > 0); // Check if key value pair has colon const keyInputHasColon = keyValue?.includes(":"); const valueInputHasColon = value?.includes(":"); const isKeyInputValid = invalid || keyInputHasColon; const isValueInputValid = invalid || valueInputHasColon; const keyInputInvalidText = keyInputHasColon ? '":" is not allowed' : invalidText; const valueInputInvalidText = valueInputHasColon ? '":" is not allowed' : invalidText; const isAddButtonDisabled = disabled || !existValue || keyInputHasColon || valueInputHasColon; const onInputChange = (e) => { setInput(e.target.value); }; const onKeyChange = (e) => { setKeyValue(e.target.value); }; const onValueChange = (e) => { setValue(e.target.value); }; const addValue = (e) => { e.preventDefault(); const items = [...tagItems]; if (createKeyValuePair && keyValue && value) { items.push(`${keyValue}:${value}`); setKeyValue(""); setValue(""); } else { if (input) { // Check if input is a JSON object const inputToTest = input.trim(); if (inputToTest.slice(0, 1) === "{" && inputToTest.slice(-1) === "}") { const inputJsonObject = JSON.parse(input); if (typeof inputJsonObject === "object" && inputJsonObject !== null) { for (const [key, values] of Object.entries(inputJsonObject)) { const valuesArray = [...values]; valuesArray.forEach((value) => items.push(`${key}:${value}`)); } } } else { items.push(input); } } setInput(""); } setCreatedItems(items); if (onChange) onChange(items); inputRef.current?.focus(); }; const removeValue = (value) => { let items; if (removeOnlyFirst) { items = [...tagItems]; const index = items.indexOf(value); if (index !== -1) { items.splice(index, 1); } } else { items = tagItems.filter((item) => item !== value); } setCreatedItems(items); if (onChange) onChange(items); }; const sensors = core.useSensors(core.useSensor(core.PointerSensor, { activationConstraint: { distance: 5 }, })); function handleDragEnd(event) { const { active, over } = event; if (over && active.id !== over.id) { const oldIndex = tagItems.indexOf(active.id); const newIndex = tagItems.indexOf(over.id); const reorderedItems = sortable.arrayMove(tagItems, oldIndex, newIndex); setCreatedItems(reorderedItems); if (onChange) { onChange(reorderedItems); } } } return (React__default.default.createElement("div", { key: key, className: `${settings.prefix}--bmrg-creatable` }, React__default.default.createElement("div", { className: `${settings.prefix}--bmrg-creatable__input` }, createKeyValuePair ? (React__default.default.createElement("div", { className: `${settings.prefix}--bmrg-creatable__key-value-inputs` }, React__default.default.createElement("div", { style: { marginBottom: hasBothHelperText || keyHelperText ? "0" : valueHelperText ? "1.5rem" : "0rem", marginTop: hasBothLabelText || inputKeyLabel ? "0" : inputValueLabel ? "1.5rem" : "0.5rem", } }, React__default.default.createElement(react.TextInput, { disabled: disableInputs, id: `${id}-key`, invalid: isKeyInputValid, invalidText: keyInputInvalidText, helperText: keyHelperText, labelText: inputKeyLabel, onBlur: onKeyBlur, onChange: onKeyChange, placeholder: keyPlaceholder, ref: inputRef, type: type, value: keyValue, ...textInputProps })), React__default.default.createElement("span", { className: `${settings.prefix}--bmrg-creatable__colon`, style: { marginTop: inputKeyLabel || inputValueLabel ? "2.25rem" : "1.25rem", } }, ":"), React__default.default.createElement("div", { style: { marginBottom: hasBothHelperText || valueHelperText ? "0" : keyHelperText ? "1.5rem" : "0rem", marginTop: hasBothLabelText || inputValueLabel ? "0" : inputKeyLabel ? "1.5rem" : "0.5rem", } }, React__default.default.createElement(react.TextInput, { disabled: disableInputs, id: `${id}-value`, invalid: isValueInputValid, invalidText: valueInputInvalidText, helperText: valueHelperText, labelText: inputValueLabel, onBlur: onValueBlur, onChange: onValueChange, placeholder: valuePlaceholder, type: type, value: value, ...textInputProps })))) : (React__default.default.createElement(react.TextInput, { disabled: disableInputs, id: id, invalid: invalid, invalidText: invalidText, helperText: helperText, labelText: React__default.default.createElement("div", { style: { display: "flex" } }, React__default.default.createElement("div", null, inputLabel), tooltipContent && (React__default.default.createElement("div", { className: tooltipClassName }, React__default.default.createElement(TooltipHover.default, { ...tooltipProps, tooltipText: tooltipContent }, React__default.default.createElement(icons.Information, { size: 16, fill: "currentColor" }))))), onBlur: onInputBlur, onChange: onInputChange, placeholder: placeholder, ref: inputRef, type: type, value: input, ...textInputProps })), React__default.default.createElement(react.Button, { className: createButtonClassName, disabled: isAddButtonDisabled, onClick: addValue, iconDescription: "Add", renderIcon: icons.Add, size: "md", type: "button", ...buttonProps }, buttonContent)), reorderable ? (React__default.default.createElement(core.DndContext, { sensors: disabled ? [] : sensors, collisionDetection: core.closestCenter, onDragEnd: handleDragEnd }, React__default.default.createElement(sortable.SortableContext, { items: tagsToShow, strategy: sortable.verticalListSortingStrategy }, React__default.default.createElement("div", { className: `${settings.prefix}--bmrg-creatable__tags--reorderable` }, tagsToShow.map((item, index) => (React__default.default.createElement(ReorderableTag, { key: `${item}-${index}`, disabled: disabled, initialTagItems: initialTagItems, item: item, nonDeletable: nonDeletable, removeValue: removeValue, tagProps: tagProps, tagType: tagType }))))))) : (React__default.default.createElement("div", { className: `${settings.prefix}--bmrg-creatable__tags` }, tagsToShow.map((item, index) => (React__default.default.createElement(react.Tag, { key: `${item}-${index}`, disabled: disabled, type: tagType, onClick: nonDeletable && initialTagItems.includes(item) ? undefined : () => removeValue(item), onKeyDown: nonDeletable && initialTagItems.includes(item) ? undefined : (e) => accessibility.isAccessibleKeyDownEvent(e) && removeValue(item), filter: !nonDeletable || (nonDeletable && !initialTagItems.includes(item)), ...tagProps }, item))))))); } function ReorderableTag({ disabled, initialTagItems, item, nonDeletable, removeValue, tagProps, tagType, }) { const { attributes, listeners, setNodeRef, transform, transition } = sortable.useSortable({ id: item }); const style = { transform: utilities.CSS.Transform.toString(transform), transition, }; return (React__default.default.createElement("div", { ref: setNodeRef, ...attributes, ...(!disabled ? listeners : {}), style: style }, React__default.default.createElement(react.DismissibleTag, { disabled: disabled, type: tagType, onClose: nonDeletable && initialTagItems.includes(item) ? undefined : () => removeValue(item), renderIcon: icons.Draggable, title: "", text: item, ...tagProps }))); } exports.default = CreatableComponent;