@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
@@ -50,6 +50,14 @@ export const Object: Story = {
50
50
  dataType: 'json',
51
51
  resultDataType: 'json',
52
52
  },
53
+ parameters: {
54
+ docs: {
55
+ description: {
56
+ story:
57
+ 'Renders the Object field in JSON object mode with no value. Clicking "New Object" seeds an empty JSON object in the editor.',
58
+ },
59
+ },
60
+ },
53
61
  async play() {
54
62
  await testsWaitForText('New Object');
55
63
  await testsClickButton({ label: 'New Object' });
@@ -64,6 +72,14 @@ export const List: Story = {
64
72
  dataType: 'yaml',
65
73
  resultDataType: 'yaml',
66
74
  },
75
+ parameters: {
76
+ docs: {
77
+ description: {
78
+ story:
79
+ 'Renders the Object field in YAML list mode with no value. Clicking "New List" seeds an empty list in the editor.',
80
+ },
81
+ },
82
+ },
67
83
  async play() {
68
84
  await testsWaitForText('New List');
69
85
  await testsClickButton({ label: 'New List' });
@@ -79,6 +95,14 @@ export const Disabled: Story = {
79
95
  resultDataType: 'native',
80
96
  disabled: true,
81
97
  },
98
+ parameters: {
99
+ docs: {
100
+ description: {
101
+ story:
102
+ 'Renders the Object field in native-array mode but disabled — the field is visible and non-interactive.',
103
+ },
104
+ },
105
+ },
82
106
  };
83
107
 
84
108
  export const Small: Story = {
@@ -96,6 +120,14 @@ export const Small: Story = {
96
120
  false,
97
121
  ],
98
122
  },
123
+ parameters: {
124
+ docs: {
125
+ description: {
126
+ story:
127
+ 'Renders the Object field in native-array mode at "small" size with mixed item types — object, string, number and boolean.',
128
+ },
129
+ },
130
+ },
99
131
  };
100
132
 
101
133
  export const DisabledWithValue: Story = {
@@ -113,6 +145,14 @@ export const DisabledWithValue: Story = {
113
145
  ],
114
146
  disabled: true,
115
147
  },
148
+ parameters: {
149
+ docs: {
150
+ description: {
151
+ story:
152
+ 'Renders the Object field in native-array mode with a populated value but disabled — the items are visible in read-only form.',
153
+ },
154
+ },
155
+ },
116
156
  };
117
157
 
118
158
  export const NativeOnly: Story = {
@@ -129,6 +169,14 @@ export const NativeOnly: Story = {
129
169
  false,
130
170
  ],
131
171
  },
172
+ parameters: {
173
+ docs: {
174
+ description: {
175
+ story:
176
+ 'Renders the Object field in native-array mode with mixed item types — the native editor shows the items without a YAML/JSON textarea alternative.',
177
+ },
178
+ },
179
+ },
132
180
  async play() {
133
181
  await testsWaitForText('"value"');
134
182
  },
@@ -148,6 +196,14 @@ export const ValueCanBeRemoved: Story = {
148
196
  false,
149
197
  ],
150
198
  },
199
+ parameters: {
200
+ docs: {
201
+ description: {
202
+ story:
203
+ 'Renders the Object field with a populated native array. Clicking Remove clears the value and the field falls back to the "New List" placeholder.',
204
+ },
205
+ },
206
+ },
151
207
  async play() {
152
208
  await testsWaitForText('"value"');
153
209
  await testsClickButton({ label: 'Remove' });
@@ -166,6 +222,14 @@ export const Json: Story = {
166
222
  }),
167
223
  resultDataType: 'json',
168
224
  },
225
+ parameters: {
226
+ docs: {
227
+ description: {
228
+ story:
229
+ 'Renders the Object field with a JSON string value. Switching to Text mode, editing the JSON and clicking Save fires onChange with the new JSON serialization.',
230
+ },
231
+ },
232
+ },
169
233
  async play({ args }) {
170
234
  await testsWaitForText('"value"');
171
235
  await testsClickButton({ label: 'Text' });
@@ -213,6 +277,14 @@ export const Yaml: Story = {
213
277
  }),
214
278
  resultDataType: 'yaml',
215
279
  },
280
+ parameters: {
281
+ docs: {
282
+ description: {
283
+ story:
284
+ 'Renders the Object field with a YAML string value. Switching to Text mode, editing the YAML and clicking Save fires onChange with the new YAML serialization.',
285
+ },
286
+ },
287
+ },
216
288
  async play({ args }) {
217
289
  await testsWaitForText('"value"');
218
290
  await testsClickButton({ label: 'Text' });
@@ -247,6 +319,14 @@ export const YamlToJson: Story = {
247
319
  }),
248
320
  resultDataType: 'json',
249
321
  },
322
+ parameters: {
323
+ docs: {
324
+ description: {
325
+ story:
326
+ 'Renders the Object field with a YAML input value and JSON output — editing the YAML in Text mode and saving fires onChange with the equivalent JSON string.',
327
+ },
328
+ },
329
+ },
250
330
  async play({ args }) {
251
331
  await testsWaitForText('"value"');
252
332
  await testsClickButton({ label: 'Text' });
@@ -281,6 +361,14 @@ export const NativeToYaml: Story = {
281
361
  },
282
362
  resultDataType: 'yaml',
283
363
  },
364
+ parameters: {
365
+ docs: {
366
+ description: {
367
+ story:
368
+ 'Renders the Object field with a native object value and YAML output — editing in Text mode and saving fires onChange with the YAML serialization.',
369
+ },
370
+ },
371
+ },
284
372
  async play({ args }) {
285
373
  await testsWaitForText('"value"');
286
374
  await testsClickButton({ label: 'Text' });
@@ -42,6 +42,14 @@ export const Default: Story = {
42
42
  { label: 'Python', value: 'Python', 'aria-label': 'Python' },
43
43
  ],
44
44
  },
45
+ parameters: {
46
+ docs: {
47
+ description: {
48
+ story:
49
+ 'Renders the RadioGroup field with three language options and "Qore" pre-selected. Clicking a different option fires onChange with the new value.',
50
+ },
51
+ },
52
+ },
45
53
  async play({ canvasElement, args }) {
46
54
  const canvas = within(canvasElement);
47
55
  const java = canvas.getByLabelText('Java');
@@ -59,6 +67,14 @@ export const WithImages: Story = {
59
67
  { label: 'Python', value: 'Python', image: python },
60
68
  ],
61
69
  },
70
+ parameters: {
71
+ docs: {
72
+ description: {
73
+ story:
74
+ 'Renders the RadioGroup field with three language options — each option displays its language logo alongside the label.',
75
+ },
76
+ },
77
+ },
62
78
  async play({ canvasElement }) {
63
79
  await expect(canvasElement.querySelector(`img[src="${qore}"]`)).toBeInTheDocument();
64
80
  await expect(canvasElement.querySelector(`img[src="${java}"]`)).toBeInTheDocument();
@@ -68,4 +84,12 @@ export const WithImages: Story = {
68
84
 
69
85
  export const Disabled: Story = {
70
86
  args: { ...Default.args, disabled: true },
87
+ parameters: {
88
+ docs: {
89
+ description: {
90
+ story:
91
+ 'Renders the RadioGroup field with three language options but disabled — the group is visible and non-interactive.',
92
+ },
93
+ },
94
+ },
71
95
  };
@@ -33,6 +33,14 @@ export const WithValue: Story = {
33
33
  args: {
34
34
  value: 'Hello world',
35
35
  },
36
+ parameters: {
37
+ docs: {
38
+ description: {
39
+ story:
40
+ 'Renders the RichText field pre-populated with the plain-string value "Hello world" — the editor mounts with the text rendered as a paragraph.',
41
+ },
42
+ },
43
+ },
36
44
  async play({ canvasElement }) {
37
45
  const canvas = within(canvasElement);
38
46
  // Only assert on render — typing assertions would need waitFor due to debounce
@@ -42,6 +50,13 @@ export const WithValue: Story = {
42
50
  };
43
51
 
44
52
  export const Empty: Story = {
53
+ parameters: {
54
+ docs: {
55
+ description: {
56
+ story: 'Renders the RichText field with no value — the editor mounts empty.',
57
+ },
58
+ },
59
+ },
45
60
  async play({ canvasElement }) {
46
61
  const canvas = within(canvasElement);
47
62
  await expect(canvas.getByRole('textbox')).toBeInTheDocument();
@@ -52,6 +67,14 @@ export const WithSlateValue: Story = {
52
67
  args: {
53
68
  value: [{ type: 'paragraph', children: [{ text: 'Rich text with Slate format' }] }],
54
69
  },
70
+ parameters: {
71
+ docs: {
72
+ description: {
73
+ story:
74
+ 'Renders the RichText field pre-populated with a Slate document rather than a plain string — the editor mounts with the paragraph node rendered as text.',
75
+ },
76
+ },
77
+ },
55
78
  async play({ canvasElement }) {
56
79
  const canvas = within(canvasElement);
57
80
  await expect(canvas.getByRole('textbox')).toBeInTheDocument();
@@ -40,6 +40,14 @@ type Story = StoryObj<typeof meta>;
40
40
  /** Empty definition — the catalogue drives the full tab set. */
41
41
  export const Empty: Story = {
42
42
  args: {},
43
+ parameters: {
44
+ docs: {
45
+ description: {
46
+ story:
47
+ 'Renders the SchemaDefinition editor with no existing value — the Schema, Tables, Sequences and Migrations tabs mount straight from the catalogue.',
48
+ },
49
+ },
50
+ },
43
51
  async play({ canvasElement }) {
44
52
  const canvas = within(canvasElement);
45
53
  // Tabs come straight from the catalogue's `definition` sections.
@@ -59,6 +67,14 @@ export const Starter: Story = {
59
67
  args: {
60
68
  value: starterDefinition,
61
69
  },
70
+ parameters: {
71
+ docs: {
72
+ description: {
73
+ story:
74
+ 'Renders the SchemaDefinition editor seeded with the "example_schema" starter template — the Schema tab shows the single scaffolded table.',
75
+ },
76
+ },
77
+ },
62
78
  };
63
79
 
64
80
  /** A realistic populated schema — two tables, sequence, reference data, migrations. */
@@ -66,6 +82,14 @@ export const Populated: Story = {
66
82
  args: {
67
83
  value: mockPopulatedDefinition,
68
84
  },
85
+ parameters: {
86
+ docs: {
87
+ description: {
88
+ story:
89
+ 'Renders the SchemaDefinition editor with the populated fixture. Opening the Tables tab shows the customers and addresses tables.',
90
+ },
91
+ },
92
+ },
69
93
  async play({ canvasElement }) {
70
94
  const canvas = within(canvasElement);
71
95
  // Open the Tables tab → the two table panels render from the value.
@@ -81,6 +105,14 @@ export const ReadOnly: Story = {
81
105
  value: mockPopulatedDefinition,
82
106
  readOnly: true,
83
107
  },
108
+ parameters: {
109
+ docs: {
110
+ description: {
111
+ story:
112
+ 'Renders the SchemaDefinition editor with readOnly enabled — every input becomes a typeset display row and no inputs, textareas or selects are rendered.',
113
+ },
114
+ },
115
+ },
84
116
  async play({ canvasElement }) {
85
117
  const canvas = within(canvasElement);
86
118
  await expect(await canvas.findByText('Schema')).toBeInTheDocument();
@@ -94,6 +126,14 @@ export const CatalogError: Story = {
94
126
  args: {
95
127
  catalogError: 'Schema options are unavailable on this server.',
96
128
  },
129
+ parameters: {
130
+ docs: {
131
+ description: {
132
+ story:
133
+ 'Renders the SchemaDefinition editor when the catalogue fetch fails — a "Could not load schema options" callout replaces the form.',
134
+ },
135
+ },
136
+ },
97
137
  async play({ canvasElement }) {
98
138
  const canvas = within(canvasElement);
99
139
  await expect(await canvas.findByText('Could not load schema options')).toBeInTheDocument();
@@ -106,6 +146,14 @@ export const CatalogError: Story = {
106
146
  * wired. `catalogOverride` rides in via `fieldProps`.
107
147
  */
108
148
  export const ViaFormField: Story = {
149
+ parameters: {
150
+ docs: {
151
+ description: {
152
+ story:
153
+ 'Renders the SchemaDefinition editor through the FormField dispatcher (type="schema-definition"). The catalogue is injected via fieldProps and the Schema and Tables tabs mount as usual.',
154
+ },
155
+ },
156
+ },
109
157
  render: () => {
110
158
  const [value, setValue] = useState<IDataSchemaDefinition | undefined>(mockPopulatedDefinition);
111
159
  return (
@@ -132,6 +180,14 @@ export const ViaFormField: Story = {
132
180
  * → FormField → SchemaDefinitionEditor).
133
181
  */
134
182
  export const ViaFormEngineUiType: Story = {
183
+ parameters: {
184
+ docs: {
185
+ description: {
186
+ story:
187
+ 'Renders a FormEngine schema whose "definition" option declares ui_type: schema-definition — FormEngine flows through TemplateField and FormField and mounts the schema editor with the injected catalogue.',
188
+ },
189
+ },
190
+ },
135
191
  render: () => {
136
192
  const [value, setValue] = useState<any>({
137
193
  definition: { type: 'hash', value: mockPopulatedDefinition },
@@ -177,6 +233,14 @@ export const Sandboxed: Story = {
177
233
  wrapperName: 'example_customer_addresses',
178
234
  value: mockPopulatedDefinition,
179
235
  },
236
+ parameters: {
237
+ docs: {
238
+ description: {
239
+ story:
240
+ 'Renders the SchemaDefinition editor for an untrusted (sandboxed) caller using the sandboxed catalogue — the Advanced tab and every trusted-only section are hidden.',
241
+ },
242
+ },
243
+ },
180
244
  async play({ canvasElement }) {
181
245
  const canvas = within(canvasElement);
182
246
  await expect(await canvas.findByText('Migrations')).toBeInTheDocument();
@@ -195,6 +259,14 @@ export const WithValidationBanner: Story = {
195
259
  wrapperName: 'renamed_schema',
196
260
  value: mockPopulatedDefinition,
197
261
  },
262
+ parameters: {
263
+ docs: {
264
+ description: {
265
+ story:
266
+ 'Renders the SchemaDefinition editor when the wrapper interface name and the DataSchema name differ — the "name does not match" banner is shown, and clicking "Sync name" resolves the mismatch.',
267
+ },
268
+ },
269
+ },
198
270
  async play({ canvasElement }) {
199
271
  const canvas = within(canvasElement);
200
272
  // The banner renders the mismatch both as its title and its body text.
@@ -35,6 +35,14 @@ export const Items: Story = {
35
35
  { display_name: 'Item 2', value: 'item2' },
36
36
  ],
37
37
  },
38
+ parameters: {
39
+ docs: {
40
+ description: {
41
+ story:
42
+ 'Renders the Select field with two simple items and no value. Clicking the trigger opens the popover with the item list.',
43
+ },
44
+ },
45
+ },
38
46
  async play({ canvasElement }) {
39
47
  const canvas = within(canvasElement);
40
48
  await fireEvent.click(canvas.getByRole('button'));
@@ -45,7 +53,16 @@ export const Items: Story = {
45
53
  };
46
54
 
47
55
  export const ItemsWithDescription: Story = {
56
+ parameters: {
57
+ docs: {
58
+ description: {
59
+ story:
60
+ 'Renders the Select field with twenty items, each carrying a description, icon or image. Opening the picker mounts a modal collection with all twenty entries.',
61
+ },
62
+ },
63
+ },
48
64
  args: {
65
+ forceDropdown: false,
49
66
  items: [
50
67
  { display_name: 'Item 1', desc: 'This is item 1', value: 'item1', icon: 'MoneyEuroCircleFill', groups: ['Miscellaneous'] },
51
68
  { display_name: 'Item 2', desc: 'This is item 2', value: 'item2', image: 'https://avatars.githubusercontent.com/u/8861481?v=4' },
@@ -81,7 +98,16 @@ export const ItemsWithDescription: Story = {
81
98
  };
82
99
 
83
100
  export const ItemsWithDescriptionAndMessages: Story = {
101
+ parameters: {
102
+ docs: {
103
+ description: {
104
+ story:
105
+ 'Renders the Select field with two items that carry inline messages of different intents. The picker modal shows the messages beneath each item.',
106
+ },
107
+ },
108
+ },
84
109
  args: {
110
+ forceDropdown: false,
85
111
  items: [
86
112
  {
87
113
  display_name: 'Item 1',
@@ -121,6 +147,14 @@ export const DisabledItemsWithIntent: Story = {
121
147
  { display_name: 'Disabled Item with Intent', intent: 'danger', disabled: true, value: 'item5' },
122
148
  ],
123
149
  },
150
+ parameters: {
151
+ docs: {
152
+ description: {
153
+ story:
154
+ 'Renders the Select field with a mix of enabled, disabled and intent-tagged items — the disabled entries are non-interactive while success/danger items carry their intent styling.',
155
+ },
156
+ },
157
+ },
124
158
  async play({ canvasElement }) {
125
159
  const canvas = within(canvasElement);
126
160
  await fireEvent.click(canvas.getByRole('button'));
@@ -130,6 +164,7 @@ export const DisabledItemsWithIntent: Story = {
130
164
 
131
165
  export const DisabledItemsWithIntentAndDescriptions: Story = {
132
166
  args: {
167
+ forceDropdown: false,
133
168
  items: [
134
169
  { display_name: 'Item 1', desc: 'This is item 1', value: 'item1' },
135
170
  { display_name: 'Item 2', short_desc: 'This is item 2', value: 'item2' },
@@ -138,6 +173,14 @@ export const DisabledItemsWithIntentAndDescriptions: Story = {
138
173
  { display_name: 'Disabled Item with Intent', intent: 'danger', disabled: true, short_desc: 'This is item 5', value: 'item5' },
139
174
  ],
140
175
  },
176
+ parameters: {
177
+ docs: {
178
+ description: {
179
+ story:
180
+ 'Renders the Select field with five items mixing intents, descriptions and disabled states — the picker modal shows all five so their combined presentation can be reviewed.',
181
+ },
182
+ },
183
+ },
141
184
  async play({ canvasElement }) {
142
185
  const canvas = within(canvasElement);
143
186
  await fireEvent.click(canvas.getByRole('button'));
@@ -157,6 +200,14 @@ export const WithValue: Story = {
157
200
  { display_name: 'Item 2', value: 'item2' },
158
201
  ],
159
202
  },
203
+ parameters: {
204
+ docs: {
205
+ description: {
206
+ story:
207
+ 'Renders the Select field with two items and item2 pre-selected — the trigger shows the selected label and clicking it opens the popover.',
208
+ },
209
+ },
210
+ },
160
211
  async play({ canvasElement }) {
161
212
  const canvas = within(canvasElement);
162
213
  await expect(canvas.getByRole('button')).toBeInTheDocument();
@@ -173,6 +224,14 @@ export const WithValueAndErrors: Story = {
173
224
  { display_name: 'Item 2', desc: 'This is item 1', value: 'item2', image: 'https://avatars.githubusercontent.com/u/8861481?v=4' },
174
225
  ],
175
226
  },
227
+ parameters: {
228
+ docs: {
229
+ description: {
230
+ story:
231
+ 'Renders the Select field with a danger-intent item in the list, but the selected value points at the healthy item — the trigger stays clean while the picker highlights the danger item.',
232
+ },
233
+ },
234
+ },
176
235
  };
177
236
 
178
237
  export const WithValueAndErrorsSelected: Story = {
@@ -183,6 +242,14 @@ export const WithValueAndErrorsSelected: Story = {
183
242
  { display_name: 'Item 2', desc: 'This is item 1', value: 'item2' },
184
243
  ],
185
244
  },
245
+ parameters: {
246
+ docs: {
247
+ description: {
248
+ story:
249
+ 'Renders the Select field with the danger-intent item pre-selected — the trigger carries the danger styling so the operator can see the selected item has an error.',
250
+ },
251
+ },
252
+ },
186
253
  };
187
254
 
188
255
  export const WithValueAndWarningsSelected: Story = {
@@ -193,6 +260,14 @@ export const WithValueAndWarningsSelected: Story = {
193
260
  { display_name: 'Item 2', desc: 'This is item 1', value: 'item2' },
194
261
  ],
195
262
  },
263
+ parameters: {
264
+ docs: {
265
+ description: {
266
+ story:
267
+ 'Renders the Select field with a pre-selected item whose metadata declares needs_auth — the trigger surfaces the warning so the operator knows the item needs configuration.',
268
+ },
269
+ },
270
+ },
196
271
  };
197
272
 
198
273
  export const AutoSelect: Story = {
@@ -200,6 +275,14 @@ export const AutoSelect: Story = {
200
275
  autoSelect: true,
201
276
  items: [{ display_name: 'Item 1', value: 'item1' }],
202
277
  },
278
+ parameters: {
279
+ docs: {
280
+ description: {
281
+ story:
282
+ 'Renders the Select field with autoSelect and a single item — the field auto-selects the only option and the trigger shows its label on mount.',
283
+ },
284
+ },
285
+ },
203
286
  async play({ canvasElement }) {
204
287
  const canvas = within(canvasElement);
205
288
  await waitFor(() => expect(canvas.getByText('Item 1')).toBeInTheDocument(), { timeout: 500 });
@@ -211,6 +294,14 @@ export const AutoSelectWithShortDescriptions: Story = {
211
294
  autoSelect: true,
212
295
  items: [{ display_name: 'Item 1', short_desc: 'Short item 1 description', value: 'item1' }],
213
296
  },
297
+ parameters: {
298
+ docs: {
299
+ description: {
300
+ story:
301
+ 'Renders the Select field with autoSelect and a single item that carries a short description — the field auto-selects and the trigger shows both the label and the short description.',
302
+ },
303
+ },
304
+ },
214
305
  async play({ canvasElement }) {
215
306
  const canvas = within(canvasElement);
216
307
  await waitFor(() => expect(canvas.getByText('Item 1')).toBeInTheDocument(), { timeout: 500 });
@@ -222,6 +313,14 @@ export const AutoSelectWithDescriptions: Story = {
222
313
  autoSelect: true,
223
314
  items: [{ display_name: 'Item 1', desc: 'This is item 1', value: 'item1' }],
224
315
  },
316
+ parameters: {
317
+ docs: {
318
+ description: {
319
+ story:
320
+ 'Renders the Select field with autoSelect and a single item that carries a full description — the field auto-selects and the trigger shows the label with the description.',
321
+ },
322
+ },
323
+ },
225
324
  async play({ canvasElement }) {
226
325
  const canvas = within(canvasElement);
227
326
  await waitFor(() => expect(canvas.getByText('Item 1')).toBeInTheDocument(), { timeout: 500 });
@@ -230,6 +329,7 @@ export const AutoSelectWithDescriptions: Story = {
230
329
 
231
330
  export const ItemValuesAreObjectsAndCanBeSelected: Story = {
232
331
  args: {
332
+ forceDropdown: false,
233
333
  value: { id: { type: 'string', value: 'item1' } },
234
334
  items: [
235
335
  { value: { id: { type: 'string', value: 'item1' } } },
@@ -240,6 +340,14 @@ export const ItemValuesAreObjectsAndCanBeSelected: Story = {
240
340
  },
241
341
  ],
242
342
  },
343
+ parameters: {
344
+ docs: {
345
+ description: {
346
+ story:
347
+ 'Renders the Select field with items whose values are hashes rather than primitives. The unlabelled first item shows its JSON as the trigger label; picking the second item swaps the selection to its display_name.',
348
+ },
349
+ },
350
+ },
243
351
  async play({ canvasElement }) {
244
352
  const canvas = within(canvasElement);
245
353
  await waitFor(
@@ -11,7 +11,11 @@ import { TReqoreIntent } from '@qoretechnologies/reqore/dist/constants/theme';
11
11
  import { IReqoreIconName } from '@qoretechnologies/reqore/dist/types/icons';
12
12
  import { isEqual, size } from 'lodash';
13
13
  import { memo, useCallback, useEffect, useMemo, useState } from 'react';
14
- import { ISelectFieldCollectionItem, SelectFieldCollection } from './SelectCollection';
14
+ import {
15
+ getSelectItemShortDescription,
16
+ ISelectFieldCollectionItem,
17
+ SelectFieldCollection,
18
+ } from './SelectCollection';
15
19
 
16
20
  export type ISelectFormFieldItem = ISelectFieldCollectionItem;
17
21
 
@@ -68,7 +72,7 @@ export const SelectFormField = memo(
68
72
  showPlaceholder = true,
69
73
  showRightIcon = true,
70
74
  hideItemCount,
71
- forceDropdown,
75
+ forceDropdown = true,
72
76
  fluid,
73
77
  flat,
74
78
  intent,
@@ -89,6 +93,7 @@ export const SelectFormField = memo(
89
93
  return;
90
94
  }
91
95
  onChange?.(item.value);
96
+ setCollectionOpen(false);
92
97
  },
93
98
  [onChange, value]
94
99
  );
@@ -96,7 +101,7 @@ export const SelectFormField = memo(
96
101
  const getItemDescription = useCallback(
97
102
  (itemValue: unknown) => {
98
103
  const item = items.find((item) => isEqual(item.value, itemValue));
99
- return item?.desc || item?.short_desc;
104
+ return getSelectItemShortDescription(item);
100
105
  },
101
106
  [items]
102
107
  );
@@ -133,7 +138,7 @@ export const SelectFormField = memo(
133
138
  const item = items.find(
134
139
  (item) => isEqual(item.display_name, itemName) || isEqual(item.value, itemName)
135
140
  );
136
- return item?.short_desc || (item?.desc ? 'Hover to see description' : defaultDesc);
141
+ return getSelectItemShortDescription(item, defaultDesc);
137
142
  },
138
143
  [items, showDescription]
139
144
  );
@@ -230,13 +235,35 @@ export const SelectFormField = memo(
230
235
  [size(items), hideItemCount]
231
236
  );
232
237
 
233
- if (autoSelect && filteredItems.length === 1 && !filteredItems[0].disabled) {
234
- if (!disabled && !isEqual(filteredItems[0].value, value) && !value) {
235
- handleSelectClick(filteredItems[0]);
238
+ const autoSelectedItem = useMemo(
239
+ () =>
240
+ autoSelect && filteredItems.length === 1 && !filteredItems[0].disabled
241
+ ? filteredItems[0]
242
+ : undefined,
243
+ [autoSelect, filteredItems]
244
+ );
245
+
246
+ // Selecting during render causes a parent-controlled field to synchronously
247
+ // update while this component is still rendering. React rejects that update
248
+ // and can enter an infinite render loop. Commit the derived default after
249
+ // rendering instead; the button below already renders the sole item's label
250
+ // while the controlled value catches up.
251
+ useEffect(() => {
252
+ const valueIsUnset = value === undefined || value === null || value === '';
253
+
254
+ if (
255
+ autoSelectedItem &&
256
+ !disabled &&
257
+ valueIsUnset &&
258
+ !isEqual(autoSelectedItem.value, value)
259
+ ) {
260
+ handleSelectClick(autoSelectedItem);
236
261
  }
262
+ }, [autoSelectedItem, disabled, handleSelectClick, value]);
237
263
 
238
- const itemHasError = hasError(items, filteredItems[0].value);
239
- const itemHasWarning = hasWarning(items, filteredItems[0].value);
264
+ if (autoSelectedItem) {
265
+ const itemHasError = hasError(items, autoSelectedItem.value);
266
+ const itemHasWarning = hasWarning(items, autoSelectedItem.value);
240
267
 
241
268
  return (
242
269
  <ReqoreButton
@@ -247,12 +274,12 @@ export const SelectFormField = memo(
247
274
  fluid={fluid}
248
275
  flat={flat ?? false}
249
276
  size={componentSize}
250
- label={getLabel(items, value ?? filteredItems[0].value)}
277
+ label={getLabel(items, value ?? autoSelectedItem.value)}
251
278
  description={getItemShortDescription(value as string) as string}
252
279
  readOnly
253
280
  fixed
254
281
  minimal
255
- {...getIcon(filteredItems, filteredItems[0].value)}
282
+ {...getIcon(filteredItems, autoSelectedItem.value)}
256
283
  intent={
257
284
  itemHasError ? 'danger'
258
285
  : itemHasWarning ?
@@ -291,7 +318,6 @@ export const SelectFormField = memo(
291
318
  <SelectFieldCollection
292
319
  items={filteredItems}
293
320
  filters={filters}
294
- getItemDescription={(v) => getItemDescription(v) as string}
295
321
  value={value}
296
322
  onItemSelect={handleSelectClick}
297
323
  onClose={() => setCollectionOpen(false)}