@hitachivantara/uikit-react-core
Version:
Core React components for the NEXT Design System.
150 lines (149 loc) • 4.54 kB
JavaScript
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
};