@boomerang-io/carbon-addons-boomerang-react
Version:
Carbon Addons for Boomerang apps
187 lines (180 loc) • 12 kB
JavaScript
'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;