@qoretechnologies/reqraft 0.10.39-pr.99.gdbafa34 → 0.10.39

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 (110) hide show
  1. package/.claude/CLAUDE.md +12 -0
  2. package/dist/components/codeSize/index.d.ts +37 -0
  3. package/dist/components/codeSize/index.d.ts.map +1 -0
  4. package/dist/components/codeSize/index.js +87 -0
  5. package/dist/components/codeSize/index.js.map +1 -0
  6. package/dist/components/form/engine/CompactRow.d.ts +20 -1
  7. package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
  8. package/dist/components/form/engine/CompactRow.js +365 -30
  9. package/dist/components/form/engine/CompactRow.js.map +1 -1
  10. package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
  11. package/dist/components/form/engine/CompactToolbar.js +6 -8
  12. package/dist/components/form/engine/CompactToolbar.js.map +1 -1
  13. package/dist/components/form/engine/FormEngine.d.ts +24 -45
  14. package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
  15. package/dist/components/form/engine/FormEngine.js +211 -84
  16. package/dist/components/form/engine/FormEngine.js.map +1 -1
  17. package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts +37 -0
  18. package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts.map +1 -0
  19. package/dist/components/form/engine/_structuredData/SchemaDataView.js +335 -0
  20. package/dist/components/form/engine/_structuredData/SchemaDataView.js.map +1 -0
  21. package/dist/components/form/engine/compactRowStyles.d.ts +13 -0
  22. package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
  23. package/dist/components/form/engine/compactRowStyles.js +30 -5
  24. package/dist/components/form/engine/compactRowStyles.js.map +1 -1
  25. package/dist/components/form/engine/compactToolbarContext.d.ts +0 -8
  26. package/dist/components/form/engine/compactToolbarContext.d.ts.map +1 -1
  27. package/dist/components/form/engine/compactToolbarContext.js.map +1 -1
  28. package/dist/components/form/engine/readFirst.d.ts +73 -1
  29. package/dist/components/form/engine/readFirst.d.ts.map +1 -1
  30. package/dist/components/form/engine/readFirst.js +175 -5
  31. package/dist/components/form/engine/readFirst.js.map +1 -1
  32. package/dist/components/form/fields/Field.d.ts.map +1 -1
  33. package/dist/components/form/fields/Field.js +1 -1
  34. package/dist/components/form/fields/Field.js.map +1 -1
  35. package/dist/components/form/fields/allowed-values/AllowedValues.d.ts +12 -2
  36. package/dist/components/form/fields/allowed-values/AllowedValues.d.ts.map +1 -1
  37. package/dist/components/form/fields/allowed-values/AllowedValues.js +16 -6
  38. package/dist/components/form/fields/allowed-values/AllowedValues.js.map +1 -1
  39. package/dist/components/form/fields/array/ArrayAuto.d.ts.map +1 -1
  40. package/dist/components/form/fields/array/ArrayAuto.js +51 -21
  41. package/dist/components/form/fields/array/ArrayAuto.js.map +1 -1
  42. package/dist/components/form/fields/array/ArrayAutoField.d.ts.map +1 -1
  43. package/dist/components/form/fields/array/ArrayAutoField.js +42 -25
  44. package/dist/components/form/fields/array/ArrayAutoField.js.map +1 -1
  45. package/dist/components/form/fields/auto/AutoFormField.d.ts +4 -0
  46. package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
  47. package/dist/components/form/fields/auto/AutoFormField.js +29 -4
  48. package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
  49. package/dist/components/form/fields/long-string/LongString.d.ts +9 -1
  50. package/dist/components/form/fields/long-string/LongString.d.ts.map +1 -1
  51. package/dist/components/form/fields/long-string/LongString.js +25 -4
  52. package/dist/components/form/fields/long-string/LongString.js.map +1 -1
  53. package/dist/components/form/fields/template/TemplateField.d.ts.map +1 -1
  54. package/dist/components/form/fields/template/TemplateField.js +12 -2
  55. package/dist/components/form/fields/template/TemplateField.js.map +1 -1
  56. package/dist/helpers/common.d.ts +8 -1
  57. package/dist/helpers/common.d.ts.map +1 -1
  58. package/dist/helpers/common.js +9 -1
  59. package/dist/helpers/common.js.map +1 -1
  60. package/dist/helpers/optionUiTypes.d.ts +30 -0
  61. package/dist/helpers/optionUiTypes.d.ts.map +1 -0
  62. package/dist/helpers/optionUiTypes.js +148 -0
  63. package/dist/helpers/optionUiTypes.js.map +1 -0
  64. package/dist/helpers/options.d.ts +19 -0
  65. package/dist/helpers/options.d.ts.map +1 -1
  66. package/dist/helpers/options.js +25 -1
  67. package/dist/helpers/options.js.map +1 -1
  68. package/dist/helpers/providerValue.d.ts +68 -0
  69. package/dist/helpers/providerValue.d.ts.map +1 -0
  70. package/dist/helpers/providerValue.js +50 -0
  71. package/dist/helpers/providerValue.js.map +1 -0
  72. package/dist/helpers/singleLineString.d.ts +37 -0
  73. package/dist/helpers/singleLineString.d.ts.map +1 -0
  74. package/dist/helpers/singleLineString.js +66 -0
  75. package/dist/helpers/singleLineString.js.map +1 -0
  76. package/dist/helpers/validations.d.ts +85 -2
  77. package/dist/helpers/validations.d.ts.map +1 -1
  78. package/dist/helpers/validations.js +802 -76
  79. package/dist/helpers/validations.js.map +1 -1
  80. package/dist/index.d.ts +1 -0
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +1 -0
  83. package/dist/index.js.map +1 -1
  84. package/package.json +1 -1
  85. package/src/components/codeSize/index.tsx +79 -0
  86. package/src/components/form/engine/CompactRow.tsx +450 -31
  87. package/src/components/form/engine/CompactToolbar.tsx +16 -21
  88. package/src/components/form/engine/FormEngine.stories.tsx +804 -17
  89. package/src/components/form/engine/FormEngine.tsx +207 -105
  90. package/src/components/form/engine/_structuredData/SchemaDataView.stories.tsx +233 -0
  91. package/src/components/form/engine/_structuredData/SchemaDataView.tsx +630 -0
  92. package/src/components/form/engine/compactRowStyles.ts +44 -2
  93. package/src/components/form/engine/compactToolbarContext.ts +0 -8
  94. package/src/components/form/engine/readFirst.ts +201 -5
  95. package/src/components/form/fields/Field.tsx +3 -1
  96. package/src/components/form/fields/allowed-values/AllowedValues.tsx +24 -2
  97. package/src/components/form/fields/array/ArrayAuto.tsx +35 -4
  98. package/src/components/form/fields/array/ArrayAutoField.stories.tsx +134 -0
  99. package/src/components/form/fields/array/ArrayAutoField.tsx +22 -4
  100. package/src/components/form/fields/auto/AutoFormField.tsx +30 -1
  101. package/src/components/form/fields/long-string/LongString.tsx +46 -5
  102. package/src/components/form/fields/template/TemplateField.tsx +16 -1
  103. package/src/helpers/common.ts +11 -1
  104. package/src/helpers/optionUiTypes.ts +153 -0
  105. package/src/helpers/options.ts +23 -0
  106. package/src/helpers/providerValue.ts +125 -0
  107. package/src/helpers/singleLineString.ts +61 -0
  108. package/src/helpers/validations.ts +1105 -80
  109. package/src/hooks/useWebSocket/useWebsocket.stories.tsx +23 -2
  110. package/src/index.tsx +1 -0
@@ -202,7 +202,7 @@ var StyledCommitDock = styled_components_1.default.div(templateObject_2 || (temp
202
202
  return "".concat((0, colors_1.changeDarkness)($bg, 0.4)).concat((0, colors_1.percentToHexAlpha)(55));
203
203
  });
204
204
  var getType = function (type, operators, operator) {
205
- var finalType = getTypeFromOperator(operators, (0, exports.fixOperatorValue)(operator)) || type;
205
+ var finalType = getTypeFromOperator(operators, (0, common_1.fixOperatorValue)(operator)) || type;
206
206
  var resolvedType = (0, isArray_1.default)(finalType) ? finalType[0] : finalType;
207
207
  // A value can be received before its server-driven option schema. Keep the
208
208
  // renderer type-safe during that transition without guessing a concrete type.
@@ -216,10 +216,11 @@ var getTypeFromOperator = function (operators, operatorData) {
216
216
  }
217
217
  return ((_a = operators[(0, lodash_1.last)(operatorData)]) === null || _a === void 0 ? void 0 : _a.type) || null;
218
218
  };
219
- var fixOperatorValue = function (operator) {
220
- return (0, isArray_1.default)(operator) ? operator : [operator];
221
- };
222
- exports.fixOperatorValue = fixOperatorValue;
219
+ /** Re-exported from `helpers/common` so existing importers keep working; it
220
+ * lives there because `helpers/validations` needs it and cannot import this
221
+ * module (this module imports the validators). */
222
+ var common_2 = require("../../../helpers/common");
223
+ Object.defineProperty(exports, "fixOperatorValue", { enumerable: true, get: function () { return common_2.fixOperatorValue; } });
223
224
  var getOptionSchemaStorageType = function (option, isRendererOnly) {
224
225
  if (isRendererOnly === void 0) { isRendererOnly = rendererTypes_1.isRendererOnlyUiType; }
225
226
  return (((0, readFirst_1.isFixedCompactAllowedValueOption)(option)
@@ -253,7 +254,7 @@ var fixOptions = function (value, options, operators, isRendererOnly) {
253
254
  return fixedValue;
254
255
  }
255
256
  (0, lodash_1.forEach)(options, function (option, name) {
256
- var _a, _b, _c, _d, _f, _g, _h;
257
+ var _a, _b, _c, _d, _f, _g, _h, _j;
257
258
  if (option.value ||
258
259
  option.required_groups ||
259
260
  ((option.required || option.preselected) && !fixedValue[name]) ||
@@ -264,14 +265,30 @@ var fixOptions = function (value, options, operators, isRendererOnly) {
264
265
  ((_c = fixedValue[name]) === null || _c === void 0 ? void 0 : _c.value) === undefined) {
265
266
  obj = option.default_value;
266
267
  }
268
+ else if (option.default_view === 'expression' &&
269
+ ((_d = fixedValue[name]) === null || _d === void 0 ? void 0 : _d.value) === undefined) {
270
+ // A field the schema declares as opening in expression mode starts as an
271
+ // EMPTY expression, not as its raw default. `isDefaultFunction` already
272
+ // makes the renderer open that way, so without this the data disagreed
273
+ // with what the operator was looking at: an expression editor whose
274
+ // value was still the plain default, and no `is_expression` on the field
275
+ // until the first edit.
276
+ obj = {
277
+ type: type,
278
+ value: {
279
+ args: [],
280
+ },
281
+ is_expression: true,
282
+ };
283
+ }
267
284
  else {
268
285
  obj = {
269
286
  type: type,
270
- value: (_g = (_f = (typeof fixedValue[name] === 'object' ?
271
- (_d = fixedValue[name]) === null || _d === void 0 ? void 0 : _d.value
272
- : fixedValue[name])) !== null && _f !== void 0 ? _f : option.value) !== null && _g !== void 0 ? _g : (0, common_1.getDefaultValue)(option),
287
+ value: (_h = (_g = (typeof fixedValue[name] === 'object' ?
288
+ (_f = fixedValue[name]) === null || _f === void 0 ? void 0 : _f.value
289
+ : fixedValue[name])) !== null && _g !== void 0 ? _g : option.value) !== null && _h !== void 0 ? _h : (0, common_1.getDefaultValue)(option),
273
290
  };
274
- if ((_h = fixedValue[name]) === null || _h === void 0 ? void 0 : _h.is_expression) {
291
+ if ((_j = fixedValue[name]) === null || _j === void 0 ? void 0 : _j.is_expression) {
275
292
  obj.is_expression = true;
276
293
  }
277
294
  }
@@ -280,7 +297,7 @@ var fixOptions = function (value, options, operators, isRendererOnly) {
280
297
  });
281
298
  var res = (0, reduce_1.default)(fixedValue, function (newValue, option, optionName) {
282
299
  var _a;
283
- var _b, _c, _d, _f, _g, _h, _j, _k;
300
+ var _b, _c, _d, _f, _g, _h, _j;
284
301
  var newOption = option;
285
302
  if (!(0, lodash_1.isPlainObject)(newOption) || !(newOption === null || newOption === void 0 ? void 0 : newOption.type)) {
286
303
  var isUntypedEnvelope = (0, lodash_1.isPlainObject)(newOption) && 'value' in newOption;
@@ -295,17 +312,35 @@ var fixOptions = function (value, options, operators, isRendererOnly) {
295
312
  isRendererOnly(newOption.type)) {
296
313
  newOption = __assign(__assign({}, newOption), { type: (0, exports.getType)(getOptionSchemaStorageType(options === null || options === void 0 ? void 0 : options[optionName], isRendererOnly), operators, newOption.op) });
297
314
  }
315
+ // A value that is not one of the declared choices is dropped. What counts
316
+ // as "one of the choices" is `findAllowedValueOption` — the same predicate
317
+ // the read-first row uses to LABEL a value — because a value the row can
318
+ // name is by definition a value the form must keep. Inlining a narrower
319
+ // test here (envelope and `name`, but not a bare `value`) silently erased
320
+ // every value declared the bare way: the collapsed row still showed its
321
+ // display name while the editor showed "—" and the value never reached
322
+ // the submitted data.
323
+ // `allowed_values: []` is NOT "no value is permitted" — it is the server
324
+ // saying it has no reference values to offer right now (the app-action
325
+ // catalogue ships exactly that, with an
326
+ // `option_reference_values_unavailable` message attached). An empty array
327
+ // is truthy, so testing the array itself made every such option erase the
328
+ // operator's stored value on the first render, before the
329
+ // connection-refreshed schema arrived to say otherwise — and the emptied
330
+ // form then autosaved over the draft, so the value was gone for good.
331
+ // Only an option that actually declares choices can have a value that is
332
+ // not one of them.
298
333
  if (newOption.value !== undefined &&
299
- ((_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.allowed_values) &&
300
- !((_f = (_d = options === null || options === void 0 ? void 0 : options[optionName]) === null || _d === void 0 ? void 0 : _d.allowed_values) === null || _f === void 0 ? void 0 : _f.find(function (allowedValue) { var _a; return ((_a = allowedValue.value) === null || _a === void 0 ? void 0 : _a.value) === newOption.value || allowedValue.name === newOption.value; })) &&
334
+ ((_d = (_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.allowed_values) === null || _d === void 0 ? void 0 : _d.length) &&
335
+ !(0, readFirst_1.findAllowedValueOption)(newOption.value, options === null || options === void 0 ? void 0 : options[optionName]) &&
301
336
  !(0, TemplateField_1.isValueTemplate)(newOption.value) &&
302
- !((_g = options === null || options === void 0 ? void 0 : options[optionName]) === null || _g === void 0 ? void 0 : _g.multiselect) &&
303
- !((_h = options === null || options === void 0 ? void 0 : options[optionName]) === null || _h === void 0 ? void 0 : _h.allowed_values_creatable)) {
337
+ !((_f = options === null || options === void 0 ? void 0 : options[optionName]) === null || _f === void 0 ? void 0 : _f.multiselect) &&
338
+ !((_g = options === null || options === void 0 ? void 0 : options[optionName]) === null || _g === void 0 ? void 0 : _g.allowed_values_creatable)) {
304
339
  newOption.value = undefined;
305
340
  }
306
341
  if (newOption.value &&
307
- ((_j = options === null || options === void 0 ? void 0 : options[optionName]) === null || _j === void 0 ? void 0 : _j.readonly) &&
308
- ((_k = options === null || options === void 0 ? void 0 : options[optionName]) === null || _k === void 0 ? void 0 : _k.default_value) &&
342
+ ((_h = options === null || options === void 0 ? void 0 : options[optionName]) === null || _h === void 0 ? void 0 : _h.readonly) &&
343
+ ((_j = options === null || options === void 0 ? void 0 : options[optionName]) === null || _j === void 0 ? void 0 : _j.default_value) &&
309
344
  (0, common_1.getDefaultValue)(options === null || options === void 0 ? void 0 : options[optionName]) !== newOption.value) {
310
345
  newOption.value = (0, common_1.getDefaultValue)(options[optionName]);
311
346
  }
@@ -364,12 +399,12 @@ var FormEngineImpl = function (_a) {
364
399
  var _b, _c, _d, _f, _g, _h;
365
400
  var name = _a.name, uniqueName = _a.uniqueName, value = _a.value, onChange = _a.onChange, onSingleOptionsChange = _a.onSingleOptionsChange, onDependableOptionChange = _a.onDependableOptionChange, placeholder = _a.placeholder, noValueString = _a.noValueString, // eslint-disable-line @typescript-eslint/no-unused-vars
366
401
  isValid = _a.isValid, // eslint-disable-line @typescript-eslint/no-unused-vars
367
- url = _a.url, customUrl = _a.customUrl, operatorsUrl = _a.operatorsUrl, onOptionsLoaded = _a.onOptionsLoaded, recordRequiresSearchOptions = _a.recordRequiresSearchOptions, readOnly = _a.readOnly, _j = _a.allowTemplates, allowTemplates = _j === void 0 ? true : _j, interfaceContext = _a.interfaceContext, templateFieldProps = _a.templateFieldProps, forceDropdown = _a.forceDropdown, _k = _a.showTypeToggle, showTypeToggle = _k === void 0 ? true : _k, compact = _a.compact, _l = _a.compactFlush, compactFlush = _l === void 0 ? false : _l, _m = _a.compactNested, compactNested = _m === void 0 ? false : _m, compactPanelProps = _a.compactPanelProps, _o = _a.compactCollapsedGroups, compactCollapsedGroups = _o === void 0 ? ['optional'] : _o, _p = _a.compactToolbar, compactToolbar = _p === void 0 ? true : _p, _q = _a.commitMode, commitMode = _q === void 0 ? 'immediate' : _q, _r = _a.expandMode, expandMode = _r === void 0 ? 'single' : _r, onCommit = _a.onCommit, operatorsProp = _a.operators, groups = _a.groups, optionsLoader = _a.optionsLoader, onValidityChange = _a.onValidityChange, optionActions = _a.optionActions, _s = _a.optionActionsCollapse, optionActionsCollapse = _s === void 0 ? 'auto' : _s, componentOverrides = _a.componentOverrides, codePreviewRenderer = _a.codePreviewRenderer,
402
+ url = _a.url, customUrl = _a.customUrl, operatorsUrl = _a.operatorsUrl, onOptionsLoaded = _a.onOptionsLoaded, recordRequiresSearchOptions = _a.recordRequiresSearchOptions, readOnly = _a.readOnly, _j = _a.allowTemplates, allowTemplates = _j === void 0 ? true : _j, interfaceContext = _a.interfaceContext, templateFieldProps = _a.templateFieldProps, forceDropdown = _a.forceDropdown, _k = _a.showTypeToggle, showTypeToggle = _k === void 0 ? true : _k, compact = _a.compact, _l = _a.compactFlush, compactFlush = _l === void 0 ? false : _l, _m = _a.compactNested, compactNested = _m === void 0 ? false : _m, compactPanelProps = _a.compactPanelProps, _o = _a.commitMode, commitMode = _o === void 0 ? 'immediate' : _o, _p = _a.expandMode, expandMode = _p === void 0 ? 'single' : _p, onCommit = _a.onCommit, operatorsProp = _a.operators, groups = _a.groups, optionsLoader = _a.optionsLoader, onValidityChange = _a.onValidityChange, optionActions = _a.optionActions, _q = _a.optionActionsCollapse, optionActionsCollapse = _q === void 0 ? 'auto' : _q, componentOverrides = _a.componentOverrides, codePreviewRenderer = _a.codePreviewRenderer,
368
403
  // consumed by the wrapper below, which publishes it to every description this
369
404
  // form draws; destructured here only so it cannot reach `rest` and be spread
370
405
  // onto a DOM node
371
406
  _markdownRenderer = _a.markdownRenderer, // eslint-disable-line @typescript-eslint/no-unused-vars
372
- rendererOnlyUiTypes = _a.rendererOnlyUiTypes, inheritedFromParent = _a.inheritedFromParent, autoFocusFirstRequired = _a.autoFocusFirstRequired, initialExpandedOptions = _a.initialExpandedOptions, rest = __rest(_a, ["name", "uniqueName", "value", "onChange", "onSingleOptionsChange", "onDependableOptionChange", "placeholder", "noValueString", "isValid", "url", "customUrl", "operatorsUrl", "onOptionsLoaded", "recordRequiresSearchOptions", "readOnly", "allowTemplates", "interfaceContext", "templateFieldProps", "forceDropdown", "showTypeToggle", "compact", "compactFlush", "compactNested", "compactPanelProps", "compactCollapsedGroups", "compactToolbar", "commitMode", "expandMode", "onCommit", "operators", "groups", "optionsLoader", "onValidityChange", "optionActions", "optionActionsCollapse", "componentOverrides", "codePreviewRenderer", "markdownRenderer", "rendererOnlyUiTypes", "inheritedFromParent", "autoFocusFirstRequired", "initialExpandedOptions"]);
407
+ rendererOnlyUiTypes = _a.rendererOnlyUiTypes, inheritedFromParent = _a.inheritedFromParent, autoFocusFirstRequired = _a.autoFocusFirstRequired, expandFirstRequired = _a.expandFirstRequired, initialExpandedOptions = _a.initialExpandedOptions, rest = __rest(_a, ["name", "uniqueName", "value", "onChange", "onSingleOptionsChange", "onDependableOptionChange", "placeholder", "noValueString", "isValid", "url", "customUrl", "operatorsUrl", "onOptionsLoaded", "recordRequiresSearchOptions", "readOnly", "allowTemplates", "interfaceContext", "templateFieldProps", "forceDropdown", "showTypeToggle", "compact", "compactFlush", "compactNested", "compactPanelProps", "commitMode", "expandMode", "onCommit", "operators", "groups", "optionsLoader", "onValidityChange", "optionActions", "optionActionsCollapse", "componentOverrides", "codePreviewRenderer", "markdownRenderer", "rendererOnlyUiTypes", "inheritedFromParent", "autoFocusFirstRequired", "expandFirstRequired", "initialExpandedOptions"]);
373
408
  // Built-ins + whatever the consumer declared for its own injected editors.
374
409
  var isRendererOnly = (0, react_2.useMemo)(function () { return (0, rendererTypes_1.createRendererOnlyUiTypeCheck)(rendererOnlyUiTypes); }, [JSON.stringify(rendererOnlyUiTypes)]);
375
410
  // Pointer CAPABILITY and viewport WIDTH are different questions and both
@@ -387,43 +422,83 @@ var FormEngineImpl = function (_a) {
387
422
  var collapseOptionActions = optionActionsCollapse === 'always' ? true
388
423
  : optionActionsCollapse === 'never' ? false
389
424
  : !isHoverCapable || !!isMobile;
390
- var _t = (0, react_2.useState)((rest === null || rest === void 0 ? void 0 : rest.options) || undefined), options = _t[0], setOptions = _t[1];
425
+ var _r = (0, react_2.useState)((rest === null || rest === void 0 ? void 0 : rest.options) || undefined), options = _r[0], setOptions = _r[1];
391
426
  // optionsLoader lifecycle: loading feeds the skeleton gate, error the banner.
392
- var _u = (0, react_2.useState)(!!optionsLoader && !(rest === null || rest === void 0 ? void 0 : rest.options)), optionsLoading = _u[0], setOptionsLoading = _u[1];
393
- var _v = (0, react_2.useState)(), optionsError = _v[0], setOptionsError = _v[1];
427
+ var _s = (0, react_2.useState)(!!optionsLoader && !(rest === null || rest === void 0 ? void 0 : rest.options)), optionsLoading = _s[0], setOptionsLoading = _s[1];
428
+ var _t = (0, react_2.useState)(), optionsError = _t[0], setOptionsError = _t[1];
394
429
  // Operators: prop-provided (compact) or fetched via operatorsUrl (dpql,
395
430
  // ported from IDE Options) — the fetch overrides the seeded prop value.
396
- var _w = (0, react_2.useState)(operatorsProp), operators = _w[0], setOperators = _w[1];
431
+ var _u = (0, react_2.useState)(operatorsProp), operators = _u[0], setOperators = _u[1];
397
432
  // Remote-fetch loading (ported from IDE Options); only relevant when one of
398
433
  // the fetch urls is set — schema-as-props consumers never see the skeleton.
399
- var _x = (0, react_2.useState)(!!(url || customUrl || operatorsUrl)), loading = _x[0], setLoading = _x[1];
434
+ var _v = (0, react_2.useState)(!!(url || customUrl || operatorsUrl)), loading = _v[0], setLoading = _v[1];
400
435
  var confirmAction = (0, reqore_1.useReqoreProperty)('confirmAction');
401
436
  var theme = (0, reqore_1.useReqoreTheme)();
402
- var _y = (0, react_2.useState)(), focusedEditing = _y[0], setFocusedEditing = _y[1];
403
- var _z = (0, react_2.useState)(false), showFieldTypes = _z[0], setShowFieldTypes = _z[1];
437
+ var _w = (0, react_2.useState)(), focusedEditing = _w[0], setFocusedEditing = _w[1];
438
+ var _x = (0, react_2.useState)(false), showFieldTypes = _x[0], setShowFieldTypes = _x[1];
404
439
  // Global toggle (toolbar ⓘ): reveal the short-description info panel on every
405
440
  // field that has a short_desc. Per-row ⓘ overrides still win over it.
406
441
  // Global field-info visibility, tri-state: `undefined` = default (critical
407
442
  // messages auto-open, the rest closed); `true` = show all; `false` = hide all
408
443
  // (even message fields). The toolbar ⓘ drives it.
409
- var _0 = (0, react_2.useState)(undefined), showAllDescriptions = _0[0], setShowAllDescriptions = _0[1];
410
- var _1 = (0, react_2.useState)(), showHelpForOption = _1[0], setShowHelpForOption = _1[1];
411
- var _2 = (0, react_2.useState)(false), showInvalidOptionsOnly = _2[0], setShowInvalidOptionsOnly = _2[1];
444
+ var _y = (0, react_2.useState)(undefined), showAllDescriptions = _y[0], setShowAllDescriptions = _y[1];
445
+ var _z = (0, react_2.useState)(), showHelpForOption = _z[0], setShowHelpForOption = _z[1];
446
+ var _0 = (0, react_2.useState)(false), showInvalidOptionsOnly = _0[0], setShowInvalidOptionsOnly = _0[1];
412
447
  // Which options are expanded into their editor (several can be open at once).
413
- var _3 = (0, react_2.useState)([]), expandedOptions = _3[0], setExpandedOptions = _3[1];
448
+ var _1 = (0, react_2.useState)([]), expandedOptions = _1[0], setExpandedOptions = _1[1];
449
+ // --- Reveal a status box's content when it is opened ----------------------
450
+ //
451
+ // The status boxes stack, so the last one ("Optional", which holds every
452
+ // not-yet-added field) sits at the bottom of the form — frequently at the
453
+ // bottom of the scroll container too. Opening it mounts its rows BELOW the
454
+ // fold: the box's own header is all that stays on screen, the click appears to
455
+ // have done nothing, and the fields it just revealed have to be hunted for by
456
+ // scrolling.
457
+ //
458
+ // The box that was just opened, read by the layout effect below. Held as state
459
+ // rather than acted on inside the collapse handler because the handler runs
460
+ // BEFORE React re-renders — at that moment the rows do not exist yet, so the
461
+ // box has not grown and there is nothing to scroll to. A layout effect runs
462
+ // after the DOM is updated and before paint, which makes the reveal
463
+ // deterministic instead of a guessed delay.
464
+ var _2 = (0, react_2.useState)(undefined), openedStatusBox = _2[0], setOpenedStatusBox = _2[1];
465
+ var statusBoxRefs = (0, react_2.useRef)({});
466
+ (0, react_2.useLayoutEffect)(function () {
467
+ var _a, _b;
468
+ if (!openedStatusBox) {
469
+ return;
470
+ }
471
+ var element = statusBoxRefs.current[openedStatusBox];
472
+ // Consume it either way: a box that has gone (a search narrowed it out of
473
+ // existence) must not leave a pending reveal armed for a later render.
474
+ setOpenedStatusBox(undefined);
475
+ // `scrollIntoView` is not implemented in jsdom, and a missing reveal must
476
+ // never break a form.
477
+ if (!(element === null || element === void 0 ? void 0 : element.scrollIntoView)) {
478
+ return;
479
+ }
480
+ // 'nearest' scrolls the MINIMUM needed: nothing at all when the box is
481
+ // already fully visible, and a top-alignment when it is taller than the
482
+ // viewport (header plus the first rows — the right answer for a long
483
+ // Optional list). Anything else moves the page when it did not need to.
484
+ element.scrollIntoView({
485
+ block: 'nearest',
486
+ behavior: ((_b = (_a = window.matchMedia) === null || _a === void 0 ? void 0 : _a.call(window, '(prefers-reduced-motion: reduce)')) === null || _b === void 0 ? void 0 : _b.matches) ? 'auto' : 'smooth',
487
+ });
488
+ }, [openedStatusBox]);
414
489
  // Remembers each row's last settled status box, so an actively-edited field
415
490
  // stays put when its status flips (e.g. becomes valid) instead of jumping to
416
491
  // another box mid-edit and stealing focus. Keyed by option name.
417
492
  var settledBucket = (0, react_2.useRef)({});
418
493
  // Measured form width (not viewport — the form lives in drawers/panels of
419
494
  // arbitrary width) drives the stacked narrow layout.
420
- var _4 = (0, react_use_1.useMeasure)(), compactWrapRef = _4[0], compactWrapWidth = _4[1].width;
495
+ var _3 = (0, react_use_1.useMeasure)(), compactWrapRef = _3[0], compactWrapWidth = _3[1].width;
421
496
  // Own handle on the scroll wrap (useMeasure's ref is a callback, no `.current`)
422
497
  // so the label-column measurement can publish its CSS var on the element. It's
423
498
  // STATE, not a ref: the wrap mounts only after the loading-skeleton gate
424
499
  // resolves, so the measurement effect must re-run when the node appears — a
425
500
  // ref wouldn't retrigger it.
426
- var _5 = (0, react_2.useState)(null), compactWrapNode = _5[0], setCompactWrapNode = _5[1];
501
+ var _4 = (0, react_2.useState)(null), compactWrapNode = _4[0], setCompactWrapNode = _4[1];
427
502
  // Ref mirror of the wrap node for callbacks that must not re-create when it
428
503
  // mounts (flashOptions reads it inside a rAF).
429
504
  var compactWrapNodeRef = (0, react_2.useRef)(null);
@@ -477,8 +552,8 @@ var FormEngineImpl = function (_a) {
477
552
  var readRowHeights = (0, react_2.useRef)({});
478
553
  // Required-groups linkage: hovering a group chip highlights every member row;
479
554
  // clicking a sibling in the chip's popover scrolls to it and flashes it.
480
- var _6 = (0, react_2.useState)([]), highlightedOptions = _6[0], setHighlightedOptions = _6[1];
481
- var _7 = (0, react_2.useState)([]), flashedOptions = _7[0], setFlashedOptions = _7[1];
555
+ var _5 = (0, react_2.useState)([]), highlightedOptions = _5[0], setHighlightedOptions = _5[1];
556
+ var _6 = (0, react_2.useState)([]), flashedOptions = _6[0], setFlashedOptions = _6[1];
482
557
  var flashTimeout = (0, react_2.useRef)();
483
558
  var flashOptions = (0, react_2.useCallback)(function (optionNames, scrollToFirst) {
484
559
  if (scrollToFirst === void 0) { scrollToFirst = false; }
@@ -527,16 +602,16 @@ var FormEngineImpl = function (_a) {
527
602
  });
528
603
  var compactNarrow = !!compactWrapWidth && compactWrapWidth < 480;
529
604
  // Info panels auto-open on Tier-1 content; the per-row user override sticks.
530
- var _8 = (0, react_2.useState)({}), infoPanelOverrides = _8[0], setInfoPanelOverrides = _8[1];
605
+ var _7 = (0, react_2.useState)({}), infoPanelOverrides = _7[0], setInfoPanelOverrides = _7[1];
531
606
  // Toolbar filters affect the listed rows only — the meter reflects the full set.
532
- var _9 = (0, react_2.useState)(false), requiredOnly = _9[0], setRequiredOnly = _9[1];
533
- var _10 = (0, react_2.useState)(''), compactQuery = _10[0], setCompactQuery = _10[1];
607
+ var _8 = (0, react_2.useState)(false), requiredOnly = _8[0], setRequiredOnly = _8[1];
608
+ var _9 = (0, react_2.useState)(''), compactQuery = _9[0], setCompactQuery = _9[1];
534
609
  // Compact field sort (Fields menu → "Sort by"); 'schema' = declared order.
535
- var _11 = (0, react_2.useState)('schema'), compactSort = _11[0], setCompactSort = _11[1];
536
- var _12 = (0, react_2.useState)(function () { return ({
610
+ var _10 = (0, react_2.useState)('schema'), compactSort = _10[0], setCompactSort = _10[1];
611
+ var _11 = (0, react_2.useState)(function () { return ({
537
612
  fields: (0, exports.fixOptions)(value, options || {}, undefined, isRendererOnly),
538
613
  meta: undefined,
539
- }); }), localValue = _12[0], setLocalValue = _12[1];
614
+ }); }), localValue = _11[0], setLocalValue = _11[1];
540
615
  var originalValue = (0, react_2.useRef)();
541
616
  // Track the last value we emitted via onChange so we can skip re-applying fixOptions
542
617
  // when the parent echoes it back as the new value prop (controlled component loop prevention)
@@ -545,7 +620,7 @@ var FormEngineImpl = function (_a) {
545
620
  originalValue.current = localValue.fields;
546
621
  }
547
622
  var unavailableOptionsCount = (0, react_2.useRef)(0);
548
- var _13 = (0, useQorusTypes_1.useQorusTypes)(), compactValue = _13.compactValue, typesLoading = _13.loading;
623
+ var _12 = (0, useQorusTypes_1.useQorusTypes)(), compactValue = _12.compactValue, typesLoading = _12.loading;
549
624
  var templates = (0, useTemplates_1.useTemplates)(allowTemplates, rest.stringTemplates, interfaceContext);
550
625
  (0, react_2.useEffect)(function () {
551
626
  if ((0, lodash_1.isEqual)(localValue.fields, value)) {
@@ -813,7 +888,7 @@ var FormEngineImpl = function (_a) {
813
888
  var handleOperatorChange = (0, react_2.useCallback)(function (optionName, currentValue, operator, index) {
814
889
  var _a;
815
890
  setLocalValue === null || setLocalValue === void 0 ? void 0 : setLocalValue({
816
- fields: __assign(__assign({}, currentValue), (_a = {}, _a[optionName] = __assign(__assign({}, currentValue[optionName]), { op: (0, exports.fixOperatorValue)(currentValue[optionName].op).map(function (op, idx) {
891
+ fields: __assign(__assign({}, currentValue), (_a = {}, _a[optionName] = __assign(__assign({}, currentValue[optionName]), { op: (0, common_1.fixOperatorValue)(currentValue[optionName].op).map(function (op, idx) {
817
892
  if (idx === index) {
818
893
  return operator;
819
894
  }
@@ -825,14 +900,14 @@ var FormEngineImpl = function (_a) {
825
900
  var handleAddOperator = (0, react_2.useCallback)(function (optionName, currentValue, index) {
826
901
  var _a;
827
902
  setLocalValue === null || setLocalValue === void 0 ? void 0 : setLocalValue({
828
- fields: __assign(__assign({}, currentValue), (_a = {}, _a[optionName] = __assign(__assign({}, currentValue[optionName]), { op: (0, common_1.insertAtIndex)((0, exports.fixOperatorValue)(currentValue[optionName].op), index, null) }), _a)),
903
+ fields: __assign(__assign({}, currentValue), (_a = {}, _a[optionName] = __assign(__assign({}, currentValue[optionName]), { op: (0, common_1.insertAtIndex)((0, common_1.fixOperatorValue)(currentValue[optionName].op), index, null) }), _a)),
829
904
  meta: undefined,
830
905
  });
831
906
  }, []);
832
907
  var handleRemoveOperator = (0, react_2.useCallback)(function (optionName, currentValue, index) {
833
908
  var _a;
834
909
  setLocalValue === null || setLocalValue === void 0 ? void 0 : setLocalValue({
835
- fields: __assign(__assign({}, currentValue), (_a = {}, _a[optionName] = __assign(__assign({}, currentValue[optionName]), { op: (0, exports.fixOperatorValue)(currentValue[optionName].op).filter(function (_op, idx) { return idx !== index; }) }), _a)),
910
+ fields: __assign(__assign({}, currentValue), (_a = {}, _a[optionName] = __assign(__assign({}, currentValue[optionName]), { op: (0, common_1.fixOperatorValue)(currentValue[optionName].op).filter(function (_op, idx) { return idx !== index; }) }), _a)),
836
911
  meta: undefined,
837
912
  });
838
913
  }, []);
@@ -1235,7 +1310,11 @@ var FormEngineImpl = function (_a) {
1235
1310
  // (or below-the-fold) form is never scrolled into view on mount.
1236
1311
  var autoFocusNameRef = (0, react_2.useRef)(undefined);
1237
1312
  (0, react_2.useEffect)(function () {
1238
- if (!autoFocusFirstRequired || !compact || !options) {
1313
+ // Two decisions, one scan. `autoFocusFirstRequired` opens the row AND puts
1314
+ // the caret in it; `expandFirstRequired` only opens it. Setting both keeps
1315
+ // the focusing behaviour, since focusing implies opening.
1316
+ var wantsFocus = !!autoFocusFirstRequired;
1317
+ if ((!wantsFocus && !expandFirstRequired) || !compact || !options) {
1239
1318
  return;
1240
1319
  }
1241
1320
  if (hasAutoFocusedRef.current) {
@@ -1251,8 +1330,14 @@ var FormEngineImpl = function (_a) {
1251
1330
  // clean mount focus rests on the body, so the intended "drop into the first
1252
1331
  // field" still fires. Bailing here leaves `hasAutoFocusedRef` false, so it
1253
1332
  // retries once focus is free.
1333
+ //
1334
+ // Only the FOCUSING variant waits: opening a row moves no caret, so there is
1335
+ // nothing to steal and nothing to wait for. Making the expand-only variant
1336
+ // wait here would make it a no-op in its main use — a sub-form mounted by a
1337
+ // click, where the button that mounted it still holds focus and never gives
1338
+ // it up.
1254
1339
  var active = document.activeElement;
1255
- if (active && active !== document.body) {
1340
+ if (wantsFocus && active && active !== document.body) {
1256
1341
  return;
1257
1342
  }
1258
1343
  var target = (0, readFirst_1.getFirstAttentionOptionName)(orderedNames, function (fieldName) {
@@ -1276,7 +1361,10 @@ var FormEngineImpl = function (_a) {
1276
1361
  hasAutoFocusedRef.current = true;
1277
1362
  if (target) {
1278
1363
  // Set the ref before the state update so CompactRow's focus timer sees it.
1279
- autoFocusNameRef.current = target;
1364
+ // Expand-only leaves it unset, which is what keeps the caret where it is.
1365
+ if (wantsFocus) {
1366
+ autoFocusNameRef.current = target;
1367
+ }
1280
1368
  setExpandedOptions(function (prev) {
1281
1369
  return prev.includes(target) ? prev
1282
1370
  : expandMode === 'multi' ? __spreadArray(__spreadArray([], prev, true), [target], false) : [target];
@@ -1284,6 +1372,7 @@ var FormEngineImpl = function (_a) {
1284
1372
  }
1285
1373
  }, [
1286
1374
  autoFocusFirstRequired,
1375
+ expandFirstRequired,
1287
1376
  compact,
1288
1377
  options,
1289
1378
  availableOptions,
@@ -1360,7 +1449,7 @@ var FormEngineImpl = function (_a) {
1360
1449
  suppressSchemaMessages) {
1361
1450
  var _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
1362
1451
  var type = _a.type, other = __rest(_a, ["type"]);
1363
- var operatorParts = (0, exports.fixOperatorValue)(other.op);
1452
+ var operatorParts = (0, common_1.fixOperatorValue)(other.op);
1364
1453
  // The RENDERER type for this row — which editor mounts. Distinct from the
1365
1454
  // storage type on the value envelope: a `richtext` field stores a string
1366
1455
  // but must render the richtext editor, so `ui_type` wins here.
@@ -1608,14 +1697,6 @@ var FormEngineImpl = function (_a) {
1608
1697
  cInfo,
1609
1698
  cBg,
1610
1699
  ]);
1611
- // `compactToolbar` resolved to a full object, so neither the context type nor
1612
- // the toolbar itself has to re-default anything. `null` means no toolbar.
1613
- var compactToolbarParts = (0, react_2.useMemo)(function () {
1614
- if (compactToolbar === false)
1615
- return null;
1616
- var all = { completion: true, search: true, fields: true, help: true };
1617
- return compactToolbar === true ? all : __assign(__assign({}, all), compactToolbar);
1618
- }, [JSON.stringify(compactToolbar)]);
1619
1700
  var compactToolbarContextValue = (0, react_2.useMemo)(function () { return ({
1620
1701
  readOnly: readOnly,
1621
1702
  invalidCount: (0, size_1.default)(validityData.invalidFields),
@@ -1623,7 +1704,6 @@ var FormEngineImpl = function (_a) {
1623
1704
  completion: readFirstCompletion,
1624
1705
  showInvalidOnly: showInvalidOptionsOnly,
1625
1706
  onToggleInvalidOnly: handleToggleInvalidOnly,
1626
- parts: compactToolbarParts !== null && compactToolbarParts !== void 0 ? compactToolbarParts : { completion: false, search: false, fields: false, help: false },
1627
1707
  hasMultipleOptions: (0, size_1.default)(availableOptions) > 1,
1628
1708
  compactQuery: compactQuery,
1629
1709
  setCompactQuery: setCompactQuery,
@@ -1671,9 +1751,8 @@ var FormEngineImpl = function (_a) {
1671
1751
  ]);
1672
1752
  // The engine's own toolbar action, plus whatever the consumer added through
1673
1753
  // `compactPanelProps.actions` — appended, so an outside action can never
1674
- // knock the form's toolbar out of the header. Only `compactToolbar={false}`
1675
- // removes it, and then the header carries just the consumer's own actions.
1676
- var compactHeaderActions = (0, react_2.useMemo)(function () { return __spreadArray(__spreadArray([], (compactToolbarParts ? [{ as: CompactToolbar_1.CompactToolbar, responsive: false }] : []), true), ((compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.actions) || []), true); }, [compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.actions, compactToolbarParts]);
1754
+ // knock the form's toolbar out of the header.
1755
+ var compactHeaderActions = (0, react_2.useMemo)(function () { return __spreadArray([{ as: CompactToolbar_1.CompactToolbar, responsive: false }], ((compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.actions) || []), true); }, [compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.actions]);
1677
1756
  var renderCompact = function () {
1678
1757
  var headerBg = "".concat((0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.02)).concat((0, colors_1.percentToHexAlpha)(88));
1679
1758
  // Toolbar filters narrow the listed rows; the meter reflects the full set.
@@ -1684,8 +1763,40 @@ var FormEngineImpl = function (_a) {
1684
1763
  if (requiredOnly && !((schema === null || schema === void 0 ? void 0 : schema.required) || (schema === null || schema === void 0 ? void 0 : schema.required_groups))) {
1685
1764
  return false;
1686
1765
  }
1687
- return matchesQuery(optionName);
1766
+ // A field that absorbs a sibling also answers for it: searching
1767
+ // "language" has to surface the row that now holds the language control,
1768
+ // or the field becomes unreachable through the filter.
1769
+ if (matchesQuery(optionName))
1770
+ return true;
1771
+ var absorb = schema === null || schema === void 0 ? void 0 : schema.absorb_fields;
1772
+ return !!(absorb === null || absorb === void 0 ? void 0 : absorb.some(function (absorbedName) { return matchesQuery(absorbedName); }));
1688
1773
  };
1774
+ // Fields a sibling absorbs into its own container.
1775
+ //
1776
+ // A field declaring `absorb_fields: ['language']` renders that sibling's
1777
+ // control inside its own row instead of letting it have a row of its own.
1778
+ // The pair this exists for is a code editor and its language: they are one
1779
+ // decision — "what is this code, and in what language" — and reading them
1780
+ // as two unrelated rows one above the other is what the layout used to say.
1781
+ //
1782
+ // Absorbed fields stay in `grouped`, and therefore in the Set / Optional /
1783
+ // Needs-attention counts and in the completion meter. Only the ROW is
1784
+ // skipped. Dropping them from the buckets instead would leave the meter
1785
+ // ("13/18 set", computed from `availableOptions`) disagreeing with the box
1786
+ // badge beside it, which counts row entries.
1787
+ var absorbedBy = {};
1788
+ (0, lodash_1.forEach)(options, function (option, optionName) {
1789
+ var absorb = option === null || option === void 0 ? void 0 : option.absorb_fields;
1790
+ if (!(absorb === null || absorb === void 0 ? void 0 : absorb.length))
1791
+ return;
1792
+ absorb.forEach(function (absorbedName) {
1793
+ // Only absorb a sibling that exists and is not already spoken for; a
1794
+ // schema naming a missing field must not make the field disappear.
1795
+ if ((options === null || options === void 0 ? void 0 : options[absorbedName]) && !absorbedBy[absorbedName]) {
1796
+ absorbedBy[absorbedName] = optionName;
1797
+ }
1798
+ });
1799
+ });
1689
1800
  // Group the options by their raw `group` key, remembering the order groups
1690
1801
  // first appear in the schema. Each row carries a `hidden` flag.
1691
1802
  var groupOrder = [];
@@ -1817,18 +1928,30 @@ var FormEngineImpl = function (_a) {
1817
1928
  // together at the first member's slot and rendered as a connected rail (flat
1818
1929
  // rows — no wrapper — so the value surface applies normally; the rail + nodes
1819
1930
  // are drawn per member). Narrow stacks fall back to flat rows.
1931
+ // The absorbed siblings a host row must render, in schema order. Empty for
1932
+ // every row that absorbs nothing, which is all of them by default.
1933
+ var absorbedNamesFor = function (hostName) {
1934
+ return Object.keys(absorbedBy).filter(function (absorbedName) { return absorbedBy[absorbedName] === hostName; });
1935
+ };
1820
1936
  var renderGroupRows = function (names) {
1821
1937
  var renderRow = function (entry, clustered, clusterFirst, clusterLast) { return ((0, jsx_runtime_1.jsx)(CompactRow_1.CompactRow, { optionName: entry.name, optionField: entry.hidden ?
1822
1938
  {
1823
1939
  type: getOptionSchemaStorageType(options === null || options === void 0 ? void 0 : options[entry.name], isRendererOnly),
1824
1940
  value: undefined,
1825
1941
  }
1826
- : shownOptions[entry.name], hidden: entry.hidden, clustered: clustered, clusterFirst: clusterFirst, clusterLast: clusterLast }, entry.name)); };
1942
+ : shownOptions[entry.name], hidden: entry.hidden, clustered: clustered, clusterFirst: clusterFirst, clusterLast: clusterLast,
1943
+ // The siblings this row renders inside itself instead of leaving
1944
+ // them a row of their own — see `absorbedBy`.
1945
+ absorbedFields: absorbedNamesFor(entry.name) }, entry.name)); };
1827
1946
  // (Clustering runs in narrow mode too now — the "One of the below is
1828
1947
  // required" box wraps the members regardless of width; it no longer relies
1829
1948
  // on a contiguous rail.)
1830
1949
  var emitted = new Set();
1831
1950
  var groupOf = function (name) { var _a, _b; return (_b = (_a = options === null || options === void 0 ? void 0 : options[name]) === null || _a === void 0 ? void 0 : _a.required_groups) === null || _b === void 0 ? void 0 : _b[0]; };
1951
+ // An absorbed field keeps its place in the buckets — so the Set /
1952
+ // Optional counts and the completion meter still see it — but its host
1953
+ // renders its control, so it gets no row of its own here.
1954
+ names = names.filter(function (entry) { return !absorbedBy[entry.name]; });
1832
1955
  return names.map(function (entry) {
1833
1956
  var grp = groupOf(entry.name);
1834
1957
  if (!grp)
@@ -1878,28 +2001,32 @@ var FormEngineImpl = function (_a) {
1878
2001
  var boxBg = box.key === 'optional' ?
1879
2002
  (0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.06)
1880
2003
  : undefined;
1881
- return ((0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBox, { "$accent": accent, "$bg": boxBg, flat: true, minimal: true, collapseButtonProps: { flat: true, minimal: true, size: 'small' }, collapsible: true,
1882
- // Which boxes start closed is the consumer's call
1883
- // (`compactCollapsedGroups`, default `['optional']`: the
1884
- // Optional box holds every not-yet-added field, so a form
1885
- // opens on what is in use). Two rules override it:
1886
- //
1887
- // A SEARCH forces every box open — ReqorePanel unmounts
1888
- // collapsed content, so a match inside a closed box would
1889
- // be unreachable. (isCollapsed is the panel's controllable
1890
- // state; manual toggling still works with no query set.)
1891
- //
1892
- // The Optional box stays open when it is the ONLY box,
1893
- // because collapsing it renders a card that looks empty and
1894
- // broken: an auth profile's Authorization block, whose nine
1895
- // requirement fields are all optional, showed as a titled
1896
- // card containing one collapsed "Optional 9" strip and
1897
- // nothing else. This does not generalise to the other two
1898
- // a lone Set box collapsed is a deliberate ask, and its
1899
- // header still reports what is in there.
1900
- isCollapsed: compactCollapsedGroups.includes(box.key) &&
1901
- !query &&
1902
- !(box.key === 'optional' && onlyOptionalRows), label: (0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledGroupHeader, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreP, { effect: { weight: 'bold' }, size: 'normal', children: box.label }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', minimal: true, compact: true, intent: box.intent, label: String(count) })] }), icon: box.icon, className: 'options-readfirst-group', padded: false, contentStyle: { padding: '4px 4px 6px' }, children: (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledGroupBody, { "$divider": cDivider, "$hover": cHover, "$focus": cWarning, "$success": cSuccess, "$rowBg": cRowBg, "$lineColor": cGroupLine, className: compactNarrow ? 'readfirst-narrow' : undefined, children: groupsInBox.map(function (groupName) {
2004
+ return ((0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBox, { "$accent": accent, "$bg": boxBg, ref: function (node) {
2005
+ statusBoxRefs.current[box.key] = node;
2006
+ },
2007
+ // Opening arms the reveal; collapsing disarms it, so a
2008
+ // close never scrolls.
2009
+ onCollapseChange: function (collapsed) {
2010
+ return setOpenedStatusBox(collapsed ? undefined : box.key);
2011
+ }, flat: true, minimal: true, collapseButtonProps: { flat: true, minimal: true, size: 'small' }, collapsible: true,
2012
+ // The Optional box now holds every not-yet-added field, so
2013
+ // it starts COLLAPSED to keep the form focused on what's in
2014
+ // use. But a SEARCH must surface matching addable fields —
2015
+ // and ReqorePanel unmounts collapsed content so force it
2016
+ // open whenever a query is active. (isCollapsed is the
2017
+ // panel's controllable state; manual toggling still works
2018
+ // when no query is set.)
2019
+ // The Optional box starts collapsed so a form opens on what
2020
+ // is in use but only when there IS something else to
2021
+ // open on. When every field is optional it is the whole
2022
+ // form, and collapsing it renders a card that looks empty
2023
+ // and broken: an auth profile's Authorization block, whose
2024
+ // nine requirement fields are all optional, showed as a
2025
+ // titled card containing one collapsed "Optional 9" strip
2026
+ // and nothing else. A search still forces it open
2027
+ // (ReqorePanel unmounts collapsed content, so a match
2028
+ // inside it would be unreachable otherwise).
2029
+ isCollapsed: box.key === 'optional' && !query && !onlyOptionalRows, label: (0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledGroupHeader, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreP, { effect: { weight: 'bold' }, size: 'normal', children: box.label }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', minimal: true, compact: true, intent: box.intent, label: String(count) })] }), icon: box.icon, className: 'options-readfirst-group', padded: false, contentStyle: { padding: '4px 4px 6px' }, children: (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledGroupBody, { "$divider": cDivider, "$hover": cHover, "$focus": cWarning, "$success": cSuccess, "$rowBg": cRowBg, "$lineColor": cGroupLine, className: compactNarrow ? 'readfirst-narrow' : undefined, children: groupsInBox.map(function (groupName) {
1903
2030
  var groupConfig = groups === null || groups === void 0 ? void 0 : groups[groupName];
1904
2031
  return ((0, jsx_runtime_1.jsxs)(react_2.default.Fragment, { children: [showGroupSubLabel(groupName) ?
1905
2032
  (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBoxGroupLabel, { children: (0, readFirst_1.getOptionGroupLabel)(groupName, groups) })