@qoretechnologies/reqraft 0.10.65 → 0.10.66-pr.145.g2d1b4c8

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 (101) hide show
  1. package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
  2. package/dist/components/form/engine/CompactRow.js +128 -24
  3. package/dist/components/form/engine/CompactRow.js.map +1 -1
  4. package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
  5. package/dist/components/form/engine/CompactToolbar.js +78 -15
  6. package/dist/components/form/engine/CompactToolbar.js.map +1 -1
  7. package/dist/components/form/engine/FormEngine.d.ts +48 -1
  8. package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
  9. package/dist/components/form/engine/FormEngine.js +243 -85
  10. package/dist/components/form/engine/FormEngine.js.map +1 -1
  11. package/dist/components/form/engine/OptionFieldMessages.d.ts +18 -2
  12. package/dist/components/form/engine/OptionFieldMessages.d.ts.map +1 -1
  13. package/dist/components/form/engine/OptionFieldMessages.js +22 -3
  14. package/dist/components/form/engine/OptionFieldMessages.js.map +1 -1
  15. package/dist/components/form/engine/_structuredData/SchemaDataView.d.ts.map +1 -1
  16. package/dist/components/form/engine/_structuredData/SchemaDataView.js +27 -1
  17. package/dist/components/form/engine/_structuredData/SchemaDataView.js.map +1 -1
  18. package/dist/components/form/engine/compactRowContext.d.ts +5 -0
  19. package/dist/components/form/engine/compactRowContext.d.ts.map +1 -1
  20. package/dist/components/form/engine/compactRowContext.js.map +1 -1
  21. package/dist/components/form/engine/compactRowStyles.d.ts +12 -0
  22. package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
  23. package/dist/components/form/engine/compactRowStyles.js +72 -39
  24. package/dist/components/form/engine/compactRowStyles.js.map +1 -1
  25. package/dist/components/form/engine/compactToolbarContext.d.ts +3 -0
  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/formAppearance.d.ts +48 -0
  29. package/dist/components/form/engine/formAppearance.d.ts.map +1 -0
  30. package/dist/components/form/engine/formAppearance.js +50 -0
  31. package/dist/components/form/engine/formAppearance.js.map +1 -0
  32. package/dist/components/form/engine/readFirst.d.ts +14 -2
  33. package/dist/components/form/engine/readFirst.d.ts.map +1 -1
  34. package/dist/components/form/engine/readFirst.js +6 -2
  35. package/dist/components/form/engine/readFirst.js.map +1 -1
  36. package/dist/components/form/engine/rowFocus.d.ts +9 -1
  37. package/dist/components/form/engine/rowFocus.d.ts.map +1 -1
  38. package/dist/components/form/engine/rowFocus.js +17 -5
  39. package/dist/components/form/engine/rowFocus.js.map +1 -1
  40. package/dist/components/form/fields/ChoiceGroupHeading.d.ts +21 -0
  41. package/dist/components/form/fields/ChoiceGroupHeading.d.ts.map +1 -0
  42. package/dist/components/form/fields/ChoiceGroupHeading.js +33 -0
  43. package/dist/components/form/fields/ChoiceGroupHeading.js.map +1 -0
  44. package/dist/components/form/fields/Field.d.ts.map +1 -1
  45. package/dist/components/form/fields/Field.js +5 -3
  46. package/dist/components/form/fields/Field.js.map +1 -1
  47. package/dist/components/form/fields/allowed-values/AllowedValues.d.ts.map +1 -1
  48. package/dist/components/form/fields/allowed-values/AllowedValues.js +4 -2
  49. package/dist/components/form/fields/allowed-values/AllowedValues.js.map +1 -1
  50. package/dist/components/form/fields/radio-group/RadioGroup.d.ts.map +1 -1
  51. package/dist/components/form/fields/radio-group/RadioGroup.js +13 -7
  52. package/dist/components/form/fields/radio-group/RadioGroup.js.map +1 -1
  53. package/dist/components/form/index.d.ts +1 -0
  54. package/dist/components/form/index.d.ts.map +1 -1
  55. package/dist/components/form/index.js +1 -0
  56. package/dist/components/form/index.js.map +1 -1
  57. package/dist/components/supportTicket/InterfaceReferenceTags.d.ts +3 -2
  58. package/dist/components/supportTicket/InterfaceReferenceTags.d.ts.map +1 -1
  59. package/dist/components/supportTicket/InterfaceReferenceTags.js.map +1 -1
  60. package/dist/components/supportTicket/ReferencePicker.d.ts +2 -1
  61. package/dist/components/supportTicket/ReferencePicker.d.ts.map +1 -1
  62. package/dist/components/supportTicket/ReferencePicker.js +19 -13
  63. package/dist/components/supportTicket/ReferencePicker.js.map +1 -1
  64. package/dist/components/supportTicket/TicketHeader.d.ts.map +1 -1
  65. package/dist/components/supportTicket/TicketHeader.js +4 -1
  66. package/dist/components/supportTicket/TicketHeader.js.map +1 -1
  67. package/dist/components/supportTicket/TicketReplyBox.d.ts.map +1 -1
  68. package/dist/components/supportTicket/TicketReplyBox.js +29 -10
  69. package/dist/components/supportTicket/TicketReplyBox.js.map +1 -1
  70. package/dist/components/ticketThread/TicketThread.d.ts.map +1 -1
  71. package/dist/components/ticketThread/TicketThread.js +8 -16
  72. package/dist/components/ticketThread/TicketThread.js.map +1 -1
  73. package/package.json +1 -1
  74. package/src/components/form/engine/CompactRow.tsx +141 -22
  75. package/src/components/form/engine/CompactToolbar.tsx +85 -16
  76. package/src/components/form/engine/FormEngine.stories.tsx +25 -13
  77. package/src/components/form/engine/FormEngine.tsx +358 -77
  78. package/src/components/form/engine/FormEngineAppearance.stories.tsx +540 -0
  79. package/src/components/form/engine/FormEngineStickyHeaders.stories.tsx +5 -1
  80. package/src/components/form/engine/OptionFieldMessages.tsx +73 -2
  81. package/src/components/form/engine/_structuredData/SchemaDataView.tsx +17 -4
  82. package/src/components/form/engine/compactRowContext.ts +5 -0
  83. package/src/components/form/engine/compactRowStyles.ts +218 -38
  84. package/src/components/form/engine/compactToolbarContext.ts +3 -0
  85. package/src/components/form/engine/formAppearance.ts +78 -0
  86. package/src/components/form/engine/readFirst.ts +16 -3
  87. package/src/components/form/engine/rowFocus.ts +17 -6
  88. package/src/components/form/fields/ChoiceGroupHeading.tsx +38 -0
  89. package/src/components/form/fields/Field.tsx +6 -5
  90. package/src/components/form/fields/allowed-values/AllowedValues.tsx +7 -4
  91. package/src/components/form/fields/radio-group/RadioGroup.tsx +13 -7
  92. package/src/components/form/index.tsx +1 -0
  93. package/src/components/supportTicket/InterfaceReferenceTags.tsx +3 -2
  94. package/src/components/supportTicket/ReferencePicker.stories.tsx +0 -4
  95. package/src/components/supportTicket/ReferencePicker.tsx +22 -12
  96. package/src/components/supportTicket/TicketConversation.stories.tsx +0 -1
  97. package/src/components/supportTicket/TicketHeader.tsx +2 -1
  98. package/src/components/supportTicket/TicketReplyBox.stories.tsx +24 -21
  99. package/src/components/supportTicket/TicketReplyBox.tsx +27 -5
  100. package/src/components/ticketThread/TicketThread.stories.tsx +31 -2
  101. package/src/components/ticketThread/TicketThread.tsx +13 -28
@@ -107,6 +107,7 @@ var typeChoices_1 = require("./typeChoices");
107
107
  var optionActions_1 = require("./optionActions");
108
108
  var rendererTypes_1 = require("./rendererTypes");
109
109
  var revealRow_1 = require("./revealRow");
110
+ var rowFocus_1 = require("./rowFocus");
110
111
  var emittedValues_1 = require("../fields/emittedValues");
111
112
  var lodash_1 = require("lodash");
112
113
  var map_1 = __importDefault(require("lodash/map"));
@@ -136,6 +137,7 @@ var OptionFieldMessages_1 = require("./OptionFieldMessages");
136
137
  var optionsContext_1 = require("./optionsContext");
137
138
  var markdownRendererContext_1 = require("../../Description/markdownRendererContext");
138
139
  var OptionsHelpDialog_1 = require("./OptionsHelpDialog");
140
+ var formAppearance_1 = require("./formAppearance");
139
141
  var optionUiTypes_1 = require("../../../helpers/optionUiTypes");
140
142
  var readFirst_1 = require("./readFirst");
141
143
  /**
@@ -521,25 +523,28 @@ var FormEngineImpl = function (_a) {
521
523
  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
522
524
  isValid = _a.isValid, // eslint-disable-line @typescript-eslint/no-unused-vars
523
525
  url = _a.url, customUrl = _a.customUrl, operatorsUrl = _a.operatorsUrl, onOptionsLoaded = _a.onOptionsLoaded, recordRequiresSearchOptions = _a.recordRequiresSearchOptions, readOnly = _a.readOnly, onReadOnlyActivate = _a.onReadOnlyActivate, _h = _a.allowTemplates, allowTemplates = _h === void 0 ? true : _h, interfaceContext = _a.interfaceContext, templateFieldProps = _a.templateFieldProps, forceDropdown = _a.forceDropdown, _j = _a.showTypeToggle, showTypeToggle = _j === void 0 ? true : _j, compact = _a.compact,
526
+ // Read through the context `FormEngine` provides (resolved there against an
527
+ // inherited appearance); destructured only to keep it out of `rest`.
528
+ _appearance = _a.appearance, // eslint-disable-line @typescript-eslint/no-unused-vars
524
529
  // Destructured only to keep it out of `rest` (and so off the DOM). The gutter
525
530
  // this prop documents was never implemented: it was passed to the wrap as
526
531
  // `$flush`, whose styled template had no interpolation slot, so it has always
527
532
  // been a no-op. Removing it from the API is a separate, breaking change —
528
533
  // every consumer passing it today already gets the flush layout by default.
529
534
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
530
- _k = _a.compactFlush,
535
+ _k = _a.compactFlush, // eslint-disable-line @typescript-eslint/no-unused-vars
531
536
  // Destructured only to keep it out of `rest` (and so off the DOM). The gutter
532
537
  // this prop documents was never implemented: it was passed to the wrap as
533
538
  // `$flush`, whose styled template had no interpolation slot, so it has always
534
539
  // been a no-op. Removing it from the API is a separate, breaking change —
535
540
  // every consumer passing it today already gets the flush layout by default.
536
541
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
537
- compactFlush = _k === void 0 ? false : _k, _l = _a.compactNested, compactNested = _l === void 0 ? false : _l, _m = _a.compactScroll, compactScroll = _m === void 0 ? 'host' : _m, compactPanelProps = _a.compactPanelProps, compactCollapsedGroupsProp = _a.compactCollapsedGroups, compactBoxLabels = _a.compactBoxLabels, _o = _a.compactStickyBoxHeaders, compactStickyBoxHeaders = _o === void 0 ? true : _o, _p = _a.compactStickyOffset, compactStickyOffset = _p === void 0 ? 0 : _p, _q = _a.compactToolbar, compactToolbar = _q === void 0 ? true : _q, _r = _a.commitMode, commitMode = _r === void 0 ? 'immediate' : _r, _s = _a.expandMode, expandMode = _s === void 0 ? 'single' : _s, onCommit = _a.onCommit, operatorsProp = _a.operators, groups = _a.groups, optionsLoader = _a.optionsLoader, onValidityChange = _a.onValidityChange, optionActions = _a.optionActions, _t = _a.optionActionsCollapse, optionActionsCollapse = _t === void 0 ? 'auto' : _t, componentOverrides = _a.componentOverrides, codePreviewRenderer = _a.codePreviewRenderer,
542
+ compactFlush = _k === void 0 ? false : _k, _l = _a.compactNested, compactNested = _l === void 0 ? false : _l, _m = _a.compactScroll, compactScroll = _m === void 0 ? 'host' : _m, compactPanelProps = _a.compactPanelProps, compactCollapsedGroupsProp = _a.compactCollapsedGroups, compactBoxLabels = _a.compactBoxLabels, _o = _a.revealRequired, revealRequired = _o === void 0 ? false : _o, focusAttentionRequest = _a.focusAttentionRequest, onAttentionChange = _a.onAttentionChange, _p = _a.compactStickyBoxHeaders, compactStickyBoxHeaders = _p === void 0 ? true : _p, _q = _a.compactStickyOffset, compactStickyOffset = _q === void 0 ? 0 : _q, _r = _a.compactToolbar, compactToolbar = _r === void 0 ? true : _r, _s = _a.commitMode, commitMode = _s === void 0 ? 'immediate' : _s, _t = _a.expandMode, expandMode = _t === void 0 ? 'single' : _t, onCommit = _a.onCommit, operatorsProp = _a.operators, groups = _a.groups, optionsLoader = _a.optionsLoader, onValidityChange = _a.onValidityChange, optionActions = _a.optionActions, _u = _a.optionActionsCollapse, optionActionsCollapse = _u === void 0 ? 'auto' : _u, componentOverrides = _a.componentOverrides, codePreviewRenderer = _a.codePreviewRenderer,
538
543
  // consumed by the wrapper below, which publishes it to every description this
539
544
  // form draws; destructured here only so it cannot reach `rest` and be spread
540
545
  // onto a DOM node
541
546
  _markdownRenderer = _a.markdownRenderer, // eslint-disable-line @typescript-eslint/no-unused-vars
542
- rendererOnlyUiTypes = _a.rendererOnlyUiTypes, templateAwareUiTypes = _a.templateAwareUiTypes, anyLikeUiTypes = _a.anyLikeUiTypes, inheritedFromParent = _a.inheritedFromParent, autoFocusFirstRequired = _a.autoFocusFirstRequired, expandFirstRequired = _a.expandFirstRequired, initialExpandedOptions = _a.initialExpandedOptions, maxFieldsShown = _a.maxFieldsShown, rest = __rest(_a, ["name", "uniqueName", "value", "onChange", "onSingleOptionsChange", "onDependableOptionChange", "placeholder", "noValueString", "isValid", "url", "customUrl", "operatorsUrl", "onOptionsLoaded", "recordRequiresSearchOptions", "readOnly", "onReadOnlyActivate", "allowTemplates", "interfaceContext", "templateFieldProps", "forceDropdown", "showTypeToggle", "compact", "compactFlush", "compactNested", "compactScroll", "compactPanelProps", "compactCollapsedGroups", "compactBoxLabels", "compactStickyBoxHeaders", "compactStickyOffset", "compactToolbar", "commitMode", "expandMode", "onCommit", "operators", "groups", "optionsLoader", "onValidityChange", "optionActions", "optionActionsCollapse", "componentOverrides", "codePreviewRenderer", "markdownRenderer", "rendererOnlyUiTypes", "templateAwareUiTypes", "anyLikeUiTypes", "inheritedFromParent", "autoFocusFirstRequired", "expandFirstRequired", "initialExpandedOptions", "maxFieldsShown"]);
547
+ rendererOnlyUiTypes = _a.rendererOnlyUiTypes, templateAwareUiTypes = _a.templateAwareUiTypes, anyLikeUiTypes = _a.anyLikeUiTypes, inheritedFromParent = _a.inheritedFromParent, autoFocusFirstRequired = _a.autoFocusFirstRequired, expandFirstRequired = _a.expandFirstRequired, initialExpandedOptions = _a.initialExpandedOptions, maxFieldsShown = _a.maxFieldsShown, rest = __rest(_a, ["name", "uniqueName", "value", "onChange", "onSingleOptionsChange", "onDependableOptionChange", "placeholder", "noValueString", "isValid", "url", "customUrl", "operatorsUrl", "onOptionsLoaded", "recordRequiresSearchOptions", "readOnly", "onReadOnlyActivate", "allowTemplates", "interfaceContext", "templateFieldProps", "forceDropdown", "showTypeToggle", "compact", "appearance", "compactFlush", "compactNested", "compactScroll", "compactPanelProps", "compactCollapsedGroups", "compactBoxLabels", "revealRequired", "focusAttentionRequest", "onAttentionChange", "compactStickyBoxHeaders", "compactStickyOffset", "compactToolbar", "commitMode", "expandMode", "onCommit", "operators", "groups", "optionsLoader", "onValidityChange", "optionActions", "optionActionsCollapse", "componentOverrides", "codePreviewRenderer", "markdownRenderer", "rendererOnlyUiTypes", "templateAwareUiTypes", "anyLikeUiTypes", "inheritedFromParent", "autoFocusFirstRequired", "expandFirstRequired", "initialExpandedOptions", "maxFieldsShown"]);
543
548
  // Built-ins + whatever the consumer declared for its own injected editors.
544
549
  var isRendererOnly = (0, react_2.useMemo)(function () { return (0, rendererTypes_1.createRendererOnlyUiTypeCheck)(rendererOnlyUiTypes); }, [JSON.stringify(rendererOnlyUiTypes)]);
545
550
  // Pointer CAPABILITY and viewport WIDTH are different questions and both
@@ -564,34 +569,50 @@ var FormEngineImpl = function (_a) {
564
569
  enters the component, so the header, the chips, the messages, the meter and
565
570
  the read-first summary cannot disagree about it: every one of them reads
566
571
  `options`, and none of them has to know the rule. */
567
- var _u = (0, react_2.useState)((rest === null || rest === void 0 ? void 0 : rest.options) || undefined), servedOptions = _u[0], setOptions = _u[1];
572
+ var _v = (0, react_2.useState)((rest === null || rest === void 0 ? void 0 : rest.options) || undefined), servedOptions = _v[0], setOptions = _v[1];
568
573
  var options = (0, react_2.useMemo)(function () { return (0, options_1.resolveDegenerateRequiredGroups)(servedOptions); }, [servedOptions]);
569
574
  // optionsLoader lifecycle: loading feeds the skeleton gate, error the banner.
570
- var _v = (0, react_2.useState)(!!optionsLoader && !(rest === null || rest === void 0 ? void 0 : rest.options)), optionsLoading = _v[0], setOptionsLoading = _v[1];
571
- var _w = (0, react_2.useState)(), optionsError = _w[0], setOptionsError = _w[1];
575
+ var _w = (0, react_2.useState)(!!optionsLoader && !(rest === null || rest === void 0 ? void 0 : rest.options)), optionsLoading = _w[0], setOptionsLoading = _w[1];
576
+ var _x = (0, react_2.useState)(), optionsError = _x[0], setOptionsError = _x[1];
572
577
  // Operators: prop-provided (compact) or fetched via operatorsUrl (dpql,
573
578
  // ported from IDE Options) — the fetch overrides the seeded prop value.
574
- var _x = (0, react_2.useState)(operatorsProp), operators = _x[0], setOperators = _x[1];
579
+ var _y = (0, react_2.useState)(operatorsProp), operators = _y[0], setOperators = _y[1];
575
580
  // Remote-fetch loading (ported from IDE Options); only relevant when one of
576
581
  // the fetch urls is set — schema-as-props consumers never see the skeleton.
577
- var _y = (0, react_2.useState)(!!(url || customUrl || operatorsUrl)), loading = _y[0], setLoading = _y[1];
582
+ var _z = (0, react_2.useState)(!!(url || customUrl || operatorsUrl)), loading = _z[0], setLoading = _z[1];
578
583
  var confirmAction = (0, reqore_1.useReqoreProperty)('confirmAction');
579
584
  var theme = (0, reqore_1.useReqoreTheme)();
580
- var _z = (0, react_2.useState)(), focusedEditing = _z[0], setFocusedEditing = _z[1];
581
- var _0 = (0, react_2.useState)(false), showFieldTypes = _0[0], setShowFieldTypes = _0[1];
585
+ var calm = (0, formAppearance_1.useIsCalmForm)();
586
+ var _0 = (0, react_2.useState)(), focusedEditing = _0[0], setFocusedEditing = _0[1];
587
+ var _1 = (0, react_2.useState)(false), showFieldTypes = _1[0], setShowFieldTypes = _1[1];
582
588
  // Global toggle (toolbar ⓘ): reveal the short-description info panel on every
583
589
  // field that has a short_desc. Per-row ⓘ overrides still win over it.
584
590
  // Global field-info visibility, tri-state: `undefined` = default (critical
585
591
  // messages auto-open, the rest closed); `true` = show all; `false` = hide all
586
592
  // (even message fields). The toolbar ⓘ drives it.
587
- var _1 = (0, react_2.useState)(undefined), showAllDescriptions = _1[0], setShowAllDescriptions = _1[1];
588
- var _2 = (0, react_2.useState)(), showHelpForOption = _2[0], setShowHelpForOption = _2[1];
589
- var _3 = (0, react_2.useState)(false), showInvalidOptionsOnly = _3[0], setShowInvalidOptionsOnly = _3[1];
593
+ var _2 = (0, react_2.useState)(undefined), showAllDescriptions = _2[0], setShowAllDescriptions = _2[1];
594
+ var _3 = (0, react_2.useState)(), showHelpForOption = _3[0], setShowHelpForOption = _3[1];
595
+ var _4 = (0, react_2.useState)(false), showInvalidOptionsOnly = _4[0], setShowInvalidOptionsOnly = _4[1];
590
596
  // Which options are expanded into their editor (several can be open at once).
591
- var _4 = (0, react_2.useState)([]), expandedOptions = _4[0], setExpandedOptions = _4[1];
597
+ var _5 = (0, react_2.useState)([]), expandedOptions = _5[0], setExpandedOptions = _5[1];
598
+ // The fields the person has opened and left. An empty required field becomes a
599
+ // fault only then (or after a submit attempt, `revealRequired`): a form nobody has
600
+ // touched is not already wrong.
601
+ var _6 = (0, react_2.useState)([]), visitedOptions = _6[0], setVisitedOptions = _6[1];
602
+ var lastExpandedOptions = (0, react_2.useRef)([]);
603
+ (0, react_2.useEffect)(function () {
604
+ var left = lastExpandedOptions.current.filter(function (name) { return !expandedOptions.includes(name); });
605
+ lastExpandedOptions.current = expandedOptions;
606
+ if (left.length) {
607
+ setVisitedOptions(function (prev) {
608
+ var added = left.filter(function (name) { return !prev.includes(name); });
609
+ return added.length ? __spreadArray(__spreadArray([], prev, true), added, true) : prev;
610
+ });
611
+ }
612
+ }, [expandedOptions]);
592
613
  /** Status boxes whose "N more fields" control the reader has opened. Keyed by
593
614
  box so opening Optional does not also unfold Set. */
594
- var _5 = (0, react_2.useState)([]), expandedMoreBoxes = _5[0], setExpandedMoreBoxes = _5[1];
615
+ var _7 = (0, react_2.useState)([]), expandedMoreBoxes = _7[0], setExpandedMoreBoxes = _7[1];
595
616
  // --- Reveal a status box's content when it is opened ----------------------
596
617
  //
597
618
  // The status boxes stack, so the last one ("Optional", which holds every
@@ -607,7 +628,7 @@ var FormEngineImpl = function (_a) {
607
628
  // box has not grown and there is nothing to scroll to. A layout effect runs
608
629
  // after the DOM is updated and before paint, which makes the reveal
609
630
  // deterministic instead of a guessed delay.
610
- var _6 = (0, react_2.useState)(undefined), openedStatusBox = _6[0], setOpenedStatusBox = _6[1];
631
+ var _8 = (0, react_2.useState)(undefined), openedStatusBox = _8[0], setOpenedStatusBox = _8[1];
611
632
  var statusBoxRefs = (0, react_2.useRef)({});
612
633
  (0, react_2.useLayoutEffect)(function () {
613
634
  var _a, _b;
@@ -638,13 +659,13 @@ var FormEngineImpl = function (_a) {
638
659
  var settledBucket = (0, react_2.useRef)({});
639
660
  // Measured form width (not viewport — the form lives in drawers/panels of
640
661
  // arbitrary width) drives the stacked narrow layout.
641
- var _7 = (0, react_use_1.useMeasure)(), compactWrapRef = _7[0], compactWrapWidth = _7[1].width;
662
+ var _9 = (0, react_use_1.useMeasure)(), compactWrapRef = _9[0], compactWrapWidth = _9[1].width;
642
663
  // Own handle on the scroll wrap (useMeasure's ref is a callback, no `.current`)
643
664
  // so the label-column measurement can publish its CSS var on the element. It's
644
665
  // STATE, not a ref: the wrap mounts only after the loading-skeleton gate
645
666
  // resolves, so the measurement effect must re-run when the node appears — a
646
667
  // ref wouldn't retrigger it.
647
- var _8 = (0, react_2.useState)(null), compactWrapNode = _8[0], setCompactWrapNode = _8[1];
668
+ var _10 = (0, react_2.useState)(null), compactWrapNode = _10[0], setCompactWrapNode = _10[1];
648
669
  // Ref mirror of the wrap node for callbacks that must not re-create when it
649
670
  // mounts (flashOptions reads it inside a rAF).
650
671
  var compactWrapNodeRef = (0, react_2.useRef)(null);
@@ -672,7 +693,7 @@ var FormEngineImpl = function (_a) {
672
693
  a search row and a field picker that each hide themselves when they have
673
694
  nothing to say, and what is left wraps differently at every form width.
674
695
  Zero when this form draws no toolbar at all. */
675
- var _9 = (0, react_2.useState)(0), compactToolbarHeight = _9[0], setCompactToolbarHeight = _9[1];
696
+ var _11 = (0, react_2.useState)(0), compactToolbarHeight = _11[0], setCompactToolbarHeight = _11[1];
676
697
  (0, react_2.useLayoutEffect)(function () {
677
698
  var wrap = compactWrapNode;
678
699
  if (!compact || !wrap || compactNested || !compactStickyBoxHeaders) {
@@ -757,8 +778,8 @@ var FormEngineImpl = function (_a) {
757
778
  var readRowHeights = (0, react_2.useRef)({});
758
779
  // Required-groups linkage: hovering a group chip highlights every member row;
759
780
  // clicking a sibling in the chip's popover scrolls to it and flashes it.
760
- var _10 = (0, react_2.useState)([]), highlightedOptions = _10[0], setHighlightedOptions = _10[1];
761
- var _11 = (0, react_2.useState)([]), flashedOptions = _11[0], setFlashedOptions = _11[1];
781
+ var _12 = (0, react_2.useState)([]), highlightedOptions = _12[0], setHighlightedOptions = _12[1];
782
+ var _13 = (0, react_2.useState)([]), flashedOptions = _13[0], setFlashedOptions = _13[1];
762
783
  var flashTimeout = (0, react_2.useRef)();
763
784
  var flashOptions = (0, react_2.useCallback)(function (optionNames, scrollToFirst) {
764
785
  if (scrollToFirst === void 0) { scrollToFirst = false; }
@@ -810,16 +831,16 @@ var FormEngineImpl = function (_a) {
810
831
  }
811
832
  });
812
833
  // Info panels auto-open on Tier-1 content; the per-row user override sticks.
813
- var _12 = (0, react_2.useState)({}), infoPanelOverrides = _12[0], setInfoPanelOverrides = _12[1];
834
+ var _14 = (0, react_2.useState)({}), infoPanelOverrides = _14[0], setInfoPanelOverrides = _14[1];
814
835
  // Toolbar filters affect the listed rows only — the meter reflects the full set.
815
- var _13 = (0, react_2.useState)(false), requiredOnly = _13[0], setRequiredOnly = _13[1];
816
- var _14 = (0, react_2.useState)(''), compactQuery = _14[0], setCompactQuery = _14[1];
836
+ var _15 = (0, react_2.useState)(false), requiredOnly = _15[0], setRequiredOnly = _15[1];
837
+ var _16 = (0, react_2.useState)(''), compactQuery = _16[0], setCompactQuery = _16[1];
817
838
  // Compact field sort (Fields menu → "Sort by"); 'schema' = declared order.
818
- var _15 = (0, react_2.useState)('schema'), compactSort = _15[0], setCompactSort = _15[1];
819
- var _16 = (0, react_2.useState)(function () { return ({
839
+ var _17 = (0, react_2.useState)('schema'), compactSort = _17[0], setCompactSort = _17[1];
840
+ var _18 = (0, react_2.useState)(function () { return ({
820
841
  fields: (0, exports.fixOptions)(value, options || {}, undefined, isRendererOnly),
821
842
  meta: undefined,
822
- }); }), localValue = _16[0], setLocalValue = _16[1];
843
+ }); }), localValue = _18[0], setLocalValue = _18[1];
823
844
  var originalValue = (0, react_2.useRef)();
824
845
  // Track the last value we emitted via onChange so we can skip re-applying fixOptions
825
846
  // when the parent echoes it back as the new value prop (controlled component loop prevention)
@@ -864,7 +885,7 @@ var FormEngineImpl = function (_a) {
864
885
  originalValue.current = localValue.fields;
865
886
  }
866
887
  var unavailableOptionsCount = (0, react_2.useRef)(0);
867
- var _17 = (0, useQorusTypes_1.useQorusTypes)(), compactValue = _17.compactValue, typesLoading = _17.loading;
888
+ var _19 = (0, useQorusTypes_1.useQorusTypes)(), compactValue = _19.compactValue, typesLoading = _19.loading;
868
889
  var templates = (0, useTemplates_1.useTemplates)(allowTemplates, rest.stringTemplates, interfaceContext);
869
890
  (0, react_2.useEffect)(function () {
870
891
  if (!(0, exports.shouldEmitLocalValue)({
@@ -1523,6 +1544,11 @@ var FormEngineImpl = function (_a) {
1523
1544
  return (0, reduce_1.default)(availableOptions, function (newValue, option, optionName) {
1524
1545
  var _a;
1525
1546
  if (showInvalidOptionsOnly &&
1547
+ // An open row stays while the reader is in it, as its box does
1548
+ // (`stableBucketOf`): the first character typed into an empty required
1549
+ // field makes it valid, and hiding it then would pull the field out
1550
+ // from under the caret mid-word.
1551
+ !expandedOptions.includes(optionName) &&
1526
1552
  isOptionValid(optionName, (0, exports.getOptionFieldStorageType)(optionName, option.type, options, operators, option.op, isRendererOnly, optionHoldsExpression(option)), option.value)) {
1527
1553
  return newValue;
1528
1554
  }
@@ -1530,6 +1556,7 @@ var FormEngineImpl = function (_a) {
1530
1556
  }, {});
1531
1557
  }, [
1532
1558
  showInvalidOptionsOnly,
1559
+ expandedOptions,
1533
1560
  isRendererOnly,
1534
1561
  JSON.stringify(availableOptions),
1535
1562
  JSON.stringify(options),
@@ -1585,8 +1612,11 @@ var FormEngineImpl = function (_a) {
1585
1612
  covered: covered,
1586
1613
  invalid: invalid,
1587
1614
  warned: msgIntent === 'warning',
1615
+ visited: revealRequired || visitedOptions.includes(name),
1588
1616
  });
1589
1617
  }, [
1618
+ revealRequired,
1619
+ visitedOptions,
1590
1620
  isRendererOnly,
1591
1621
  JSON.stringify(options),
1592
1622
  JSON.stringify(availableOptions),
@@ -1615,6 +1645,21 @@ var FormEngineImpl = function (_a) {
1615
1645
  return Object.keys(availableOptions || {}).filter(function (name) { return getOptionBucket(name) === 'attention'; })
1616
1646
  .length;
1617
1647
  }, [JSON.stringify(availableOptions), getOptionBucket]);
1648
+ // How many of those are faults rather than only still to fill in (`pending`). Zero
1649
+ // on a new form, so its first box reads "To fill in" without amber.
1650
+ var readFirstAttentionFaultCount = (0, react_2.useMemo)(function () {
1651
+ return Object.keys(availableOptions || {}).filter(function (name) { return getOptionBucket(name) === 'attention' && getOptionStatus(name) !== 'pending'; }).length;
1652
+ }, [JSON.stringify(availableOptions), getOptionBucket, getOptionStatus]);
1653
+ // The same two numbers, to a host that draws its own submit control from them.
1654
+ var onAttentionChangeRef = (0, react_2.useRef)(onAttentionChange);
1655
+ onAttentionChangeRef.current = onAttentionChange;
1656
+ (0, react_2.useEffect)(function () {
1657
+ var _a;
1658
+ (_a = onAttentionChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onAttentionChangeRef, {
1659
+ count: readFirstAttentionCount,
1660
+ faults: readFirstAttentionFaultCount,
1661
+ });
1662
+ }, [readFirstAttentionCount, readFirstAttentionFaultCount]);
1618
1663
  var getIntent = (0, react_2.useCallback)(
1619
1664
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
1620
1665
  function (optName, type, optValue, _op) {
@@ -1717,6 +1762,31 @@ var FormEngineImpl = function (_a) {
1717
1762
  // field update or an in-place schema reload will NOT re-grab focus; only a
1718
1763
  // genuine remount (a fresh instance) auto-focuses again, which is the intended
1719
1764
  // on-mount behaviour.
1765
+ // What the "first field to fix" scans read: the opener on arrival below and the
1766
+ // caret move on a submit attempt (`focusAttentionRequest`) pick the same field.
1767
+ var getAttentionFieldMeta = (0, react_2.useCallback)(function (fieldName) {
1768
+ var schema = options === null || options === void 0 ? void 0 : options[fieldName];
1769
+ if (!schema) {
1770
+ return undefined;
1771
+ }
1772
+ return {
1773
+ focusable: !readOnly &&
1774
+ !schema.disabled &&
1775
+ !schema.readonly &&
1776
+ !dependencyLockedNames.includes(fieldName),
1777
+ // Single source of truth: the same bucket the read-first status boxes
1778
+ // show, so a filled-but-invalid required row is a target too.
1779
+ needsAttention: getOptionBucket(fieldName) === 'attention',
1780
+ };
1781
+ }, [options, readOnly, dependencyLockedNames, getOptionBucket]);
1782
+ // Opening a row by name: `expandMode: 'single'` replaces only what a click could
1783
+ // (see the note in the opener below), never a row the host named.
1784
+ var openOption = (0, react_2.useCallback)(function (target) {
1785
+ return setExpandedOptions(function (prev) {
1786
+ return prev.includes(target) ? prev
1787
+ : expandMode === 'multi' ? __spreadArray(__spreadArray([], prev, true), [target], false) : __spreadArray(__spreadArray([], prev.filter(function (name) { return initialExpandedOptions === null || initialExpandedOptions === void 0 ? void 0 : initialExpandedOptions.includes(name); }), true), [target], false);
1788
+ });
1789
+ }, [expandMode, initialExpandedOptions]);
1720
1790
  var hasAutoFocusedRef = (0, react_2.useRef)(false);
1721
1791
  (0, react_2.useEffect)(function () {
1722
1792
  // Two decisions, one scan. Both open the row that needs attention;
@@ -1752,37 +1822,19 @@ var FormEngineImpl = function (_a) {
1752
1822
  if (wantsFocus && active && active !== document.body) {
1753
1823
  return;
1754
1824
  }
1755
- var target = (0, readFirst_1.getFirstAttentionOptionName)(orderedNames, function (fieldName) {
1756
- var schema = options[fieldName];
1757
- if (!schema) {
1758
- return undefined;
1759
- }
1760
- return {
1761
- focusable: !readOnly &&
1762
- !schema.disabled &&
1763
- !schema.readonly &&
1764
- !dependencyLockedNames.includes(fieldName),
1765
- // Single source of truth: the same bucket the read-first status boxes
1766
- // show, so a filled-but-invalid required row is a target too.
1767
- needsAttention: getOptionBucket(fieldName) === 'attention',
1768
- };
1769
- });
1825
+ var target = (0, readFirst_1.getFirstAttentionOptionName)(orderedNames, getAttentionFieldMeta);
1770
1826
  // Mark done even when nothing needs attention, so later value edits or an
1771
1827
  // in-place schema reload never re-scan or re-focus. Only a remount arms it
1772
1828
  // again.
1773
1829
  hasAutoFocusedRef.current = true;
1774
1830
  if (target) {
1775
- setExpandedOptions(function (prev) {
1776
- return prev.includes(target) ? prev
1777
- : expandMode === 'multi' ? __spreadArray(__spreadArray([], prev, true), [target], false)
1778
- // `expandMode: 'single'` is a rule about what a CLICK does: opening a
1779
- // row closes the one the reader last opened. It is not a licence to
1780
- // close a row the HOST named through `initialExpandedOptions`. That
1781
- // is an address — a statement about what the page is FOR, made before
1782
- // the reader did anything — and this scan is a convenience layered on
1783
- // top of it. Keep the named rows; replace only what a click could.
1784
- : __spreadArray(__spreadArray([], prev.filter(function (name) { return initialExpandedOptions === null || initialExpandedOptions === void 0 ? void 0 : initialExpandedOptions.includes(name); }), true), [target], false);
1785
- });
1831
+ // `expandMode: 'single'` is a rule about what a CLICK does: opening a row
1832
+ // closes the one the reader last opened. It is not a licence to close a row
1833
+ // the HOST named through `initialExpandedOptions`. That is an address — a
1834
+ // statement about what the page is FOR, made before the reader did anything
1835
+ // — and this scan is a convenience layered on top of it. `openOption` keeps
1836
+ // the named rows and replaces only what a click could.
1837
+ openOption(target);
1786
1838
  }
1787
1839
  }, [
1788
1840
  autoFocusFirstRequired,
@@ -1790,12 +1842,48 @@ var FormEngineImpl = function (_a) {
1790
1842
  compact,
1791
1843
  options,
1792
1844
  availableOptions,
1793
- readOnly,
1794
- dependencyLockedNames,
1795
- getOptionBucket,
1796
- expandMode,
1797
- initialExpandedOptions,
1845
+ getAttentionFieldMeta,
1846
+ openOption,
1798
1847
  ]);
1848
+ // A submit that could not go is answered with where to type: each new
1849
+ // `focusAttentionRequest` opens the first field that needs attention and puts the
1850
+ // caret in it. The host's submit button holds the caret at that moment, and an open
1851
+ // row never takes a caret held outside it (CompactRow), so the button lets go of it
1852
+ // here first; the person asked to submit, and this is the answer to that.
1853
+ var lastFocusRequest = (0, react_2.useRef)(focusAttentionRequest);
1854
+ (0, react_2.useEffect)(function () {
1855
+ var _a;
1856
+ if (focusAttentionRequest === lastFocusRequest.current) {
1857
+ return;
1858
+ }
1859
+ lastFocusRequest.current = focusAttentionRequest;
1860
+ if (!focusAttentionRequest || !compact || !options) {
1861
+ return;
1862
+ }
1863
+ var target = (0, readFirst_1.getFirstAttentionOptionName)(Object.keys(availableOptions), getAttentionFieldMeta);
1864
+ if (!target) {
1865
+ return;
1866
+ }
1867
+ var wrap = compactWrapNodeRef.current;
1868
+ var active = document.activeElement;
1869
+ if (active && active !== document.body && !(wrap === null || wrap === void 0 ? void 0 : wrap.contains(active))) {
1870
+ active.blur();
1871
+ }
1872
+ if (!expandedOptions.includes(target)) {
1873
+ // The row's own open effect reveals it and takes the caret.
1874
+ openOption(target);
1875
+ return;
1876
+ }
1877
+ // Already open (the field the form opened on arrival): its open effect has run,
1878
+ // so the caret goes to its control here.
1879
+ var row = wrap === null || wrap === void 0 ? void 0 : wrap.querySelector("[data-field=\"".concat(target, "\"]"));
1880
+ if (row) {
1881
+ (0, revealRow_1.revealRow)(row, 'auto');
1882
+ (_a = (0, rowFocus_1.findRowFocusTarget)(row.querySelector('.options-readfirst-row-editor'), {
1883
+ textEntryOnly: row.classList.contains('options-readfirst-card'),
1884
+ })) === null || _a === void 0 ? void 0 : _a.focus({ preventScroll: true });
1885
+ }
1886
+ }, [focusAttentionRequest]);
1799
1887
  // Read-first completion summary (how many shown options have a value set),
1800
1888
  // surfaced as a progress meter at the top of the compact form.
1801
1889
  var readFirstCompletion = (0, react_2.useMemo)(function () {
@@ -2042,7 +2130,10 @@ var FormEngineImpl = function (_a) {
2042
2130
  readOnly ||
2043
2131
  !(0, validations_1.hasAllDependenciesFullfilled)((_v = options === null || options === void 0 ? void 0 : options[optionName]) === null || _v === void 0 ? void 0 : _v.depends_on, availableOptions, options || {}), readOnly: readOnly, size: editorSize || rest.size, menuItems: (0, typeChoices_1.offersTypeChoices)(options === null || options === void 0 ? void 0 : options[optionName], anyLikeUiTypes) ?
2044
2132
  getCustomMenuTemplateItems(optionName)
2045
- : undefined }, templateFieldProps, { forceDropdown: effectiveForceDropdown })), (0, jsx_runtime_1.jsx)(OptionFieldMessages_1.OptionFieldMessages, { schema: options || {}, allOptions: availableOptions, name: optionName, option: __assign({ type: resolvedType }, other), getType: getTypeForOption, isRendererOnly: isRendererOnly }), operators && (0, size_1.default)(operators) && (0, size_1.default)(other.op) ?
2133
+ : undefined }, templateFieldProps, { forceDropdown: effectiveForceDropdown })), (0, jsx_runtime_1.jsx)(OptionFieldMessages_1.OptionFieldMessages, { schema: options || {}, allOptions: availableOptions, name: optionName, option: __assign({ type: resolvedType }, other), getType: getTypeForOption, isRendererOnly: isRendererOnly,
2134
+ // Open is not left: a field the form opened for typing (the first empty
2135
+ // one, on a new form) says what it needs without already being wrong.
2136
+ requirementPending: !(revealRequired || visitedOptions.includes(optionName)) }), operators && (0, size_1.default)(operators) && (0, size_1.default)(other.op) ?
2046
2137
  (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 ?
2047
2138
  resolvedType === 'richtext' ?
2048
2139
  (0, common_1.richtextToString)(other.value)
@@ -2074,6 +2165,8 @@ var FormEngineImpl = function (_a) {
2074
2165
  getTypeForOption,
2075
2166
  inheritedScopes,
2076
2167
  inheritedFromParent,
2168
+ revealRequired,
2169
+ visitedOptions,
2077
2170
  ]);
2078
2171
  // Compact (read-first) rendering.
2079
2172
  // Theme-derived colours so the flat-row layout adapts to light/dark/custom themes.
@@ -2096,6 +2189,10 @@ var FormEngineImpl = function (_a) {
2096
2189
  // The "N more fields" row's dashed edge. Well above the divider tint: this
2097
2190
  // one is an affordance the reader has to notice, not a hairline between rows.
2098
2191
  var cMoreBorder = "".concat(cText, "4d");
2192
+ // Calm: the section surface and its hairline, from the theme's panel (the
2193
+ // same surface and edge Reqore gives the section panels themselves).
2194
+ var cPanel = (0, formAppearance_1.getCalmPanelSurface)(theme);
2195
+ var cHairline = (0, formAppearance_1.getCalmPanelHairline)(theme);
2099
2196
  // The closure surface the extracted CompactRow reads through context. Refs and
2100
2197
  // setters are stable; the state/memo/handler fields change identity as they do
2101
2198
  // today, so a row re-renders exactly when its inputs do.
@@ -2112,6 +2209,8 @@ var FormEngineImpl = function (_a) {
2112
2209
  codePreviewRenderer: codePreviewRenderer,
2113
2210
  showAllDescriptions: showAllDescriptions,
2114
2211
  expandedOptions: expandedOptions,
2212
+ visitedOptions: visitedOptions,
2213
+ revealRequired: revealRequired,
2115
2214
  highlightedOptions: highlightedOptions,
2116
2215
  flashedOptions: flashedOptions,
2117
2216
  infoPanelOverrides: infoPanelOverrides,
@@ -2159,6 +2258,8 @@ var FormEngineImpl = function (_a) {
2159
2258
  codePreviewRenderer,
2160
2259
  showAllDescriptions,
2161
2260
  expandedOptions,
2261
+ visitedOptions,
2262
+ revealRequired,
2162
2263
  highlightedOptions,
2163
2264
  flashedOptions,
2164
2265
  infoPanelOverrides,
@@ -2207,6 +2308,7 @@ var FormEngineImpl = function (_a) {
2207
2308
  readOnly: readOnly,
2208
2309
  invalidCount: (0, size_1.default)(validityData.invalidFields),
2209
2310
  attentionCount: readFirstAttentionCount,
2311
+ attentionFaultCount: readFirstAttentionFaultCount,
2210
2312
  completion: readFirstCompletion,
2211
2313
  showInvalidOnly: showInvalidOptionsOnly,
2212
2314
  onToggleInvalidOnly: handleToggleInvalidOnly,
@@ -2253,6 +2355,7 @@ var FormEngineImpl = function (_a) {
2253
2355
  onReadOnlyActivate,
2254
2356
  validityData,
2255
2357
  readFirstAttentionCount,
2358
+ readFirstAttentionFaultCount,
2256
2359
  readFirstCompletion,
2257
2360
  showInvalidOptionsOnly,
2258
2361
  handleToggleInvalidOnly,
@@ -2282,7 +2385,7 @@ var FormEngineImpl = function (_a) {
2282
2385
  // removes it, and then the header carries just the consumer's own actions.
2283
2386
  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]);
2284
2387
  var renderCompact = function () {
2285
- var _a, _b, _c, _d;
2388
+ var _a, _b, _c, _d, _f;
2286
2389
  var headerBg = "".concat((0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.02)).concat((0, colors_1.percentToHexAlpha)(88));
2287
2390
  // Toolbar filters narrow the listed rows; the meter reflects the full set.
2288
2391
  var query = compactQuery.trim().toLowerCase();
@@ -2512,16 +2615,24 @@ var FormEngineImpl = function (_a) {
2512
2615
  var stickyBoxHeaders = compactStickyBoxHeaders && !compactNested;
2513
2616
  var boxStickyOffset = compactStickyOffset + compactToolbarHeight;
2514
2617
  var STATUS_BOXES = [
2515
- {
2516
- key: 'attention',
2517
- label: (_a = compactBoxLabels === null || compactBoxLabels === void 0 ? void 0 : compactBoxLabels.attention) !== null && _a !== void 0 ? _a : 'Needs attention',
2518
- intent: 'warning',
2519
- icon: 'ErrorWarningLine',
2520
- },
2521
- { key: 'set', label: (_b = compactBoxLabels === null || compactBoxLabels === void 0 ? void 0 : compactBoxLabels.set) !== null && _b !== void 0 ? _b : 'Set', intent: 'success', icon: 'CheckLine' },
2618
+ // The first box is amber only once something in it is a fault. On a new form it
2619
+ // holds the required fields still to fill in, which is not yet anything wrong.
2620
+ readFirstAttentionFaultCount ?
2621
+ {
2622
+ key: 'attention',
2623
+ label: (_a = compactBoxLabels === null || compactBoxLabels === void 0 ? void 0 : compactBoxLabels.attention) !== null && _a !== void 0 ? _a : 'Needs attention',
2624
+ intent: 'warning',
2625
+ icon: 'ErrorWarningLine',
2626
+ }
2627
+ : {
2628
+ key: 'attention',
2629
+ label: (_b = compactBoxLabels === null || compactBoxLabels === void 0 ? void 0 : compactBoxLabels.pending) !== null && _b !== void 0 ? _b : 'To fill in',
2630
+ icon: 'CheckboxBlankCircleLine',
2631
+ },
2632
+ { key: 'set', label: (_c = compactBoxLabels === null || compactBoxLabels === void 0 ? void 0 : compactBoxLabels.set) !== null && _c !== void 0 ? _c : 'Set', intent: 'success', icon: 'CheckLine' },
2522
2633
  {
2523
2634
  key: 'optional',
2524
- label: (_c = compactBoxLabels === null || compactBoxLabels === void 0 ? void 0 : compactBoxLabels.optional) !== null && _c !== void 0 ? _c : 'Optional',
2635
+ label: (_d = compactBoxLabels === null || compactBoxLabels === void 0 ? void 0 : compactBoxLabels.optional) !== null && _d !== void 0 ? _d : 'Optional',
2525
2636
  icon: 'CheckboxBlankCircleLine',
2526
2637
  },
2527
2638
  ];
@@ -2571,7 +2682,10 @@ var FormEngineImpl = function (_a) {
2571
2682
  // "Covers"/"Covered by" chips already say which member satisfies it.
2572
2683
  if (requiredGroupsInfo.satisfiedBy[grp])
2573
2684
  return railed;
2574
- 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));
2685
+ // Amber once someone has been to the group (or a submit was attempted); until
2686
+ // then it is still to fill in, in the quiet colour, like its members.
2687
+ var clusterColor = memberEntries.some(function (e) { return getOptionStatus(e.name) !== 'pending'; }) ? cWarning : cMuted;
2688
+ return ((0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledRequiredClusterBox, { className: 'options-readfirst-required-cluster', "$border": "".concat(clusterColor, "33"), "$tint": "".concat(clusterColor, "0d"), "$calm": calm, children: [(0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledRequiredClusterHeader, { className: 'options-readfirst-required-cluster-header', "$color": clusterColor, "$calm": calm, children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreIcon, { icon: 'LinkM', size: calm ? '13px' : '11px', style: { color: clusterColor } }), "One of the below is required"] }), railed] }, grp));
2575
2689
  });
2576
2690
  };
2577
2691
  // One schema group inside a status box: its thin sub-label, the group's
@@ -2590,14 +2704,18 @@ var FormEngineImpl = function (_a) {
2590
2704
  return null;
2591
2705
  }
2592
2706
  return ((0, jsx_runtime_1.jsxs)(react_2.default.Fragment, { children: [showGroupSubLabel(groupName) ?
2593
- (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBoxGroupLabel, { children: (0, readFirst_1.getOptionGroupLabel)(groupName, groups) })
2707
+ (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBoxGroupLabel, { className: 'options-readfirst-group-label', "$calm": calm, "$color": cKey, children: (0, readFirst_1.getOptionGroupLabel)(groupName, groups) })
2594
2708
  : null, showGroupSubLabel(groupName) && (groupConfig === null || groupConfig === void 0 ? void 0 : groupConfig.subtitle) ?
2595
- (0, jsx_runtime_1.jsx)(reqore_1.ReqoreP, { size: 'small', effect: { opacity: 0.6 }, style: {
2596
- marginTop: 2,
2597
- marginBottom: 8,
2598
- marginLeft: compactRowStyles_1.GROUP_INDENT,
2599
- paddingRight: 10,
2600
- }, children: groupConfig.subtitle })
2709
+ (0, jsx_runtime_1.jsx)(reqore_1.ReqoreP, { className: 'options-readfirst-group-subtitle', size: 'small', effect: { opacity: 0.6 }, style: calm ?
2710
+ // Under the calm heading, at the rows' inset; the space below
2711
+ // it is the next row's own padding.
2712
+ { margin: 0, padding: "2px ".concat(compactRowStyles_1.CALM_SECTION_INSET, "px 4px") }
2713
+ : {
2714
+ marginTop: 2,
2715
+ marginBottom: 8,
2716
+ marginLeft: compactRowStyles_1.GROUP_INDENT,
2717
+ paddingRight: 10,
2718
+ }, children: groupConfig.subtitle })
2601
2719
  : null, renderGroupRows(rows)] }, groupName));
2602
2720
  };
2603
2721
  return ((0, jsx_runtime_1.jsx)(optionsContext_1.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', "$ownScroll": compactScroll === 'own' && !compactNested, children: [(0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledCompactPanel
@@ -2607,7 +2725,14 @@ var FormEngineImpl = function (_a) {
2607
2725
  , __assign({ "$tightHeader": !((compactToolbarParts === null || compactToolbarParts === void 0 ? void 0 : compactToolbarParts.search) && (0, size_1.default)(options) > 1), "$headerBg": compactNested ? 'transparent' : headerBg, "$nested": compactNested, "$stickyBoxes": compactStickyBoxHeaders && !compactNested, "$stackHeader": compactNarrow &&
2608
2726
  !!((compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.label) ||
2609
2727
  (compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.icon) ||
2610
- ((_d = compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.actions) === null || _d === void 0 ? void 0 : _d.length)), flat: true, raised: true, minimal: true,
2728
+ ((_f = compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.actions) === null || _f === void 0 ? void 0 : _f.length)), flat: true,
2729
+ // Calm: no surface and no lift at all. A theme that gives
2730
+ // panels a surface of their own (Reqore's `theme.panel`) would
2731
+ // otherwise paint this wrapper as a card around the section
2732
+ // cards inside it. Transparent and un-raised, Reqore also drops
2733
+ // the wrapper's horizontal padding, so the readiness line, the
2734
+ // search and the sections share one left edge with the host.
2735
+ raised: !calm, minimal: true, transparent: calm || undefined,
2611
2736
  // No panel background: the form sits transparently on whatever
2612
2737
  // hosts it (page, drawer, or — for an arg_schema field — the
2613
2738
  // parent's edit card) instead of stacking its own dark surface.
@@ -2661,7 +2786,7 @@ var FormEngineImpl = function (_a) {
2661
2786
  : 'No fields match the current filters.' })
2662
2787
  : null, readOnly ?
2663
2788
  bucketCount('set') ?
2664
- (0, jsx_runtime_1.jsx)("div", { className: 'options-readfirst-read', style: { 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, "$moreBorder": cMoreBorder, className: compactNarrow ? 'readfirst-narrow' : undefined, children: bucketGroups.set.map(function (groupName) { return renderBoxGroup('set', groupName); }) }) })
2789
+ (0, jsx_runtime_1.jsx)("div", { className: 'options-readfirst-read', style: { padding: calm ? 0 : '4px 4px 6px' }, children: (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledGroupBody, { "$calm": calm, "$hairline": cHairline, "$divider": cDivider, "$hover": cHover, "$focus": cWarning, "$success": cSuccess, "$rowBg": cRowBg, "$lineColor": cGroupLine, "$moreBorder": cMoreBorder, className: "readfirst-read-list".concat(compactNarrow ? ' readfirst-narrow' : ''), children: bucketGroups.set.map(function (groupName) { return renderBoxGroup('set', groupName); }) }) })
2665
2790
  : null
2666
2791
  : STATUS_BOXES.map(function (box) {
2667
2792
  var groupsInBox = bucketGroups[box.key];
@@ -2682,6 +2807,12 @@ var FormEngineImpl = function (_a) {
2682
2807
  // Group order is preserved so the visible rows read in the
2683
2808
  // same order they would if nothing were folded.
2684
2809
  var orderedRows = groupsInBox.flatMap(function (groupName) { return buckets[box.key][groupName] || []; });
2810
+ // The number in the box's header counts the rows whose value
2811
+ // belongs in it NOW. A field being edited keeps its box until it
2812
+ // is left (so it does not jump away under the caret), and it used
2813
+ // to keep its count too: a box read "To fill in 1" while its last
2814
+ // field already had a value and the host's submit read ready.
2815
+ var headerCount = readOnly ? count : (orderedRows.filter(function (entry) { return getOptionBucket(entry.name, entry.hidden) === box.key; }).length);
2685
2816
  // Optional's own rule first: a box opened solely to reveal
2686
2817
  // preselected rows offers those, not an arbitrary first-N.
2687
2818
  var candidateRows = splitForPreselected ? orderedRows.filter(isPreselectedRow) : orderedRows;
@@ -2706,23 +2837,32 @@ var FormEngineImpl = function (_a) {
2706
2837
  return (buckets[box.key][groupName] || []).some(function (entry) { return !shownRowSet.has(entry.name); });
2707
2838
  });
2708
2839
  var moreOpen = Boolean(query) || expandedMoreBoxes.includes(box.key);
2709
- var accent = box.key === 'attention' ? cWarning
2840
+ var accent = box.key === 'attention' && readFirstAttentionFaultCount ? cWarning
2710
2841
  : box.key === 'set' ? cSuccess
2711
2842
  : cMuted;
2712
2843
  // The muted "Optional" box reads as a quieter, recessed
2713
2844
  // surface — a touch darker than the page rather than the
2714
2845
  // faint grey tint the accent would give.
2715
- var boxBg = box.key === 'optional' ?
2846
+ // Calm: every box is the same panel — no recessed one.
2847
+ var boxBg = box.key === 'optional' && !calm ?
2716
2848
  (0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.06)
2717
2849
  : undefined;
2718
- return ((0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBox, { "$accent": accent, "$bg": boxBg, "$surface": stickyBoxHeaders ? (0, colors_1.getMainBackgroundColor)(theme) : undefined, ref: function (node) {
2850
+ return ((0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBox, { "$accent": accent, "$bg": boxBg, "$calm": calm, "$surface": stickyBoxHeaders ?
2851
+ calm ? cPanel
2852
+ : (0, colors_1.getMainBackgroundColor)(theme)
2853
+ : undefined, ref: function (node) {
2719
2854
  statusBoxRefs.current[box.key] = node;
2720
2855
  },
2721
2856
  // Opening arms the reveal; collapsing disarms it, so a
2722
2857
  // close never scrolls.
2723
2858
  onCollapseChange: function (collapsed) {
2724
2859
  return setOpenedStatusBox(collapsed ? undefined : box.key);
2725
- }, flat: true, minimal: true,
2860
+ },
2861
+ // Calm: an ordinary panel — Reqore paints the theme's
2862
+ // panel surface and its hairline edge. The header stays
2863
+ // minimal (no surface or rule of its own); the first
2864
+ // row's hairline is the line under it.
2865
+ flat: !calm, minimal: true,
2726
2866
  /* The header stays on screen while its own box is
2727
2867
  being read — see `compactStickyBoxHeaders`. Sticky
2728
2868
  is bounded by its containing block, so the header
@@ -2754,7 +2894,17 @@ var FormEngineImpl = function (_a) {
2754
2894
  // the box reveals the preselected fields without also
2755
2895
  // dumping every not-yet-added optional field on the
2756
2896
  // author.
2757
- isCollapsed: wouldCollapse && !hasPreselectedRows, 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.jsxs)(compactRowStyles_1.StyledGroupBody, { "$divider": cDivider, "$hover": cHover, "$focus": cWarning, "$success": cSuccess, "$rowBg": cRowBg, "$lineColor": cGroupLine, "$moreBorder": cMoreBorder, className: compactNarrow ? 'readfirst-narrow' : undefined, children: [shownGroups.map(function (groupName) {
2897
+ isCollapsed: wouldCollapse && !hasPreselectedRows, label: calm ?
2898
+ // One status dot and a word — and only where a
2899
+ // person is needed. The count is a quiet number.
2900
+ (0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledGroupHeader, { "$calm": true, children: [box.key === 'attention' && readFirstAttentionFaultCount ?
2901
+ (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusDot, { className: 'options-readfirst-group-dot', "$color": cWarning, "aria-hidden": true })
2902
+ : null, (0, jsx_runtime_1.jsx)(reqore_1.ReqoreP, { effect: { weight: 'bold' }, size: 'normal', children: box.label }), headerCount ?
2903
+ (0, jsx_runtime_1.jsx)(reqore_1.ReqoreSpan, { className: 'options-readfirst-group-count', size: 'small', effect: { opacity: 0.65 }, children: headerCount })
2904
+ : null] })
2905
+ : (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 }), headerCount ?
2906
+ (0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', minimal: true, compact: true, intent: box.intent, label: String(headerCount) })
2907
+ : null] }), icon: calm ? undefined : box.icon, className: 'options-readfirst-group', padded: false, contentStyle: { padding: calm ? 0 : '4px 4px 6px' }, children: (0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledGroupBody, { "$calm": calm, "$hairline": cHairline, "$divider": cDivider, "$hover": cHover, "$focus": cWarning, "$success": cSuccess, "$rowBg": cRowBg, "$lineColor": cGroupLine, "$moreBorder": cMoreBorder, className: compactNarrow ? 'readfirst-narrow' : undefined, children: [shownGroups.map(function (groupName) {
2758
2908
  return renderBoxGroup(box.key, groupName, shownRowSet);
2759
2909
  }), deferredCount ?
2760
2910
  (0, jsx_runtime_1.jsxs)("button", { type: 'button', className: 'readfirst-row readfirst-more-row options-readfirst-more', "aria-expanded": moreOpen, onClick: function () {
@@ -2967,7 +3117,15 @@ var FormEngineImpl = function (_a) {
2967
3117
  * a child of the row it belongs to. Threading a renderer to each of them by
2968
3118
  * hand is how one of them gets missed.
2969
3119
  */
2970
- var FormEngine = function (props) { return ((0, jsx_runtime_1.jsx)(markdownRendererContext_1.MarkdownRendererContext.Provider, { value: props.markdownRenderer, children: (0, jsx_runtime_1.jsx)(FormEngineImpl, __assign({}, props)) })); };
3120
+ var FormEngine = function (props) {
3121
+ var _a;
3122
+ // The form's own `appearance` wins; without one it follows the form (or the
3123
+ // host's provider) it sits in, so a nested sub-form never changes look
3124
+ // halfway down its parent.
3125
+ var inherited = (0, formAppearance_1.useFormAppearance)();
3126
+ var appearance = (_a = props.appearance) !== null && _a !== void 0 ? _a : inherited;
3127
+ return ((0, jsx_runtime_1.jsx)(markdownRendererContext_1.MarkdownRendererContext.Provider, { value: props.markdownRenderer, children: (0, jsx_runtime_1.jsx)(formAppearance_1.FormAppearanceProvider, { value: appearance, children: (0, jsx_runtime_1.jsx)(FormEngineImpl, __assign({}, props)) }) }));
3128
+ };
2971
3129
  exports.FormEngine = FormEngine;
2972
3130
  exports.default = exports.FormEngine;
2973
3131
  var templateObject_1, templateObject_2, templateObject_3, templateObject_4;