@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
@@ -11,6 +11,7 @@
11
11
  import { StoryObj } from '@storybook/react-vite';
12
12
  import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
13
13
  import { useState } from 'react';
14
+ import { _testsClickButton, sleep } from '../../../stories/Tests/utils';
14
15
  import { StoryMeta } from '../../../types';
15
16
  import { FormEngine } from './FormEngine';
16
17
 
@@ -123,6 +124,14 @@ export const SchemaFromUrl: Story = {
123
124
  name: 'remoteBasic',
124
125
  url: 'sb-remote/basic',
125
126
  },
127
+ parameters: {
128
+ docs: {
129
+ description: {
130
+ story:
131
+ 'Renders FormEngine with a url — the options schema is fetched from options/{url}, three fields mount with the preselected localhost default seeded and onOptionsLoaded fires with the fetched schema.',
132
+ },
133
+ },
134
+ },
126
135
  async beforeEach() {
127
136
  return mockFetchRoutes({ 'options/sb-remote/basic': { body: BASIC_SCHEMA } });
128
137
  },
@@ -153,6 +162,14 @@ export const OperatorsFromUrl: Story = {
153
162
  hostname: { type: 'string', value: 'qore', op: ['like'] },
154
163
  } as any,
155
164
  },
165
+ parameters: {
166
+ docs: {
167
+ description: {
168
+ story:
169
+ 'Renders FormEngine with both url and operatorsUrl — the operator select resolves the "like" op against the fetched operator schema and the WHERE/IS summary tags appear alongside the option.',
170
+ },
171
+ },
172
+ },
156
173
  async beforeEach() {
157
174
  return mockFetchRoutes({
158
175
  'options/sb-remote/search': { body: SEARCH_SCHEMA },
@@ -181,6 +198,14 @@ export const FetchFailure: Story = {
181
198
  name: 'remoteFail',
182
199
  url: 'sb-remote/fail',
183
200
  },
201
+ parameters: {
202
+ docs: {
203
+ description: {
204
+ story:
205
+ 'Renders FormEngine when the schema fetch returns 500 — the skeleton resolves into the "No options available" empty state instead of crashing.',
206
+ },
207
+ },
208
+ },
184
209
  async beforeEach() {
185
210
  return mockFetchRoutes({
186
211
  'options/sb-remote/fail': { status: 500, body: { err: 'boom' } },
@@ -202,6 +227,14 @@ export const UrlChangeResetsValue: Story = {
202
227
  name: 'remoteSwitch',
203
228
  url: 'sb-remote/first',
204
229
  },
230
+ parameters: {
231
+ docs: {
232
+ description: {
233
+ story:
234
+ 'Renders FormEngine wired to url="first". Clicking the switch button re-points the engine to a different schema — the previous value (localhost) is dropped and the new Token field mounts.',
235
+ },
236
+ },
237
+ },
205
238
  render(args) {
206
239
  const [url, setUrl] = useState(args.url);
207
240
  return (
@@ -256,6 +289,14 @@ export const InjectedOptionActions: Story = {
256
289
  },
257
290
  ],
258
291
  },
292
+ parameters: {
293
+ docs: {
294
+ description: {
295
+ story:
296
+ 'Renders FormEngine with an optionActions factory that injects a per-option AI-assist button. Hovering an option reveals the injected action next to it.',
297
+ },
298
+ },
299
+ },
259
300
  async play() {
260
301
  await waitFor(() => expect(optionCount()).toBe(3), { timeout: 10000 });
261
302
 
@@ -267,6 +308,334 @@ export const InjectedOptionActions: Story = {
267
308
  },
268
309
  };
269
310
 
311
+ /**
312
+ * The same injected actions seam must also work in compact/read-first mode. The
313
+ * IDE uses this path for option-based forms and relies on the action slot for
314
+ * small per-field Qonsole controls.
315
+ */
316
+ export const InjectedCompactOptionActions: Story = {
317
+ args: {
318
+ name: 'compactOptionActionsSeam',
319
+ compact: true,
320
+ options: BASIC_SCHEMA as any,
321
+ optionActions: ({ name }) => [
322
+ {
323
+ icon: 'MagicLine',
324
+ className: 'option-compact-ai-assist',
325
+ tooltip: `AI assistance for ${name}`,
326
+ // The shape the IDE passes on the classic path — hover-gated here too.
327
+ show: 'hover',
328
+ size: 'tiny',
329
+ fixed: true,
330
+ },
331
+ {
332
+ icon: 'InformationLine',
333
+ className: 'option-compact-always',
334
+ tooltip: `Details for ${name}`,
335
+ size: 'tiny',
336
+ fixed: true,
337
+ },
338
+ ],
339
+ },
340
+ parameters: {
341
+ docs: {
342
+ description: {
343
+ story:
344
+ 'Renders compact FormEngine rows with two injected per-option actions: one always visible, one declared `show: "hover"` that stays transparent until its row is hovered or focused. Hover-gating applies only where the pointer can hover — on touch both collapse into the row\'s overflow menu instead, so neither is ever hover-only.',
345
+ },
346
+ },
347
+ },
348
+ async play() {
349
+ await waitFor(
350
+ () => expect(document.querySelectorAll('.readfirst-row').length).toBeGreaterThan(0),
351
+ { timeout: 10000 }
352
+ );
353
+
354
+ const rowCount = document.querySelectorAll('.readfirst-row').length;
355
+
356
+ await waitFor(() => {
357
+ expect(document.querySelectorAll('.option-compact-always').length).toBe(rowCount);
358
+ expect(document.querySelectorAll('.option-compact-ai-assist').length).toBe(rowCount);
359
+ });
360
+
361
+ // The hover-only action carries the CSS gate; the always-on one does not.
362
+ const hoverAction = document.querySelector(
363
+ '.option-compact-ai-assist.options-injected-action-hover'
364
+ ) as HTMLElement;
365
+ expect(hoverAction).toBeTruthy();
366
+ expect(
367
+ document.querySelectorAll('.option-compact-always.options-injected-action-hover').length
368
+ ).toBe(0);
369
+
370
+ // Actually exercise the reveal condition rather than just asserting the
371
+ // class is present: gated the action is transparent and not hit-testable.
372
+ expect(getComputedStyle(hoverAction).opacity).toBe('0');
373
+ expect(getComputedStyle(hoverAction).pointerEvents).toBe('none');
374
+
375
+ // Focus is the reveal path a test can drive: the gate keys on
376
+ // `:hover, :focus-within`, and a synthetic mouse event does NOT put a real
377
+ // browser into `:hover`. Focusing the action is also the keyboard route a
378
+ // user takes, so this covers the accessibility path at the same time.
379
+ hoverAction.focus();
380
+ await waitFor(() => {
381
+ expect(getComputedStyle(hoverAction).opacity).toBe('1');
382
+ expect(getComputedStyle(hoverAction).pointerEvents).toBe('auto');
383
+ });
384
+
385
+ // Left revealed so the captured frame shows the action rather than an
386
+ // empty slot — the whole point of the story.
387
+ await sleep(200);
388
+ },
389
+ };
390
+
391
+ /**
392
+ * The no-hover case. A touch device never fires `:hover`, so a hover-gated
393
+ * action would be permanently unreachable; instead every injected action moves
394
+ * into the row's own overflow menu. `optionActionsCollapse='always'` forces the
395
+ * branch that `(hover: none)`/`(pointer: coarse)` picks on a real phone, which a
396
+ * desktop browser cannot emulate.
397
+ */
398
+ export const InjectedCompactOptionActionsMobile: Story = {
399
+ args: {
400
+ name: 'compactOptionActionsMobile',
401
+ compact: true,
402
+ options: BASIC_SCHEMA as any,
403
+ optionActionsCollapse: 'always',
404
+ optionActions: ({ name }) => [
405
+ {
406
+ icon: 'MagicLine',
407
+ className: 'option-compact-ai-assist',
408
+ tooltip: `AI assistance for ${name}`,
409
+ show: 'hover',
410
+ size: 'tiny',
411
+ fixed: true,
412
+ },
413
+ {
414
+ icon: 'InformationLine',
415
+ className: 'option-compact-always',
416
+ tooltip: `Details for ${name}`,
417
+ size: 'tiny',
418
+ fixed: true,
419
+ },
420
+ ],
421
+ },
422
+ parameters: {
423
+ qlip: { viewport: { width: 420, height: 900 } },
424
+ docs: {
425
+ description: {
426
+ story:
427
+ 'Renders the compact rows at phone width with injected actions collapsed into each row\'s overflow menu — the no-hover path, where a hover-gated button would otherwise be unreachable. The menu is opened so the actions are visible.',
428
+ },
429
+ },
430
+ },
431
+ async play() {
432
+ await waitFor(
433
+ () => expect(document.querySelectorAll('.readfirst-row').length).toBeGreaterThan(0),
434
+ { timeout: 10000 }
435
+ );
436
+
437
+ // Collapsed: no inline injected buttons at all, one overflow menu per row.
438
+ const rowCount = document.querySelectorAll('.readfirst-row').length;
439
+ await waitFor(() => {
440
+ expect(document.querySelectorAll('.options-injected-actions-menu').length).toBe(rowCount);
441
+ });
442
+ expect(document.querySelectorAll('.option-compact-ai-assist').length).toBe(0);
443
+ expect(document.querySelectorAll('.option-compact-always').length).toBe(0);
444
+
445
+ // Both actions are reachable from the menu — the reason the collapse exists.
446
+ await _testsClickButton({ selector: '.options-injected-actions-menu', nth: 0 });
447
+ await waitFor(
448
+ () => {
449
+ const labels = Array.from(document.querySelectorAll('.reqore-menu-item')).map(
450
+ (item) => item.textContent ?? ''
451
+ );
452
+ expect(labels.some((label) => label.includes('AI assistance for'))).toBe(true);
453
+ expect(labels.some((label) => label.includes('Details for'))).toBe(true);
454
+ },
455
+ { timeout: 10000 }
456
+ );
457
+ },
458
+ };
459
+
460
+ /**
461
+ * Many injected actions. Beyond the inline cap the extras overflow into the
462
+ * row's menu instead of squeezing the value out of the row, so a consumer can
463
+ * inject any number without breaking the layout.
464
+ */
465
+ export const InjectedCompactOptionActionsMany: Story = {
466
+ args: {
467
+ name: 'compactOptionActionsMany',
468
+ compact: true,
469
+ options: BASIC_SCHEMA as any,
470
+ optionActions: ({ name }) =>
471
+ ['MagicLine', 'InformationLine', 'FileCopyLine', 'DeleteBinLine', 'ShareLine'].map(
472
+ (icon, index) => ({
473
+ icon: icon as any,
474
+ className: `option-compact-many-${index}`,
475
+ tooltip: `${icon} for ${name}`,
476
+ size: 'tiny',
477
+ fixed: true,
478
+ })
479
+ ),
480
+ },
481
+ parameters: {
482
+ docs: {
483
+ description: {
484
+ story:
485
+ 'Renders the compact rows with five injected actions per option — the first two stay inline and the remaining three collapse into the row\'s overflow menu, which is opened here to show them.',
486
+ },
487
+ },
488
+ },
489
+ async play() {
490
+ await waitFor(
491
+ () => expect(document.querySelectorAll('.readfirst-row').length).toBeGreaterThan(0),
492
+ { timeout: 10000 }
493
+ );
494
+
495
+ const rowCount = document.querySelectorAll('.readfirst-row').length;
496
+
497
+ // Only the first two render inline; the rest are in the menu.
498
+ await waitFor(() => {
499
+ expect(document.querySelectorAll('.option-compact-many-0').length).toBe(rowCount);
500
+ expect(document.querySelectorAll('.option-compact-many-1').length).toBe(rowCount);
501
+ });
502
+ expect(document.querySelectorAll('.option-compact-many-2').length).toBe(0);
503
+ expect(document.querySelectorAll('.option-compact-many-4').length).toBe(0);
504
+ expect(document.querySelectorAll('.options-injected-actions-menu').length).toBe(rowCount);
505
+
506
+ await _testsClickButton({ selector: '.options-injected-actions-menu', nth: 0 });
507
+ await waitFor(
508
+ () => {
509
+ const labels = Array.from(document.querySelectorAll('.reqore-menu-item')).map(
510
+ (item) => item.textContent ?? ''
511
+ );
512
+ expect(labels.some((label) => label.includes('DeleteBinLine for'))).toBe(true);
513
+ expect(labels.some((label) => label.includes('ShareLine for'))).toBe(true);
514
+ },
515
+ { timeout: 10000 }
516
+ );
517
+ },
518
+ };
519
+
520
+ // A compact row renders the SAME logical state three ways — the read row, the
521
+ // inline editor, and the edit card (complex types get the card). An injected
522
+ // action has to survive all three, and per the affordance-parity rule each
523
+ // branch needs its own story: the branch without one is where a dead action
524
+ // hides, because the branch under test is the branch that works.
525
+ const BRANCH_SCHEMA = {
526
+ host: {
527
+ type: 'string',
528
+ display_name: 'Host',
529
+ short_desc: 'Edits inline inside the row',
530
+ preselected: true,
531
+ default_value: 'localhost',
532
+ },
533
+ notes: {
534
+ type: 'string',
535
+ ui_type: 'long-string',
536
+ display_name: 'Notes',
537
+ short_desc: 'A complex type — edits in the card branch',
538
+ preselected: true,
539
+ // Needs a value: an empty optional field sits in the collapsed "Optional"
540
+ // group, where `initialExpandedOptions` has nothing to open.
541
+ default_value: 'Notes that are long enough to want the card editor.',
542
+ },
543
+ };
544
+
545
+ const branchAction = ({ name }: { name: string }) => [
546
+ {
547
+ icon: 'MagicLine' as const,
548
+ className: 'option-branch-action',
549
+ tooltip: `AI assistance for ${name}`,
550
+ size: 'tiny' as const,
551
+ fixed: true,
552
+ },
553
+ ];
554
+
555
+ /**
556
+ * Branch 1 of 3: the INLINE editor. A simple type opens inside the row itself,
557
+ * and the injected action has to be reachable there, not just on the read row.
558
+ */
559
+ export const InjectedOptionActionsInlineEditing: Story = {
560
+ args: {
561
+ name: 'compactOptionActionsInline',
562
+ compact: true,
563
+ options: BRANCH_SCHEMA as any,
564
+ initialExpandedOptions: ['host'],
565
+ optionActions: branchAction,
566
+ },
567
+ parameters: {
568
+ docs: {
569
+ description: {
570
+ story:
571
+ 'Renders the compact form with the simple `host` field already open, so it edits inline inside the row — the injected per-option action is asserted inside that inline branch.',
572
+ },
573
+ },
574
+ },
575
+ async play() {
576
+ await waitFor(
577
+ () => expect(document.querySelector('.readfirst-row-editing')).toBeTruthy(),
578
+ { timeout: 10000 }
579
+ );
580
+
581
+ // Scoped to the branch on purpose: a global query would pass on the read
582
+ // row's copy and prove nothing about the inline editor.
583
+ const injected = await waitFor(() => {
584
+ const el = document.querySelector(
585
+ '.readfirst-row-editing .option-branch-action'
586
+ ) as HTMLElement;
587
+ expect(el).toBeTruthy();
588
+ return el;
589
+ });
590
+
591
+ // The injected action must match the size of the row's own actions. The
592
+ // fixture deliberately asks for `size: 'tiny'` — the row overrides it,
593
+ // because a consumer-sized button rendered visibly smaller than the revert
594
+ // and More buttons beside it (qlip build #57 rejection).
595
+ const neighbour = document.querySelector(
596
+ '.readfirst-row-editing .options-readfirst-more'
597
+ ) as HTMLElement;
598
+ expect(neighbour).toBeTruthy();
599
+ expect(injected.getBoundingClientRect().height).toBe(
600
+ neighbour.getBoundingClientRect().height
601
+ );
602
+ },
603
+ };
604
+
605
+ /**
606
+ * Branch 2 of 3: the EDIT CARD. A complex type (`long-string`) is too tall to
607
+ * edit in-row, so it opens as a card — a different subtree, and historically
608
+ * where an action wired only in the other branch went missing.
609
+ */
610
+ export const InjectedOptionActionsEditCard: Story = {
611
+ args: {
612
+ name: 'compactOptionActionsCard',
613
+ compact: true,
614
+ options: BRANCH_SCHEMA as any,
615
+ initialExpandedOptions: ['notes'],
616
+ optionActions: branchAction,
617
+ },
618
+ parameters: {
619
+ docs: {
620
+ description: {
621
+ story:
622
+ 'Renders the compact form with the complex `notes` field already open, so it edits in the card branch rather than in-row — the injected per-option action is asserted inside that card.',
623
+ },
624
+ },
625
+ },
626
+ async play() {
627
+ await waitFor(() => expect(document.querySelector('.options-readfirst-card')).toBeTruthy(), {
628
+ timeout: 10000,
629
+ });
630
+
631
+ await waitFor(() => {
632
+ expect(
633
+ document.querySelector('.options-readfirst-card .option-branch-action')
634
+ ).toBeTruthy();
635
+ });
636
+ },
637
+ };
638
+
270
639
  /**
271
640
  * Opt-in template fetching: `interfaceContext` makes `useTemplates` fetch
272
641
  * `system/getContextData` (the IDE's behavior); without it, no request is
@@ -278,6 +647,14 @@ export const TemplatesFromContext: Story = {
278
647
  options: BASIC_SCHEMA as any,
279
648
  interfaceContext: 'sb-ctx',
280
649
  },
650
+ parameters: {
651
+ docs: {
652
+ description: {
653
+ story:
654
+ 'Renders FormEngine with an interfaceContext — useTemplates hits system/getContextData so template values are available in the schema fields.',
655
+ },
656
+ },
657
+ },
281
658
  async beforeEach() {
282
659
  return mockFetchRoutes({
283
660
  'system/getContextData': {
@@ -57,6 +57,14 @@ export const WorkflowOrderData: Story = {
57
57
  // Expand deep enough that the parsed-YAML sub-tree is visible.
58
58
  defaultExpandDepth: 3,
59
59
  },
60
+ parameters: {
61
+ docs: {
62
+ description: {
63
+ story:
64
+ 'Renders StructuredDataView over a workflow-order payload — UI-encoded envelopes unwrap to scalars, embedded YAML strings parse into sub-trees and Qorus timestamps format to YYYY-MM-DD HH:mm:ss.SSS in the viewer\'s zone.',
65
+ },
66
+ },
67
+ },
60
68
  play: async () => {
61
69
  await _testsWaitForText('ORD-1002');
62
70
  await _testsWaitForText('order-process');
@@ -9,6 +9,7 @@ import {
9
9
  import { MutableRefObject } from 'react';
10
10
  import { createContext } from 'use-context-selector';
11
11
  import { IOperatorsSchema } from './FormEngine';
12
+ import { TOptionActions } from './optionActions';
12
13
 
13
14
  /**
14
15
  * The complete closure surface of the (former) `renderCompactRow` function,
@@ -34,6 +35,12 @@ export interface ICompactRowContext {
34
35
  // display name in the read-first chip.
35
36
  templates?: IReqoreFormTemplates;
36
37
  expandedOptions: string[];
38
+ // Name of the field the engine expanded programmatically for
39
+ // `autoFocusFirstRequired`. CompactRow focuses this one with `preventScroll`
40
+ // so an off-screen / below-the-fold form is never scrolled into view on
41
+ // mount. A ref (not state) so it's current when the 60ms focus timer fires,
42
+ // regardless of render batching.
43
+ autoFocusNameRef?: MutableRefObject<string | undefined>;
37
44
  highlightedOptions: string[];
38
45
  flashedOptions: string[];
39
46
  infoPanelOverrides: Record<string, boolean>;
@@ -68,6 +75,13 @@ export interface ICompactRowContext {
68
75
 
69
76
  // Function passed through as a value (stays defined in FormEngine because the
70
77
  // classic non-compact path uses it too).
78
+ optionActions?: TOptionActions;
79
+ /**
80
+ * Injected actions render inside the row's overflow menu instead of as inline
81
+ * buttons. True on touch (where a hover-gated button is unreachable) and on
82
+ * narrow viewports. Resolved once by FormEngine so rows share one subscription.
83
+ */
84
+ collapseOptionActions?: boolean;
71
85
  renderOption: (
72
86
  optionName: string,
73
87
  field: IQorusFormField,