UNPKG

react-querybuilder

Version:

React Query Builder component for constructing queries and filters, with utilities for executing them in various database and evaluation contexts

1,328 lines (1,296 loc) 155 kB
import { LogType, TestID, add, clsx, defaultCombinatorLabelMap, defaultCombinators, defaultControlClassnames, defaultOperatorLabelMap, defaultOperators, defaultTranslations, filterFieldsByComparator, findPath, generateAccessibleDescription, generateID, getFirstOption, getMatchModesUtil, getOption, getParentPath, getParseNumberMethod, getValidationClassNames, getValueSourcesUtil, group, isFlexibleOptionArray, isFlexibleOptionGroupArray, isOptionGroupArray, isPojo, isRuleGroup, isRuleGroupType, isRuleGroupTypeIC, joinWith, lc, mergeAnyTranslation, mergeAnyTranslations, mergeClassnames, move, parseNumber, pathIsDisabled, pathsAreEqual, preferAnyProp, preferFlagProps, preferProp, prepareOptionList, prepareRuleGroup, remove, rootPath, standardClassnames, toArray, toFullOptionList, update } from "@react-querybuilder/core"; import * as React from "react"; import { Fragment, createContext, forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"; import { combineSlices, configureStore, createSlice } from "@reduxjs/toolkit"; import { createDispatchHook, createSelectorHook, createStoreHook } from "react-redux"; import { produce } from "immer"; //#region src/components/ActionElement.tsx /** * Default `<button>` component used by {@link QueryBuilder}. * * @group Components */ const ActionElement = (props) => /* @__PURE__ */ React.createElement("button", { type: "button", "data-testid": props.testID, disabled: props.disabled && !props.disabledTranslation, className: props.className, title: props.disabledTranslation && props.disabled ? props.disabledTranslation.title : props.title, onClick: (e) => props.handleOnClick(e) }, props.disabledTranslation && props.disabled ? props.disabledTranslation.label : props.label); //#endregion //#region src/components/DragHandle.tsx /** * Default drag handle component used by {@link QueryBuilder} when `enableDragAndDrop` is `true`. * * @group Components */ const DragHandle = forwardRef((props, dragRef) => /* @__PURE__ */ React.createElement("span", { "data-testid": props.testID, ref: dragRef, className: props.className, title: props.title }, props.label)); //#endregion //#region \0@oxc-project+runtime@0.99.0/helpers/objectWithoutPropertiesLoose.js function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (e.includes(n)) continue; t[n] = r[n]; } return t; } //#endregion //#region \0@oxc-project+runtime@0.99.0/helpers/objectWithoutProperties.js function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var s = Object.getOwnPropertySymbols(e); for (r = 0; r < s.length; r++) o = s[r], t.includes(o) || {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } //#endregion //#region \0@oxc-project+runtime@0.99.0/helpers/typeof.js function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o$1) { return typeof o$1; } : function(o$1) { return o$1 && "function" == typeof Symbol && o$1.constructor === Symbol && o$1 !== Symbol.prototype ? "symbol" : typeof o$1; }, _typeof(o); } //#endregion //#region \0@oxc-project+runtime@0.99.0/helpers/toPrimitive.js function toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } //#endregion //#region \0@oxc-project+runtime@0.99.0/helpers/toPropertyKey.js function toPropertyKey(t) { var i = toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } //#endregion //#region \0@oxc-project+runtime@0.99.0/helpers/defineProperty.js function _defineProperty(e, r, t) { return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } //#endregion //#region \0@oxc-project+runtime@0.99.0/helpers/objectSpread2.js function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function(r$1) { return Object.getOwnPropertyDescriptor(e, r$1).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function(r$1) { _defineProperty(e, r$1, t[r$1]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r$1) { Object.defineProperty(e, r$1, Object.getOwnPropertyDescriptor(t, r$1)); }); } return e; } //#endregion //#region src/components/InlineCombinator.tsx const _excluded$2 = ["component"]; /** * Default `inlineCombinator` component used by {@link QueryBuilder}. A small `<div>` * wrapper around the `combinatorSelector` component, used when either * `showCombinatorsBetweenRules` or `independentCombinators` are `true`. * * @group Components */ const InlineCombinator = (allProps) => { const { component: CombinatorSelectorComponent } = allProps, props = _objectWithoutProperties(allProps, _excluded$2); const className = clsx(props.schema.suppressStandardClassnames || standardClassnames.betweenRules, props.schema.classNames.betweenRules); return /* @__PURE__ */ React.createElement("div", { className, "data-testid": TestID.inlineCombinator }, /* @__PURE__ */ React.createElement(CombinatorSelectorComponent, _objectSpread2(_objectSpread2({}, props), {}, { testID: TestID.combinators }))); }; //#endregion //#region src/components/MatchModeEditor.tsx const dummyFieldData = { name: "", value: "", label: "" }; const requiresThreshold = (mm) => { var _lc; return [ "atleast", "atmost", "exactly" ].includes((_lc = lc(mm)) !== null && _lc !== void 0 ? _lc : ""); }; const dummyPath = []; /** * Default `matchModeEditor` component used by {@link QueryBuilder}. * * @group Components */ const MatchModeEditor = (props) => { const { match, options, title, className, disabled, testID, schema, selectorComponent: SelectorComponent = props.schema.controls.valueSelector, numericEditorComponent: NumericEditorComponent = props.schema.controls.valueEditor } = props; const { thresholdNum, thresholdRule, thresholdSchema, handleChangeMode, handleChangeThreshold } = useMatchModeEditor(props); return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SelectorComponent, { schema, testID, className, title, handleOnChange: handleChangeMode, disabled, value: match.mode, options, multiple: false, listsAsArrays: false, path: dummyPath, level: 0 }), requiresThreshold(match.mode) && /* @__PURE__ */ React.createElement(NumericEditorComponent, { skipHook: true, testID, inputType: "number", title, className, disabled, handleOnChange: handleChangeThreshold, field: "", operator: "", value: thresholdNum, valueSource: "value", fieldData: dummyFieldData, schema: thresholdSchema, path: dummyPath, level: 0, rule: thresholdRule })); }; const useMatchModeEditor = (props) => { const { match, handleOnChange } = props; const thresholdNum = React.useMemo(() => typeof match.threshold === "number" ? Math.max(0, match.threshold) : 1, [match.threshold]); return { thresholdNum, thresholdRule: React.useMemo(() => ({ field: "", operator: "=", value: thresholdNum }), [thresholdNum]), thresholdSchema: React.useMemo(() => _objectSpread2(_objectSpread2({}, props.schema), {}, { parseNumbers: true }), [props.schema]), handleChangeMode: useCallback((mode) => { if (requiresThreshold(mode) && typeof match.threshold !== "number") handleOnChange(_objectSpread2(_objectSpread2({}, match), {}, { mode, threshold: 1 })); else handleOnChange(_objectSpread2(_objectSpread2({}, match), {}, { mode })); }, [handleOnChange, match]), handleChangeThreshold: useCallback((threshold) => { handleOnChange(_objectSpread2(_objectSpread2({}, match), {}, { threshold: parseNumber(threshold, { parseNumbers: true }) })); }, [handleOnChange, match]) }; }; //#endregion //#region src/components/NotToggle.tsx /** * Default `notToggle` (aka inversion) component used by {@link QueryBuilder}. * * @group Components */ const NotToggle = (props) => { const id = React.useId(); return /* @__PURE__ */ React.createElement("label", { "data-testid": props.testID, className: props.className, title: props.title, htmlFor: id }, /* @__PURE__ */ React.createElement("input", { id, type: "checkbox", onChange: (e) => props.handleOnChange(e.target.checked), checked: !!props.checked, disabled: props.disabled }), props.label); }; //#endregion //#region src/messages.ts const messages = { errorInvalidIndependentCombinatorsProp: "QueryBuilder was rendered with a truthy independentCombinators prop. This prop is deprecated and unnecessary. Furthermore, the initial query/defaultQuery prop was of type RuleGroupType instead of type RuleGroupIC. More info: https://react-querybuilder.js.org/docs/components/querybuilder#independent-combinators", errorUnnecessaryIndependentCombinatorsProp: "QueryBuilder was rendered with the deprecated and unnecessary independentCombinators prop. To use independent combinators, make sure the query/defaultQuery prop is of type RuleGroupIC when the component mounts. More info: https://react-querybuilder.js.org/docs/components/querybuilder#independent-combinators", errorDeprecatedRuleGroupProps: "A custom RuleGroup component has rendered a standard RuleGroup component with deprecated props. The combinator, not, and rules props should not be used. Instead, the full group object should be passed as the ruleGroup prop.", errorDeprecatedRuleProps: "A custom RuleGroup component has rendered a standard Rule component with deprecated props. The field, operator, value, and valueSource props should not be used. Instead, the full rule object should be passed as the rule prop.", errorBothQueryDefaultQuery: "QueryBuilder was rendered with both query and defaultQuery props. QueryBuilder must be either controlled or uncontrolled (specify either the query prop, or the defaultQuery prop, but not both). Decide between using a controlled or uncontrolled query builder and remove one of these props. More info: https://reactjs.org/link/controlled-components", errorUncontrolledToControlled: "QueryBuilder is changing from an uncontrolled component to be controlled. This is likely caused by the query changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled query builder for the lifetime of the component. More info: https://reactjs.org/link/controlled-components", errorControlledToUncontrolled: "QueryBuilder is changing from a controlled component to be uncontrolled. This is likely caused by the query changing from defined to undefined, which should not happen. Decide between using a controlled or uncontrolled query builder for the lifetime of the component. More info: https://reactjs.org/link/controlled-components", errorEnabledDndWithoutReactDnD: "QueryBuilder was rendered with the enableDragAndDrop prop set to true, but either react-dnd was not detected or one of react-dnd-html5-backend or react-dnd-touch-backend was not detected. To enable drag-and-drop functionality, install react-dnd and one of the backend packages and wrap QueryBuilder in QueryBuilderDnD from @react-querybuilder/dnd.", errorDeprecatedDebugImport: `Importing from react-querybuilder/debug is deprecated. To enable Redux DevTools for React Query Builder's internal store, set globalThis.__RQB_DEVTOOLS__ = true.` }; //#endregion //#region src/redux/queriesSlice.ts const initialState$1 = {}; const queriesSlice = createSlice({ name: "queries", initialState: initialState$1, reducers: { setQueryState: (state, { payload: { qbId, query } }) => { state[qbId] = query; } }, selectors: { getQuerySelectorById: (state, qbId) => state[qbId] } }); //#endregion //#region src/redux/QueryBuilderStateContext.ts const QueryBuilderStateContext = React.createContext(null); //#endregion //#region src/redux/warningsSlice.ts const initialState = { [messages.errorInvalidIndependentCombinatorsProp]: false, [messages.errorUnnecessaryIndependentCombinatorsProp]: false, [messages.errorDeprecatedRuleGroupProps]: false, [messages.errorDeprecatedRuleProps]: false, [messages.errorBothQueryDefaultQuery]: false, [messages.errorUncontrolledToControlled]: false, [messages.errorControlledToUncontrolled]: false, [messages.errorEnabledDndWithoutReactDnD]: false, [messages.errorDeprecatedDebugImport]: false }; const warningsSlice = createSlice({ name: "warnings", initialState, reducers: { rqbWarn: (state, { payload }) => { if (!state[payload]) { console.error(payload); state[payload] = true; } } } }); //#endregion //#region src/redux/rootReducer.ts const rootReducer = combineSlices(queriesSlice, warningsSlice).withLazyLoadedSlices(); //#endregion //#region src/redux/_internal/hooks.ts const genUseQueryBuilderDispatch = (ctx) => createDispatchHook(ctx); const genUseQueryBuilderStore = (ctx) => createStoreHook(ctx); const genUseQueryBuilderSelector = (ctx) => createSelectorHook(ctx); const getInternalHooks = (ctx) => ({ useRQB_INTERNAL_QueryBuilderDispatch: genUseQueryBuilderDispatch(ctx), useRQB_INTERNAL_QueryBuilderStore: genUseQueryBuilderStore(ctx), useRQB_INTERNAL_QueryBuilderSelector: genUseQueryBuilderSelector(ctx) }); //#endregion //#region src/redux/_internal/index.ts const _RQB_INTERNAL_dispatchThunk = ({ payload, onQueryChange }) => (dispatch) => { dispatch(queriesSlice.actions.setQueryState(payload)); if (typeof onQueryChange === "function") onQueryChange(payload.query); }; const internalHooks = getInternalHooks(QueryBuilderStateContext); /** * Gets the `dispatch` function for the RQB Redux store. */ const useRQB_INTERNAL_QueryBuilderDispatch = internalHooks.useRQB_INTERNAL_QueryBuilderDispatch; /** * Gets the full RQB Redux store. */ const useRQB_INTERNAL_QueryBuilderStore = internalHooks.useRQB_INTERNAL_QueryBuilderStore; /** * General purpose selector hook for the RQB Redux store. */ const useRQB_INTERNAL_QueryBuilderSelector = internalHooks.useRQB_INTERNAL_QueryBuilderSelector; const { rqbWarn: _SYNC_rqbWarn } = warningsSlice.actions; const rqbWarn = (msg) => (dispatch) => { setTimeout(() => dispatch(_SYNC_rqbWarn(msg))); }; const preloadedState = { queries: queriesSlice.getInitialState(), warnings: warningsSlice.getInitialState() }; const storeCommon = { reducer: rootReducer, preloadedState, middleware: (getDefaultMiddleware) => getDefaultMiddleware({ serializableCheck: { ignoredActions: [queriesSlice.actions.setQueryState.type], ignoredPaths: [/^queries\b.*\.rules\.\d+\.value$/] } }) }; //#endregion //#region src/hooks/usePrevious.ts /** * Returns the prop value from the last render. * * Adapted from https://usehooks.com/usePrevious/. * * @group Hooks */ const usePrevious = (value) => { const ref = useRef({ value, prev: null }); const current = ref.current.value; if (value !== current) { ref.current.prev = current; ref.current.value = value; } return ref.current.prev; }; //#endregion //#region src/hooks/useControlledOrUncontrolled.ts /** * Logs a warning when the component changes from controlled to uncontrolled, * vice versa, or both `query` and `defaultQuery` are provided. * * @group Hooks */ const useControlledOrUncontrolled = (params) => { const dispatch = useRQB_INTERNAL_QueryBuilderDispatch(); const { defaultQuery, queryProp } = params; const prevQueryPresent = usePrevious(!!queryProp); // istanbul ignore else if (process.env.NODE_ENV !== "production") { if (!!queryProp && !!defaultQuery) dispatch(rqbWarn(messages.errorBothQueryDefaultQuery)); else if (prevQueryPresent === true && !queryProp && !!defaultQuery) dispatch(rqbWarn(messages.errorControlledToUncontrolled)); else if (prevQueryPresent === false && !!queryProp && !defaultQuery) dispatch(rqbWarn(messages.errorUncontrolledToControlled)); } }; //#endregion //#region src/hooks/useDeprecatedProps.ts function useDeprecatedProps(type, logWarning, otherParams) { const dispatch = useRQB_INTERNAL_QueryBuilderDispatch(); if (process.env.NODE_ENV !== "production" && logWarning) { if (type === "independentCombinators") { if (otherParams === "invalid") dispatch(rqbWarn(messages.errorInvalidIndependentCombinatorsProp)); if (otherParams === "unnecessary") dispatch(rqbWarn(messages.errorUnnecessaryIndependentCombinatorsProp)); } if (type === "rule") dispatch(rqbWarn(messages.errorDeprecatedRuleProps)); if (type === "ruleGroup") dispatch(rqbWarn(messages.errorDeprecatedRuleGroupProps)); } } //#endregion //#region src/hooks/useFields.ts const useFields = (props) => { const { optionList: fields, optionsMap: fieldMap, defaultOption: defaultField } = useMemo(() => prepareOptionList({ placeholder: props.translations.fields, optionList: props.fields, autoSelectOption: props.autoSelectField, baseOption: props.baseField }), [ props.autoSelectField, props.baseField, props.fields, props.translations.fields ]); return { fields, fieldMap, defaultField }; }; //#endregion //#region src/redux/configureRqbStore.ts const configureRqbStore = (devTools) => { const queryBuilderStore = configureStore(_objectSpread2(_objectSpread2({}, storeCommon), {}, { devTools: devTools ? ( /* istanbul ignore next */ { name: "React Query Builder" }) : false })); queryBuilderStore.addSlice = (slice) => { rootReducer.inject(slice); queryBuilderStore.dispatch({ type: crypto.randomUUID().slice(0, 8), meta: `Initializing state for slice "${slice.name}"` }); }; return queryBuilderStore; }; //#endregion //#region src/redux/getRqbStore.ts let _store = null; /** * Gets the singleton React Query Builder store instance. * DevTools are enabled if either: * - globalThis.__RQB_DEVTOOLS__ is truthy * - window.__RQB_DEVTOOLS__ is truthy */ function getRqbStore(devTools) { if (!_store) { var _globalThis; _store = configureRqbStore(devTools || ((_globalThis = globalThis) === null || _globalThis === void 0 ? void 0 : _globalThis.__RQB_DEVTOOLS__)); } return _store; } /** * Injects a slice into the React Query Builder store. Useful for extensions * that need to integrate their own state management. */ const injectSlice = (slice) => getRqbStore().addSlice(slice); //#endregion //#region src/redux/selectors.ts /** * Given a `qbId` (passed to every component as part of the `schema` prop), returns * a Redux selector for use with {@link useQueryBuilderSelector}. * * Note that {@link useQueryBuilderQuery} is a more concise way of accessing the * query for the nearest ancestor {@link QueryBuilder} component. */ const getQuerySelectorById = (qbId) => (state) => queriesSlice.selectors.getQuerySelectorById({ queries: state.queries }, qbId); //#endregion //#region src/redux/hooks.ts /** * A Redux `useSelector` hook for RQB's internal store. See also {@link getQuerySelectorById}. * * **TIP:** Prefer {@link useQueryBuilderQuery} if you only need to access the query object * for the nearest ancestor {@link QueryBuilder} component. * * @group Hooks */ const useQueryBuilderSelector = (selector, other) => { const rqbContext = React.useContext(QueryBuilderContext); const result = useRQB_INTERNAL_QueryBuilderSelector(selector, other); return result !== null && result !== void 0 ? result : rqbContext === null || rqbContext === void 0 ? void 0 : rqbContext.initialQuery; }; /** * Retrieves the full, latest query object for the nearest ancestor {@link QueryBuilder} * component. * * The optional parameter should only be used when retrieving a query object from a different * {@link QueryBuilder} than the nearest ancestor. It can be a full props object as passed * to a custom component or any object matching the interface `{ schema: { qbId: string } }`. * * Must follow React's [Rules of Hooks](https://react.dev/warnings/invalid-hook-call-warning). * * @group Hooks */ const useQueryBuilderQuery = (props) => { var _useRQB_INTERNAL_Quer, _ref, _props$schema$qbId; const rqbContext = React.useContext(QueryBuilderContext); return (_useRQB_INTERNAL_Quer = useRQB_INTERNAL_QueryBuilderSelector(getQuerySelectorById((_ref = (_props$schema$qbId = props === null || props === void 0 ? void 0 : props.schema.qbId) !== null && _props$schema$qbId !== void 0 ? _props$schema$qbId : rqbContext.qbId) !== null && _ref !== void 0 ? _ref : ""))) !== null && _useRQB_INTERNAL_Quer !== void 0 ? _useRQB_INTERNAL_Quer : rqbContext === null || rqbContext === void 0 ? void 0 : rqbContext.initialQuery; }; //#endregion //#region src/components/QueryBuilder.useQueryBuilderSchema.ts const defaultValidationResult = {}; const defaultValidationMap = {}; const defaultDisabledPaths = []; const icCombinatorPropObject = {}; const defaultGetValueEditorSeparator = () => null; const defaultGetRuleOrGroupClassname = () => ""; const defaultOnAddMoveRemove = () => true; // istanbul ignore next const defaultOnLog = (...params) => { console.log(...params); }; /** * For given {@link QueryBuilderProps} and setup values from {@link useQueryBuilderSetup}, * prepares and returns all values required to render a query builder. * * @group Hooks */ function useQueryBuilderSchema(props, setup) { var _props$maxLevels, _ref, _ref2, _props$independentCom; const { query: queryProp, defaultQuery: defaultQueryProp, getValueEditorSeparator = defaultGetValueEditorSeparator, getRuleClassname = defaultGetRuleOrGroupClassname, getRuleGroupClassname = defaultGetRuleOrGroupClassname, onAddRule = defaultOnAddMoveRemove, onAddGroup = defaultOnAddMoveRemove, onMoveRule = defaultOnAddMoveRemove, onMoveGroup = defaultOnAddMoveRemove, onGroupRule = defaultOnAddMoveRemove, onGroupGroup = defaultOnAddMoveRemove, onRemove = defaultOnAddMoveRemove, onQueryChange, showCombinatorsBetweenRules: showCombinatorsBetweenRulesProp = false, showNotToggle: showNotToggleProp = false, showShiftActions: showShiftActionsProp = false, showCloneButtons: showCloneButtonsProp = false, showLockButtons: showLockButtonsProp = false, showMuteButtons: showMuteButtonsProp = false, suppressStandardClassnames: suppressStandardClassnamesProp = false, resetOnFieldChange: resetOnFieldChangeProp = true, resetOnOperatorChange: resetOnOperatorChangeProp = false, autoSelectField: autoSelectFieldProp = true, autoSelectOperator: autoSelectOperatorProp = true, autoSelectValue: autoSelectValueProp = true, addRuleToNewGroups: addRuleToNewGroupsProp = false, listsAsArrays: listsAsArraysProp = false, parseNumbers = false, disabled = false, validator, onLog = defaultOnLog, idGenerator, accessibleDescriptionGenerator = generateAccessibleDescription } = props; const { qbId, rqbContext: incomingRqbContext, fields, fieldMap, combinators, getOperatorsMain, getMatchModesMain, getRuleDefaultOperator, getSubQueryBuilderPropsMain, getValueEditorTypeMain, getValueSourcesMain, getValuesMain, getRuleDefaultValue, getInputTypeMain, createRule, createRuleGroup } = setup; const { controlClassnames, controlElements: controls, debugMode, enableDragAndDrop, enableMountQueryChange, translations } = incomingRqbContext; const showCombinatorsBetweenRules = !!showCombinatorsBetweenRulesProp; const showNotToggle = !!showNotToggleProp; const showShiftActions = !!showShiftActionsProp; const showCloneButtons = !!showCloneButtonsProp; const showLockButtons = !!showLockButtonsProp; const showMuteButtons = !!showMuteButtonsProp; const resetOnFieldChange = !!resetOnFieldChangeProp; const resetOnOperatorChange = !!resetOnOperatorChangeProp; const autoSelectField = !!autoSelectFieldProp; const autoSelectOperator = !!autoSelectOperatorProp; const autoSelectValue = !!autoSelectValueProp; const addRuleToNewGroups = !!addRuleToNewGroupsProp; const listsAsArrays = !!listsAsArraysProp; const suppressStandardClassnames = !!suppressStandardClassnamesProp; const maxLevels = ((_props$maxLevels = props.maxLevels) !== null && _props$maxLevels !== void 0 ? _props$maxLevels : 0) > 0 ? Number(props.maxLevels) : Infinity; const log = useCallback((...params) => { if (debugMode) onLog(...params); }, [debugMode, onLog]); useControlledOrUncontrolled({ defaultQuery: defaultQueryProp, queryProp }); const queryBuilderStore = useRQB_INTERNAL_QueryBuilderStore(); const queryBuilderDispatch = useRQB_INTERNAL_QueryBuilderDispatch(); const querySelector = useMemo(() => getQuerySelectorById(qbId), [qbId]); const storeQuery = useQueryBuilderSelector(querySelector); const getQuery = useCallback(() => querySelector(queryBuilderStore.getState()), [queryBuilderStore, querySelector]); const fallbackQuery = useMemo(() => createRuleGroup(), [createRuleGroup]); const candidateQuery = (_ref = (_ref2 = queryProp !== null && queryProp !== void 0 ? queryProp : storeQuery) !== null && _ref2 !== void 0 ? _ref2 : defaultQueryProp) !== null && _ref !== void 0 ? _ref : fallbackQuery; const rootGroup = candidateQuery.id ? candidateQuery : prepareRuleGroup(candidateQuery, { idGenerator }); const [initialQuery] = useState(rootGroup); const rqbContext = useMemo(() => _objectSpread2(_objectSpread2({}, incomingRqbContext), {}, { initialQuery }), [incomingRqbContext, initialQuery]); useEffect(() => { if (!!queryProp && !Object.is(queryProp, storeQuery)) queryBuilderDispatch(_RQB_INTERNAL_dispatchThunk({ payload: { qbId, query: queryProp }, onQueryChange: void 0 })); }, [ queryProp, qbId, storeQuery, queryBuilderDispatch ]); const independentCombinators = useMemo(() => isRuleGroupTypeIC(rootGroup), [rootGroup]); const invalidIC = !!props.independentCombinators && !independentCombinators; useDeprecatedProps("independentCombinators", invalidIC || !invalidIC && ((_props$independentCom = props.independentCombinators) !== null && _props$independentCom !== void 0 ? _props$independentCom : "not present") !== "not present", invalidIC ? "invalid" : "unnecessary"); const hasRunMountQueryChange = useRef(false); useEffect(() => { if (hasRunMountQueryChange.current) return; hasRunMountQueryChange.current = true; queryBuilderDispatch(_RQB_INTERNAL_dispatchThunk({ payload: { qbId, query: rootGroup }, onQueryChange: enableMountQueryChange && typeof onQueryChange === "function" ? onQueryChange : void 0 })); }, [ enableMountQueryChange, onQueryChange, qbId, queryBuilderDispatch, rootGroup ]); /** * Updates the redux-based query, then calls `onQueryChange` with the updated * query object. NOTE: `useCallback` is only effective here when the user's * `onQueryChange` handler is undefined or has a stable reference, which usually * means that it's wrapped in its own `useCallback`. */ const dispatchQuery = useCallback((newQuery) => { queryBuilderDispatch(_RQB_INTERNAL_dispatchThunk({ payload: { qbId, query: newQuery }, onQueryChange })); }, [ onQueryChange, qbId, queryBuilderDispatch ]); const disabledPaths = Array.isArray(disabled) && disabled || defaultDisabledPaths; const queryDisabled = disabled === true; const rootGroupDisabled = rootGroup.disabled || disabledPaths.some((p) => p.length === 0); const onRuleAdd = useCallback((rule, parentPath, context) => { var _newRule$combinatorPr; const queryLocal = getQuerySelectorById(qbId)(queryBuilderStore.getState()); // istanbul ignore if if (!queryLocal) return; if (pathIsDisabled(parentPath, queryLocal) || queryDisabled) { log({ qbId, type: LogType.parentPathDisabled, rule, parentPath, query: queryLocal }); return; } const nextRule = onAddRule(rule, parentPath, queryLocal, context); if (!nextRule) { log({ qbId, type: LogType.onAddRuleFalse, rule, parentPath, query: queryLocal }); return; } const newRule = nextRule === true ? rule : nextRule; const newQuery = add(queryLocal, newRule, parentPath, { combinators, combinatorPreceding: (_newRule$combinatorPr = newRule.combinatorPreceding) !== null && _newRule$combinatorPr !== void 0 ? _newRule$combinatorPr : void 0, idGenerator }); log({ qbId, type: LogType.add, query: queryLocal, newQuery, newRule, parentPath }); dispatchQuery(newQuery); }, [ combinators, dispatchQuery, idGenerator, log, onAddRule, qbId, queryBuilderStore, queryDisabled ]); const onGroupAdd = useCallback((ruleGroup, parentPath, context) => { var _combinatorPreceding; if (parentPath.length >= maxLevels) return; const queryLocal = getQuerySelectorById(qbId)(queryBuilderStore.getState()); // istanbul ignore if if (!queryLocal) return; if (pathIsDisabled(parentPath, queryLocal) || queryDisabled) { log({ qbId, type: LogType.parentPathDisabled, ruleGroup, parentPath, query: queryLocal }); return; } const nextGroup = onAddGroup(ruleGroup, parentPath, queryLocal, context); if (!nextGroup) { log({ qbId, type: LogType.onAddGroupFalse, ruleGroup, parentPath, query: queryLocal }); return; } const newGroup = nextGroup === true ? ruleGroup : nextGroup; const newQuery = add(queryLocal, newGroup, parentPath, { combinators, combinatorPreceding: (_combinatorPreceding = newGroup.combinatorPreceding) !== null && _combinatorPreceding !== void 0 ? _combinatorPreceding : void 0, idGenerator }); log({ qbId, type: LogType.add, query: queryLocal, newQuery, newGroup, parentPath }); dispatchQuery(newQuery); }, [ combinators, dispatchQuery, idGenerator, log, maxLevels, onAddGroup, qbId, queryBuilderStore, queryDisabled ]); const onPropChange = useCallback((prop, value, path) => { const queryLocal = getQuerySelectorById(qbId)(queryBuilderStore.getState()); // istanbul ignore if if (!queryLocal) return; if (pathIsDisabled(path, queryLocal) && prop !== "disabled" || queryDisabled) { log({ qbId, type: LogType.pathDisabled, path, prop, value, query: queryLocal }); return; } const newQuery = update(queryLocal, prop, value, path, { resetOnFieldChange, resetOnOperatorChange, getRuleDefaultOperator, getValueSources: getValueSourcesMain, getRuleDefaultValue, getMatchModes: getMatchModesMain }); log({ qbId, type: LogType.update, query: queryLocal, newQuery, prop, value, path }); dispatchQuery(newQuery); }, [ dispatchQuery, getMatchModesMain, getRuleDefaultOperator, getRuleDefaultValue, getValueSourcesMain, log, qbId, queryBuilderStore, queryDisabled, resetOnFieldChange, resetOnOperatorChange ]); const onRuleOrGroupRemove = useCallback((path, context) => { const queryLocal = getQuerySelectorById(qbId)(queryBuilderStore.getState()); // istanbul ignore if if (!queryLocal) return; if (pathIsDisabled(path, queryLocal) || queryDisabled) { log({ qbId, type: LogType.pathDisabled, path, query: queryLocal }); return; } const ruleOrGroup = findPath(path, queryLocal); // istanbul ignore else if (ruleOrGroup) if (onRemove(ruleOrGroup, path, queryLocal, context)) { const newQuery = remove(queryLocal, path); log({ qbId, type: LogType.remove, query: queryLocal, newQuery, path, ruleOrGroup }); dispatchQuery(newQuery); } else log({ qbId, type: LogType.onRemoveFalse, ruleOrGroup, path, query: queryLocal }); }, [ dispatchQuery, log, onRemove, qbId, queryBuilderStore, queryDisabled ]); const moveRule = useCallback((oldPath, newPath, clone, context) => { const queryLocal = getQuerySelectorById(qbId)(queryBuilderStore.getState()); // istanbul ignore if if (!queryLocal) return; if (pathIsDisabled(oldPath, queryLocal) || queryDisabled) { log({ qbId, type: LogType.pathDisabled, oldPath, newPath, query: queryLocal }); return; } const nextQuery = move(queryLocal, oldPath, newPath, { clone, combinators, idGenerator }); const ruleOrGroup = findPath(oldPath, queryLocal); const isGroup = isRuleGroup(ruleOrGroup); const callbackResult = (isGroup ? onMoveGroup : onMoveRule)(ruleOrGroup, oldPath, newPath, queryLocal, nextQuery, { clone, combinators }, context); if (!callbackResult) { log({ qbId, type: isGroup ? LogType.onMoveGroupFalse : LogType.onMoveRuleFalse, ruleOrGroup, oldPath, newPath, clone, query: queryLocal, nextQuery }); return; } const newQuery = isRuleGroup(callbackResult) ? callbackResult : nextQuery; log({ qbId, type: LogType.move, query: queryLocal, newQuery, oldPath, newPath, clone }); dispatchQuery(newQuery); }, [ combinators, dispatchQuery, idGenerator, log, onMoveGroup, onMoveRule, qbId, queryBuilderStore, queryDisabled ]); const groupRule = useCallback((sourcePath, targetPath, clone, context) => { const queryLocal = getQuerySelectorById(qbId)(queryBuilderStore.getState()); // istanbul ignore if if (!queryLocal) return; if (pathIsDisabled(sourcePath, queryLocal) || queryDisabled) { log({ qbId, type: LogType.pathDisabled, sourcePath, targetPath, query: queryLocal }); return; } const nextQuery = group(queryLocal, sourcePath, targetPath, { clone, combinators, idGenerator }); const ruleOrGroup = findPath(sourcePath, queryLocal); const isGroup = isRuleGroup(ruleOrGroup); const callbackResult = (isGroup ? onGroupGroup : onGroupRule)(ruleOrGroup, sourcePath, targetPath, queryLocal, nextQuery, { clone, combinators }, context); if (!callbackResult) { log({ qbId, type: isGroup ? LogType.onGroupGroupFalse : LogType.onGroupRuleFalse, ruleOrGroup, sourcePath, targetPath, clone, query: queryLocal, nextQuery }); return; } const newQuery = isRuleGroup(callbackResult) ? callbackResult : nextQuery; log({ qbId, type: LogType.group, query: queryLocal, newQuery, sourcePath, targetPath, clone }); dispatchQuery(newQuery); }, [ combinators, dispatchQuery, idGenerator, log, onGroupGroup, onGroupRule, qbId, queryBuilderStore, queryDisabled ]); const { validationResult, validationMap } = useMemo(() => { const validationResult$1 = typeof validator === "function" && rootGroup ? validator(rootGroup) : defaultValidationResult; return { validationResult: validationResult$1, validationMap: typeof validationResult$1 === "boolean" ? defaultValidationMap : validationResult$1 }; }, [rootGroup, validator]); const dndEnabledAttr = enableDragAndDrop ? "enabled" : "disabled"; const inlineCombinatorsAttr = independentCombinators || showCombinatorsBetweenRules ? "enabled" : "disabled"; const combinatorPropObject = useMemo(() => typeof rootGroup.combinator === "string" ? { combinator: rootGroup.combinator } : icCombinatorPropObject, [rootGroup.combinator]); const wrapperClassName = useMemo(() => clsx(suppressStandardClassnames || standardClassnames.queryBuilder, clsx(controlClassnames.queryBuilder), queryDisabled && controlClassnames.disabled, typeof validationResult === "boolean" && validationResult && controlClassnames.valid, typeof validationResult === "boolean" && !validationResult && controlClassnames.invalid, suppressStandardClassnames || { [standardClassnames.disabled]: queryDisabled, [standardClassnames.valid]: typeof validationResult === "boolean" && validationResult, [standardClassnames.invalid]: typeof validationResult === "boolean" && !validationResult }), [ controlClassnames.disabled, controlClassnames.invalid, controlClassnames.queryBuilder, controlClassnames.valid, queryDisabled, suppressStandardClassnames, validationResult ]); /** * This function overrides `createRuleGroup` from `useQueryBuilderSetup`, removing the * requirement to pass a `boolean` parameter. If `independentCombinators` is `true`, it will * always create a `RuleGroupTypeIC` even if called with no parameters. (We have to override * it here because `independentCombinators` is not evaluated in `useQueryBuilderSetup`.) */ const createRuleGroupOverride = useCallback((ic) => createRuleGroup(ic !== null && ic !== void 0 ? ic : independentCombinators), [createRuleGroup, independentCombinators]); const schema = useMemo(() => ({ addRuleToNewGroups, accessibleDescriptionGenerator, autoSelectField, autoSelectOperator, autoSelectValue, classNames: controlClassnames, combinators, controls, createRule, createRuleGroup: createRuleGroupOverride, disabledPaths, enableDragAndDrop, fieldMap, fields, dispatchQuery, getQuery, getInputType: getInputTypeMain, getOperators: getOperatorsMain, getMatchModes: getMatchModesMain, getRuleClassname, getRuleGroupClassname, getSubQueryBuilderProps: getSubQueryBuilderPropsMain, getValueEditorSeparator, getValueEditorType: getValueEditorTypeMain, getValues: getValuesMain, getValueSources: getValueSourcesMain, independentCombinators, listsAsArrays, maxLevels, parseNumbers, qbId, showCloneButtons, showCombinatorsBetweenRules, showLockButtons, showMuteButtons, showNotToggle, showShiftActions, suppressStandardClassnames, validationMap }), [ accessibleDescriptionGenerator, addRuleToNewGroups, autoSelectField, autoSelectOperator, autoSelectValue, combinators, controlClassnames, controls, createRule, createRuleGroupOverride, disabledPaths, dispatchQuery, enableDragAndDrop, fieldMap, fields, getInputTypeMain, getOperatorsMain, getMatchModesMain, getQuery, getRuleClassname, getRuleGroupClassname, getSubQueryBuilderPropsMain, getValueEditorSeparator, getValueEditorTypeMain, getValuesMain, getValueSourcesMain, independentCombinators, listsAsArrays, maxLevels, parseNumbers, qbId, showCloneButtons, showCombinatorsBetweenRules, showLockButtons, showMuteButtons, showNotToggle, showShiftActions, suppressStandardClassnames, validationMap ]); return { actions: useMemo(() => ({ moveRule, onGroupAdd, onGroupRemove: onRuleOrGroupRemove, onPropChange, onRuleAdd, onRuleRemove: onRuleOrGroupRemove, groupRule }), [ groupRule, moveRule, onGroupAdd, onPropChange, onRuleAdd, onRuleOrGroupRemove ]), rootGroup, rootGroupDisabled, queryDisabled, rqbContext, schema, translations, wrapperClassName, dndEnabledAttr, inlineCombinatorsAttr, combinatorPropObject }; } //#endregion //#region src/components/QueryBuilder.useQueryBuilderSetup.ts const getFirstOptionsFrom = (opts, r, listsAsArrays) => { const firstOption = getFirstOption(opts); if (r.operator === "between" || r.operator === "notBetween") { const valueAsArray = [firstOption, firstOption]; return listsAsArrays ? valueAsArray : joinWith(valueAsArray.map((v) => v !== null && v !== void 0 ? v : ""), ","); } return firstOption; }; /** * Massages the props as necessary and prepares the basic update/generate methods * for use by the {@link QueryBuilder} component. * * @group Hooks */ const useQueryBuilderSetup = (props) => { var _props$query; const [qbId] = useState(generateID); const { fields: fieldsProp, baseField, operators: operatorsProp, baseOperator, combinators: combinatorsProp, baseCombinator, translations: translationsProp, enableMountQueryChange: enableMountQueryChangeProp = true, controlClassnames: controlClassnamesProp, controlElements: controlElementsProp, getDefaultField, getDefaultOperator, getDefaultValue, getMatchModes, getOperators, getSubQueryBuilderProps, getValueEditorType, getValueSources, getInputType, getValues, autoSelectField = true, autoSelectOperator = true, autoSelectValue = true, addRuleToNewGroups = false, enableDragAndDrop: enableDragAndDropProp, listsAsArrays = false, debugMode: debugModeProp = false, idGenerator = generateID } = props; const [initialQueryProp] = useState((_props$query = props.query) !== null && _props$query !== void 0 ? _props$query : props.defaultQuery); const rqbContext = useMergedContext({ controlClassnames: controlClassnamesProp, controlElements: controlElementsProp, debugMode: debugModeProp, enableDragAndDrop: enableDragAndDropProp, enableMountQueryChange: enableMountQueryChangeProp, translations: translationsProp, initialQuery: initialQueryProp, qbId, finalize: true }); const { translations } = rqbContext; const { fields, fieldMap } = useFields({ fields: fieldsProp, baseField, autoSelectField, translations }); const { optionList: combinators } = useMemo(() => prepareOptionList({ optionList: combinatorsProp !== null && combinatorsProp !== void 0 ? combinatorsProp : defaultCombinators, labelMap: defaultCombinatorLabelMap, baseOption: baseCombinator, autoSelectOption: true }), [baseCombinator, combinatorsProp]); const { optionList: operators } = useMemo(() => prepareOptionList({ optionList: operatorsProp !== null && operatorsProp !== void 0 ? operatorsProp : defaultOperators, placeholder: translations.operators, labelMap: defaultOperatorLabelMap, baseOption: baseOperator, autoSelectOption: autoSelectOperator }), [ autoSelectOperator, baseOperator, operatorsProp, translations.operators ]); const getOperatorsMain = useCallback((field, { fieldData }) => { var _ref, _fieldData$operators; return prepareOptionList({ optionList: (_ref = (_fieldData$operators = fieldData === null || fieldData === void 0 ? void 0 : fieldData.operators) !== null && _fieldData$operators !== void 0 ? _fieldData$operators : getOperators === null || getOperators === void 0 ? void 0 : getOperators(field, { fieldData })) !== null && _ref !== void 0 ? _ref : operators, placeholder: translations.operators, baseOption: baseOperator, labelMap: defaultOperatorLabelMap, autoSelectOption: autoSelectOperator }).optionList; }, [ autoSelectOperator, baseOperator, getOperators, operators, translations.operators ]); const getRuleDefaultOperator = useCallback((field) => { var _getOperatorsMain, _getFirstOption; const fieldData = fieldMap[field]; if (fieldData === null || fieldData === void 0 ? void 0 : fieldData.defaultOperator) return fieldData.defaultOperator; if (getDefaultOperator) return typeof getDefaultOperator === "function" ? getDefaultOperator(field, { fieldData }) : getDefaultOperator; return (_getFirstOption = getFirstOption((_getOperatorsMain = getOperatorsMain(field, { fieldData })) !== null && _getOperatorsMain !== void 0 ? _getOperatorsMain : [])) !== null && _getFirstOption !== void 0 ? _getFirstOption : ""; }, [ fieldMap, getDefaultOperator, getOperatorsMain ]); const getValueEditorTypeMain = useCallback((field, operator, { fieldData }) => { var _getValueEditorType; if (fieldData.valueEditorType) { if (typeof fieldData.valueEditorType === "function") return fieldData.valueEditorType(operator); return fieldData.valueEditorType; } return (_getValueEditorType = getValueEditorType === null || getValueEditorType === void 0 ? void 0 : getValueEditorType(field, operator, { fieldData })) !== null && _getValueEditorType !== void 0 ? _getValueEditorType : "text"; }, [getValueEditorType]); const getValueSourcesMain = useCallback((field, operator, _misc) => getValueSourcesUtil(fieldMap[field], operator, getValueSources), [fieldMap, getValueSources]); const getMatchModesMain = useCallback((field, _misc) => getMatchModesUtil(fieldMap[field], getMatchModes), [fieldMap, getMatchModes]); const getSubQueryBuilderPropsMain = useCallback((field, misc) => { var _getSubQueryBuilderPr; return (_getSubQueryBuilderPr = getSubQueryBuilderProps === null || getSubQueryBuilderProps === void 0 ? void 0 : getSubQueryBuilderProps(field, misc)) !== null && _getSubQueryBuilderPr !== void 0 ? _getSubQueryBuilderPr : {}; }, [getSubQueryBuilderProps]); const getValuesMain = useCallback((field, operator, { fieldData }) => { var _ref2, _fieldData$values; return prepareOptionList({ optionList: (_ref2 = (_fieldData$values = fieldData === null || fieldData === void 0 ? void 0 : fieldData.values) !== null && _fieldData$values !== void 0 ? _fieldData$values : getValues === null || getValues === void 0 ? void 0 : getValues(field, operator, { fieldData })) !== null && _ref2 !== void 0 ? _ref2 : [], placeholder: translations.values, autoSelectOption: autoSelectValue }).optionList; }, [ autoSelectValue, getValues, translations.values ]); const getRuleDefaultValue = useCallback((r) => { var _fieldMap; const fieldData = (_fieldMap = fieldMap[r.field]) !== null && _fieldMap !== void 0 ? _fieldMap : {}; if ((fieldData === null || fieldData === void 0 ? void 0 : fieldData.defaultValue) !== void 0 && fieldData.defaultValue !== null) return fieldData.defaultValue; else if (getDefaultValue) return getDefaultValue(r, { fieldData }); let value = ""; const values = getValuesMain(r.field, r.operator, { fieldData }); if (r.valueSource === "field") { const filteredFields = filterFieldsByComparator(fieldData, fields, r.operator); value = filteredFields.length > 0 ? getFirstOptionsFrom(filteredFields, r, listsAsArrays) : ""; } else if (values.length > 0) { const editorType = getValueEditorTypeMain(r.field, r.operator, { fieldData }); if (editorType === "multiselect") value = listsAsArrays ? [] : ""; else if (editorType === "select" || editorType === "radio") value = getFirstOptionsFrom(values, r, listsAsArrays); } else if (getValueEditorTypeMain(r.field, r.operator, { fieldData }) === "checkbox") value = false; return value; }, [ fieldMap, fields, getDefaultValue, getValueEditorTypeMain, getValuesMain, listsAsArrays ]); const getInputTypeMain = useCallback((field, operator, { fieldData }) => { if (getInputType) { const inputType = getInputType(field, operator, { fieldData }); if (inputType) return inputType; } return "text"; }, [getInputType]); const createRule = useCallback(() => { var _getFirstOption2; let field = ""; const flds = fields; /* istanbul ignore else */ if ((flds === null || flds === void 0 ? void 0 : flds.length) > 0 && flds[0]) { const fo = getFirstOption(flds); /* istanbul ignore else */ if (fo) field = fo; } if (getDefaultField) if (typeof getDefaultField === "function") { const df = getDefaultField(flds); /* istanbul ignore else */ if (df) field = df; } else field = getDefaultField; const operator = getRuleDefaultOperator(field); const valueSource = (_getFirstOption2 = getFirstOption(getValueSourcesMain(field, operator, { fieldData: getOption(flds, field) }))) !== null && _getFirstOption2 !== void 0 ? _getFirstOption2 : "value"; const matchMode = getFirstOption(getMatchModesMain(field, { fieldData: getOption(flds, field) })); const newRule = _objectSpread2({ id: idGenerator(), field, operator, valueSource, value: "" }, matchMode ? { match: { mode: matchMode, threshold: 1 } } : null); const value = getRuleDefaultValue(newRule); return _objectSpread2(_objectSpread2({}, newRule), {}, { value }); }, [ fields, getDefaultField, getMatchModesMain, getRuleDefaultOperator, getRuleDefaultValue, getValueSourcesMain, idGenerator ]); return { qbId, rqbContext, fields, fieldMap, combinators, getMatchModesMain, getOperatorsMain, getRuleDefaultOperator, getSubQueryBuilderPropsMain, getValueEditorTypeMain, getValueSourcesMain, getValuesMain, getRuleDefaultValue, getInputTypeMain, createRule, createRuleGroup: useCallback((independentCombinators) => { var _getFirstOption3; if (independentCombinators) return { id: idGenerator(), rules: addRuleToNewGroups ? [createRule()] : [], not: false }; return { id: idGenerator(), rules: addRuleToNewGroups ? [createRule()] : [], combinator: (_getFirstOption3 = getFirstOption(combinators)) !== null && _getFirstOption3 !== void 0 ? _getFirstOption3 : "", not: false }; }, [ addRuleToNewGroups, combinators, createRule, idGenerator ]) }; }; //#endregion //#region src/components/QueryBuilder.useQueryBuilder.ts /** * Calls {@link useQueryBuilderSetup} to massage the props and prepare basic * update/generate methods, then passes the result to {@link useQueryBuilderSchema} * to prepare and return all values required to render {@link QueryBuilder}. * * @group Hooks */ const useQueryBuilder = (props) => useQueryBuilderSchema(props, useQueryBuilderSetup(props)); //#endregion //#region src/components/QueryBuilderContext.ts /** * Context provider for {@link QueryBuilder}. Any descendant query builders * will inherit the props from a context provider. */ const QueryBuilderContext = createContext({}); //#endregion //#region src/components/RuleGroup.tsx /** * Default component to display {@link RuleGroupType} and {@link RuleGroupTypeIC} * objects. This is actually a small wrapper around {@link RuleGroupHeaderComponents} * and {@link RuleGroupBodyComponents}. * * @group Components */ const RuleGroup = React.memo(function RuleGroup$1(props) { const rg = useRuleGroup(props); const { schema: { controls: { ruleGroupBodyElements: RuleGroupBodyElements, ruleGroupHeaderElements: RuleGroupHeaderElements } } } = rg; const addRule = useStopEventPropagation(rg.addRule); const addGroup = useStopEventPropagation(rg.addGroup); const cloneGroup = useStopEventPropagation(rg.cloneGroup); const toggleLockG