UNPKG

@carbon/ibm-products

Version:

Carbon for IBM Products

238 lines (232 loc) 8.36 kB
/** * Copyright IBM Corp. 2020, 2025 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ 'use strict'; var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHelpers.js'); var React = require('react'); var react = require('@carbon/react'); var index = require('../../../_virtual/index.js'); var icons = require('@carbon/react/icons'); var ConditionBuilderButton = require('../ConditionBuilderButton/ConditionBuilderButton.js'); var useTranslations = require('../utils/useTranslations.js'); var ConditionBuilderProvider = require('../ConditionBuilderContext/ConditionBuilderProvider.js'); var handleKeyboardEvents = require('../utils/handleKeyboardEvents.js'); var util = require('../utils/util.js'); var translationObject = require('../ConditionBuilderContext/translationObject.js'); const ConditionBuilderItem = _ref => { let { children, className, label, renderIcon, title, type, showToolTip, condition, popOverClassName, config, renderChildren, onChange, description, ...rest } = _ref; const popoverRef = React.useRef(null); const [open, setOpen] = React.useState(false); const { conditionBuilderRef, statementConfigCustom } = React.useContext(ConditionBuilderProvider.ConditionBuilderContext); const statementIdMap = { ifAll: translationObject.translationsObject.ifText, ifAny: translationObject.translationsObject.ifText, unlessAll: translationObject.translationsObject.unlessText, unlessAny: translationObject.translationsObject.unlessText }; //Appending statements from custom statement configuration if present statementConfigCustom?.forEach(statement => { statementIdMap[statement.id] = statement.label; }); const [invalidText, addConditionText, addPropertyText, addOperatorText, addValueText, labelText] = useTranslations.useTranslations(['invalidText', 'addConditionText', 'addPropertyText', 'addOperatorText', 'addValueText', label], statementIdMap); const getPropertyDetails = () => { const { property, operator } = condition || {}; if (label === 'INVALID' || rest['data-name'] === 'propertyField' && property === 'INVALID' || rest['data-name'] === 'operatorField' && operator === 'INVALID') { return { propertyLabel: invalidText, isInvalid: true }; } const propertyId = rest['data-name'] == 'valueField' && type ? util.getValue(type, label, config) : labelText; return { isInvalid: false, propertyLabel: propertyId }; }; const { propertyLabel, isInvalid } = getPropertyDetails(); React.useEffect(() => { /** * rest['data-name'] holds the current field name * popoverToOpen hold the next popover to be opened if required */ if (condition) { const currentField = rest['data-name']; //if any condition is changed, state prop is triggered if (condition.popoverToOpen && currentField !== condition.popoverToOpen) { // close the previous popover closePopover(); } else if (currentField == 'valueField' && type === 'option' && !util.checkForMultiSelectOperator(condition, config)) { //close the current popover if the field is valueField and is a single select dropdown. For all other inputs ,popover need to be open on value changes. closePopover(); } if (condition.popoverToOpen == currentField) { //current popover need to be opened openPopOver(); } } else { // when we change any statement(if/ excl.if) which is not part of condition state, label change is triggered. //close popOver when statement is changed. closePopover(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [condition, label]); React.useEffect(() => { //this will focus the first input field in the popover if (open && popoverRef.current) { const firstFocusableElement = popoverRef?.current?.querySelector('input,textarea'); if (firstFocusableElement) { setTimeout(() => firstFocusableElement.focus(), 0); } } }, [popoverRef, open]); const manageInvalidSelection = () => { //when the user didn't select any value , we need to show as incomplete if (rest['data-name'] === 'propertyField' && !condition?.property || rest['data-name'] === 'operatorField' && !condition?.operator || rest['data-name'] === 'valueField' && !condition?.value) { onChange?.('INVALID'); } }; const closePopover = () => { if (open) { manageInvalidSelection(); } setOpen(false); }; const openPopOver = () => setOpen(true); const togglePopover = () => { if (children || renderChildren) { setOpen(!open); } }; const handleKeyDownHandler = evt => { handleKeyboardEvents.handleKeyDownForPopover(evt, conditionBuilderRef, popoverRef); if (evt.key === 'Escape') { manageInvalidSelection(); } }; const getCustomOperatorLabel = propertyLabel => { return propertyLabel && config?.operators?.find(operator => { return operator.id === propertyLabel; }); }; const getLabel = () => { if (config?.operators && rest['data-name'] === 'operatorField') { return getCustomOperatorLabel(propertyLabel)?.label ?? addOperatorText; } else if (propertyLabel) { return propertyLabel; } else if (rest['data-name'] === 'propertyField') { return addPropertyText; } else if (rest['data-name'] === 'operatorField') { return addOperatorText; } else if (rest['data-name'] === 'valueField') { return addValueText; } else { return addConditionText; } }; return /*#__PURE__*/React.createElement(react.Popover, { open: open, isTabTip: true, role: "gridcell", className: `${popOverClassName} ${util.blockClass}__popover`, ref: popoverRef, onRequestClose: closePopover }, /*#__PURE__*/React.createElement(ConditionBuilderButton.ConditionBuilderButton, _rollupPluginBabelHelpers.extends({ label: getLabel(), hideLabel: !label ? true : false, onClick: togglePopover, className: className, "aria-haspopup": true, "aria-expanded": open, renderIcon: renderIcon ? renderIcon : label == undefined ? icons.Add : undefined, showToolTip: showToolTip, isInvalid: isInvalid, description: description }, rest)), open && /*#__PURE__*/React.createElement(react.PopoverContent, { className: `${util.blockClass}__popover-content-wrapper`, role: "dialog", "aria-label": title, onKeyDown: handleKeyDownHandler }, /*#__PURE__*/React.createElement(react.Layer, null, /*#__PURE__*/React.createElement(react.Section, null, /*#__PURE__*/React.createElement(react.Heading, { className: `${util.blockClass}__item__title` }, title), /*#__PURE__*/React.createElement("div", { className: `${util.blockClass}__popover-content` }, renderChildren ? renderChildren(popoverRef) : children))))); }; ConditionBuilderItem.propTypes = { /** * provide the contents of the popover */ children: index.default.node, /** * Provide an optional class to be applied to the containing node. */ className: index.default.string, /** * current condition state object */ condition: index.default.object, /** * this is the config object again the current property from inputConfig */ config: index.default.object, /** * text to be displayed in the field */ label: index.default.oneOfType([index.default.string, index.default.array, index.default.object]), /** * callback to update the current condition of the state tree */ onChange: index.default.func, /** * class name for popover */ popOverClassName: index.default.string, /** * callback prop that returns the jsx for children */ renderChildren: index.default.func, /** * Optional prop to allow overriding the icon rendering. */ renderIcon: index.default.oneOfType([index.default.func, index.default.object]), /** * show tool tip */ showToolTip: index.default.bool, /** * title of the popover */ title: index.default.string, /** * input type */ type: index.default.string }; exports.ConditionBuilderItem = ConditionBuilderItem;