UNPKG

@hitachivantara/uikit-react-core

Version:

Core React components for the NEXT Design System.

150 lines (149 loc) 4.54 kB
import { jsxs, jsx } from "react/jsx-runtime"; import { useRef, useState, useReducer, useMemo, useEffect } from "react"; import { useDefaultProps } from "@hitachivantara/uikit-react-utils"; import { useControlled } from "../hooks/useControlled.js"; import { useLabels } from "../hooks/useLabels.js"; import { isEqual } from "../utils/helpers.js"; import { defaultOperators, defaultCombinators, HvQueryBuilderProvider, defaultLabels } from "./Context.js"; import { useClasses } from "./QueryBuilder.styles.js"; import { staticClasses } from "./QueryBuilder.styles.js"; import { emptyGroup, setNodeIds, clearNodeIds } from "./utils/index.js"; import reducer from "./utils/reducer.js"; import { RuleGroup } from "./RuleGroup/RuleGroup.js"; import { ConfirmationDialog } from "./ConfirmationDialog/ConfirmationDialog.js"; const HvQueryBuilder = (props) => { const { attributes, renderers, query: queryProp, // TODO - remove in v6 value, defaultValue, onChange, disableConfirmation = false, allowRepeatedAttributes = false, operators = defaultOperators, combinators = defaultCombinators, maxDepth = 1, labels: labelsProp, readOnly = false, emptyRenderer = ["Empty", "IsNotEmpty"], classes: classesProp } = useDefaultProps("HvQueryBuilder", props); const { classes } = useClasses(classesProp); const currentAttributes = useRef( null ); const controlled = useRef(value != null); const initialQuery = useRef( value ?? defaultValue ?? queryProp ?? emptyGroup() ); const [query, setQuery] = useControlled(value, initialQuery.current); const prevQuery = useRef(query); const [pendingAction, setPendingAction] = useState(); const [initialState, setInitialState] = useState(true); const [state, dispatchAction] = useReducer( reducer, setNodeIds(structuredClone(initialQuery.current)) ); const labels = useLabels(defaultLabels, labelsProp); const contextValue = useMemo( () => ({ dispatchAction, askAction: setPendingAction, attributes, operators, combinators, maxDepth, labels, initialTouched: initialState, readOnly, renderers, disableConfirmation, allowRepeatedAttributes, emptyRenderer }), [ attributes, operators, combinators, maxDepth, labels, readOnly, initialState, renderers, disableConfirmation, emptyRenderer, allowRepeatedAttributes ] ); useEffect(() => { if (currentAttributes.current == null) { currentAttributes.current = attributes; } else if (currentAttributes.current !== attributes) { currentAttributes.current = attributes; dispatchAction({ type: "reset-query" }); } }, [attributes]); useEffect(() => { if (!isEqual(prevQuery.current, query)) { dispatchAction({ type: "set-query", query: setNodeIds(structuredClone(query), state) }); prevQuery.current = query; } else if (!isEqual( clearNodeIds(structuredClone(state)), clearNodeIds(structuredClone(query)) )) { setInitialState(false); if (!controlled.current) { onChange?.( clearNodeIds(structuredClone(state), true) ); } else { onChange?.(clearNodeIds(structuredClone(state))); } prevQuery.current = state; setQuery(state); } }, [onChange, query, setQuery, state]); const handleConfirm = () => { if (pendingAction) { setPendingAction(void 0); pendingAction.actions.forEach((action) => dispatchAction(action)); } }; const handleCancel = () => { setPendingAction(void 0); }; return /* @__PURE__ */ jsxs(HvQueryBuilderProvider, { value: contextValue, children: [ /* @__PURE__ */ jsx( RuleGroup, { level: 0, id: state.id, combinator: state.combinator, rules: state.rules, classes } ), /* @__PURE__ */ jsx( ConfirmationDialog, { isOpen: pendingAction != null, onConfirm: handleConfirm, onCancel: handleCancel, title: pendingAction?.dialog.dialogTitle, message: pendingAction?.dialog.dialogMessage, confirmButtonLabel: pendingAction?.dialog.dialogConfirm, cancelButtonLabel: pendingAction?.dialog.dialogCancel, closeButtonTooltip: pendingAction?.dialog.dialogCloseTooltip } ) ] }); }; export { HvQueryBuilder, staticClasses as queryBuilderClasses };