@qoretechnologies/reqraft 0.10.4 → 0.10.6

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 (25) hide show
  1. package/.claude/CLAUDE.md +5 -0
  2. package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
  3. package/dist/components/form/engine/CompactRow.js +7 -9
  4. package/dist/components/form/engine/CompactRow.js.map +1 -1
  5. package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
  6. package/dist/components/form/engine/CompactToolbar.js +8 -27
  7. package/dist/components/form/engine/CompactToolbar.js.map +1 -1
  8. package/dist/components/form/engine/FormEngine.d.ts +10 -2
  9. package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
  10. package/dist/components/form/engine/FormEngine.js +127 -44
  11. package/dist/components/form/engine/FormEngine.js.map +1 -1
  12. package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
  13. package/dist/components/form/engine/compactRowStyles.js +8 -3
  14. package/dist/components/form/engine/compactRowStyles.js.map +1 -1
  15. package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
  16. package/dist/components/form/fields/auto/AutoFormField.js +4 -1
  17. package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
  18. package/package.json +4 -3
  19. package/src/components/form/engine/CompactRow.tsx +18 -25
  20. package/src/components/form/engine/CompactToolbar.tsx +4 -17
  21. package/src/components/form/engine/FormEngine.stories.tsx +219 -10
  22. package/src/components/form/engine/FormEngine.tsx +126 -16
  23. package/src/components/form/engine/compactRowStyles.ts +33 -29
  24. package/src/components/form/fields/auto/AutoFormField.stories.tsx +9 -2
  25. package/src/components/form/fields/auto/AutoFormField.tsx +3 -0
@@ -129,6 +129,35 @@ var compactRowStyles_1 = require("./compactRowStyles");
129
129
  var OptionFieldMessages_1 = require("./OptionFieldMessages");
130
130
  var OptionsHelpDialog_1 = require("./OptionsHelpDialog");
131
131
  var readFirst_1 = require("./readFirst");
132
+ /**
133
+ * Resolve a field's `inherit_props` map against the current available
134
+ * options, producing a `{ propName: siblingValue }` hash suitable for
135
+ * spreading onto the field's renderer.
136
+ *
137
+ * For each entry `<prop-name-on-renderer> -> <sibling-field-name>`, the
138
+ * sibling's current value (`availableOptions[siblingName]?.value`) is
139
+ * forwarded under the receiving prop name. Missing siblings emit
140
+ * `undefined`, which the renderer's prop type can treat as "no hint".
141
+ *
142
+ * Designed to be JSON-pure: no closures, no transformations. Renderers
143
+ * decide how to use the forwarded value (e.g. the consumer-injected
144
+ * `code-editor` renderer maps a `language: "qore"` prop to its
145
+ * highlighter mode).
146
+ *
147
+ * Mirrored in qorus-ide `src/components/Field/systemOptions.tsx`; keep
148
+ * the two in sync (see qorus-ide's `.claude/CLAUDE.md`).
149
+ */
150
+ var resolveInheritProps = function (inheritProps, availableOptions) {
151
+ var _a;
152
+ if (!inheritProps || !availableOptions)
153
+ return {};
154
+ var out = {};
155
+ for (var propName in inheritProps) {
156
+ var siblingName = inheritProps[propName];
157
+ out[propName] = (_a = availableOptions[siblingName]) === null || _a === void 0 ? void 0 : _a.value;
158
+ }
159
+ return out;
160
+ };
132
161
  var NegativeColorEffect = {
133
162
  gradient: {
134
163
  colors: { 0: 'danger', 100: 'danger:darken:2' },
@@ -297,44 +326,44 @@ var FormEngine = function (_a) {
297
326
  var _b, _c, _d, _f, _g;
298
327
  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
299
328
  isValid = _a.isValid, // eslint-disable-line @typescript-eslint/no-unused-vars
300
- url = _a.url, customUrl = _a.customUrl, operatorsUrl = _a.operatorsUrl, onOptionsLoaded = _a.onOptionsLoaded, recordRequiresSearchOptions = _a.recordRequiresSearchOptions, readOnly = _a.readOnly, _h = _a.allowTemplates, allowTemplates = _h === void 0 ? true : _h, interfaceContext = _a.interfaceContext, templateFieldProps = _a.templateFieldProps, _j = _a.showTypeToggle, showTypeToggle = _j === void 0 ? true : _j, compact = _a.compact, _k = _a.compactFlush, compactFlush = _k === void 0 ? false : _k, _l = _a.commitMode, commitMode = _l === void 0 ? 'immediate' : _l, _m = _a.expandMode, expandMode = _m === void 0 ? 'single' : _m, onCommit = _a.onCommit, operatorsProp = _a.operators, groups = _a.groups, optionsLoader = _a.optionsLoader, onValidityChange = _a.onValidityChange, optionActions = _a.optionActions, componentOverrides = _a.componentOverrides, rest = __rest(_a, ["name", "uniqueName", "value", "onChange", "onSingleOptionsChange", "onDependableOptionChange", "placeholder", "noValueString", "isValid", "url", "customUrl", "operatorsUrl", "onOptionsLoaded", "recordRequiresSearchOptions", "readOnly", "allowTemplates", "interfaceContext", "templateFieldProps", "showTypeToggle", "compact", "compactFlush", "commitMode", "expandMode", "onCommit", "operators", "groups", "optionsLoader", "onValidityChange", "optionActions", "componentOverrides"]);
301
- var _o = (0, react_2.useState)((rest === null || rest === void 0 ? void 0 : rest.options) || undefined), options = _o[0], setOptions = _o[1];
329
+ url = _a.url, customUrl = _a.customUrl, operatorsUrl = _a.operatorsUrl, onOptionsLoaded = _a.onOptionsLoaded, recordRequiresSearchOptions = _a.recordRequiresSearchOptions, readOnly = _a.readOnly, _h = _a.allowTemplates, allowTemplates = _h === void 0 ? true : _h, interfaceContext = _a.interfaceContext, templateFieldProps = _a.templateFieldProps, _j = _a.showTypeToggle, showTypeToggle = _j === void 0 ? true : _j, compact = _a.compact, _k = _a.compactFlush, compactFlush = _k === void 0 ? false : _k, _l = _a.compactNested, compactNested = _l === void 0 ? false : _l, _m = _a.commitMode, commitMode = _m === void 0 ? 'immediate' : _m, _o = _a.expandMode, expandMode = _o === void 0 ? 'single' : _o, onCommit = _a.onCommit, operatorsProp = _a.operators, groups = _a.groups, optionsLoader = _a.optionsLoader, onValidityChange = _a.onValidityChange, optionActions = _a.optionActions, componentOverrides = _a.componentOverrides, rest = __rest(_a, ["name", "uniqueName", "value", "onChange", "onSingleOptionsChange", "onDependableOptionChange", "placeholder", "noValueString", "isValid", "url", "customUrl", "operatorsUrl", "onOptionsLoaded", "recordRequiresSearchOptions", "readOnly", "allowTemplates", "interfaceContext", "templateFieldProps", "showTypeToggle", "compact", "compactFlush", "compactNested", "commitMode", "expandMode", "onCommit", "operators", "groups", "optionsLoader", "onValidityChange", "optionActions", "componentOverrides"]);
330
+ var _p = (0, react_2.useState)((rest === null || rest === void 0 ? void 0 : rest.options) || undefined), options = _p[0], setOptions = _p[1];
302
331
  // optionsLoader lifecycle: loading feeds the skeleton gate, error the banner.
303
- var _p = (0, react_2.useState)(!!optionsLoader && !(rest === null || rest === void 0 ? void 0 : rest.options)), optionsLoading = _p[0], setOptionsLoading = _p[1];
304
- var _q = (0, react_2.useState)(), optionsError = _q[0], setOptionsError = _q[1];
332
+ var _q = (0, react_2.useState)(!!optionsLoader && !(rest === null || rest === void 0 ? void 0 : rest.options)), optionsLoading = _q[0], setOptionsLoading = _q[1];
333
+ var _r = (0, react_2.useState)(), optionsError = _r[0], setOptionsError = _r[1];
305
334
  // Operators: prop-provided (compact) or fetched via operatorsUrl (dpql,
306
335
  // ported from IDE Options) — the fetch overrides the seeded prop value.
307
- var _r = (0, react_2.useState)(operatorsProp), operators = _r[0], setOperators = _r[1];
336
+ var _s = (0, react_2.useState)(operatorsProp), operators = _s[0], setOperators = _s[1];
308
337
  // Remote-fetch loading (ported from IDE Options); only relevant when one of
309
338
  // the fetch urls is set — schema-as-props consumers never see the skeleton.
310
- var _s = (0, react_2.useState)(!!(url || customUrl || operatorsUrl)), loading = _s[0], setLoading = _s[1];
339
+ var _t = (0, react_2.useState)(!!(url || customUrl || operatorsUrl)), loading = _t[0], setLoading = _t[1];
311
340
  var confirmAction = (0, reqore_1.useReqoreProperty)('confirmAction');
312
341
  var theme = (0, reqore_1.useReqoreTheme)();
313
- var _t = (0, react_2.useState)(), focusedEditing = _t[0], setFocusedEditing = _t[1];
314
- var _u = (0, react_2.useState)(false), showFieldTypes = _u[0], setShowFieldTypes = _u[1];
342
+ var _u = (0, react_2.useState)(), focusedEditing = _u[0], setFocusedEditing = _u[1];
343
+ var _v = (0, react_2.useState)(false), showFieldTypes = _v[0], setShowFieldTypes = _v[1];
315
344
  // Global toggle (toolbar ⓘ): reveal the short-description info panel on every
316
345
  // field that has a short_desc. Per-row ⓘ overrides still win over it.
317
346
  // Global field-info visibility, tri-state: `undefined` = default (critical
318
347
  // messages auto-open, the rest closed); `true` = show all; `false` = hide all
319
348
  // (even message fields). The toolbar ⓘ drives it.
320
- var _v = (0, react_2.useState)(undefined), showAllDescriptions = _v[0], setShowAllDescriptions = _v[1];
321
- var _w = (0, react_2.useState)(), showHelpForOption = _w[0], setShowHelpForOption = _w[1];
322
- var _x = (0, react_2.useState)(false), showInvalidOptionsOnly = _x[0], setShowInvalidOptionsOnly = _x[1];
349
+ var _w = (0, react_2.useState)(undefined), showAllDescriptions = _w[0], setShowAllDescriptions = _w[1];
350
+ var _x = (0, react_2.useState)(), showHelpForOption = _x[0], setShowHelpForOption = _x[1];
351
+ var _y = (0, react_2.useState)(false), showInvalidOptionsOnly = _y[0], setShowInvalidOptionsOnly = _y[1];
323
352
  // Which options are expanded into their editor (several can be open at once).
324
- var _y = (0, react_2.useState)([]), expandedOptions = _y[0], setExpandedOptions = _y[1];
353
+ var _z = (0, react_2.useState)([]), expandedOptions = _z[0], setExpandedOptions = _z[1];
325
354
  // Remembers each row's last settled status box, so an actively-edited field
326
355
  // stays put when its status flips (e.g. becomes valid) instead of jumping to
327
356
  // another box mid-edit and stealing focus. Keyed by option name.
328
357
  var settledBucket = (0, react_2.useRef)({});
329
358
  // Measured form width (not viewport — the form lives in drawers/panels of
330
359
  // arbitrary width) drives the stacked narrow layout.
331
- var _z = (0, react_use_1.useMeasure)(), compactWrapRef = _z[0], compactWrapWidth = _z[1].width;
360
+ var _0 = (0, react_use_1.useMeasure)(), compactWrapRef = _0[0], compactWrapWidth = _0[1].width;
332
361
  // Own handle on the scroll wrap (useMeasure's ref is a callback, no `.current`)
333
362
  // so the label-column measurement can publish its CSS var on the element. It's
334
363
  // STATE, not a ref: the wrap mounts only after the loading-skeleton gate
335
364
  // resolves, so the measurement effect must re-run when the node appears — a
336
365
  // ref wouldn't retrigger it.
337
- var _0 = (0, react_2.useState)(null), compactWrapNode = _0[0], setCompactWrapNode = _0[1];
366
+ var _1 = (0, react_2.useState)(null), compactWrapNode = _1[0], setCompactWrapNode = _1[1];
338
367
  var setCompactWrap = (0, react_2.useCallback)(function (node) {
339
368
  compactWrapRef(node);
340
369
  setCompactWrapNode(function (prev) { return (prev === node ? prev : node); });
@@ -371,15 +400,21 @@ var FormEngine = function (_a) {
371
400
  var readRowHeights = (0, react_2.useRef)({});
372
401
  // Required-groups linkage: hovering a group chip highlights every member row;
373
402
  // clicking a sibling in the chip's popover scrolls to it and flashes it.
374
- var _1 = (0, react_2.useState)([]), highlightedOptions = _1[0], setHighlightedOptions = _1[1];
375
- var _2 = (0, react_2.useState)([]), flashedOptions = _2[0], setFlashedOptions = _2[1];
403
+ var _2 = (0, react_2.useState)([]), highlightedOptions = _2[0], setHighlightedOptions = _2[1];
404
+ var _3 = (0, react_2.useState)([]), flashedOptions = _3[0], setFlashedOptions = _3[1];
376
405
  var flashTimeout = (0, react_2.useRef)();
377
406
  var flashOptions = (0, react_2.useCallback)(function (optionNames, scrollToFirst) {
378
- var _a;
379
407
  if (scrollToFirst === void 0) { scrollToFirst = false; }
380
408
  if (scrollToFirst && optionNames[0]) {
381
- (_a = document
382
- .querySelector(".readfirst-row[data-field=\"".concat(optionNames[0], "\"]"))) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ block: 'center', behavior: 'smooth' });
409
+ // Defer to the next frame: when this fires for a field that just changed
410
+ // panels, its row has only just re-mounted in the new box scrolling in the
411
+ // same tick targets the stale (pre-move) layout, so the page doesn't budge.
412
+ // A rAF lets the new position settle first.
413
+ requestAnimationFrame(function () {
414
+ var _a;
415
+ (_a = document
416
+ .querySelector(".readfirst-row[data-field=\"".concat(optionNames[0], "\"]"))) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ block: 'center', behavior: 'smooth' });
417
+ });
383
418
  }
384
419
  setFlashedOptions(optionNames);
385
420
  clearTimeout(flashTimeout.current);
@@ -387,18 +422,37 @@ var FormEngine = function (_a) {
387
422
  }, []);
388
423
  var flashOption = (0, react_2.useCallback)(function (optionName) { return flashOptions([optionName], true); }, [flashOptions]);
389
424
  (0, react_2.useEffect)(function () { return function () { return clearTimeout(flashTimeout.current); }; }, []);
425
+ // Follow a field across panels: when its status bucket changes — e.g. you fill
426
+ // an optional field and it jumps to Set / Needs attention — scroll to its new
427
+ // row and flash it so it's easy to keep track of. `settledBucket` holds each
428
+ // field's current panel (frozen while the field is being edited, it re-buckets
429
+ // on collapse), so diffing it after every render catches the move the instant it
430
+ // lands in the new panel. Runs every render; the diff is cheap and only fires a
431
+ // scroll on an ACTUAL move of a non-expanded field.
432
+ var prevSettledBucket = (0, react_2.useRef)({});
433
+ (0, react_2.useEffect)(function () {
434
+ if (!compact)
435
+ return;
436
+ var cur = settledBucket.current;
437
+ var prev = prevSettledBucket.current;
438
+ var moved = Object.keys(cur).find(function (name) { return prev[name] && prev[name] !== cur[name] && !expandedOptions.includes(name); });
439
+ prevSettledBucket.current = __assign({}, cur);
440
+ if (moved) {
441
+ flashOptions([moved], true);
442
+ }
443
+ });
390
444
  var compactNarrow = !!compactWrapWidth && compactWrapWidth < 480;
391
445
  // Info panels auto-open on Tier-1 content; the per-row user override sticks.
392
- var _3 = (0, react_2.useState)({}), infoPanelOverrides = _3[0], setInfoPanelOverrides = _3[1];
446
+ var _4 = (0, react_2.useState)({}), infoPanelOverrides = _4[0], setInfoPanelOverrides = _4[1];
393
447
  // Toolbar filters affect the listed rows only — the meter reflects the full set.
394
- var _4 = (0, react_2.useState)(false), requiredOnly = _4[0], setRequiredOnly = _4[1];
395
- var _5 = (0, react_2.useState)(''), compactQuery = _5[0], setCompactQuery = _5[1];
448
+ var _5 = (0, react_2.useState)(false), requiredOnly = _5[0], setRequiredOnly = _5[1];
449
+ var _6 = (0, react_2.useState)(''), compactQuery = _6[0], setCompactQuery = _6[1];
396
450
  // Compact field sort (Fields menu → "Sort by"); 'schema' = declared order.
397
- var _6 = (0, react_2.useState)('schema'), compactSort = _6[0], setCompactSort = _6[1];
398
- var _7 = (0, react_2.useState)(function () { return ({
451
+ var _7 = (0, react_2.useState)('schema'), compactSort = _7[0], setCompactSort = _7[1];
452
+ var _8 = (0, react_2.useState)(function () { return ({
399
453
  fields: (0, exports.fixOptions)(value, options || {}),
400
454
  meta: undefined,
401
- }); }), localValue = _7[0], setLocalValue = _7[1];
455
+ }); }), localValue = _8[0], setLocalValue = _8[1];
402
456
  var originalValue = (0, react_2.useRef)();
403
457
  // Track the last value we emitted via onChange so we can skip re-applying fixOptions
404
458
  // when the parent echoes it back as the new value prop (controlled component loop prevention)
@@ -407,7 +461,7 @@ var FormEngine = function (_a) {
407
461
  originalValue.current = localValue.fields;
408
462
  }
409
463
  var unavailableOptionsCount = (0, react_2.useRef)(0);
410
- var _8 = (0, useQorusTypes_1.useQorusTypes)(), compactValue = _8.compactValue, typesLoading = _8.loading;
464
+ var _9 = (0, useQorusTypes_1.useQorusTypes)(), compactValue = _9.compactValue, typesLoading = _9.loading;
411
465
  var templates = (0, useTemplates_1.useTemplates)(allowTemplates, rest.stringTemplates, interfaceContext);
412
466
  (0, react_2.useEffect)(function () {
413
467
  if ((0, lodash_1.isEqual)(localValue.fields, value)) {
@@ -730,6 +784,10 @@ var FormEngine = function (_a) {
730
784
  meta: undefined,
731
785
  };
732
786
  });
787
+ // Collapse it too: a removed field drops back to the (collapsed) Optional box
788
+ // as a quiet addable row — if it was being edited, that editor must close
789
+ // rather than linger as an open editor for a field that's no longer added.
790
+ setExpandedOptions(function (prev) { return prev.filter(function (name) { return name !== optionName; }); });
733
791
  }, []);
734
792
  var handleAddOptionalFieldChange = (0, react_2.useCallback)(function (_name, optionName) {
735
793
  var _a, _b, _c;
@@ -1076,7 +1134,7 @@ var FormEngine = function (_a) {
1076
1134
  // The info panel below the row keeps showing schema messages while editing —
1077
1135
  // rendering them in the editor too would balloon a one-line edit.
1078
1136
  suppressSchemaMessages) {
1079
- var _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p;
1137
+ var _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
1080
1138
  var type = _a.type, other = __rest(_a, ["type"]);
1081
1139
  var operatorParts = (0, exports.fixOperatorValue)(other.op);
1082
1140
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(function () {
@@ -1111,22 +1169,22 @@ var FormEngine = function (_a) {
1111
1169
  (0, jsx_runtime_1.jsx)(reqore_1.ReqoreButton, { disabled: readOnly, icon: 'DeleteBinLine', effect: NegativeColorEffect, fixed: true, onClick: function () { return handleRemoveOperator(optionName, fixedValue, index); } })
1112
1170
  : null] }, index));
1113
1171
  }) }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreVerticalSpacer, { height: 5 })] })
1114
- : null, (0, react_1.createElement)(TemplateField_1.TemplateField, __assign({ fluid: true }, options === null || options === void 0 ? void 0 : options[optionName], {
1172
+ : null, (0, react_1.createElement)(TemplateField_1.TemplateField, __assign({ fluid: true }, options === null || options === void 0 ? void 0 : options[optionName], resolveInheritProps((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.inherit_props, availableOptions), {
1115
1173
  // Propagate compact so an arg_schema field renders a COMPACT sub-form
1116
1174
  // (consistent with the parent) rather than the classic FormEngine.
1117
1175
  compact: compact,
1118
1176
  // SEAM: forwarded through TemplateField's rest-spread to AutoFormField,
1119
1177
  // which renders consumer-injected editors by field type/ui_type.
1120
- componentOverrides: componentOverrides, allowTemplates: !!(allowTemplates && ((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.supports_templates)), allowFunctions: !!((_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.supports_expressions),
1178
+ componentOverrides: componentOverrides, allowTemplates: !!(allowTemplates && ((_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.supports_templates)), allowFunctions: !!((_d = options === null || options === void 0 ? void 0 : options[optionName]) === null || _d === void 0 ? void 0 : _d.supports_expressions),
1121
1179
  // reqraft: form-level expression fields get the Visual/Text shell
1122
1180
  // (DPQL text mode); opt out per-form via `templateFieldProps`.
1123
- allowTextExpressions: true, allowCustomValues: ((_d = options === null || options === void 0 ? void 0 : options[optionName]) === null || _d === void 0 ? void 0 : _d.supports_custom_values) !== false && type !== 'any', templates: templates.value }, (0, exports.getTypeAndCanBeNull)(type, (_f = options === null || options === void 0 ? void 0 : options[optionName]) === null || _f === void 0 ? void 0 : _f.allowed_values, other.op), { ui_type: type, name: optionName, uniqueName: "".concat(uniqueName ? "".concat(uniqueName, ".") : "".concat(name ? "".concat(name, ".") : '')).concat(optionName), onChange:
1181
+ allowTextExpressions: true, allowCustomValues: ((_f = options === null || options === void 0 ? void 0 : options[optionName]) === null || _f === void 0 ? void 0 : _f.supports_custom_values) !== false && type !== 'any', templates: templates.value }, (0, exports.getTypeAndCanBeNull)(type, (_g = options === null || options === void 0 ? void 0 : options[optionName]) === null || _g === void 0 ? void 0 : _g.allowed_values, other.op), { ui_type: type, name: optionName, uniqueName: "".concat(uniqueName ? "".concat(uniqueName, ".") : "".concat(name ? "".concat(name, ".") : '')).concat(optionName), onChange:
1124
1182
  // Identity-stable on purpose: the typed fields debounce on
1125
1183
  // `[localValue, onChange]` — an inline lambda resets the pending emit
1126
1184
  // every render and the typed value can starve.
1127
- handleValueChange, key: optionName, arg_schema: (_g = options === null || options === void 0 ? void 0 : options[optionName]) === null || _g === void 0 ? void 0 : _g.arg_schema, noSoft: !!(rest === null || rest === void 0 ? void 0 : rest.options), value: other.value, isFunction: other.is_expression, isDefaultFunction: ((_h = options === null || options === void 0 ? void 0 : options[optionName]) === null || _h === void 0 ? void 0 : _h.default_view) === 'expression', sensitive: (_j = options === null || options === void 0 ? void 0 : options[optionName]) === null || _j === void 0 ? void 0 : _j.sensitive, default_value: (0, common_1.getDefaultValue)(options === null || options === void 0 ? void 0 : options[optionName]), isDefaultTemplate: ((_k = options === null || options === void 0 ? void 0 : options[optionName]) === null || _k === void 0 ? void 0 : _k.default_view) === 'template', allowed_values: (_l = options === null || options === void 0 ? void 0 : options[optionName]) === null || _l === void 0 ? void 0 : _l.allowed_values, disabled: ((_m = options === null || options === void 0 ? void 0 : options[optionName]) === null || _m === void 0 ? void 0 : _m.disabled) ||
1185
+ handleValueChange, key: optionName, arg_schema: (_h = options === null || options === void 0 ? void 0 : options[optionName]) === null || _h === void 0 ? void 0 : _h.arg_schema, noSoft: !!(rest === null || rest === void 0 ? void 0 : rest.options), value: other.value, isFunction: other.is_expression, isDefaultFunction: ((_j = options === null || options === void 0 ? void 0 : options[optionName]) === null || _j === void 0 ? void 0 : _j.default_view) === 'expression', sensitive: (_k = options === null || options === void 0 ? void 0 : options[optionName]) === null || _k === void 0 ? void 0 : _k.sensitive, default_value: (0, common_1.getDefaultValue)(options === null || options === void 0 ? void 0 : options[optionName]), isDefaultTemplate: ((_l = options === null || options === void 0 ? void 0 : options[optionName]) === null || _l === void 0 ? void 0 : _l.default_view) === 'template', allowed_values: (_m = options === null || options === void 0 ? void 0 : options[optionName]) === null || _m === void 0 ? void 0 : _m.allowed_values, disabled: ((_o = options === null || options === void 0 ? void 0 : options[optionName]) === null || _o === void 0 ? void 0 : _o.disabled) ||
1128
1186
  readOnly ||
1129
- !(0, validations_1.hasAllDependenciesFullfilled)((_o = options === null || options === void 0 ? void 0 : options[optionName]) === null || _o === void 0 ? void 0 : _o.depends_on, availableOptions, options || {}), readOnly: readOnly, size: editorSize || rest.size, menuItems: ((_p = options === null || options === void 0 ? void 0 : options[optionName]) === null || _p === void 0 ? void 0 : _p.ui_type) === 'any' ?
1187
+ !(0, validations_1.hasAllDependenciesFullfilled)((_p = options === null || options === void 0 ? void 0 : options[optionName]) === null || _p === void 0 ? void 0 : _p.depends_on, availableOptions, options || {}), readOnly: readOnly, size: editorSize || rest.size, menuItems: ((_q = options === null || options === void 0 ? void 0 : options[optionName]) === null || _q === void 0 ? void 0 : _q.ui_type) === 'any' ?
1130
1188
  getCustomMenuTemplateItems(optionName)
1131
1189
  : undefined }, templateFieldProps)), (0, jsx_runtime_1.jsx)(OptionFieldMessages_1.OptionFieldMessages, { schema: options || {}, allOptions: availableOptions, name: optionName, option: __assign({ type: type }, other), getType: getTypeForOption }), operators && (0, size_1.default)(operators) && (0, size_1.default)(other.op) ?
1132
1190
  (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreVerticalSpacer, { height: 5 }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { size: 'small', children: (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreTagGroup, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', labelKey: 'WHERE', label: optionName }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', labelKey: 'IS', label: operatorParts.join(' ') }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', intent: 'info', label: other.value ?
@@ -1349,15 +1407,18 @@ var FormEngine = function (_a) {
1349
1407
  pushRow(optionName, false);
1350
1408
  }
1351
1409
  });
1352
- // When searching, also surface matching hidden optional fields (not yet
1353
- // added) so the search spans the whole schema, not just the visible rows.
1354
- if (query) {
1355
- (0, lodash_1.forEach)(filteredOptions, function (_schema, optionName) {
1356
- if (matchesQuery(optionName)) {
1357
- pushRow(optionName, true);
1358
- }
1359
- });
1360
- }
1410
+ // Surface EVERY not-yet-added optional field as an addable (hidden) row, so
1411
+ // the whole schema is browsable inline they all land in the Optional box
1412
+ // (hidden ⇒ 'optional' bucket) instead of being buried in the Fields menu.
1413
+ // Narrowed by the same filters as the listed rows (search query + required-
1414
+ // only). availableOptions (listed) and filteredOptions (these) are disjoint —
1415
+ // the former is built from fixedValue keys, the latter excludes them — so a
1416
+ // field is never both a listed and a hidden row.
1417
+ (0, lodash_1.forEach)(filteredOptions, function (_schema, optionName) {
1418
+ if (matchesFilters(optionName)) {
1419
+ pushRow(optionName, true);
1420
+ }
1421
+ });
1361
1422
  // User sort (Fields menu → "Sort by"), applied WITHIN each group so the
1362
1423
  // group sections and the required-group rails are preserved. Schema order is
1363
1424
  // the default and the stable tiebreaker (Array.sort is stable, and each
@@ -1492,11 +1553,25 @@ var FormEngine = function (_a) {
1492
1553
  return ((0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledRequiredClusterBox, { className: 'options-readfirst-required-cluster', "$border": "".concat(cWarning, "33"), "$tint": "".concat(cWarning, "0d"), children: [(0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledRequiredClusterHeader, { "$color": cWarning, children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreIcon, { icon: 'LinkM', size: '11px', style: { color: cWarning } }), "One of the below is required"] }), railed] }, grp));
1493
1554
  });
1494
1555
  };
1495
- return ((0, jsx_runtime_1.jsx)(exports.OptionsContext.Provider, { value: { schema: options, value: availableOptions }, children: (0, jsx_runtime_1.jsx)(compactRowContext_1.CompactRowContext.Provider, { value: compactRowContextValue, children: (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreErrorBoundary, { children: [showHelpForOption && ((0, jsx_runtime_1.jsx)(OptionsHelpDialog_1.OptionsHelpDialog, { onClose: function () { return setShowHelpForOption(undefined); }, option: options[showHelpForOption] })), (0, jsx_runtime_1.jsx)(compactToolbarContext_1.CompactToolbarContext.Provider, { value: compactToolbarContextValue, children: (0, jsx_runtime_1.jsxs)(StyledCompactWrap, { ref: setCompactWrap, className: 'options-readfirst-scroll', "$flush": compactFlush, children: [(0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledCompactPanel, { "$headerBg": headerBg, flat: true, stickyHeader: true, padded: false, actions: compactHeaderActions, contentStyle: {
1556
+ return ((0, jsx_runtime_1.jsx)(exports.OptionsContext.Provider, { value: { schema: options, value: availableOptions }, children: (0, jsx_runtime_1.jsx)(compactRowContext_1.CompactRowContext.Provider, { value: compactRowContextValue, children: (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreErrorBoundary, { children: [showHelpForOption && ((0, jsx_runtime_1.jsx)(OptionsHelpDialog_1.OptionsHelpDialog, { onClose: function () { return setShowHelpForOption(undefined); }, option: options[showHelpForOption] })), (0, jsx_runtime_1.jsx)(compactToolbarContext_1.CompactToolbarContext.Provider, { value: compactToolbarContextValue, children: (0, jsx_runtime_1.jsxs)(StyledCompactWrap, { ref: setCompactWrap, className: 'options-readfirst-scroll', "$flush": compactFlush || compactNested, children: [(0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledCompactPanel
1557
+ // The top-level form scrolls, so its toolbar STICKS and carries a
1558
+ // dark blurred backdrop so content ghosts cleanly beneath it. A
1559
+ // nested (arg_schema) sub-form owns no scroll context — drop the
1560
+ // sticky, the backdrop, and the stacking context so its header is
1561
+ // transparent inside the parent's card.
1562
+ , { "$headerBg": compactNested ? 'transparent' : headerBg, "$nested": compactNested, flat: true,
1563
+ // No panel background: the form sits transparently on whatever
1564
+ // hosts it (page, drawer, or — for an arg_schema field — the
1565
+ // parent's edit card) instead of stacking its own dark surface.
1566
+ // The status boxes keep their own tints; the sticky toolbar keeps
1567
+ // its blurred header via the $headerBg override.
1568
+ transparent: true, stickyHeader: !compactNested, padded: false, actions: compactHeaderActions, contentStyle: {
1496
1569
  display: 'flex',
1497
1570
  flexFlow: 'column',
1498
1571
  gap: '10px',
1499
- padding: '0 0 12px',
1572
+ // Nested sub-form: no surrounding panel padding (it's flush in
1573
+ // the parent card); top-level keeps a small bottom gutter.
1574
+ padding: compactNested ? '0' : '0 0 12px',
1500
1575
  }, children: [(0, size_1.default)(groupKeys) === 0 ?
1501
1576
  (0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { flat: true, opaque: false, size: 'small', children: "No fields match the current filters." })
1502
1577
  : null, STATUS_BOXES.map(function (box) {
@@ -1513,7 +1588,15 @@ var FormEngine = function (_a) {
1513
1588
  var boxBg = box.key === 'optional' ?
1514
1589
  (0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.06)
1515
1590
  : undefined;
1516
- 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, 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) {
1591
+ 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,
1592
+ // The Optional box now holds every not-yet-added field, so
1593
+ // it starts COLLAPSED to keep the form focused on what's in
1594
+ // use. But a SEARCH must surface matching addable fields —
1595
+ // and ReqorePanel unmounts collapsed content — so force it
1596
+ // open whenever a query is active. (isCollapsed is the
1597
+ // panel's controllable state; manual toggling still works
1598
+ // when no query is set.)
1599
+ isCollapsed: box.key === 'optional' && !query, 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) {
1517
1600
  var groupConfig = groups === null || groups === void 0 ? void 0 : groups[groupName];
1518
1601
  return ((0, jsx_runtime_1.jsxs)(react_2.default.Fragment, { children: [showGroupSubLabel(groupName) ?
1519
1602
  (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBoxGroupLabel, { children: (0, readFirst_1.getOptionGroupLabel)(groupName, groups) })