@react-querybuilder/core 8.22.5 → 8.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/derivations/package.json +4 -0
  2. package/dist/cjs/react-querybuilder_core.cjs.development.d.ts +2078 -1665
  3. package/dist/cjs/react-querybuilder_core.cjs.development.js +1293 -422
  4. package/dist/cjs/react-querybuilder_core.cjs.development.js.map +1 -1
  5. package/dist/cjs/react-querybuilder_core.cjs.production.d.ts +2078 -1665
  6. package/dist/cjs/react-querybuilder_core.cjs.production.js +1 -1
  7. package/dist/cjs/react-querybuilder_core.cjs.production.js.map +1 -1
  8. package/dist/{convertQuery-Cw76XFIn.js → convertQuery-BLT0GIhM.js} +17 -8
  9. package/dist/{convertQuery-Cw76XFIn.js.map → convertQuery-BLT0GIhM.js.map} +1 -1
  10. package/dist/{convertQuery-D_4J7E-Z.mjs → convertQuery-DaXv3h7S.mjs} +6 -3
  11. package/dist/{convertQuery-D_4J7E-Z.mjs.map → convertQuery-DaXv3h7S.mjs.map} +1 -1
  12. package/dist/derivations.d.mts +2902 -0
  13. package/dist/derivations.d.ts +2902 -0
  14. package/dist/derivations.js +2845 -0
  15. package/dist/derivations.js.map +1 -0
  16. package/dist/derivations.mjs +2678 -0
  17. package/dist/derivations.mjs.map +1 -0
  18. package/dist/formatQuery.d.mts +2 -895
  19. package/dist/formatQuery.d.ts +2 -895
  20. package/dist/formatQuery.js +120 -140
  21. package/dist/formatQuery.js.map +1 -1
  22. package/dist/formatQuery.mjs +8 -28
  23. package/dist/formatQuery.mjs.map +1 -1
  24. package/dist/{import-DVWI7Fdh.d.mts → import-BdKPtLzo.d.mts} +2 -2
  25. package/dist/{import-6ExjhifL.d.ts → import-BfZTwhp2.d.ts} +2 -2
  26. package/dist/{index-CX9mehdL.d.mts → index-DOIE2pwx.d.mts} +274 -3
  27. package/dist/{index-CX9mehdL.d.ts → index-DOIE2pwx.d.ts} +274 -3
  28. package/dist/index-OF2Q1gTp.d.mts +895 -0
  29. package/dist/index-XueTy_XQ.d.ts +895 -0
  30. package/dist/isRuleOrGroupValid-CIMZNkt4.mjs +27 -0
  31. package/dist/isRuleOrGroupValid-CIMZNkt4.mjs.map +1 -0
  32. package/dist/isRuleOrGroupValid-CtUf4_4x.js +38 -0
  33. package/dist/isRuleOrGroupValid-CtUf4_4x.js.map +1 -0
  34. package/dist/{isRuleGroup-CqLThsbu.mjs → objectUtils-DDZ-KhV5.mjs} +25 -2
  35. package/dist/objectUtils-DDZ-KhV5.mjs.map +1 -0
  36. package/dist/{isRuleGroup-0JNiQgLg.js → objectUtils-DfnEmDSV.js} +48 -1
  37. package/dist/objectUtils-DfnEmDSV.js.map +1 -0
  38. package/dist/parseCEL.d.mts +2 -2
  39. package/dist/parseCEL.d.ts +2 -2
  40. package/dist/parseCEL.js +19 -16
  41. package/dist/parseCEL.js.map +1 -1
  42. package/dist/parseCEL.mjs +12 -9
  43. package/dist/parseCEL.mjs.map +1 -1
  44. package/dist/parseCypher.d.mts +1 -1
  45. package/dist/parseCypher.d.ts +1 -1
  46. package/dist/parseGremlin.d.mts +1 -1
  47. package/dist/parseGremlin.d.ts +1 -1
  48. package/dist/parseJSONata.d.mts +2 -2
  49. package/dist/parseJSONata.d.ts +2 -2
  50. package/dist/parseJSONata.js +17 -14
  51. package/dist/parseJSONata.js.map +1 -1
  52. package/dist/parseJSONata.mjs +11 -8
  53. package/dist/parseJSONata.mjs.map +1 -1
  54. package/dist/parseJsonLogic.d.mts +2 -2
  55. package/dist/parseJsonLogic.d.ts +2 -2
  56. package/dist/parseJsonLogic.js +38 -38
  57. package/dist/parseJsonLogic.js.map +1 -1
  58. package/dist/parseJsonLogic.mjs +5 -5
  59. package/dist/parseMongoDB.d.mts +2 -2
  60. package/dist/parseMongoDB.d.ts +2 -2
  61. package/dist/parseMongoDB.js +50 -47
  62. package/dist/parseMongoDB.js.map +1 -1
  63. package/dist/parseMongoDB.mjs +35 -32
  64. package/dist/parseMongoDB.mjs.map +1 -1
  65. package/dist/parseSPARQL.d.mts +1 -1
  66. package/dist/parseSPARQL.d.ts +1 -1
  67. package/dist/parseSQL.d.mts +2 -2
  68. package/dist/parseSQL.d.ts +2 -2
  69. package/dist/parseSQL.js +27 -23
  70. package/dist/parseSQL.js.map +1 -1
  71. package/dist/parseSQL.mjs +21 -17
  72. package/dist/parseSQL.mjs.map +1 -1
  73. package/dist/parseSpEL.d.mts +2 -2
  74. package/dist/parseSpEL.d.ts +2 -2
  75. package/dist/parseSpEL.js +16 -13
  76. package/dist/parseSpEL.js.map +1 -1
  77. package/dist/parseSpEL.mjs +12 -9
  78. package/dist/parseSpEL.mjs.map +1 -1
  79. package/dist/parserUtils-BKPstAaO.mjs +30 -0
  80. package/dist/parserUtils-BKPstAaO.mjs.map +1 -0
  81. package/dist/parserUtils-DbBXyAht.js +41 -0
  82. package/dist/parserUtils-DbBXyAht.js.map +1 -0
  83. package/dist/{prepareQueryObjects-BnGL91Tt.js → prepareQueryObjects-Dj9cTl9D.js} +90 -63
  84. package/dist/prepareQueryObjects-Dj9cTl9D.js.map +1 -0
  85. package/dist/{prepareQueryObjects-ChINDIap.mjs → prepareQueryObjects-Dmyf3Wi_.mjs} +56 -59
  86. package/dist/prepareQueryObjects-Dmyf3Wi_.mjs.map +1 -0
  87. package/dist/react-querybuilder_core.d.mts +2078 -1665
  88. package/dist/react-querybuilder_core.legacy-esm.d.ts +2078 -1665
  89. package/dist/react-querybuilder_core.legacy-esm.js +1445 -635
  90. package/dist/react-querybuilder_core.legacy-esm.js.map +1 -1
  91. package/dist/react-querybuilder_core.mjs +1288 -424
  92. package/dist/react-querybuilder_core.mjs.map +1 -1
  93. package/dist/react-querybuilder_core.production.d.mts +2078 -1665
  94. package/dist/react-querybuilder_core.production.mjs +1 -1
  95. package/dist/react-querybuilder_core.production.mjs.map +1 -1
  96. package/dist/transformQuery-B7d9AWUf.d.mts +116 -0
  97. package/dist/transformQuery-BXDiUBGB.d.ts +116 -0
  98. package/dist/transformQuery.d.mts +2 -116
  99. package/dist/transformQuery.d.ts +2 -116
  100. package/dist/transformQuery.js +3 -4
  101. package/dist/transformQuery.js.map +1 -1
  102. package/dist/transformQuery.mjs +1 -2
  103. package/dist/transformQuery.mjs.map +1 -1
  104. package/dist/utils-CP5Jqy1P.mjs +1294 -0
  105. package/dist/utils-CP5Jqy1P.mjs.map +1 -0
  106. package/dist/utils-e-7KHkjV.js +1779 -0
  107. package/dist/utils-e-7KHkjV.js.map +1 -0
  108. package/package.json +33 -22
  109. package/dist/isRuleGroup-0JNiQgLg.js.map +0 -1
  110. package/dist/isRuleGroup-CqLThsbu.mjs.map +0 -1
  111. package/dist/objectUtils-Cr02aGxb.js +0 -27
  112. package/dist/objectUtils-Cr02aGxb.js.map +0 -1
  113. package/dist/objectUtils-DBlmJgBf.mjs +0 -16
  114. package/dist/objectUtils-DBlmJgBf.mjs.map +0 -1
  115. package/dist/prepareQueryObjects-BnGL91Tt.js.map +0 -1
  116. package/dist/prepareQueryObjects-ChINDIap.mjs.map +0 -1
  117. package/dist/utils-4k-j5FBa.mjs +0 -537
  118. package/dist/utils-4k-j5FBa.mjs.map +0 -1
  119. package/dist/utils-C79dxwZb.js +0 -752
  120. package/dist/utils-C79dxwZb.js.map +0 -1
@@ -0,0 +1,2678 @@
1
+ import { $ as defaultCombinators, A as isFlexibleOptionGroupArray, B as uniqByName, Ct as queryBuilderFlagDefaults, D as getFirstOption, Dt as substringOperators, E as parseNumber, Et as standardClassnames, F as toFlatOptionArray, G as splitBy, H as uniqOptList, I as toFullOption, J as LogType, K as toArray, L as toFullOptionList, M as isFullOptionGroupArray, N as isOptionGroupArray, O as getOption, P as prepareOptionList, Q as defaultCombinatorLabelMap, R as toFullOptionMap, St as nullOperators, T as getParseNumberMethod, Tt as rootPath, U as joinWith, V as uniqOptGroups, W as nullFreeArray, X as betweenOperators, Y as TestID, Z as defaultCoalesceMs, _t as defaultPlaceholderValueLabel, at as defaultOperatorLabelMap, bt as groupInvalidReasons, ct as defaultPlaceholderFieldGroupLabel, dt as defaultPlaceholderLabel, et as defaultCombinatorsExtended, ft as defaultPlaceholderName, gt as defaultPlaceholderValueGroupLabel, ht as defaultPlaceholderOperatorName, it as defaultMaxHistory, j as isFullOptionArray, k as isFlexibleOptionArray, lt as defaultPlaceholderFieldLabel, mt as defaultPlaceholderOperatorLabel, nt as defaultJoinChar, ot as defaultOperatorNegationMap, pt as defaultPlaceholderOperatorGroupLabel, q as trimIfString, rt as defaultMatchModes, st as defaultOperators, tt as defaultControlClassnames, ut as defaultPlaceholderFieldName, vt as defaultPlaceholderValueName, wt as relationalOperators, xt as inOperators, yt as defaultTranslations, z as uniqByIdentifier } from "./utils-CP5Jqy1P.mjs";
2
+ import { a as isRuleGroupType, c as isPojo, d as numericRegex, i as isRuleGroup, l as lc, n as objectEntries, o as isRuleGroupTypeIC, r as objectKeys, s as isRuleType, t as isUnsafeKey, u as nullOrUndefinedOrEmpty } from "./objectUtils-DDZ-KhV5.mjs";
3
+ import { n as convertQuery, r as convertToIC, t as convertFromIC } from "./convertQuery-DaXv3h7S.mjs";
4
+ import { a as getValueSourcesUtil, c as filterFieldsByComparator, i as resolveCandidateQuery, n as prepareRuleGroup, o as generateID, r as prepareRuleOrGroup, s as uuidV4regex, t as prepareRule } from "./prepareQueryObjects-Dmyf3Wi_.mjs";
5
+ import { n as isValidationResult, t as isRuleOrGroupValid } from "./isRuleOrGroupValid-CIMZNkt4.mjs";
6
+ import { transformQuery } from "./transformQuery.mjs";
7
+ import { Immer, current, isDraft, produce, setAutoFreeze as setAutoFreeze$1 } from "immer";
8
+ //#region src/controlPropKeys.ts
9
+ /**
10
+ * Runtime data describing the set of query builder controls and the props each one receives.
11
+ *
12
+ * These live in `@react-querybuilder/core` (not `react-querybuilder`) so that non-React ports
13
+ * can consume them without a React dependency.
14
+ *
15
+ * Nothing here can drift from the React implementation unnoticed:
16
+ * `react-querybuilder`'s `types/controlPropKeys.test.ts` gates {@link controlKeys} against
17
+ * `defaultControlElements` and `ControlElementsProp`, and every entry of
18
+ * {@link controlPropKeys} against the corresponding props interface—both at runtime and at
19
+ * compile time, in both directions.
20
+ */
21
+ /**
22
+ * The name of every query builder control, alphabetized.
23
+ *
24
+ * @group Props
25
+ */
26
+ const controlKeys = [
27
+ "actionElement",
28
+ "addGroupAction",
29
+ "addRuleAction",
30
+ "cloneGroupAction",
31
+ "cloneRuleAction",
32
+ "combinatorSelector",
33
+ "dragHandle",
34
+ "fieldSelector",
35
+ "inlineCombinator",
36
+ "lockGroupAction",
37
+ "lockRuleAction",
38
+ "matchModeEditor",
39
+ "muteGroupAction",
40
+ "muteRuleAction",
41
+ "notToggle",
42
+ "operatorSelector",
43
+ "removeGroupAction",
44
+ "removeRuleAction",
45
+ "rule",
46
+ "ruleGroup",
47
+ "ruleGroupBodyElements",
48
+ "ruleGroupHeaderElements",
49
+ "shiftActions",
50
+ "undoRedoActions",
51
+ "valueEditor",
52
+ "valueSelector",
53
+ "valueSourceSelector"
54
+ ];
55
+ /**
56
+ * The full set of prop names each default control receives. Ports can use this to declare
57
+ * every prop explicitly instead of relying on fall-through/attribute inheritance.
58
+ *
59
+ * Each array is the complete, alphabetized key set of the control's props interface in
60
+ * `react-querybuilder`. The lists are written out in full rather than composed from shared
61
+ * bases because `--isolatedDeclarations` cannot infer array types built with spreads. A
62
+ * compile-time gate in `react-querybuilder` (`types/controlPropKeys.test.ts`) fails the build
63
+ * if any list drifts from its interface in either direction.
64
+ *
65
+ * @group Props
66
+ */
67
+ const controlPropKeys = {
68
+ actionElement: [
69
+ "className",
70
+ "context",
71
+ "disabled",
72
+ "disabledTranslation",
73
+ "handleOnClick",
74
+ "label",
75
+ "level",
76
+ "path",
77
+ "ruleOrGroup",
78
+ "rules",
79
+ "schema",
80
+ "testID",
81
+ "title",
82
+ "validation"
83
+ ],
84
+ addGroupAction: [
85
+ "className",
86
+ "context",
87
+ "disabled",
88
+ "disabledTranslation",
89
+ "handleOnClick",
90
+ "label",
91
+ "level",
92
+ "path",
93
+ "ruleOrGroup",
94
+ "rules",
95
+ "schema",
96
+ "testID",
97
+ "title",
98
+ "validation"
99
+ ],
100
+ addRuleAction: [
101
+ "className",
102
+ "context",
103
+ "disabled",
104
+ "disabledTranslation",
105
+ "handleOnClick",
106
+ "label",
107
+ "level",
108
+ "path",
109
+ "ruleOrGroup",
110
+ "rules",
111
+ "schema",
112
+ "testID",
113
+ "title",
114
+ "validation"
115
+ ],
116
+ cloneGroupAction: [
117
+ "className",
118
+ "context",
119
+ "disabled",
120
+ "disabledTranslation",
121
+ "handleOnClick",
122
+ "label",
123
+ "level",
124
+ "path",
125
+ "ruleOrGroup",
126
+ "rules",
127
+ "schema",
128
+ "testID",
129
+ "title",
130
+ "validation"
131
+ ],
132
+ cloneRuleAction: [
133
+ "className",
134
+ "context",
135
+ "disabled",
136
+ "disabledTranslation",
137
+ "handleOnClick",
138
+ "label",
139
+ "level",
140
+ "path",
141
+ "ruleOrGroup",
142
+ "rules",
143
+ "schema",
144
+ "testID",
145
+ "title",
146
+ "validation"
147
+ ],
148
+ combinatorSelector: [
149
+ "className",
150
+ "context",
151
+ "disabled",
152
+ "handleOnChange",
153
+ "level",
154
+ "options",
155
+ "path",
156
+ "ruleGroup",
157
+ "rules",
158
+ "schema",
159
+ "testID",
160
+ "title",
161
+ "validation",
162
+ "value"
163
+ ],
164
+ dragHandle: [
165
+ "className",
166
+ "context",
167
+ "disabled",
168
+ "dragHandleAttributes",
169
+ "label",
170
+ "level",
171
+ "path",
172
+ "ruleOrGroup",
173
+ "schema",
174
+ "testID",
175
+ "title",
176
+ "validation"
177
+ ],
178
+ fieldSelector: [
179
+ "className",
180
+ "context",
181
+ "disabled",
182
+ "handleOnChange",
183
+ "level",
184
+ "operator",
185
+ "options",
186
+ "path",
187
+ "rule",
188
+ "schema",
189
+ "testID",
190
+ "title",
191
+ "validation",
192
+ "value"
193
+ ],
194
+ inlineCombinator: [
195
+ "className",
196
+ "component",
197
+ "context",
198
+ "disabled",
199
+ "handleOnChange",
200
+ "level",
201
+ "options",
202
+ "path",
203
+ "ruleGroup",
204
+ "rules",
205
+ "schema",
206
+ "testID",
207
+ "title",
208
+ "validation",
209
+ "value"
210
+ ],
211
+ lockGroupAction: [
212
+ "className",
213
+ "context",
214
+ "disabled",
215
+ "disabledTranslation",
216
+ "handleOnClick",
217
+ "label",
218
+ "level",
219
+ "path",
220
+ "ruleOrGroup",
221
+ "rules",
222
+ "schema",
223
+ "testID",
224
+ "title",
225
+ "validation"
226
+ ],
227
+ lockRuleAction: [
228
+ "className",
229
+ "context",
230
+ "disabled",
231
+ "disabledTranslation",
232
+ "handleOnClick",
233
+ "label",
234
+ "level",
235
+ "path",
236
+ "ruleOrGroup",
237
+ "rules",
238
+ "schema",
239
+ "testID",
240
+ "title",
241
+ "validation"
242
+ ],
243
+ matchModeEditor: [
244
+ "className",
245
+ "classNames",
246
+ "context",
247
+ "disabled",
248
+ "field",
249
+ "fieldData",
250
+ "handleOnChange",
251
+ "level",
252
+ "match",
253
+ "numericEditorComponent",
254
+ "options",
255
+ "path",
256
+ "rule",
257
+ "schema",
258
+ "selectorComponent",
259
+ "testID",
260
+ "thresholdPlaceholder",
261
+ "title",
262
+ "validation",
263
+ "value"
264
+ ],
265
+ muteGroupAction: [
266
+ "className",
267
+ "context",
268
+ "disabled",
269
+ "disabledTranslation",
270
+ "handleOnClick",
271
+ "label",
272
+ "level",
273
+ "path",
274
+ "ruleOrGroup",
275
+ "rules",
276
+ "schema",
277
+ "testID",
278
+ "title",
279
+ "validation"
280
+ ],
281
+ muteRuleAction: [
282
+ "className",
283
+ "context",
284
+ "disabled",
285
+ "disabledTranslation",
286
+ "handleOnClick",
287
+ "label",
288
+ "level",
289
+ "path",
290
+ "ruleOrGroup",
291
+ "rules",
292
+ "schema",
293
+ "testID",
294
+ "title",
295
+ "validation"
296
+ ],
297
+ notToggle: [
298
+ "checked",
299
+ "className",
300
+ "context",
301
+ "disabled",
302
+ "handleOnChange",
303
+ "label",
304
+ "level",
305
+ "path",
306
+ "ruleGroup",
307
+ "schema",
308
+ "testID",
309
+ "title",
310
+ "validation"
311
+ ],
312
+ operatorSelector: [
313
+ "className",
314
+ "context",
315
+ "disabled",
316
+ "field",
317
+ "fieldData",
318
+ "handleOnChange",
319
+ "level",
320
+ "options",
321
+ "path",
322
+ "rule",
323
+ "schema",
324
+ "testID",
325
+ "title",
326
+ "validation",
327
+ "value"
328
+ ],
329
+ removeGroupAction: [
330
+ "className",
331
+ "context",
332
+ "disabled",
333
+ "disabledTranslation",
334
+ "handleOnClick",
335
+ "label",
336
+ "level",
337
+ "path",
338
+ "ruleOrGroup",
339
+ "rules",
340
+ "schema",
341
+ "testID",
342
+ "title",
343
+ "validation"
344
+ ],
345
+ removeRuleAction: [
346
+ "className",
347
+ "context",
348
+ "disabled",
349
+ "disabledTranslation",
350
+ "handleOnClick",
351
+ "label",
352
+ "level",
353
+ "path",
354
+ "ruleOrGroup",
355
+ "rules",
356
+ "schema",
357
+ "testID",
358
+ "title",
359
+ "validation"
360
+ ],
361
+ rule: [
362
+ "actions",
363
+ "context",
364
+ "disabled",
365
+ "dndRef",
366
+ "dragHandleAttributes",
367
+ "dragMonitorId",
368
+ "dragRef",
369
+ "dropEffect",
370
+ "dropMonitorId",
371
+ "dropNotAllowed",
372
+ "field",
373
+ "groupItems",
374
+ "id",
375
+ "isDragging",
376
+ "isOver",
377
+ "operator",
378
+ "parentDisabled",
379
+ "parentMuted",
380
+ "path",
381
+ "rule",
382
+ "schema",
383
+ "shiftDownDisabled",
384
+ "shiftUpDisabled",
385
+ "translations",
386
+ "value",
387
+ "valueSource"
388
+ ],
389
+ ruleGroup: [
390
+ "actions",
391
+ "combinator",
392
+ "context",
393
+ "disabled",
394
+ "dragHandleAttributes",
395
+ "dragMonitorId",
396
+ "dragRef",
397
+ "dropEffect",
398
+ "dropMonitorId",
399
+ "dropNotAllowed",
400
+ "dropRef",
401
+ "groupItems",
402
+ "id",
403
+ "isDragging",
404
+ "isOver",
405
+ "not",
406
+ "parentDisabled",
407
+ "parentMuted",
408
+ "path",
409
+ "previewRef",
410
+ "ruleGroup",
411
+ "rules",
412
+ "schema",
413
+ "shiftDownDisabled",
414
+ "shiftUpDisabled",
415
+ "translations"
416
+ ],
417
+ ruleGroupBodyElements: [
418
+ "accessibleDescription",
419
+ "actions",
420
+ "addGroup",
421
+ "addRule",
422
+ "classNames",
423
+ "cloneGroup",
424
+ "combinator",
425
+ "context",
426
+ "disabled",
427
+ "dragHandleAttributes",
428
+ "dragMonitorId",
429
+ "dragRef",
430
+ "dropEffect",
431
+ "dropMonitorId",
432
+ "dropNotAllowed",
433
+ "dropRef",
434
+ "groupItems",
435
+ "id",
436
+ "isDragging",
437
+ "isOver",
438
+ "muted",
439
+ "not",
440
+ "onCombinatorChange",
441
+ "onGroupAdd",
442
+ "onIndependentCombinatorChange",
443
+ "onNotToggleChange",
444
+ "outerClassName",
445
+ "parentDisabled",
446
+ "parentMuted",
447
+ "path",
448
+ "pathsMemo",
449
+ "previewRef",
450
+ "removeGroup",
451
+ "ruleGroup",
452
+ "rules",
453
+ "schema",
454
+ "shiftDownDisabled",
455
+ "shiftGroupDown",
456
+ "shiftGroupUp",
457
+ "shiftUpDisabled",
458
+ "toggleLockGroup",
459
+ "toggleMuteGroup",
460
+ "translations",
461
+ "validationClassName",
462
+ "validationResult"
463
+ ],
464
+ ruleGroupHeaderElements: [
465
+ "accessibleDescription",
466
+ "actions",
467
+ "addGroup",
468
+ "addRule",
469
+ "classNames",
470
+ "cloneGroup",
471
+ "combinator",
472
+ "context",
473
+ "disabled",
474
+ "dragHandleAttributes",
475
+ "dragMonitorId",
476
+ "dragRef",
477
+ "dropEffect",
478
+ "dropMonitorId",
479
+ "dropNotAllowed",
480
+ "dropRef",
481
+ "groupItems",
482
+ "id",
483
+ "isDragging",
484
+ "isOver",
485
+ "muted",
486
+ "not",
487
+ "onCombinatorChange",
488
+ "onGroupAdd",
489
+ "onIndependentCombinatorChange",
490
+ "onNotToggleChange",
491
+ "outerClassName",
492
+ "parentDisabled",
493
+ "parentMuted",
494
+ "path",
495
+ "pathsMemo",
496
+ "previewRef",
497
+ "removeGroup",
498
+ "ruleGroup",
499
+ "rules",
500
+ "schema",
501
+ "shiftDownDisabled",
502
+ "shiftGroupDown",
503
+ "shiftGroupUp",
504
+ "shiftUpDisabled",
505
+ "toggleLockGroup",
506
+ "toggleMuteGroup",
507
+ "translations",
508
+ "validationClassName",
509
+ "validationResult"
510
+ ],
511
+ shiftActions: [
512
+ "className",
513
+ "context",
514
+ "disabled",
515
+ "labels",
516
+ "level",
517
+ "path",
518
+ "ruleOrGroup",
519
+ "schema",
520
+ "shiftDown",
521
+ "shiftDownDisabled",
522
+ "shiftUp",
523
+ "shiftUpDisabled",
524
+ "testID",
525
+ "title",
526
+ "titles",
527
+ "validation"
528
+ ],
529
+ undoRedoActions: [
530
+ "className",
531
+ "classNames",
532
+ "context",
533
+ "disabled",
534
+ "labels",
535
+ "level",
536
+ "path",
537
+ "ruleOrGroup",
538
+ "schema",
539
+ "testID",
540
+ "title",
541
+ "titles",
542
+ "validation"
543
+ ],
544
+ valueEditor: [
545
+ "className",
546
+ "context",
547
+ "disabled",
548
+ "field",
549
+ "fieldData",
550
+ "handleOnChange",
551
+ "inputType",
552
+ "level",
553
+ "listsAsArrays",
554
+ "operator",
555
+ "parseNumbers",
556
+ "path",
557
+ "rule",
558
+ "schema",
559
+ "selectorComponent",
560
+ "separator",
561
+ "skipHook",
562
+ "testID",
563
+ "title",
564
+ "type",
565
+ "validation",
566
+ "value",
567
+ "valueSource",
568
+ "values"
569
+ ],
570
+ valueSelector: [
571
+ "className",
572
+ "context",
573
+ "disabled",
574
+ "handleOnChange",
575
+ "level",
576
+ "listsAsArrays",
577
+ "multiple",
578
+ "options",
579
+ "path",
580
+ "schema",
581
+ "testID",
582
+ "title",
583
+ "validation",
584
+ "value"
585
+ ],
586
+ valueSourceSelector: [
587
+ "className",
588
+ "context",
589
+ "disabled",
590
+ "field",
591
+ "fieldData",
592
+ "handleOnChange",
593
+ "level",
594
+ "options",
595
+ "path",
596
+ "rule",
597
+ "schema",
598
+ "testID",
599
+ "title",
600
+ "validation",
601
+ "value"
602
+ ]
603
+ };
604
+ /**
605
+ * Which bulk override, if any, applies to each control: `"action"` for controls that a supplied
606
+ * `actionElement` replaces, `"selector"` for controls that a supplied `valueSelector` replaces,
607
+ * and `null` for controls that neither replaces.
608
+ *
609
+ * `actionElement` and `valueSelector` are themselves `null`—they are the _source_ of a bulk
610
+ * override, not a target of one.
611
+ *
612
+ * Replaces name-suffix sniffing (`key.endsWith('Action')`), which would silently misclassify a
613
+ * future control named e.g. `pathSelector`, and which disagrees between implementations about
614
+ * whether `shiftActions`/`undoRedoActions` (plural) match. They do not: neither receives the
615
+ * `actionElement` bulk override.
616
+ *
617
+ * @group Props
618
+ */
619
+ const controlKind = {
620
+ actionElement: null,
621
+ addGroupAction: "action",
622
+ addRuleAction: "action",
623
+ cloneGroupAction: "action",
624
+ cloneRuleAction: "action",
625
+ combinatorSelector: "selector",
626
+ dragHandle: null,
627
+ fieldSelector: "selector",
628
+ inlineCombinator: null,
629
+ lockGroupAction: "action",
630
+ lockRuleAction: "action",
631
+ matchModeEditor: null,
632
+ muteGroupAction: "action",
633
+ muteRuleAction: "action",
634
+ notToggle: null,
635
+ operatorSelector: "selector",
636
+ removeGroupAction: "action",
637
+ removeRuleAction: "action",
638
+ rule: null,
639
+ ruleGroup: null,
640
+ ruleGroupBodyElements: null,
641
+ ruleGroupHeaderElements: null,
642
+ shiftActions: null,
643
+ undoRedoActions: null,
644
+ valueEditor: null,
645
+ valueSelector: null,
646
+ valueSourceSelector: "selector"
647
+ };
648
+ //#endregion
649
+ //#region src/utils/abortReasons.ts
650
+ /**
651
+ * Abort reasons that {@link QueryManager}'s `strict` mode treats as errors. The remaining
652
+ * reasons—`"same-location"` and `"no-change"`—describe valid operations that had nothing to do,
653
+ * so they are reported to `onInvalidTarget` but never throw.
654
+ *
655
+ * Declared apart from `QueryManager` so the `@react-querybuilder/core/derivations` entry point can
656
+ * export it without putting the manager in its module graph.
657
+ *
658
+ * @group Query Tools
659
+ */
660
+ const strictAbortReasons = [
661
+ "target-not-found",
662
+ "parent-not-found",
663
+ "parent-not-a-group",
664
+ "destination-not-found",
665
+ "root-not-allowed",
666
+ "not-a-combinator-slot",
667
+ "target-disabled",
668
+ "parent-disabled",
669
+ "max-levels-exceeded"
670
+ ];
671
+ new Set(strictAbortReasons);
672
+ //#endregion
673
+ //#region ../../node_modules/clsx/dist/clsx.mjs
674
+ function r(e) {
675
+ var t, f, n = "";
676
+ if ("string" == typeof e || "number" == typeof e) n += e;
677
+ else if ("object" == typeof e) if (Array.isArray(e)) {
678
+ var o = e.length;
679
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
680
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
681
+ return n;
682
+ }
683
+ function clsx() {
684
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
685
+ return n;
686
+ }
687
+ //#endregion
688
+ //#region src/utils/signature.ts
689
+ /**
690
+ * Signature returned when a change alters the _shape_ of the query—rules or groups added,
691
+ * removed, moved, or reordered—rather than the properties of a single node. Structural changes
692
+ * never coalesce with each other, so each one produces its own history entry.
693
+ */
694
+ const structuralSignature = "~structural";
695
+ /**
696
+ * Signature returned when two queries differ by reference only, with no observable difference
697
+ * in their properties.
698
+ */
699
+ const unchangedSignature = "";
700
+ /**
701
+ * Returns the list of property names that differ between two nodes, ignoring `rules` (which is
702
+ * compared structurally by the caller).
703
+ */
704
+ const changedProps = (prev, next) => {
705
+ const keys = /* @__PURE__ */ new Set([...Object.keys(prev), ...Object.keys(next)]);
706
+ keys.delete("rules");
707
+ const changed = [];
708
+ for (const key of keys) if (!Object.is(prev[key], next[key])) changed.push(key);
709
+ return changed.toSorted();
710
+ };
711
+ const signatureOfNode = (prev, next, parentId, index) => {
712
+ if (prev === next) return "";
713
+ if (typeof prev === "string" || typeof next === "string") return typeof prev === typeof next ? `${parentId}:combinator[${index}]` : structuralSignature;
714
+ const prevIsGroup = isRuleGroup(prev);
715
+ const nextIsGroup = isRuleGroup(next);
716
+ if (prevIsGroup !== nextIsGroup) return structuralSignature;
717
+ if (!prevIsGroup || !nextIsGroup) {
718
+ const props = changedProps(prev, next);
719
+ return props.length === 0 ? "" : `${next.id ?? ""}:${props.join(",")}`;
720
+ }
721
+ if (prev.rules.length !== next.rules.length) return structuralSignature;
722
+ const ownProps = changedProps(prev, next);
723
+ let changedIndex = -1;
724
+ for (const [i, prevRule] of prev.rules.entries()) if (prevRule !== next.rules[i]) {
725
+ if (changedIndex !== -1) return structuralSignature;
726
+ changedIndex = i;
727
+ }
728
+ if (changedIndex === -1) return ownProps.length === 0 ? "" : `${next.id ?? ""}:${ownProps.join(",")}`;
729
+ if (ownProps.length > 0) return structuralSignature;
730
+ return signatureOfNode(prev.rules[changedIndex], next.rules[changedIndex], next.id ?? "", changedIndex);
731
+ };
732
+ /**
733
+ * Describes _what changed_ between two versions of a query as a short string, so that
734
+ * consecutive edits to the same property of the same rule (e.g. typing in a value editor) can
735
+ * be recognized and coalesced into a single history entry.
736
+ *
737
+ * Returns {@link structuralSignature} for changes to the shape of the query, {@link unchangedSignature} when the
738
+ * two queries differ by reference only, and `"<id>:<props>"` otherwise.
739
+ *
740
+ * The walk prunes on reference equality, so it costs O(depth) rather than O(size) for the
741
+ * single-node edits that make up the overwhelming majority of changes.
742
+ *
743
+ * Note that this relies on the structural sharing that Immer—and therefore every query
744
+ * produced by RQB's own update functions—guarantees: nodes that did not change keep their
745
+ * identity. A query that has been wholly rebuilt (deep-cloned, round-tripped through JSON,
746
+ * re-parsed from a string) shares no identity with its predecessor, so it is reported as
747
+ * {@link structuralSignature} and will not coalesce. That is a graceful degradation—every change simply
748
+ * gets its own history entry—but controlled components that clone the query on every change
749
+ * will not benefit from coalescing.
750
+ */
751
+ const signatureOf = (prev, next) => signatureOfNode(prev, next, "", -1);
752
+ //#endregion
753
+ //#region src/utils/coalesce.ts
754
+ /**
755
+ * Determines whether a change should be absorbed into the current history entry instead of
756
+ * pushing a new one. This is the exact rule {@link QueryManager} applies when recording history,
757
+ * exposed so non-React implementations can manage their own history stacks without
758
+ * reimplementing (and drifting from) the semantics.
759
+ *
760
+ * A change coalesces only when all three hold:
761
+ * - the change is not structural (rules/groups added, removed, moved, or reordered)
762
+ * - its signature matches the previously recorded signature
763
+ * - it occurred within `coalesceMs` of the previous recording
764
+ *
765
+ * Note that {@link unchangedSignature} is not handled here. A change with no observable
766
+ * difference is never recorded at all, which is a separate decision made before this check.
767
+ *
768
+ * @param prevSig Signature of the previously recorded change, or `undefined` if there is none.
769
+ * @param nextSig Signature of the change being recorded, from {@link signatureOf}.
770
+ * @param prevAt Timestamp of the previous recording.
771
+ * @param now Timestamp of the change being recorded.
772
+ * @param coalesceMs Coalescing window in milliseconds.
773
+ */
774
+ const shouldCoalesce = (prevSig, nextSig, prevAt, now, coalesceMs = 500) => nextSig !== "~structural" && nextSig === prevSig && now >= prevAt && now - prevAt < coalesceMs;
775
+ //#endregion
776
+ //#region src/utils/defaultValidator.ts
777
+ /**
778
+ * This is an example validation function you can pass to {@link react-querybuilder!QueryBuilder QueryBuilder} in the
779
+ * `validator` prop. It assumes that you want to validate groups, and has a no-op
780
+ * for validating rules which you can replace with your own implementation.
781
+ */
782
+ const defaultValidator = (query) => {
783
+ const result = {};
784
+ /**
785
+ * Replace this with your custom rule validator.
786
+ */
787
+ const validateRule = (rule) => {
788
+ /* v8 ignore start -- @preserve */
789
+ if (rule.id) result[rule.id];
790
+ /* v8 ignore stop -- @preserve */
791
+ };
792
+ const validateGroup = (rg) => {
793
+ const reasons = [];
794
+ if (rg.rules.length === 0) reasons.push(groupInvalidReasons.empty);
795
+ else if (!isRuleGroupType(rg)) {
796
+ let invalidICs = false;
797
+ for (let i = 0; i < rg.rules.length && !invalidICs; i++) if (i % 2 === 0 && typeof rg.rules[i] === "string" || i % 2 === 1 && typeof rg.rules[i] !== "string" || i % 2 === 1 && typeof rg.rules[i] === "string" && !defaultCombinators.map((c) => c.name).includes(rg.rules[i])) invalidICs = true;
798
+ if (invalidICs) reasons.push(groupInvalidReasons.invalidIndependentCombinators);
799
+ }
800
+ if (isRuleGroupType(rg) && !defaultCombinators.map((c) => c.name).includes(rg.combinator) && rg.rules.length > 1) reasons.push(groupInvalidReasons.invalidCombinator);
801
+ /* v8 ignore else -- @preserve */
802
+ if (rg.id) result[rg.id] = reasons.length > 0 ? {
803
+ valid: false,
804
+ reasons
805
+ } : true;
806
+ for (const r of rg.rules) if (typeof r === "string") {} else if (isRuleGroup(r)) validateGroup(r);
807
+ else validateRule(r);
808
+ };
809
+ validateGroup(query);
810
+ return result;
811
+ };
812
+ //#endregion
813
+ //#region src/utils/deriveClassNames.ts
814
+ const ruleClassnameSources = {
815
+ shiftActions: ["shiftActions"],
816
+ dragHandle: ["dragHandle"],
817
+ fields: ["valueSelector", "fields"],
818
+ matchMode: ["valueSelector", "matchMode"],
819
+ matchThreshold: ["valueSelector", "matchThreshold"],
820
+ operators: ["valueSelector", "operators"],
821
+ valueSource: ["valueSelector", "valueSource"],
822
+ value: ["value"],
823
+ cloneRule: ["actionElement", "cloneRule"],
824
+ lockRule: ["actionElement", "lockRule"],
825
+ muteRule: ["actionElement", "muteRule"],
826
+ removeRule: ["actionElement", "removeRule"],
827
+ valueListItem: ["valueListItem"]
828
+ };
829
+ const ruleGroupClassnameSources = {
830
+ header: {
831
+ sources: ["header"],
832
+ conditions: [
833
+ {
834
+ key: "dndOver",
835
+ when: (s) => s.isOver,
836
+ standardOnly: true
837
+ },
838
+ {
839
+ key: "dndCopy",
840
+ when: (s) => s.isOver && s.dropEffect === "copy"
841
+ },
842
+ {
843
+ key: "dndDropNotAllowed",
844
+ when: (s) => s.dropNotAllowed
845
+ }
846
+ ]
847
+ },
848
+ shiftActions: ["shiftActions"],
849
+ undoRedoActions: ["undoRedoActions"],
850
+ undoAction: ["actionElement", "undoAction"],
851
+ redoAction: ["actionElement", "redoAction"],
852
+ dragHandle: ["dragHandle"],
853
+ combinators: ["valueSelector", "combinators"],
854
+ notToggle: ["notToggle"],
855
+ addRule: ["actionElement", "addRule"],
856
+ addGroup: ["actionElement", "addGroup"],
857
+ cloneGroup: ["actionElement", "cloneGroup"],
858
+ lockGroup: ["actionElement", "lockGroup"],
859
+ muteGroup: ["actionElement", "muteGroup"],
860
+ removeGroup: ["actionElement", "removeGroup"],
861
+ body: ["body"]
862
+ };
863
+ /**
864
+ * Conditional classes applied to a rule's wrapper element.
865
+ *
866
+ * Note that this is deliberately _not_ the same set as {@link ruleGroupOuterConditions}: a rule
867
+ * reflects more drag-and-drop states than a group does. Declaring each set separately is what
868
+ * keeps an implementation from assuming they're symmetric.
869
+ */
870
+ const ruleOuterConditions = [
871
+ {
872
+ key: "disabled",
873
+ when: (s) => s.disabled
874
+ },
875
+ {
876
+ key: "muted",
877
+ when: (s) => s.muted
878
+ },
879
+ {
880
+ key: "dndDragging",
881
+ when: (s) => s.isDragging
882
+ },
883
+ {
884
+ key: "dndOver",
885
+ when: (s) => s.isOver
886
+ },
887
+ {
888
+ key: "dndCopy",
889
+ when: (s) => s.isOver && s.dropEffect === "copy"
890
+ },
891
+ {
892
+ key: "dndGroup",
893
+ when: (s) => s.isOver && s.groupItems
894
+ },
895
+ {
896
+ key: "dndDropNotAllowed",
897
+ when: (s) => s.dropNotAllowed
898
+ },
899
+ {
900
+ key: "hasSubQuery",
901
+ when: (s) => s.hasSubQuery
902
+ }
903
+ ];
904
+ /** Conditional classes applied to a rule group's wrapper element. */
905
+ const ruleGroupOuterConditions = [
906
+ {
907
+ key: "disabled",
908
+ when: (s) => s.disabled
909
+ },
910
+ {
911
+ key: "muted",
912
+ when: (s) => s.muted
913
+ },
914
+ {
915
+ key: "dndDragging",
916
+ when: (s) => s.isDragging
917
+ },
918
+ {
919
+ key: "dndGroup",
920
+ when: (s) => s.isOver && s.groupItems
921
+ }
922
+ ];
923
+ /**
924
+ * Conditional classes applied to the query builder's wrapper element.
925
+ *
926
+ * Only a `boolean` validation result contributes a class; a {@link ValidationMap} describes
927
+ * individual rules and groups, not the query as a whole.
928
+ */
929
+ const queryBuilderOuterConditions = [
930
+ {
931
+ key: "disabled",
932
+ when: (s) => s.disabled
933
+ },
934
+ {
935
+ key: "valid",
936
+ when: (s) => typeof s.validationResult === "boolean" && s.validationResult
937
+ },
938
+ {
939
+ key: "invalid",
940
+ when: (s) => typeof s.validationResult === "boolean" && !s.validationResult
941
+ }
942
+ ];
943
+ /**
944
+ * Expands conditions into `clsx` arguments: every custom class first (in declaration order),
945
+ * then a single object of standard classes.
946
+ */
947
+ const conditionArgs = (conditions, state, { classNames, suppressStandardClassnames }) => {
948
+ const evaluated = conditions.map((condition) => [condition, !!condition.when(state)]);
949
+ return [...evaluated.filter(([condition]) => !condition.standardOnly).map(([condition, active]) => active && classNames?.[condition.key]), suppressStandardClassnames || Object.fromEntries(evaluated.map(([condition, active]) => [standardClassnames[condition.key], active]))];
950
+ };
951
+ /** Composes the classname for a single entry of a spec map. */
952
+ const deriveFromSpec = (key, spec, state, options) => {
953
+ const { sources, conditions } = Array.isArray(spec) ? { sources: spec } : spec;
954
+ return clsx(options.suppressStandardClassnames || standardClassnames[key], ...sources.map((source) => options.classNames?.[source]), ...conditions ? conditionArgs(conditions, state, options) : []);
955
+ };
956
+ const deriveFromSpecs = (specs, state, options) => {
957
+ const result = {};
958
+ for (const [key, spec] of Object.entries(specs)) result[key] = deriveFromSpec(key, spec, state, options);
959
+ return result;
960
+ };
961
+ /**
962
+ * Classnames for each element rendered by a rule. This is the framework-agnostic core of the
963
+ * `classNames` object returned by the `useRule` hook.
964
+ *
965
+ * @group Query Tools
966
+ */
967
+ const deriveRuleClassNames = (options) => deriveFromSpecs(ruleClassnameSources, {}, options);
968
+ /**
969
+ * The classname for a single element of a rule, composed from the same table as
970
+ * {@link deriveRuleClassNames}. Useful where only one is needed, such as the items of a
971
+ * multi-value editor.
972
+ *
973
+ * @group Query Tools
974
+ */
975
+ const deriveRuleClassName = (key, options) => deriveFromSpec(key, ruleClassnameSources[key], {}, options);
976
+ /**
977
+ * Classnames for each element rendered by a rule group, including its conditionally-classed
978
+ * `header`. This is the framework-agnostic core of the `classNames` object returned by the
979
+ * `useRuleGroup` hook.
980
+ *
981
+ * @group Query Tools
982
+ */
983
+ const deriveRuleGroupClassNames = (options) => deriveFromSpecs(ruleGroupClassnameSources, options, options);
984
+ const deriveOuterClassName = (standardKey, conditions, options) => {
985
+ const { classNames, suppressStandardClassnames, leadingClassNames = [], validationClassName } = options;
986
+ return clsx(...leadingClassNames, suppressStandardClassnames || standardClassnames[standardKey], classNames?.[standardKey], ...conditionArgs(conditions, options, options), validationClassName);
987
+ };
988
+ /**
989
+ * The outer (wrapper) classname for a rule, including every conditional state class.
990
+ *
991
+ * @group Query Tools
992
+ */
993
+ const deriveRuleOuterClassName = (options) => deriveOuterClassName("rule", ruleOuterConditions, options);
994
+ /**
995
+ * The outer (wrapper) classname for a rule group, including every conditional state class.
996
+ *
997
+ * A group reflects fewer drag-and-drop states than a rule—`dndOver`, `dndCopy`,
998
+ * `dndDropNotAllowed`, and `hasSubQuery` do not apply—so this is not interchangeable with
999
+ * {@link deriveRuleOuterClassName}.
1000
+ *
1001
+ * @group Query Tools
1002
+ */
1003
+ const deriveRuleGroupOuterClassName = (options) => deriveOuterClassName("ruleGroup", ruleGroupOuterConditions, options);
1004
+ /**
1005
+ * The outer (wrapper) classname for the query builder itself, including the conditional
1006
+ * `disabled`, `valid`, and `invalid` state classes.
1007
+ *
1008
+ * @group Query Tools
1009
+ */
1010
+ const deriveQueryBuilderClassNames = (options) => deriveOuterClassName("queryBuilder", queryBuilderOuterConditions, options);
1011
+ //#endregion
1012
+ //#region src/utils/deriveRuleContext.ts
1013
+ /**
1014
+ * Resolves the field configuration for a rule's `field`, falling back to a minimal option object
1015
+ * when the field isn't present in the field map.
1016
+ */
1017
+ const getFieldData = (field, fieldMap) => fieldMap?.[field] ?? {
1018
+ name: field,
1019
+ value: field,
1020
+ label: field
1021
+ };
1022
+ /**
1023
+ * The input type for a rule. A field's own `inputType` takes precedence over `getInputType`.
1024
+ */
1025
+ const getRuleInputType = (field, operator, fieldData, getInputType) => fieldData.inputType ?? getInputType(field, operator, { fieldData });
1026
+ /**
1027
+ * Whether the value editor(s) should be hidden for an operator, based on its `arity`.
1028
+ */
1029
+ const hideValueControlsForOperator = (operatorObject) => {
1030
+ const arity = operatorObject?.arity;
1031
+ return typeof arity === "string" && arity === "unary" || typeof arity === "number" && arity < 2;
1032
+ };
1033
+ /**
1034
+ * Value source options for a rule. A `valueSource` present on the rule but absent from the
1035
+ * configured list is appended, so the current selection is always representable.
1036
+ */
1037
+ const getRuleValueSourceOptions = (rule, fieldData, getValueSources) => {
1038
+ const configuredVSs = getValueSources(rule.field, rule.operator, { fieldData });
1039
+ if (rule.valueSource && !getOption(configuredVSs, rule.valueSource)) return [...configuredVSs, {
1040
+ name: rule.valueSource,
1041
+ value: rule.valueSource,
1042
+ label: rule.valueSource
1043
+ }];
1044
+ return configuredVSs;
1045
+ };
1046
+ /**
1047
+ * Normalizes the result of `getParameters` to a non-empty list or `null`.
1048
+ */
1049
+ const getParametersAsList = (parameters) => parameters && parameters.length > 0 ? parameters : null;
1050
+ /**
1051
+ * The value editor type for a rule. `valueSource: "field"` always uses a select list, and
1052
+ * `valueSource: "parameter"` uses a (multi)select when parameters are available.
1053
+ */
1054
+ const getRuleValueEditorType = (rule, fieldData, parametersAsList, getValueEditorType) => rule.valueSource === "field" ? "select" : rule.valueSource === "parameter" ? parametersAsList ? lc(rule.operator) === "in" || lc(rule.operator) === "notin" ? "multiselect" : "select" : "text" : getValueEditorType(rule.field, rule.operator, { fieldData });
1055
+ /**
1056
+ * The option list presented by a rule's value editor, resolved from its `valueSource`.
1057
+ */
1058
+ const getRuleValues = (rule, fieldData, fields, parametersAsList, getValues) => {
1059
+ const v = rule.valueSource === "field" ? filterFieldsByComparator(fieldData, fields, rule.operator) : rule.valueSource === "parameter" ? parametersAsList ?? [] : getValues(rule.field, rule.operator, { fieldData });
1060
+ return isFlexibleOptionArray(v) || isFlexibleOptionGroupArray(v) ? toFullOptionList(v) : v;
1061
+ };
1062
+ /**
1063
+ * The validation result for a rule: the entry from a query-level {@link ValidationMap} if present,
1064
+ * otherwise the field's own `validator` result, otherwise `null`.
1065
+ */
1066
+ const getRuleValidationResult = (rule, fieldData, validationMap = {}, id = rule.id ?? "") => validationMap[id] ?? (typeof fieldData.validator === "function" ? fieldData.validator(rule) : null);
1067
+ /**
1068
+ * Resolves everything about a single rule that depends on the field/operator configuration:
1069
+ * its field data, operators, value editor type, value list, value sources, match modes, and
1070
+ * validation result.
1071
+ *
1072
+ * This is the framework-agnostic core of the `useRule` hook, shared with
1073
+ * {@link QueryManager.getRuleContext} so that non-React implementations derive identical results.
1074
+ * It performs no memoization; callers are responsible for caching as appropriate.
1075
+ *
1076
+ * @group Query Tools
1077
+ */
1078
+ const deriveRuleContext = (rule, resolvers, options = {}) => {
1079
+ const { fields, fieldMap, getInputType, getMatchModes, getOperators, getParameters, getValueEditorType, getValues, getValueSources, getSubQueryBuilderProps } = resolvers;
1080
+ const fieldData = getFieldData(rule.field, fieldMap);
1081
+ const inputType = fieldData.inputType ?? getInputType(rule.field, rule.operator, { fieldData });
1082
+ const matchModes = getMatchModes(rule.field, { fieldData });
1083
+ const operators = getOperators(rule.field, { fieldData });
1084
+ const operatorObject = getOption(operators, rule.operator);
1085
+ const valueSourceOptions = getRuleValueSourceOptions(rule, fieldData, getValueSources);
1086
+ const parameters = getParametersAsList(getParameters(rule.field, rule.operator, { fieldData }));
1087
+ return {
1088
+ fieldData,
1089
+ hideValueControls: hideValueControlsForOperator(operatorObject),
1090
+ inputType,
1091
+ matchModes,
1092
+ operatorObject,
1093
+ operators,
1094
+ parameters,
1095
+ validationResult: getRuleValidationResult(rule, fieldData, options.validationMap, options.id),
1096
+ valueEditorType: getRuleValueEditorType(rule, fieldData, parameters, getValueEditorType),
1097
+ values: getRuleValues(rule, fieldData, fields, parameters, getValues),
1098
+ valueSourceOptions,
1099
+ valueSources: valueSourceOptions.map(({ value }) => value),
1100
+ subQueryBuilderProps: getSubQueryBuilderProps?.(rule.field, { fieldData }) ?? {}
1101
+ };
1102
+ };
1103
+ /**
1104
+ * The effective combinator for a group: its own `combinator` when it has one, otherwise the
1105
+ * first configured combinator (which is the case for groups with independent combinators).
1106
+ *
1107
+ * This intentionally covers only the current property-based API. The `RuleGroup` component
1108
+ * additionally falls back to its deprecated `combinator` prop; that fallback stays in the hook.
1109
+ */
1110
+ const getRuleGroupCombinator = (ruleGroup, combinators) => isRuleGroupType(ruleGroup) ? ruleGroup.combinator : getFirstOption(combinators) ?? "";
1111
+ /**
1112
+ * Resolves everything about a rule group that depends on the combinator configuration, plus its
1113
+ * validation result.
1114
+ *
1115
+ * Note that unlike {@link deriveRuleContext}, there is no field-level validator fallback—a
1116
+ * group's validation result comes only from the query-level {@link ValidationMap}.
1117
+ *
1118
+ * @group Query Tools
1119
+ */
1120
+ const deriveRuleGroupContext = (ruleGroup, combinators, options = {}) => {
1121
+ const independentCombinators = isRuleGroupTypeIC(ruleGroup);
1122
+ const combinator = getRuleGroupCombinator(ruleGroup, combinators);
1123
+ const combinatorObject = getOption(combinators, combinator);
1124
+ return {
1125
+ combinator,
1126
+ combinatorObject,
1127
+ combinators,
1128
+ combinatorBasedClassName: independentCombinators ? null : combinatorObject?.className ?? "",
1129
+ independentCombinators,
1130
+ validationResult: (options.validationMap ?? {})[options.id ?? ruleGroup.id ?? ""] ?? null
1131
+ };
1132
+ };
1133
+ //#endregion
1134
+ //#region src/utils/deriveValueEditor.ts
1135
+ /** Operators whose value is a list rather than a single scalar. */
1136
+ const multiValueOperators = /* @__PURE__ */ new Set([
1137
+ "between",
1138
+ "notBetween",
1139
+ "in",
1140
+ "notIn"
1141
+ ]);
1142
+ /**
1143
+ * Whether an operator's value is a list of two bounds.
1144
+ *
1145
+ * @group Value Editors
1146
+ */
1147
+ const isBetweenOperator = (operator) => operator === "between" || operator === "notBetween";
1148
+ /**
1149
+ * Determines whether a rule's `value` needs to be collapsed to a single element because it no
1150
+ * longer represents a list, and what it should become.
1151
+ *
1152
+ * This happens when the value is an array (or a comma-containing string in a `number` input,
1153
+ * which `<input type="number">` can't display) while the operator is not one of the multi-value
1154
+ * operators and the editor is not a multiselect—typically right after the operator changes from
1155
+ * `"in"` or `"between"` to something else.
1156
+ *
1157
+ * The React `useValueEditor` hook applies the result in an effect; other implementations may
1158
+ * apply it wherever is idiomatic.
1159
+ *
1160
+ * @group Value Editors
1161
+ */
1162
+ const getValueEditorReset = ({ skipHook, type, operator, value, inputType }) => {
1163
+ return !skipHook && type !== "multiselect" && !multiValueOperators.has(operator) && (Array.isArray(value) || inputType === "number" && typeof value === "string" && value.includes(",")) ? {
1164
+ reset: true,
1165
+ value: toArray(value, { retainEmptyStrings: true })[0] ?? ""
1166
+ } : {
1167
+ reset: false,
1168
+ value
1169
+ };
1170
+ };
1171
+ /**
1172
+ * Produces the next value for a series of value editors when the editor at `index` changes.
1173
+ *
1174
+ * For `between`/`notBetween`, editing the first bound guarantees an array of at least two
1175
+ * elements, seeding the second from the first available option. The result is a comma-joined
1176
+ * string unless `listsAsArrays` is `true`.
1177
+ *
1178
+ * @group Value Editors
1179
+ */
1180
+ const getMultiValueUpdate = ({ value, index, valueAsArray, operator, values, listsAsArrays, parseNumberMethod }) => {
1181
+ const parsedVal = parseNumber(value, { parseNumbers: parseNumberMethod });
1182
+ const needsBetweenFix = index === 0 && isBetweenOperator(operator) && (valueAsArray.length < 2 || valueAsArray[1] === void 0);
1183
+ if (valueAsArray[index] === parsedVal && !needsBetweenFix) return listsAsArrays ? valueAsArray : joinWith(valueAsArray, ",");
1184
+ const v = [...valueAsArray];
1185
+ v[index] = parsedVal;
1186
+ if (needsBetweenFix) v[1] = getFirstOption(values) ?? "";
1187
+ return listsAsArrays ? v : joinWith(v, ",");
1188
+ };
1189
+ /**
1190
+ * Coerces a value to a `bigint`, falling back to the parsed number when it can't be represented
1191
+ * as one (an empty string or a decimal, for example).
1192
+ *
1193
+ * @group Value Editors
1194
+ */
1195
+ const coerceBigIntValue = (value, parseNumberMethod) => {
1196
+ const valAsMaybeNumber = parseNumber(value, {
1197
+ parseNumbers: parseNumberMethod,
1198
+ bigIntOnOverflow: true
1199
+ });
1200
+ try {
1201
+ return BigInt(valAsMaybeNumber);
1202
+ } catch {
1203
+ return valAsMaybeNumber;
1204
+ }
1205
+ };
1206
+ /**
1207
+ * The `type` attribute an `<input>` should use for a rule. `bigint` values and the `in`/`notIn`
1208
+ * operators (whose value is a comma-separated list) both require a text input.
1209
+ *
1210
+ * @group Value Editors
1211
+ */
1212
+ const coerceInputType = (inputType, operator) => inputType === "bigint" || operator === "in" || operator === "notIn" ? "text" : inputType || "text";
1213
+ /**
1214
+ * Produces the next value for a value selector. Multiselect values are normalized to an array
1215
+ * first, then comma-joined unless `listsAsArrays` is `true`. Single-select values pass through.
1216
+ *
1217
+ * @group Value Editors
1218
+ */
1219
+ const getValueSelectorUpdate = (value, { multiple, listsAsArrays } = {}) => {
1220
+ if (!multiple) return value;
1221
+ const valueAsArray = toArray(value);
1222
+ return listsAsArrays ? valueAsArray : joinWith(valueAsArray, ",");
1223
+ };
1224
+ /**
1225
+ * Normalizes a value selector's current value for display. Multiselect values become an array of
1226
+ * strings so they match option names, which are always strings (e.g. `[42]` becomes `["42"]`).
1227
+ *
1228
+ * @group Value Editors
1229
+ */
1230
+ const normalizeValueSelectorValue = (value, multiple) => multiple ? toArray(value).map(String) : value;
1231
+ //#endregion
1232
+ //#region src/utils/pathUtils.ts
1233
+ /**
1234
+ * Returns the {@link RuleType} or {@link RuleGroupType}/{@link RuleGroupTypeIC}
1235
+ * at the given path within a query.
1236
+ */
1237
+ const findPath = (path, query) => {
1238
+ let target = query;
1239
+ let level = 0;
1240
+ while (level < path.length && target && isRuleGroup(target)) {
1241
+ const t = target.rules[path[level]];
1242
+ target = typeof t === "string" ? null : t;
1243
+ level++;
1244
+ }
1245
+ return level < path.length ? null : target;
1246
+ };
1247
+ /**
1248
+ * Returns the {@link RuleType} or {@link RuleGroupType}/{@link RuleGroupTypeIC}
1249
+ * with the given `id` within a query.
1250
+ */
1251
+ const findID = (id, query) => {
1252
+ if (query.id === id) return query;
1253
+ for (const rule of query.rules) {
1254
+ if (typeof rule === "string") continue;
1255
+ if (rule.id === id) return rule;
1256
+ else if (isRuleGroup(rule)) {
1257
+ const subRule = findID(id, rule);
1258
+ if (subRule) return subRule;
1259
+ }
1260
+ }
1261
+ return null;
1262
+ };
1263
+ /**
1264
+ * Returns the {@link Path} of the {@link RuleType} or {@link RuleGroupType}/{@link RuleGroupTypeIC}
1265
+ * with the given `id` within a query.
1266
+ */
1267
+ const getPathOfID = (id, query) => {
1268
+ if (query.id === id) return [];
1269
+ const idx = query.rules.findIndex((r) => !(typeof r === "string") && r.id === id);
1270
+ if (idx >= 0) return [idx];
1271
+ for (const [i, r] of Object.entries(query.rules)) if (isRuleGroup(r)) {
1272
+ const subPath = getPathOfID(id, r);
1273
+ if (Array.isArray(subPath)) return [Number.parseInt(i), ...subPath];
1274
+ }
1275
+ return null;
1276
+ };
1277
+ /**
1278
+ * Truncates the last element of an array and returns the result as a new array.
1279
+ */
1280
+ const getParentPath = (path) => path.slice(0, -1);
1281
+ /**
1282
+ * Determines if two paths (each `Path`) are equivalent.
1283
+ */
1284
+ const pathsAreEqual = (path1, path2) => {
1285
+ if (path1.length !== path2.length) return false;
1286
+ for (let i = 0; i < path1.length; i++) if (path1[i] !== path2[i]) return false;
1287
+ return true;
1288
+ };
1289
+ /**
1290
+ * Determines if the first path is an ancestor of the second path. The first path must
1291
+ * be shorter and exactly match the second path up through the length of the first path.
1292
+ */
1293
+ const isAncestor = (maybeAncestor, path) => {
1294
+ if (maybeAncestor.length >= path.length) return false;
1295
+ for (let i = 0; i < maybeAncestor.length; i++) if (maybeAncestor[i] !== path[i]) return false;
1296
+ return true;
1297
+ };
1298
+ /**
1299
+ * Finds the deepest/longest path that two paths have in common.
1300
+ */
1301
+ const getCommonAncestorPath = (path1, path2) => {
1302
+ const commonAncestorPath = [];
1303
+ const parentPath1 = getParentPath(path1);
1304
+ const parentPath2 = getParentPath(path2);
1305
+ let i = 0;
1306
+ while (i < parentPath1.length && i < parentPath2.length && parentPath1[i] === parentPath2[i]) {
1307
+ commonAncestorPath.push(parentPath2[i]);
1308
+ i++;
1309
+ }
1310
+ return commonAncestorPath;
1311
+ };
1312
+ /**
1313
+ * Determines if the rule or group at the specified path is either disabled itself
1314
+ * or disabled by an ancestor group.
1315
+ */
1316
+ const pathIsDisabled = (path, query) => {
1317
+ let disabled = !!query.disabled;
1318
+ let target = query;
1319
+ let level = 0;
1320
+ while (level < path.length && !disabled && isRuleGroup(target)) {
1321
+ const t = target.rules[path[level]];
1322
+ if (isPojo(t) && (isRuleGroup(t) || "field" in t && !!t.field)) {
1323
+ disabled = !!t.disabled;
1324
+ target = t;
1325
+ }
1326
+ level++;
1327
+ }
1328
+ return disabled;
1329
+ };
1330
+ /**
1331
+ * Determines if the rule or group at the specified path is disabled by `disabledPaths`—the array
1332
+ * form of the `QueryBuilder` `disabled` prop, which disables nodes by position rather than by a
1333
+ * `disabled` property on the node itself. A path is disabled if it appears in `disabledPaths` or
1334
+ * descends from a path that does.
1335
+ *
1336
+ * @group Paths
1337
+ */
1338
+ const pathIsDisabledByPaths = (path, disabledPaths = []) => disabledPaths.some((p) => pathsAreEqual(p, path) || isAncestor(p, path));
1339
+ /**
1340
+ * Builds the {@link PathInfo} for each child of a group at `path`. A child is disabled if its
1341
+ * parent is disabled or if its own path appears in `disabledPaths`.
1342
+ *
1343
+ * @group Paths
1344
+ */
1345
+ const derivePathInfo = (path, childCount, { disabled = false, disabledPaths = [] } = {}) => {
1346
+ const paths = [];
1347
+ for (let i = 0; i < childCount; i++) {
1348
+ const thisPath = [...path, i];
1349
+ paths[i] = {
1350
+ path: thisPath,
1351
+ disabled: disabled || disabledPaths.some((p) => pathsAreEqual(thisPath, p))
1352
+ };
1353
+ }
1354
+ return paths;
1355
+ };
1356
+ //#endregion
1357
+ //#region src/utils/generateAccessibleDescription.ts
1358
+ /**
1359
+ * The default `accessibleDescriptionGenerator`. Produces the `aria-label` for a rule group:
1360
+ * `"Query builder"` for the root group, `"Rule group at path 0-1"` for any other.
1361
+ *
1362
+ * @group Accessibility
1363
+ */
1364
+ const generateAccessibleDescription = (params) => pathsAreEqual([], params.path) ? `Query builder` : `Rule group at path ${params.path.join("-")}`;
1365
+ //#endregion
1366
+ //#region src/utils/getMatchModesUtil.ts
1367
+ const dummyFD = {
1368
+ name: "name",
1369
+ value: "name",
1370
+ matchModes: null,
1371
+ label: "label"
1372
+ };
1373
+ /**
1374
+ * Utility function to get the match modes array for the given
1375
+ * field. If the field definition does not define a `matchModes`
1376
+ * property, the `getMatchModes` prop is used. Returns
1377
+ * `FullOption<MatchMode>[]` of all match modes by default.
1378
+ */
1379
+ const getMatchModesUtil = (fieldData, getMatchModes) => {
1380
+ const fd = fieldData ? toFullOption(fieldData) : /* v8 ignore next -- @preserve */ dummyFD;
1381
+ let matchModes = fd.matchModes ?? false;
1382
+ if (!matchModes && getMatchModes) matchModes = getMatchModes(fd.value, { fieldData: fd });
1383
+ if (matchModes === true) return defaultMatchModes;
1384
+ else if (matchModes === false) return [];
1385
+ if (isFlexibleOptionArray(matchModes)) return toFullOptionList(matchModes);
1386
+ return matchModes?.map((mm) => defaultMatchModes.find((dmm) => dmm.value === lc(mm)) ?? {
1387
+ name: mm,
1388
+ value: mm,
1389
+ label: mm
1390
+ }) ?? [];
1391
+ };
1392
+ //#endregion
1393
+ //#region src/utils/getRuleDefaultValue.ts
1394
+ const getFirstOptionsFrom = (opts, r, listsAsArrays) => {
1395
+ const firstOption = getFirstOption(opts);
1396
+ if (r.operator === "between" || r.operator === "notBetween") {
1397
+ const valueAsArray = [firstOption, firstOption];
1398
+ return listsAsArrays ? valueAsArray : joinWith(valueAsArray.map((v) => v ?? /* v8 ignore start -- @preserve */ ""), ",");
1399
+ }
1400
+ return firstOption;
1401
+ };
1402
+ /**
1403
+ * Computes the default `value` for a rule given its `field`/`operator`/`valueSource`, mirroring
1404
+ * the precedence the {@link react-querybuilder!QueryBuilder QueryBuilder} applies: a field's
1405
+ * `defaultValue`, then a `getDefaultValue` override, then a value derived from the field/operator's
1406
+ * value list and editor type (first option for `select`/`radio`, `false` for `checkbox`, paired for
1407
+ * `between`/`notBetween`), or a comparator-valid field when `valueSource` is `'field'`. Falls back
1408
+ * to `''`.
1409
+ *
1410
+ * @group Option Lists
1411
+ */
1412
+ const getRuleDefaultValue = (rule, options) => {
1413
+ const { fieldData, fields, getValueEditorType, getValues, getDefaultValue, getParameters, listsAsArrays } = options;
1414
+ if (fieldData?.defaultValue !== void 0 && fieldData.defaultValue !== null) return fieldData.defaultValue;
1415
+ else if (getDefaultValue) return getDefaultValue(rule, { fieldData });
1416
+ let value = "";
1417
+ const values = getValues(rule.field, rule.operator, { fieldData });
1418
+ if (rule.valueSource === "field") {
1419
+ const filteredFields = filterFieldsByComparator(fieldData, fields, rule.operator);
1420
+ value = filteredFields.length > 0 ? getFirstOptionsFrom(filteredFields, rule, listsAsArrays) : "";
1421
+ } else if (rule.valueSource === "parameter") {
1422
+ const parameters = getParameters ? getParameters(rule.field, rule.operator, { fieldData }) : null;
1423
+ value = parameters && parameters.length > 0 ? getFirstOption(parameters) : "";
1424
+ } else if (values.length > 0) {
1425
+ const editorType = getValueEditorType(rule.field, rule.operator, { fieldData });
1426
+ if (editorType === "multiselect") value = listsAsArrays ? [] : "";
1427
+ else if (editorType === "select" || editorType === "radio") value = getFirstOptionsFrom(values, rule, listsAsArrays);
1428
+ } else if (getValueEditorType(rule.field, rule.operator, { fieldData }) === "checkbox") value = false;
1429
+ return value;
1430
+ };
1431
+ //#endregion
1432
+ //#region src/utils/getValidationClassNames.ts
1433
+ /**
1434
+ * Gets the standard classname for valid or invalid components
1435
+ * based on the given validation result.
1436
+ */
1437
+ const getValidationClassNames = (validationResult) => {
1438
+ const valid = typeof validationResult === "boolean" ? validationResult : typeof validationResult === "object" && validationResult !== null ? validationResult.valid : null;
1439
+ return typeof valid === "boolean" ? valid ? standardClassnames.valid : standardClassnames.invalid : "";
1440
+ };
1441
+ //#endregion
1442
+ //#region src/utils/immerInstances.ts
1443
+ /**
1444
+ * Globally enables or disables immer's auto-freeze, i.e. the deep freeze applied to every query
1445
+ * returned by {@link add}, {@link update}, {@link remove}, {@link move}, {@link insert}, and
1446
+ * {@link group}.
1447
+ *
1448
+ * Re-exported from immer so that consumers mixing these tools with their own `produce` calls can
1449
+ * switch both at once. Prefer the per-call `freeze` option, or the {@link QueryManager} option of
1450
+ * the same name, when the change should not be process-wide. A per-call `freeze: false` wins
1451
+ * regardless of this setting; a per-call `freeze: true` does not re-enable freezing once this has
1452
+ * turned it off, since it selects immer's default instance.
1453
+ *
1454
+ * @group Query Tools
1455
+ */
1456
+ const setAutoFreeze = setAutoFreeze$1;
1457
+ const unfrozenImmer = new Immer({ autoFreeze: false });
1458
+ /**
1459
+ * The `produce` implementation matching the requested freeze behavior.
1460
+ *
1461
+ * @internal
1462
+ */
1463
+ const producerFor = (freeze = true) => freeze ? produce : unfrozenImmer.produce;
1464
+ //#endregion
1465
+ //#region src/utils/mergeAnyTranslations.ts
1466
+ /**
1467
+ * Merges any number of partial translations into a single definition.
1468
+ */
1469
+ const mergeAnyTranslations = (base, ...otherTranslations) => {
1470
+ const result = { ...base };
1471
+ for (const translations of otherTranslations)
1472
+ // v8 ignore else
1473
+ if (translations) for (const key of objectKeys(translations)) {
1474
+ if (isUnsafeKey(key)) continue;
1475
+ if (result[key]) result[key] = {
1476
+ ...result[key],
1477
+ ...translations[key]
1478
+ };
1479
+ else result[key] = { ...translations[key] };
1480
+ }
1481
+ return result;
1482
+ };
1483
+ const mergeAnyTranslation = (el, keyPropContextMap, defaults) => {
1484
+ if (isUnsafeKey(el)) return void 0;
1485
+ const finalKeys = objectEntries(keyPropContextMap).map(([key, [pT, cT]]) => [key, pT ?? cT ?? defaults?.[el]?.[key]]).filter((k) => !isUnsafeKey(k[0]) && !!k[1]);
1486
+ if (finalKeys.length > 0 || defaults) {
1487
+ const defaultProperties = defaults?.[el] ?? {};
1488
+ const finalObject = Object.assign({}, defaultProperties, Object.fromEntries(finalKeys));
1489
+ return { [el]: finalObject };
1490
+ }
1491
+ };
1492
+ //#endregion
1493
+ //#region src/utils/mergeClassnames.ts
1494
+ const joinClassnamesByName = (name, args) => {
1495
+ let result = "";
1496
+ for (let i = 0; i < args.length; i++) {
1497
+ const v = args[i]?.[name];
1498
+ if (!v) continue;
1499
+ const s = typeof v === "string" ? v : clsx(v);
1500
+ if (s) result = result ? `${result} ${s}` : s;
1501
+ }
1502
+ return result;
1503
+ };
1504
+ /**
1505
+ * Merges a list of partial {@link Classnames} definitions into a single definition.
1506
+ */
1507
+ const mergeClassnames = (...args) => ({
1508
+ queryBuilder: joinClassnamesByName("queryBuilder", args),
1509
+ ruleGroup: joinClassnamesByName("ruleGroup", args),
1510
+ header: joinClassnamesByName("header", args),
1511
+ body: joinClassnamesByName("body", args),
1512
+ combinators: joinClassnamesByName("combinators", args),
1513
+ addRule: joinClassnamesByName("addRule", args),
1514
+ addGroup: joinClassnamesByName("addGroup", args),
1515
+ cloneRule: joinClassnamesByName("cloneRule", args),
1516
+ cloneGroup: joinClassnamesByName("cloneGroup", args),
1517
+ removeGroup: joinClassnamesByName("removeGroup", args),
1518
+ rule: joinClassnamesByName("rule", args),
1519
+ fields: joinClassnamesByName("fields", args),
1520
+ operators: joinClassnamesByName("operators", args),
1521
+ value: joinClassnamesByName("value", args),
1522
+ removeRule: joinClassnamesByName("removeRule", args),
1523
+ notToggle: joinClassnamesByName("notToggle", args),
1524
+ shiftActions: joinClassnamesByName("shiftActions", args),
1525
+ undoRedoActions: joinClassnamesByName("undoRedoActions", args),
1526
+ undoAction: joinClassnamesByName("undoAction", args),
1527
+ redoAction: joinClassnamesByName("redoAction", args),
1528
+ dragHandle: joinClassnamesByName("dragHandle", args),
1529
+ lockRule: joinClassnamesByName("lockRule", args),
1530
+ lockGroup: joinClassnamesByName("lockGroup", args),
1531
+ muteRule: joinClassnamesByName("muteRule", args),
1532
+ muteGroup: joinClassnamesByName("muteGroup", args),
1533
+ muted: joinClassnamesByName("muted", args),
1534
+ valueSource: joinClassnamesByName("valueSource", args),
1535
+ actionElement: joinClassnamesByName("actionElement", args),
1536
+ valueSelector: joinClassnamesByName("valueSelector", args),
1537
+ betweenRules: joinClassnamesByName("betweenRules", args),
1538
+ valid: joinClassnamesByName("valid", args),
1539
+ invalid: joinClassnamesByName("invalid", args),
1540
+ dndDragging: joinClassnamesByName("dndDragging", args),
1541
+ dndOver: joinClassnamesByName("dndOver", args),
1542
+ dndCopy: joinClassnamesByName("dndCopy", args),
1543
+ dndGroup: joinClassnamesByName("dndGroup", args),
1544
+ dndDropNotAllowed: joinClassnamesByName("dndDropNotAllowed", args),
1545
+ dndPreviewPosition: joinClassnamesByName("dndPreviewPosition", args),
1546
+ dndHidden: joinClassnamesByName("dndHidden", args),
1547
+ disabled: joinClassnamesByName("disabled", args),
1548
+ valueListItem: joinClassnamesByName("valueListItem", args),
1549
+ matchMode: joinClassnamesByName("matchMode", args),
1550
+ matchThreshold: joinClassnamesByName("matchThreshold", args),
1551
+ branches: joinClassnamesByName("branches", args),
1552
+ hasSubQuery: joinClassnamesByName("hasSubQuery", args),
1553
+ loading: joinClassnamesByName("loading", args),
1554
+ valueDateTimeRelative: joinClassnamesByName("valueDateTimeRelative", args)
1555
+ });
1556
+ //#endregion
1557
+ //#region src/utils/optionResolvers.ts
1558
+ /**
1559
+ * Resolves the operator list for a field, applying the same precedence as the `QueryBuilder`
1560
+ * component: the field's own `operators`, then the `getOperators` callback, then the
1561
+ * query-level operator list.
1562
+ *
1563
+ * @group Option Lists
1564
+ */
1565
+ const resolveOperatorList = ({ field, fieldData, getOperators, operators, placeholder, baseOption, autoSelectOption }) => prepareOptionList({
1566
+ optionList: fieldData?.operators ?? getOperators?.(field, { fieldData }) ?? operators,
1567
+ placeholder,
1568
+ baseOption,
1569
+ labelMap: defaultOperatorLabelMap,
1570
+ autoSelectOption
1571
+ }).optionList;
1572
+ /**
1573
+ * Resolves the default operator for a field, applying the same precedence as the `QueryBuilder`
1574
+ * component: the field's own `defaultOperator`, then the `getDefaultOperator` option (a string or
1575
+ * a function), then the first available operator.
1576
+ *
1577
+ * @group Option Lists
1578
+ */
1579
+ const resolveDefaultOperator = ({ field, fieldData, getDefaultOperator, getOperators }) => {
1580
+ if (fieldData?.defaultOperator) return fieldData.defaultOperator;
1581
+ if (getDefaultOperator) return typeof getDefaultOperator === "function" ? getDefaultOperator(field, { fieldData }) : getDefaultOperator;
1582
+ return getFirstOption(getOperators(field, { fieldData })) ?? "";
1583
+ };
1584
+ /**
1585
+ * Resolves the value editor type for a field/operator pair, applying the same precedence as the
1586
+ * `QueryBuilder` component: the field's own `valueEditorType` (a string or a function of the
1587
+ * operator), then the `getValueEditorType` callback, then `"text"`.
1588
+ *
1589
+ * @group Option Lists
1590
+ */
1591
+ const resolveValueEditorType = ({ field, operator, fieldData, getValueEditorType }) => {
1592
+ if (fieldData?.valueEditorType) return typeof fieldData.valueEditorType === "function" ? fieldData.valueEditorType(operator) : fieldData.valueEditorType;
1593
+ return getValueEditorType?.(field, operator, { fieldData }) ?? "text";
1594
+ };
1595
+ /**
1596
+ * Resolves the value option list for a field/operator pair, applying the same precedence as the
1597
+ * `QueryBuilder` component: the field's own `values`, then the `getValues` callback, then an
1598
+ * empty list.
1599
+ *
1600
+ * @group Option Lists
1601
+ */
1602
+ const resolveValueList = ({ field, operator, fieldData, getValues, placeholder, baseOption, autoSelectOption }) => prepareOptionList({
1603
+ optionList: fieldData?.values ?? getValues?.(field, operator, { fieldData }) ?? [],
1604
+ placeholder,
1605
+ baseOption,
1606
+ autoSelectOption
1607
+ }).optionList;
1608
+ //#endregion
1609
+ //#region src/utils/optionsEqual.ts
1610
+ const isPlainObject = (x) => {
1611
+ const proto = Object.getPrototypeOf(x);
1612
+ return proto === null || proto === Object.prototype;
1613
+ };
1614
+ /**
1615
+ * Structural equality for {@link QueryManagerOptions} values. Arrays and plain objects are
1616
+ * compared by value; everything else — functions, class instances, `Map`s, `Date`s — by
1617
+ * identity.
1618
+ *
1619
+ * That split is what makes an options object rebuilt on every render compare equal as long as
1620
+ * its _data_ did not change, which is the entire point: a caller that passes object literals
1621
+ * (`fields={[...]}`, `translations={{...}}`) hands a fresh identity to every reconfigure, so an
1622
+ * identity-only comparison would report a change every time.
1623
+ *
1624
+ * Comparing functions by identity is deliberate rather than a limitation. Two functions cannot
1625
+ * be proven equivalent, so a caller that rebuilds `getDefaultValue` per render must either
1626
+ * memoize it or accept the reconfigure.
1627
+ */
1628
+ const valuesEqual = (a, b) => {
1629
+ if (Object.is(a, b)) return true;
1630
+ if (Array.isArray(a) || Array.isArray(b)) return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((v, i) => valuesEqual(v, b[i]));
1631
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
1632
+ if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b) || !isPlainObject(a)) return false;
1633
+ const aKeys = Object.keys(a);
1634
+ return aKeys.length === Object.keys(b).length && aKeys.every((k) => valuesEqual(a[k], b[k]));
1635
+ };
1636
+ /**
1637
+ * Whether two {@link QueryManagerOptions} objects describe the same configuration, per
1638
+ * {@link valuesEqual}: data by value, functions by identity.
1639
+ *
1640
+ * {@link QueryManager.reconfigure} uses this to gate itself, so most callers never need it
1641
+ * directly. It is exported for framework adapters that decide whether to _call_ `reconfigure`
1642
+ * at all — skipping the call avoids building the merged options object in the first place.
1643
+ *
1644
+ * Nested option objects (`history`, `translations`, …) are descended into rather than compared
1645
+ * by identity, so `{ history: { maxHistory: 10 } }` rebuilt per render compares equal.
1646
+ */
1647
+ const optionsEqual = (a, b) => valuesEqual(a, b);
1648
+ //#endregion
1649
+ //#region src/utils/preferProp.ts
1650
+ const preferPropDefaultTrue = (prop, context) => prop === false ? false : prop ? true : !(context === false);
1651
+ const preferPropDefaultFalse = (prop, context) => prop ? true : prop === false ? false : !!context;
1652
+ /**
1653
+ * For given default, prop, and context values, return the first provided of prop,
1654
+ * context, and default, in that order.
1655
+ */
1656
+ const preferProp = (def, prop, context, doNotFinalize) => !doNotFinalize ? def ? preferPropDefaultTrue(prop, context) : preferPropDefaultFalse(prop, context) : prop ?? context;
1657
+ /**
1658
+ * For given default, prop, and context values, return the first provided of prop,
1659
+ * context, and default, in that order.
1660
+ */
1661
+ const preferAnyProp = (def, prop, context) => prop !== void 0 && prop != null ? prop : context !== void 0 && context != null ? context : def;
1662
+ /**
1663
+ * For a given set of defaults, props, and context values, return the first provided of prop,
1664
+ * context, and default—in that order—for each property in the defaults object.
1665
+ */
1666
+ const preferFlagProps = (props = {}, contextVals = {}, finalize) => objectEntries(queryBuilderFlagDefaults).reduce((acc, [key, def]) => {
1667
+ acc[key] = preferProp(def, props[key], contextVals[key], !finalize);
1668
+ return acc;
1669
+ }, {});
1670
+ //#endregion
1671
+ //#region src/utils/regenerateIDs.ts
1672
+ /**
1673
+ * Generates a new `id` property for a rule.
1674
+ */
1675
+ const regenerateID = (rule, { idGenerator = generateID } = {}) => structuredClone({
1676
+ ...rule,
1677
+ id: idGenerator()
1678
+ });
1679
+ /**
1680
+ * Recursively generates new `id` properties for a rule group and all its rules and subgroups.
1681
+ */
1682
+ const regenerateIDs = (subject, { idGenerator = generateID } = {}) => {
1683
+ if (!isPojo(subject)) return subject;
1684
+ if (!isRuleGroup(subject)) return structuredClone({
1685
+ ...subject,
1686
+ id: idGenerator()
1687
+ });
1688
+ const newGroup = {
1689
+ ...subject,
1690
+ id: idGenerator()
1691
+ };
1692
+ // v8 ignore else
1693
+ if (Array.isArray(newGroup.rules)) newGroup.rules = subject.rules.map((r) => typeof r === "string" ? r : isRuleGroup(r) ? regenerateIDs(r, { idGenerator }) : regenerateID(r, { idGenerator }));
1694
+ return newGroup;
1695
+ };
1696
+ //#endregion
1697
+ //#region src/utils/queryTools.ts
1698
+ /**
1699
+ * Whether a mutation targeting `pathOrID` is blocked by the given guards, and why.
1700
+ * Returns `null` when the mutation may proceed.
1701
+ *
1702
+ * Exported so that callers which run their own logic before mutating—such as a UI layer that
1703
+ * invokes a confirmation callback—can apply the same rules without duplicating them.
1704
+ *
1705
+ * @group Query Tools
1706
+ */
1707
+ const getGuardAbortReason = (query, pathOrID, guards = {}, { asParent = false } = {}) => {
1708
+ if (guards.queryDisabled) return asParent ? "parent-disabled" : "target-disabled";
1709
+ if (!guards.respectDisabled || pathOrID === void 0) return null;
1710
+ const path = Array.isArray(pathOrID) ? pathOrID : getPathOfID(pathOrID, query);
1711
+ if (path && (pathIsDisabled(path, query) || pathIsDisabledByPaths(path, guards.disabledPaths))) return asParent ? "parent-disabled" : "target-disabled";
1712
+ return null;
1713
+ };
1714
+ /**
1715
+ * Whether adding a group beneath `parentPath` would exceed `maxLevels`.
1716
+ *
1717
+ * @group Query Tools
1718
+ */
1719
+ const exceedsMaxLevels = (parentPath, { maxLevels = Infinity } = {}) => !!parentPath && parentPath.length >= maxLevels;
1720
+ /**
1721
+ * Adds a rule or group to a query without mutating the original query.
1722
+ *
1723
+ * @returns A new query with the rule or group added.
1724
+ *
1725
+ * @group Query Tools
1726
+ */
1727
+ const add = (query, ruleOrGroup, parentPathOrID, options = {}) => producerFor(options.freeze)(query, (q) => addInPlace(q, ruleOrGroup, parentPathOrID, options));
1728
+ /**
1729
+ * Adds a rule or group to a query in place.
1730
+ *
1731
+ * @returns The query (mutated in place) with the rule or group added.
1732
+ *
1733
+ * @group Query Tools
1734
+ */
1735
+ const addInPlace = (query, ruleOrGroup, parentPathOrID, options = {}) => {
1736
+ const { combinators = defaultCombinators, combinatorPreceding, idGenerator = generateID, onAbort } = options;
1737
+ const parent = Array.isArray(parentPathOrID) ? findPath(parentPathOrID, query) : findID(parentPathOrID, query);
1738
+ if (!parent) {
1739
+ onAbort?.({
1740
+ reason: "parent-not-found",
1741
+ operation: "add",
1742
+ pathOrID: parentPathOrID
1743
+ });
1744
+ return query;
1745
+ }
1746
+ if (!isRuleGroup(parent)) {
1747
+ onAbort?.({
1748
+ reason: "parent-not-a-group",
1749
+ operation: "add",
1750
+ pathOrID: parentPathOrID
1751
+ });
1752
+ return query;
1753
+ }
1754
+ const parentPath = Array.isArray(parentPathOrID) ? parentPathOrID : getPathOfID(parentPathOrID, query);
1755
+ const addGuardReason = getGuardAbortReason(query, parentPath, options, { asParent: true });
1756
+ if (addGuardReason) {
1757
+ onAbort?.({
1758
+ reason: addGuardReason,
1759
+ operation: "add",
1760
+ pathOrID: parentPathOrID
1761
+ });
1762
+ return query;
1763
+ }
1764
+ if (isRuleGroup(ruleOrGroup) && exceedsMaxLevels(parentPath, options)) {
1765
+ onAbort?.({
1766
+ reason: "max-levels-exceeded",
1767
+ operation: "add",
1768
+ pathOrID: parentPathOrID
1769
+ });
1770
+ return query;
1771
+ }
1772
+ if (isRuleGroupTypeIC(parent) && parent.rules.length > 0) {
1773
+ const prevCombinator = parent.rules.at(-2);
1774
+ parent.rules.push(combinatorPreceding ?? (typeof prevCombinator === "string" ? prevCombinator : getFirstOption(combinators)));
1775
+ }
1776
+ parent.rules.push(prepareRuleOrGroup(ruleOrGroup, { idGenerator }));
1777
+ return query;
1778
+ };
1779
+ /**
1780
+ * Relative order in which properties are applied during a multi-property update.
1781
+ * Lower ranks apply first; `value` applies last so an explicitly-provided value
1782
+ * is never clobbered by a reset triggered by a `field`/`operator`/`valueSource`
1783
+ * change. Unranked properties default to `3` (between `valueSource` and `value`).
1784
+ */
1785
+ const updatePropRank = {
1786
+ field: 0,
1787
+ operator: 1,
1788
+ valueSource: 2,
1789
+ value: 4
1790
+ };
1791
+ /** Stable-sorts `[prop, value]` entries by {@link updatePropRank}. */
1792
+ const orderUpdateEntries = (entries) => entries.toSorted((x, y) => (updatePropRank[x[0]] ?? 3) - (updatePropRank[y[0]] ?? 3));
1793
+ /**
1794
+ * Normalizes the variadic {@link update}/{@link updateInPlace} arguments (single
1795
+ * prop+value, parallel arrays, or property map) into a canonically-ordered list
1796
+ * of `[prop, value]` entries plus the target path/ID and options.
1797
+ */
1798
+ const normalizeUpdateArgs = (a, b, c, d) => {
1799
+ if (typeof a === "string") return {
1800
+ entries: [[a, b]],
1801
+ pathOrID: c,
1802
+ options: d ?? {}
1803
+ };
1804
+ if (Array.isArray(a)) {
1805
+ const values = b;
1806
+ return {
1807
+ entries: orderUpdateEntries(a.map((prop, i) => [prop, values[i]])),
1808
+ pathOrID: c,
1809
+ options: d ?? {}
1810
+ };
1811
+ }
1812
+ return {
1813
+ entries: orderUpdateEntries(Object.entries(a)),
1814
+ pathOrID: b,
1815
+ options: c ?? {}
1816
+ };
1817
+ };
1818
+ /**
1819
+ * The options argument of an {@link update} call, whose position depends on the argument form.
1820
+ * Cheaper than {@link normalizeUpdateArgs} when only the options are needed.
1821
+ */
1822
+ const updateOptionsOf = (a, b, c, d) => (typeof a === "string" || Array.isArray(a) ? d : c) ?? {};
1823
+ /**
1824
+ * Applies one or more property updates to a query in place. Shared by
1825
+ * {@link update} and {@link updateInPlace}.
1826
+ */
1827
+ const applyUpdatesInPlace = (query, a, b, c, d) => {
1828
+ const { entries, pathOrID, options } = normalizeUpdateArgs(a, b, c, d);
1829
+ for (const [prop, value] of entries) updateInPlaceSingle(query, prop, value, pathOrID, options);
1830
+ return query;
1831
+ };
1832
+ /**
1833
+ * Updates one or more properties of a rule or group within a query without
1834
+ * mutating the original query. Properties may be supplied individually
1835
+ * (`prop`, `value`), as parallel arrays (`props`, `values`), or as a
1836
+ * property-to-value map. For multi-property updates, `field`, `operator`, and
1837
+ * `valueSource` are applied before `value`, so an explicit `value` is never
1838
+ * reset by a change to one of those properties.
1839
+ *
1840
+ * @returns A new query with the rule or group properties updated.
1841
+ *
1842
+ * @group Query Tools
1843
+ */
1844
+ const update = ((query, a, b, c, d) => producerFor(updateOptionsOf(a, b, c, d).freeze)(query, (q) => {
1845
+ applyUpdatesInPlace(q, a, b, c, d);
1846
+ }));
1847
+ /**
1848
+ * Updates one or more properties of a rule or group within a query in place.
1849
+ * See {@link update} for the supported argument forms and ordering semantics.
1850
+ *
1851
+ * @returns The query (mutated in place) with the rule or group properties updated.
1852
+ *
1853
+ * @group Query Tools
1854
+ */
1855
+ const updateInPlace = ((query, a, b, c, d) => applyUpdatesInPlace(query, a, b, c, d));
1856
+ /**
1857
+ * Updates a single property of a rule or group within a query in place.
1858
+ */
1859
+ const updateInPlaceSingle = (query, prop, value, pathOrID, options = {}) => {
1860
+ const { resetOnFieldChange: _resetOnFieldChange = true, resetOnOperatorChange = false, getRuleDefaultOperator = () => "=", getValueSources = () => ["value"], getRuleDefaultValue = () => "", getMatchModes = () => [], onAbort } = options;
1861
+ let resetOnFieldChange = _resetOnFieldChange;
1862
+ const path = Array.isArray(pathOrID) ? pathOrID : getPathOfID(pathOrID, query);
1863
+ if (!path) {
1864
+ onAbort?.({
1865
+ reason: "target-not-found",
1866
+ operation: "update",
1867
+ pathOrID
1868
+ });
1869
+ return query;
1870
+ }
1871
+ const updateGuards = prop === "disabled" ? { queryDisabled: options.queryDisabled } : options;
1872
+ const updateGuardReason = getGuardAbortReason(query, path, updateGuards);
1873
+ if (updateGuardReason) {
1874
+ onAbort?.({
1875
+ reason: updateGuardReason,
1876
+ operation: "update",
1877
+ pathOrID
1878
+ });
1879
+ return query;
1880
+ }
1881
+ if (prop === "combinator" && !isRuleGroupType(query)) {
1882
+ const parent = findPath(getParentPath(path), query);
1883
+ if (!parent || !isRuleGroup(parent)) {
1884
+ onAbort?.({
1885
+ reason: "target-not-found",
1886
+ operation: "update",
1887
+ pathOrID
1888
+ });
1889
+ return query;
1890
+ }
1891
+ const parentRules = parent.rules;
1892
+ if (path.at(-1) % 2 === 1) {
1893
+ if (parentRules[path.at(-1)] === value) onAbort?.({
1894
+ reason: "no-change",
1895
+ operation: "update",
1896
+ pathOrID
1897
+ });
1898
+ else parentRules[path.at(-1)] = value;
1899
+ } else onAbort?.({
1900
+ reason: "not-a-combinator-slot",
1901
+ operation: "update",
1902
+ pathOrID
1903
+ });
1904
+ return query;
1905
+ }
1906
+ const ruleOrGroup = findPath(path, query);
1907
+ if (!ruleOrGroup) {
1908
+ onAbort?.({
1909
+ reason: "target-not-found",
1910
+ operation: "update",
1911
+ pathOrID
1912
+ });
1913
+ return query;
1914
+ }
1915
+ const isGroup = isRuleGroup(ruleOrGroup);
1916
+ if (ruleOrGroup[prop] === value) {
1917
+ onAbort?.({
1918
+ reason: "no-change",
1919
+ operation: "update",
1920
+ pathOrID
1921
+ });
1922
+ return query;
1923
+ }
1924
+ if (prop !== "valueSource") ruleOrGroup[prop] = value;
1925
+ if (isGroup) return query;
1926
+ let resetValueSource = false;
1927
+ let resetValue = false;
1928
+ if (prop === "field") {
1929
+ const fromFieldMatchModes = getMatchModes(ruleOrGroup.field);
1930
+ const toFieldMatchModes = getMatchModes(value);
1931
+ if (toFieldMatchModes.length === 0) delete ruleOrGroup.match;
1932
+ else {
1933
+ const nextMatchMode = ruleOrGroup.match?.mode && getOption(toFieldMatchModes, ruleOrGroup.match.mode) ? null : getFirstOption(toFieldMatchModes);
1934
+ if (nextMatchMode) ruleOrGroup.match = {
1935
+ mode: nextMatchMode,
1936
+ threshold: 1
1937
+ };
1938
+ }
1939
+ if (fromFieldMatchModes.length > 0 || toFieldMatchModes.length > 0) resetOnFieldChange = true;
1940
+ }
1941
+ if (resetOnFieldChange && prop === "field") {
1942
+ ruleOrGroup.operator = getRuleDefaultOperator(value);
1943
+ resetValueSource = true;
1944
+ resetValue = true;
1945
+ }
1946
+ if (resetOnOperatorChange && prop === "operator") {
1947
+ resetValueSource = true;
1948
+ resetValue = true;
1949
+ }
1950
+ const valueSources = getValueSourcesUtil({
1951
+ name: ruleOrGroup.field,
1952
+ value: ruleOrGroup.field,
1953
+ label: ""
1954
+ }, ruleOrGroup.operator, getValueSources);
1955
+ const defaultValueSource = getFirstOption(valueSources);
1956
+ if (resetValueSource && ruleOrGroup.valueSource && defaultValueSource !== ruleOrGroup.valueSource || prop === "valueSource" && value !== ruleOrGroup.valueSource) {
1957
+ resetValue = !!ruleOrGroup.valueSource || !ruleOrGroup.valueSource && value !== defaultValueSource;
1958
+ ruleOrGroup.valueSource = resetValueSource ? defaultValueSource : value;
1959
+ }
1960
+ if (resetValue) ruleOrGroup.value = getRuleDefaultValue(ruleOrGroup);
1961
+ return query;
1962
+ };
1963
+ /**
1964
+ * Removes a rule or group from a query without mutating the original query.
1965
+ *
1966
+ * @returns A new query with the rule or group removed.
1967
+ *
1968
+ * @group Query Tools
1969
+ */
1970
+ const remove = (query, pathOrID, options = {}) => producerFor(options.freeze)(query, (q) => removeInPlace(q, pathOrID, options));
1971
+ /**
1972
+ * Removes a rule or group from a query in place.
1973
+ *
1974
+ * @returns The query (mutated in place) with the rule or group removed.
1975
+ *
1976
+ * @group Query Tools
1977
+ */
1978
+ const removeInPlace = (query, pathOrID, options = {}) => {
1979
+ const { onAbort } = options;
1980
+ const path = Array.isArray(pathOrID) ? pathOrID : getPathOfID(pathOrID, query);
1981
+ if (!path) {
1982
+ onAbort?.({
1983
+ reason: "target-not-found",
1984
+ operation: "remove",
1985
+ pathOrID
1986
+ });
1987
+ return query;
1988
+ }
1989
+ if (path.length === 0) {
1990
+ onAbort?.({
1991
+ reason: "root-not-allowed",
1992
+ operation: "remove",
1993
+ pathOrID
1994
+ });
1995
+ return query;
1996
+ }
1997
+ const removeGuardReason = getGuardAbortReason(query, path, options);
1998
+ if (removeGuardReason) {
1999
+ onAbort?.({
2000
+ reason: removeGuardReason,
2001
+ operation: "remove",
2002
+ pathOrID
2003
+ });
2004
+ return query;
2005
+ }
2006
+ if (!findPath(path, query)) {
2007
+ onAbort?.({
2008
+ reason: "target-not-found",
2009
+ operation: "remove",
2010
+ pathOrID
2011
+ });
2012
+ return query;
2013
+ }
2014
+ const index = path.at(-1);
2015
+ const parent = findPath(getParentPath(path), query);
2016
+ if (!isRuleGroupType(parent) && parent.rules.length > 1) {
2017
+ const idxStartDelete = index === 0 ? 0 : index - 1;
2018
+ parent.rules.splice(idxStartDelete, 2);
2019
+ } else parent.rules.splice(index, 1);
2020
+ return query;
2021
+ };
2022
+ const getNextPath = (query, currentPath, newPathOrShiftDirection) => {
2023
+ if (Array.isArray(newPathOrShiftDirection)) return newPathOrShiftDirection;
2024
+ const ic = isRuleGroupTypeIC(query);
2025
+ if (newPathOrShiftDirection === "up") {
2026
+ if (pathsAreEqual(currentPath, [0])) return currentPath;
2027
+ else if (currentPath.at(-1) === 0) {
2028
+ const parentPath = getParentPath(currentPath);
2029
+ return [...getParentPath(parentPath), Math.max(0, parentPath.at(-1) - (ic ? 1 : 0))];
2030
+ } else {
2031
+ const evaluationPath = [...getParentPath(currentPath), Math.max(0, currentPath.at(-1) - (ic ? 2 : 1))];
2032
+ const entityAtTarget = findPath(evaluationPath, query);
2033
+ if (isRuleGroup(entityAtTarget)) return [...evaluationPath, entityAtTarget.rules.length];
2034
+ else return [...getParentPath(currentPath), Math.max(0, currentPath.at(-1) - (ic ? 3 : 1))];
2035
+ }
2036
+ } else if (newPathOrShiftDirection === "down") {
2037
+ if (pathsAreEqual([query.rules.length - 1], currentPath)) return currentPath;
2038
+ else if (currentPath.at(-1) === findPath(getParentPath(currentPath), query).rules.length - 1) {
2039
+ const parentPath = getParentPath(currentPath);
2040
+ return [...getParentPath(parentPath), parentPath.at(-1) + 1];
2041
+ } else {
2042
+ const evaluationPath = [...getParentPath(currentPath), currentPath.at(-1) + (ic ? 2 : 1)];
2043
+ const entityToEvaluate = findPath(evaluationPath, query);
2044
+ if (isRuleGroup(entityToEvaluate)) return [...evaluationPath, 0];
2045
+ else return [...getParentPath(currentPath), currentPath.at(-1) + (ic ? 3 : 2)];
2046
+ }
2047
+ }
2048
+ return currentPath;
2049
+ };
2050
+ /**
2051
+ * Moves a rule or group from one path to another without mutating the original query.
2052
+ * In the options parameter, pass `{ clone: true }` to copy instead of move.
2053
+ *
2054
+ * @returns A new query with the rule or group moved or cloned.
2055
+ *
2056
+ * @group Query Tools
2057
+ */
2058
+ const move = (query, oldPathOrID, newPath, options = {}) => producerFor(options.freeze)(query, (q) => moveInPlace(q, oldPathOrID, newPath, options));
2059
+ /**
2060
+ * Moves a rule or group from one path to another in place.
2061
+ * In the options parameter, pass `{ clone: true }` to copy instead of move.
2062
+ *
2063
+ * @returns The query (mutated in place) with the rule or group moved or cloned.
2064
+ *
2065
+ * @group Query Tools
2066
+ */
2067
+ const moveInPlace = (query, oldPathOrID, newPath, options = {}) => {
2068
+ const { clone = false, combinators = defaultCombinators, idGenerator = generateID, onAbort } = options;
2069
+ const oldPath = Array.isArray(oldPathOrID) ? oldPathOrID : getPathOfID(oldPathOrID, query);
2070
+ if (!oldPath) {
2071
+ onAbort?.({
2072
+ reason: "target-not-found",
2073
+ operation: "move",
2074
+ pathOrID: oldPathOrID
2075
+ });
2076
+ return query;
2077
+ }
2078
+ const ruleOrGroupOriginal = findPath(oldPath, query);
2079
+ if (!ruleOrGroupOriginal) {
2080
+ onAbort?.({
2081
+ reason: "target-not-found",
2082
+ operation: "move",
2083
+ pathOrID: oldPathOrID
2084
+ });
2085
+ return query;
2086
+ }
2087
+ const nextPath = getNextPath(query, oldPath, newPath);
2088
+ if (oldPath.length === 0) {
2089
+ onAbort?.({
2090
+ reason: "root-not-allowed",
2091
+ operation: "move",
2092
+ pathOrID: oldPathOrID
2093
+ });
2094
+ return query;
2095
+ }
2096
+ const moveGuardReason = getGuardAbortReason(query, oldPath, options);
2097
+ if (moveGuardReason) {
2098
+ onAbort?.({
2099
+ reason: moveGuardReason,
2100
+ operation: "move",
2101
+ pathOrID: oldPathOrID
2102
+ });
2103
+ return query;
2104
+ }
2105
+ if (pathsAreEqual(oldPath, nextPath)) {
2106
+ onAbort?.({
2107
+ reason: "same-location",
2108
+ operation: "move",
2109
+ pathOrID: oldPathOrID
2110
+ });
2111
+ return query;
2112
+ }
2113
+ if (!findPath(getParentPath(nextPath), query)) {
2114
+ onAbort?.({
2115
+ reason: "destination-not-found",
2116
+ operation: "move",
2117
+ pathOrID: newPath
2118
+ });
2119
+ return query;
2120
+ }
2121
+ if (!clone && isAncestor(oldPath, nextPath)) {
2122
+ onAbort?.({
2123
+ reason: "destination-not-found",
2124
+ operation: "move",
2125
+ pathOrID: newPath
2126
+ });
2127
+ return query;
2128
+ }
2129
+ const ruleOrGroup = clone ? regenerateIDs(isDraft(ruleOrGroupOriginal) ? current(ruleOrGroupOriginal) : ruleOrGroupOriginal, { idGenerator }) : ruleOrGroupOriginal;
2130
+ const independentCombinators = isRuleGroupTypeIC(query);
2131
+ const parentOfRuleToRemove = findPath(getParentPath(oldPath), query);
2132
+ const ruleToRemoveIndex = oldPath.at(-1);
2133
+ const oldPrevCombinator = independentCombinators && ruleToRemoveIndex > 0 ? parentOfRuleToRemove.rules[ruleToRemoveIndex - 1] : null;
2134
+ const oldNextCombinator = independentCombinators && ruleToRemoveIndex < parentOfRuleToRemove.rules.length - 1 ? parentOfRuleToRemove.rules[ruleToRemoveIndex + 1] : null;
2135
+ if (!clone) {
2136
+ const idxStartDelete = independentCombinators ? Math.max(0, ruleToRemoveIndex - 1) : ruleToRemoveIndex;
2137
+ const deleteLength = independentCombinators ? 2 : 1;
2138
+ parentOfRuleToRemove.rules.splice(idxStartDelete, deleteLength);
2139
+ }
2140
+ const newNewPath = [...nextPath];
2141
+ if (independentCombinators && newNewPath.at(-1) % 2 === 1) newNewPath[newNewPath.length - 1] += 1;
2142
+ const commonAncestorPath = getCommonAncestorPath(oldPath, nextPath);
2143
+ if (!clone && oldPath.length === commonAncestorPath.length + 1 && newNewPath[commonAncestorPath.length] > oldPath[commonAncestorPath.length]) newNewPath[commonAncestorPath.length] -= independentCombinators ? 2 : 1;
2144
+ const newNewParentPath = getParentPath(newNewPath);
2145
+ const parentToInsertInto = findPath(newNewParentPath, query);
2146
+ const newIndex = newNewPath.at(-1);
2147
+ const spliceIndex = independentCombinators && newIndex > 0 ? newIndex - 1 : newIndex;
2148
+ /**
2149
+ * This function 1) glosses over the need for type assertions to splice directly
2150
+ * into `parentToInsertInto.rules`, and 2) shortens the actual insertion code.
2151
+ */
2152
+ const insertRuleOrGroup = (...args) => parentToInsertInto.rules.splice(spliceIndex, 0, ...args);
2153
+ if (parentToInsertInto.rules.length === 0 || !independentCombinators) insertRuleOrGroup(ruleOrGroup);
2154
+ else if (newIndex === 0) {
2155
+ if (ruleToRemoveIndex === 0 && oldNextCombinator) insertRuleOrGroup(ruleOrGroup, oldNextCombinator);
2156
+ else insertRuleOrGroup(ruleOrGroup, parentToInsertInto.rules[1] ?? oldPrevCombinator ?? getFirstOption(combinators));
2157
+ } else if (oldPrevCombinator) insertRuleOrGroup(oldPrevCombinator, ruleOrGroup);
2158
+ else insertRuleOrGroup(parentToInsertInto.rules[spliceIndex - 2] ?? oldNextCombinator ?? getFirstOption(combinators), ruleOrGroup);
2159
+ return query;
2160
+ };
2161
+ /**
2162
+ * Inserts a rule or group into a query without mutating the original query.
2163
+ *
2164
+ * @returns A new query with the rule or group inserted.
2165
+ *
2166
+ * @group Query Tools
2167
+ */
2168
+ const insert = (query, ruleOrGroup, path, options = {}) => producerFor(options.freeze)(query, (q) => insertInPlace(q, ruleOrGroup, path, options));
2169
+ /**
2170
+ * Inserts a rule or group into a query in place.
2171
+ *
2172
+ * @returns The query (mutated in place) with the rule or group inserted.
2173
+ *
2174
+ * @group Query Tools
2175
+ */
2176
+ const insertInPlace = (query, ruleOrGroup, path, options = {}) => {
2177
+ const { combinators = defaultCombinators, combinatorPreceding, combinatorSucceeding, idGenerator = generateID, replace = false, onAbort } = options;
2178
+ const parentToInsertInto = findPath(getParentPath(path), query);
2179
+ if (!parentToInsertInto) {
2180
+ onAbort?.({
2181
+ reason: "parent-not-found",
2182
+ operation: "insert",
2183
+ pathOrID: path
2184
+ });
2185
+ return query;
2186
+ }
2187
+ if (!isRuleGroup(parentToInsertInto)) {
2188
+ onAbort?.({
2189
+ reason: "parent-not-a-group",
2190
+ operation: "insert",
2191
+ pathOrID: path
2192
+ });
2193
+ return query;
2194
+ }
2195
+ const parentPath = getParentPath(path);
2196
+ const insertGuardReason = getGuardAbortReason(query, parentPath, options, { asParent: true });
2197
+ if (insertGuardReason) {
2198
+ onAbort?.({
2199
+ reason: insertGuardReason,
2200
+ operation: "insert",
2201
+ pathOrID: path
2202
+ });
2203
+ return query;
2204
+ }
2205
+ if (isRuleGroup(ruleOrGroup) && exceedsMaxLevels(parentPath, options)) {
2206
+ onAbort?.({
2207
+ reason: "max-levels-exceeded",
2208
+ operation: "insert",
2209
+ pathOrID: path
2210
+ });
2211
+ return query;
2212
+ }
2213
+ const rorg = regenerateIDs(ruleOrGroup, { idGenerator });
2214
+ const independentCombinators = isRuleGroupTypeIC(query);
2215
+ const newIndex = path.at(-1);
2216
+ /**
2217
+ * This function 1) glosses over the need for type assertions to splice directly
2218
+ * into `parentToInsertInto.rules`, and 2) shortens the actual insertion code.
2219
+ */
2220
+ const insertRuleOrGroup = (idx, ...args) => parentToInsertInto.rules.splice(idx, replace ? args.length : 0, ...args);
2221
+ if (parentToInsertInto.rules.length === 0 || !independentCombinators) insertRuleOrGroup(newIndex, rorg);
2222
+ else if (replace && independentCombinators) insertRuleOrGroup(newIndex + newIndex % 2, rorg);
2223
+ else if (newIndex === 0) {
2224
+ if (rorg.path?.at(-1) === 0 && combinatorSucceeding) insertRuleOrGroup(newIndex, rorg, combinatorSucceeding);
2225
+ else insertRuleOrGroup(newIndex, rorg, parentToInsertInto.rules[1] ?? combinatorPreceding ?? getFirstOption(combinators));
2226
+ } else {
2227
+ const normalizedNewIndex = newIndex % 2 === 0 ? newIndex - 1 : newIndex;
2228
+ if (combinatorPreceding) insertRuleOrGroup(normalizedNewIndex, combinatorPreceding, rorg);
2229
+ else insertRuleOrGroup(normalizedNewIndex, parentToInsertInto.rules[normalizedNewIndex - 2] ?? combinatorSucceeding ?? getFirstOption(combinators), rorg);
2230
+ }
2231
+ return query;
2232
+ };
2233
+ /**
2234
+ * Creates a new group at a target path with its `rules` array containing the current
2235
+ * objects at the target path and the source path without mutating the original query.
2236
+ * In the options parameter, pass `{ clone: true }` to copy the source rule/group instead of move.
2237
+ *
2238
+ * @returns A new query with the rules or groups grouped.
2239
+ *
2240
+ * @group Query Tools
2241
+ */
2242
+ const group = (query, sourcePathOrID, targetPathOrID, options = {}) => producerFor(options.freeze)(query, (q) => groupInPlace(q, sourcePathOrID, targetPathOrID, options));
2243
+ /**
2244
+ * Creates a new group at a target path with its `rules` array containing the current
2245
+ * objects at the target path and the source path in place.
2246
+ * In the options parameter, pass `{ clone: true }` to copy the source rule/group instead of move.
2247
+ *
2248
+ * @returns The query (mutated in place) with the rules or groups grouped.
2249
+ *
2250
+ * @group Query Tools
2251
+ */
2252
+ const groupInPlace = (query, sourcePathOrID, targetPathOrID, options = {}) => {
2253
+ const { clone = false, combinators = defaultCombinators, idGenerator = generateID, onAbort } = options;
2254
+ const sourcePath = Array.isArray(sourcePathOrID) ? sourcePathOrID : getPathOfID(sourcePathOrID, query);
2255
+ const targetPath = Array.isArray(targetPathOrID) ? targetPathOrID : getPathOfID(targetPathOrID, query);
2256
+ if (!sourcePath) {
2257
+ onAbort?.({
2258
+ reason: "target-not-found",
2259
+ operation: "group",
2260
+ pathOrID: sourcePathOrID
2261
+ });
2262
+ return query;
2263
+ }
2264
+ if (!targetPath) {
2265
+ onAbort?.({
2266
+ reason: "target-not-found",
2267
+ operation: "group",
2268
+ pathOrID: targetPathOrID
2269
+ });
2270
+ return query;
2271
+ }
2272
+ const nextPath = getNextPath(query, sourcePath, targetPath);
2273
+ if (sourcePath.length === 0) {
2274
+ onAbort?.({
2275
+ reason: "root-not-allowed",
2276
+ operation: "group",
2277
+ pathOrID: sourcePathOrID
2278
+ });
2279
+ return query;
2280
+ }
2281
+ const groupGuardReason = getGuardAbortReason(query, sourcePath, options);
2282
+ if (groupGuardReason) {
2283
+ onAbort?.({
2284
+ reason: groupGuardReason,
2285
+ operation: "group",
2286
+ pathOrID: sourcePathOrID
2287
+ });
2288
+ return query;
2289
+ }
2290
+ if (pathsAreEqual(sourcePath, nextPath)) {
2291
+ onAbort?.({
2292
+ reason: "same-location",
2293
+ operation: "group",
2294
+ pathOrID: sourcePathOrID
2295
+ });
2296
+ return query;
2297
+ }
2298
+ if (!findPath(getParentPath(nextPath), query)) {
2299
+ onAbort?.({
2300
+ reason: "destination-not-found",
2301
+ operation: "group",
2302
+ pathOrID: targetPathOrID
2303
+ });
2304
+ return query;
2305
+ }
2306
+ if (!clone && isAncestor(sourcePath, nextPath)) {
2307
+ onAbort?.({
2308
+ reason: "destination-not-found",
2309
+ operation: "group",
2310
+ pathOrID: targetPathOrID
2311
+ });
2312
+ return query;
2313
+ }
2314
+ const sourceRuleOrGroupOriginal = findPath(sourcePath, query);
2315
+ const targetRuleOrGroup = findPath(targetPath, query);
2316
+ if (!sourceRuleOrGroupOriginal) {
2317
+ onAbort?.({
2318
+ reason: "target-not-found",
2319
+ operation: "group",
2320
+ pathOrID: sourcePathOrID
2321
+ });
2322
+ return query;
2323
+ }
2324
+ if (!targetRuleOrGroup) {
2325
+ onAbort?.({
2326
+ reason: "target-not-found",
2327
+ operation: "group",
2328
+ pathOrID: targetPathOrID
2329
+ });
2330
+ return query;
2331
+ }
2332
+ const sourceRuleOrGroup = clone ? regenerateIDs(isDraft(sourceRuleOrGroupOriginal) ? current(sourceRuleOrGroupOriginal) : sourceRuleOrGroupOriginal, { idGenerator }) : sourceRuleOrGroupOriginal;
2333
+ const independentCombinators = isRuleGroupTypeIC(query);
2334
+ const parentOfRuleToRemove = findPath(getParentPath(sourcePath), query);
2335
+ const ruleToRemoveIndex = sourcePath.at(-1);
2336
+ if (!clone) {
2337
+ const idxStartDelete = independentCombinators ? Math.max(0, ruleToRemoveIndex - 1) : ruleToRemoveIndex;
2338
+ const deleteLength = independentCombinators ? 2 : 1;
2339
+ parentOfRuleToRemove.rules.splice(idxStartDelete, deleteLength);
2340
+ }
2341
+ const newNewPath = [...nextPath];
2342
+ const commonAncestorPath = getCommonAncestorPath(sourcePath, nextPath);
2343
+ if (!clone && sourcePath.length === commonAncestorPath.length + 1 && nextPath[commonAncestorPath.length] > sourcePath[commonAncestorPath.length]) newNewPath[commonAncestorPath.length] -= independentCombinators ? 2 : 1;
2344
+ const newNewParentPath = getParentPath(newNewPath);
2345
+ const parentOfTargetPath = findPath(newNewParentPath, query);
2346
+ const targetPathIndex = newNewPath.at(-1);
2347
+ parentOfTargetPath.rules.splice(targetPathIndex, 1, prepareRuleOrGroup(independentCombinators ? { rules: [
2348
+ targetRuleOrGroup,
2349
+ getFirstOption(combinators),
2350
+ sourceRuleOrGroup
2351
+ ] } : {
2352
+ combinator: getFirstOption(combinators),
2353
+ rules: [targetRuleOrGroup, sourceRuleOrGroup]
2354
+ }, { idGenerator }));
2355
+ return query;
2356
+ };
2357
+ //#endregion
2358
+ //#region src/utils/queryActions.ts
2359
+ /**
2360
+ * Builds the query builder's six mutation handlers as pure functions of the current query.
2361
+ *
2362
+ * This is the framework-agnostic core of the action handlers in `useQueryBuilderSchema`. It owns
2363
+ * the policy that surrounds the query tools—disabled gating, the confirmation callback protocol,
2364
+ * `maxLevels`, and debug logging—so an implementation only has to supply its own storage: read
2365
+ * the current query, call the action, and apply a non-`undefined` result.
2366
+ *
2367
+ * @group Query Tools
2368
+ */
2369
+ const createQueryActions = (config = {}) => {
2370
+ const { qbId, combinators, idGenerator, maxLevels = Infinity, queryDisabled, respectDisabled = true, disabledPaths, resetOnFieldChange, resetOnOperatorChange, getRuleDefaultOperator, getValueSources, getRuleDefaultValue, getMatchModes, freeze, onAddRule, onAddGroup, onRemove, onMoveRule, onMoveGroup, onGroupRule, onGroupGroup, onLog } = config;
2371
+ const log = (payload) => onLog?.({
2372
+ qbId,
2373
+ ...payload
2374
+ });
2375
+ const guards = {
2376
+ respectDisabled,
2377
+ queryDisabled,
2378
+ disabledPaths
2379
+ };
2380
+ /** Whether the mutation is blocked, using the same rules the query tools apply internally. */
2381
+ const blocked = (query, path, asParent = false) => !!getGuardAbortReason(query, path, guards, { asParent });
2382
+ return {
2383
+ addRule: (query, rule, parentPath, context) => {
2384
+ if (blocked(query, parentPath, true)) {
2385
+ log({
2386
+ type: LogType.parentPathDisabled,
2387
+ rule,
2388
+ parentPath,
2389
+ query
2390
+ });
2391
+ return;
2392
+ }
2393
+ const nextRule = onAddRule ? onAddRule(rule, parentPath, query, context) : true;
2394
+ if (!nextRule) {
2395
+ log({
2396
+ type: LogType.onAddRuleFalse,
2397
+ rule,
2398
+ parentPath,
2399
+ query
2400
+ });
2401
+ return;
2402
+ }
2403
+ const newRule = nextRule === true ? rule : nextRule;
2404
+ const newQuery = add(query, newRule, parentPath, {
2405
+ combinators,
2406
+ combinatorPreceding: newRule.combinatorPreceding,
2407
+ idGenerator,
2408
+ freeze
2409
+ });
2410
+ log({
2411
+ type: LogType.add,
2412
+ query,
2413
+ newQuery,
2414
+ newRule,
2415
+ parentPath
2416
+ });
2417
+ return newQuery;
2418
+ },
2419
+ addGroup: (query, ruleGroup, parentPath, context) => {
2420
+ if (parentPath.length >= maxLevels) return void 0;
2421
+ if (blocked(query, parentPath, true)) {
2422
+ log({
2423
+ type: LogType.parentPathDisabled,
2424
+ ruleGroup,
2425
+ parentPath,
2426
+ query
2427
+ });
2428
+ return;
2429
+ }
2430
+ const nextGroup = onAddGroup ? onAddGroup(ruleGroup, parentPath, query, context) : true;
2431
+ if (!nextGroup) {
2432
+ log({
2433
+ type: LogType.onAddGroupFalse,
2434
+ ruleGroup,
2435
+ parentPath,
2436
+ query
2437
+ });
2438
+ return;
2439
+ }
2440
+ const newGroup = nextGroup === true ? ruleGroup : nextGroup;
2441
+ const newQuery = add(query, newGroup, parentPath, {
2442
+ combinators,
2443
+ combinatorPreceding: newGroup.combinatorPreceding ?? void 0,
2444
+ idGenerator,
2445
+ freeze
2446
+ });
2447
+ log({
2448
+ type: LogType.add,
2449
+ query,
2450
+ newQuery,
2451
+ newGroup,
2452
+ parentPath
2453
+ });
2454
+ return newQuery;
2455
+ },
2456
+ propChange: (query, prop, value, path) => {
2457
+ if (getGuardAbortReason(query, path, prop === "disabled" ? { queryDisabled } : guards)) {
2458
+ log({
2459
+ type: LogType.pathDisabled,
2460
+ path,
2461
+ prop,
2462
+ value,
2463
+ query
2464
+ });
2465
+ return;
2466
+ }
2467
+ const newQuery = update(query, prop, value, path, {
2468
+ resetOnFieldChange,
2469
+ resetOnOperatorChange,
2470
+ getRuleDefaultOperator,
2471
+ getValueSources,
2472
+ getRuleDefaultValue,
2473
+ getMatchModes,
2474
+ freeze
2475
+ });
2476
+ log({
2477
+ type: LogType.update,
2478
+ query,
2479
+ newQuery,
2480
+ prop,
2481
+ value,
2482
+ path
2483
+ });
2484
+ return newQuery;
2485
+ },
2486
+ removeRuleOrGroup: (query, path, context) => {
2487
+ if (blocked(query, path)) {
2488
+ log({
2489
+ type: LogType.pathDisabled,
2490
+ path,
2491
+ query
2492
+ });
2493
+ return;
2494
+ }
2495
+ const ruleOrGroup = findPath(path, query);
2496
+ /* v8 ignore next -- @preserve */
2497
+ if (!ruleOrGroup) return void 0;
2498
+ if (onRemove && !onRemove(ruleOrGroup, path, query, context)) {
2499
+ log({
2500
+ type: LogType.onRemoveFalse,
2501
+ ruleOrGroup,
2502
+ path,
2503
+ query
2504
+ });
2505
+ return;
2506
+ }
2507
+ const newQuery = remove(query, path, { freeze });
2508
+ log({
2509
+ type: LogType.remove,
2510
+ query,
2511
+ newQuery,
2512
+ path,
2513
+ ruleOrGroup
2514
+ });
2515
+ return newQuery;
2516
+ },
2517
+ moveRule: (query, oldPath, newPath, clone, context) => {
2518
+ if (blocked(query, oldPath)) {
2519
+ log({
2520
+ type: LogType.pathDisabled,
2521
+ oldPath,
2522
+ newPath,
2523
+ query
2524
+ });
2525
+ return;
2526
+ }
2527
+ const ruleOrGroup = findPath(oldPath, query);
2528
+ if (!ruleOrGroup) return void 0;
2529
+ const nextQuery = move(query, oldPath, newPath, {
2530
+ clone,
2531
+ combinators,
2532
+ idGenerator,
2533
+ freeze
2534
+ });
2535
+ const isGroup = isRuleGroup(ruleOrGroup);
2536
+ const callback = isGroup ? onMoveGroup : onMoveRule;
2537
+ const callbackResult = callback ? callback(ruleOrGroup, oldPath, newPath, query, nextQuery, {
2538
+ clone,
2539
+ combinators
2540
+ }, context) : true;
2541
+ if (!callbackResult) {
2542
+ log({
2543
+ type: isGroup ? LogType.onMoveGroupFalse : LogType.onMoveRuleFalse,
2544
+ ruleOrGroup,
2545
+ oldPath,
2546
+ newPath,
2547
+ clone,
2548
+ query,
2549
+ nextQuery
2550
+ });
2551
+ return;
2552
+ }
2553
+ const newQuery = isRuleGroup(callbackResult) ? callbackResult : nextQuery;
2554
+ log({
2555
+ type: LogType.move,
2556
+ query,
2557
+ newQuery,
2558
+ oldPath,
2559
+ newPath,
2560
+ clone
2561
+ });
2562
+ return newQuery;
2563
+ },
2564
+ groupRule: (query, sourcePath, targetPath, clone, context) => {
2565
+ if (blocked(query, sourcePath)) {
2566
+ log({
2567
+ type: LogType.pathDisabled,
2568
+ sourcePath,
2569
+ targetPath,
2570
+ query
2571
+ });
2572
+ return;
2573
+ }
2574
+ const ruleOrGroup = findPath(sourcePath, query);
2575
+ if (!ruleOrGroup) return void 0;
2576
+ const nextQuery = group(query, sourcePath, targetPath, {
2577
+ clone,
2578
+ combinators,
2579
+ idGenerator,
2580
+ freeze
2581
+ });
2582
+ const isGroup = isRuleGroup(ruleOrGroup);
2583
+ const callback = isGroup ? onGroupGroup : onGroupRule;
2584
+ const callbackResult = callback ? callback(ruleOrGroup, sourcePath, targetPath, query, nextQuery, {
2585
+ clone,
2586
+ combinators
2587
+ }, context) : true;
2588
+ if (!callbackResult) {
2589
+ log({
2590
+ type: isGroup ? LogType.onGroupGroupFalse : LogType.onGroupRuleFalse,
2591
+ ruleOrGroup,
2592
+ sourcePath,
2593
+ targetPath,
2594
+ clone,
2595
+ query,
2596
+ nextQuery
2597
+ });
2598
+ return;
2599
+ }
2600
+ const newQuery = isRuleGroup(callbackResult) ? callbackResult : nextQuery;
2601
+ log({
2602
+ type: LogType.group,
2603
+ query,
2604
+ newQuery,
2605
+ sourcePath,
2606
+ targetPath,
2607
+ clone
2608
+ });
2609
+ return newQuery;
2610
+ }
2611
+ };
2612
+ };
2613
+ //#endregion
2614
+ //#region src/utils/ruleFactory.ts
2615
+ /**
2616
+ * Creates a rule from the given configuration, applying the same precedence as the
2617
+ * `QueryBuilder` component. The `value` is computed in a second pass, once `field`, `operator`,
2618
+ * and `valueSource` are known, since the default value depends on all three.
2619
+ *
2620
+ * @group Query Tools
2621
+ */
2622
+ const createRule = ({ fields, getDefaultField, getRuleDefaultOperator, getValueSources, getMatchModes, getRuleDefaultValue, idGenerator = generateID }) => {
2623
+ let field = getFirstOption(fields) ?? "";
2624
+ if (getDefaultField) {
2625
+ if (typeof getDefaultField === "function") {
2626
+ const defaultField = getDefaultField(fields);
2627
+ if (defaultField) field = defaultField;
2628
+ } else field = getDefaultField;
2629
+ }
2630
+ const fieldData = getOption(fields, field);
2631
+ const operator = getRuleDefaultOperator(field);
2632
+ const valueSource = getFirstOption(getValueSources(field, operator, { fieldData })) ?? "value";
2633
+ const matchMode = getFirstOption(getMatchModes(field, { fieldData }));
2634
+ const newRule = {
2635
+ id: idGenerator(),
2636
+ field,
2637
+ operator,
2638
+ valueSource,
2639
+ value: "",
2640
+ ...matchMode ? { match: {
2641
+ mode: matchMode,
2642
+ threshold: 1
2643
+ } } : null
2644
+ };
2645
+ return {
2646
+ ...newRule,
2647
+ value: getRuleDefaultValue(newRule)
2648
+ };
2649
+ };
2650
+ /**
2651
+ * Creates a group from the given configuration. Pass `true` for `independentCombinators` to omit
2652
+ * the `combinator` property.
2653
+ *
2654
+ * The group's own `id` is generated _before_ any contained rule's, matching the order the
2655
+ * `QueryBuilder` component has always used. This is observable when `idGenerator` is
2656
+ * deterministic, as it often is in tests.
2657
+ *
2658
+ * @group Query Tools
2659
+ */
2660
+ const createRuleGroup = ({ combinators, addRuleToNewGroups, createRule: createRuleMain, idGenerator = generateID }, independentCombinators) => {
2661
+ const id = idGenerator();
2662
+ const rules = addRuleToNewGroups ? [createRuleMain()] : [];
2663
+ if (independentCombinators) return {
2664
+ id,
2665
+ rules,
2666
+ not: false
2667
+ };
2668
+ return {
2669
+ id,
2670
+ rules,
2671
+ combinator: getFirstOption(combinators) ?? "",
2672
+ not: false
2673
+ };
2674
+ };
2675
+ //#endregion
2676
+ export { LogType, TestID, add, addInPlace, betweenOperators, clsx, coerceBigIntValue, coerceInputType, controlKeys, controlKind, controlPropKeys, convertFromIC, convertQuery, convertToIC, createQueryActions, createRule, createRuleGroup, defaultCoalesceMs, defaultCombinatorLabelMap, defaultCombinators, defaultCombinatorsExtended, defaultControlClassnames, defaultJoinChar, defaultMatchModes, defaultMaxHistory, defaultOperatorLabelMap, defaultOperatorNegationMap, defaultOperators, defaultPlaceholderFieldGroupLabel, defaultPlaceholderFieldLabel, defaultPlaceholderFieldName, defaultPlaceholderLabel, defaultPlaceholderName, defaultPlaceholderOperatorGroupLabel, defaultPlaceholderOperatorLabel, defaultPlaceholderOperatorName, defaultPlaceholderValueGroupLabel, defaultPlaceholderValueLabel, defaultPlaceholderValueName, defaultTranslations, defaultValidator, derivePathInfo, deriveQueryBuilderClassNames, deriveRuleClassName, deriveRuleClassNames, deriveRuleContext, deriveRuleGroupClassNames, deriveRuleGroupContext, deriveRuleGroupOuterClassName, deriveRuleOuterClassName, exceedsMaxLevels, filterFieldsByComparator, findID, findPath, generateAccessibleDescription, generateID, getCommonAncestorPath, getFieldData, getFirstOption, getGuardAbortReason, getMatchModesUtil, getMultiValueUpdate, getOption, getParametersAsList, getParentPath, getParseNumberMethod, getPathOfID, getRuleDefaultValue, getRuleGroupCombinator, getRuleInputType, getRuleValidationResult, getRuleValueEditorType, getRuleValueSourceOptions, getRuleValues, getValidationClassNames, getValueEditorReset, getValueSelectorUpdate, getValueSourcesUtil, group, groupInPlace, groupInvalidReasons, hideValueControlsForOperator, inOperators, insert, insertInPlace, isAncestor, isBetweenOperator, isFlexibleOptionArray, isFlexibleOptionGroupArray, isFullOptionArray, isFullOptionGroupArray, isOptionGroupArray, isPojo, isRuleGroup, isRuleGroupType, isRuleGroupTypeIC, isRuleOrGroupValid, isRuleType, isUnsafeKey, isValidationResult, joinWith, lc, mergeAnyTranslation, mergeAnyTranslations, mergeClassnames, move, moveInPlace, normalizeValueSelectorValue, nullFreeArray, nullOperators, nullOrUndefinedOrEmpty, numericRegex, objectEntries, objectKeys, optionsEqual, parseNumber, pathIsDisabled, pathIsDisabledByPaths, pathsAreEqual, preferAnyProp, preferFlagProps, preferProp, prepareOptionList, prepareRule, prepareRuleGroup, prepareRuleOrGroup, queryBuilderFlagDefaults, regenerateID, regenerateIDs, relationalOperators, remove, removeInPlace, resolveCandidateQuery, resolveDefaultOperator, resolveOperatorList, resolveValueEditorType, resolveValueList, rootPath, setAutoFreeze, shouldCoalesce, signatureOf, splitBy, standardClassnames, strictAbortReasons, structuralSignature, substringOperators, toArray, toFlatOptionArray, toFullOption, toFullOptionList, toFullOptionMap, transformQuery, trimIfString, unchangedSignature, uniqByIdentifier, uniqByName, uniqOptGroups, uniqOptList, update, updateInPlace, uuidV4regex, valuesEqual };
2677
+
2678
+ //# sourceMappingURL=derivations.mjs.map