@feugene/granularity 0.8.0 → 0.9.1

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 (268) hide show
  1. package/dist/chunks/{adapter-CRyH4YC8.js.map → adapter-BqqjEZGU.js.map} +1 -1
  2. package/dist/chunks/arrow-up-DZdIrpaF.js.map +1 -0
  3. package/dist/chunks/config-72sW9Bag2.js.map +1 -0
  4. package/dist/chunks/{config-B8rC_K97.js.map → config-B1kFmhpM.js.map} +1 -1
  5. package/dist/chunks/{config-BhvNm4Pp.js.map → config-B2YTEe_h.js.map} +1 -1
  6. package/dist/chunks/{config-C0rHS1-l.js.map → config-BOdu-O_B.js.map} +1 -1
  7. package/dist/chunks/{config-D27BL0H9.js.map → config-BU0olrvr.js.map} +1 -1
  8. package/dist/chunks/{config-XoANT5mU.js → config-BY81UKv0.js} +1 -1
  9. package/dist/chunks/{config-XoANT5mU.js.map → config-BY81UKv0.js.map} +1 -1
  10. package/dist/chunks/config-B_nSBc7W.js.map +1 -0
  11. package/dist/chunks/{config-DbqFk-IW.js.map → config-BbKroFtR.js.map} +1 -1
  12. package/dist/chunks/config-Bcf-8XlK2.js.map +1 -0
  13. package/dist/chunks/config-BduXEXjt.js.map +1 -0
  14. package/dist/chunks/config-BeQuykDk2.js.map +1 -0
  15. package/dist/chunks/{config-Dusr9jcE.js.map → config-BnWSHTEU.js.map} +1 -1
  16. package/dist/chunks/{config-C4AlNm912.js → config-Br_qI3Za.js} +1 -1
  17. package/dist/chunks/config-Br_qI3Za.js.map +1 -0
  18. package/dist/chunks/{config-C5TN9J2Z.js → config-C5OwJM3-.js} +1 -1
  19. package/dist/chunks/{config-C5TN9J2Z.js.map → config-C5OwJM3-.js.map} +1 -1
  20. package/dist/chunks/config-C6zT56Jc2.js.map +1 -0
  21. package/dist/chunks/{config-ZJVOVgqR.js → config-CFf7xaG1.js} +1 -1
  22. package/dist/chunks/{config-ZJVOVgqR.js.map → config-CFf7xaG1.js.map} +1 -1
  23. package/dist/chunks/{config-wo-ncgTH.js.map → config-CdJpnjDj.js.map} +1 -1
  24. package/dist/chunks/config-CetsgpaZ2.js.map +1 -0
  25. package/dist/chunks/{config-D1DI3roo.js.map → config-Ci9nXGUV.js.map} +1 -1
  26. package/dist/chunks/{config-CjEplP6D.js.map → config-CpMYmvVT.js.map} +1 -1
  27. package/dist/chunks/{config-DZAQpfz0.js.map → config-Cp_XHsze.js.map} +1 -1
  28. package/dist/chunks/{config-D98m8iyz.js.map → config-CvGdaXvH.js.map} +1 -1
  29. package/dist/chunks/{config-CtomKf-k.js.map → config-D4s_QWVP.js.map} +1 -1
  30. package/dist/chunks/{config-D32znLtV2.js.map → config-D6Oe3blW2.js.map} +1 -1
  31. package/dist/chunks/{config-CVnluhKO.js.map → config-DF_RlCIO.js.map} +1 -1
  32. package/dist/chunks/{config-C4qAA0Sb.js.map → config-DSBlHQVa.js.map} +1 -1
  33. package/dist/chunks/{config-Mp9DJ9Mq2.js.map → config-DaHI5bD_2.js.map} +1 -1
  34. package/dist/chunks/{config-3SftO0uG.js.map → config-Dcb7xK-C.js.map} +1 -1
  35. package/dist/chunks/config-DmjwIqx1.js.map +1 -0
  36. package/dist/chunks/{config-D6Af6WZw.js.map → config-DoBk_CzG.js.map} +1 -1
  37. package/dist/chunks/config-Dzd6BzIN2.js.map +1 -0
  38. package/dist/chunks/{config-Db4BEG8Y.js.map → config-O1_FTqD3.js.map} +1 -1
  39. package/dist/chunks/config-_3De4HFf.js.map +1 -0
  40. package/dist/chunks/{config-B44QVIge.js → config-d386uO3O.js} +1 -1
  41. package/dist/chunks/{config-B44QVIge.js.map → config-d386uO3O.js.map} +1 -1
  42. package/dist/chunks/{config-DudL02ag.js.map → config-iuMz79Mg.js.map} +1 -1
  43. package/dist/chunks/config-vcDVCYXo.js.map +1 -0
  44. package/dist/chunks/{en-QNZhjmSJ.js.map → en-foQA8imU.js.map} +1 -1
  45. package/dist/chunks/{es-CKLPuE0h.js → es-Bx3Kuy6z.js} +3 -3
  46. package/dist/chunks/{es-CKLPuE0h.js.map → es-Bx3Kuy6z.js.map} +1 -1
  47. package/dist/chunks/{es-C1c5XsIK.js.map → es-DZFSojYL.js.map} +1 -1
  48. package/dist/chunks/{fileValidation-CwJA8Vmn.js.map → fileValidation-c_iBg74s.js.map} +1 -1
  49. package/dist/chunks/{grDropdownStyles-DMp7RrI9.js.map → grDropdownStyles-B41mVR1H.js.map} +1 -1
  50. package/dist/chunks/{grLoadingStyles-CrxZHFL0.js.map → grLoadingStyles-DmI-SJ3i.js.map} +1 -1
  51. package/dist/chunks/{grModalStyles-Dv2NXBKi.js.map → grModalStyles-DS1Vl6EW.js.map} +1 -1
  52. package/dist/chunks/{grSelectStyles-DTAYNzxn.js.map → grSelectStyles-pUt19VGy.js.map} +1 -1
  53. package/dist/chunks/{grStyle-5EMYYctb.js.map → grStyle-CUaTmpyW.js.map} +1 -1
  54. package/dist/chunks/{granularityI18n-CXa_uN7f.js → granularityI18n-LcJ88Vce.js} +1 -1
  55. package/dist/chunks/{granularityI18n-CXa_uN7f.js.map → granularityI18n-LcJ88Vce.js.map} +1 -1
  56. package/dist/chunks/{ru-DcF7ciz0.js.map → ru-LhkPpPIl.js.map} +1 -1
  57. package/dist/chunks/safelist-_UVzJrgE2.js.map +1 -0
  58. package/dist/chunks/{shared-D7q-upeJ.js → shared-BiqXd5MW.js} +37 -37
  59. package/dist/chunks/{shared-D7q-upeJ.js.map → shared-BiqXd5MW.js.map} +1 -1
  60. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-DE-d77Us.js → GrConfirmDialog-DuUQA7nv.js} +31 -8
  61. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-DuUQA7nv.js.map +1 -0
  62. package/dist/components/GrConfirmDialog/index.js +2 -2
  63. package/dist/components/GrDataTable/chunks/{GrDataTable-QDOJWmdY.js → GrDataTable-ClcYiyc8.js} +2 -2
  64. package/dist/components/GrDataTable/chunks/{GrDataTable-QDOJWmdY.js.map → GrDataTable-ClcYiyc8.js.map} +1 -1
  65. package/dist/components/GrDataTable/index.js +2 -2
  66. package/dist/components/GrDialog/chunks/{GrDialog-Ba3Ojcsq.js → GrDialog-SYcF-4op.js} +1 -1
  67. package/dist/components/GrDialog/chunks/{GrDialog-Ba3Ojcsq.js.map → GrDialog-SYcF-4op.js.map} +1 -1
  68. package/dist/components/GrDialog/index.js +2 -2
  69. package/dist/components/GrDrawer/chunks/{GrDrawer-h33X403E.js → GrDrawer-BW3wtI7h.js} +1 -1
  70. package/dist/components/GrDrawer/chunks/{GrDrawer-h33X403E.js.map → GrDrawer-BW3wtI7h.js.map} +1 -1
  71. package/dist/components/GrDrawer/index.js +2 -2
  72. package/dist/components/GrDropdown/chunks/{GrDropdown-BkACCXdp.js → GrDropdown-DOvHKnih.js} +1 -1
  73. package/dist/components/GrDropdown/chunks/{GrDropdown-BkACCXdp.js.map → GrDropdown-DOvHKnih.js.map} +1 -1
  74. package/dist/components/GrDropdown/index.js +2 -2
  75. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-BEenXrJw.js → GrDropdownMenu-CLPwbiyG.js} +1 -1
  76. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-BEenXrJw.js.map → GrDropdownMenu-CLPwbiyG.js.map} +1 -1
  77. package/dist/components/GrDropdownMenu/index.js +2 -2
  78. package/dist/components/GrEmptyState/chunks/{GrEmptyState-BLbMJFW-.js.map → GrEmptyState-Dj2V5GaX.js.map} +1 -1
  79. package/dist/components/GrEmptyState/index.js +2 -2
  80. package/dist/components/GrFileUpload/chunks/{GrFileUpload-DYRERhI2.js → GrFileUpload-BEKNB1RM.js} +5 -5
  81. package/dist/components/GrFileUpload/chunks/GrFileUpload-BEKNB1RM.js.map +1 -0
  82. package/dist/components/GrFileUpload/index.js +3 -3
  83. package/dist/components/GrFormField/chunks/{GrFormField-C1oWTT_0.js.map → GrFormField-U7c_aDPJ.js.map} +1 -1
  84. package/dist/components/GrFormField/index.js +2 -2
  85. package/dist/components/GrFormFile/chunks/{GrFormFile-WqF-dPTB.js → GrFormFile-CIleXnfr.js} +1 -1
  86. package/dist/components/GrFormFile/chunks/{GrFormFile-WqF-dPTB.js.map → GrFormFile-CIleXnfr.js.map} +1 -1
  87. package/dist/components/GrFormFile/index.js +2 -2
  88. package/dist/components/GrFormSection/chunks/{GrFormSection-CWBk2EUm.js.map → GrFormSection-DpGhY7MX.js.map} +1 -1
  89. package/dist/components/GrFormSection/index.js +2 -2
  90. package/dist/components/GrImageViewer/chunks/{GrImageViewer-Cpj5zyZQ.js.map → GrImageViewer-Cn1X-sWS.js.map} +1 -1
  91. package/dist/components/GrImageViewer/index.js +2 -2
  92. package/dist/components/GrInput/chunks/{GrInput-CfO2RsM-.js.map → GrInput-gwFQ1sk4.js.map} +1 -1
  93. package/dist/components/GrInput/index.js +2 -2
  94. package/dist/components/GrInputTag/chunks/{GrInputTag-CeEy0IwD.js → GrInputTag-Dcj3F6rQ.js} +1 -1
  95. package/dist/components/GrInputTag/chunks/{GrInputTag-CeEy0IwD.js.map → GrInputTag-Dcj3F6rQ.js.map} +1 -1
  96. package/dist/components/GrInputTag/index.js +2 -2
  97. package/dist/components/GrLink/chunks/{GrLink-BLPigqij.js → GrLink-BMwn2iJ9.js} +1 -1
  98. package/dist/components/GrLink/chunks/{GrLink-BLPigqij.js.map → GrLink-BMwn2iJ9.js.map} +1 -1
  99. package/dist/components/GrLink/index.js +2 -2
  100. package/dist/components/GrList/chunks/{GrList-C2GpK56-.js.map → GrList-D8nM1FuV.js.map} +1 -1
  101. package/dist/components/GrList/index.js +2 -2
  102. package/dist/components/GrLoading/chunks/{GrLoading-CxNgHgNw.js → GrLoading-mfyfghxs.js} +1 -1
  103. package/dist/components/GrLoading/chunks/{GrLoading-CxNgHgNw.js.map → GrLoading-mfyfghxs.js.map} +1 -1
  104. package/dist/components/GrLoading/index.js +2 -2
  105. package/dist/components/GrModal/chunks/{GrModal-gvfvlp7k.js → GrModal-2ALC3kwy.js} +73 -7
  106. package/dist/components/GrModal/chunks/GrModal-2ALC3kwy.js.map +1 -0
  107. package/dist/components/GrModal/index.js +3 -3
  108. package/dist/components/GrNavbar/chunks/{GrNavbar-CxHwBvSG.js → GrNavbar-BH7XiF9q.js} +1 -1
  109. package/dist/components/GrNavbar/chunks/{GrNavbar-CxHwBvSG.js.map → GrNavbar-BH7XiF9q.js.map} +1 -1
  110. package/dist/components/GrNavbar/index.js +2 -2
  111. package/dist/components/GrNumberInput/chunks/{GrNumberInput-ECtFCIKV.js → GrNumberInput-YIWhV85S.js} +1 -1
  112. package/dist/components/GrNumberInput/chunks/{GrNumberInput-ECtFCIKV.js.map → GrNumberInput-YIWhV85S.js.map} +1 -1
  113. package/dist/components/GrNumberInput/index.js +2 -2
  114. package/dist/components/GrPagination/chunks/{GrPagination-dMXZz120.js → GrPagination-cD6rFO9W.js} +2 -2
  115. package/dist/components/GrPagination/chunks/{GrPagination-dMXZz120.js.map → GrPagination-cD6rFO9W.js.map} +1 -1
  116. package/dist/components/GrPagination/index.js +2 -2
  117. package/dist/components/GrProgressBar/chunks/{GrProgressBar-hQQK8cYh.js → GrProgressBar-C2HdYjp4.js} +1 -1
  118. package/dist/components/GrProgressBar/chunks/{GrProgressBar-hQQK8cYh.js.map → GrProgressBar-C2HdYjp4.js.map} +1 -1
  119. package/dist/components/GrProgressBar/index.js +2 -2
  120. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-CfKf4tPx.js → GrPromptDialog-23x2nZvv.js} +54 -28
  121. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-23x2nZvv.js.map +1 -0
  122. package/dist/components/GrPromptDialog/index.js +2 -2
  123. package/dist/components/GrRadio/chunks/{GrRadio-CQ3w3Bj6.js → GrRadio-IFU9Hiu2.js} +1 -1
  124. package/dist/components/GrRadio/chunks/{GrRadio-CQ3w3Bj6.js.map → GrRadio-IFU9Hiu2.js.map} +1 -1
  125. package/dist/components/GrRadio/index.js +2 -2
  126. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-DAaVzlPx.js → GrRadioGroup-C8IcJuuF.js} +1 -1
  127. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-DAaVzlPx.js.map → GrRadioGroup-C8IcJuuF.js.map} +1 -1
  128. package/dist/components/GrRadioGroup/index.js +2 -2
  129. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-BMvXREcv.js +221 -0
  130. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-BMvXREcv.js.map +1 -0
  131. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-CzdTh4gd.js +782 -0
  132. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-CzdTh4gd.js.map +1 -0
  133. package/dist/components/GrResponseErrorBanner/index.js +3 -0
  134. package/dist/components/GrSegmented/chunks/{GrSegmented-BPl1koHc.js → GrSegmented-BRmwBsEG.js} +1 -1
  135. package/dist/components/GrSegmented/chunks/{GrSegmented-BPl1koHc.js.map → GrSegmented-BRmwBsEG.js.map} +1 -1
  136. package/dist/components/GrSegmented/index.js +2 -2
  137. package/dist/components/GrSelect/chunks/{GrSelect-C3NAfTqL.js → GrSelect-W9lbAjRZ.js} +2 -2
  138. package/dist/components/GrSelect/chunks/{GrSelect-C3NAfTqL.js.map → GrSelect-W9lbAjRZ.js.map} +1 -1
  139. package/dist/components/GrSelect/index.js +2 -2
  140. package/dist/components/GrSidebar/chunks/{GrSidebar-DVucgcfV.js.map → GrSidebar-BpBtAGBs.js.map} +1 -1
  141. package/dist/components/GrSidebar/index.js +2 -2
  142. package/dist/components/GrSkeleton/chunks/{GrSkeleton-CDTvCSoH.js.map → GrSkeleton-URyMkBqI.js.map} +1 -1
  143. package/dist/components/GrSkeleton/index.js +2 -2
  144. package/dist/components/GrSwitch/chunks/{GrSwitch-Bnamgqb2.js → GrSwitch-29h0QhMO.js} +1 -1
  145. package/dist/components/GrSwitch/chunks/{GrSwitch-Bnamgqb2.js.map → GrSwitch-29h0QhMO.js.map} +1 -1
  146. package/dist/components/GrSwitch/index.js +2 -2
  147. package/dist/components/GrTable/chunks/{GrTable-CyQ9uw8A.js.map → GrTable-dTWUxzRm.js.map} +1 -1
  148. package/dist/components/GrTable/index.js +2 -2
  149. package/dist/components/GrTabs/chunks/{GrTabs-CiGmcmvm.js.map → GrTabs-D3ntDdtg.js.map} +1 -1
  150. package/dist/components/GrTabs/index.js +2 -2
  151. package/dist/components/GrTextarea/chunks/{GrTextarea-VBSc6A7D.js → GrTextarea-Cv6r2GuC.js} +1 -1
  152. package/dist/components/GrTextarea/chunks/{GrTextarea-VBSc6A7D.js.map → GrTextarea-Cv6r2GuC.js.map} +1 -1
  153. package/dist/components/GrTextarea/index.js +2 -2
  154. package/dist/components/GrToaster/chunks/{GrToaster-BGNNmnr9.js → GrToaster-DluJmR5D.js} +1 -1
  155. package/dist/components/GrToaster/chunks/{GrToaster-BGNNmnr9.js.map → GrToaster-DluJmR5D.js.map} +1 -1
  156. package/dist/components/GrToaster/index.js +2 -2
  157. package/dist/components/GrTooltip/chunks/{GrTooltip-CrV1gI_c.js.map → GrTooltip-B7I1AVIC.js.map} +1 -1
  158. package/dist/components/GrTooltip/index.js +2 -2
  159. package/dist/components/GrTree/chunks/{GrTree-mYa3COxG.js.map → GrTree-B2SMU5Py.js.map} +1 -1
  160. package/dist/components/GrTree/index.js +2 -2
  161. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-BEdtrjwX.js → GrTreeSelect-C1abr5uH.js} +4 -4
  162. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-BEdtrjwX.js.map → GrTreeSelect-C1abr5uH.js.map} +1 -1
  163. package/dist/components/GrTreeSelect/index.js +2 -2
  164. package/dist/directives/dropzone.js +1 -1
  165. package/dist/directives/loading.js +1 -1
  166. package/dist/fileValidation/index.js +1 -1
  167. package/dist/granular-provider-node.js +2 -2
  168. package/dist/granular-provider.js +1 -1
  169. package/dist/i18n/all.js +1 -1
  170. package/dist/i18n/index.js +2 -2
  171. package/dist/index.js +474 -1015
  172. package/dist/index.js.map +1 -1
  173. package/dist/types/src/components/GrConfirmDialog/GrConfirmDialog.vue.d.ts +36 -3
  174. package/dist/types/src/components/GrDialogService/GrDialogServiceHost.vue.d.ts +3 -0
  175. package/dist/types/src/components/GrDialogService/config.d.ts +1 -0
  176. package/dist/types/src/components/GrDialogService/index.d.ts +4 -0
  177. package/dist/types/src/components/GrDialogService/store.d.ts +22 -0
  178. package/dist/types/src/components/GrDialogService/types.d.ts +141 -0
  179. package/dist/types/src/components/GrDialogService/useDialogService.d.ts +13 -0
  180. package/dist/types/src/components/GrFileUpload/GrFileUpload.vue.d.ts +3 -3
  181. package/dist/types/src/components/GrFormFile/GrFormFile.vue.d.ts +2 -2
  182. package/dist/types/src/components/GrInput/GrInput.vue.d.ts +2 -2
  183. package/dist/types/src/components/GrInputTag/GrInputTag.vue.d.ts +1 -1
  184. package/dist/types/src/components/GrModal/grModalEscStack.d.ts +30 -0
  185. package/dist/types/src/components/GrNumberInput/GrNumberInput.vue.d.ts +4 -4
  186. package/dist/types/src/components/GrPromptDialog/GrPromptDialog.vue.d.ts +42 -3
  187. package/dist/types/src/components/GrResponseErrorBanner/GrUploadErrorBanner.vue.d.ts +1 -1
  188. package/dist/types/src/components/GrResponseErrorBanner/index.d.ts +2 -2
  189. package/dist/types/src/components/GrResponseErrorBanner/parsers/createResponseErrorClassifier.d.ts +27 -0
  190. package/dist/types/src/components/GrResponseErrorBanner/parsers/index.d.ts +2 -2
  191. package/dist/types/src/components/GrSelect/GrSelect.vue.d.ts +1 -1
  192. package/dist/types/src/components/GrTextarea/GrTextarea.vue.d.ts +2 -2
  193. package/dist/types/src/components/GrToaster/GrToaster.vue.d.ts +1 -1
  194. package/dist/types/src/index.d.ts +1 -0
  195. package/package.json +5 -1
  196. package/dist/chunks/arrow-up-DNXrMoAI.js.map +0 -1
  197. package/dist/chunks/config-C0b_3LJV.js.map +0 -1
  198. package/dist/chunks/config-C4AlNm912.js.map +0 -1
  199. package/dist/chunks/config-CxCAfXZ1.js.map +0 -1
  200. package/dist/chunks/config-DDEWvph-2.js.map +0 -1
  201. package/dist/chunks/config-DDLoUczC.js.map +0 -1
  202. package/dist/chunks/config-DK2NpdyX2.js.map +0 -1
  203. package/dist/chunks/config-DQOSlWvp.js.map +0 -1
  204. package/dist/chunks/config-DnsISjD8.js.map +0 -1
  205. package/dist/chunks/config-DxqMXzNV2.js.map +0 -1
  206. package/dist/chunks/config-DxqpV-KM.js.map +0 -1
  207. package/dist/chunks/config-iDTkWUdh2.js.map +0 -1
  208. package/dist/chunks/config-rxFL-6yF2.js.map +0 -1
  209. package/dist/chunks/safelist-BF822K15.js.map +0 -1
  210. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-DE-d77Us.js.map +0 -1
  211. package/dist/components/GrFileUpload/chunks/GrFileUpload-DYRERhI2.js.map +0 -1
  212. package/dist/components/GrModal/chunks/GrModal-gvfvlp7k.js.map +0 -1
  213. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-CfKf4tPx.js.map +0 -1
  214. /package/dist/chunks/{adapter-CRyH4YC8.js → adapter-BqqjEZGU.js} +0 -0
  215. /package/dist/chunks/{arrow-up-DNXrMoAI.js → arrow-up-DZdIrpaF.js} +0 -0
  216. /package/dist/chunks/{config-C0b_3LJV.js → config-72sW9Bag2.js} +0 -0
  217. /package/dist/chunks/{config-B8rC_K97.js → config-B1kFmhpM.js} +0 -0
  218. /package/dist/chunks/{config-BhvNm4Pp.js → config-B2YTEe_h.js} +0 -0
  219. /package/dist/chunks/{config-C0rHS1-l.js → config-BOdu-O_B.js} +0 -0
  220. /package/dist/chunks/{config-D27BL0H9.js → config-BU0olrvr.js} +0 -0
  221. /package/dist/chunks/{config-DxqMXzNV2.js → config-B_nSBc7W.js} +0 -0
  222. /package/dist/chunks/{config-DbqFk-IW.js → config-BbKroFtR.js} +0 -0
  223. /package/dist/chunks/{config-DQOSlWvp.js → config-Bcf-8XlK2.js} +0 -0
  224. /package/dist/chunks/{config-iDTkWUdh2.js → config-BduXEXjt.js} +0 -0
  225. /package/dist/chunks/{config-DnsISjD8.js → config-BeQuykDk2.js} +0 -0
  226. /package/dist/chunks/{config-Dusr9jcE.js → config-BnWSHTEU.js} +0 -0
  227. /package/dist/chunks/{config-DxqpV-KM.js → config-C6zT56Jc2.js} +0 -0
  228. /package/dist/chunks/{config-wo-ncgTH.js → config-CdJpnjDj.js} +0 -0
  229. /package/dist/chunks/{config-CxCAfXZ1.js → config-CetsgpaZ2.js} +0 -0
  230. /package/dist/chunks/{config-D1DI3roo.js → config-Ci9nXGUV.js} +0 -0
  231. /package/dist/chunks/{config-CjEplP6D.js → config-CpMYmvVT.js} +0 -0
  232. /package/dist/chunks/{config-DZAQpfz0.js → config-Cp_XHsze.js} +0 -0
  233. /package/dist/chunks/{config-D98m8iyz.js → config-CvGdaXvH.js} +0 -0
  234. /package/dist/chunks/{config-CtomKf-k.js → config-D4s_QWVP.js} +0 -0
  235. /package/dist/chunks/{config-D32znLtV2.js → config-D6Oe3blW2.js} +0 -0
  236. /package/dist/chunks/{config-CVnluhKO.js → config-DF_RlCIO.js} +0 -0
  237. /package/dist/chunks/{config-C4qAA0Sb.js → config-DSBlHQVa.js} +0 -0
  238. /package/dist/chunks/{config-Mp9DJ9Mq2.js → config-DaHI5bD_2.js} +0 -0
  239. /package/dist/chunks/{config-3SftO0uG.js → config-Dcb7xK-C.js} +0 -0
  240. /package/dist/chunks/{config-DDEWvph-2.js → config-DmjwIqx1.js} +0 -0
  241. /package/dist/chunks/{config-D6Af6WZw.js → config-DoBk_CzG.js} +0 -0
  242. /package/dist/chunks/{config-DDLoUczC.js → config-Dzd6BzIN2.js} +0 -0
  243. /package/dist/chunks/{config-Db4BEG8Y.js → config-O1_FTqD3.js} +0 -0
  244. /package/dist/chunks/{config-rxFL-6yF2.js → config-_3De4HFf.js} +0 -0
  245. /package/dist/chunks/{config-DudL02ag.js → config-iuMz79Mg.js} +0 -0
  246. /package/dist/chunks/{config-DK2NpdyX2.js → config-vcDVCYXo.js} +0 -0
  247. /package/dist/chunks/{en-QNZhjmSJ.js → en-foQA8imU.js} +0 -0
  248. /package/dist/chunks/{es-C1c5XsIK.js → es-DZFSojYL.js} +0 -0
  249. /package/dist/chunks/{fileValidation-CwJA8Vmn.js → fileValidation-c_iBg74s.js} +0 -0
  250. /package/dist/chunks/{grDropdownStyles-DMp7RrI9.js → grDropdownStyles-B41mVR1H.js} +0 -0
  251. /package/dist/chunks/{grLoadingStyles-CrxZHFL0.js → grLoadingStyles-DmI-SJ3i.js} +0 -0
  252. /package/dist/chunks/{grModalStyles-Dv2NXBKi.js → grModalStyles-DS1Vl6EW.js} +0 -0
  253. /package/dist/chunks/{grSelectStyles-DTAYNzxn.js → grSelectStyles-pUt19VGy.js} +0 -0
  254. /package/dist/chunks/{grStyle-5EMYYctb.js → grStyle-CUaTmpyW.js} +0 -0
  255. /package/dist/chunks/{ru-DcF7ciz0.js → ru-LhkPpPIl.js} +0 -0
  256. /package/dist/chunks/{safelist-BF822K15.js → safelist-_UVzJrgE2.js} +0 -0
  257. /package/dist/components/GrEmptyState/chunks/{GrEmptyState-BLbMJFW-.js → GrEmptyState-Dj2V5GaX.js} +0 -0
  258. /package/dist/components/GrFormField/chunks/{GrFormField-C1oWTT_0.js → GrFormField-U7c_aDPJ.js} +0 -0
  259. /package/dist/components/GrFormSection/chunks/{GrFormSection-CWBk2EUm.js → GrFormSection-DpGhY7MX.js} +0 -0
  260. /package/dist/components/GrImageViewer/chunks/{GrImageViewer-Cpj5zyZQ.js → GrImageViewer-Cn1X-sWS.js} +0 -0
  261. /package/dist/components/GrInput/chunks/{GrInput-CfO2RsM-.js → GrInput-gwFQ1sk4.js} +0 -0
  262. /package/dist/components/GrList/chunks/{GrList-C2GpK56-.js → GrList-D8nM1FuV.js} +0 -0
  263. /package/dist/components/GrSidebar/chunks/{GrSidebar-DVucgcfV.js → GrSidebar-BpBtAGBs.js} +0 -0
  264. /package/dist/components/GrSkeleton/chunks/{GrSkeleton-CDTvCSoH.js → GrSkeleton-URyMkBqI.js} +0 -0
  265. /package/dist/components/GrTable/chunks/{GrTable-CyQ9uw8A.js → GrTable-dTWUxzRm.js} +0 -0
  266. /package/dist/components/GrTabs/chunks/{GrTabs-CiGmcmvm.js → GrTabs-D3ntDdtg.js} +0 -0
  267. /package/dist/components/GrTooltip/chunks/{GrTooltip-CrV1gI_c.js → GrTooltip-B7I1AVIC.js} +0 -0
  268. /package/dist/components/GrTree/chunks/{GrTree-mYa3COxG.js → GrTree-B2SMU5Py.js} +0 -0
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/components/GrResponseErrorBanner/responseError.defaults.ts","../src/components/GrResponseErrorBanner/parsers/abortErrorParser.ts","../src/components/GrResponseErrorBanner/parsers/fileValidationParser.ts","../src/components/GrResponseErrorBanner/parsers/httpStatusParser.ts","../src/components/GrResponseErrorBanner/parsers/jsonApiErrorParser.ts","../src/components/GrResponseErrorBanner/parsers/laravelValidationParser.ts","../src/components/GrResponseErrorBanner/parsers/networkErrorParser.ts","../src/components/GrResponseErrorBanner/parsers/normalizeError.ts","../src/components/GrResponseErrorBanner/parsers/plainMessageParser.ts","../src/components/GrResponseErrorBanner/parsers/problemDetailsParser.ts","../src/components/GrResponseErrorBanner/parsers/createResponseErrorClassifier.ts","../src/components/GrResponseErrorBanner/GrResponseErrorBanner.vue","../src/components/GrResponseErrorBanner/GrResponseErrorBanner.vue","../src/components/GrResponseErrorBanner/GrUploadErrorBanner.vue","../src/components/GrResponseErrorBanner/GrUploadErrorBanner.vue","../src/components/GrResponseErrorBanner/GrFormErrorBanner.vue","../src/components/GrResponseErrorBanner/GrFormErrorBanner.vue","../src/components/GrResponseErrorBanner/useResponseError.ts","../src/components/shared/tones.ts"],"sourcesContent":["import type { ResponseErrorKind, ResponseErrorTexts, ResponseErrorTone } from './responseError.types'\n\n/**\n * Default English texts. Any field can be overridden via the `texts` prop\n * on `GrResponseErrorBanner` or the `texts` option of `useResponseError`.\n */\nexport const DEFAULT_RESPONSE_ERROR_TEXTS: ResponseErrorTexts = {\n networkTitle: 'No connection to the server',\n networkMessage: 'Check your internet connection and try again.',\n abortedTitle: 'Request cancelled',\n abortedMessage: 'The request was cancelled.',\n validationTitle: 'Check the data',\n validationMessage: 'The server returned a validation error. Fix the fields and try again.',\n clientTitle: 'Request error',\n clientMessage: 'The server rejected the request.',\n serverTitle: 'Server error',\n serverMessage: 'A server error occurred. Please try again.',\n unknownTitle: 'Something went wrong',\n unknownMessage: 'The operation could not be completed. Please try again.',\n retryLabel: 'Retry',\n dismissLabel: 'Dismiss',\n}\n\n/**\n * Маппинг `kind` → `tone` по умолчанию. Применяется внутри баннера, если\n * пользователь не передал `tone` или `toneByKind`. Цель — визуально отделить\n * «исправь ввод» (warning) от «упало по сети/серверу» (danger).\n */\nexport const DEFAULT_TONE_BY_KIND: Record<ResponseErrorKind, ResponseErrorTone> = {\n network: 'danger',\n aborted: 'info',\n validation: 'warning',\n client: 'warning',\n server: 'danger',\n unknown: 'danger',\n}\n\n/**\n * `kind`'ы, которые по умолчанию не показываются (баннер скрыт).\n * Семантика: отмена пользователем — не «ошибка», UI обычно тихо проглатывает.\n * Пользователь может переопределить через `autoHideKinds: []`, чтобы показать info-плашку.\n */\nexport const DEFAULT_AUTO_HIDE_KINDS: ResponseErrorKind[] = []\n","import type { ResponseErrorParser } from '../responseError.types'\n\n/**\n * Распознаёт отмену запроса клиентом.\n *\n * Триггеры:\n * - `ctx.isAbort === true` (выставляется `normalizeError` для `AbortError`,\n * axios `isCancel`/`ERR_CANCELED`, xhr `status === 0 && readyState === 4`).\n *\n * Возвращает `kind: 'aborted'` и `stop: true` — другие парсеры пропускаются,\n * чтобы случайный `status === 0` не интерпретировался как сетевая ошибка.\n *\n * По умолчанию `aborted` показывается info-плашкой; чтобы скрыть совсем —\n * добавьте `'aborted'` в `autoHideKinds`.\n */\nexport const abortErrorParser: ResponseErrorParser = (ctx) => {\n if (!ctx.isAbort) return null\n return {\n kind: 'aborted',\n message: ctx.texts.abortedMessage,\n stop: true,\n }\n}\n","import type { ResponseErrorParser } from '../responseError.types'\n\n/**\n * Распознаёт `FileValidationError` от `GrFileUpload` (или совместимый по форме\n * объект). Не зависит от жёсткого импорта класса — определяет по `name`.\n *\n * Активируется, если `ctx.raw.name === 'FileValidationError'` и есть массив\n * `issues`/`errors` с полями `{ file?, code?, message }`.\n *\n * Возвращает `kind: 'validation'` и `stop: true` — это локальная клиентская\n * валидация, незачем дальше идти по HTTP-парсерам.\n */\nexport const fileValidationParser: ResponseErrorParser = (ctx) => {\n const raw = ctx.raw as\n | undefined\n | {\n name?: string\n message?: string\n issues?: Array<{ file?: { name?: string }, message?: unknown, code?: string }>\n errors?: Array<{ file?: { name?: string }, message?: unknown, code?: string }>\n }\n if (!raw || typeof raw !== 'object') return null\n if (raw.name !== 'FileValidationError') return null\n\n const list = raw.issues ?? raw.errors ?? []\n const details: string[] = []\n for (const it of list) {\n if (!it || typeof it !== 'object') continue\n const msg = typeof it.message === 'string' ? it.message : ''\n if (!msg) continue\n const fileName = it.file?.name\n details.push(fileName ? `${fileName}: ${msg}` : msg)\n }\n\n return {\n kind: 'validation',\n message: raw.message || ctx.texts.validationMessage,\n details: details.length ? details : undefined,\n stop: true,\n }\n}\n","import type { ResponseErrorParser } from '../responseError.types'\n\n/**\n * Базовая классификация по HTTP-статусу.\n *\n * Правила:\n * - `400` / `422` ⇒ `kind: 'validation'`,\n * - остальные `4xx` ⇒ `kind: 'client'`,\n * - `>= 500` ⇒ `kind: 'server'`.\n *\n * Не использует `stop` — даёт более специализированным парсерам\n * (Laravel/JSON:API/RFC 7807) уточнить сообщение и `fieldErrors`.\n *\n * `message` берёт из `ctx.texts` как осмысленный фолбэк.\n */\nexport const httpStatusParser: ResponseErrorParser = (ctx) => {\n const status = ctx.status\n if (typeof status !== 'number') return null\n\n if (status >= 500) {\n return { kind: 'server', status, message: ctx.texts.serverMessage }\n }\n if (status === 400 || status === 422) {\n return { kind: 'validation', status, message: ctx.texts.validationMessage }\n }\n if (status >= 400) {\n return { kind: 'client', status, message: ctx.texts.clientMessage }\n }\n return null\n}\n","import type { ResponseErrorFieldError, ResponseErrorParser } from '../responseError.types'\n\n/**\n * Парсер JSON:API-стиля:\n *\n * ```json\n * { \"errors\": [\n * { \"status\": \"422\", \"title\": \"Invalid Attribute\",\n * \"detail\": \"Email is required.\",\n * \"source\": { \"pointer\": \"/data/attributes/email\" } }\n * ] }\n * ```\n *\n * Активируется, когда `ctx.body.errors` — массив объектов с `title`/`detail`.\n * Поле извлекается из последнего сегмента `source.pointer`. Все `detail`\n * собираются в `details`, первый `title` — в `message`.\n */\nexport const jsonApiErrorParser: ResponseErrorParser = (ctx) => {\n const body = ctx.body\n if (!body || typeof body !== 'object') return null\n\n const errors = (body as { errors?: unknown }).errors\n if (!Array.isArray(errors) || errors.length === 0) return null\n\n // Эвристика: первый элемент должен иметь title/detail/source — иначе это не JSON:API\n const first = errors[0]\n if (!first || typeof first !== 'object') return null\n const has = (key: string) => key in (first as object)\n if (!has('title') && !has('detail') && !has('source')) return null\n\n const fieldErrorsMap = new Map<string, string[]>()\n const details: string[] = []\n let message: string | undefined\n\n for (const e of errors) {\n if (!e || typeof e !== 'object') continue\n const eo = e as { title?: unknown, detail?: unknown, source?: { pointer?: unknown } }\n const text = (typeof eo.detail === 'string' && eo.detail) || (typeof eo.title === 'string' && eo.title) || ''\n if (!text) continue\n if (!message && typeof eo.title === 'string') message = eo.title\n\n const pointer = typeof eo.source?.pointer === 'string' ? eo.source.pointer : ''\n const field = pointer ? pointer.split('/').filter(Boolean).pop() : undefined\n\n if (field) {\n const list = fieldErrorsMap.get(field) ?? []\n list.push(text)\n fieldErrorsMap.set(field, list)\n }\n details.push(text)\n }\n\n if (!details.length) return null\n\n const fieldErrors: ResponseErrorFieldError[] = Array.from(fieldErrorsMap, ([field, messages]) => ({ field, messages }))\n\n const kind = fieldErrors.length ? 'validation' : undefined\n\n return {\n kind,\n message: message || (kind === 'validation' ? ctx.texts.validationMessage : ctx.texts.clientMessage),\n details,\n fieldErrors: fieldErrors.length ? fieldErrors : undefined,\n }\n}\n","import type { ResponseErrorFieldError, ResponseErrorParser } from '../responseError.types'\n\n/**\n * Парсит Laravel-формат ответа об ошибке валидации:\n *\n * ```json\n * { \"message\": \"The given data was invalid.\",\n * \"errors\": { \"file\": [\"The file is required.\"], \"amount\": [\"...\"] } }\n * ```\n *\n * Активируется при наличии `ctx.body.errors` как plain-объекта (значения —\n * массив строк или строка). Если есть `fieldErrors`, повышает `kind` до\n * `validation` независимо от статуса (полезно, когда сервер прислал 200/4xx\n * без 422). `message` берётся из `body.message` / `body.error`.\n */\nexport const laravelValidationParser: ResponseErrorParser = (ctx) => {\n const body = ctx.body\n if (!body || typeof body !== 'object' || Array.isArray(body)) return null\n\n const data = body as Record<string, unknown>\n const errors = data.errors\n if (!errors || typeof errors !== 'object' || Array.isArray(errors)) return null\n\n const fieldErrors: ResponseErrorFieldError[] = []\n for (const [field, raw] of Object.entries(errors as Record<string, unknown>)) {\n const messages = Array.isArray(raw)\n ? raw.filter((m): m is string => typeof m === 'string')\n : typeof raw === 'string' ? [raw] : []\n if (messages.length) fieldErrors.push({ field, messages })\n }\n\n if (!fieldErrors.length) return null\n\n const message = (typeof data.message === 'string' && data.message)\n || (typeof data.error === 'string' && data.error)\n || ctx.texts.validationMessage\n\n const details = fieldErrors.flatMap(fe => fe.messages)\n\n return {\n kind: 'validation',\n message,\n details,\n fieldErrors,\n }\n}\n","import type { ResponseErrorParser } from '../responseError.types'\n\n/**\n * Распознаёт транспортные ошибки **без ответа сервера**: отсутствие интернета,\n * DNS-фейл, CORS-preflight, fetch `TypeError('Failed to fetch')`,\n * axios `ERR_NETWORK`/`ECONNABORTED`.\n *\n * Триггеры:\n * - `ctx.isNetwork === true` (выставлено `normalizeError`),\n * - либо нет ни `status`, ни `body`, ни признака отмены, но есть исходная\n * ошибка с `code === 'ERR_NETWORK'` / `message ~ /network|fetch/i/`.\n *\n * Возвращает `kind: 'network'` и `stop: true`.\n */\nexport const networkErrorParser: ResponseErrorParser = (ctx) => {\n if (ctx.isAbort) return null\n\n if (ctx.isNetwork) {\n return {\n kind: 'network',\n message: ctx.texts.networkMessage,\n stop: true,\n }\n }\n\n // Эвристика для случаев, когда normalizeError не пометил, но статус-кода нет.\n if (typeof ctx.status !== 'number' && ctx.body == null && ctx.raw && typeof ctx.raw === 'object') {\n const r = ctx.raw as { code?: string, message?: string, name?: string }\n if (r.code === 'ERR_NETWORK' || (typeof r.message === 'string' && /network|failed to fetch/i.test(r.message))) {\n return {\n kind: 'network',\n message: ctx.texts.networkMessage,\n stop: true,\n }\n }\n }\n\n return null\n}\n","import type { NormalizedRawError } from '../responseError.types'\n\n/**\n * Универсально приводит «сырой» вход к {@link NormalizedRawError}.\n *\n * Поддерживаемые источники:\n * - **axios** — `AxiosError` с `response.status`/`response.data`/`response.headers`,\n * либо `request` без `response` + `code === 'ERR_NETWORK'`, либо `code === 'ERR_CANCELED'`.\n * - **fetch `Response`** — объект `Response` с `ok=false`. Тело читается через\n * `clone().json()` (с фолбэком на `.text()`); поэтому функция асинхронная.\n * - **fetch `TypeError`** — `TypeError('Failed to fetch')` ⇒ `isNetwork=true`.\n * - **`{ response: Response, body: unknown }`** — если потребитель уже прочитал тело сам.\n * - **`XMLHttpRequest`** / `{ status, responseText, response }` — пара полей.\n * - **`AbortError` / `DOMException`** ⇒ `isAbort=true`.\n * - **`Error`/строка/произвольный объект** — кладётся в `body`/`raw` как есть.\n *\n * Цель — отделить «откуда пришла ошибка» от «как её классифицировать»: парсеры\n * работают только с нормализованным `ResponseErrorContext`, не зная о транспорте.\n */\nexport async function normalizeError(raw: unknown): Promise<NormalizedRawError> {\n // 1) Уже нормализованный вход (потребитель сам подготовил)\n if (isPlainNormalized(raw)) {\n return { ...(raw as NormalizedRawError), raw }\n }\n\n // 2) `{ response: Response, body }` — уже прочитанное тело\n if (isResponseEnvelope(raw)) {\n const res = raw.response\n return {\n raw,\n status: res.status,\n body: raw.body,\n headers: readHeaders(res),\n }\n }\n\n // 3) Голый fetch Response\n if (isFetchResponse(raw)) {\n const body = await readFetchBody(raw)\n return {\n raw,\n status: raw.status,\n body,\n headers: readHeaders(raw),\n }\n }\n\n // 4) XMLHttpRequest\n if (isXhr(raw)) {\n const body = parseMaybeJson(raw.responseText) ?? raw.response\n return {\n raw,\n status: typeof raw.status === 'number' ? raw.status : undefined,\n body,\n isAbort: raw.status === 0 && raw.readyState === 4,\n }\n }\n\n // 5) axios error (есть `isAxiosError` или `response`/`request` + `code`)\n if (isAxiosLike(raw)) {\n const e = raw as AxiosLikeError\n const status = e.response?.status\n const code = e.code\n const isAbort = code === 'ERR_CANCELED' || code === 'CANCELED' || (e as { __CANCEL__?: boolean }).__CANCEL__ === true\n const isNetwork = !e.response && (code === 'ERR_NETWORK' || code === 'ECONNABORTED')\n\n return {\n raw,\n status,\n body: e.response?.data,\n headers: normalizeHeaderRecord(e.response?.headers),\n isAbort,\n isNetwork,\n }\n }\n\n // 6) AbortError / DOMException\n if (isAbortError(raw)) {\n return { raw, isAbort: true }\n }\n\n // 7) Сетевой TypeError от fetch\n if (raw instanceof TypeError && /fetch|network/i.test(raw.message || '')) {\n return { raw, isNetwork: true }\n }\n\n // 8) Произвольный Error / строка / объект\n if (raw instanceof Error) {\n return { raw, body: { message: raw.message } }\n }\n\n if (typeof raw === 'string') {\n return { raw, body: { message: raw } }\n }\n\n if (raw && typeof raw === 'object') {\n return { raw, body: raw }\n }\n\n return { raw }\n}\n\n// ----------------- helpers -----------------\n\ntype AxiosLikeError = Error & {\n isAxiosError?: boolean\n code?: string\n response?: { status?: number, data?: unknown, headers?: unknown }\n request?: unknown\n}\n\nfunction isPlainNormalized(v: unknown): v is NormalizedRawError {\n if (!v || typeof v !== 'object') return false\n const o = v as Record<string, unknown>\n return 'raw' in o && (\n 'status' in o || 'body' in o || 'isAbort' in o || 'isNetwork' in o || 'headers' in o\n )\n}\n\nfunction isResponseEnvelope(v: unknown): v is { response: Response, body: unknown } {\n return !!v && typeof v === 'object'\n && 'response' in (v as object)\n && isFetchResponse((v as { response: unknown }).response)\n}\n\nfunction isFetchResponse(v: unknown): v is Response {\n return typeof Response !== 'undefined' && v instanceof Response\n}\n\nfunction isXhr(v: unknown): v is XMLHttpRequest {\n return typeof XMLHttpRequest !== 'undefined' && v instanceof XMLHttpRequest\n}\n\nfunction isAxiosLike(v: unknown): v is AxiosLikeError {\n if (!v || typeof v !== 'object') return false\n const o = v as Record<string, unknown>\n return o.isAxiosError === true\n || ('response' in o && typeof o.response === 'object' && o.response !== null)\n || ('code' in o && typeof o.code === 'string')\n}\n\nfunction isAbortError(v: unknown): boolean {\n if (!v || typeof v !== 'object') return false\n const o = v as { name?: string, code?: string }\n return o.name === 'AbortError' || o.name === 'CanceledError' || o.code === 'ERR_CANCELED'\n}\n\nasync function readFetchBody(res: Response): Promise<unknown> {\n if (res.bodyUsed) return undefined\n try {\n const clone = res.clone()\n const text = await clone.text()\n return parseMaybeJson(text) ?? text\n }\n catch {\n return undefined\n }\n}\n\nfunction readHeaders(res: Response): Record<string, string> {\n const out: Record<string, string> = {}\n res.headers.forEach((value, key) => {\n out[key.toLowerCase()] = value\n })\n return out\n}\n\nfunction normalizeHeaderRecord(h: unknown): Record<string, string> | undefined {\n if (!h || typeof h !== 'object') return undefined\n const out: Record<string, string> = {}\n for (const [k, v] of Object.entries(h as Record<string, unknown>)) {\n if (typeof v === 'string') out[k.toLowerCase()] = v\n }\n return out\n}\n\nfunction parseMaybeJson(text: string | undefined): unknown {\n if (typeof text !== 'string' || !text) return undefined\n try {\n return JSON.parse(text)\n }\n catch {\n return undefined\n }\n}\n","import type { ResponseErrorParser } from '../responseError.types'\n\n/**\n * Финальный фолбэк-парсер. Достаёт хоть какое-нибудь человекочитаемое\n * сообщение, чтобы баннер не был пустым.\n *\n * Источники (по приоритету):\n * 1. `ctx.body` — если строка ⇒ message,\n * 2. `ctx.body[messageKey]` (default `'message'`),\n * 3. `ctx.body.error` (строка),\n * 4. `ctx.raw.message` (для голых `Error`).\n *\n * Не выставляет `kind` — оставляет на усмотрение классификатора.\n * Использует ключ `messageKey` из `ctx.meta._messageKey`, если задан.\n */\nexport const plainMessageParser: ResponseErrorParser = (ctx) => {\n const messageKey = (ctx.meta._messageKey as string | undefined) || 'message'\n\n if (typeof ctx.body === 'string' && ctx.body.trim()) {\n return { message: ctx.body }\n }\n\n if (ctx.body && typeof ctx.body === 'object') {\n const data = ctx.body as Record<string, unknown>\n const fromKey = data[messageKey]\n if (typeof fromKey === 'string' && fromKey) return { message: fromKey }\n if (typeof data.error === 'string' && data.error) return { message: data.error }\n }\n\n if (ctx.raw instanceof Error && ctx.raw.message) {\n return { message: ctx.raw.message }\n }\n\n return null\n}\n","import type { ResponseErrorParser } from '../responseError.types'\n\n/**\n * Парсер RFC 7807 «Problem Details for HTTP APIs»:\n *\n * ```json\n * { \"type\": \"https://example.com/probs/out-of-credit\",\n * \"title\": \"You do not have enough credit.\",\n * \"status\": 403,\n * \"detail\": \"Your current balance is 30.\",\n * \"errors\": { \"balance\": [\"...\"] } }\n * ```\n *\n * Активируется, если есть `body.type` + `body.title`, либо\n * Content-Type заголовка `application/problem+json`. Берёт `title` как\n * `message`, `detail` — в `details[0]`, status — в `status`.\n */\nexport const problemDetailsParser: ResponseErrorParser = (ctx) => {\n const body = ctx.body\n if (!body || typeof body !== 'object' || Array.isArray(body)) return null\n\n const data = body as { type?: unknown, title?: unknown, detail?: unknown, status?: unknown }\n const isProblemContentType = ctx.headers?.['content-type']?.includes('application/problem+json')\n const hasShape = typeof data.title === 'string' && (typeof data.type === 'string' || typeof data.status === 'number')\n\n if (!isProblemContentType && !hasShape) return null\n\n const message = typeof data.title === 'string' ? data.title : ctx.texts.unknownMessage\n const details: string[] = []\n if (typeof data.detail === 'string' && data.detail) details.push(data.detail)\n\n const status = typeof data.status === 'number' ? data.status : ctx.status\n\n return {\n message,\n details: details.length ? details : undefined,\n status,\n }\n}\n","import { DEFAULT_RESPONSE_ERROR_TEXTS } from '../responseError.defaults'\nimport type {\n ResponseErrorContext,\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorParser,\n ResponseErrorTexts,\n} from '../responseError.types'\n\nimport { abortErrorParser } from './abortErrorParser'\nimport { fileValidationParser } from './fileValidationParser'\nimport { httpStatusParser } from './httpStatusParser'\nimport { jsonApiErrorParser } from './jsonApiErrorParser'\nimport { laravelValidationParser } from './laravelValidationParser'\nimport { networkErrorParser } from './networkErrorParser'\nimport { normalizeError } from './normalizeError'\nimport { plainMessageParser } from './plainMessageParser'\nimport { problemDetailsParser } from './problemDetailsParser'\n\n/**\n * Дефолтная цепочка парсеров. Порядок важен:\n * `abort → network → fileValidation → laravel → problemDetails → jsonApi → httpStatus → plainMessage`.\n *\n * - Ранние специализированные парсеры могут поставить `stop` (abort/file).\n * - HTTP-парсер даёт fallback-kind/message, чтобы остальное могло уточнить.\n * - `plainMessage` всегда последний — добывает хоть какое-то сообщение.\n */\nexport const defaultResponseErrorParsers: ResponseErrorParser[] = [\n abortErrorParser,\n networkErrorParser,\n fileValidationParser,\n laravelValidationParser,\n problemDetailsParser,\n jsonApiErrorParser,\n httpStatusParser,\n plainMessageParser,\n]\n\n/** Добавляет пользовательские парсеры в начало дефолтной цепочки. */\nexport function extendDefaultParsers(extra: ResponseErrorParser[]): ResponseErrorParser[] {\n return [...extra, ...defaultResponseErrorParsers]\n}\n\nexport type CreateResponseErrorClassifierOptions = {\n parsers?: ResponseErrorParser[]\n texts?: Partial<ResponseErrorTexts>\n /** Имя поля основного сообщения в body (для `plainMessageParser`). */\n messageKey?: string\n}\n\n/**\n * Фабрика классификатора. Возвращает функцию `(raw, meta?) => Promise<ResponseErrorInfo>`,\n * которая:\n * 1. нормализует вход через `normalizeError`,\n * 2. строит `ResponseErrorContext`,\n * 3. прогоняет цепочку парсеров (с поддержкой `stop`),\n * 4. собирает финальный `ResponseErrorInfo` с фолбэками из `texts`.\n */\nexport function createResponseErrorClassifier(options: CreateResponseErrorClassifierOptions = {}) {\n const parsers = options.parsers ?? defaultResponseErrorParsers\n const texts: ResponseErrorTexts = { ...DEFAULT_RESPONSE_ERROR_TEXTS, ...(options.texts ?? {}) }\n const messageKey = options.messageKey ?? 'message'\n\n return async function classify(raw: unknown, meta: Record<string, unknown> = {}): Promise<ResponseErrorInfo> {\n const normalized = await normalizeError(raw)\n\n const ctx: ResponseErrorContext = {\n ...normalized,\n meta: { ...meta, _messageKey: messageKey },\n texts,\n }\n\n let kind: ResponseErrorKind | undefined\n let status: number | undefined = ctx.status\n let message: string | undefined\n let details: string[] | undefined\n let fieldErrors: ResponseErrorInfo['fieldErrors']\n\n for (const parser of parsers) {\n const result = parser(ctx)\n if (!result) continue\n if (result.kind) kind = result.kind\n if (typeof result.status === 'number') status = result.status\n if (result.message) message = result.message\n if (result.details?.length) details = result.details\n if (result.fieldErrors?.length) fieldErrors = result.fieldErrors\n if (result.stop) break\n }\n\n if (!kind) kind = 'unknown'\n\n if (!message) message = resolveDefaultMessage(kind, texts)\n\n return {\n kind,\n status,\n message,\n details,\n fieldErrors,\n raw,\n meta,\n }\n }\n}\n\nfunction resolveDefaultMessage(kind: ResponseErrorKind, texts: ResponseErrorTexts): string {\n switch (kind) {\n case 'network': return texts.networkMessage\n case 'aborted': return texts.abortedMessage\n case 'validation': return texts.validationMessage\n case 'client': return texts.clientMessage\n case 'server': return texts.serverMessage\n case 'unknown':\n default: return texts.unknownMessage\n }\n}\n\nexport function resolveResponseErrorTitle(kind: ResponseErrorKind, texts: ResponseErrorTexts): string {\n switch (kind) {\n case 'network': return texts.networkTitle\n case 'aborted': return texts.abortedTitle\n case 'validation': return texts.validationTitle\n case 'client': return texts.clientTitle\n case 'server': return texts.serverTitle\n case 'unknown':\n default: return texts.unknownTitle\n }\n}\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrAlert from '../GrAlert/GrAlert.vue'\nimport GrButton from '../GrButton/GrButton.vue'\n\nimport { resolveResponseErrorTitle } from './parsers/createResponseErrorClassifier'\nimport {\n DEFAULT_AUTO_HIDE_KINDS,\n DEFAULT_RESPONSE_ERROR_TEXTS,\n DEFAULT_TONE_BY_KIND,\n} from './responseError.defaults'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nexport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nconst props = withDefaults(defineProps<{\n /** Готовая структура ошибки. Если `null` — баннер не рендерится. */\n error: ResponseErrorInfo | null\n /** Частичный override текстов. Мерджится с `DEFAULT_RESPONSE_ERROR_TEXTS`. */\n texts?: Partial<ResponseErrorTexts>\n /** Жёсткий оверрайд тона. Бьёт `toneByKind`. */\n tone?: ResponseErrorTone\n /** Маппинг `kind` → `tone`. Мерджится с `DEFAULT_TONE_BY_KIND`. */\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n /** Показывать ли блок `details`/`fieldErrors` под основным сообщением. */\n showDetails?: boolean\n /** Префиксить ли `field:` перед сообщениями по полям. */\n showFieldLabels?: boolean\n /** Человекочитаемые подписи полей (`{ file: 'Файл' }`). */\n fieldLabels?: Record<string, string>\n /** Удалять дубликаты сообщений между `message` и `details`. */\n dedupeDetails?: boolean\n /** Показывать ли кнопку «Повторить». */\n canRetry?: boolean\n /** Показывать ли кнопку «Скрыть». */\n canDismiss?: boolean\n /** Какие `kind` не рендерить вообще (баннер скрывается). */\n autoHideKinds?: ResponseErrorKind[]\n /** Показывать ли HTTP-status бейдж. */\n showStatus?: boolean\n /** Префикс `data-testid`. */\n testIdPrefix?: string\n}>(), {\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({}),\n showDetails: true,\n showFieldLabels: true,\n fieldLabels: () => ({}),\n dedupeDetails: true,\n canRetry: false,\n canDismiss: true,\n autoHideKinds: () => DEFAULT_AUTO_HIDE_KINDS,\n showStatus: true,\n testIdPrefix: 'response-error',\n})\n\nconst emit = defineEmits<{\n (e: 'retry', error: ResponseErrorInfo): void\n (e: 'dismiss'): void\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst i18nTexts = computed<ResponseErrorTexts>(() => {\n const out = {} as ResponseErrorTexts\n for (const key of Object.keys(DEFAULT_RESPONSE_ERROR_TEXTS) as (keyof ResponseErrorTexts)[]) {\n out[key] = t(`gr.responseError.${key}`, DEFAULT_RESPONSE_ERROR_TEXTS[key])\n }\n return out\n})\n\nconst mergedTexts = computed<ResponseErrorTexts>(() => ({\n ...DEFAULT_RESPONSE_ERROR_TEXTS,\n ...i18nTexts.value,\n ...props.texts,\n}))\n\nconst mergedToneByKind = computed<Record<ResponseErrorKind, ResponseErrorTone>>(() => ({\n ...DEFAULT_TONE_BY_KIND,\n ...props.toneByKind,\n}))\n\nconst isHidden = computed(() => {\n if (!props.error) return true\n return props.autoHideKinds.includes(props.error.kind)\n})\n\nconst tone = computed<ResponseErrorTone>(() => {\n if (props.tone) return props.tone\n if (!props.error) return 'danger'\n return mergedToneByKind.value[props.error.kind] ?? 'danger'\n})\n\nconst title = computed(() => {\n if (!props.error) return ''\n return resolveResponseErrorTitle(props.error.kind, mergedTexts.value)\n})\n\n/**\n * Маппинг `kind` → ключ поля сообщения в `ResponseErrorTexts`.\n * Используется, чтобы подменить «дефолтное английское» fallback-сообщение\n * классификатора на i18n-перевод (или текущий `mergedTexts.<kind>Message`).\n */\nconst KIND_MESSAGE_KEY: Record<ResponseErrorKind, keyof ResponseErrorTexts> = {\n network: 'networkMessage',\n aborted: 'abortedMessage',\n validation: 'validationMessage',\n client: 'clientMessage',\n server: 'serverMessage',\n unknown: 'unknownMessage',\n}\n\nconst DEFAULT_FALLBACK_MESSAGES = new Set<string>([\n DEFAULT_RESPONSE_ERROR_TEXTS.networkMessage,\n DEFAULT_RESPONSE_ERROR_TEXTS.abortedMessage,\n DEFAULT_RESPONSE_ERROR_TEXTS.validationMessage,\n DEFAULT_RESPONSE_ERROR_TEXTS.clientMessage,\n DEFAULT_RESPONSE_ERROR_TEXTS.serverMessage,\n DEFAULT_RESPONSE_ERROR_TEXTS.unknownMessage,\n])\n\nconst message = computed(() => {\n const raw = props.error?.message ?? ''\n if (!props.error) return raw\n // Если в `ResponseErrorInfo.message` сидит англ. дефолт-фолбэк классификатора,\n // подменяем на i18n-перевод соответствующего kind.\n if (!raw || DEFAULT_FALLBACK_MESSAGES.has(raw)) {\n return mergedTexts.value[KIND_MESSAGE_KEY[props.error.kind]]\n }\n return raw\n})\n\n/**\n * Сводный список «деталей» под основным `message`.\n * Предпочитаем `fieldErrors` (поле → сообщения), затем — плоский `details`.\n * Дедуплицируем и убираем повтор с `message`.\n */\nconst detailEntries = computed<{ field?: string, text: string }[]>(() => {\n if (!props.error || !props.showDetails) return []\n\n const seen = new Set<string>()\n if (props.dedupeDetails) {\n const main = message.value.trim()\n if (main) seen.add(main)\n }\n\n const result: { field?: string, text: string }[] = []\n const fieldErrors = props.error.fieldErrors\n if (fieldErrors?.length) {\n for (const fe of fieldErrors) {\n for (const m of fe.messages) {\n const text = m.trim()\n if (!text || seen.has(text)) continue\n seen.add(text)\n result.push({ field: fe.field, text })\n }\n }\n if (result.length) return result\n }\n\n const details = props.error.details\n if (details?.length) {\n for (const d of details) {\n const text = (d ?? '').trim()\n if (!text || seen.has(text)) continue\n seen.add(text)\n result.push({ text })\n }\n }\n return result\n})\n\nfunction fieldLabel(field?: string): string | undefined {\n if (!field) return undefined\n return props.fieldLabels[field] ?? field\n}\n\nfunction onRetry(): void {\n if (props.error) emit('retry', props.error)\n}\n\nfunction onDismiss(): void {\n emit('dismiss')\n}\n</script>\n\n<template>\n <GrAlert\n v-if=\"!isHidden && props.error\"\n :tone=\"tone\"\n :title=\"title\"\n :closable=\"props.canDismiss\"\n :data-testid=\"`${props.testIdPrefix}-banner`\"\n :data-kind=\"props.error.kind\"\n @close=\"onDismiss\"\n >\n <div class=\"flex flex-col gap-2\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <span\n v-if=\"props.showStatus && typeof props.error.status === 'number'\"\n class=\"inline-flex items-center rounded-[var(--ds-radius-sm)] bg-[color-mix(in_srgb,currentColor_12%,transparent)] px-1.5 py-0.5 text-[11px] font-700 leading-none\"\n :data-testid=\"`${props.testIdPrefix}-status`\"\n >\n HTTP {{ props.error.status }}\n </span>\n <span\n class=\"text-[13px]\"\n :data-testid=\"`${props.testIdPrefix}-message`\"\n >\n {{ message }}\n </span>\n </div>\n\n <ul\n v-if=\"detailEntries.length\"\n class=\"m-0 list-disc pl-5 text-[12px]\"\n :data-testid=\"`${props.testIdPrefix}-details`\"\n >\n <li\n v-for=\"(entry, idx) in detailEntries\"\n :key=\"`${entry.field ?? ''}:${idx}`\"\n >\n <template v-if=\"props.showFieldLabels && entry.field\">\n <strong>{{ fieldLabel(entry.field) }}:</strong>&nbsp;\n </template>{{ entry.text }}\n </li>\n </ul>\n\n <div\n v-if=\"props.canRetry\"\n class=\"mt-1 flex flex-wrap items-center gap-2\"\n >\n <GrButton\n size=\"sm\"\n variant=\"outline\"\n :data-testid=\"`${props.testIdPrefix}-retry`\"\n @click=\"onRetry\"\n >\n {{ mergedTexts.retryLabel }}\n </GrButton>\n </div>\n </div>\n </GrAlert>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrAlert from '../GrAlert/GrAlert.vue'\nimport GrButton from '../GrButton/GrButton.vue'\n\nimport { resolveResponseErrorTitle } from './parsers/createResponseErrorClassifier'\nimport {\n DEFAULT_AUTO_HIDE_KINDS,\n DEFAULT_RESPONSE_ERROR_TEXTS,\n DEFAULT_TONE_BY_KIND,\n} from './responseError.defaults'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nexport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nconst props = withDefaults(defineProps<{\n /** Готовая структура ошибки. Если `null` — баннер не рендерится. */\n error: ResponseErrorInfo | null\n /** Частичный override текстов. Мерджится с `DEFAULT_RESPONSE_ERROR_TEXTS`. */\n texts?: Partial<ResponseErrorTexts>\n /** Жёсткий оверрайд тона. Бьёт `toneByKind`. */\n tone?: ResponseErrorTone\n /** Маппинг `kind` → `tone`. Мерджится с `DEFAULT_TONE_BY_KIND`. */\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n /** Показывать ли блок `details`/`fieldErrors` под основным сообщением. */\n showDetails?: boolean\n /** Префиксить ли `field:` перед сообщениями по полям. */\n showFieldLabels?: boolean\n /** Человекочитаемые подписи полей (`{ file: 'Файл' }`). */\n fieldLabels?: Record<string, string>\n /** Удалять дубликаты сообщений между `message` и `details`. */\n dedupeDetails?: boolean\n /** Показывать ли кнопку «Повторить». */\n canRetry?: boolean\n /** Показывать ли кнопку «Скрыть». */\n canDismiss?: boolean\n /** Какие `kind` не рендерить вообще (баннер скрывается). */\n autoHideKinds?: ResponseErrorKind[]\n /** Показывать ли HTTP-status бейдж. */\n showStatus?: boolean\n /** Префикс `data-testid`. */\n testIdPrefix?: string\n}>(), {\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({}),\n showDetails: true,\n showFieldLabels: true,\n fieldLabels: () => ({}),\n dedupeDetails: true,\n canRetry: false,\n canDismiss: true,\n autoHideKinds: () => DEFAULT_AUTO_HIDE_KINDS,\n showStatus: true,\n testIdPrefix: 'response-error',\n})\n\nconst emit = defineEmits<{\n (e: 'retry', error: ResponseErrorInfo): void\n (e: 'dismiss'): void\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst i18nTexts = computed<ResponseErrorTexts>(() => {\n const out = {} as ResponseErrorTexts\n for (const key of Object.keys(DEFAULT_RESPONSE_ERROR_TEXTS) as (keyof ResponseErrorTexts)[]) {\n out[key] = t(`gr.responseError.${key}`, DEFAULT_RESPONSE_ERROR_TEXTS[key])\n }\n return out\n})\n\nconst mergedTexts = computed<ResponseErrorTexts>(() => ({\n ...DEFAULT_RESPONSE_ERROR_TEXTS,\n ...i18nTexts.value,\n ...props.texts,\n}))\n\nconst mergedToneByKind = computed<Record<ResponseErrorKind, ResponseErrorTone>>(() => ({\n ...DEFAULT_TONE_BY_KIND,\n ...props.toneByKind,\n}))\n\nconst isHidden = computed(() => {\n if (!props.error) return true\n return props.autoHideKinds.includes(props.error.kind)\n})\n\nconst tone = computed<ResponseErrorTone>(() => {\n if (props.tone) return props.tone\n if (!props.error) return 'danger'\n return mergedToneByKind.value[props.error.kind] ?? 'danger'\n})\n\nconst title = computed(() => {\n if (!props.error) return ''\n return resolveResponseErrorTitle(props.error.kind, mergedTexts.value)\n})\n\n/**\n * Маппинг `kind` → ключ поля сообщения в `ResponseErrorTexts`.\n * Используется, чтобы подменить «дефолтное английское» fallback-сообщение\n * классификатора на i18n-перевод (или текущий `mergedTexts.<kind>Message`).\n */\nconst KIND_MESSAGE_KEY: Record<ResponseErrorKind, keyof ResponseErrorTexts> = {\n network: 'networkMessage',\n aborted: 'abortedMessage',\n validation: 'validationMessage',\n client: 'clientMessage',\n server: 'serverMessage',\n unknown: 'unknownMessage',\n}\n\nconst DEFAULT_FALLBACK_MESSAGES = new Set<string>([\n DEFAULT_RESPONSE_ERROR_TEXTS.networkMessage,\n DEFAULT_RESPONSE_ERROR_TEXTS.abortedMessage,\n DEFAULT_RESPONSE_ERROR_TEXTS.validationMessage,\n DEFAULT_RESPONSE_ERROR_TEXTS.clientMessage,\n DEFAULT_RESPONSE_ERROR_TEXTS.serverMessage,\n DEFAULT_RESPONSE_ERROR_TEXTS.unknownMessage,\n])\n\nconst message = computed(() => {\n const raw = props.error?.message ?? ''\n if (!props.error) return raw\n // Если в `ResponseErrorInfo.message` сидит англ. дефолт-фолбэк классификатора,\n // подменяем на i18n-перевод соответствующего kind.\n if (!raw || DEFAULT_FALLBACK_MESSAGES.has(raw)) {\n return mergedTexts.value[KIND_MESSAGE_KEY[props.error.kind]]\n }\n return raw\n})\n\n/**\n * Сводный список «деталей» под основным `message`.\n * Предпочитаем `fieldErrors` (поле → сообщения), затем — плоский `details`.\n * Дедуплицируем и убираем повтор с `message`.\n */\nconst detailEntries = computed<{ field?: string, text: string }[]>(() => {\n if (!props.error || !props.showDetails) return []\n\n const seen = new Set<string>()\n if (props.dedupeDetails) {\n const main = message.value.trim()\n if (main) seen.add(main)\n }\n\n const result: { field?: string, text: string }[] = []\n const fieldErrors = props.error.fieldErrors\n if (fieldErrors?.length) {\n for (const fe of fieldErrors) {\n for (const m of fe.messages) {\n const text = m.trim()\n if (!text || seen.has(text)) continue\n seen.add(text)\n result.push({ field: fe.field, text })\n }\n }\n if (result.length) return result\n }\n\n const details = props.error.details\n if (details?.length) {\n for (const d of details) {\n const text = (d ?? '').trim()\n if (!text || seen.has(text)) continue\n seen.add(text)\n result.push({ text })\n }\n }\n return result\n})\n\nfunction fieldLabel(field?: string): string | undefined {\n if (!field) return undefined\n return props.fieldLabels[field] ?? field\n}\n\nfunction onRetry(): void {\n if (props.error) emit('retry', props.error)\n}\n\nfunction onDismiss(): void {\n emit('dismiss')\n}\n</script>\n\n<template>\n <GrAlert\n v-if=\"!isHidden && props.error\"\n :tone=\"tone\"\n :title=\"title\"\n :closable=\"props.canDismiss\"\n :data-testid=\"`${props.testIdPrefix}-banner`\"\n :data-kind=\"props.error.kind\"\n @close=\"onDismiss\"\n >\n <div class=\"flex flex-col gap-2\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <span\n v-if=\"props.showStatus && typeof props.error.status === 'number'\"\n class=\"inline-flex items-center rounded-[var(--ds-radius-sm)] bg-[color-mix(in_srgb,currentColor_12%,transparent)] px-1.5 py-0.5 text-[11px] font-700 leading-none\"\n :data-testid=\"`${props.testIdPrefix}-status`\"\n >\n HTTP {{ props.error.status }}\n </span>\n <span\n class=\"text-[13px]\"\n :data-testid=\"`${props.testIdPrefix}-message`\"\n >\n {{ message }}\n </span>\n </div>\n\n <ul\n v-if=\"detailEntries.length\"\n class=\"m-0 list-disc pl-5 text-[12px]\"\n :data-testid=\"`${props.testIdPrefix}-details`\"\n >\n <li\n v-for=\"(entry, idx) in detailEntries\"\n :key=\"`${entry.field ?? ''}:${idx}`\"\n >\n <template v-if=\"props.showFieldLabels && entry.field\">\n <strong>{{ fieldLabel(entry.field) }}:</strong>&nbsp;\n </template>{{ entry.text }}\n </li>\n </ul>\n\n <div\n v-if=\"props.canRetry\"\n class=\"mt-1 flex flex-wrap items-center gap-2\"\n >\n <GrButton\n size=\"sm\"\n variant=\"outline\"\n :data-testid=\"`${props.testIdPrefix}-retry`\"\n @click=\"onRetry\"\n >\n {{ mergedTexts.retryLabel }}\n </GrButton>\n </div>\n </div>\n </GrAlert>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «загрузка файлов»:\n *\n * - Включена кнопка «Повторить» по умолчанию (`canRetry=true`).\n * - Тексты сдвинуты под загрузку файлов.\n * - Опциональный prop `files` пробрасывает контекст наружу через `retry`.\n *\n * Парсеры/нормализация — те же, что у базового баннера. Если нужны кастомные\n * парсеры — используйте напрямую `GrResponseErrorBanner` + `useResponseError`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nconst props = withDefaults(defineProps<{\n error: ResponseErrorInfo | null\n /** Файлы, которые пытались загрузить — пробрасываются в `retry` payload. */\n files?: File[]\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}>(), {\n files: () => [],\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({}),\n canRetry: true,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'upload-error',\n})\n\nconst emit = defineEmits<{\n (e: 'retry', payload: { error: ResponseErrorInfo, files: File[] }): void\n (e: 'dismiss'): void\n}>()\n\nconst UPLOAD_TEXTS: Partial<ResponseErrorTexts> = {\n networkTitle: 'Failed to upload files',\n networkMessage: 'Check your connection and try again.',\n validationTitle: 'Files did not pass validation',\n validationMessage: 'Some of the files do not meet the requirements.',\n serverTitle: 'Upload error on the server',\n serverMessage: 'The server could not process the upload. Please try again.',\n}\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...UPLOAD_TEXTS,\n ...props.texts,\n}))\n\nfunction onRetry(info: ResponseErrorInfo): void {\n emit('retry', { error: info, files: props.files })\n}\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"onRetry\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «загрузка файлов»:\n *\n * - Включена кнопка «Повторить» по умолчанию (`canRetry=true`).\n * - Тексты сдвинуты под загрузку файлов.\n * - Опциональный prop `files` пробрасывает контекст наружу через `retry`.\n *\n * Парсеры/нормализация — те же, что у базового баннера. Если нужны кастомные\n * парсеры — используйте напрямую `GrResponseErrorBanner` + `useResponseError`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nconst props = withDefaults(defineProps<{\n error: ResponseErrorInfo | null\n /** Файлы, которые пытались загрузить — пробрасываются в `retry` payload. */\n files?: File[]\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}>(), {\n files: () => [],\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({}),\n canRetry: true,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'upload-error',\n})\n\nconst emit = defineEmits<{\n (e: 'retry', payload: { error: ResponseErrorInfo, files: File[] }): void\n (e: 'dismiss'): void\n}>()\n\nconst UPLOAD_TEXTS: Partial<ResponseErrorTexts> = {\n networkTitle: 'Failed to upload files',\n networkMessage: 'Check your connection and try again.',\n validationTitle: 'Files did not pass validation',\n validationMessage: 'Some of the files do not meet the requirements.',\n serverTitle: 'Upload error on the server',\n serverMessage: 'The server could not process the upload. Please try again.',\n}\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...UPLOAD_TEXTS,\n ...props.texts,\n}))\n\nfunction onRetry(info: ResponseErrorInfo): void {\n emit('retry', { error: info, files: props.files })\n}\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"onRetry\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «валидация формы»:\n *\n * - `showFieldLabels=true` — рисуются подписи `field:` перед каждой строкой.\n * - `canRetry=false` — обычно пользователь правит поля сам, retry не нужен.\n * - `toneByKind.validation = 'warning'` — визуально «исправь», не «упало».\n * - Тексты сдвинуты под формы.\n *\n * Для кастомных парсеров используйте напрямую `GrResponseErrorBanner` +\n * `useResponseError({ parsers: () => extendDefaultParsers([myParser]) })`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nconst props = withDefaults(defineProps<{\n error: ResponseErrorInfo | null\n fieldLabels?: Record<string, string>\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}>(), {\n fieldLabels: () => ({}),\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({ validation: 'warning' }),\n canRetry: false,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'form-error',\n})\n\nconst emit = defineEmits<{\n (e: 'retry', error: ResponseErrorInfo): void\n (e: 'dismiss'): void\n}>()\n\nconst FORM_TEXTS: Partial<ResponseErrorTexts> = {\n validationTitle: 'Check the form fields',\n validationMessage: 'The server rejected the data. Fix the highlighted fields and try again.',\n clientTitle: 'Failed to save',\n serverTitle: 'Save error',\n serverMessage: 'Could not save the data. Please try again later.',\n}\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...FORM_TEXTS,\n ...props.texts,\n}))\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :field-labels=\"props.fieldLabels\"\n show-field-labels\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"(info) => emit('retry', info)\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «валидация формы»:\n *\n * - `showFieldLabels=true` — рисуются подписи `field:` перед каждой строкой.\n * - `canRetry=false` — обычно пользователь правит поля сам, retry не нужен.\n * - `toneByKind.validation = 'warning'` — визуально «исправь», не «упало».\n * - Тексты сдвинуты под формы.\n *\n * Для кастомных парсеров используйте напрямую `GrResponseErrorBanner` +\n * `useResponseError({ parsers: () => extendDefaultParsers([myParser]) })`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nconst props = withDefaults(defineProps<{\n error: ResponseErrorInfo | null\n fieldLabels?: Record<string, string>\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}>(), {\n fieldLabels: () => ({}),\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({ validation: 'warning' }),\n canRetry: false,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'form-error',\n})\n\nconst emit = defineEmits<{\n (e: 'retry', error: ResponseErrorInfo): void\n (e: 'dismiss'): void\n}>()\n\nconst FORM_TEXTS: Partial<ResponseErrorTexts> = {\n validationTitle: 'Check the form fields',\n validationMessage: 'The server rejected the data. Fix the highlighted fields and try again.',\n clientTitle: 'Failed to save',\n serverTitle: 'Save error',\n serverMessage: 'Could not save the data. Please try again later.',\n}\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...FORM_TEXTS,\n ...props.texts,\n}))\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :field-labels=\"props.fieldLabels\"\n show-field-labels\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"(info) => emit('retry', info)\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","import { computed, ref, shallowRef } from 'vue'\nimport type { ComputedRef, Ref } from 'vue'\n\nimport { createResponseErrorClassifier, defaultResponseErrorParsers } from './parsers/createResponseErrorClassifier'\nimport { DEFAULT_AUTO_HIDE_KINDS, DEFAULT_RESPONSE_ERROR_TEXTS } from './responseError.defaults'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorParser,\n ResponseErrorTexts,\n} from './responseError.types'\n\n/**\n * Опции для `useResponseError`. Все поля опциональны и поддерживают\n * **реактивные геттеры** (`() => value`) — чтобы пробрасывать пропсы\n * родителя без потери реактивности.\n */\nexport type UseResponseErrorOptions = {\n /** Цепочка парсеров. По умолчанию — `defaultResponseErrorParsers`. */\n parsers?: () => ResponseErrorParser[] | undefined\n /** Частичный override текстов баннера. */\n texts?: () => Partial<ResponseErrorTexts> | undefined\n /**\n * `kind`'ы, которые **не** выставляются в state (баннер останется скрытым).\n * По умолчанию пусто — `aborted` показывается info-плашкой. Передайте\n * `['aborted']`, если хотите тихо проглатывать отмены.\n */\n autoHideKinds?: () => ResponseErrorKind[] | undefined\n /** Имя поля основного сообщения в body (для `plainMessageParser`). */\n messageKey?: () => string | undefined\n /** Контекст, который попадёт в `ctx.meta` каждого парсера (`{ files, formId, ... }`). */\n meta?: () => Record<string, unknown> | undefined\n /** Побочка после успешной классификации (логирование, sentry). */\n onClassify?: (info: ResponseErrorInfo) => void\n}\n\n/** Публичный возвращаемый API. */\nexport type UseResponseErrorReturn = {\n /** Текущее состояние ошибки. `null` — баннер скрыт. */\n currentError: Ref<ResponseErrorInfo | null>\n /** `currentError.value !== null`. */\n isVisible: ComputedRef<boolean>\n /** Последний «сырой» вход (для retry/логов). */\n lastRaw: Ref<unknown>\n\n /**\n * Главное API: классифицирует raw, сохраняет в state, возвращает info\n * (или `null`, если `kind` в `autoHideKinds`). Возвращает Promise,\n * т.к. нормализатор поддерживает `Response.json()` (async).\n */\n setRaw: (raw: unknown, meta?: Record<string, unknown>) => Promise<ResponseErrorInfo | null>\n\n /** Установить готовый info, не пропуская через парсеры. */\n setError: (info: ResponseErrorInfo) => void\n\n /** Чистая классификация без записи в state — для предпросмотра. */\n classify: (raw: unknown, meta?: Record<string, unknown>) => Promise<ResponseErrorInfo>\n\n /** Сбросить state (скрыть баннер). */\n dismiss: () => void\n /** Алиас `dismiss`. */\n reset: () => void\n\n /**\n * Хелпер: вызывает `handler(currentError)`. Если handler завершился без\n * исключения — сбрасывает state. Если кинул — оставляет state, поднимает.\n * Удобно бинать к кнопке «Повторить».\n */\n retry: (handler: (info: ResponseErrorInfo) => void | Promise<void>) => Promise<void>\n}\n\n/**\n * Stateful-композабл вокруг `createResponseErrorClassifier`. Хранит\n * `currentError`, инкапсулирует setRaw/retry/dismiss. Подходит для типичного\n * сценария «поймал ошибку запроса → показал баннер → ретрай/скрыть».\n */\nexport function useResponseError(options: UseResponseErrorOptions = {}): UseResponseErrorReturn {\n const currentError = shallowRef<ResponseErrorInfo | null>(null)\n const lastRaw = ref<unknown>(null)\n\n function getClassifier() {\n return createResponseErrorClassifier({\n parsers: options.parsers?.() ?? defaultResponseErrorParsers,\n texts: options.texts?.() ?? {},\n messageKey: options.messageKey?.(),\n })\n }\n\n function isAutoHidden(kind: ResponseErrorKind): boolean {\n const list = options.autoHideKinds?.() ?? DEFAULT_AUTO_HIDE_KINDS\n return list.includes(kind)\n }\n\n async function classify(raw: unknown, extra?: Record<string, unknown>): Promise<ResponseErrorInfo> {\n const classifier = getClassifier()\n const meta = { ...(options.meta?.() ?? {}), ...(extra ?? {}) }\n const info = await classifier(raw, meta)\n options.onClassify?.(info)\n return info\n }\n\n async function setRaw(raw: unknown, extra?: Record<string, unknown>): Promise<ResponseErrorInfo | null> {\n lastRaw.value = raw\n const info = await classify(raw, extra)\n if (isAutoHidden(info.kind)) {\n currentError.value = null\n return null\n }\n currentError.value = info\n return info\n }\n\n function setError(info: ResponseErrorInfo): void {\n currentError.value = info\n }\n\n function dismiss(): void {\n currentError.value = null\n }\n\n async function retry(handler: (info: ResponseErrorInfo) => void | Promise<void>): Promise<void> {\n const info = currentError.value\n if (!info) return\n await handler(info)\n currentError.value = null\n }\n\n return {\n currentError,\n isVisible: computed(() => currentError.value !== null),\n lastRaw,\n setRaw,\n setError,\n classify,\n dismiss,\n reset: dismiss,\n retry,\n }\n}\n\nexport { DEFAULT_RESPONSE_ERROR_TEXTS }\n","/**\n * Единый перечень дизайн-тонов для всех компонентов библиотеки.\n *\n * Источник истины: список объявлен как `as const`-кортеж, из которого\n * автоматически выводится тип `GrTone`. Это позволяет использовать\n * `GR_TONES` в рантайме (валидация, итерация, safelist) и `GrTone`\n * в типах одновременно, без расхождений.\n */\nexport const GR_TONES = [\n 'primary',\n 'neutral',\n 'success',\n 'warning',\n 'danger',\n 'info',\n 'slate',\n 'azure',\n] as const\n\nexport type GrTone = typeof GR_TONES[number]\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/components/GrDialogService/store.ts","../src/components/GrDialogService/GrDialogServiceHost.vue","../src/components/GrDialogService/GrDialogServiceHost.vue","../src/components/GrDialogService/useDialogService.ts","../src/components/GrDialogService/config.ts","../src/components/shared/tones.ts"],"sourcesContent":["import { reactive } from 'vue'\n\nimport type {\n DialogBaseOptions,\n DialogKind,\n DialogOnConfirm,\n DialogResult,\n} from './types'\n\n/**\n * Внутреннее описание одного запроса диалога в очереди. Создаётся методами\n * сервиса (`confirm`/`alert`/`prompt`/`open`) и потребляется хостом\n * (`GrDialogServiceHost`), который рендерит «голову» очереди (FIFO).\n */\nexport interface DialogRequest {\n id: string\n kind: DialogKind\n message: string\n options: DialogBaseOptions\n onConfirm?: DialogOnConfirm<any>\n /** Резолвит промис вызова детальным результатом `{ action, value }`. */\n resolve: (result: DialogResult<any>) => void\n}\n\n/**\n * Модульный синглтон очереди диалогов: единый источник правды для всех\n * вызовов сервиса. Хост-компонент рендерит только `queue[0]` — это\n * сериализует диалоги (FIFO) и исключает конкуренцию за фокус-трап.\n */\nexport const dialogQueue = reactive<DialogRequest[]>([])\n\nlet counter = 0\n\nexport function makeDialogId(): string {\n counter += 1\n return `gr-dialog-${Date.now()}-${counter}`\n}\n","<script setup lang=\"ts\">\n/**\n * GrDialogServiceHost — внутренний компонент-оркестратор императивного\n * `useDialogService`. Не предназначен для прямого использования в шаблонах.\n *\n * Рендерит «голову» очереди `dialogQueue` (FIFO-сериализация), переиспользуя\n * декларативные `GrConfirmDialog`/`GrPromptDialog`. Управляет состоянием\n * загрузки и ошибок во время async-`onConfirm`, прогоняя «сырые» ответы\n * сервера через цепочку парсеров `GrResponseErrorBanner`.\n */\nimport { computed, nextTick, onBeforeUnmount, ref, shallowRef, watch } from 'vue'\n\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrConfirmDialog from '../GrConfirmDialog/GrConfirmDialog.vue'\nimport GrPromptDialog from '../GrPromptDialog/GrPromptDialog.vue'\nimport {\n coreResponseErrorParsers,\n createResponseErrorClassifier,\n responseErrorParserPresets,\n} from '../GrResponseErrorBanner'\nimport type { ResponseErrorInfo } from '../GrResponseErrorBanner'\n\nimport { dialogQueue } from './store'\nimport type { DialogRequest } from './store'\nimport type { DialogCloseAction, DialogConfirmContext } from './types'\n\nconst active = computed<DialogRequest | null>(() => dialogQueue[0] ?? null)\n\nconst open = ref(false)\nconst loading = ref(false)\nconst currentError = shallowRef<ResponseErrorInfo | null>(null)\nconst fieldError = ref<string | null>(null)\nconst promptValue = ref('')\n\nlet controller: AbortController | null = null\nlet finishing = false\nlet externalAbortCleanup: (() => void) | null = null\n\nfunction resetState(): void {\n loading.value = false\n currentError.value = null\n fieldError.value = null\n finishing = false\n}\n\nfunction buildClassifier(req: DialogRequest) {\n const opts = req.options\n const parsers = typeof opts.errorParsers === 'function'\n ? opts.errorParsers(responseErrorParserPresets)\n : opts.errorParsers ?? coreResponseErrorParsers\n\n return createResponseErrorClassifier({\n parsers,\n texts: opts.errorTexts,\n messageKey: opts.errorMessageKey,\n })\n}\n\nwatch(\n () => active.value?.id,\n (id) => {\n cleanupExternalAbort()\n resetState()\n\n const req = active.value\n if (!req || !id) {\n open.value = false\n return\n }\n\n promptValue.value = req.options && 'value' in req.options\n ? ((req.options as { value?: string }).value ?? '')\n : ''\n\n controller = new AbortController()\n\n // Внешний AbortSignal закрывает диалог как `close`.\n const sig = req.options.signal\n if (sig) {\n if (sig.aborted) {\n finish('close')\n return\n }\n const onAbort = () => finish('close')\n sig.addEventListener('abort', onAbort)\n externalAbortCleanup = () => sig.removeEventListener('abort', onAbort)\n }\n\n void nextTick(() => {\n open.value = true\n })\n },\n)\n\nfunction cleanupExternalAbort(): void {\n externalAbortCleanup?.()\n externalAbortCleanup = null\n}\n\nfunction finish(action: DialogCloseAction, value?: unknown): void {\n const req = active.value\n if (!req || finishing) return\n finishing = true\n\n open.value = false\n controller?.abort()\n controller = null\n cleanupExternalAbort()\n\n req.resolve({ action, value })\n\n // Снимаем «голову» очереди на следующем тике — watch откроет следующий диалог.\n void nextTick(() => {\n const index = dialogQueue.findIndex(item => item.id === req.id)\n if (index >= 0) dialogQueue.splice(index, 1)\n })\n}\n\nfunction buildContext(req: DialogRequest, value: unknown): DialogConfirmContext<any> & { _errorSet: () => boolean } {\n let errorSet = false\n\n const setError = (message: string | null): void => {\n if (message == null) {\n currentError.value = null\n return\n }\n errorSet = true\n currentError.value = { kind: 'unknown', message, raw: message }\n }\n\n const setFieldError = (field: string, message: string | null): void => {\n if (message == null) {\n fieldError.value = null\n return\n }\n errorSet = true\n fieldError.value = message\n }\n\n const clearErrors = (): void => {\n currentError.value = null\n fieldError.value = null\n }\n\n const setRawError = async (raw: unknown, meta?: Record<string, unknown>): Promise<ResponseErrorInfo | null> => {\n const info = await buildClassifier(req)(raw, meta)\n if (req.kind === 'prompt' && info.fieldErrors?.length) {\n const match = info.fieldErrors.find(f => f.field === 'value') ?? info.fieldErrors[0]\n fieldError.value = match.messages.join(' ')\n }\n currentError.value = info\n errorSet = true\n return info\n }\n\n return {\n value,\n signal: controller!.signal,\n setError,\n setRawError,\n setFieldError,\n clearErrors,\n setLoading: (v: boolean) => { loading.value = v },\n close: (action: DialogCloseAction = 'close') => finish(action),\n _errorSet: () => errorSet,\n }\n}\n\nasync function handleConfirm(): Promise<void> {\n const req = active.value\n if (!req) return\n\n const value = req.kind === 'prompt' ? promptValue.value : undefined\n\n if (!req.onConfirm) {\n finish('confirm', value)\n return\n }\n\n currentError.value = null\n fieldError.value = null\n loading.value = true\n\n const ctx = buildContext(req, value)\n\n try {\n const result = await req.onConfirm(ctx)\n loading.value = false\n if (finishing) return // ctx.close уже завершил диалог\n if (result === false) return // оставить открытым без ошибки\n if (currentError.value || fieldError.value || ctx._errorSet()) return // есть ошибка — не закрывать\n finish('confirm', value)\n }\n catch (error) {\n loading.value = false\n if (finishing) return\n if (!ctx._errorSet()) await ctx.setRawError(error)\n // оставить диалог открытым с показанной ошибкой\n }\n}\n\nfunction handleCancel(): void {\n finish('cancel')\n}\n\nfunction handleModelUpdate(value: boolean): void {\n if (!value) finish('close')\n}\n\nonBeforeUnmount(() => {\n cleanupExternalAbort()\n controller?.abort()\n})\n\n// Прокидываемые в дочерний диалог общие пропы.\nconst sharedProps = computed(() => {\n const o = active.value?.options ?? {}\n return {\n title: o.title,\n size: o.size,\n closeOnBackdrop: o.closeOnBackdrop,\n closeOnEsc: o.closeOnEsc,\n showHeader: o.showHeader,\n showCloseButton: o.showCloseButton,\n headerConfig: o.headerConfig,\n footerConfig: o.footerConfig,\n bodyConfig: o.bodyConfig,\n closeLabel: o.closeLabel,\n buttonSize: o.buttonSize,\n confirmText: o.confirmText,\n confirmVariant: o.confirmVariant,\n confirmTone: o.confirmTone,\n }\n})\n</script>\n\n<template>\n <template v-if=\"active\">\n <!-- prompt -->\n <GrPromptDialog\n v-if=\"active.kind === 'prompt'\"\n v-bind=\"sharedProps\"\n v-model:value=\"promptValue\"\n :model-value=\"open\"\n :description=\"active.options.message ?? active.options.description\"\n :label=\"(active.options as any).label\"\n :placeholder=\"(active.options as any).placeholder\"\n :required=\"(active.options as any).required ?? false\"\n :required-error-text=\"(active.options as any).requiredErrorText\"\n :cancel-text=\"(active.options as any).cancelText\"\n :error=\"currentError\"\n :field-error=\"fieldError\"\n :confirm-loading=\"loading\"\n :close-on-confirm=\"false\"\n @update:model-value=\"handleModelUpdate\"\n @confirm=\"handleConfirm\"\n @cancel=\"handleCancel\"\n />\n\n <!-- alert: confirm-диалог без кнопки Cancel -->\n <GrConfirmDialog\n v-else-if=\"active.kind === 'alert'\"\n :model-value=\"open\"\n v-bind=\"sharedProps\"\n :description=\"active.options.message ?? active.options.description\"\n :error=\"currentError\"\n :confirm-loading=\"loading\"\n :close-on-confirm=\"false\"\n @update:model-value=\"handleModelUpdate\"\n @confirm=\"handleConfirm\"\n >\n <template #footer>\n <div class=\"flex items-center justify-end gap-3\">\n <GrButton\n data-testid=\"ds-alert-confirm\"\n :variant=\"sharedProps.confirmVariant ?? 'primary'\"\n :tone=\"sharedProps.confirmTone ?? 'primary'\"\n :size=\"sharedProps.buttonSize\"\n :loading=\"loading\"\n @click=\"handleConfirm\"\n >\n {{ sharedProps.confirmText ?? 'OK' }}\n </GrButton>\n </div>\n </template>\n </GrConfirmDialog>\n\n <!-- confirm -->\n <GrConfirmDialog\n v-else\n :model-value=\"open\"\n v-bind=\"sharedProps\"\n :description=\"active.options.message ?? active.options.description\"\n :cancel-text=\"(active.options as any).cancelText\"\n :error=\"currentError\"\n :confirm-loading=\"loading\"\n :close-on-confirm=\"false\"\n @update:model-value=\"handleModelUpdate\"\n @confirm=\"handleConfirm\"\n @cancel=\"handleCancel\"\n />\n </template>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrDialogServiceHost — внутренний компонент-оркестратор императивного\n * `useDialogService`. Не предназначен для прямого использования в шаблонах.\n *\n * Рендерит «голову» очереди `dialogQueue` (FIFO-сериализация), переиспользуя\n * декларативные `GrConfirmDialog`/`GrPromptDialog`. Управляет состоянием\n * загрузки и ошибок во время async-`onConfirm`, прогоняя «сырые» ответы\n * сервера через цепочку парсеров `GrResponseErrorBanner`.\n */\nimport { computed, nextTick, onBeforeUnmount, ref, shallowRef, watch } from 'vue'\n\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrConfirmDialog from '../GrConfirmDialog/GrConfirmDialog.vue'\nimport GrPromptDialog from '../GrPromptDialog/GrPromptDialog.vue'\nimport {\n coreResponseErrorParsers,\n createResponseErrorClassifier,\n responseErrorParserPresets,\n} from '../GrResponseErrorBanner'\nimport type { ResponseErrorInfo } from '../GrResponseErrorBanner'\n\nimport { dialogQueue } from './store'\nimport type { DialogRequest } from './store'\nimport type { DialogCloseAction, DialogConfirmContext } from './types'\n\nconst active = computed<DialogRequest | null>(() => dialogQueue[0] ?? null)\n\nconst open = ref(false)\nconst loading = ref(false)\nconst currentError = shallowRef<ResponseErrorInfo | null>(null)\nconst fieldError = ref<string | null>(null)\nconst promptValue = ref('')\n\nlet controller: AbortController | null = null\nlet finishing = false\nlet externalAbortCleanup: (() => void) | null = null\n\nfunction resetState(): void {\n loading.value = false\n currentError.value = null\n fieldError.value = null\n finishing = false\n}\n\nfunction buildClassifier(req: DialogRequest) {\n const opts = req.options\n const parsers = typeof opts.errorParsers === 'function'\n ? opts.errorParsers(responseErrorParserPresets)\n : opts.errorParsers ?? coreResponseErrorParsers\n\n return createResponseErrorClassifier({\n parsers,\n texts: opts.errorTexts,\n messageKey: opts.errorMessageKey,\n })\n}\n\nwatch(\n () => active.value?.id,\n (id) => {\n cleanupExternalAbort()\n resetState()\n\n const req = active.value\n if (!req || !id) {\n open.value = false\n return\n }\n\n promptValue.value = req.options && 'value' in req.options\n ? ((req.options as { value?: string }).value ?? '')\n : ''\n\n controller = new AbortController()\n\n // Внешний AbortSignal закрывает диалог как `close`.\n const sig = req.options.signal\n if (sig) {\n if (sig.aborted) {\n finish('close')\n return\n }\n const onAbort = () => finish('close')\n sig.addEventListener('abort', onAbort)\n externalAbortCleanup = () => sig.removeEventListener('abort', onAbort)\n }\n\n void nextTick(() => {\n open.value = true\n })\n },\n)\n\nfunction cleanupExternalAbort(): void {\n externalAbortCleanup?.()\n externalAbortCleanup = null\n}\n\nfunction finish(action: DialogCloseAction, value?: unknown): void {\n const req = active.value\n if (!req || finishing) return\n finishing = true\n\n open.value = false\n controller?.abort()\n controller = null\n cleanupExternalAbort()\n\n req.resolve({ action, value })\n\n // Снимаем «голову» очереди на следующем тике — watch откроет следующий диалог.\n void nextTick(() => {\n const index = dialogQueue.findIndex(item => item.id === req.id)\n if (index >= 0) dialogQueue.splice(index, 1)\n })\n}\n\nfunction buildContext(req: DialogRequest, value: unknown): DialogConfirmContext<any> & { _errorSet: () => boolean } {\n let errorSet = false\n\n const setError = (message: string | null): void => {\n if (message == null) {\n currentError.value = null\n return\n }\n errorSet = true\n currentError.value = { kind: 'unknown', message, raw: message }\n }\n\n const setFieldError = (field: string, message: string | null): void => {\n if (message == null) {\n fieldError.value = null\n return\n }\n errorSet = true\n fieldError.value = message\n }\n\n const clearErrors = (): void => {\n currentError.value = null\n fieldError.value = null\n }\n\n const setRawError = async (raw: unknown, meta?: Record<string, unknown>): Promise<ResponseErrorInfo | null> => {\n const info = await buildClassifier(req)(raw, meta)\n if (req.kind === 'prompt' && info.fieldErrors?.length) {\n const match = info.fieldErrors.find(f => f.field === 'value') ?? info.fieldErrors[0]\n fieldError.value = match.messages.join(' ')\n }\n currentError.value = info\n errorSet = true\n return info\n }\n\n return {\n value,\n signal: controller!.signal,\n setError,\n setRawError,\n setFieldError,\n clearErrors,\n setLoading: (v: boolean) => { loading.value = v },\n close: (action: DialogCloseAction = 'close') => finish(action),\n _errorSet: () => errorSet,\n }\n}\n\nasync function handleConfirm(): Promise<void> {\n const req = active.value\n if (!req) return\n\n const value = req.kind === 'prompt' ? promptValue.value : undefined\n\n if (!req.onConfirm) {\n finish('confirm', value)\n return\n }\n\n currentError.value = null\n fieldError.value = null\n loading.value = true\n\n const ctx = buildContext(req, value)\n\n try {\n const result = await req.onConfirm(ctx)\n loading.value = false\n if (finishing) return // ctx.close уже завершил диалог\n if (result === false) return // оставить открытым без ошибки\n if (currentError.value || fieldError.value || ctx._errorSet()) return // есть ошибка — не закрывать\n finish('confirm', value)\n }\n catch (error) {\n loading.value = false\n if (finishing) return\n if (!ctx._errorSet()) await ctx.setRawError(error)\n // оставить диалог открытым с показанной ошибкой\n }\n}\n\nfunction handleCancel(): void {\n finish('cancel')\n}\n\nfunction handleModelUpdate(value: boolean): void {\n if (!value) finish('close')\n}\n\nonBeforeUnmount(() => {\n cleanupExternalAbort()\n controller?.abort()\n})\n\n// Прокидываемые в дочерний диалог общие пропы.\nconst sharedProps = computed(() => {\n const o = active.value?.options ?? {}\n return {\n title: o.title,\n size: o.size,\n closeOnBackdrop: o.closeOnBackdrop,\n closeOnEsc: o.closeOnEsc,\n showHeader: o.showHeader,\n showCloseButton: o.showCloseButton,\n headerConfig: o.headerConfig,\n footerConfig: o.footerConfig,\n bodyConfig: o.bodyConfig,\n closeLabel: o.closeLabel,\n buttonSize: o.buttonSize,\n confirmText: o.confirmText,\n confirmVariant: o.confirmVariant,\n confirmTone: o.confirmTone,\n }\n})\n</script>\n\n<template>\n <template v-if=\"active\">\n <!-- prompt -->\n <GrPromptDialog\n v-if=\"active.kind === 'prompt'\"\n v-bind=\"sharedProps\"\n v-model:value=\"promptValue\"\n :model-value=\"open\"\n :description=\"active.options.message ?? active.options.description\"\n :label=\"(active.options as any).label\"\n :placeholder=\"(active.options as any).placeholder\"\n :required=\"(active.options as any).required ?? false\"\n :required-error-text=\"(active.options as any).requiredErrorText\"\n :cancel-text=\"(active.options as any).cancelText\"\n :error=\"currentError\"\n :field-error=\"fieldError\"\n :confirm-loading=\"loading\"\n :close-on-confirm=\"false\"\n @update:model-value=\"handleModelUpdate\"\n @confirm=\"handleConfirm\"\n @cancel=\"handleCancel\"\n />\n\n <!-- alert: confirm-диалог без кнопки Cancel -->\n <GrConfirmDialog\n v-else-if=\"active.kind === 'alert'\"\n :model-value=\"open\"\n v-bind=\"sharedProps\"\n :description=\"active.options.message ?? active.options.description\"\n :error=\"currentError\"\n :confirm-loading=\"loading\"\n :close-on-confirm=\"false\"\n @update:model-value=\"handleModelUpdate\"\n @confirm=\"handleConfirm\"\n >\n <template #footer>\n <div class=\"flex items-center justify-end gap-3\">\n <GrButton\n data-testid=\"ds-alert-confirm\"\n :variant=\"sharedProps.confirmVariant ?? 'primary'\"\n :tone=\"sharedProps.confirmTone ?? 'primary'\"\n :size=\"sharedProps.buttonSize\"\n :loading=\"loading\"\n @click=\"handleConfirm\"\n >\n {{ sharedProps.confirmText ?? 'OK' }}\n </GrButton>\n </div>\n </template>\n </GrConfirmDialog>\n\n <!-- confirm -->\n <GrConfirmDialog\n v-else\n :model-value=\"open\"\n v-bind=\"sharedProps\"\n :description=\"active.options.message ?? active.options.description\"\n :cancel-text=\"(active.options as any).cancelText\"\n :error=\"currentError\"\n :confirm-loading=\"loading\"\n :close-on-confirm=\"false\"\n @update:model-value=\"handleModelUpdate\"\n @confirm=\"handleConfirm\"\n @cancel=\"handleCancel\"\n />\n </template>\n</template>\n","import { createVNode, getCurrentInstance, render } from 'vue'\nimport type { AppContext } from 'vue'\n\nimport GrDialogServiceHost from './GrDialogServiceHost.vue'\nimport { dialogQueue, makeDialogId } from './store'\nimport type { DialogRequest } from './store'\nimport type {\n DialogAlertOptions,\n DialogBaseOptions,\n DialogConfirmOptions,\n DialogKind,\n DialogOnConfirm,\n DialogPromise,\n DialogPromptOptions,\n DialogResult,\n DialogService,\n DialogServiceDefaults,\n} from './types'\n\n/**\n * `useDialogService` — императивный сервис диалогов (в духе Element Plus\n * `ElMessageBox`). Позволяет вызывать `confirm`/`alert`/`prompt` из `<script>`\n * или `.ts` без вставки компонента в шаблон.\n *\n * Поверх существующих `GrConfirmDialog`/`GrPromptDialog`: лениво монтирует\n * единый хост (`GrDialogServiceHost`) в `document.body`, наследуя контекст\n * приложения (i18n / тема / `granular-provider`). Диалоги сериализуются\n * очередью FIFO.\n */\n\nlet mounted = false\nlet container: HTMLElement | null = null\nlet cachedAppContext: AppContext | null = null\n\nfunction ensureMounted(appContext?: AppContext | null): void {\n if (typeof window === 'undefined' || typeof document === 'undefined') return\n\n if (appContext) cachedAppContext = appContext\n if (mounted) return\n\n container = document.createElement('div')\n container.setAttribute('data-gr-dialog-service-host', '')\n document.body.appendChild(container)\n\n const vnode = createVNode(GrDialogServiceHost)\n vnode.appContext = cachedAppContext ?? null\n render(vnode, container)\n mounted = true\n}\n\n/** Тестовая/служебная очистка смонтированного хоста. */\nexport function teardownDialogService(): void {\n if (container) {\n render(null, container)\n container.remove()\n container = null\n }\n mounted = false\n dialogQueue.splice(0, dialogQueue.length)\n}\n\nfunction enqueue(\n kind: DialogKind,\n message: string,\n options: DialogBaseOptions,\n onConfirm: DialogOnConfirm<any> | undefined,\n): { promise: Promise<DialogResult<any>>, close: () => void } {\n ensureMounted(options.appContext ?? cachedAppContext)\n\n const id = makeDialogId()\n let resolveFn!: (result: DialogResult<any>) => void\n const promise = new Promise<DialogResult<any>>((resolve) => {\n resolveFn = resolve\n })\n\n const request: DialogRequest = {\n id,\n kind,\n message,\n options: { ...options, message },\n onConfirm,\n resolve: resolveFn,\n }\n\n dialogQueue.push(request)\n\n const close = (): void => {\n const index = dialogQueue.findIndex(item => item.id === id)\n if (index < 0) return\n dialogQueue.splice(index, 1)\n resolveFn({ action: 'close' })\n }\n\n return { promise, close }\n}\n\nfunction withClose<T>(promise: Promise<T>, close: () => void): DialogPromise<T> {\n const result = promise as DialogPromise<T>\n result.close = close\n return result\n}\n\nfunction mergeErrorDefaults(\n defaults: DialogServiceDefaults,\n options: DialogBaseOptions,\n): DialogBaseOptions {\n return {\n size: defaults.size,\n confirmText: defaults.confirmText,\n confirmVariant: defaults.confirmVariant,\n confirmTone: defaults.confirmTone,\n buttonSize: defaults.buttonSize,\n closeOnBackdrop: defaults.closeOnBackdrop,\n closeOnEsc: defaults.closeOnEsc,\n errorParsers: defaults.errorParsers,\n errorTexts: defaults.errorTexts,\n errorMessageKey: defaults.errorMessageKey,\n fieldLabels: defaults.fieldLabels,\n ...options,\n }\n}\n\n/**\n * Создаёт сервис диалогов. Опциональные `defaults` применяются ко всем\n * вызовам (можно переопределить в каждом конкретном вызове).\n *\n * Контекст приложения кэшируется автоматически при первом вызове внутри\n * `setup`. Для вызовов вне компонента используйте `setAppContext`.\n */\nexport function useDialogService(defaults: DialogServiceDefaults = {}): DialogService {\n // Авто-кэш appContext из текущего компонента (если вызвано в setup).\n const instance = getCurrentInstance()\n if (instance?.appContext && !cachedAppContext) {\n cachedAppContext = instance.appContext\n }\n\n function confirm(message: string, options: DialogConfirmOptions = {}): DialogPromise<boolean> {\n const merged = mergeErrorDefaults(defaults, options)\n const { promise, close } = enqueue('confirm', message, merged, options.onConfirm)\n return withClose(promise.then(r => r.action === 'confirm'), close)\n }\n\n function alert(message: string, options: DialogAlertOptions = {}): DialogPromise<void> {\n const merged = mergeErrorDefaults(defaults, options)\n const { promise, close } = enqueue('alert', message, merged, options.onConfirm)\n return withClose(promise.then(() => undefined), close)\n }\n\n function prompt(message: string, options: DialogPromptOptions = {}): DialogPromise<string | null> {\n const merged = mergeErrorDefaults(defaults, options)\n const { promise, close } = enqueue('prompt', message, merged, options.onConfirm)\n return withClose(\n promise.then(r => (r.action === 'confirm' ? ((r.value as string) ?? '') : null)),\n close,\n )\n }\n\n function open<V = unknown>(\n kind: DialogKind,\n message: string,\n options: DialogBaseOptions = {},\n ): DialogPromise<DialogResult<V>> {\n const merged = mergeErrorDefaults(defaults, options)\n const { promise, close } = enqueue(kind, message, merged, (options as DialogConfirmOptions).onConfirm)\n return withClose(promise as Promise<DialogResult<V>>, close)\n }\n\n function closeAll(): void {\n while (dialogQueue.length > 0) {\n const request = dialogQueue.pop()!\n request.resolve({ action: 'close' })\n }\n }\n\n function setAppContext(ctx: AppContext | null): void {\n cachedAppContext = ctx\n }\n\n return { confirm, alert, prompt, open, closeAll, setAppContext }\n}\n\n/** Готовый синглтон-сервис с дефолтными настройками. */\nexport const dialogService: DialogService = useDialogService()\n","import {defineGranularComponent} from '@feugene/unocss-preset-granular/contract'\n\nexport const grDialogServiceConfig = defineGranularComponent(import.meta.url, {\n name: 'GrDialogServiceHost',\n dependencies: ['GrButton', 'GrDialog', 'GrConfirmDialog', 'GrPromptDialog', 'GrResponseErrorBanner'],\n})\n","/**\n * Единый перечень дизайн-тонов для всех компонентов библиотеки.\n *\n * Источник истины: список объявлен как `as const`-кортеж, из которого\n * автоматически выводится тип `GrTone`. Это позволяет использовать\n * `GR_TONES` в рантайме (валидация, итерация, safelist) и `GrTone`\n * в типах одновременно, без расхождений.\n */\nexport const GR_TONES = [\n 'primary',\n 'neutral',\n 'success',\n 'warning',\n 'danger',\n 'info',\n 'slate',\n 'azure',\n] as const\n\nexport type GrTone = typeof GR_TONES[number]\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton';
2
2
  import type { GrDialogSectionConfig, GrDialogSize } from '../GrDialog';
3
+ import type { ResponseErrorInfo } from '../GrResponseErrorBanner';
3
4
  export interface GrConfirmDialogProps {
4
5
  modelValue: boolean;
5
6
  title?: string;
@@ -19,12 +20,32 @@ export interface GrConfirmDialogProps {
19
20
  cancelText?: string;
20
21
  confirmVariant?: GrButtonVariant;
21
22
  confirmTone?: GrButtonTone;
23
+ /**
24
+ * Структура ошибки ответа сервера для показа в теле диалога
25
+ * (через `GrResponseErrorBanner`). Используется императивным
26
+ * `useDialogService` для async-`onConfirm`. `null` — блок скрыт.
27
+ */
28
+ error?: ResponseErrorInfo | null;
29
+ /** Состояние загрузки кнопки Confirm (async-`onConfirm` in-flight). */
30
+ confirmLoading?: boolean;
31
+ /** Принудительно дизейблит кнопку Confirm. */
32
+ confirmDisabled?: boolean;
33
+ /**
34
+ * Закрывать ли диалог автоматически по клику Confirm. По умолчанию `true`
35
+ * (историческое поведение). `false` — отдаёт управление закрытием наружу
36
+ * (нужно `useDialogService`, который ждёт результат async-`onConfirm`).
37
+ */
38
+ closeOnConfirm?: boolean;
22
39
  }
23
- declare var __VLS_8: {}, __VLS_11: {};
40
+ declare var __VLS_8: {}, __VLS_10: {
41
+ error: ResponseErrorInfo | null;
42
+ }, __VLS_18: {};
24
43
  type __VLS_Slots = {} & {
25
44
  default?: (props: typeof __VLS_8) => any;
26
45
  } & {
27
- footer?: (props: typeof __VLS_11) => any;
46
+ error?: (props: typeof __VLS_10) => any;
47
+ } & {
48
+ footer?: (props: typeof __VLS_18) => any;
28
49
  };
29
50
  declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<GrConfirmDialogProps>, {
30
51
  title: string;
@@ -43,6 +64,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
43
64
  cancelText: string;
44
65
  confirmVariant: string;
45
66
  confirmTone: string;
67
+ error: null;
68
+ confirmLoading: boolean;
69
+ confirmDisabled: boolean;
70
+ closeOnConfirm: boolean;
46
71
  }>>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
47
72
  "update:modelValue": (value: boolean) => void;
48
73
  confirm: () => void;
@@ -64,13 +89,18 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
64
89
  cancelText: string;
65
90
  confirmVariant: string;
66
91
  confirmTone: string;
92
+ error: null;
93
+ confirmLoading: boolean;
94
+ confirmDisabled: boolean;
95
+ closeOnConfirm: boolean;
67
96
  }>>> & Readonly<{
68
97
  "onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
69
- onConfirm?: (() => any) | undefined;
70
98
  onCancel?: (() => any) | undefined;
99
+ onConfirm?: (() => any) | undefined;
71
100
  }>, {
72
101
  title: string;
73
102
  size: GrDialogSize;
103
+ error: ResponseErrorInfo | null;
74
104
  closeOnBackdrop: boolean;
75
105
  closeOnEsc: boolean;
76
106
  description: string;
@@ -85,6 +115,9 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
85
115
  cancelText: string;
86
116
  confirmVariant: GrButtonVariant;
87
117
  confirmTone: GrButtonTone;
118
+ confirmLoading: boolean;
119
+ confirmDisabled: boolean;
120
+ closeOnConfirm: boolean;
88
121
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
89
122
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
90
123
  declare const _default: typeof __VLS_export;
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1 @@
1
+ export declare const grDialogServiceConfig: import("@feugene/unocss-preset-granular").GranularComponentDescriptor<"GrDialogServiceHost">;
@@ -0,0 +1,4 @@
1
+ export { default as GrDialogServiceHost } from './GrDialogServiceHost.vue';
2
+ export { dialogService, teardownDialogService, useDialogService } from './useDialogService';
3
+ export { grDialogServiceConfig } from './config';
4
+ export type { DialogAlertOptions, DialogBaseOptions, DialogCloseAction, DialogConfirmContext, DialogConfirmOptions, DialogErrorOptions, DialogKind, DialogOnConfirm, DialogPromise, DialogPromptOptions, DialogResult, DialogService, DialogServiceDefaults, } from './types';
@@ -0,0 +1,22 @@
1
+ import type { DialogBaseOptions, DialogKind, DialogOnConfirm, DialogResult } from './types';
2
+ /**
3
+ * Внутреннее описание одного запроса диалога в очереди. Создаётся методами
4
+ * сервиса (`confirm`/`alert`/`prompt`/`open`) и потребляется хостом
5
+ * (`GrDialogServiceHost`), который рендерит «голову» очереди (FIFO).
6
+ */
7
+ export interface DialogRequest {
8
+ id: string;
9
+ kind: DialogKind;
10
+ message: string;
11
+ options: DialogBaseOptions;
12
+ onConfirm?: DialogOnConfirm<any>;
13
+ /** Резолвит промис вызова детальным результатом `{ action, value }`. */
14
+ resolve: (result: DialogResult<any>) => void;
15
+ }
16
+ /**
17
+ * Модульный синглтон очереди диалогов: единый источник правды для всех
18
+ * вызовов сервиса. Хост-компонент рендерит только `queue[0]` — это
19
+ * сериализует диалоги (FIFO) и исключает конкуренцию за фокус-трап.
20
+ */
21
+ export declare const dialogQueue: import("vue").Reactive<DialogRequest[]>;
22
+ export declare function makeDialogId(): string;
@@ -0,0 +1,141 @@
1
+ import type { AppContext } from 'vue';
2
+ import type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton';
3
+ import type { GrDialogSectionConfig, GrDialogSize } from '../GrDialog';
4
+ import type { ResponseErrorInfo, ResponseErrorParser, ResponseErrorParserPresets, ResponseErrorTexts } from '../GrResponseErrorBanner';
5
+ /** Действие, которым был закрыт диалог. */
6
+ export type DialogCloseAction = 'confirm' | 'cancel' | 'close';
7
+ /**
8
+ * Конфигурация разбора серверных ошибок внутри `onConfirm`.
9
+ *
10
+ * По умолчанию используется универсальное «ядро» парсеров
11
+ * (`coreResponseErrorParsers`) — безопасное для любого бэкенда. Подключение
12
+ * серверо-специфичных парсеров (Laravel / RFC 7807 / JSON:API) — осознанное,
13
+ * через `errorParsers`.
14
+ */
15
+ export interface DialogErrorOptions {
16
+ /**
17
+ * Цепочка парсеров для классификации сырого ответа.
18
+ * - не задано — `coreResponseErrorParsers`;
19
+ * - массив — полная замена цепочки;
20
+ * - `(presets) => ResponseErrorParser[]` — композиция из пресетов.
21
+ */
22
+ errorParsers?: ResponseErrorParser[] | ((presets: ResponseErrorParserPresets) => ResponseErrorParser[]);
23
+ /** Частичный override текстов-фолбэков баннера ошибок (i18n). */
24
+ errorTexts?: Partial<ResponseErrorTexts>;
25
+ /** Имя поля основного сообщения в теле ответа (для `plainMessageParser`). */
26
+ errorMessageKey?: string;
27
+ /** Человекочитаемые подписи полей для `fieldErrors`. */
28
+ fieldLabels?: Record<string, string>;
29
+ }
30
+ /**
31
+ * Контекст, передаваемый в колбэк `onConfirm`. Позволяет управлять
32
+ * жизненным циклом диалога во время асинхронной операции: показывать ошибки,
33
+ * управлять лоадером, закрывать диалог.
34
+ */
35
+ export interface DialogConfirmContext<V = unknown> {
36
+ /** Введённое значение (для `prompt` — строка; для `confirm`/`alert` — `undefined`). */
37
+ readonly value: V;
38
+ /** `AbortSignal`, прерывающийся при закрытии/отмене диалога. */
39
+ readonly signal: AbortSignal;
40
+ /** Показать общую ошибку текстом. `null` — скрыть. */
41
+ setError: (message: string | null) => void;
42
+ /**
43
+ * Классифицировать «сырой» ответ (Response / axios / fetch error / Error /
44
+ * строку / JSON) через цепочку парсеров: общий блок попадёт в баннер,
45
+ * `fieldErrors` — на поля формы. Возвращает распознанную информацию.
46
+ */
47
+ setRawError: (raw: unknown, meta?: Record<string, unknown>) => Promise<ResponseErrorInfo | null>;
48
+ /** Привязать ошибку к конкретному полю (`prompt` — поле `value`). */
49
+ setFieldError: (field: string, message: string | null) => void;
50
+ /** Сбросить все выставленные ошибки. */
51
+ clearErrors: () => void;
52
+ /** Принудительно управлять состоянием загрузки кнопки Confirm. */
53
+ setLoading: (loading: boolean) => void;
54
+ /** Закрыть диалог из колбэка. */
55
+ close: (action?: DialogCloseAction) => void;
56
+ }
57
+ /**
58
+ * Колбэк, выполняемый при клике Confirm.
59
+ *
60
+ * Возврат:
61
+ * - `resolved` / `true` / `void` — успех: диалог закрывается;
62
+ * - `false` — оставить диалог открытым (без ошибки);
63
+ * - `throw` / `rejected` — ошибка: диалог остаётся открытым, исключение
64
+ * автоматически прогоняется через `setRawError`.
65
+ */
66
+ export type DialogOnConfirm<V = unknown> = (ctx: DialogConfirmContext<V>) => void | boolean | Promise<void | boolean>;
67
+ /** Базовые опции, проксируемые в `GrDialog`/`GrModal`. */
68
+ export interface DialogBaseOptions extends DialogErrorOptions {
69
+ title?: string;
70
+ /** Текст-сообщение в теле диалога. */
71
+ message?: string;
72
+ description?: string;
73
+ size?: GrDialogSize;
74
+ closeOnBackdrop?: boolean;
75
+ closeOnEsc?: boolean;
76
+ showHeader?: boolean;
77
+ showCloseButton?: boolean;
78
+ headerConfig?: GrDialogSectionConfig;
79
+ footerConfig?: GrDialogSectionConfig;
80
+ bodyConfig?: GrDialogSectionConfig;
81
+ closeLabel?: string;
82
+ buttonSize?: GrButtonSize;
83
+ confirmText?: string;
84
+ confirmVariant?: GrButtonVariant;
85
+ confirmTone?: GrButtonTone;
86
+ /** Внешний `AbortSignal`: при abort диалог закрывается с `action: 'close'`. */
87
+ signal?: AbortSignal;
88
+ /** Наследование контекста приложения (i18n / тема / `granular-provider`). */
89
+ appContext?: AppContext | null;
90
+ }
91
+ export interface DialogConfirmOptions extends DialogBaseOptions {
92
+ cancelText?: string;
93
+ onConfirm?: DialogOnConfirm<undefined>;
94
+ }
95
+ export interface DialogAlertOptions extends DialogBaseOptions {
96
+ onConfirm?: DialogOnConfirm<undefined>;
97
+ }
98
+ export interface DialogPromptOptions extends DialogBaseOptions {
99
+ cancelText?: string;
100
+ /** Начальное значение поля ввода. */
101
+ value?: string;
102
+ label?: string;
103
+ placeholder?: string;
104
+ required?: boolean;
105
+ requiredErrorText?: string;
106
+ onConfirm?: DialogOnConfirm<string>;
107
+ }
108
+ /** Результат низкоуровневого `open()`. */
109
+ export interface DialogResult<V = unknown> {
110
+ action: DialogCloseAction;
111
+ value?: V;
112
+ }
113
+ /** Тип диалога. */
114
+ export type DialogKind = 'confirm' | 'alert' | 'prompt';
115
+ /** Промис вызова диалога с возможностью императивного закрытия. */
116
+ export type DialogPromise<T> = Promise<T> & {
117
+ /** Закрыть диалог программно (как `action: 'close'`). */
118
+ close: () => void;
119
+ };
120
+ /** Дефолты сервиса, общие на приложение. */
121
+ export interface DialogServiceDefaults extends DialogErrorOptions {
122
+ size?: GrDialogSize;
123
+ confirmText?: string;
124
+ cancelText?: string;
125
+ confirmVariant?: GrButtonVariant;
126
+ confirmTone?: GrButtonTone;
127
+ buttonSize?: GrButtonSize;
128
+ closeOnBackdrop?: boolean;
129
+ closeOnEsc?: boolean;
130
+ }
131
+ /** Публичный API сервиса диалогов. */
132
+ export interface DialogService {
133
+ confirm: (message: string, options?: DialogConfirmOptions) => DialogPromise<boolean>;
134
+ alert: (message: string, options?: DialogAlertOptions) => DialogPromise<void>;
135
+ prompt: (message: string, options?: DialogPromptOptions) => DialogPromise<string | null>;
136
+ open: <V = unknown>(kind: DialogKind, message: string, options?: DialogBaseOptions) => DialogPromise<DialogResult<V>>;
137
+ /** Закрыть все активные/ожидающие диалоги. */
138
+ closeAll: () => void;
139
+ /** Явно зарегистрировать контекст приложения (для вызовов вне `setup`). */
140
+ setAppContext: (ctx: AppContext | null) => void;
141
+ }
@@ -0,0 +1,13 @@
1
+ import type { DialogService, DialogServiceDefaults } from './types';
2
+ /** Тестовая/служебная очистка смонтированного хоста. */
3
+ export declare function teardownDialogService(): void;
4
+ /**
5
+ * Создаёт сервис диалогов. Опциональные `defaults` применяются ко всем
6
+ * вызовам (можно переопределить в каждом конкретном вызове).
7
+ *
8
+ * Контекст приложения кэшируется автоматически при первом вызове внутри
9
+ * `setup`. Для вызовов вне компонента используйте `setAppContext`.
10
+ */
11
+ export declare function useDialogService(defaults?: DialogServiceDefaults): DialogService;
12
+ /** Готовый синглтон-сервис с дефолтными настройками. */
13
+ export declare const dialogService: DialogService;
@@ -128,7 +128,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
128
128
  error: (error: unknown) => void;
129
129
  progress: (percent: number, info?: GrUploadProgressInfo | undefined) => void;
130
130
  change: (files: File[]) => void;
131
- "state-change": (state: GrUploadState) => void;
131
+ stateChange: (state: GrUploadState) => void;
132
132
  }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<GrFileUploadProps>, {
133
133
  action: undefined;
134
134
  request: undefined;
@@ -153,11 +153,12 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
153
153
  onProgress?: ((percent: number, info?: GrUploadProgressInfo | undefined) => any) | undefined;
154
154
  onChange?: ((files: File[]) => any) | undefined;
155
155
  onError?: ((error: unknown) => any) | undefined;
156
- "onState-change"?: ((state: GrUploadState) => any) | undefined;
156
+ onStateChange?: ((state: GrUploadState) => any) | undefined;
157
157
  }>, {
158
158
  disabled: boolean;
159
159
  name: string;
160
160
  headers: Record<string, string>;
161
+ placeholder: string;
161
162
  withCredentials: boolean;
162
163
  action: string;
163
164
  request: GrFileUploadRequest;
@@ -168,7 +169,6 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
168
169
  validators: FileValidator[];
169
170
  showFileList: boolean;
170
171
  uploadExtraData: (files: File[]) => GrFileUploadExtraData | undefined;
171
- placeholder: string;
172
172
  showProgress: boolean;
173
173
  progressTone: GrProgressBarTone;
174
174
  progressLabel: string;
@@ -65,15 +65,15 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
65
65
  }>>> & Readonly<{
66
66
  "onUpdate:modelValue"?: ((value: File | File[] | null) => any) | undefined;
67
67
  onChange?: ((value: File | File[] | null) => any) | undefined;
68
- onClear?: (() => any) | undefined;
69
68
  onValidation?: ((errors: FileValidationIssue[]) => any) | undefined;
69
+ onClear?: (() => any) | undefined;
70
70
  "onUpdate:errors"?: ((errors: FileValidationIssue[]) => any) | undefined;
71
71
  }>, {
72
72
  disabled: boolean;
73
+ placeholder: string;
73
74
  accept: string;
74
75
  multiple: boolean;
75
76
  validators: FileValidator[];
76
- placeholder: string;
77
77
  uploadText: string;
78
78
  changeText: string;
79
79
  removeText: string;
@@ -71,10 +71,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
71
71
  name: string;
72
72
  id: string;
73
73
  invalid: boolean;
74
- placeholder: string;
75
- state: "default" | "success" | "warning" | "danger";
76
74
  inputmode: "text" | "search" | "none" | "email" | "tel" | "url" | "numeric" | "decimal";
75
+ placeholder: string;
77
76
  autocomplete: string;
77
+ state: "default" | "success" | "warning" | "danger";
78
78
  textAlign: GrInputTextAlign;
79
79
  prefixMinWidth: string;
80
80
  prefixMaxWidth: string;