diff --git a/docs/api/classnames.mdx b/docs/api/classnames.mdx
index ef6327ff61..3e6500fcc7 100644
--- a/docs/api/classnames.mdx
+++ b/docs/api/classnames.mdx
@@ -44,6 +44,17 @@ import { standardClassnames as sc } from 'react-querybuilder';
label: `.${sc.valueSource}`,
valueSources: ['value', 'field'],
},
+ {
+ name: 'fb1',
+ label: `Value list`,
+ operators: [{ name: 'between', label: 'between' }],
+ valueSources: ['field', 'value'],
+ comparator: f => f.name === 'fb2',
+ },
+ {
+ name: 'fb2',
+ label: `.${sc.valueListItem}`,
+ },
]}
combinators={[{ name: 'and', label: `.${sc.combinators}` }]}
getOperators={() => [{ name: '=', label: `.${sc.operators}` }]}
@@ -138,6 +149,7 @@ import { standardClassnames as sc } from 'react-querybuilder';
],
},
{ field: 'f3', operator: '=', value: 'f1' },
+ { field: 'fb1', operator: 'between', value: 'fb2,fb2', valueSource: 'field' },
],
}}
/>
diff --git a/docs/api/export.mdx b/docs/api/export.mdx
index 137146cb7d..6a97bcb3c4 100644
--- a/docs/api/export.mdx
+++ b/docs/api/export.mdx
@@ -50,6 +50,49 @@ const query: RuleGroupType = {
};
```
+:::tip
+
+_TL;DR: For best results, use the [default combinators and operators](./misc#defaults) or map custom combinators/operators to the defaults with [`transformQuery`](./misc#transformquery)._
+
+While `formatQuery` technically accepts query objects of type `RuleGroupTypeAny` (i.e. `RuleGroupType` or `RuleGroupTypeIC`), it is not guaranteed to process a query correctly unless the query also conforms to the type `DefaultRuleGroupTypeAny` (i.e. `DefaultRuleGroupType` or `DefaultRuleGroupTypeIC`).
+
+In practice, this means that all `combinator` and `operator` properties in the query must match the `name` of an element in [`defaultCombinators` or `defaultOperators`](./misc#defaults), respectively. If you implement custom combinator/operator names, you can use the [`transformQuery` function](./misc#transformquery) to map your query properties to the defaults.
+
+For example, assume your implementation replaces the default "between" operator (`{ name: "between", label: "between" }`) with `{ name: "b/w", label: "b/w" }`. Any rules using this operator would have `operator: "b/w"` instead of `operator: "between"`. So if a query looked like this...
+
+```json
+{
+ "combinator": "and",
+ "rules": [
+ {
+ "field": "someNumber",
+ "operator": "b/w",
+ "value": "12,14"
+ }
+ ]
+}
+```
+
+...you could run it through `transformQuery` with the `operatorMap` option:
+
+```ts
+const newQuery = transformQuery(query, { operatorMap: { 'b/w': 'between' } });
+// {
+// "combinator": "and",
+// "rules": [
+// {
+// "field": "someNumber",
+// "operator": "between",
+// "value": "12,14"
+// }
+// ]
+// }
+```
+
+The `newQuery` object would be ready for processing by `formatQuery`, including its special handling of the "between" operator.
+
+:::
+
## Basic usage
### JSON
@@ -260,17 +303,17 @@ To avoid information loss, this option is more strict about what qualifies as "n
The following expressions all evaluate to `true`:
```ts
-parseFloat('000111abcdef') === 111;
+parseFloat('000111abcdef') === 111; // everything from the 'a' on is ignored by `parseFloat`
formatQuery(
{ rules: [{ field: 'f', operator: '=', value: '000111abcdef' }] },
{ format: 'sql', parseNumbers: true }
-) === "(f = '000111abcdef')";
+) === "(f = '000111abcdef')"; // `value` contains non-numeric characters, so remains as-is
formatQuery(
{ rules: [{ field: 'f', operator: '=', value: ' 000111 ' }] },
{ format: 'sql', parseNumbers: true }
-) === '(f = 111)';
+) === '(f = 111)'; // after trimming whitespace, `value` is wholly numeric
```
:::
diff --git a/docs/api/querybuilder.mdx b/docs/api/querybuilder.mdx
index 3bb53ac475..5d4556120c 100644
--- a/docs/api/querybuilder.mdx
+++ b/docs/api/querybuilder.mdx
@@ -101,7 +101,7 @@ If the `independentCombinators` prop is provided, then the `query` argument will
`RuleGroupTypeAny`
-The query is an object of type `RuleGroupType` (or `RuleGroupTypeIC`, if [`independentCombinators`](#independentCombinators) is `true`). If this prop is provided, `` will be a controlled component.
+The query is an object of type `RuleGroupType` (or `RuleGroupTypeIC`, if [`independentCombinators`](#independentcombinators) is `true`). If this prop is provided, `` will be a controlled component.
The `query` prop follows the same format as the parameter passed to the [`onQueryChange`](#onquerychange) callback since they are meant to be used together to control the component. See [examples](https://github.com/react-querybuilder/react-querybuilder/blob/main/examples).
@@ -720,11 +720,47 @@ Pass `false` to automatically add an "empty" option with value `"~"` and label `
Pass `true` to automatically add a rule to new groups. If a `query` prop is not passed in, a rule will be added to the root group when the component is mounted. If a `query` prop is passed in with an empty `rules` array, no rule will be added automatically.
+### `listsAsArrays`
+
+`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#listsAsArrays=true)
+
+Pass `true` to update rule values that represent lists with proper arrays instead of comma-separated strings. Applies when `valueEditorType` is "multiselect" and when a rule's `operator` is "between", "notBetween", "in", or "notIn".
+
+For example, the default behavior for the "between" operator might produce this rule:
+
+```json {4}
+{
+ "field": "f1",
+ "operator": "between",
+ "value": "f2,f3",
+ "valueSource": "field"
+}
+```
+
+When `listsAsArrays` is true, the rule's `value` will be an array:
+
+```json {4}
+{
+ "field": "f1",
+ "operator": "between",
+ "value": ["f2", "f3"],
+ "valueSource": "field"
+}
+```
+
### `independentCombinators`
`boolean` (default `false`) [_Click for demo_](https://react-querybuilder.js.org/react-querybuilder/#independentCombinators=true)
-Pass `true` to insert an independent combinator selector between each rule/group in a rule group. The combinator selector at the group level will not be available. Visually, this is similar to the [`showCombinatorsBetweenRules`](#showcombinatorsbetweenrules) option, except that each combinator selector is independently controlled. You may find that users take to this configuration more easily, as it can allow them to express queries more like they would in natural language.
+Pass `true` to insert an independent combinator selector between each rule/group in a rule group. The combinator selector at the group level will not be rendered.
+
+Visually, this option has a similar effect as the [`showCombinatorsBetweenRules`](#showcombinatorsbetweenrules) option, except that each combinator selector is independently controlled. You may find that users take to this configuration more easily, as it can allow them to express queries more like they would in natural language.
+
+:::caution
+
+When the `independentCombinators` option is enabled, the `query` (or `defaultQuery`) prop _must_ be of type `RuleGroupTypeIC` instead of the default `RuleGroupType`. See [`onQueryChange`](#onquerychange) above, or the [Rules and groups section](../typescript#rules-and-groups) of the TypeScript documentation for more information.
+
+:::
### `enableDragAndDrop`