@qoretechnologies/reqraft 0.10.25 → 0.10.26

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 (310) hide show
  1. package/.claude/CLAUDE.md +52 -23
  2. package/design/COMPACT_ENGINE_REDESIGN.md +156 -0
  3. package/design/FORM_ENGINE_COMPACT_UX_PLAN.md +353 -0
  4. package/dist/components/FocusedEditing/index.d.ts +9 -1
  5. package/dist/components/FocusedEditing/index.d.ts.map +1 -1
  6. package/dist/components/FocusedEditing/index.js +2 -2
  7. package/dist/components/FocusedEditing/index.js.map +1 -1
  8. package/dist/components/composer/Composer.d.ts +108 -0
  9. package/dist/components/composer/Composer.d.ts.map +1 -0
  10. package/dist/components/composer/Composer.js +238 -0
  11. package/dist/components/composer/Composer.js.map +1 -0
  12. package/dist/components/composer/helpers.d.ts +21 -0
  13. package/dist/components/composer/helpers.d.ts.map +1 -0
  14. package/dist/components/composer/helpers.js +75 -0
  15. package/dist/components/composer/helpers.js.map +1 -0
  16. package/dist/components/composer/index.d.ts +3 -0
  17. package/dist/components/composer/index.d.ts.map +1 -0
  18. package/dist/components/composer/index.js +19 -0
  19. package/dist/components/composer/index.js.map +1 -0
  20. package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
  21. package/dist/components/form/engine/CompactRow.js +307 -110
  22. package/dist/components/form/engine/CompactRow.js.map +1 -1
  23. package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
  24. package/dist/components/form/engine/CompactToolbar.js +123 -106
  25. package/dist/components/form/engine/CompactToolbar.js.map +1 -1
  26. package/dist/components/form/engine/FormEngine.d.ts +107 -11
  27. package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
  28. package/dist/components/form/engine/FormEngine.js +618 -179
  29. package/dist/components/form/engine/FormEngine.js.map +1 -1
  30. package/dist/components/form/engine/compactRowContext.d.ts +9 -0
  31. package/dist/components/form/engine/compactRowContext.d.ts.map +1 -1
  32. package/dist/components/form/engine/compactRowContext.js.map +1 -1
  33. package/dist/components/form/engine/compactRowStyles.d.ts +7 -3
  34. package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
  35. package/dist/components/form/engine/compactRowStyles.js +88 -51
  36. package/dist/components/form/engine/compactRowStyles.js.map +1 -1
  37. package/dist/components/form/engine/compactToolbarContext.d.ts +1 -0
  38. package/dist/components/form/engine/compactToolbarContext.d.ts.map +1 -1
  39. package/dist/components/form/engine/compactToolbarContext.js.map +1 -1
  40. package/dist/components/form/engine/optionActions.d.ts +28 -0
  41. package/dist/components/form/engine/optionActions.d.ts.map +1 -0
  42. package/dist/components/form/engine/optionActions.js +18 -0
  43. package/dist/components/form/engine/optionActions.js.map +1 -0
  44. package/dist/components/form/engine/readFirst.d.ts +63 -2
  45. package/dist/components/form/engine/readFirst.d.ts.map +1 -1
  46. package/dist/components/form/engine/readFirst.js +121 -6
  47. package/dist/components/form/engine/readFirst.js.map +1 -1
  48. package/dist/components/form/engine/rendererTypes.d.ts +35 -0
  49. package/dist/components/form/engine/rendererTypes.d.ts.map +1 -0
  50. package/dist/components/form/engine/rendererTypes.js +63 -0
  51. package/dist/components/form/engine/rendererTypes.js.map +1 -0
  52. package/dist/components/form/engine/variants/VariantCalmTable.d.ts +6 -0
  53. package/dist/components/form/engine/variants/VariantCalmTable.d.ts.map +1 -0
  54. package/dist/components/form/engine/variants/VariantCalmTable.js +94 -0
  55. package/dist/components/form/engine/variants/VariantCalmTable.js.map +1 -0
  56. package/dist/components/form/engine/variants/VariantCards.d.ts +6 -0
  57. package/dist/components/form/engine/variants/VariantCards.d.ts.map +1 -0
  58. package/dist/components/form/engine/variants/VariantCards.js +80 -0
  59. package/dist/components/form/engine/variants/VariantCards.js.map +1 -0
  60. package/dist/components/form/engine/variants/VariantFocus.d.ts +7 -0
  61. package/dist/components/form/engine/variants/VariantFocus.d.ts.map +1 -0
  62. package/dist/components/form/engine/variants/VariantFocus.js +138 -0
  63. package/dist/components/form/engine/variants/VariantFocus.js.map +1 -0
  64. package/dist/components/form/engine/variants/VariantMinimal.d.ts +6 -0
  65. package/dist/components/form/engine/variants/VariantMinimal.d.ts.map +1 -0
  66. package/dist/components/form/engine/variants/VariantMinimal.js +73 -0
  67. package/dist/components/form/engine/variants/VariantMinimal.js.map +1 -0
  68. package/dist/components/form/engine/variants/focusDemo.d.ts +13 -0
  69. package/dist/components/form/engine/variants/focusDemo.d.ts.map +1 -0
  70. package/dist/components/form/engine/variants/focusDemo.js +139 -0
  71. package/dist/components/form/engine/variants/focusDemo.js.map +1 -0
  72. package/dist/components/form/engine/variants/variantModel.d.ts +70 -0
  73. package/dist/components/form/engine/variants/variantModel.d.ts.map +1 -0
  74. package/dist/components/form/engine/variants/variantModel.js +133 -0
  75. package/dist/components/form/engine/variants/variantModel.js.map +1 -0
  76. package/dist/components/form/engine/variants/variantParts.d.ts +79 -0
  77. package/dist/components/form/engine/variants/variantParts.d.ts.map +1 -0
  78. package/dist/components/form/engine/variants/variantParts.js +191 -0
  79. package/dist/components/form/engine/variants/variantParts.js.map +1 -0
  80. package/dist/components/form/expressions/builder/index.d.ts.map +1 -1
  81. package/dist/components/form/expressions/builder/index.js +13 -2
  82. package/dist/components/form/expressions/builder/index.js.map +1 -1
  83. package/dist/components/form/expressions/useExpressions.d.ts.map +1 -1
  84. package/dist/components/form/expressions/useExpressions.js +4 -1
  85. package/dist/components/form/expressions/useExpressions.js.map +1 -1
  86. package/dist/components/form/fields/Field.d.ts.map +1 -1
  87. package/dist/components/form/fields/Field.js +5 -3
  88. package/dist/components/form/fields/Field.js.map +1 -1
  89. package/dist/components/form/fields/allowed-values/AllowedValues.d.ts +2 -1
  90. package/dist/components/form/fields/allowed-values/AllowedValues.d.ts.map +1 -1
  91. package/dist/components/form/fields/allowed-values/AllowedValues.js +8 -26
  92. package/dist/components/form/fields/allowed-values/AllowedValues.js.map +1 -1
  93. package/dist/components/form/fields/auto/AutoFormField.d.ts +3 -0
  94. package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
  95. package/dist/components/form/fields/auto/AutoFormField.js +42 -8
  96. package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
  97. package/dist/components/form/fields/binary/Binary.d.ts +15 -0
  98. package/dist/components/form/fields/binary/Binary.d.ts.map +1 -0
  99. package/dist/components/form/fields/binary/Binary.js +74 -0
  100. package/dist/components/form/fields/binary/Binary.js.map +1 -0
  101. package/dist/components/form/fields/boolean/Boolean.js +1 -1
  102. package/dist/components/form/fields/boolean/Boolean.js.map +1 -1
  103. package/dist/components/form/fields/multi-select/MultiSelectFormField.d.ts.map +1 -1
  104. package/dist/components/form/fields/multi-select/MultiSelectFormField.js +5 -4
  105. package/dist/components/form/fields/multi-select/MultiSelectFormField.js.map +1 -1
  106. package/dist/components/form/fields/select/Select.d.ts.map +1 -1
  107. package/dist/components/form/fields/select/Select.js +29 -12
  108. package/dist/components/form/fields/select/Select.js.map +1 -1
  109. package/dist/components/form/fields/select/SelectCollection.d.ts +8 -2
  110. package/dist/components/form/fields/select/SelectCollection.d.ts.map +1 -1
  111. package/dist/components/form/fields/select/SelectCollection.js +52 -16
  112. package/dist/components/form/fields/select/SelectCollection.js.map +1 -1
  113. package/dist/components/form/index.d.ts +2 -0
  114. package/dist/components/form/index.d.ts.map +1 -1
  115. package/dist/components/form/index.js +2 -0
  116. package/dist/components/form/index.js.map +1 -1
  117. package/dist/components/imageLightbox/ImageLightbox.d.ts +21 -0
  118. package/dist/components/imageLightbox/ImageLightbox.d.ts.map +1 -0
  119. package/dist/components/imageLightbox/ImageLightbox.js +169 -0
  120. package/dist/components/imageLightbox/ImageLightbox.js.map +1 -0
  121. package/dist/components/imageLightbox/index.d.ts +2 -0
  122. package/dist/components/imageLightbox/index.d.ts.map +1 -0
  123. package/dist/components/imageLightbox/index.js +18 -0
  124. package/dist/components/imageLightbox/index.js.map +1 -0
  125. package/dist/components/searchFilterBar/SearchFilterBar.d.ts +33 -0
  126. package/dist/components/searchFilterBar/SearchFilterBar.d.ts.map +1 -0
  127. package/dist/components/searchFilterBar/SearchFilterBar.js +76 -0
  128. package/dist/components/searchFilterBar/SearchFilterBar.js.map +1 -0
  129. package/dist/components/searchFilterBar/index.d.ts +2 -0
  130. package/dist/components/searchFilterBar/index.d.ts.map +1 -0
  131. package/dist/components/searchFilterBar/index.js +18 -0
  132. package/dist/components/searchFilterBar/index.js.map +1 -0
  133. package/dist/components/supportTicket/AttachmentChips.d.ts +10 -0
  134. package/dist/components/supportTicket/AttachmentChips.d.ts.map +1 -0
  135. package/dist/components/supportTicket/AttachmentChips.js +122 -0
  136. package/dist/components/supportTicket/AttachmentChips.js.map +1 -0
  137. package/dist/components/supportTicket/InterfaceReferenceTags.d.ts +43 -0
  138. package/dist/components/supportTicket/InterfaceReferenceTags.d.ts.map +1 -0
  139. package/dist/components/supportTicket/InterfaceReferenceTags.js +31 -0
  140. package/dist/components/supportTicket/InterfaceReferenceTags.js.map +1 -0
  141. package/dist/components/supportTicket/ReferencePicker.d.ts +87 -0
  142. package/dist/components/supportTicket/ReferencePicker.d.ts.map +1 -0
  143. package/dist/components/supportTicket/ReferencePicker.js +295 -0
  144. package/dist/components/supportTicket/ReferencePicker.js.map +1 -0
  145. package/dist/components/supportTicket/TicketHeader.d.ts +86 -0
  146. package/dist/components/supportTicket/TicketHeader.d.ts.map +1 -0
  147. package/dist/components/supportTicket/TicketHeader.js +149 -0
  148. package/dist/components/supportTicket/TicketHeader.js.map +1 -0
  149. package/dist/components/supportTicket/TicketMetaTags.d.ts +32 -0
  150. package/dist/components/supportTicket/TicketMetaTags.d.ts.map +1 -0
  151. package/dist/components/supportTicket/TicketMetaTags.js +21 -0
  152. package/dist/components/supportTicket/TicketMetaTags.js.map +1 -0
  153. package/dist/components/supportTicket/TicketReplyBox.d.ts +63 -0
  154. package/dist/components/supportTicket/TicketReplyBox.d.ts.map +1 -0
  155. package/dist/components/supportTicket/TicketReplyBox.js +115 -0
  156. package/dist/components/supportTicket/TicketReplyBox.js.map +1 -0
  157. package/dist/components/supportTicket/attachmentAccess.d.ts +37 -0
  158. package/dist/components/supportTicket/attachmentAccess.d.ts.map +1 -0
  159. package/dist/components/supportTicket/attachmentAccess.js +132 -0
  160. package/dist/components/supportTicket/attachmentAccess.js.map +1 -0
  161. package/dist/components/supportTicket/fileToAttachment.d.ts +9 -0
  162. package/dist/components/supportTicket/fileToAttachment.d.ts.map +1 -0
  163. package/dist/components/supportTicket/fileToAttachment.js +28 -0
  164. package/dist/components/supportTicket/fileToAttachment.js.map +1 -0
  165. package/dist/components/supportTicket/index.d.ts +11 -0
  166. package/dist/components/supportTicket/index.d.ts.map +1 -0
  167. package/dist/components/supportTicket/index.js +27 -0
  168. package/dist/components/supportTicket/index.js.map +1 -0
  169. package/dist/components/supportTicket/meta.d.ts +71 -0
  170. package/dist/components/supportTicket/meta.d.ts.map +1 -0
  171. package/dist/components/supportTicket/meta.js +115 -0
  172. package/dist/components/supportTicket/meta.js.map +1 -0
  173. package/dist/components/supportTicket/ticketModel.d.ts +102 -0
  174. package/dist/components/supportTicket/ticketModel.d.ts.map +1 -0
  175. package/dist/components/supportTicket/ticketModel.js +3 -0
  176. package/dist/components/supportTicket/ticketModel.js.map +1 -0
  177. package/dist/components/ticketReferences/TicketReferences.d.ts +52 -0
  178. package/dist/components/ticketReferences/TicketReferences.d.ts.map +1 -0
  179. package/dist/components/ticketReferences/TicketReferences.js +492 -0
  180. package/dist/components/ticketReferences/TicketReferences.js.map +1 -0
  181. package/dist/components/ticketReferences/index.d.ts +3 -0
  182. package/dist/components/ticketReferences/index.d.ts.map +1 -0
  183. package/dist/components/ticketReferences/index.js +6 -0
  184. package/dist/components/ticketReferences/index.js.map +1 -0
  185. package/dist/components/ticketThread/TicketThread.d.ts +57 -0
  186. package/dist/components/ticketThread/TicketThread.d.ts.map +1 -0
  187. package/dist/components/ticketThread/TicketThread.js +299 -0
  188. package/dist/components/ticketThread/TicketThread.js.map +1 -0
  189. package/dist/components/ticketThread/index.d.ts +3 -0
  190. package/dist/components/ticketThread/index.d.ts.map +1 -0
  191. package/dist/components/ticketThread/index.js +7 -0
  192. package/dist/components/ticketThread/index.js.map +1 -0
  193. package/dist/helpers/common.d.ts +5 -0
  194. package/dist/helpers/common.d.ts.map +1 -1
  195. package/dist/helpers/common.js +20 -1
  196. package/dist/helpers/common.js.map +1 -1
  197. package/dist/helpers/scrollbar.d.ts +2 -0
  198. package/dist/helpers/scrollbar.d.ts.map +1 -0
  199. package/dist/helpers/scrollbar.js +25 -0
  200. package/dist/helpers/scrollbar.js.map +1 -0
  201. package/dist/index.d.ts +8 -1
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +10 -1
  204. package/dist/index.js.map +1 -1
  205. package/dist/providers/StorageProvider.d.ts +13 -0
  206. package/dist/providers/StorageProvider.d.ts.map +1 -1
  207. package/dist/providers/StorageProvider.js +29 -5
  208. package/dist/providers/StorageProvider.js.map +1 -1
  209. package/package.json +6 -5
  210. package/src/components/FocusedEditing/index.tsx +17 -2
  211. package/src/components/composer/Composer.stories.tsx +238 -0
  212. package/src/components/composer/Composer.tsx +545 -0
  213. package/src/components/composer/helpers.ts +74 -0
  214. package/src/components/composer/index.ts +2 -0
  215. package/src/components/dpqlEditor/DpqlEditor.stories.tsx +74 -2
  216. package/src/components/form/engine/CompactRow.tsx +561 -283
  217. package/src/components/form/engine/CompactToolbar.tsx +216 -182
  218. package/src/components/form/engine/FormEngine.stories.tsx +1736 -162
  219. package/src/components/form/engine/FormEngine.tsx +886 -170
  220. package/src/components/form/engine/FormEngineRemote.stories.tsx +377 -0
  221. package/src/components/form/engine/_structuredData/StructuredDataView.stories.tsx +8 -0
  222. package/src/components/form/engine/compactRowContext.ts +14 -0
  223. package/src/components/form/engine/compactRowStyles.ts +273 -146
  224. package/src/components/form/engine/compactToolbarContext.ts +1 -0
  225. package/src/components/form/engine/optionActions.ts +40 -0
  226. package/src/components/form/engine/readFirst.ts +169 -10
  227. package/src/components/form/engine/rendererTypes.ts +55 -0
  228. package/src/components/form/engine/variants/FormEngineVariants.stories.tsx +159 -0
  229. package/src/components/form/engine/variants/VariantCalmTable.tsx +242 -0
  230. package/src/components/form/engine/variants/VariantCards.tsx +212 -0
  231. package/src/components/form/engine/variants/VariantFocus.tsx +382 -0
  232. package/src/components/form/engine/variants/VariantMinimal.tsx +170 -0
  233. package/src/components/form/engine/variants/focusDemo.ts +145 -0
  234. package/src/components/form/engine/variants/variantModel.ts +216 -0
  235. package/src/components/form/engine/variants/variantParts.tsx +313 -0
  236. package/src/components/form/expressions/ExpressionField.stories.tsx +84 -2
  237. package/src/components/form/expressions/builder/ExpressionBuilder.stories.tsx +213 -19
  238. package/src/components/form/expressions/builder/index.tsx +12 -1
  239. package/src/components/form/expressions/useExpressions.ts +4 -1
  240. package/src/components/form/fields/Field.stories.tsx +40 -0
  241. package/src/components/form/fields/Field.tsx +10 -1
  242. package/src/components/form/fields/allowed-values/AllowedValues.tsx +13 -36
  243. package/src/components/form/fields/array/ArrayAutoField.stories.tsx +64 -0
  244. package/src/components/form/fields/auto/AutoFormField.stories.tsx +146 -2
  245. package/src/components/form/fields/auto/AutoFormField.tsx +42 -1
  246. package/src/components/form/fields/binary/Binary.stories.tsx +122 -0
  247. package/src/components/form/fields/binary/Binary.tsx +81 -0
  248. package/src/components/form/fields/boolean/Boolean.stories.tsx +58 -0
  249. package/src/components/form/fields/boolean/Boolean.tsx +1 -1
  250. package/src/components/form/fields/byte-size/ByteSize.stories.tsx +24 -0
  251. package/src/components/form/fields/color/Color.stories.tsx +30 -0
  252. package/src/components/form/fields/cron/Cron.stories.tsx +8 -0
  253. package/src/components/form/fields/date/Date.stories.tsx +22 -0
  254. package/src/components/form/fields/file/File.stories.tsx +48 -0
  255. package/src/components/form/fields/long-string/LongString.stories.tsx +24 -0
  256. package/src/components/form/fields/markdown/Markdown.stories.tsx +8 -0
  257. package/src/components/form/fields/multi-select/MultiSelectFormField.tsx +14 -10
  258. package/src/components/form/fields/number/Number.stories.tsx +31 -0
  259. package/src/components/form/fields/object/Object.stories.tsx +88 -0
  260. package/src/components/form/fields/radio-group/RadioGroup.stories.tsx +24 -0
  261. package/src/components/form/fields/rich-text/RichText.stories.tsx +23 -0
  262. package/src/components/form/fields/schema-definition/SchemaDefinitionField.stories.tsx +72 -0
  263. package/src/components/form/fields/select/Select.stories.tsx +108 -0
  264. package/src/components/form/fields/select/Select.tsx +38 -12
  265. package/src/components/form/fields/select/SelectCollection.tsx +78 -17
  266. package/src/components/form/fields/string/String.stories.tsx +16 -0
  267. package/src/components/form/fields/template/TemplateField.stories.tsx +160 -0
  268. package/src/components/form/fields/url/Url.stories.tsx +24 -0
  269. package/src/components/form/index.tsx +2 -0
  270. package/src/components/imageLightbox/ImageLightbox.stories.tsx +238 -0
  271. package/src/components/imageLightbox/ImageLightbox.tsx +236 -0
  272. package/src/components/imageLightbox/index.ts +1 -0
  273. package/src/components/log/Log.stories.tsx +96 -0
  274. package/src/components/menu/Menu.stories.tsx +54 -0
  275. package/src/components/qonsoleSmartInput/QonsoleSmartInput.stories.tsx +83 -37
  276. package/src/components/searchFilterBar/SearchFilterBar.tsx +131 -0
  277. package/src/components/searchFilterBar/index.ts +1 -0
  278. package/src/components/smartEditor/SmartEditor.stories.tsx +32 -0
  279. package/src/components/supportTicket/AttachmentChips.stories.tsx +171 -0
  280. package/src/components/supportTicket/AttachmentChips.tsx +147 -0
  281. package/src/components/supportTicket/InterfaceReferenceTags.stories.tsx +171 -0
  282. package/src/components/supportTicket/InterfaceReferenceTags.tsx +96 -0
  283. package/src/components/supportTicket/ReferencePicker.stories.tsx +519 -0
  284. package/src/components/supportTicket/ReferencePicker.tsx +563 -0
  285. package/src/components/supportTicket/TicketConversation.stories.tsx +121 -0
  286. package/src/components/supportTicket/TicketHeader.stories.tsx +183 -0
  287. package/src/components/supportTicket/TicketHeader.tsx +247 -0
  288. package/src/components/supportTicket/TicketMetaTags.stories.tsx +103 -0
  289. package/src/components/supportTicket/TicketMetaTags.tsx +85 -0
  290. package/src/components/supportTicket/TicketReplyBox.stories.tsx +351 -0
  291. package/src/components/supportTicket/TicketReplyBox.tsx +146 -0
  292. package/src/components/supportTicket/attachmentAccess.ts +97 -0
  293. package/src/components/supportTicket/fileToAttachment.ts +24 -0
  294. package/src/components/supportTicket/index.ts +10 -0
  295. package/src/components/supportTicket/meta.ts +185 -0
  296. package/src/components/supportTicket/ticketModel.ts +131 -0
  297. package/src/components/ticketReferences/TicketReferences.stories.tsx +315 -0
  298. package/src/components/ticketReferences/TicketReferences.tsx +886 -0
  299. package/src/components/ticketReferences/index.ts +2 -0
  300. package/src/components/ticketThread/TicketThread.stories.tsx +828 -0
  301. package/src/components/ticketThread/TicketThread.tsx +704 -0
  302. package/src/components/ticketThread/index.ts +6 -0
  303. package/src/helpers/common.ts +19 -0
  304. package/src/helpers/scrollbar.ts +32 -0
  305. package/src/hooks/useFetch/useFetch.stories.tsx +30 -0
  306. package/src/hooks/useStorage/useStorage.stories.tsx +82 -0
  307. package/src/hooks/useWebSocket/useWebsocket.stories.tsx +127 -1
  308. package/src/index.tsx +8 -1
  309. package/src/providers/StorageProvider.tsx +30 -4
  310. package/src/stores/currentUser/currentUser.stories.tsx +49 -0
@@ -102,6 +102,8 @@ var react_1 = require("react");
102
102
  var jsx_runtime_1 = require("react/jsx-runtime");
103
103
  var reqore_1 = require("@qoretechnologies/reqore");
104
104
  var colors_1 = require("@qoretechnologies/reqore/dist/helpers/colors");
105
+ var optionActions_1 = require("./optionActions");
106
+ var rendererTypes_1 = require("./rendererTypes");
105
107
  var lodash_1 = require("lodash");
106
108
  var isArray_1 = __importDefault(require("lodash/isArray"));
107
109
  var map_1 = __importDefault(require("lodash/map"));
@@ -109,26 +111,64 @@ var reduce_1 = __importDefault(require("lodash/reduce"));
109
111
  var size_1 = __importDefault(require("lodash/size"));
110
112
  var react_2 = __importStar(require("react"));
111
113
  var react_use_1 = require("react-use");
112
- var use_context_selector_1 = require("use-context-selector");
113
114
  var styled_components_1 = __importDefault(require("styled-components"));
115
+ var use_context_selector_1 = require("use-context-selector");
114
116
  var common_1 = require("../../../helpers/common");
115
117
  var options_1 = require("../../../helpers/options");
116
- var fetch_1 = require("../../../utils/fetch");
117
118
  var validations_1 = require("../../../helpers/validations");
118
119
  var useQorusTypes_1 = require("../../../hooks/useQorusTypes");
119
120
  var useTemplates_1 = require("../../../hooks/useTemplates");
121
+ var fetch_1 = require("../../../utils/fetch");
120
122
  var Description_1 = require("../../Description");
121
123
  var FocusedEditing_1 = require("../../FocusedEditing");
122
124
  var Select_1 = require("../fields/select/Select");
123
125
  var TemplateField_1 = require("../fields/template/TemplateField");
124
126
  var CompactRow_1 = require("./CompactRow");
125
127
  var compactRowContext_1 = require("./compactRowContext");
128
+ var compactRowStyles_1 = require("./compactRowStyles");
126
129
  var CompactToolbar_1 = require("./CompactToolbar");
127
130
  var compactToolbarContext_1 = require("./compactToolbarContext");
128
- var compactRowStyles_1 = require("./compactRowStyles");
129
131
  var OptionFieldMessages_1 = require("./OptionFieldMessages");
130
132
  var OptionsHelpDialog_1 = require("./OptionsHelpDialog");
131
133
  var readFirst_1 = require("./readFirst");
134
+ /**
135
+ * Resolve a field's `inherit_props` map against the current available
136
+ * options (plus any values inherited from an outer FormEngine scope),
137
+ * producing a `{ propName: siblingValue }` hash suitable for spreading
138
+ * onto the field's renderer.
139
+ *
140
+ * For each entry `<prop-name-on-renderer> -> <sibling-field-name>`, the
141
+ * sibling's current value is forwarded under the receiving prop name.
142
+ * Lookup order:
143
+ * 1. `availableOptions[siblingName]?.value` — the field's local scope.
144
+ * 2. `inheritedFromParent[siblingName]` — the bag threaded in by an
145
+ * outer FormEngine (see the `inheritedFromParent` prop). Used when
146
+ * a composite field's `arg_schema` sub-form needs to reach a value
147
+ * on an ancestor scope — e.g. a service-method row's `body` picking
148
+ * up `language` from the parent service form.
149
+ * Missing siblings emit `undefined`, which the renderer's prop type can
150
+ * treat as "no hint".
151
+ *
152
+ * Designed to be JSON-pure: no closures, no transformations. Renderers
153
+ * decide how to use the forwarded value (e.g. the consumer-injected
154
+ * `code-editor` renderer maps a `language: "qore"` prop to its
155
+ * highlighter mode).
156
+ *
157
+ * Mirrored in qorus-ide `src/components/Field/systemOptions.tsx`; keep
158
+ * the two in sync (see qorus-ide's `.claude/CLAUDE.md`).
159
+ */
160
+ var resolveInheritProps = function (inheritProps, availableOptions, inheritedFromParent) {
161
+ var _a;
162
+ if (!inheritProps)
163
+ return {};
164
+ var out = {};
165
+ for (var propName in inheritProps) {
166
+ var siblingName = inheritProps[propName];
167
+ var localValue = (_a = availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[siblingName]) === null || _a === void 0 ? void 0 : _a.value;
168
+ out[propName] = localValue !== undefined ? localValue : inheritedFromParent === null || inheritedFromParent === void 0 ? void 0 : inheritedFromParent[siblingName];
169
+ }
170
+ return out;
171
+ };
132
172
  var NegativeColorEffect = {
133
173
  gradient: {
134
174
  colors: { 0: 'danger', 100: 'danger:darken:2' },
@@ -145,10 +185,7 @@ var PositiveColorEffect = {
145
185
  };
146
186
  // Compact (read-first) layout: flat label | value | action rows in collapsible
147
187
  // group panels; colours come in as props so the layout follows the Reqore theme.
148
- var StyledCompactWrap = styled_components_1.default.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n display: flex;\n flex-flow: column;\n gap: 10px;\n width: 100%;\n /* Allow the wrap to shrink inside flex/grid parents so its rows' ellipsis can\n engage instead of overflowing the container horizontally. */\n min-width: 0;\n max-width: 100%;\n /* A bit of horizontal breathing room for the whole form (header + content\n alike). Horizontal only \u2014 top padding would break the sticky toolbar's\n flush pin (see the scroll-context note below). Dropped to flush via the\n compactFlush prop, for embeds that own their own gutters (e.g. the\n SchemaDefinition tab body). */\n padding: ", ";\n\n /* Own our scroll context instead of borrowing the host's. The sticky toolbar\n pins to whatever scrolls; if that scroller carries top padding (e.g. a\n ReqorePanel/ReqoreContent body), sticky `top: 0` resolves against its\n padding box and leaves an unblurred strip above the toolbar. By scrolling\n here \u2014 an UNPADDED box \u2014 the toolbar always pins flush and content ghosts\n cleanly beneath it, regardless of host padding (mirrors how the IDE\n dashboard keeps its StyledScrollBody scroller unpadded).\n We cap at the host's available height and scroll past it, but do NOT grow\n to fill it \u2014 short forms still hug their content. When the host height is\n indefinite, `max-height: 100%` resolves to none and the box grows so the\n host scrolls as before (graceful fallback). */\n min-height: 0;\n max-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n\n /* Option logos (e.g. language images) render as <img> inside ReqoreIcon's\n square box; constrain them so portrait PNGs don't overflow the row. */\n .reqore-icon img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n"], ["\n display: flex;\n flex-flow: column;\n gap: 10px;\n width: 100%;\n /* Allow the wrap to shrink inside flex/grid parents so its rows' ellipsis can\n engage instead of overflowing the container horizontally. */\n min-width: 0;\n max-width: 100%;\n /* A bit of horizontal breathing room for the whole form (header + content\n alike). Horizontal only \u2014 top padding would break the sticky toolbar's\n flush pin (see the scroll-context note below). Dropped to flush via the\n compactFlush prop, for embeds that own their own gutters (e.g. the\n SchemaDefinition tab body). */\n padding: ", ";\n\n /* Own our scroll context instead of borrowing the host's. The sticky toolbar\n pins to whatever scrolls; if that scroller carries top padding (e.g. a\n ReqorePanel/ReqoreContent body), sticky \\`top: 0\\` resolves against its\n padding box and leaves an unblurred strip above the toolbar. By scrolling\n here \u2014 an UNPADDED box \u2014 the toolbar always pins flush and content ghosts\n cleanly beneath it, regardless of host padding (mirrors how the IDE\n dashboard keeps its StyledScrollBody scroller unpadded).\n We cap at the host's available height and scroll past it, but do NOT grow\n to fill it \u2014 short forms still hug their content. When the host height is\n indefinite, \\`max-height: 100%\\` resolves to none and the box grows so the\n host scrolls as before (graceful fallback). */\n min-height: 0;\n max-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n\n /* Option logos (e.g. language images) render as <img> inside ReqoreIcon's\n square box; constrain them so portrait PNGs don't overflow the row. */\n .reqore-icon img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n"])), function (_a) {
149
- var $flush = _a.$flush;
150
- return ($flush ? '0' : '0 12px');
151
- });
188
+ var StyledCompactWrap = styled_components_1.default.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n display: flex;\n flex-flow: column;\n gap: 10px;\n width: 100%;\n /* Allow the wrap to shrink inside flex/grid parents so its rows' ellipsis can\n engage instead of overflowing the container horizontally. */\n min-width: 0;\n max-width: 100%;\n /* Own our scroll context instead of borrowing the host's. The sticky toolbar\n pins to whatever scrolls; if that scroller carries top padding (e.g. a\n ReqorePanel/ReqoreContent body), sticky `top: 0` resolves against its\n padding box and leaves an unblurred strip above the toolbar. By scrolling\n here \u2014 an UNPADDED box \u2014 the toolbar always pins flush and content ghosts\n cleanly beneath it, regardless of host padding (mirrors how the IDE\n dashboard keeps its StyledScrollBody scroller unpadded).\n We cap at the host's available height and scroll past it, but do NOT grow\n to fill it \u2014 short forms still hug their content. When the host height is\n indefinite, `max-height: 100%` resolves to none and the box grows so the\n host scrolls as before (graceful fallback). */\n min-height: 0;\n max-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n\n /* Option logos (e.g. language images) render as <img> inside ReqoreIcon's\n square box; constrain them so portrait PNGs don't overflow the row. */\n .reqore-icon img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n"], ["\n display: flex;\n flex-flow: column;\n gap: 10px;\n width: 100%;\n /* Allow the wrap to shrink inside flex/grid parents so its rows' ellipsis can\n engage instead of overflowing the container horizontally. */\n min-width: 0;\n max-width: 100%;\n /* Own our scroll context instead of borrowing the host's. The sticky toolbar\n pins to whatever scrolls; if that scroller carries top padding (e.g. a\n ReqorePanel/ReqoreContent body), sticky \\`top: 0\\` resolves against its\n padding box and leaves an unblurred strip above the toolbar. By scrolling\n here \u2014 an UNPADDED box \u2014 the toolbar always pins flush and content ghosts\n cleanly beneath it, regardless of host padding (mirrors how the IDE\n dashboard keeps its StyledScrollBody scroller unpadded).\n We cap at the host's available height and scroll past it, but do NOT grow\n to fill it \u2014 short forms still hug their content. When the host height is\n indefinite, \\`max-height: 100%\\` resolves to none and the box grows so the\n host scrolls as before (graceful fallback). */\n min-height: 0;\n max-height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n\n /* Option logos (e.g. language images) render as <img> inside ReqoreIcon's\n square box; constrain them so portrait PNGs don't overflow the row. */\n .reqore-icon img {\n width: 100%;\n height: 100%;\n object-fit: contain;\n }\n"])));
152
189
  // Batched-commit dock: a floating Save/Discard card pinned bottom-right. Sticky
153
190
  // (not fixed) so it stays within the form's own scroll bounds when the engine
154
191
  // renders inside a drawer/panel; align-self pushes it to the right edge, and it
@@ -165,7 +202,10 @@ var StyledCommitDock = styled_components_1.default.div(templateObject_2 || (temp
165
202
  });
166
203
  var getType = function (type, operators, operator) {
167
204
  var finalType = getTypeFromOperator(operators, (0, exports.fixOperatorValue)(operator)) || type;
168
- return ((0, isArray_1.default)(finalType) ? finalType[0] : finalType);
205
+ var resolvedType = (0, isArray_1.default)(finalType) ? finalType[0] : finalType;
206
+ // A value can be received before its server-driven option schema. Keep the
207
+ // renderer type-safe during that transition without guessing a concrete type.
208
+ return (resolvedType || 'any');
169
209
  };
170
210
  exports.getType = getType;
171
211
  var getTypeFromOperator = function (operators, operatorData) {
@@ -179,15 +219,38 @@ var fixOperatorValue = function (operator) {
179
219
  return (0, isArray_1.default)(operator) ? operator : [operator];
180
220
  };
181
221
  exports.fixOperatorValue = fixOperatorValue;
222
+ var getOptionSchemaStorageType = function (option, isRendererOnly) {
223
+ if (isRendererOnly === void 0) { isRendererOnly = rendererTypes_1.isRendererOnlyUiType; }
224
+ return (((0, readFirst_1.isFixedCompactAllowedValueOption)(option)
225
+ ? (option === null || option === void 0 ? void 0 : option.type) || (option === null || option === void 0 ? void 0 : option.ui_type)
226
+ : isRendererOnly(option === null || option === void 0 ? void 0 : option.ui_type)
227
+ ? (option === null || option === void 0 ? void 0 : option.type) || (option === null || option === void 0 ? void 0 : option.ui_type)
228
+ : (option === null || option === void 0 ? void 0 : option.ui_type) || (option === null || option === void 0 ? void 0 : option.type)) || 'any');
229
+ };
230
+ var getOptionFieldStorageType = function (optionName, fieldType, schema, operators, operatorData, isRendererOnly) {
231
+ if (isRendererOnly === void 0) { isRendererOnly = rendererTypes_1.isRendererOnlyUiType; }
232
+ var schemaOption = schema === null || schema === void 0 ? void 0 : schema[optionName];
233
+ var storedType = fieldType && !(fieldType === (schemaOption === null || schemaOption === void 0 ? void 0 : schemaOption.ui_type) && isRendererOnly(fieldType))
234
+ ? fieldType
235
+ : getOptionSchemaStorageType(schemaOption, isRendererOnly);
236
+ return (0, exports.getType)(storedType, operators, operatorData);
237
+ };
182
238
  var hasRequiredOptions = function (options) {
183
239
  if (options === void 0) { options = {}; }
184
240
  return !!(0, lodash_1.findKey)(options, function (option) { return option.required; });
185
241
  };
186
242
  exports.hasRequiredOptions = hasRequiredOptions;
187
243
  exports.OptionsContext = (0, use_context_selector_1.createContext)({});
188
- var fixOptions = function (value, options, operators) {
244
+ var fixOptions = function (value, options, operators, isRendererOnly) {
189
245
  if (value === void 0) { value = {}; }
246
+ if (isRendererOnly === void 0) { isRendererOnly = rendererTypes_1.isRendererOnlyUiType; }
190
247
  var fixedValue = (0, lodash_1.cloneDeep)(value);
248
+ // Server-driven schemas can arrive after the persisted value. Preserve that
249
+ // value verbatim until its schema is available instead of manufacturing
250
+ // partially typed form fields that can crash the following render.
251
+ if (!(0, size_1.default)(options)) {
252
+ return fixedValue;
253
+ }
191
254
  (0, lodash_1.forEach)(options, function (option, name) {
192
255
  var _a, _b, _c, _d, _f, _g, _h;
193
256
  if (option.value ||
@@ -195,7 +258,7 @@ var fixOptions = function (value, options, operators) {
195
258
  ((option.required || option.preselected) && !fixedValue[name]) ||
196
259
  ((option.required || option.preselected) && option.default_value && !option.value)) {
197
260
  var obj = void 0;
198
- var type = (0, exports.getType)((option.ui_type || option.type), operators, (_a = fixedValue[name]) === null || _a === void 0 ? void 0 : _a.op);
261
+ var type = (0, exports.getType)(getOptionSchemaStorageType(option, isRendererOnly), operators, (_a = fixedValue[name]) === null || _a === void 0 ? void 0 : _a.op);
199
262
  if (((_b = option.default_value) === null || _b === void 0 ? void 0 : _b.is_expression) &&
200
263
  ((_c = fixedValue[name]) === null || _c === void 0 ? void 0 : _c.value) === undefined) {
201
264
  obj = option.default_value;
@@ -216,29 +279,32 @@ var fixOptions = function (value, options, operators) {
216
279
  });
217
280
  var res = (0, reduce_1.default)(fixedValue, function (newValue, option, optionName) {
218
281
  var _a;
219
- var _b, _c, _d, _f, _g, _h, _j, _k, _l;
282
+ var _b, _c, _d, _f, _g, _h, _j, _k;
220
283
  var newOption = option;
221
284
  if (!(0, lodash_1.isPlainObject)(newOption) || !(newOption === null || newOption === void 0 ? void 0 : newOption.type)) {
222
- var fixedOption = {
223
- type: (0, exports.getType)((((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.ui_type) || ((_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.type)), operators, newOption === null || newOption === void 0 ? void 0 : newOption.op),
224
- value: newOption,
225
- };
226
- if (newOption === null || newOption === void 0 ? void 0 : newOption.is_expression) {
227
- fixedOption.is_expression = true;
228
- }
285
+ var isUntypedEnvelope = (0, lodash_1.isPlainObject)(newOption) && 'value' in newOption;
286
+ var untypedFieldValue = isUntypedEnvelope ? newOption.value : newOption;
287
+ // Spread the original envelope first so every key it carried survives —
288
+ // rebuilding from just {type, value} silently dropped `op`, `is_expression`
289
+ // and anything else a field needs to render, which emptied the card.
290
+ var fixedOption = __assign(__assign({}, ((0, lodash_1.isPlainObject)(newOption) ? newOption : {})), { type: (0, exports.getType)(getOptionSchemaStorageType(options === null || options === void 0 ? void 0 : options[optionName], isRendererOnly), operators, newOption === null || newOption === void 0 ? void 0 : newOption.op), value: untypedFieldValue });
229
291
  newOption = fixedOption;
230
292
  }
293
+ else if (newOption.type === ((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.ui_type) &&
294
+ isRendererOnly(newOption.type)) {
295
+ newOption = __assign(__assign({}, newOption), { type: (0, exports.getType)(getOptionSchemaStorageType(options === null || options === void 0 ? void 0 : options[optionName], isRendererOnly), operators, newOption.op) });
296
+ }
231
297
  if (newOption.value !== undefined &&
232
- ((_d = options === null || options === void 0 ? void 0 : options[optionName]) === null || _d === void 0 ? void 0 : _d.allowed_values) &&
233
- !((_g = (_f = options === null || options === void 0 ? void 0 : options[optionName]) === null || _f === void 0 ? void 0 : _f.allowed_values) === null || _g === void 0 ? void 0 : _g.find(function (allowedValue) { var _a; return ((_a = allowedValue.value) === null || _a === void 0 ? void 0 : _a.value) === newOption.value || allowedValue.name === newOption.value; })) &&
298
+ ((_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.allowed_values) &&
299
+ !((_f = (_d = options === null || options === void 0 ? void 0 : options[optionName]) === null || _d === void 0 ? void 0 : _d.allowed_values) === null || _f === void 0 ? void 0 : _f.find(function (allowedValue) { var _a; return ((_a = allowedValue.value) === null || _a === void 0 ? void 0 : _a.value) === newOption.value || allowedValue.name === newOption.value; })) &&
234
300
  !(0, TemplateField_1.isValueTemplate)(newOption.value) &&
235
- !((_h = options === null || options === void 0 ? void 0 : options[optionName]) === null || _h === void 0 ? void 0 : _h.multiselect) &&
236
- !((_j = options === null || options === void 0 ? void 0 : options[optionName]) === null || _j === void 0 ? void 0 : _j.allowed_values_creatable)) {
301
+ !((_g = options === null || options === void 0 ? void 0 : options[optionName]) === null || _g === void 0 ? void 0 : _g.multiselect) &&
302
+ !((_h = options === null || options === void 0 ? void 0 : options[optionName]) === null || _h === void 0 ? void 0 : _h.allowed_values_creatable)) {
237
303
  newOption.value = undefined;
238
304
  }
239
305
  if (newOption.value &&
240
- ((_k = options === null || options === void 0 ? void 0 : options[optionName]) === null || _k === void 0 ? void 0 : _k.readonly) &&
241
- ((_l = options === null || options === void 0 ? void 0 : options[optionName]) === null || _l === void 0 ? void 0 : _l.default_value) &&
306
+ ((_j = options === null || options === void 0 ? void 0 : options[optionName]) === null || _j === void 0 ? void 0 : _j.readonly) &&
307
+ ((_k = options === null || options === void 0 ? void 0 : options[optionName]) === null || _k === void 0 ? void 0 : _k.default_value) &&
242
308
  (0, common_1.getDefaultValue)(options === null || options === void 0 ? void 0 : options[optionName]) !== newOption.value) {
243
309
  newOption.value = (0, common_1.getDefaultValue)(options[optionName]);
244
310
  }
@@ -294,43 +360,64 @@ exports.getTypeAndCanBeNull = getTypeAndCanBeNull;
294
360
  // Option types rendered full-width (IDE Options parity, commit 8e6b7781).
295
361
  var STRECHABLE_TYPES = new Set(['tool-catalog']);
296
362
  var FormEngine = function (_a) {
297
- var _b, _c, _d, _f, _g;
363
+ var _b, _c, _d, _f, _g, _h;
298
364
  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
365
  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];
366
+ url = _a.url, customUrl = _a.customUrl, operatorsUrl = _a.operatorsUrl, onOptionsLoaded = _a.onOptionsLoaded, recordRequiresSearchOptions = _a.recordRequiresSearchOptions, readOnly = _a.readOnly, _j = _a.allowTemplates, allowTemplates = _j === void 0 ? true : _j, interfaceContext = _a.interfaceContext, templateFieldProps = _a.templateFieldProps, forceDropdown = _a.forceDropdown, _k = _a.showTypeToggle, showTypeToggle = _k === void 0 ? true : _k, compact = _a.compact, _l = _a.compactFlush, compactFlush = _l === void 0 ? false : _l, _m = _a.compactNested, compactNested = _m === void 0 ? false : _m, compactPanelProps = _a.compactPanelProps, _o = _a.commitMode, commitMode = _o === void 0 ? 'immediate' : _o, _p = _a.expandMode, expandMode = _p === void 0 ? 'single' : _p, onCommit = _a.onCommit, operatorsProp = _a.operators, groups = _a.groups, optionsLoader = _a.optionsLoader, onValidityChange = _a.onValidityChange, optionActions = _a.optionActions, _q = _a.optionActionsCollapse, optionActionsCollapse = _q === void 0 ? 'auto' : _q, componentOverrides = _a.componentOverrides, rendererOnlyUiTypes = _a.rendererOnlyUiTypes, inheritedFromParent = _a.inheritedFromParent, autoFocusFirstRequired = _a.autoFocusFirstRequired, initialExpandedOptions = _a.initialExpandedOptions, rest = __rest(_a, ["name", "uniqueName", "value", "onChange", "onSingleOptionsChange", "onDependableOptionChange", "placeholder", "noValueString", "isValid", "url", "customUrl", "operatorsUrl", "onOptionsLoaded", "recordRequiresSearchOptions", "readOnly", "allowTemplates", "interfaceContext", "templateFieldProps", "forceDropdown", "showTypeToggle", "compact", "compactFlush", "compactNested", "compactPanelProps", "commitMode", "expandMode", "onCommit", "operators", "groups", "optionsLoader", "onValidityChange", "optionActions", "optionActionsCollapse", "componentOverrides", "rendererOnlyUiTypes", "inheritedFromParent", "autoFocusFirstRequired", "initialExpandedOptions"]);
367
+ // Built-ins + whatever the consumer declared for its own injected editors.
368
+ var isRendererOnly = (0, react_2.useMemo)(function () { return (0, rendererTypes_1.createRendererOnlyUiTypeCheck)(rendererOnlyUiTypes); }, [JSON.stringify(rendererOnlyUiTypes)]);
369
+ // Pointer CAPABILITY and viewport WIDTH are different questions and both
370
+ // matter here: a hover-gated action is unreachable without a hover, and a
371
+ // phone-width row has no space for a button strip either way. Both now come
372
+ // from Reqore's context (one subscription for the whole app) rather than a
373
+ // reqraft-local matchMedia hook.
374
+ //
375
+ // `isHoverCapable` defaults to `true` in Reqore, but fall back explicitly so
376
+ // an older Reqore — where the property does not exist — degrades to "this
377
+ // pointer hovers" (the pre-existing behaviour) instead of collapsing every
378
+ // action into a menu for everyone.
379
+ var isHoverCapable = (_b = (0, reqore_1.useReqoreProperty)('isHoverCapable')) !== null && _b !== void 0 ? _b : true;
380
+ var isMobile = (0, reqore_1.useReqoreProperty)('isMobile');
381
+ var collapseOptionActions = optionActionsCollapse === 'always' ? true
382
+ : optionActionsCollapse === 'never' ? false
383
+ : !isHoverCapable || !!isMobile;
384
+ var _r = (0, react_2.useState)((rest === null || rest === void 0 ? void 0 : rest.options) || undefined), options = _r[0], setOptions = _r[1];
302
385
  // 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];
386
+ var _s = (0, react_2.useState)(!!optionsLoader && !(rest === null || rest === void 0 ? void 0 : rest.options)), optionsLoading = _s[0], setOptionsLoading = _s[1];
387
+ var _t = (0, react_2.useState)(), optionsError = _t[0], setOptionsError = _t[1];
305
388
  // Operators: prop-provided (compact) or fetched via operatorsUrl (dpql,
306
389
  // 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];
390
+ var _u = (0, react_2.useState)(operatorsProp), operators = _u[0], setOperators = _u[1];
308
391
  // Remote-fetch loading (ported from IDE Options); only relevant when one of
309
392
  // 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];
393
+ var _v = (0, react_2.useState)(!!(url || customUrl || operatorsUrl)), loading = _v[0], setLoading = _v[1];
311
394
  var confirmAction = (0, reqore_1.useReqoreProperty)('confirmAction');
312
395
  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];
396
+ var _w = (0, react_2.useState)(), focusedEditing = _w[0], setFocusedEditing = _w[1];
397
+ var _x = (0, react_2.useState)(false), showFieldTypes = _x[0], setShowFieldTypes = _x[1];
315
398
  // Global toggle (toolbar ⓘ): reveal the short-description info panel on every
316
399
  // field that has a short_desc. Per-row ⓘ overrides still win over it.
317
400
  // Global field-info visibility, tri-state: `undefined` = default (critical
318
401
  // messages auto-open, the rest closed); `true` = show all; `false` = hide all
319
402
  // (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];
403
+ var _y = (0, react_2.useState)(undefined), showAllDescriptions = _y[0], setShowAllDescriptions = _y[1];
404
+ var _z = (0, react_2.useState)(), showHelpForOption = _z[0], setShowHelpForOption = _z[1];
405
+ var _0 = (0, react_2.useState)(false), showInvalidOptionsOnly = _0[0], setShowInvalidOptionsOnly = _0[1];
323
406
  // 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];
407
+ var _1 = (0, react_2.useState)([]), expandedOptions = _1[0], setExpandedOptions = _1[1];
408
+ // Remembers each row's last settled status box, so an actively-edited field
409
+ // stays put when its status flips (e.g. becomes valid) instead of jumping to
410
+ // another box mid-edit and stealing focus. Keyed by option name.
411
+ var settledBucket = (0, react_2.useRef)({});
325
412
  // Measured form width (not viewport — the form lives in drawers/panels of
326
413
  // arbitrary width) drives the stacked narrow layout.
327
- var _z = (0, react_use_1.useMeasure)(), compactWrapRef = _z[0], compactWrapWidth = _z[1].width;
414
+ var _2 = (0, react_use_1.useMeasure)(), compactWrapRef = _2[0], compactWrapWidth = _2[1].width;
328
415
  // Own handle on the scroll wrap (useMeasure's ref is a callback, no `.current`)
329
416
  // so the label-column measurement can publish its CSS var on the element. It's
330
417
  // STATE, not a ref: the wrap mounts only after the loading-skeleton gate
331
418
  // resolves, so the measurement effect must re-run when the node appears — a
332
419
  // ref wouldn't retrigger it.
333
- var _0 = (0, react_2.useState)(null), compactWrapNode = _0[0], setCompactWrapNode = _0[1];
420
+ var _3 = (0, react_2.useState)(null), compactWrapNode = _3[0], setCompactWrapNode = _3[1];
334
421
  var setCompactWrap = (0, react_2.useCallback)(function (node) {
335
422
  compactWrapRef(node);
336
423
  setCompactWrapNode(function (prev) { return (prev === node ? prev : node); });
@@ -367,15 +454,22 @@ var FormEngine = function (_a) {
367
454
  var readRowHeights = (0, react_2.useRef)({});
368
455
  // Required-groups linkage: hovering a group chip highlights every member row;
369
456
  // clicking a sibling in the chip's popover scrolls to it and flashes it.
370
- var _1 = (0, react_2.useState)([]), highlightedOptions = _1[0], setHighlightedOptions = _1[1];
371
- var _2 = (0, react_2.useState)([]), flashedOptions = _2[0], setFlashedOptions = _2[1];
457
+ var _4 = (0, react_2.useState)([]), highlightedOptions = _4[0], setHighlightedOptions = _4[1];
458
+ var _5 = (0, react_2.useState)([]), flashedOptions = _5[0], setFlashedOptions = _5[1];
372
459
  var flashTimeout = (0, react_2.useRef)();
373
460
  var flashOptions = (0, react_2.useCallback)(function (optionNames, scrollToFirst) {
374
- var _a;
375
461
  if (scrollToFirst === void 0) { scrollToFirst = false; }
376
462
  if (scrollToFirst && optionNames[0]) {
377
- (_a = document
378
- .querySelector(".readfirst-row[data-field=\"".concat(optionNames[0], "\"]"))) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ block: 'center', behavior: 'smooth' });
463
+ // Defer to the next frame: when this fires for a field that just changed
464
+ // panels, its row has only just re-mounted in the new box scrolling in the
465
+ // same tick targets the stale (pre-move) layout, so the page doesn't budge.
466
+ // A rAF lets the new position settle first.
467
+ requestAnimationFrame(function () {
468
+ var target = document.querySelector(".readfirst-row[data-field=\"".concat(optionNames[0], "\"]"));
469
+ if (typeof (target === null || target === void 0 ? void 0 : target.scrollIntoView) === 'function') {
470
+ target.scrollIntoView({ block: 'center', behavior: 'smooth' });
471
+ }
472
+ });
379
473
  }
380
474
  setFlashedOptions(optionNames);
381
475
  clearTimeout(flashTimeout.current);
@@ -383,18 +477,37 @@ var FormEngine = function (_a) {
383
477
  }, []);
384
478
  var flashOption = (0, react_2.useCallback)(function (optionName) { return flashOptions([optionName], true); }, [flashOptions]);
385
479
  (0, react_2.useEffect)(function () { return function () { return clearTimeout(flashTimeout.current); }; }, []);
480
+ // Follow a field across panels: when its status bucket changes — e.g. you fill
481
+ // an optional field and it jumps to Set / Needs attention — scroll to its new
482
+ // row and flash it so it's easy to keep track of. `settledBucket` holds each
483
+ // field's current panel (frozen while the field is being edited, it re-buckets
484
+ // on collapse), so diffing it after every render catches the move the instant it
485
+ // lands in the new panel. Runs every render; the diff is cheap and only fires a
486
+ // scroll on an ACTUAL move of a non-expanded field.
487
+ var prevSettledBucket = (0, react_2.useRef)({});
488
+ (0, react_2.useEffect)(function () {
489
+ if (!compact)
490
+ return;
491
+ var cur = settledBucket.current;
492
+ var prev = prevSettledBucket.current;
493
+ var moved = Object.keys(cur).find(function (name) { return prev[name] && prev[name] !== cur[name] && !expandedOptions.includes(name); });
494
+ prevSettledBucket.current = __assign({}, cur);
495
+ if (moved) {
496
+ flashOptions([moved], true);
497
+ }
498
+ });
386
499
  var compactNarrow = !!compactWrapWidth && compactWrapWidth < 480;
387
500
  // Info panels auto-open on Tier-1 content; the per-row user override sticks.
388
- var _3 = (0, react_2.useState)({}), infoPanelOverrides = _3[0], setInfoPanelOverrides = _3[1];
501
+ var _6 = (0, react_2.useState)({}), infoPanelOverrides = _6[0], setInfoPanelOverrides = _6[1];
389
502
  // Toolbar filters affect the listed rows only — the meter reflects the full set.
390
- var _4 = (0, react_2.useState)(false), requiredOnly = _4[0], setRequiredOnly = _4[1];
391
- var _5 = (0, react_2.useState)(''), compactQuery = _5[0], setCompactQuery = _5[1];
503
+ var _7 = (0, react_2.useState)(false), requiredOnly = _7[0], setRequiredOnly = _7[1];
504
+ var _8 = (0, react_2.useState)(''), compactQuery = _8[0], setCompactQuery = _8[1];
392
505
  // Compact field sort (Fields menu → "Sort by"); 'schema' = declared order.
393
- var _6 = (0, react_2.useState)('schema'), compactSort = _6[0], setCompactSort = _6[1];
394
- var _7 = (0, react_2.useState)(function () { return ({
395
- fields: (0, exports.fixOptions)(value, options || {}),
506
+ var _9 = (0, react_2.useState)('schema'), compactSort = _9[0], setCompactSort = _9[1];
507
+ var _10 = (0, react_2.useState)(function () { return ({
508
+ fields: (0, exports.fixOptions)(value, options || {}, undefined, isRendererOnly),
396
509
  meta: undefined,
397
- }); }), localValue = _7[0], setLocalValue = _7[1];
510
+ }); }), localValue = _10[0], setLocalValue = _10[1];
398
511
  var originalValue = (0, react_2.useRef)();
399
512
  // Track the last value we emitted via onChange so we can skip re-applying fixOptions
400
513
  // when the parent echoes it back as the new value prop (controlled component loop prevention)
@@ -403,7 +516,7 @@ var FormEngine = function (_a) {
403
516
  originalValue.current = localValue.fields;
404
517
  }
405
518
  var unavailableOptionsCount = (0, react_2.useRef)(0);
406
- var _8 = (0, useQorusTypes_1.useQorusTypes)(), compactValue = _8.compactValue, typesLoading = _8.loading;
519
+ var _11 = (0, useQorusTypes_1.useQorusTypes)(), compactValue = _11.compactValue, typesLoading = _11.loading;
407
520
  var templates = (0, useTemplates_1.useTemplates)(allowTemplates, rest.stringTemplates, interfaceContext);
408
521
  (0, react_2.useEffect)(function () {
409
522
  if ((0, lodash_1.isEqual)(localValue.fields, value)) {
@@ -477,7 +590,7 @@ var FormEngine = function (_a) {
477
590
  setOptions({});
478
591
  return [2 /*return*/];
479
592
  }
480
- setLocalValue({ fields: (0, exports.fixOptions)(value, data.data), meta: undefined });
593
+ setLocalValue({ fields: (0, exports.fixOptions)(value, data.data, undefined, isRendererOnly), meta: undefined });
481
594
  if (!operatorsUrl) {
482
595
  setLoading(false);
483
596
  }
@@ -536,7 +649,7 @@ var FormEngine = function (_a) {
536
649
  }
537
650
  setOptions(data.data);
538
651
  onOptionsLoaded === null || onOptionsLoaded === void 0 ? void 0 : onOptionsLoaded(data.data);
539
- setLocalValue({ fields: (0, exports.fixOptions)({}, data.data), meta: undefined });
652
+ setLocalValue({ fields: (0, exports.fixOptions)({}, data.data, undefined, isRendererOnly), meta: undefined });
540
653
  return [2 /*return*/];
541
654
  }
542
655
  });
@@ -569,7 +682,7 @@ var FormEngine = function (_a) {
569
682
  }
570
683
  }, [operatorsUrl]);
571
684
  (0, react_use_1.useUpdateEffect)(function () {
572
- var fixedValue = (0, exports.fixOptions)(value, options || {});
685
+ var fixedValue = (0, exports.fixOptions)(value, options || {}, undefined, isRendererOnly);
573
686
  // When the value we're receiving is the one we just emitted AND fixOptions has nothing to
574
687
  // meaningfully add or change, skip the update. This breaks the controlled-component loop for
575
688
  // arg_schema fields while still allowing required/preselected options to be restored (in that
@@ -588,21 +701,23 @@ var FormEngine = function (_a) {
588
701
  originalValue.current = fixedValue;
589
702
  }
590
703
  setLocalValue === null || setLocalValue === void 0 ? void 0 : setLocalValue({ fields: fixedValue, meta: undefined });
591
- }, [JSON.stringify(options), JSON.stringify(value)]);
704
+ }, [JSON.stringify(options), JSON.stringify(value), isRendererOnly]);
592
705
  var handleValueChange = (0, react_2.useCallback)(function (optionName, val, _type, isFunction) {
593
706
  setLocalValue(function (_a) {
594
707
  var _b, _c;
595
- var _d, _f, _g, _h, _j, _k, _l, _m, _o;
596
- var _p = _a.fields, fields = _p === void 0 ? {} : _p;
597
- var schemaType = (((_d = options === null || options === void 0 ? void 0 : options[optionName]) === null || _d === void 0 ? void 0 : _d.ui_type) ||
598
- ((_f = options === null || options === void 0 ? void 0 : options[optionName]) === null || _f === void 0 ? void 0 : _f.type));
708
+ var _d, _f, _g, _h, _j, _k, _l, _m, _o, _p;
709
+ var _q = _a.fields, fields = _q === void 0 ? {} : _q;
710
+ var schemaType = getOptionSchemaStorageType(options === null || options === void 0 ? void 0 : options[optionName], isRendererOnly);
599
711
  var isAnyLike = schemaType === 'any' || schemaType === 'auto';
600
712
  // For any/auto schema types, preserve the user's chosen type stored in the field
601
- var resolvedSchemaType = isAnyLike && ((_g = fields[optionName]) === null || _g === void 0 ? void 0 : _g.type) ?
602
- fields[optionName].type
603
- : schemaType || ((_h = fields[optionName]) === null || _h === void 0 ? void 0 : _h.type);
713
+ var resolvedSchemaType = isAnyLike && ((_d = fields[optionName]) === null || _d === void 0 ? void 0 : _d.type)
714
+ ? fields[optionName].type
715
+ : ((_f = fields[optionName]) === null || _f === void 0 ? void 0 : _f.type) === ((_g = options === null || options === void 0 ? void 0 : options[optionName]) === null || _g === void 0 ? void 0 : _g.ui_type) &&
716
+ isRendererOnly((_h = fields[optionName]) === null || _h === void 0 ? void 0 : _h.type)
717
+ ? schemaType
718
+ : schemaType || ((_j = fields[optionName]) === null || _j === void 0 ? void 0 : _j.type);
604
719
  var type = _type ||
605
- (0, exports.getTypeAndCanBeNull)(resolvedSchemaType, (_j = options === null || options === void 0 ? void 0 : options[optionName]) === null || _j === void 0 ? void 0 : _j.allowed_values).type;
720
+ (0, exports.getTypeAndCanBeNull)(resolvedSchemaType, (_k = options === null || options === void 0 ? void 0 : options[optionName]) === null || _k === void 0 ? void 0 : _k.allowed_values).type;
606
721
  if (!fields[optionName]) {
607
722
  var defaultOperators = (0, reduce_1.default)(operators || {}, function (filteredOperators, operator, operatorKey) {
608
723
  if (operator.selected) {
@@ -631,9 +746,9 @@ var FormEngine = function (_a) {
631
746
  delete updatedValue[optionName].is_expression;
632
747
  }
633
748
  var meta = {};
634
- if (((_k = options === null || options === void 0 ? void 0 : options[optionName]) === null || _k === void 0 ? void 0 : _k.has_dependents) &&
749
+ if (((_l = options === null || options === void 0 ? void 0 : options[optionName]) === null || _l === void 0 ? void 0 : _l.has_dependents) &&
635
750
  val !== undefined &&
636
- val !== ((_l = fields[optionName]) === null || _l === void 0 ? void 0 : _l.value)) {
751
+ val !== ((_m = fields[optionName]) === null || _m === void 0 ? void 0 : _m.value)) {
637
752
  (0, lodash_1.forEach)(options, function (option, depName) {
638
753
  if (option.depends_on &&
639
754
  (0, lodash_1.flatten)(option.depends_on).includes(optionName) &&
@@ -643,10 +758,15 @@ var FormEngine = function (_a) {
643
758
  });
644
759
  onDependableOptionChange === null || onDependableOptionChange === void 0 ? void 0 : onDependableOptionChange(optionName, val, updatedValue, options);
645
760
  }
646
- if ((0, size_1.default)((_m = options === null || options === void 0 ? void 0 : options[optionName]) === null || _m === void 0 ? void 0 : _m.on_change)) {
647
- meta.events = (_o = options === null || options === void 0 ? void 0 : options[optionName]) === null || _o === void 0 ? void 0 : _o.on_change;
761
+ if ((0, size_1.default)((_o = options === null || options === void 0 ? void 0 : options[optionName]) === null || _o === void 0 ? void 0 : _o.on_change)) {
762
+ meta.events = (_p = options === null || options === void 0 ? void 0 : options[optionName]) === null || _p === void 0 ? void 0 : _p.on_change;
648
763
  }
649
764
  onSingleOptionsChange === null || onSingleOptionsChange === void 0 ? void 0 : onSingleOptionsChange(optionName, updatedValue[optionName]);
765
+ if (compact &&
766
+ !readOnly &&
767
+ (0, readFirst_1.shouldAutoCollapseCompactOption)(options === null || options === void 0 ? void 0 : options[optionName], val)) {
768
+ setExpandedOptions(function (prev) { return prev.filter(function (name) { return name !== optionName; }); });
769
+ }
650
770
  return {
651
771
  fields: updatedValue,
652
772
  meta: meta,
@@ -655,6 +775,9 @@ var FormEngine = function (_a) {
655
775
  }, [
656
776
  onSingleOptionsChange,
657
777
  onDependableOptionChange,
778
+ isRendererOnly,
779
+ compact,
780
+ readOnly,
658
781
  JSON.stringify(options),
659
782
  JSON.stringify(operators),
660
783
  ]);
@@ -726,11 +849,14 @@ var FormEngine = function (_a) {
726
849
  meta: undefined,
727
850
  };
728
851
  });
852
+ // Collapse it too: a removed field drops back to the (collapsed) Optional box
853
+ // as a quiet addable row — if it was being edited, that editor must close
854
+ // rather than linger as an open editor for a field that's no longer added.
855
+ setExpandedOptions(function (prev) { return prev.filter(function (name) { return name !== optionName; }); });
729
856
  }, []);
730
857
  var handleAddOptionalFieldChange = (0, react_2.useCallback)(function (_name, optionName) {
731
- var _a, _b, _c;
732
- handleValueChange(optionName, (0, common_1.getDefaultValue)(options === null || options === void 0 ? void 0 : options[optionName]), (0, exports.getTypeAndCanBeNull)((((_a = options === null || options === void 0 ? void 0 : options[optionName]) === null || _a === void 0 ? void 0 : _a.ui_type) ||
733
- ((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.type)), (_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.allowed_values).type);
858
+ var _a;
859
+ handleValueChange(optionName, (0, common_1.getDefaultValue)(options === null || options === void 0 ? void 0 : options[optionName]), (0, exports.getTypeAndCanBeNull)(getOptionSchemaStorageType(options === null || options === void 0 ? void 0 : options[optionName], isRendererOnly), (_a = options === null || options === void 0 ? void 0 : options[optionName]) === null || _a === void 0 ? void 0 : _a.allowed_values).type);
734
860
  }, [JSON.stringify(options), handleValueChange]);
735
861
  var availableOptions = (0, react_2.useMemo)(function () {
736
862
  if (!options) {
@@ -752,22 +878,18 @@ var FormEngine = function (_a) {
752
878
  removeSelectedOption(optionName);
753
879
  return newValue;
754
880
  }
755
- var schemaType = (0, exports.getType)((options[optionName].ui_type || options[optionName].type), operators, option === null || option === void 0 ? void 0 : option.op);
881
+ var rendererType = (0, exports.getType)((options[optionName].ui_type || options[optionName].type), operators, option === null || option === void 0 ? void 0 : option.op);
882
+ var storageType = getOptionFieldStorageType(optionName, option === null || option === void 0 ? void 0 : option.type, options, operators, option === null || option === void 0 ? void 0 : option.op, isRendererOnly);
756
883
  if (!(0, lodash_1.isPlainObject)(option)) {
757
884
  return __assign(__assign({}, newValue), (_a = {}, _a[optionName] = {
758
- type: schemaType,
885
+ type: storageType || rendererType,
759
886
  value: option,
760
887
  }, _a));
761
888
  }
762
- // any/auto: preserve the user-picked type; otherwise normalize to the
763
- // schema type (ui_type wins) so rendering and validation agree.
764
- var isAnyLike = schemaType === 'any' || schemaType === 'auto';
765
- var effectiveType = isAnyLike && (option === null || option === void 0 ? void 0 : option.type) ?
766
- option.type
767
- : schemaType;
768
- return __assign(__assign({}, newValue), (_b = {}, _b[optionName] = __assign(__assign({}, option), { type: effectiveType }), _b));
889
+ return __assign(__assign({}, newValue), (_b = {}, _b[optionName] = __assign(__assign({}, option), { type: storageType || rendererType }), _b));
769
890
  }, {});
770
891
  }, [
892
+ isRendererOnly,
771
893
  JSON.stringify(fixedValue),
772
894
  JSON.stringify(options),
773
895
  unavailableOptionsCount.current,
@@ -836,13 +958,11 @@ var FormEngine = function (_a) {
836
958
  }, [JSON.stringify(options), JSON.stringify(availableOptions), JSON.stringify(localValue.fields)]);
837
959
  var getValidityData = (0, react_2.useCallback)(function () {
838
960
  var fields = (0, reduce_1.default)(availableOptions, function (result, option, optionName) {
839
- var _a, _b, _c, _d;
840
- var type = option.type ||
841
- ((_a = options === null || options === void 0 ? void 0 : options[optionName]) === null || _a === void 0 ? void 0 : _a.ui_type) ||
842
- ((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.type);
961
+ var _a, _b;
962
+ var type = getOptionFieldStorageType(optionName, option.type, options, operators, option.op, isRendererOnly);
843
963
  var optionValue = option.value;
844
- var isRequired = (_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.required;
845
- var hasRequiredGroups = !!((_d = options === null || options === void 0 ? void 0 : options[optionName]) === null || _d === void 0 ? void 0 : _d.required_groups);
964
+ var isRequired = (_a = options === null || options === void 0 ? void 0 : options[optionName]) === null || _a === void 0 ? void 0 : _a.required;
965
+ var hasRequiredGroups = !!((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.required_groups);
846
966
  var isEmpty = optionValue === undefined || optionValue === '';
847
967
  var validation;
848
968
  if (!isRequired && !hasRequiredGroups && isEmpty) {
@@ -868,8 +988,10 @@ var FormEngine = function (_a) {
868
988
  invalidFields: invalidFields,
869
989
  };
870
990
  }, [
991
+ isRendererOnly,
871
992
  JSON.stringify(availableOptions),
872
993
  JSON.stringify(options),
994
+ JSON.stringify(operators),
873
995
  JSON.stringify(localValue.fields),
874
996
  ]);
875
997
  var validityData = (0, react_2.useMemo)(function () { return getValidityData(); }, [getValidityData]);
@@ -880,15 +1002,82 @@ var FormEngine = function (_a) {
880
1002
  var shownOptions = (0, react_2.useMemo)(function () {
881
1003
  return (0, reduce_1.default)(availableOptions, function (newValue, option, optionName) {
882
1004
  var _a;
883
- var _b, _c;
884
1005
  if (showInvalidOptionsOnly &&
885
- isOptionValid(optionName, ((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.ui_type) ||
886
- ((_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.type), option.value)) {
1006
+ isOptionValid(optionName, getOptionFieldStorageType(optionName, option.type, options, operators, option.op, isRendererOnly), option.value)) {
887
1007
  return newValue;
888
1008
  }
889
1009
  return __assign(__assign({}, newValue), (_a = {}, _a[optionName] = option, _a));
890
1010
  }, {});
891
- }, [showInvalidOptionsOnly, JSON.stringify(availableOptions)]);
1011
+ }, [
1012
+ showInvalidOptionsOnly,
1013
+ isRendererOnly,
1014
+ JSON.stringify(availableOptions),
1015
+ JSON.stringify(options),
1016
+ JSON.stringify(operators),
1017
+ ]);
1018
+ // Read-first STATUS / BOX for one option — lifted to component scope so the
1019
+ // status boxes (renderCompact) and the header's "needs attention" count share
1020
+ // exactly one definition. One-of group members travel together (bucket by the
1021
+ // group's satisfaction); everything else by its own status.
1022
+ var schemaMsgIntent = (0, react_2.useCallback)(function (name) {
1023
+ var _a;
1024
+ var msgs = (((_a = options === null || options === void 0 ? void 0 : options[name]) === null || _a === void 0 ? void 0 : _a.messages) || []);
1025
+ if (msgs.some(function (m) { return m.intent === 'danger'; }))
1026
+ return 'danger';
1027
+ if (msgs.some(function (m) { return m.intent === 'warning'; }))
1028
+ return 'warning';
1029
+ return undefined;
1030
+ }, [JSON.stringify(options)]);
1031
+ var getOptionStatus = (0, react_2.useCallback)(function (name, hidden) {
1032
+ var _a, _b, _c;
1033
+ if (hidden === void 0) { hidden = false; }
1034
+ if (hidden)
1035
+ return 'optional';
1036
+ var schema = options === null || options === void 0 ? void 0 : options[name];
1037
+ var type = getOptionFieldStorageType(name, (_a = availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[name]) === null || _a === void 0 ? void 0 : _a.type, options, operators, (_b = availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[name]) === null || _b === void 0 ? void 0 : _b.op, isRendererOnly);
1038
+ var value = (_c = availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[name]) === null || _c === void 0 ? void 0 : _c.value;
1039
+ var empty = (0, readFirst_1.isOptionValueEmpty)(value);
1040
+ var reqGroups = (schema === null || schema === void 0 ? void 0 : schema.required_groups) || [];
1041
+ var required = !!((schema === null || schema === void 0 ? void 0 : schema.required) || reqGroups.length);
1042
+ var covered = empty &&
1043
+ reqGroups.some(function (g) {
1044
+ var by = requiredGroupsInfo.satisfiedBy[g];
1045
+ return !!by && by !== name;
1046
+ });
1047
+ var msgIntent = schemaMsgIntent(name);
1048
+ var invalid = (!empty && !isOptionValid(name, type, value)) || msgIntent === 'danger';
1049
+ return (0, readFirst_1.getReadFirstStatus)({
1050
+ empty: empty,
1051
+ required: required,
1052
+ covered: covered,
1053
+ invalid: invalid,
1054
+ warned: msgIntent === 'warning',
1055
+ });
1056
+ }, [
1057
+ isRendererOnly,
1058
+ JSON.stringify(options),
1059
+ JSON.stringify(availableOptions),
1060
+ JSON.stringify(operators),
1061
+ isOptionValid,
1062
+ requiredGroupsInfo,
1063
+ schemaMsgIntent,
1064
+ ]);
1065
+ var getOptionBucket = (0, react_2.useCallback)(function (name, hidden) {
1066
+ var _a;
1067
+ if (hidden === void 0) { hidden = false; }
1068
+ if (!hidden) {
1069
+ var reqGroups = ((_a = options === null || options === void 0 ? void 0 : options[name]) === null || _a === void 0 ? void 0 : _a.required_groups) || [];
1070
+ if (reqGroups.length) {
1071
+ return reqGroups.some(function (g) { return !requiredGroupsInfo.satisfiedBy[g]; }) ? 'attention' : 'set';
1072
+ }
1073
+ }
1074
+ return (0, readFirst_1.getReadFirstBucket)(getOptionStatus(name, hidden));
1075
+ }, [JSON.stringify(options), requiredGroupsInfo, getOptionStatus]);
1076
+ // How many fields are in the "Needs attention" box — drives the header link.
1077
+ var readFirstAttentionCount = (0, react_2.useMemo)(function () {
1078
+ return Object.keys(availableOptions || {}).filter(function (name) { return getOptionBucket(name) === 'attention'; })
1079
+ .length;
1080
+ }, [JSON.stringify(availableOptions), getOptionBucket]);
892
1081
  var getIntent = (0, react_2.useCallback)(
893
1082
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
894
1083
  function (optName, type, optValue, _op) {
@@ -945,6 +1134,111 @@ var FormEngine = function (_a) {
945
1134
  : __spreadArray(__spreadArray([], prev, true), [optionName], false);
946
1135
  });
947
1136
  }, [expandMode]);
1137
+ // --- Caller-named starting rows (opt-in) ----------------------------------
1138
+ // `initialExpandedOptions` lets a consumer name the rows that must already
1139
+ // be open when the form first paints — the case where the expanded row is
1140
+ // part of an address rather than a click (see the prop's docs).
1141
+ //
1142
+ // One-shot for the same reason autofocus is: it fires on the first render
1143
+ // that actually has rows (so an async-loaded schema is covered) and then
1144
+ // never again, so a row the user collapses afterwards stays collapsed and a
1145
+ // later schema reload does not reopen it.
1146
+ var hasAppliedInitialExpansionRef = (0, react_2.useRef)(false);
1147
+ (0, react_2.useEffect)(function () {
1148
+ if (!(initialExpandedOptions === null || initialExpandedOptions === void 0 ? void 0 : initialExpandedOptions.length) || !compact || hasAppliedInitialExpansionRef.current) {
1149
+ return;
1150
+ }
1151
+ var names = Object.keys(availableOptions);
1152
+ if (!names.length) {
1153
+ return;
1154
+ }
1155
+ hasAppliedInitialExpansionRef.current = true;
1156
+ var toExpand = initialExpandedOptions.filter(function (name) { return names.includes(name); });
1157
+ if (!toExpand.length) {
1158
+ return;
1159
+ }
1160
+ setExpandedOptions(function (prev) { return __spreadArray(__spreadArray([], prev, true), toExpand.filter(function (name) { return !prev.includes(name); }), true); });
1161
+ }, [initialExpandedOptions, compact, availableOptions]);
1162
+ // --- First-attention-field autofocus (opt-in) -----------------------------
1163
+ // With `autoFocusFirstRequired`, drop the user straight into the first field
1164
+ // they must fix. We reuse the engine's own ordering (`availableOptions`), the
1165
+ // very same `getOptionBucket` the status boxes use to decide "needs attention"
1166
+ // (so we cover empty-required, unsatisfied one-of, AND filled-but-invalid rows
1167
+ // without ever drifting from what the user sees), and dependency gating
1168
+ // (`dependencyLockedNames`), then expand the target row through
1169
+ // `expandedOptions` — the row's editor-focus effect does the rest. No DOM
1170
+ // scraping, no synthetic clicks, no polling.
1171
+ //
1172
+ // Strictly one-shot: it fires the first time the form has focusable content
1173
+ // (so an async-loaded schema is still covered — the empty first pass doesn't
1174
+ // count), then never again for the life of this instance. A server-driven
1175
+ // field update or an in-place schema reload will NOT re-grab focus; only a
1176
+ // genuine remount (a fresh instance) auto-focuses again, which is the intended
1177
+ // on-mount behaviour.
1178
+ var hasAutoFocusedRef = (0, react_2.useRef)(false);
1179
+ // The field expanded programmatically for autofocus. A ref (not state) so
1180
+ // CompactRow's 60ms focus timer reads the current value regardless of render
1181
+ // batching; CompactRow focuses this one with `preventScroll` so an off-screen
1182
+ // (or below-the-fold) form is never scrolled into view on mount.
1183
+ var autoFocusNameRef = (0, react_2.useRef)(undefined);
1184
+ (0, react_2.useEffect)(function () {
1185
+ if (!autoFocusFirstRequired || !compact || !options) {
1186
+ return;
1187
+ }
1188
+ if (hasAutoFocusedRef.current) {
1189
+ return;
1190
+ }
1191
+ var orderedNames = Object.keys(availableOptions);
1192
+ if (!orderedNames.length) {
1193
+ return;
1194
+ }
1195
+ // Never grab focus from a control the user is already in — including a field
1196
+ // *inside* this form. If a slow/async schema lets the user start typing
1197
+ // before this first-required scan runs, we must not steal their caret. On a
1198
+ // clean mount focus rests on the body, so the intended "drop into the first
1199
+ // field" still fires. Bailing here leaves `hasAutoFocusedRef` false, so it
1200
+ // retries once focus is free.
1201
+ var active = document.activeElement;
1202
+ if (active && active !== document.body) {
1203
+ return;
1204
+ }
1205
+ var target = (0, readFirst_1.getFirstAttentionOptionName)(orderedNames, function (fieldName) {
1206
+ var schema = options[fieldName];
1207
+ if (!schema) {
1208
+ return undefined;
1209
+ }
1210
+ return {
1211
+ focusable: !readOnly &&
1212
+ !schema.disabled &&
1213
+ !schema.readonly &&
1214
+ !dependencyLockedNames.includes(fieldName),
1215
+ // Single source of truth: the same bucket the read-first status boxes
1216
+ // show, so a filled-but-invalid required row is a target too.
1217
+ needsAttention: getOptionBucket(fieldName) === 'attention',
1218
+ };
1219
+ });
1220
+ // Mark done even when nothing needs attention, so later value edits or an
1221
+ // in-place schema reload never re-scan or re-focus. Only a remount arms it
1222
+ // again.
1223
+ hasAutoFocusedRef.current = true;
1224
+ if (target) {
1225
+ // Set the ref before the state update so CompactRow's focus timer sees it.
1226
+ autoFocusNameRef.current = target;
1227
+ setExpandedOptions(function (prev) {
1228
+ return prev.includes(target) ? prev
1229
+ : expandMode === 'multi' ? __spreadArray(__spreadArray([], prev, true), [target], false) : [target];
1230
+ });
1231
+ }
1232
+ }, [
1233
+ autoFocusFirstRequired,
1234
+ compact,
1235
+ options,
1236
+ availableOptions,
1237
+ readOnly,
1238
+ dependencyLockedNames,
1239
+ getOptionBucket,
1240
+ expandMode,
1241
+ ]);
948
1242
  // Read-first completion summary (how many shown options have a value set),
949
1243
  // surfaced as a progress meter at the top of the compact form.
950
1244
  var readFirstCompletion = (0, react_2.useMemo)(function () { return (0, readFirst_1.getReadFirstCompletion)(availableOptions); }, [JSON.stringify(availableOptions)]);
@@ -989,10 +1283,10 @@ var FormEngine = function (_a) {
989
1283
  next[optionName] = value;
990
1284
  }
991
1285
  });
992
- return { fields: (0, exports.fixOptions)(next, options || {}, operators), meta: undefined };
1286
+ return { fields: (0, exports.fixOptions)(next, options || {}, operators, isRendererOnly), meta: undefined };
993
1287
  });
994
1288
  setRequiredOnly(false);
995
- }, [JSON.stringify(options), JSON.stringify(operators)]);
1289
+ }, [JSON.stringify(options), JSON.stringify(operators), isRendererOnly]);
996
1290
  var getCustomMenuTemplateItems = (0, react_2.useCallback)(function (optionName) {
997
1291
  return compactValue === null || compactValue === void 0 ? void 0 : compactValue.map(function (type) { return ({
998
1292
  label: type.display_name,
@@ -1011,13 +1305,53 @@ var FormEngine = function (_a) {
1011
1305
  // The info panel below the row keeps showing schema messages while editing —
1012
1306
  // rendering them in the editor too would balloon a one-line edit.
1013
1307
  suppressSchemaMessages) {
1014
- var _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
1308
+ var _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
1015
1309
  var type = _a.type, other = __rest(_a, ["type"]);
1016
1310
  var operatorParts = (0, exports.fixOperatorValue)(other.op);
1017
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(suppressSchemaMessages ? [] : ((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.messages) || []).map(function (_a, index) {
1018
- var intent = _a.intent, title = _a.title, content = _a.content;
1019
- return ((0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { intent: intent, title: title, opaque: false, size: 'small', margin: 'bottom', children: content }, title || index));
1020
- }), operators && (0, size_1.default)(operators) ?
1311
+ // The RENDERER type for this row which editor mounts. Distinct from the
1312
+ // storage type on the value envelope: a `richtext` field stores a string
1313
+ // but must render the richtext editor, so `ui_type` wins here.
1314
+ //
1315
+ // The exception is an any-like `ui_type`. Those schemas say
1316
+ // `ui_type: 'any'` precisely so the user can pick a concrete type, and
1317
+ // that pick lives on the field's stored `type` — letting 'any' win would
1318
+ // pin the row to the untyped editor forever.
1319
+ //
1320
+ // The trailing fallbacks keep the row rendering when a server-driven
1321
+ // schema has not arrived yet (`type` undefined) instead of crashing.
1322
+ var optionSchema = options === null || options === void 0 ? void 0 : options[optionName];
1323
+ var schemaUiType = optionSchema === null || optionSchema === void 0 ? void 0 : optionSchema.ui_type;
1324
+ var uiTypeIsAnyLike = schemaUiType === 'any' || schemaUiType === 'auto';
1325
+ var resolvedType = ((0, readFirst_1.isFixedCompactAllowedValueOption)(optionSchema)
1326
+ ? getOptionSchemaStorageType(optionSchema, isRendererOnly)
1327
+ : schemaUiType && !uiTypeIsAnyLike
1328
+ ? schemaUiType
1329
+ : undefined) ||
1330
+ type ||
1331
+ schemaUiType ||
1332
+ (optionSchema === null || optionSchema === void 0 ? void 0 : optionSchema.type) ||
1333
+ 'any';
1334
+ var effectiveForceDropdown = forceDropdown !== null && forceDropdown !== void 0 ? forceDropdown : templateFieldProps === null || templateFieldProps === void 0 ? void 0 : templateFieldProps.forceDropdown;
1335
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(function () {
1336
+ var _a;
1337
+ var schemaMsgs = (suppressSchemaMessages ?
1338
+ []
1339
+ : ((_a = options === null || options === void 0 ? void 0 : options[optionName]) === null || _a === void 0 ? void 0 : _a.messages) || []);
1340
+ if (!schemaMsgs.length)
1341
+ return null;
1342
+ var items = schemaMsgs.map(function (_a, index) {
1343
+ var intent = _a.intent, title = _a.title, content = _a.content;
1344
+ return ((0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { intent: intent, title: title, opaque: false, size: 'small',
1345
+ // Compact: flat (no border) to match the read-row info panels;
1346
+ // classic forms keep the bordered, bottom-margined message.
1347
+ flat: compact || undefined, margin: compact ? undefined : 'bottom', children: content }, title || index));
1348
+ });
1349
+ // Compact: stack them in a 4px-gap panel so a field's messages look
1350
+ // identical whether the row is collapsed (read panel) or expanded.
1351
+ return compact ?
1352
+ (0, jsx_runtime_1.jsx)("div", { className: 'options-readfirst-info-panel', style: { display: 'flex', flexFlow: 'column', gap: 4, marginBottom: 8 }, children: items })
1353
+ : (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: items });
1354
+ })(), operators && (0, size_1.default)(operators) ?
1021
1355
  (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreControlGroup, { fill: true, wrap: true, className: 'operators', children: operatorParts.map(function (operator, index) {
1022
1356
  var _a, _b;
1023
1357
  return ((0, jsx_runtime_1.jsxs)(react_2.default.Fragment, { children: [(0, jsx_runtime_1.jsx)(Select_1.SelectFormField, { items: (0, map_1.default)(operators, function (op) { return (__assign(__assign({}, op), { value: op.name })); }), disabled: readOnly, value: operator && "".concat((_a = operators === null || operators === void 0 ? void 0 : operators[operator]) === null || _a === void 0 ? void 0 : _a.name), onChange: function (val) {
@@ -1032,23 +1366,51 @@ var FormEngine = function (_a) {
1032
1366
  (0, jsx_runtime_1.jsx)(reqore_1.ReqoreButton, { disabled: readOnly, icon: 'DeleteBinLine', effect: NegativeColorEffect, fixed: true, onClick: function () { return handleRemoveOperator(optionName, fixedValue, index); } })
1033
1367
  : null] }, index));
1034
1368
  }) }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreVerticalSpacer, { height: 5 })] })
1035
- : null, (0, react_1.createElement)(TemplateField_1.TemplateField, __assign({ fluid: true }, options === null || options === void 0 ? void 0 : options[optionName], {
1369
+ : 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, inheritedFromParent), {
1370
+ // qorus#347-followup (scope forwarding): merge accumulated
1371
+ // inheritance (`inheritedFromParent`) with THIS field's freshly
1372
+ // resolved inherit_props, and pass down as a single bag so any
1373
+ // nested `arg_schema` sub-form (mounted by AutoFormField for
1374
+ // `hash` / `free-hash` / list-of-hash fields) sees every value
1375
+ // the ancestor chain forwarded. This is the plumbing that lets a
1376
+ // service-method row's `body` sub-field pick up the parent
1377
+ // service form's `language` — the parent field declares
1378
+ // `inherit_props: { language: 'language' }`, the list renderer
1379
+ // forwards it into each row, and the row's body resolves against
1380
+ // the accumulated bag.
1381
+ inheritedFromParent: __assign(__assign({}, inheritedFromParent), resolveInheritProps((_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.inherit_props, availableOptions, inheritedFromParent)),
1382
+ // Propagate compact so an arg_schema field renders a COMPACT sub-form
1383
+ // (consistent with the parent) rather than the classic FormEngine.
1384
+ compact: compact,
1036
1385
  // SEAM: forwarded through TemplateField's rest-spread to AutoFormField,
1037
1386
  // which renders consumer-injected editors by field type/ui_type.
1038
- 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),
1387
+ componentOverrides: componentOverrides, allowTemplates: !!(allowTemplates && ((_d = options === null || options === void 0 ? void 0 : options[optionName]) === null || _d === void 0 ? void 0 : _d.supports_templates)), allowFunctions: !!((_f = options === null || options === void 0 ? void 0 : options[optionName]) === null || _f === void 0 ? void 0 : _f.supports_expressions),
1039
1388
  // reqraft: form-level expression fields get the Visual/Text shell
1040
1389
  // (DPQL text mode); opt out per-form via `templateFieldProps`.
1041
- 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:
1390
+ allowTextExpressions: true,
1391
+ // A fixed allowed-value field still needs its selector even when
1392
+ // arbitrary custom values are forbidden. TemplateField uses this
1393
+ // flag to decide whether to mount AutoFormField at all; treating
1394
+ // `supports_custom_values: false` as "no input" left dependent
1395
+ // delivery fields (Discord server/channel, for example) as empty
1396
+ // control groups. The allowed-values renderer itself enforces the
1397
+ // fixed catalogue and never exposes free-form entry.
1398
+ allowCustomValues: (0, readFirst_1.isFixedCompactAllowedValueOption)(optionSchema) ||
1399
+ (((_g = options === null || options === void 0 ? void 0 : options[optionName]) === null || _g === void 0 ? void 0 : _g.supports_custom_values) !== false && resolvedType !== 'any'), templates: templates.value }, (0, exports.getTypeAndCanBeNull)(
1400
+ // The RENDERER type picks the editor — the storage type lives on
1401
+ // the value envelope. Passing storage here rendered a `richtext`
1402
+ // field as a plain string input.
1403
+ resolvedType, (_h = options === null || options === void 0 ? void 0 : options[optionName]) === null || _h === void 0 ? void 0 : _h.allowed_values, other.op), { ui_type: resolvedType, name: optionName, uniqueName: "".concat(uniqueName ? "".concat(uniqueName, ".") : "".concat(name ? "".concat(name, ".") : '')).concat(optionName), onChange:
1042
1404
  // Identity-stable on purpose: the typed fields debounce on
1043
1405
  // `[localValue, onChange]` — an inline lambda resets the pending emit
1044
1406
  // every render and the typed value can starve.
1045
- 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) ||
1407
+ handleValueChange, key: optionName, arg_schema: (_j = options === null || options === void 0 ? void 0 : options[optionName]) === null || _j === void 0 ? void 0 : _j.arg_schema, noSoft: !!(rest === null || rest === void 0 ? void 0 : rest.options), value: other.value, isFunction: other.is_expression, isDefaultFunction: ((_k = options === null || options === void 0 ? void 0 : options[optionName]) === null || _k === void 0 ? void 0 : _k.default_view) === 'expression', sensitive: (_l = options === null || options === void 0 ? void 0 : options[optionName]) === null || _l === void 0 ? void 0 : _l.sensitive, default_value: (0, common_1.getDefaultValue)(options === null || options === void 0 ? void 0 : options[optionName]), isDefaultTemplate: ((_m = options === null || options === void 0 ? void 0 : options[optionName]) === null || _m === void 0 ? void 0 : _m.default_view) === 'template', allowed_values: (_o = options === null || options === void 0 ? void 0 : options[optionName]) === null || _o === void 0 ? void 0 : _o.allowed_values, allowed_values_creatable: (_p = options === null || options === void 0 ? void 0 : options[optionName]) === null || _p === void 0 ? void 0 : _p.allowed_values_creatable, disabled: ((_q = options === null || options === void 0 ? void 0 : options[optionName]) === null || _q === void 0 ? void 0 : _q.disabled) ||
1046
1408
  readOnly ||
1047
- !(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' ?
1409
+ !(0, validations_1.hasAllDependenciesFullfilled)((_r = options === null || options === void 0 ? void 0 : options[optionName]) === null || _r === void 0 ? void 0 : _r.depends_on, availableOptions, options || {}), readOnly: readOnly, size: editorSize || rest.size, menuItems: ((_s = options === null || options === void 0 ? void 0 : options[optionName]) === null || _s === void 0 ? void 0 : _s.ui_type) === 'any' ?
1048
1410
  getCustomMenuTemplateItems(optionName)
1049
- : 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) ?
1411
+ : 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 }), operators && (0, size_1.default)(operators) && (0, size_1.default)(other.op) ?
1050
1412
  (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 ?
1051
- type === 'richtext' ?
1413
+ resolvedType === 'richtext' ?
1052
1414
  (0, common_1.richtextToString)(other.value)
1053
1415
  : JSON.stringify(other.value)
1054
1416
  : '' })] }) })] })
@@ -1063,6 +1425,7 @@ var FormEngine = function (_a) {
1063
1425
  uniqueName,
1064
1426
  componentOverrides,
1065
1427
  templateFieldProps,
1428
+ forceDropdown,
1066
1429
  availableOptions,
1067
1430
  fixedValue,
1068
1431
  // Depend on the specific `rest` values used, not the whole `rest` object
@@ -1078,7 +1441,7 @@ var FormEngine = function (_a) {
1078
1441
  ]);
1079
1442
  // Compact (read-first) rendering.
1080
1443
  // Theme-derived colours so the flat-row layout adapts to light/dark/custom themes.
1081
- var cText = ((_b = theme === null || theme === void 0 ? void 0 : theme.text) === null || _b === void 0 ? void 0 : _b.color) || '#f1f0ee';
1444
+ var cText = ((_c = theme === null || theme === void 0 ? void 0 : theme.text) === null || _c === void 0 ? void 0 : _c.color) || '#f1f0ee';
1082
1445
  // Text emphasis tiers via reqore's readable-colour helper (key = full readable
1083
1446
  // text, muted = its dimmed variant, faint = the dimmed variant softened
1084
1447
  // further) instead of hand-rolled hex-alpha suffixes on the raw text colour.
@@ -1087,10 +1450,10 @@ var FormEngine = function (_a) {
1087
1450
  var cFaint = "".concat(cMuted, "99");
1088
1451
  var cDivider = "".concat(cText, "14");
1089
1452
  var cHover = "".concat(cText, "0d");
1090
- var cDanger = ((_c = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _c === void 0 ? void 0 : _c.danger) || '#e35a5a';
1091
- var cWarning = ((_d = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _d === void 0 ? void 0 : _d.warning) || '#ffdf34';
1092
- var cInfo = ((_f = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _f === void 0 ? void 0 : _f.info) || '#3b8eea';
1093
- var cSuccess = ((_g = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _g === void 0 ? void 0 : _g.success) || '#36b37e';
1453
+ var cDanger = ((_d = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _d === void 0 ? void 0 : _d.danger) || '#e35a5a';
1454
+ var cWarning = ((_f = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _f === void 0 ? void 0 : _f.warning) || '#ffdf34';
1455
+ var cInfo = ((_g = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _g === void 0 ? void 0 : _g.info) || '#3b8eea';
1456
+ var cSuccess = ((_h = theme === null || theme === void 0 ? void 0 : theme.intents) === null || _h === void 0 ? void 0 : _h.success) || '#36b37e';
1094
1457
  var cBg = (theme === null || theme === void 0 ? void 0 : theme.main) || '#181818';
1095
1458
  var cRowBg = (0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.01);
1096
1459
  var cGroupLine = "".concat(cText, "1f");
@@ -1108,6 +1471,7 @@ var FormEngine = function (_a) {
1108
1471
  showFieldTypes: showFieldTypes,
1109
1472
  showAllDescriptions: showAllDescriptions,
1110
1473
  expandedOptions: expandedOptions,
1474
+ autoFocusNameRef: autoFocusNameRef,
1111
1475
  highlightedOptions: highlightedOptions,
1112
1476
  flashedOptions: flashedOptions,
1113
1477
  infoPanelOverrides: infoPanelOverrides,
@@ -1128,6 +1492,8 @@ var FormEngine = function (_a) {
1128
1492
  getTypeForOption: getTypeForOption,
1129
1493
  isOptionValid: isOptionValid,
1130
1494
  confirmAction: confirmAction,
1495
+ optionActions: optionActions,
1496
+ collapseOptionActions: collapseOptionActions,
1131
1497
  renderOption: renderOption,
1132
1498
  theme: theme,
1133
1499
  cText: cText,
@@ -1151,6 +1517,7 @@ var FormEngine = function (_a) {
1151
1517
  showFieldTypes,
1152
1518
  showAllDescriptions,
1153
1519
  expandedOptions,
1520
+ autoFocusNameRef,
1154
1521
  highlightedOptions,
1155
1522
  flashedOptions,
1156
1523
  infoPanelOverrides,
@@ -1171,6 +1538,8 @@ var FormEngine = function (_a) {
1171
1538
  getTypeForOption,
1172
1539
  isOptionValid,
1173
1540
  confirmAction,
1541
+ optionActions,
1542
+ collapseOptionActions,
1174
1543
  renderOption,
1175
1544
  theme,
1176
1545
  cText,
@@ -1187,6 +1556,7 @@ var FormEngine = function (_a) {
1187
1556
  var compactToolbarContextValue = (0, react_2.useMemo)(function () { return ({
1188
1557
  readOnly: readOnly,
1189
1558
  invalidCount: (0, size_1.default)(validityData.invalidFields),
1559
+ attentionCount: readFirstAttentionCount,
1190
1560
  completion: readFirstCompletion,
1191
1561
  showInvalidOnly: showInvalidOptionsOnly,
1192
1562
  onToggleInvalidOnly: handleToggleInvalidOnly,
@@ -1211,6 +1581,7 @@ var FormEngine = function (_a) {
1211
1581
  }); }, [
1212
1582
  readOnly,
1213
1583
  validityData,
1584
+ readFirstAttentionCount,
1214
1585
  readFirstCompletion,
1215
1586
  showInvalidOptionsOnly,
1216
1587
  handleToggleInvalidOnly,
@@ -1234,7 +1605,10 @@ var FormEngine = function (_a) {
1234
1605
  handleResetToDefaultFields,
1235
1606
  handleRevertChangesClick,
1236
1607
  ]);
1237
- var compactHeaderActions = (0, react_2.useMemo)(function () { return [{ as: CompactToolbar_1.CompactToolbar, responsive: false }]; }, []);
1608
+ // The engine's own toolbar action, plus whatever the consumer added through
1609
+ // `compactPanelProps.actions` — appended, so an outside action can never
1610
+ // knock the form's toolbar out of the header.
1611
+ var compactHeaderActions = (0, react_2.useMemo)(function () { return __spreadArray([{ as: CompactToolbar_1.CompactToolbar, responsive: false }], ((compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.actions) || []), true); }, [compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.actions]);
1238
1612
  var renderCompact = function () {
1239
1613
  var headerBg = "".concat((0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.02)).concat((0, colors_1.percentToHexAlpha)(88));
1240
1614
  // Toolbar filters narrow the listed rows; the meter reflects the full set.
@@ -1265,15 +1639,18 @@ var FormEngine = function (_a) {
1265
1639
  pushRow(optionName, false);
1266
1640
  }
1267
1641
  });
1268
- // When searching, also surface matching hidden optional fields (not yet
1269
- // added) so the search spans the whole schema, not just the visible rows.
1270
- if (query) {
1271
- (0, lodash_1.forEach)(filteredOptions, function (_schema, optionName) {
1272
- if (matchesQuery(optionName)) {
1273
- pushRow(optionName, true);
1274
- }
1275
- });
1276
- }
1642
+ // Surface EVERY not-yet-added optional field as an addable (hidden) row, so
1643
+ // the whole schema is browsable inline they all land in the Optional box
1644
+ // (hidden ⇒ 'optional' bucket) instead of being buried in the Fields menu.
1645
+ // Narrowed by the same filters as the listed rows (search query + required-
1646
+ // only). availableOptions (listed) and filteredOptions (these) are disjoint —
1647
+ // the former is built from fixedValue keys, the latter excludes them — so a
1648
+ // field is never both a listed and a hidden row.
1649
+ (0, lodash_1.forEach)(filteredOptions, function (_schema, optionName) {
1650
+ if (matchesFilters(optionName)) {
1651
+ pushRow(optionName, true);
1652
+ }
1653
+ });
1277
1654
  // User sort (Fields menu → "Sort by"), applied WITHIN each group so the
1278
1655
  // group sections and the required-group rails are preserved. Schema order is
1279
1656
  // the default and the stable tiebreaker (Array.sort is stable, and each
@@ -1285,7 +1662,7 @@ var FormEngine = function (_a) {
1285
1662
  var isUnset_1 = function (name) { var _a; return (0, readFirst_1.isOptionValueEmpty)((_a = shownOptions[name]) === null || _a === void 0 ? void 0 : _a.value); };
1286
1663
  var isFieldInvalid_1 = function (name) {
1287
1664
  var _a, _b, _c;
1288
- return !isOptionValid(name, (((_a = options === null || options === void 0 ? void 0 : options[name]) === null || _a === void 0 ? void 0 : _a.ui_type) || ((_b = options === null || options === void 0 ? void 0 : options[name]) === null || _b === void 0 ? void 0 : _b.type)), (_c = shownOptions[name]) === null || _c === void 0 ? void 0 : _c.value);
1665
+ return !isOptionValid(name, getOptionFieldStorageType(name, (_a = shownOptions[name]) === null || _a === void 0 ? void 0 : _a.type, options, operators, (_b = shownOptions[name]) === null || _b === void 0 ? void 0 : _b.op, isRendererOnly), (_c = shownOptions[name]) === null || _c === void 0 ? void 0 : _c.value);
1289
1666
  };
1290
1667
  var comparator_1 = function (a, b) {
1291
1668
  switch (compactSort) {
@@ -1317,22 +1694,71 @@ var FormEngine = function (_a) {
1317
1694
  return 1;
1318
1695
  return groupOrder.indexOf(a) - groupOrder.indexOf(b);
1319
1696
  });
1697
+ var buckets = {
1698
+ attention: {},
1699
+ set: {},
1700
+ optional: {},
1701
+ };
1702
+ var bucketGroups = { attention: [], set: [], optional: [] };
1703
+ // Freeze the box of any field currently being edited (or whose one-of group
1704
+ // has an edited member) to its last settled box — so finishing an edit that
1705
+ // flips its status doesn't remount it in another box and steal focus.
1706
+ var stableBucketOf = function (entry) {
1707
+ var _a;
1708
+ var fresh = getOptionBucket(entry.name, entry.hidden);
1709
+ var groupBeingEdited = !entry.hidden &&
1710
+ (((_a = options === null || options === void 0 ? void 0 : options[entry.name]) === null || _a === void 0 ? void 0 : _a.required_groups) || []).some(function (g) {
1711
+ return (requiredGroupsInfo.members[g] || []).some(function (m) { return expandedOptions.includes(m); });
1712
+ });
1713
+ if (!entry.hidden && (expandedOptions.includes(entry.name) || groupBeingEdited)) {
1714
+ var memo = settledBucket.current[entry.name];
1715
+ if (memo)
1716
+ return memo;
1717
+ }
1718
+ settledBucket.current[entry.name] = fresh;
1719
+ return fresh;
1720
+ };
1721
+ groupKeys.forEach(function (groupName) {
1722
+ grouped[groupName].forEach(function (entry) {
1723
+ var b = stableBucketOf(entry);
1724
+ if (!buckets[b][groupName]) {
1725
+ buckets[b][groupName] = [];
1726
+ bucketGroups[b].push(groupName);
1727
+ }
1728
+ buckets[b][groupName].push(entry);
1729
+ });
1730
+ });
1731
+ var bucketCount = function (b) {
1732
+ return bucketGroups[b].reduce(function (n, g) { return n + buckets[b][g].length; }, 0);
1733
+ };
1734
+ // 'general' / 'optional' are the SYNTHETIC fallback group keys getOptionGroup
1735
+ // assigns to fields with no explicit `group` — printing a "General"/"Optional"
1736
+ // sub-label for those is just noise, so suppress it. BUT a consumer may also
1737
+ // use 'general' as a REAL group (defining it in the `groups` prop and tagging
1738
+ // fields with `group: 'general'`); in that case it's a named group like any
1739
+ // other and DOES get its sub-label.
1740
+ var showGroupSubLabel = function (groupName) {
1741
+ return (groupName !== 'general' && groupName !== 'optional') || !!(groups === null || groups === void 0 ? void 0 : groups[groupName]);
1742
+ };
1743
+ var STATUS_BOXES = [
1744
+ { key: 'attention', label: 'Needs attention', intent: 'warning', icon: 'ErrorWarningLine' },
1745
+ { key: 'set', label: 'Set', intent: 'success', icon: 'CheckLine' },
1746
+ { key: 'optional', label: 'Optional', icon: 'CheckboxBlankCircleLine' },
1747
+ ];
1320
1748
  // Build the rows for one group: contiguous required-group members are pulled
1321
1749
  // together at the first member's slot and rendered as a connected rail (flat
1322
1750
  // rows — no wrapper — so the value surface applies normally; the rail + nodes
1323
1751
  // are drawn per member). Narrow stacks fall back to flat rows.
1324
1752
  var renderGroupRows = function (names) {
1325
- var renderRow = function (entry, clustered, clusterFirst, clusterLast) {
1326
- var _a, _b;
1327
- return ((0, jsx_runtime_1.jsx)(CompactRow_1.CompactRow, { optionName: entry.name, optionField: entry.hidden ?
1328
- {
1329
- type: (((_a = options === null || options === void 0 ? void 0 : options[entry.name]) === null || _a === void 0 ? void 0 : _a.ui_type) || ((_b = options === null || options === void 0 ? void 0 : options[entry.name]) === null || _b === void 0 ? void 0 : _b.type)),
1330
- value: undefined,
1331
- }
1332
- : shownOptions[entry.name], hidden: entry.hidden, clustered: clustered, clusterFirst: clusterFirst, clusterLast: clusterLast }, entry.name));
1333
- };
1334
- if (compactNarrow)
1335
- return names.map(function (entry) { return renderRow(entry, false); });
1753
+ var renderRow = function (entry, clustered, clusterFirst, clusterLast) { return ((0, jsx_runtime_1.jsx)(CompactRow_1.CompactRow, { optionName: entry.name, optionField: entry.hidden ?
1754
+ {
1755
+ type: getOptionSchemaStorageType(options === null || options === void 0 ? void 0 : options[entry.name], isRendererOnly),
1756
+ value: undefined,
1757
+ }
1758
+ : shownOptions[entry.name], hidden: entry.hidden, clustered: clustered, clusterFirst: clusterFirst, clusterLast: clusterLast }, entry.name)); };
1759
+ // (Clustering runs in narrow mode too now — the "One of the below is
1760
+ // required" box wraps the members regardless of width; it no longer relies
1761
+ // on a contiguous rail.)
1336
1762
  var emitted = new Set();
1337
1763
  var groupOf = function (name) { var _a, _b; return (_b = (_a = options === null || options === void 0 ? void 0 : options[name]) === null || _a === void 0 ? void 0 : _a.required_groups) === null || _b === void 0 ? void 0 : _b[0]; };
1338
1764
  return names.map(function (entry) {
@@ -1345,52 +1771,67 @@ var FormEngine = function (_a) {
1345
1771
  if (memberEntries.length < 2)
1346
1772
  return renderRow(entry, false);
1347
1773
  emitted.add(grp);
1348
- return memberEntries.map(function (e, idx) {
1774
+ var railed = memberEntries.map(function (e, idx) {
1349
1775
  return renderRow(e, true, idx === 0, idx === memberEntries.length - 1);
1350
1776
  });
1777
+ // An UNMET one-of group gets the explicit "One of the below is required"
1778
+ // box (the Focus cluster). A met group needs no banner — the rail + the
1779
+ // "Covers"/"Covered by" chips already say which member satisfies it.
1780
+ if (requiredGroupsInfo.satisfiedBy[grp])
1781
+ return railed;
1782
+ 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));
1351
1783
  });
1352
1784
  };
1353
- 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: {
1354
- display: 'flex',
1355
- flexFlow: 'column',
1356
- gap: '10px',
1357
- padding: '0 0 12px',
1358
- }, children: [(0, size_1.default)(groupKeys) === 0 ?
1785
+ 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
1786
+ // The top-level form scrolls, so its toolbar STICKS and carries a
1787
+ // dark blurred backdrop so content ghosts cleanly beneath it. A
1788
+ // nested (arg_schema) sub-form owns no scroll context — drop the
1789
+ // sticky, the backdrop, and the stacking context so its header is
1790
+ // transparent inside the parent's card.
1791
+ , __assign({ "$headerBg": compactNested ? 'transparent' : headerBg, "$nested": compactNested, flat: true, raised: true, minimal: true,
1792
+ // No panel background: the form sits transparently on whatever
1793
+ // hosts it (page, drawer, or — for an arg_schema field — the
1794
+ // parent's edit card) instead of stacking its own dark surface.
1795
+ // The status boxes keep their own tints; the sticky toolbar keeps
1796
+ // its blurred header via the $headerBg override.
1797
+ stickyHeader: !compactNested }, compactPanelProps, { actions: compactHeaderActions, contentStyle: __assign({ display: 'flex', flexFlow: 'column', gap: '10px' }, compactPanelProps === null || compactPanelProps === void 0 ? void 0 : compactPanelProps.contentStyle), children: [(0, size_1.default)(groupKeys) === 0 ?
1359
1798
  (0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { flat: true, opaque: false, size: 'small', children: "No fields match the current filters." })
1360
- : null, groupKeys.map(function (groupName) {
1361
- var names = grouped[groupName];
1362
- var groupConfig = groups === null || groups === void 0 ? void 0 : groups[groupName];
1363
- var invalidCount = names.filter(function (entry) {
1364
- var _a, _b, _c;
1365
- return !entry.hidden &&
1366
- !isOptionValid(entry.name, ((_a = options === null || options === void 0 ? void 0 : options[entry.name]) === null || _a === void 0 ? void 0 : _a.ui_type) ||
1367
- ((_b = options === null || options === void 0 ? void 0 : options[entry.name]) === null || _b === void 0 ? void 0 : _b.type), (_c = shownOptions[entry.name]) === null || _c === void 0 ? void 0 : _c.value);
1368
- }).length;
1369
- return ((0, jsx_runtime_1.jsxs)(reqore_1.ReqorePanel, { 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: 'big', children: (0, readFirst_1.getOptionGroupLabel)(groupName, groups) }), (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledGroupHeaderLine, { "$color": cGroupLine }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreButton, __assign({ readOnly: true, size: 'tiny', minimal: true, flat: true, compact: true, effect: { uppercase: true, spaced: 1 } }, (groupName === 'optional' ? { label: "".concat(names.length, " optional") }
1370
- : invalidCount ?
1371
- {
1372
- label: "".concat(invalidCount, " to resolve"),
1373
- intent: 'warning',
1374
- icon: 'ErrorWarningLine',
1375
- }
1376
- : {
1377
- label: 'All set',
1378
- intent: 'success',
1379
- icon: 'CheckLine',
1380
- })))] }), icon: groupConfig === null || groupConfig === void 0 ? void 0 : groupConfig.icon, className: 'options-readfirst-group', padded: false, contentStyle: { padding: '4px 4px 6px' }, children: [(groupConfig === null || groupConfig === void 0 ? void 0 : groupConfig.subtitle) ?
1381
- (0, jsx_runtime_1.jsx)(reqore_1.ReqoreP, { size: 'small', effect: { opacity: 0.6 },
1382
- // Indent to the same content line as the rows (StyledGroupBody's
1383
- // `margin-left` clamp) so the subtitle sits tucked under the group
1384
- // name instead of at the panel edge — and clears the group's
1385
- // vertical rule (left:16px) rather than crossing it.
1386
- style: {
1387
- marginTop: 2,
1388
- marginBottom: 8,
1389
- marginLeft: compactRowStyles_1.GROUP_INDENT,
1390
- paddingRight: 10,
1391
- }, children: groupConfig.subtitle })
1392
- : null, (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: renderGroupRows(names) })] }, groupName));
1393
- })] }), commitMode === 'batched' && !readOnly && dirtyOptionNames.length ?
1799
+ : null, STATUS_BOXES.map(function (box) {
1800
+ var groupsInBox = bucketGroups[box.key];
1801
+ var count = bucketCount(box.key);
1802
+ if (!count)
1803
+ return null;
1804
+ var accent = box.key === 'attention' ? cWarning
1805
+ : box.key === 'set' ? cSuccess
1806
+ : cMuted;
1807
+ // The muted "Optional" box reads as a quieter, recessed
1808
+ // surface a touch darker than the page rather than the
1809
+ // faint grey tint the accent would give.
1810
+ var boxBg = box.key === 'optional' ?
1811
+ (0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.06)
1812
+ : undefined;
1813
+ 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,
1814
+ // The Optional box now holds every not-yet-added field, so
1815
+ // it starts COLLAPSED to keep the form focused on what's in
1816
+ // use. But a SEARCH must surface matching addable fields —
1817
+ // and ReqorePanel unmounts collapsed content — so force it
1818
+ // open whenever a query is active. (isCollapsed is the
1819
+ // panel's controllable state; manual toggling still works
1820
+ // when no query is set.)
1821
+ 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) {
1822
+ var groupConfig = groups === null || groups === void 0 ? void 0 : groups[groupName];
1823
+ return ((0, jsx_runtime_1.jsxs)(react_2.default.Fragment, { children: [showGroupSubLabel(groupName) ?
1824
+ (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBoxGroupLabel, { children: (0, readFirst_1.getOptionGroupLabel)(groupName, groups) })
1825
+ : null, showGroupSubLabel(groupName) && (groupConfig === null || groupConfig === void 0 ? void 0 : groupConfig.subtitle) ?
1826
+ (0, jsx_runtime_1.jsx)(reqore_1.ReqoreP, { size: 'small', effect: { opacity: 0.6 }, style: {
1827
+ marginTop: 2,
1828
+ marginBottom: 8,
1829
+ marginLeft: compactRowStyles_1.GROUP_INDENT,
1830
+ paddingRight: 10,
1831
+ }, children: groupConfig.subtitle })
1832
+ : null, renderGroupRows(buckets[box.key][groupName])] }, groupName));
1833
+ }) }) }, box.key));
1834
+ })] })), commitMode === 'batched' && !readOnly && dirtyOptionNames.length ?
1394
1835
  (0, jsx_runtime_1.jsx)(StyledCommitDock, { "$bg": cBg, "$border": cDivider, children: (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreControlGroup, { className: 'options-readfirst-commitbar', verticalAlign: 'center', wrap: true, children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'tiny', minimal: true, flat: true, compact: true, effect: { uppercase: true, spaced: 1 }, intent: 'warning', icon: 'EditLine', label: "".concat(dirtyOptionNames.length, " unsaved change").concat(dirtyOptionNames.length === 1 ? '' : 's') }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreButton, { size: 'small', intent: 'success', icon: 'CheckLine', fixed: true, className: 'options-readfirst-save', disabled: !validityData.isValid, tooltip: validityData.isValid ?
1395
1836
  'Apply the staged changes'
1396
1837
  : 'Resolve the invalid fields before saving', onClick: handleCommitClick, children: "Save" }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreButton, { size: 'small', minimal: true, flat: true, fixed: true, icon: 'HistoryLine', className: 'options-readfirst-discard', onClick: handleRevertChangesClick, children: "Discard" })] }) })
@@ -1480,13 +1921,11 @@ var FormEngine = function (_a) {
1480
1921
  options[optionName].stretch,
1481
1922
  size: 'small',
1482
1923
  floatingActions: true,
1483
- actions: __spreadArray(__spreadArray([], (typeof optionActions === 'function' ?
1484
- optionActions({
1485
- name: optionName,
1486
- schema: options[optionName],
1487
- value: availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[optionName],
1488
- })
1489
- : (optionActions !== null && optionActions !== void 0 ? optionActions : [])), true), [
1924
+ actions: __spreadArray(__spreadArray([], (0, optionActions_1.resolveOptionActions)(optionActions, {
1925
+ name: optionName,
1926
+ schema: options[optionName],
1927
+ value: availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[optionName],
1928
+ }), true), [
1490
1929
  {
1491
1930
  size: 'tiny',
1492
1931
  icon: 'FullscreenLine',