:toc:
:toc-placement!:
toc::[]

ifdef::env-github[]
:tip-caption: :bulb:
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
:caution-caption: :fire:
:warning-caption: :warning:
endif::[]

:queryString:  https://github.com/ukrbublik/react-awesome-query-builder/#querystring
:i18n:         https://github.com/ukrbublik/react-awesome-query-builder/#i18n
:config1:      https://github.com/ukrbublik/react-awesome-query-builder/tree/master/packages/sandbox_simple/src/demo/config.jsx
:config2:      https://github.com/ukrbublik/react-awesome-query-builder/tree/master/packages/sandbox/src/demo/config.tsx
:config3:      https://github.com/ukrbublik/react-awesome-query-builder/tree/master/packages/examples/src/demo/config/index.tsx
:funcs:        https://github.com/ukrbublik/react-awesome-query-builder/tree/master/packages/core/modules/config/funcs.js
:renderConjs:  https://github.com/ukrbublik/react-awesome-query-builder/blob/master/packages/antd/modules/config/index.jsx#L21
:renderItem:   https://github.com/ukrbublik/react-awesome-query-builder/blob/master/packages/ui/modules/components/item/Item.jsx#L167
:config_ser:   https://github.com/ukrbublik/react-awesome-query-builder/blob/master/packages/sandbox_next/lib/config_ser.js
:d_ts:         https://github.com/ukrbublik/react-awesome-query-builder/blob/master/packages/core/modules/index.d.ts
:ts-pattern:   https://github.com/gvergnaud/ts-pattern

:number-format: https://s-yadav.github.io/react-number-format/docs/numeric_format

= Config format

Has 8 sections:

[source,javascript]
----
{conjunctions, operators, widgets, types, funcs, settings, fields, ctx}
----

Each section is described below.

Usually it's enough to just reuse link:#basic-config[basic config], provide your own link:#configfields[fields] and maybe change some link:#configsettings[settings]. +
Optionally you can override some options in basic config or add your own types/widgets/operators (or even conjunctions like XOR or NOR).

There are functions for building query string: `formatConj`, `formatValue`, `formatOp`, `formatField`, `formatFunc` which are used for `QbUtils.queryString()`. +
They have common param `isForDisplay` - false by default, true will be used for {queryString}[`QbUtils.queryString(immutableTree, config, true)`] (see 3rd param true). +
Also there are similar `mongoConj`, `mongoFormatOp`, `mongoFormatValue`, `mongoFunc`, `mongoFormatFunc`, `mongoArgsAsObject` for building MongoDb query with `QbUtils.mongodbFormat()`. +
And `sqlFormatConj`, `sqlOp`, `sqlOps`, `sqlFormatOp`, `sqlFormatValue`, `sqlFormatReverse`, `formatSpelField`, `sqlFunc`, `sqlFormatFunc`, `sqlImport` for building SQL where query with `QbUtils.sqlFormat()`. +
And `spelFormatConj`, `spelOp`, `spelFormatOp`, `spelFormatValue`, `spelFormatReverse`, `spelFunc`, `spelFormatFunc` for building query in (https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/expressions.html)[Spring Expression Language (SpEL)] with `QbUtils.spelFormat()`. +
And `jsonLogic` for building http://jsonlogic.com[JsonLogic] with `QbUtils.jsonLogicFormat()`. +

TIP: Example 1: {config1}[`config for sandbox_simple`]

TIP: Example 2: {config2}[`config for sandbox`]

{nbsp} +

[[basicconfig]]
== Basic config

- Use `BasicConfig` for simple vanilla UI
- Use `AntdConfig` for more advanced UI with https://ant.design/[AntDesign] widgets
- Use `MuiConfig` for https://mui.com/[MUI] widgets
- Use `MaterialConfig` for https://v4.mui.com/[Material-UI v4] widgets
- Use `BootstrapConfig` for https://reactstrap.github.io/[Bootstrap] widgets
- Use `FluentUIConfig` for https://developer.microsoft.com/en-us/fluentui[Fluent UI] widgets
[source,javascript]
----
import {BasicConfig} from '@react-awesome-query-builder/ui';
import {AntdConfig} from '@react-awesome-query-builder/antd';
import {MuiConfig} from '@react-awesome-query-builder/mui';
import {MaterialConfig} from '@react-awesome-query-builder/material';
import {BootstrapConfig} from "@react-awesome-query-builder/bootstrap";
import {FluentUIConfig} from "@react-awesome-query-builder/fluent";
const InitialConfig = BasicConfig; // or AntdConfig or MuiConfig or BootstrapConfig or FluentUIConfig

const myConfig = {
  ...InitialConfig, // reuse basic config

  fields: {
    stock: {
        label: 'In stock',
        type: 'boolean',
    },
    // ... my other fields
  }
};
----

What is in basic config?
[source,javascript]
----
const {
  conjunctions: {
    AND, 
    OR
  },
  operators: {
    equal,
    not_equal,
    less,
    less_or_equal,
    greater,
    greater_or_equal,
    like,
    not_like,
    starts_with,
    ends_with,
    between,
    not_between,
    is_null,
    is_not_null,
    is_empty,
    is_not_empty,
    select_equals, // like `equal`, but for select
    select_not_equals,
    select_any_in,
    select_not_any_in,
    multiselect_contains,
    multiselect_not_contains,
    multiselect_equals, // like `equal`, but for multiselect
    multiselect_not_equals,
    proximity, // complex operator with options
  },
  widgets: {
    text,
    textarea, // multiline text
    number,
    price, // same as number but with decimal separator etc.
    slider,
    rangeslider, // missing in `BasicConfig`, `BootstrapConfig`, `FluentUIConfig`
    select,
    multiselect,
    treeselect, // present only in `AntdConfig`
    treemultiselect, // present only in `AntdConfig`
    date,
    time,
    datetime,
    boolean,
    field, // to compare field with another field of same type
    func, // to compare field with result of function
  },
  types: {
    text,
    number,
    date,
    time,
    datetime,
    select,
    multiselect,
    treeselect,
    treemultiselect,
    boolean,
  },
  settings,
  ctx,
} = AntdConfig;
----



{nbsp} +

== Sections

[[configfields]]
=== config.fields

Example:
[source,javascript]
----
{
  // simple
  qty: {
    type: 'number',
    label: 'Quantity',
    fieldSettings: {
      min: 0,
      max: 100,
    }
  },
  // complex
  user: {
    type: '!struct', // special keyword for complex fields
    label: 'User',
    subfields: {
      // subfields of complex field
      name: {
        type: 'text',
        label: 'Name',
        label2: 'User name', //optional, see below
        fieldSettings: {
          validateValue: (val, _fieldSettings) => (val.length <= 20),
        }
      },
    },
  },
  ...
}
----

[cols="1m,1,1,5a",options="header"]
|===
|key |required |default |meaning
|type |+ | |One of types described in link:#configtypes[config.types] or `!struct`/`!group` for complex field +
  (use `!struct` for objects, `!group` for arrays)
|mode | | |For `!group` type, values are: `some`/`array` +
  `some` is light mode (default), at least one subrule should match +
   (for export https://docs.mongodb.com/manual/reference/operator/query/elemMatch/[elemMatch] will be used in MongoDb, http://jsonlogic.com/operations.html#all-none-and-some[some] in JsonLogic) +
   `array` is extended mode, user can choose one of group operators (`some`/`all`/`none`/`count >/</==/...`)
|subfields |+ for `!struct`/`!group` type | |Config for subfields of complex field (multiple nesting is supported)
|label |+ | |Label to be displayed in field list +
  (If not specified, fields's key will be used instead)
|label2 | | |Can be optionally specified for nested fields. +
  By default, if nested field is selected (eg. `name` of `user` in example above), `<FieldDropdown>` component will show `name`. +
  Just `name` can be confusing, so can be overriden by setting `label2` to something like `User name`. +
  As alternative, you can use `<FieldCascader>` component which handles nested fields right. See `renderField` in link:#configsettings[settings].
|fieldName | | |By default field name for export is constructed from current feild key and ancestors keys joined by `settings.fieldSeparator`. You can override this by specifying `fieldName`
|tooltip | | |Optional tooltip to be displayed in field list by hovering on item
|fieldSettings | | |Settings for widgets, will be passed as props. Example: `{min: 1, max: 10}` +
  Available settings for Number/Slider widgets: `min`, `max`, `step`. +
  Slider also supports `marks` (example: `{ 0: "0%", 100: "100%" }`). +
  Available settings for Price widgets: `thousandSeparator`, `decimalSeparator`, `decimalScale`, `prefix`, `suffix`, `allowNegative` (see {d_ts}[type] `PriceFieldSettings` and {number-format}[react-number-format]). +
  Available settings for date/time widgets: `timeFormat`, `dateFormat`, `valueFormat`, `use12Hours`. +
  Available settings for text widget: `maxLength`, `maxRows`. +
  See table for other `fieldSettings` below.
|defaultValue | | |Default value
|preferWidgets | | |See usecase at {config3}[`packages/examples/src/demo/config`] for `slider` field. Its type is `number`. +
  There are 4 widgets defined for `number` type: `number`, `price`, `slider`, `rangeslider`. +
  So setting `preferWidgets: ['slider', 'rangeslider']` will force rendering slider instead of number input. +
  Setting `preferWidgets: ['price']` will render price input (supports thousands separator) instead of number. +
  Also you can use `preferWidgets: ['textarea']` for type `text` for multiline input.
|operators, defaultOperator, widgets, valueSources | | |You can override config of corresponding type (see below at section link:#configtypes[config.types])
|mainWidgetProps | | |Shorthand for `widgets.<main>.widgetProps`
|excludeOperators | | |Can exclude some operators. Example: `['proximity']` for `text` type
|funcs | | |If comparing with funcs is enabled for this field (`valueSources` contains `'func'`), you can also limit list of funcs to be compared (by default will be available all funcs from link:#configfuncs[config.funcs] with `returnType` matching field's `type`)
|hideForSelect | |false |If true, field will appear only at right side (when you compare field with another field)
|hideForCompare | |false |If true, field will appear only at left side
|conjunctions, showNot | | | For type=`!group` with mode=`array`. Example: `conjunctions: ['AND'], showNot: false`
|===


{empty} +

`fieldSettings`

[cols="1m,1,1,5a",options="header"]
|===
|key |default |for widgets |meaning
|validateValue | |* |Function to validate input value. +
  Simple way: return true/false. Advanced: if value is valid, return `null`, otherwise return error string or object `{error, fixedValue?}`. +
  `error` can be a string or an object `{key, args}` to use {i18n}[i18n]. +
  `(val: any, fieldSettings: Object) => boolean \| string \| {error: string \| Object, fixedValue?: any} \| null`
|listValues | |`select`, `multiselect` |*Required* if `asyncFetch` is not provided. Static list of values. +
  Example: `[{value: 'yellow', title: 'Yellow'}, {value: 'green', title: 'Green'}]` 
   (or alternatively `{ yellow: 'Yellow', green: 'Green' }`) +
  You can also use `groupTitle` to group values. 
  Example: `[{value: 'red', groupTitle: 'Warm colors'}, {value: 'orange', groupTitle: 'Warm colors'} ...]`
|treeValues | |`treeselect`, `treemultiselect` |*Required*. Static list of values. +
  Example: `[{value: 'warm', title: 'Warm colors'}, {value: 'red', title: 'Red', parent: 'warm'}, {value: 'orange', title: 'Orange', parent: 'warm'}]` +
   (or alternatively `[{value: 'warm', title: 'Warm colors', children: [ {value: 'red', title: 'Red'}, {value: 'orange', title: 'Orange'} ]}]`)
|maxLength | |`text`, `textarea` |Max text length in characters
|maxRows | |`textarea` |Max rows
|allowCustomValues |false |`select`, `multiselect` |If true, user can provide own options in multiselect. +
  Otherwise they will be limited to static `listValues` (or values loaded via `asyncFetch`)
|showSearch |false |`select`, `multiselect`, `treeselect`, `treemultiselect` |Show search (autocomplete)?
|treeExpandAll |false |`treeselect`, `treemultiselect` |Whether to expand all nodes by default
|treeSelectOnlyLeafs |true |`treeselect` |Can select only leafs or any node?
|asyncFetch | |`select`, `multiselect` |*Required* if `listValues` is not provided. +
  Async function to load list of options from server. +
  Function format: `async (string search, int offset) => { values: Array, hasMore: boolean }` +
  `values` - list of `{title: string, value: string/number, groupTitle?: string}` +
  See also `useLoadMore`, `useAsyncSearch`, `fetchSelectedValuesOnInit`.
|useAsyncSearch |false |`select`, `multiselect` with `asyncFetch` |If true, `asyncFetch` supports server-side search. +
  Otherwise search will be performed locally only within already loaded list values from server.
|useLoadMore |false |`select`, `multiselect` with `asyncFetch` |If true, `asyncFetch` supports pagination.
|forceAsyncSearch |false |`select`, `multiselect` with `asyncFetch` |If true, list of options will be loaded only when user types into search string (if search is empty, no options to be presented).
|fetchSelectedValuesOnInit |false |`select`, `multiselect` with `asyncFetch` |If true, selected list values will be initially fetched from server (on query load) to resolve their titles for UI. +
  `asyncFetch` should support format `async (Array selectedValues) => { values: Array }` +
  where `selectedValues` - array of values (string/number) and `values` - list of `{title: string, value: mixed, groupTitle?: string}` +
  Example for `multiselect`: `asyncFetch(['#FFFF00', '#008000', '#20B2A2'])` should be resolved with `[{title: "Yellow", value: "#FFFF00"}, {title: "Green", value: "#008000"}]` to display color names in UI. (Assuming `#20B2A2` is a custom value entered by user) +
  Example for `select`: `asyncFetch(['#FFFF00'])` should be resolved with `[{title: "Yellow", value: "#FFFF00"}]`. +
  See `logic/autocomplete` data in demo app.
|thousandSeparator | |`price` |Defines the thousands separator character (eg. `,`).
|decimalSeparator |`.` |`price` |Defines the decimal character.
|decimalScale | |`price` |If defined, it limits the number of digits after the decimal point.
|prefix | |`price` |Adds the prefix character before the input value (useful for currency).
|suffix | |`price` |Adds the suffix after the input value (useful for currency).
|allowNegative |true |`price` |If set to false, negative numbers will not be allowed.
|timeFormat |`HH:mm` |`time`, `datetime` |Format to render time in widget
|dateFormat |`DD.MM.YYYY` |`date`, `datetime` |Format to render date in widget
|use12Hours |false |`time`, `datetime` |Use AM/PM?
|===

{nbsp} +
{nbsp} +
[[configsettings]]
=== config.settings

Example:
[source,javascript]
----
import ru_RU from 'antd/es/locale/ru_RU';
import { ruRU } from '@material-ui/core/locale'; //v4
import { ruRU as muiRuRU } from '@mui/material/locale';
import { AntdWidgets } from '@react-awesome-query-builder/antd';
const { FieldCascader, FieldDropdown, FieldTreeSelect } = AntdWidgets;
----

[source,javascript]
----
{
  valueSourcesInfo: {
    value: {
      label: "Value"
    },
    field: {
      label: "Field",
      widget: "field",
    },
    func: {
      label: "Function",
      widget: "func",
    }
  },
  fieldSources: ["field", "func"],
  locale: {
      moment: 'ru',
      antd: ru_RU,
      material: ruRU,
      mui: muiRuRU,
  },
  renderField: (props) => <FieldCascader {...props} />,
  renderOperator: (props) => <FieldDropdown {...props} />,
  renderFunc: (props) => <FieldDropdown {...props} />,
  canReorder: true,
  canRegroup: true,
  maxNesting: 10,
  showLabels: false,
  showNot: true,
  setOpOnChangeField: ['keep', 'default'],
  customFieldSelectProps: {
      showSearch: true
  },
  ...
}
----

Behaviour settings:

[cols="1m,1,3a",options="header",]
|===
|key |default |meaning
|valueSourcesInfo |`{
  value: { label: "Value" },
  field: { label: "Field" },
  func: { label: "Function" }
}` |Sources for RHS (right side of rule, after operator). By default LHS (left side of rule) can be compared with values, another fields and functions in RHS. +
  If you want to disable comparing with another fields in RHS, remove `field` key. +
  If you want to disable comparing with result of function in RHS, remove `func` key.
|fieldSources |`["field"]` |Sources for LHS. To enable functions in LHS, set to `["field", "func"]`
|keepInputOnChangeFieldSrc |true |Keep value entered in RHS after changing source of LHS? 
|showErrorMessage |false |Show error message in QueryBuilder if `validateValue()` in field config returns false for the value or if input value does not satisfy `max`, `min` constraints in `fieldSettings`
|canReorder |true |Activate reordering support for rules and groups of rules?
|canRegroup |true |Allow to move a rule (group) in/out of group during reorder? +
  False - allow "safe" reorder, means only reorder at same level
|canRegroupCases |false |For ternary mode - Allow to move a rule (group) from one case to another?
|showNot |true |Show `NOT` together with `AND`/`OR`?
|forceShowConj |false |Show conjuction for 1 rule in group?
|defaultConjunction |`AND` |Default group conjunction, should be key in `config.conjunctions`
|maxNumberOfRules | |Maximum number of rules which can be added to the query builder
|maxNesting | |Max nesting for groups. +
  Set `1` if you don't want to use groups at all. This will remove also `Add group` button.
|maxNumberOfCases | |For ternary mode - maximum number of cases
|canLeaveEmptyGroup |true |True - leave empty group after deletion of rules, false - automatically remove empty groups + add 1 empty rule to empty root
|shouldCreateEmptyGroup |false |False - automatically add 1 empty rule into new group
|immutableGroupsMode |false |Not allow to add/delete rules or groups, but allow change
|immutableFieldsMode |false |Not allow to change fields
|immutableOpsMode |false |Not allow to change operators
|immutableValuesMode |false |Not allow to change values
|clearValueOnChangeField |false |Clear value on field change? false - if prev & next fields have same type (widget), keep
|clearValueOnChangeOp |false |Clear value on operator change?
|setOpOnChangeField |`['keep', 'default']` |Strategies for selecting operator for new field (used by order until success): +
  `default` (default if present), `keep` (keep prev from last field), `first`, `none`
|canCompareFieldWithField | |For `<ValueFieldWidget>` - Function for building right list of fields to compare field with field +
  `(string leftField, Object leftFieldConfig, string rightField, Object rightFieldConfig) => boolean` +
  For type == `select`/`multiselect` you can optionally check `listValues`
|groupOperators |`['all', 'some', 'none']` |Operators usable in `!group` fields with `array` mode
|showLock |false |Show "Lock" switch for rules and groups to make them read-only ("admin mode") +
  NOTE: To preserve read-only state of rules in JsonLogic, please use `jsonLogic.add_operation("locked", v => v);` in your code
|canDeleteLocked |false |Show "Delete" button for locked rule?
|removeIncompleteRulesOnLoad |false |Remove incomplete rules (without field, operator, value, or if not all required args are present for functin) during initial validation of `value` prop passed to `<Query>`
|exportPreserveGroups |false |Preserve unnecessary groups (ie. groups with only one rule or empty groups) during JsonLogic export
|removeEmptyRulesOnLoad |true |Remove empty rules during initial validation of `value` prop passed to `<Query>`
|removeEmptyGroupsOnLoad |true |Remove empty groups during initial validation of `value` prop passed to `<Query>`
|removeInvalidMultiSelectValuesOnLoad |true |Remove values that are not in `listValues` during initial validation of `value` prop passed to `<Query>`? +
  By default `true`, but `false` for AntDesign as can be removed manually
|useConfigCompress |false |Set to `true` if you use `Utils.ConfigUtils.decompressConfig()`
|fieldItemKeysForSearch |`["label", "path", "altLabel", "grouplabel"]` |Keys in field item (see {d_ts}[type] `FieldItem`) available for search. Available keys: "key", "path", "label", "altLabel" (label2), "tooltip", "grouplabel" (label of parent group, for subfields of complex fields)
|listKeysForSearch |`["title", "value"]` |Keys in list item (see {d_ts}[type] `ListItem`) available for search. Available keys: "title", "value", "groupTitle"
|reverseOperatorsForNot |false |True to convert "!(x == 1)" to "x != 1" on import and export
|canShortMongoQuery |true |True to simplify exported MongoDb query eg. `{$and: [ {num:{$gt:1}}, {num:{$ne:5} } ]}` to `{ num: {$gt: 1, $ne: 5} }`
|fixJsonLogicDateCompareOp |false |Fix comparing of Date instances in JsonLogic by using custom ops `date==`/`datetime==` instead of `==`  and  `date1=`/`datetime!=` instead of `1=`
|===

TIP: For fully read-only mode use these settings:
[source,javascript]
----
immutableGroupsMode: true,
immutableFieldsMode: true,
immutableOpsMode: true,
immutableValuesMode: true,
canReorder: false,
canRegroup: false,
----


Theme settings:

[cols="1m,1,3a",options="header",]
|===
|key |default |meaning
|themeMode |undefined |`light` or `dark`. +
 If <Query> is wrapped in theme provider component (eg. `<ThemeProvider>` for MUI, `<ConfigProvider>` for AntDesign) then will be detected automatically (doesn't work for `reactstrap`). +
 Otherwise `light` by default
|compactMode |false | Use compact styles (eg. smaller margins)
|liteMode |true | Hide some elements (butons "Add", "Delete", drag icon, select source arrow, inactive conjunctions buttons). Show only on hover. +
 Same as adding class `.qb-lite` to `.query-builder`
|theme.material |{} |Options for https://v4.mui.com/customization/theming/[createTheme]
|theme.mui |{} |Options for https://mui.com/material-ui/customization/theming/[createTheme]
|theme.antd |{} |Options for https://ant.design/docs/react/customize-theme[ConfigProvider]
|theme.fluent |{} |Options for https://developer.microsoft.com/en-us/fluentui#/controls/web/themeprovider[ThemeProvider]
|designSettings.canInheritThemeFromOuterProvider |true |If <Query> is wrapped in theme provider component (eg. `<ThemeProvider>` for MUI) and `settings.theme.mui` is also provided then merge themes.
|designSettings.generateCssVarsFromThemeLibrary |true |Adopt <Query> styling to used UI framework theme (MUI/AntDesign etc.). +
 Use false if you don't want a new behaviour and want to use static styles like in versions < 6.7.0
|designSettings.useThickLeftBorderOnHoverItem |false |Fancy effect for hovering on rule/group
|designSettings.useShadowOnHoverItem |false |Fancy effect for hovering on rule/group
|generateCssVars.* | |If you want to override generation of css vars for RAQB using UI framework's theme, use your own function. +
 `generateCssVars` is an object with keys `mui`, `antd`, `fluent`, `material`. Value - function `(theme, config) => Object` +
 Example of overriding: `generateCssVars.mui = (theme, config) => ({ "--group-background": theme.palette.background.paper })` +
 Example of extending: `generateCssVars.mui = (theme, config) => ({ ...config.ctx.generateCssVars(theme, config), "--group-background": theme.palette.grey["200"] })`
|renderSize |`small` |Size of components - `small`, `middle` or `large`
|dropdownPlacement |`bottomLeft` |Placement of antdesign's https://ant.design/components/dropdown/[dropdown] pop-up menu
|groupActionsPosition |`topRight` |You can change the position of the group actions to the following: +
 `topLeft, topCenter, topRight, bottomLeft, bottomCenter, bottomRight`
|defaultSliderWidth |`200px` |Width for `slider`
|defaultSelectWidth |`200px` |Width for `select`
|defaultSearchWidth |`100px` |Width for search in autocomplete inputs
|defaultMaxRows |5 | Max rows for `textarea` widget
|maxLabelsLength |100 |To shorten long labels of fields/values (by length, i.e. number of chars)
|showLabels |false |Show labels above all fields?
|showSelectedValueSourceLabel |false |Show selected value source label?
|===


Render settings:

[cols="1m,1,3a",options="header",]
|===
|key |default |meaning
|renderField |`(props) => <FieldSelect {...props} />` |Render fields list +
  Available widgets for AntDesign: `FieldSelect`, `FieldDropdown`, `FieldCascader`, `FieldTreeSelect`
|renderOperator |`(props) => <FieldSelect {...props} />` |Render operators list +
  Available widgets for AntDesign: `FieldSelect`, `FieldDropdown`
|renderFunc |`(props) => <FieldSelect {...props} />` |Render functions list +
  Available widgets for AntDesign: `FieldSelect`, `FieldDropdown`
|renderConjs, renderButton, renderIcon, renderButtonGroup, renderSwitch, renderProvider, renderValueSources, renderConfirm, useConfirm, renderRuleError | |Other internal render functions you can override if using another UI framework ({renderConjs}[example])
|renderItem | |Able to {renderItem}[customize] render behavior for rule/group items.
|customFieldSelectProps |`{}` |You can pass props to the field select widget. Example: `{showSearch: true}`
|customOperatorSelectProps |`{}` |You can pass props to the operator select widget. Example: `{showSearch: true}`
|renderBeforeWidget | | 
|renderAfterWidget | | 
|renderBeforeActions | | 
|renderAfterActions | | 
|renderSwitchPrefix |`IF` | For ternary mode - render on top of all confitions
|renderBeforeCaseValue |`<span>then</span>` | For ternary mode - render before case value (except default case), after case condition tree
|renderAfterCaseValue | | For ternary mode - render after case value (except default case)
|===


Other settings:

[cols="1m,1,3a",options="header",]
|===
|key |default |meaning
|formatReverse | |Function for formatting query string, used to format rule with reverse operator which haven't `formatOp`. +
  `(string q, string operator, string reversedOp, Object operatorDefinition, Object revOperatorDefinition, bool isForDisplay) => string` +
  `q` - already formatted rule for opposite operator (which have `formatOp`) +
  return smth like `"NOT(" + q + ")"`
|formatField | |Function for formatting query string, used to format field +
  `(string field, Array parts, string label2, Object fieldDefinition, Object config, bool isForDisplay) => string` +
  `parts` - list of fields's keys for struct field +
  `label2` - field's `label2` OR parts joined by `fieldSeparatorDisplay` +
  Default impl will just return `field` (or `label2` for `isForDisplay==true`)
|formatAggr | |Function for formatting query string, used to format aggregation rule (like `SOME OF Cars HAVE Year > 2010`) +
  `(string whereStr, string aggrField, string operator, mixed value, string valueSrc, string valueType, Object operatorDefinition, Object operatorOptions, bool isForDisplay, Object aggrFieldDef) => string` +
  `whereStr` - formatted string representing condition for items (eg. `Year > 2010` in example) +
  `aggrField` - aggregation field (eg. `Cars` in example) +
  `operator` - can be `some`/`all`/`none` (with cardinality 0) or `equal`/`less`/`between`/.. (applied to count of items) +
  `value` - for operators with cardinality 1/2 it is value for comparing with count of items
|fieldSeparator |`.` |Separator for struct fields.
|fieldSeparatorDisplay |`.` |Separator for struct fields in UI.
|defaultField | |Field to be selected by default for new rule.
|defaultOperator | |Operator to be selected by default for new rule.
|caseValueField | |(For ternary mode) Special field config to be used for displaying widget in "then" parts. +
  Example: `{type: "text"}` for simple text input in "then" part
|sqlDialect | |Affects import/export to SQL. Possible values: `BigQuery`, `PostgreSQL`, `MySQL`.
|===


Localization settings:

[cols="1m,1,3a",options="header",]
|===
|key |default |meaning
|locale.moment |`en` |Locale (string or array of strings) used for https://momentjs.com/docs/#/i18n/[moment]
|locale.antd |`en_US` |Locale object used for https://ant.design/docs/react/i18n[AntDesign] widgets
|locale.material |`enUS` |Locale object used for https://v4.mui.com/getting-started/installation/[MaterialUI v4] widgets
|locale.mui |`enUS` |Locale object used for https://mui.com/material-ui/guides/localization/[MUI] widgets
|===


Localization strings:

[cols="1m,1a",options="header",]
|===
|key |default
|valueLabel |Value
|valuePlaceholder |Value
|fieldLabel |Field
|operatorLabel |Operator
|funcLabel |Function
|fieldPlaceholder |Select field
|funcPlaceholder |Select function
|operatorPlaceholder |Select operator
|lockLabel |Lock
|lockedLabel |Locked
|deleteLabel |`null`
|delGroupLabel |`null`
|addGroupLabel |Add group
|addRuleLabel |Add rule
|addSubRuleLabel |Add sub rule
|addSubGroupLabel |Add sub group
|notLabel |Not
|fieldSourcesPopupTitle |Select source
|valueSourcesPopupTitle |Select value source
|removeRuleConfirmOptions |If you want to ask confirmation of removing non-empty rule/group, add these options. +
  List of all valid properties is https://ant.design/components/modal/#API[here]
|removeRuleConfirmOptions.title |Are you sure delete this rule?
|removeRuleConfirmOptions.okText |Yes
|removeRuleConfirmOptions.okType |`danger`
|removeRuleConfirmOptions.cancelText |Cancel
|removeGroupConfirmOptions.title |Are you sure delete this group?
|removeGroupConfirmOptions.okText |Yes
|removeGroupConfirmOptions.okType |`danger`
|removeGroupConfirmOptions.cancelText |Cancel
|defaultCaseLabel |Default:
|addCaseLabel |Add condition
|addDefaultCaseLabel |Add default condition
|loadMoreLabel |Load more...
|loadingMoreLabel |Loading more...
|typeToSearchLabel |Type to search
|loadingLabel |Loading...
|notFoundLabel |Not found
|===



{nbsp} +
{nbsp} +
[[configconjunctions]]
=== config.conjunctions

[source,javascript]
----
{
  AND: {
    label: 'And',
    formatConj: (children, _conj, not) => ( (not ? 'NOT ' : '') + '(' + children.join(' || ') + ')' ),
    reversedConj: 'OR',
    mongoConj: '$and',
  },
  OR: {...},
}
----

where `AND` and `OR` - available conjuctions (logical operators). You can add `NOR` if you want.

[cols="1m,1,4a",options="header",]
|===
|key |required |meaning
|label |+ |Label to be displayed in conjunctions swicther
|formatConj |+ |Function for formatting query, used to join rules into group with conjunction. +
  `(Immultable.List children, string conj, bool not, bool isForDisplay) => string` +
  `children` - list of already formatted queries (strings) to be joined with conjuction
|mongoConj |+ for MongoDB format |https://docs.mongodb.com/manual/reference/operator/query-logical/[Name] of logical operator for MongoDb
|sqlFormatConj |+ for SQL format |See `formatConj`
|spelFormatConj |+ for SpEL format |See `formatConj`
|reversedConj | |Opposite logical operator. +
  Can be used to optimize `!(A OR B)` to `!A && !B` (done for MongoDB format)
|===



{nbsp} +
{nbsp} +
[[configoperators]]
=== config.operators

[source,javascript]
----
{
  equal: {
    label: 'equals',
    reversedOp: 'not_equal',
    labelForFormat: '==',
    cardinality: 1,
    formatOp: (field, _op, value, _valueSrc, _valueType, opDef) => `${field} ${opDef.labelForFormat} ${value}`,
    mongoFormatOp: (field, op, value) => ({ [field]: { '$eq': value } }),
  },
  ..
}
----

[cols="1m,1,1,5a",options="header",]
|===
|key |required |default |meaning
|label |+ | |Label to be displayed in operators select component
|tooltip | | |Optional tooltip to be displayed in operators list by hovering on item
|reversedOp |+ | |Opposite operator
|isNotOp | |false |Eg. true for operator "!=", false for operator "=="
|cardinality | |1 |Number of right operands (1 for binary, 2 for `between`)
|formatOp |+ | |Function for formatting query string, used to join operands into rule. +
  `(string field, string op, mixed value, string valueSrc, string valueType, Object opDef, Object operatorOptions, bool isForDisplay) => string` +
  `value` - string (already formatted value) for `cardinality==1` -or- `Immutable.List` of strings for `cardinality>1`
|labelForFormat | | |If `formatOp` is missing, `labelForFormat` will be used to join operands when building query string
|mongoFormatOp |+ for MongoDB format | |Function for formatting MongoDb expression, used to join operands into rule. +
  `(string field, string op, mixed value, bool not, bool useExpr, string valueSrc, string valueType, Object opDef, Object operatorOptions, Object fieldDef) => object` +
  `value` - mixed for `cardinality==1` -or- `Array` for `cardinality>2` +
  `useExpr` - true if resulted expression will be wrapped in https://docs.mongodb.com/manual/reference/operator/query/expr/index.html[`{'$expr': {...}}`] (used only if you compare field with another field or function) (you need to use aggregation operators in this case, like https://docs.mongodb.com/manual/reference/operator/aggregation/eq/[$eq (aggregation)] instead of https://docs.mongodb.com/manual/reference/operator/query/eq/[$eq])
|sqlOp |+ for SQL format | |Operator name in SQL
|sqlOps |- for SQL format | |Operator names in SQL
|sqlFormatOp |- for SQL format | |Function for advanced formatting SQL WHERE query when just `sqlOp` is not enough. +
  `(string field, string op, mixed value, string valueSrc, string valueType, Object opDef, Object operatorOptions, Object fieldDef) => string` +
  `value` - mixed for `cardinality==1` -or- `Array` for `cardinality>2`
|sqlImport |- for SQL format | |Function to convert given raw SQL value (not string, but object got from `node-sql-parser`) to `{ children: Array }`. If given expression can't be parsed into current operator, throw an error.
|spelOp |+ for SpEL format | |Operator name in SpEL
|spelFormatOp |- for SpEL format | |Function for advanced formatting query in SpEL when just `spelOp` is not enough. +
  `(string field, string op, mixed value, string valueSrc, string valueType, Object opDef, Object operatorOptions, Object fieldDef) => string` +
  `value` - mixed for `cardinality==1` -or- `Array` for `cardinality>2`
|jsonLogic |+ for http://jsonlogic.com[JsonLogic] | |String (eg. `'<'`) -or- function for advanced formatting  +
  `(object field, string op, mixed value, Object opDef, Object operatorOptions, Object fieldDef) => object` +
  `value` - mixed for `cardinality==1` -or- `Array` for `cardinality>2` +
  `field` - already formatted `{"var": <some field>}`
|elasticSearchQueryType |+ for ElasticSearch format | |String (eg. `term`) -or- function `(string valueType) => string` +
  One of https://www.elastic.co/guide/en/elasticsearch/reference/6.8/term-level-queries.html[types of term-level queries]
|valueLabels |+ for `cardinality==2` | |Labels to be displayed on top of 2 values widgets if `config.settings.showLabels` is true +
  Example: `['Value from', {label: 'Value to', placeholder: 'Enter value to'}]`
|textSeparators |+ for `cardinality==2` | |Labels to be displayed before each 2 values widgets +
  Example: `[null, 'and']`
|options | | |Special for `proximity` operator (see demo for details)
|===

[NOTE]
====
There is also special `proximity` operator, its options are rendered with `<ProximityOperator>`.

[source,javascript]
----
import {CustomOperators: {ProximityOperator}} from '@react-awesome-query-builder/ui';
----

See {config3}[`packages/examples/src/demo/config`]
====



{nbsp} +
{nbsp} +
[[configwidgets]]
=== config.widgets

[source,javascript]
----
import {VanillaWidgets} from '@react-awesome-query-builder/ui';
import {AntdWidgets} from '@react-awesome-query-builder/antd';
import {MuiWidgets} from '@react-awesome-query-builder/mui';
import {MaterialWidgets} from '@react-awesome-query-builder/material'; // MUI v4
import {BootstrapWidgets} from '@react-awesome-query-builder/bootstrap';
import {FluentUIWidgets} from "@react-awesome-query-builder/fluent";
const {
    VanillaTextWidget,
    VanillaNumberWidget,
    ...
} = VanillaWidgets;
const {
    TextWidget,
    NumberWidget,
    ...
} = AntdWidgets;
const {
    MuiTextWidget,
    MuiNumberWidget,
    ...
} = MuiWidgets;
const {
    BootstrapTextWidget,
    BootstrapNumberWidget,
    ...
} = BootstrapWidgets;
const {
    FluentUITextWidget,
    FluentUINumberWidget,
    ...
} = FluentUIWidgets;
----

[source,javascript]
----
{
  text: {
    type: 'text',
    valueSrc: 'value',
    factory: (props) => <TextWidget {...props} />,
    formatValue: (val, _fieldDef, _wgtDef, isForDisplay) => (isForDisplay ? val.toString() : JSON.stringify(val)),
    mongoFormatValue: (val, _fieldDef, _wgtDef) => (val),
    // Options:
    valueLabel: "Text",
    valuePlaceholder: "Enter text",
    // Custom props (https://ant.design/components/input/):
    customProps: {
        maxLength: 3
    },
  },
  ..
},
----

[cols="1m,1,1,1,5a",options="header",]
|===
|key |required |default |for widgets |meaning
|type |+ | |* |One of types described in link:#configtypes[config.types]
|factory |+ | |* |React function component
|formatValue |+ | |* |Function for formatting widget's value in query string. +
  `(mixed val, Object fieldDef, Object wgtDef, bool isForDisplay, string op, Object opDef) => string`
|mongoFormatValue |- for MongoDB format |v => v |* |Function for formatting widget's value in MongoDb query. +
  `(mixed val, Object fieldDef, Object wgtDef, string op, Object opDef) => any`
|sqlFormatValue |- for SQL format |`SqlString.escape` |* |Function for formatting widget's value in SQL WHERE query. +
  `(mixed val, Object fieldDef, Object wgtDef, string op, Object opDef) => string`
|spelFormatValue |- for SpEL format |`spelEscape` from `ExportUtils` |* |Function for formatting widget's value in SpEL query. +
  `(mixed val, Object fieldDef, Object wgtDef, string op, Object opDef) => string`
|jsonLogic |- for http://jsonlogic.com[JsonLogic] |v => v |* |Function for formatting widget's value for JsonLogic. +
  `(mixed val, Object fieldDef, Object wgtDef, string op, Object opDef) => any`
|elasticSearchFormatValue |- for ElasticSearch format |`v => v` |* |Function for formatting widget's value for ES query. +
  `(string esQueryType, mixed val, string op, string field, Object config) => Object`
|valueLabel | |`valueLabel` from `config.settings` |* |Common option, text to be placed on top of widget if `config.settings.showLabels` is true
|valuePlaceholder | |`valuePlaceholder` from `config.settings` |* |Common option, placeholder text to be shown in widget for empty value
|timeFormat | |`HH:mm` |`<TimeWidget>`, `<DateTimeWidget>` |Option to display time in widget. Example: `'HH:mm'`
|use12Hours | |`false` |`<TimeWidget>` |Use AM/PM?
|dateFormat | |`DD.MM.YYYY` |`<DateWidget>`, `<DateTimeWidget>` |Option to display date in widget. Example: `YYYY-MM-DD`
|valueFormat | |`YYYY-MM-DD HH:mm:ss` for datetime, `YYYY-MM-DD` for date, `HH:mm:ss` for time |`<TimeWidget>`, `<DateWidget>`, `<DateTimeWidget>` |Option to prepare string representation of value to be stored in query tree.
|maxLength | | |`<TextWidget>`, `<TextAreaWidget>` |Max length in characters
|maxRows | | |`<TextAreaWidget>` |Max rows
|labelYes, labelNo | | |`<BooleanWidget>` |Labels for true/false, can be string or JSX
|thousandSeparator| | |`<PriceWidget>` |Defines the thousands separator character (eg. `,`). +
|decimalSeparator| |`.` |`<PriceWidget>` |Defines the decimal character. +
|decimalScale| | |`<PriceWidget>` |If defined, it limits the number of digits after the decimal point. +
|prefix| | |`<PriceWidget>` |Adds the prefix character before the input value (useful for currency). +
|suffix| | |`<PriceWidget>` |Adds the suffix after the input value (useful for currency). +
|allowNegative| |true |`<PriceWidget>` |If set to false, negative numbers will not be allowed.
|customProps | | |* |You can pass any props directly to widget with `customProps`. +
  For example enable search for https://ant.design/components/select/[`<Select>`] widget: `customProps: {showSearch: true}`
|hideOperator | |false |* |Can be useful for `<BooleanWidget>`: it can always use only operator `equal` by default, then operator select can be hidden.
|operatorInlineLabel | | |* |Can be used together with `hideOperator` to render text/JSX instead of operator select input.
|===

NOTE: There is special `field` widget, rendered by `<ValueFieldWidget>`. +
It can be used to compare field with another field of same type. +
To enable this feature set `valueSources` of type to `['value', 'field']` (see below in link:#configtypes[config.types]).

NOTE: There is special `func` widget, rendered by `<FuncWidget>`. +
It can be used to compare field with result of function (see link:#configfuncs[config.funcs]). +
To enable this feature set `valueSources` of type to `['value', 'func']` (see below in link:#configtypes[config.types]).



{nbsp} +
{nbsp} +
[[configtypes]]
=== config.types

[source,javascript]
----
{
  time: {
      valueSources: ['value', 'field', 'func'],
      defaultOperator: 'equal',
      widgets: {
          time: {
              operators: ['equal', 'between'],
              widgetProps: {
                  valuePlaceholder: "Time",
                  timeFormat: 'h:mm:ss A',
                  use12Hours: true,
              },
              opProps: {
                  between: {
                      valueLabels: ['Time from', 'Time to'],
                  },
              },
          },
      },
  },
  ..
}
----

[cols="1m,1,1,5a",options="header",]
|===
|key |required |default |meaning
|valueSources | |keys of `valueSourcesInfo` at link:#configsettings[config.settings] |Array with values `'value'`, `'field'`, `'func'`. If `'value'` is included, you can compare field with values. If `'field'` is included, you can compare field with another field of same type. If `'func'` is included, you can compare field with result of function (see link:#configfuncs[config.funcs]).
|defaultOperator | | |If specified, it will be auto selected when user selects field
|widgets.* |+ | |Available widgets for current type and their config. +
  Normally there is only 1 widget per type. But see type `number` at {config3}[`packages/examples/src/demo/config`] - it has 4 widgets: `number`, `slider`, `rangeslider`, `price`. +
  Or see type `select` - it has widget `select` for operator `=` and widget `multiselect` for operator `IN`.
|widgets.<widget>.operators | | |List of operators for widget, described in link:#configoperators[config.operators]
|widgets.<widget>.widgetProps | | |Can be used to override config of corresponding widget specified in link:#configwidgets[config.widgets]. Example: `{timeFormat: 'h:mm:ss A'}` for time field with AM/PM.
|widgets.<widget>.opProps.<operator> | | |Can be used to override config of operator for widget. Example: `opProps: { between: {valueLabels: ['Time from', 'Time to']} }` for building range of times.
|===



{nbsp} +
{nbsp} +
[[configfuncs]]
=== config.funcs


[source,javascript]
----
{
  lower: {
    label: 'Lowercase',
    sqlFunc: 'LOWER',
    mongoFunc: '$toLower',
    returnType: 'text',
    args: {
      str: {
        type: 'text',
        valueSources: ['value', 'field'],
      }
    }
  },
  ..
}
----


[cols="1m,1,1,5a",options="header",]
|===
|key |required |default |meaning
|returnType |+ | |One of types described in link:#configtypes[config.types]
|label | |same as func key |Label to be displayed in functions list
|args.* | | |Arguments of function. Config is almost same as for simple link:#configfields[fields]. See "Argument config" below
|allowSelfNesting | |false |Allows the function to be used within its own arguments.
|formatFunc | |Example result: for `isForDisplay==false` - `FUNC(val1, val2)`, for `isForDisplay==true` - `FUNC(arg1: val1, arg2: val2)` |Function for formatting func expression in query rule. +
  `(Object args, bool isForDisplay) => string` +
  where `args` is object `{<arg name> : <arg value>}`
|sqlFunc |- for SQL format |same as func key |Func name in SQL
|sqlFormatFunc |- for SQL format | |Can be used instead of `sqlFunc`. Function with 1 param - args object `{<arg name> : <arg value>}`, should return formatted function expression string. +
  Example: SUM function can be formatted with `({a, b}) => a + " + " + b`
|sqlImport |- for SQL format | |Function to convert given raw SQL value (not string, but object got from `node-sql-parser`) to `{args: Object}`. If given expression can't be parsed into current function, throw an error.
|spelFunc |- for SpEL format |same as func key |Func name in SpEL
|spelFormatFunc |- for SpEL format | |Can be used instead of `spelFunc`. Function with 1 param - args object `{<arg name> : <arg value>}`, should return formatted function expression string. +
  Example: SUM function can be formatted with `({a, b}) => a + " + " + b`
|mongoFunc |- for MongoDB format |same as func key |Func name in Mongo
|mongoArgsAsObject | |false |Some functions like https://docs.mongodb.com/manual/reference/operator/aggregation/rtrim/[$rtrim] supports named args, other ones like https://docs.mongodb.com/manual/reference/operator/aggregation/slice/[$slice] takes args as array
|mongoFormatFunc |- for MongoDB format | |Can be used instead of `mongoFunc`. Function with 1 param - args object `{<arg name> : <arg value>}`, should return formatted function expression object.
|jsonLogic |+ for http://jsonlogic.com[JsonLogic] | |String (function name) or function with 1 param - args object `{<arg name> : <arg value>}`, should return formatted function expression for JsonLogic.
|jsonLogicImport | | |Function to convert given JsonLogic expression to array of arguments of current function. If given expression can't be parsed into current function, throw an error.
|spelImport | | |Function to convert given raw SpEL value to object of arguments of current function. If given value can't be parsed into current function, throw an error or return undefined.
|renderBrackets | |`['(', ')']` |Can render custom function brackets in UI (or not render).
|renderSeps | |`[', ']` |Can render custom arguments separators in UI (other than `,`).
|===

Argument config:

[cols="1m,1,1,5a",options="header",]
|===
|key |required |default |meaning
|label | |arg's key |Label to be displayed in arg's label or placeholder (if `config.settings.showLabels` is false)
|type |+ | |One of types described in link:#configtypes[config.types]
|valueSources | |keys of `valueSourcesInfo` at link:#configsettings[config.settings] |Array with values `'value'`, `'field'`, `'func'`, `'const'`. +
  `const` requires `defaultValue`
|defaultValue | | |Default value
|fieldSettings | | |Settings for widgets, will be passed as props. Example: `{min: 1, max: 10}`
|fieldSettings.listValues |+ for (multi)select widgets | |List of values for Select widget. +
  Example: `[{value: 'yellow', title: 'Yellow'}, {value: 'green', title: 'Green'}]`
|fieldSettings.treeValues |+ for tree (multi)select widgets | |List of values for TreeSelect widget. +
  Example: `[{value: 'warm', title: 'Warm colors'}, {value: 'red', title: 'Red', parent: 'warm'}, {value: 'orange', title: 'Orange', parent: 'warm'}]`
|isOptional | |false |Last args can be optional
|===

See the collection of {funcs}[basic funcstions].
You can copy them to `config.funcs`:
[source,javascript]
----
import { BasicFuncs } from '@react-awesome-query-builder/ui';
const config = {
  //...
  funcs: {
    LINEAR_REGRESSION: BasicFuncs.LINEAR_REGRESSION,
    LOWER: BasicFuncs.LOWER,
  }
};
----


{nbsp} +
{nbsp} +
[[configctx]]
=== config.ctx

Required starting from version 6.3.0

It is a collection of JS functions and React components to be used in other sections of config by reference to `ctx` rather than by reference to imported modules. 

TIP: The purpose of `ctx` is to isolate non-serializable part of config. 

Typically you just need to copy it from link:#basicconfig[basic config] - `AntdConfig.ctx` for AntDesign, `MuiConfig.ctx` for MUI, `BasicConfig.ctx` for vanilla UI etc.

But if you use advanced server-side config, you may need to add your custom functions (eg. `validateValue`) to `ctx` and refer to them in other config sections by name.

[source,javascript]
----
import {BasicConfig} from '@react-awesome-query-builder/ui';

const fields = {
  firstName: {
    type: "text",
    fieldSettings: {
      // use function `validateFirstName` from `ctx` by name
      validateValue: "validateFirstName",
    }
  },
};

const ctx = {
  ...BasicConfig.ctx,
  validateFirstName: (val: string) => {
    return (val.length < 10);
  },
};

// `zipConfig` can be passed to backend as JSON
const zipConfig = {
  fields,
  settings: {
    useConfigCompress: true, // this is required to use Utils.ConfigUtils.decompressConfig()
  },
  // you can add here other sections like `widgets` or `types`, but don't add `ctx`
};

// Config can be loaded from backend with providing `ctx`
const config = Utils.ConfigUtils.decompressConfig(zipConfig, BasicConfig, ctx);
----

You _can't_ just pass JS function to `validateValue` in `fieldSettings` because functions can't be serialized to JSON. 

{nbsp} +
The shape of `ctx`:
[source,javascript]
----
const ctx = {
  // provided in BasicConfig:
  RCE: React.createElement,
  W: {
    VanillaButton,
    // ... other widgets provieded with the lib
  },
  utils: {
    moment, // used in `formatValue`
    SqlString, // used in `sqlFormatValue`
    // ... other utils
  },
  // your custom extensions:
  components: {
    MyLabel, // used in `labelYes` and `labelNo` below
    // ... other custom components used in JSXs in your config
  },
  validateFirstName: (val: string) => {
    return (val.length < 10);
  },
  myRenderField: (props: FieldProps, _ctx: ConfigContext) => {
    if (props.customProps?.["showSearch"]) {
      return <MuiFieldAutocomplete {...props}/>;
    } else {
      return <MuiFieldSelect {...props}/>;
    }
  },
  autocompleteFetch, // see implementation in `/packages/sandbox_next/components/demo/config_ctx.tsx`
}
----

Referring to `ctx` in `zipConfig`:
[source,javascript]
----
const zipConfig = {
  fields: {
    firstName: {
      type: "text",
      fieldSettings: {
        validateValue: "validateFirstName",
      }
    },
    in_stock: {
      type: "boolean",
      mainWidgetProps: {
        labelYes: <MyLabel>Yes</MyLabel>,
        labelNo: <MyLabel>No</MyLabel>,
      }
    },
    autocomplete: {
      type: "select",
      fieldSettings: {
        asyncFetch: "autocompleteFetch",
      },
    },
  },
  settings: {
    renderField: "myRenderField",
    renderButton: "W.VanillaButton",
    useConfigCompress: true, // this is required
  },
};
----

To build zip config from full config you can use this util:
[source,javascript]
----
const zipConfig = Utils.ConfigUtils.compressConfig(config, BasicConfig);
----
In order to generate zip config corretly (to JSON-serializable object), you should put your custom functions to `ctx` and refer to them by names as in examples above.
[source,javascript]
----
import merge from "lodash/merge";
const ctx = {
  validateFirstName: (val) => {
    return (val.length < 10);
  },
};
const config = merge({}, BasicConfig, {
  fields: {
    firstName: {
      type: "text",
      fieldSettings: {
        validateValue: "validateFirstName",
      }
    },
  },
  ctx,
});
const zipConfig = Utils.ConfigUtils.compressConfig(config, BasicConfig);
const config2 = Utils.ConfigUtils.decompressConfig(zipConfig, BasicConfig, ctx); // should be same as `config`
----

NOTE: `settings.useConfigCompress` should be `true` if you use `Utils.ConfigUtils.decompressConfig()`


{nbsp} +
{nbsp} +
[[configserialize]]
=== Serialize entire config to string

Section link:#configctx[config.ctx] demonstrates the concept of `zipConfig` which is a special config format that contains _only changes_ against full config and can be serialized to JSON. 
Base configs provided by this library (`BasicConfig`, `AntdConfig` etc.) still has JS functions (at least for the moment of writing, in version 6.3.0). 
If you want to serialize the _entire_ config (not only changes), you can't do it to JSON as it contains JS functions. But you can do it to string with a help of https://www.npmjs.com/package/serialize-javascript[serialize-javascript] and deserialize back with `eval()`. Yes, it's *unsecure*, but can be used for some purposes. 

CAUTION: Using `eval()` is not secure

To achieve this ability, JS functions in config (like `factory`, `formatValue`, `validateValue` etc.) should be pure functions, they should not use imported modules like this:
[source,javascript]
----
import { VanillaWidgets } from '@react-awesome-query-builder/ui';
const { VanillaButton } = VanillaWidgets;
import moment from "moment";

const config = {
  settings: {
    renderButton: (props) => <VanillaButton {...props} />,
  },
  widgets: {
    date: {
      jsonLogic: (val, fieldDef, wgtDef) => moment(val, wgtDef.valueFormat).toDate(),
    },
  },
};
----
If you try to serialize this config and deserialize back with `eval()`, you will get
`ReferenceError: react\__WEBPACK_IMPORTED_MODULE_0___default is not defined`.

Instead of this all imported modules should be included in `config.ctx`. All render functions in config have `ctx` as 2nd argument. In format functions you can refer to `ctx` via `this`.
[source,javascript]
----
const config = {
  settings: {
    renderButton: (props, {RCE, W: {VanillaButton}}) => RCE(VanillaButton, props),
  },
  widgets: {
    date: {
      jsonLogic: function (val, fieldDef, wgtDef) {
        return this.utils.moment(val, wgtDef.valueFormat).toDate();
      },
    },
  },

  ctx: {
    RCE: React.createElement,
    W: {
      VanillaButton,
    },
    utils: {
      moment,
    },
  }
};
----
Now entire config (without `ctx`) can be serialized to a string with https://www.npmjs.com/package/serialize-javascript[serialize-javascript] and then deserialized back with `eval()` and appending `ctx`.
See {config_ser}[example]. +
