UNPKG

@carbon/ibm-products

Version:
231 lines (229 loc) 8.65 kB
/** * Copyright IBM Corp. 2020, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ import uuidv4 from "../../../global/js/utils/uuidv4.js"; import { blockClass } from "../utils/util.js"; import { ConditionBuilderContext, getEmptyState } from "../ConditionBuilderContext/ConditionBuilderProvider.js"; import { ConditionBuilderButton } from "../ConditionBuilderButton/ConditionBuilderButton.js"; import { useTranslations } from "../utils/useTranslations.js"; import ConditionPreview from "../ConditionPreview/ConditionPreview.js"; import ConditionGroupBuilder from "../ConditionGroupBuilder/ConditionGroupBuilder.js"; import GroupConnector from "../ConditionBuilderConnector/GroupConnector.js"; import ConditionBuilderActions from "../ConditionBuilderActions/ConditionBuilderActions.js"; import React, { useCallback, useContext, useEffect, useRef, useState } from "react"; import PropTypes from "prop-types"; import { Button, Heading, Section } from "@carbon/react"; import { Add, TextNewLine } from "@carbon/react/icons"; //#region src/components/ConditionBuilder/ConditionBuilderContent/ConditionBuilderContent.tsx /** * Copyright IBM Corp. 2024 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ /**@ts-ignore */ const ConditionBuilderContent = ({ startConditionLabel, getConditionState, getActionsState, initialState, actions }) => { const { rootState, setRootState, variant, actionState, onAddItem, onRemoveItem, readOnly, statementConfigCustom } = useContext(ConditionBuilderContext); const initialConditionState = useRef(initialState?.state ? JSON.parse(JSON.stringify(initialState?.state)) : null); const [isConditionBuilderActive, setIsConditionBuilderActive] = useState(false); const [showConditionGroupPreview, setShowConditionGroupPreview] = useState(false); const [addConditionGroupText, conditionHeadingText, conditionBuilderHierarchicalText] = useTranslations([ "addConditionGroupText", "conditionHeadingText", "conditionBuilderHierarchicalText" ]); const showConditionGroupPreviewHandler = () => { setShowConditionGroupPreview(true); }; const hideConditionGroupPreviewHandler = () => { setShowConditionGroupPreview(false); }; useEffect(() => { if (rootState?.groups?.length) setIsConditionBuilderActive(true); else setIsConditionBuilderActive(false); if (getConditionState) getConditionState(rootState ?? {}); }, [rootState]); useEffect(() => { getActionsState?.(actionState ?? []); }, [actionState]); useEffect(() => { if (initialState?.enabledDefault) setRootState?.(initialState.state); }, [initialState]); const onStartConditionBuilder = () => { setIsConditionBuilderActive(true); if (initialConditionState?.current?.groups?.length) { setRootState?.(initialConditionState.current); initialConditionState.current = null; } else setRootState?.(getEmptyState(statementConfigCustom)); }; const onRemove = useCallback((groupId) => { const groupToRemove = rootState?.groups?.find((group) => group?.id === groupId); const { preventRemove } = onRemoveItem?.({ type: "group", state: rootState, item: groupToRemove }) ?? {}; if (!preventRemove) { const groups = rootState?.groups?.filter((group) => groupId !== group?.id); setRootState?.({ ...rootState, groups: rootState ? groups : [] }); if (groups?.length === 0) initialConditionState.current = null; } }, [ setRootState, rootState, onRemoveItem ]); const onChangeHandler = (updatedGroup, groupIndex) => { /** * This method is triggered from inner components. This will be called every time when any change is to be updated in the rootState. * This gets the updated group as argument. */ if (rootState && rootState.groups) { const groups = [ ...rootState.groups ? rootState.groups.slice(0, groupIndex) : [], updatedGroup, ...rootState.groups ? rootState.groups.slice(groupIndex + 1) : [] ]; setRootState?.({ ...rootState, groups }); } }; const addConditionGroupHandler = () => { const { preventAdd } = onAddItem?.({ type: "group", state: rootState }) ?? {}; if (!preventAdd) { const newGroup = getEmptyState(statementConfigCustom).groups?.[0]; setRootState?.({ ...rootState, groups: rootState && rootState.groups ? [...rootState.groups, newGroup] : [newGroup] }); } }; const getColorIndex = () => { return (rootState?.groups?.length ?? 0) % 5; }; if (!isConditionBuilderActive) return /* @__PURE__ */ React.createElement(Button, { className: `${blockClass}__addConditionText-button`, renderIcon: (props) => /* @__PURE__ */ React.createElement(Add, props), iconDescription: startConditionLabel, kind: "ghost", size: "sm", onClick: onStartConditionBuilder }, startConditionLabel); const wrapperRole = variant === "Hierarchical" ? { role: "treegrid", "aria-label": conditionBuilderHierarchicalText } : null; return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Section, { className: `${blockClass}__heading`, level: 4 }, /* @__PURE__ */ React.createElement(Heading, null, conditionHeadingText)), /* @__PURE__ */ React.createElement("div", { className: `${blockClass}__content-container`, ...wrapperRole }, rootState && rootState?.groups?.map((eachGroup, groupIndex) => /* @__PURE__ */ React.createElement("div", { key: eachGroup.id, className: `${blockClass}__group-wrapper` }, /* @__PURE__ */ React.createElement(ConditionGroupBuilder, { className: `${blockClass}__group`, aria: { level: 1, posinset: groupIndex * 2 + 1, setsize: (rootState.groups && rootState.groups.length * 2) ?? 0 }, group: eachGroup, onRemove: () => { onRemove(eachGroup.id); }, onChange: (updatedGroup) => { onChangeHandler(updatedGroup, groupIndex); } }), rootState.groups && groupIndex < rootState.groups.length - 1 && /* @__PURE__ */ React.createElement(GroupConnector, null))), !readOnly && variant == "Hierarchical" && /* @__PURE__ */ React.createElement("div", { role: "row", tabIndex: -1, "aria-level": 1, className: `${blockClass}__add-group` }, /* @__PURE__ */ React.createElement(ConditionBuilderButton, { renderIcon: TextNewLine, onClick: addConditionGroupHandler, onMouseEnter: showConditionGroupPreviewHandler, onMouseLeave: hideConditionGroupPreviewHandler, onFocus: showConditionGroupPreviewHandler, onBlur: hideConditionGroupPreviewHandler, className: `${blockClass}__add-condition-group `, hideLabel: true, label: addConditionGroupText, wrapperProps: { role: "gridcell", "aria-label": addConditionGroupText } })), variant === "Hierarchical" ? /* @__PURE__ */ React.createElement(ConditionPreview, { previewType: "newGroup", colorIndex: getColorIndex(), className: showConditionGroupPreview ? `${blockClass}__visible` : `${blockClass}__hidden`, group: { groupOperator: rootState?.operator, id: uuidv4() } }) : null), actions && /* @__PURE__ */ React.createElement(ConditionBuilderActions, { actions, className: `${blockClass}__actions-container` })); }; ConditionBuilderContent.propTypes = { /** * optional array of object that give the list of actions. */ actions: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, label: PropTypes.string.isRequired })), /** * callback functions that will provide the updated action state back. */ getActionsState: PropTypes.func, /** * This is a callback function that returns the updated state */ getConditionState: PropTypes.func.isRequired, /** * Optional prop if the condition building need to start from a predefined initial state */ initialState: PropTypes.shape({ state: PropTypes.shape({ groups: PropTypes.arrayOf(PropTypes.shape({ groupOperator: PropTypes.string, statement: PropTypes.string, conditions: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({ property: PropTypes.string, operator: PropTypes.string, value: PropTypes.oneOfType([ PropTypes.string, PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.string, label: PropTypes.string })), PropTypes.shape({ id: PropTypes.string, label: PropTypes.string }) ]) }), PropTypes.object])) })), operator: PropTypes.string }), enabledDefault: PropTypes.bool }), startConditionLabel: PropTypes.string.isRequired }; //#endregion export { ConditionBuilderContent as default };