@8wave/ai-elements 0.115.0-beta.60 → 0.115.0-beta.72

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 (193) hide show
  1. package/dist/_chunks/{Agent-Bz23Ejuh.js → Agent-B5gICwnq.js} +2 -5
  2. package/dist/_chunks/Agent-B5gICwnq.js.map +1 -0
  3. package/dist/_chunks/{PkChatbotFilePreview-CyaNjBrA.js → PkChatbotFilePreview-Dc9NJ0WF.js} +2 -2
  4. package/dist/_chunks/{PkChatbotFilePreview-CyaNjBrA.js.map → PkChatbotFilePreview-Dc9NJ0WF.js.map} +1 -1
  5. package/dist/_chunks/{PkHeldImage-CtqqMvpW.js → PkHeldImage-B4gZSfa6.js} +2 -2
  6. package/dist/_chunks/{PkHeldImage-CtqqMvpW.js.map → PkHeldImage-B4gZSfa6.js.map} +1 -1
  7. package/dist/_chunks/{PkLazyImg-Ci06XyhW.js → PkLazyImg-DT3U67q-.js} +3 -2
  8. package/dist/_chunks/PkLazyImg-DT3U67q-.js.map +1 -0
  9. package/dist/_chunks/{PkStreamingMarkdown-DbSttKVa.js → PkStreamingMarkdown-LBiDnEgV.js} +3 -3
  10. package/dist/_chunks/{PkStreamingMarkdown-DbSttKVa.js.map → PkStreamingMarkdown-LBiDnEgV.js.map} +1 -1
  11. package/dist/_chunks/{PkToolEditSpreadsheet-BrYSJlT4.js → PkToolEditSpreadsheet-YoiuyH9p.js} +3 -3
  12. package/dist/_chunks/{PkToolEditSpreadsheet-BrYSJlT4.js.map → PkToolEditSpreadsheet-YoiuyH9p.js.map} +1 -1
  13. package/dist/_chunks/{PkToolRequestGeolocation-D4rIR3LN.js → PkToolRequestGeolocation-m-IXD3Dg.js} +7 -4
  14. package/dist/_chunks/PkToolRequestGeolocation-m-IXD3Dg.js.map +1 -0
  15. package/dist/_chunks/{PkToolRequestOAuthConnection-epwcNb5F.js → PkToolRequestOAuthConnection-BLEQZ51Y.js} +3 -3
  16. package/dist/_chunks/{PkToolRequestOAuthConnection-epwcNb5F.js.map → PkToolRequestOAuthConnection-BLEQZ51Y.js.map} +1 -1
  17. package/dist/_chunks/{PkToolShowArtifact-BGUn1sMi.js → PkToolShowArtifact-KbxEd7Tv.js} +3 -3
  18. package/dist/_chunks/{PkToolShowArtifact-BGUn1sMi.js.map → PkToolShowArtifact-KbxEd7Tv.js.map} +1 -1
  19. package/dist/_chunks/{PkToolShowCalendarEvent-DwxqgAUr.js → PkToolShowCalendarEvent-DcaMadO7.js} +3 -3
  20. package/dist/_chunks/PkToolShowCalendarEvent-DcaMadO7.js.map +1 -0
  21. package/dist/_chunks/{PkToolShowComparison-hDhhVvwp.js → PkToolShowComparison-DcXSOyMw.js} +2 -2
  22. package/dist/_chunks/{PkToolShowComparison-hDhhVvwp.js.map → PkToolShowComparison-DcXSOyMw.js.map} +1 -1
  23. package/dist/_chunks/{PkToolShowContactForm-ChaAOt5I.js → PkToolShowContactForm-BjlnuEVy.js} +4 -4
  24. package/dist/_chunks/{PkToolShowContactForm-ChaAOt5I.js.map → PkToolShowContactForm-BjlnuEVy.js.map} +1 -1
  25. package/dist/_chunks/{PkToolShowDiagram-CyNPq6j7.js → PkToolShowDiagram-BgyU0CGk.js} +2 -2
  26. package/dist/_chunks/{PkToolShowDiagram-CyNPq6j7.js.map → PkToolShowDiagram-BgyU0CGk.js.map} +1 -1
  27. package/dist/_chunks/{PkToolShowEmail-BM16pMjW.js → PkToolShowEmail-AWhVo3l3.js} +2 -2
  28. package/dist/_chunks/{PkToolShowEmail-BM16pMjW.js.map → PkToolShowEmail-AWhVo3l3.js.map} +1 -1
  29. package/dist/_chunks/{PkToolShowForm-BpTuRgHg.js → PkToolShowForm-CaYPCOeb.js} +110 -100
  30. package/dist/_chunks/PkToolShowForm-CaYPCOeb.js.map +1 -0
  31. package/dist/_chunks/{PkToolShowImageGallery-CgjP34RE.js → PkToolShowImageGallery-CTuPFowW.js} +4 -4
  32. package/dist/_chunks/{PkToolShowImageGallery-CgjP34RE.js.map → PkToolShowImageGallery-CTuPFowW.js.map} +1 -1
  33. package/dist/_chunks/{PkToolShowLocation-rK5fcW4y.js → PkToolShowLocation-Bf4jmDYQ.js} +2 -2
  34. package/dist/_chunks/{PkToolShowLocation-rK5fcW4y.js.map → PkToolShowLocation-Bf4jmDYQ.js.map} +1 -1
  35. package/dist/_chunks/{PkToolShowMessage-DgT-JkYg.js → PkToolShowMessage-DlckklB3.js} +2 -2
  36. package/dist/_chunks/{PkToolShowMessage-DgT-JkYg.js.map → PkToolShowMessage-DlckklB3.js.map} +1 -1
  37. package/dist/_chunks/{PkToolShowProductList-BIeg8NR-.js → PkToolShowProductList-CThKOr9K.js} +5 -5
  38. package/dist/_chunks/{PkToolShowProductList-BIeg8NR-.js.map → PkToolShowProductList-CThKOr9K.js.map} +1 -1
  39. package/dist/_chunks/{PkToolShowQrCode-C2hZDGqM.js → PkToolShowQrCode-CFueYo4P.js} +2 -2
  40. package/dist/_chunks/{PkToolShowQrCode-C2hZDGqM.js.map → PkToolShowQrCode-CFueYo4P.js.map} +1 -1
  41. package/dist/_chunks/{PkToolShowSources-B9nZyCAn.js → PkToolShowSources-DW4LZzdI.js} +49 -28
  42. package/dist/_chunks/PkToolShowSources-DW4LZzdI.js.map +1 -0
  43. package/dist/_chunks/{PkToolShowSuggestedReply-D6g3UYqI.js → PkToolShowSuggestedReply-C81p7lmP.js} +3 -3
  44. package/dist/_chunks/{PkToolShowSuggestedReply-D6g3UYqI.js.map → PkToolShowSuggestedReply-C81p7lmP.js.map} +1 -1
  45. package/dist/_chunks/{PkToolShowVideo-B6GG8PJm.js → PkToolShowVideo-BBdH255K.js} +4 -4
  46. package/dist/_chunks/{PkToolShowVideo-B6GG8PJm.js.map → PkToolShowVideo-BBdH255K.js.map} +1 -1
  47. package/dist/_chunks/{PkToolShowWeather-C80WsCYi.js → PkToolShowWeather-BVllZARr.js} +2 -2
  48. package/dist/_chunks/{PkToolShowWeather-C80WsCYi.js.map → PkToolShowWeather-BVllZARr.js.map} +1 -1
  49. package/dist/_chunks/{PkToolShowWebPages-BkUh-IyZ.js → PkToolShowWebPages-Bbc8WuLf.js} +5 -5
  50. package/dist/_chunks/{PkToolShowWebPages-BkUh-IyZ.js.map → PkToolShowWebPages-Bbc8WuLf.js.map} +1 -1
  51. package/dist/_chunks/{VvCheckbox.es-UTRUhwdC.js → VvCheckbox.es-DKT8ys4U.js} +2 -2
  52. package/dist/_chunks/{VvCheckbox.es-UTRUhwdC.js.map → VvCheckbox.es-DKT8ys4U.js.map} +1 -1
  53. package/dist/_chunks/{VvCheckboxGroup.es-Cj7KLXHq.js → VvCheckboxGroup.es-BR2Zrit_.js} +2 -2
  54. package/dist/_chunks/{VvCheckboxGroup.es-Cj7KLXHq.js.map → VvCheckboxGroup.es-BR2Zrit_.js.map} +1 -1
  55. package/dist/_chunks/{VvCombobox.es-DptfdnAe.js → VvCombobox.es-DWJtN8ha.js} +2 -2
  56. package/dist/_chunks/{VvCombobox.es-DptfdnAe.js.map → VvCombobox.es-DWJtN8ha.js.map} +1 -1
  57. package/dist/_chunks/{VvInputText.es-DqLQDq9I.js → VvInputText.es-BH6ohnZF.js} +2 -2
  58. package/dist/_chunks/{VvInputText.es-DqLQDq9I.js.map → VvInputText.es-BH6ohnZF.js.map} +1 -1
  59. package/dist/_chunks/{VvRadio.es-D7Ws1in6.js → VvRadio.es-L9HmgYh4.js} +2 -2
  60. package/dist/_chunks/{VvRadio.es-D7Ws1in6.js.map → VvRadio.es-L9HmgYh4.js.map} +1 -1
  61. package/dist/_chunks/{VvRadioGroup.es-BDgpsR9Z.js → VvRadioGroup.es-Dyip2x3c.js} +2 -2
  62. package/dist/_chunks/{VvRadioGroup.es-BDgpsR9Z.js.map → VvRadioGroup.es-Dyip2x3c.js.map} +1 -1
  63. package/dist/_chunks/{VvSelect.es-DWbNpZKw.js → VvSelect.es-B8GZOw4X.js} +2 -2
  64. package/dist/_chunks/{VvSelect.es-DWbNpZKw.js.map → VvSelect.es-B8GZOw4X.js.map} +1 -1
  65. package/dist/_chunks/{VvTextarea.es-5UD9_C3G.js → VvTextarea.es-7E1SuavW.js} +2 -2
  66. package/dist/_chunks/{VvTextarea.es-5UD9_C3G.js.map → VvTextarea.es-7E1SuavW.js.map} +1 -1
  67. package/dist/_chunks/{chatImagePolicy-Cnmsgd96.js → chatImagePolicy-LzNQAjTs.js} +2 -2
  68. package/dist/_chunks/{chatImagePolicy-Cnmsgd96.js.map → chatImagePolicy-LzNQAjTs.js.map} +1 -1
  69. package/dist/_chunks/{index.es-D9VqgSyV.js → index.es-DJbHM2zZ.js} +10 -10
  70. package/dist/_chunks/{index.es-D9VqgSyV.js.map → index.es-DJbHM2zZ.js.map} +1 -1
  71. package/dist/_chunks/{index.es-B9zAw2XU.js → index.es-D_E1Gj_U.js} +2 -2
  72. package/dist/_chunks/{index.es-B9zAw2XU.js.map → index.es-D_E1Gj_U.js.map} +1 -1
  73. package/dist/_chunks/{markdown-25UY48qE.js → markdown-CQLsnBKV.js} +2 -2
  74. package/dist/_chunks/{markdown-25UY48qE.js.map → markdown-CQLsnBKV.js.map} +1 -1
  75. package/dist/ai-elements.es.js +293 -221
  76. package/dist/ai-elements.es.js.map +1 -1
  77. package/dist-vue/PkChatbot.js +1 -1
  78. package/dist-vue/PkChatbotAuth.js +1 -1
  79. package/dist-vue/PkChatbotEmptyState.js +1 -1
  80. package/dist-vue/PkChatbotFeedbackForm.js +1 -1
  81. package/dist-vue/PkChatbotInput.js +1 -1
  82. package/dist-vue/PkChatbotMessages.js +1 -1
  83. package/dist-vue/PkChatbotStepPayload.js +1 -1
  84. package/dist-vue/PkChatbotStepToolDetail.js +1 -1
  85. package/dist-vue/PkChatbotSteps.js +1 -1
  86. package/dist-vue/PkChatbotViewChat.js +1 -1
  87. package/dist-vue/PkChatbotViewConversations.js +1 -1
  88. package/dist-vue/PkChatbotViewFiles.js +1 -1
  89. package/dist-vue/PkChatbotViewProfile.js +1 -1
  90. package/dist-vue/_chunks/{Agent-Ci7XnQ12.js → Agent-iJ7nRWUV.js} +3 -7
  91. package/dist-vue/_chunks/Agent-iJ7nRWUV.js.map +1 -0
  92. package/dist-vue/_chunks/{Document-Bhlc3wdt.js → Document-BFyHxMgI.js} +2 -2
  93. package/dist-vue/_chunks/{Document-Bhlc3wdt.js.map → Document-BFyHxMgI.js.map} +1 -1
  94. package/dist-vue/_chunks/{PkAvatar-paEJByEA.js → PkAvatar-ZgCsoO-p.js} +2 -2
  95. package/dist-vue/_chunks/PkAvatar-ZgCsoO-p.js.map +1 -0
  96. package/dist-vue/_chunks/{PkChatbot-C05Rv5zO.js → PkChatbot-Ct2nH8y4.js} +9 -9
  97. package/dist-vue/_chunks/{PkChatbot-C05Rv5zO.js.map → PkChatbot-Ct2nH8y4.js.map} +1 -1
  98. package/dist-vue/_chunks/{PkChatbotAuth-DD5RF7kY.js → PkChatbotAuth-CwsXLIku.js} +4 -4
  99. package/dist-vue/_chunks/PkChatbotAuth-CwsXLIku.js.map +1 -0
  100. package/dist-vue/_chunks/{PkChatbotEmptyState-B5qeL1kv.js → PkChatbotEmptyState-CQCBF59f.js} +3 -3
  101. package/dist-vue/_chunks/{PkChatbotEmptyState-B5qeL1kv.js.map → PkChatbotEmptyState-CQCBF59f.js.map} +1 -1
  102. package/dist-vue/_chunks/{PkChatbotFeedbackForm-BJ_Omuq2.js → PkChatbotFeedbackForm-CYiwvSs_.js} +2 -2
  103. package/dist-vue/_chunks/{PkChatbotFeedbackForm-BJ_Omuq2.js.map → PkChatbotFeedbackForm-CYiwvSs_.js.map} +1 -1
  104. package/dist-vue/_chunks/{PkChatbotInput-BLzTQmvy.js → PkChatbotInput-D7IIfTw1.js} +2 -2
  105. package/dist-vue/_chunks/{PkChatbotInput-BLzTQmvy.js.map → PkChatbotInput-D7IIfTw1.js.map} +1 -1
  106. package/dist-vue/_chunks/{PkChatbotMessages-CxTz0W0d.js → PkChatbotMessages-DJPqKh-G.js} +19 -19
  107. package/dist-vue/_chunks/{PkChatbotMessages-CxTz0W0d.js.map → PkChatbotMessages-DJPqKh-G.js.map} +1 -1
  108. package/dist-vue/_chunks/{PkChatbotStepPayload-B04aqOGu.js → PkChatbotStepPayload-dl2-8f27.js} +2 -2
  109. package/dist-vue/_chunks/{PkChatbotStepPayload-B04aqOGu.js.map → PkChatbotStepPayload-dl2-8f27.js.map} +1 -1
  110. package/dist-vue/_chunks/{PkChatbotStepToolDetail-yII_Dk3p.js → PkChatbotStepToolDetail-f8zOnu2W.js} +3 -3
  111. package/dist-vue/_chunks/{PkChatbotStepToolDetail-yII_Dk3p.js.map → PkChatbotStepToolDetail-f8zOnu2W.js.map} +1 -1
  112. package/dist-vue/_chunks/{PkChatbotSteps-DYiCeWOd.js → PkChatbotSteps-CeuoK2Gk.js} +5 -5
  113. package/dist-vue/_chunks/{PkChatbotSteps-DYiCeWOd.js.map → PkChatbotSteps-CeuoK2Gk.js.map} +1 -1
  114. package/dist-vue/_chunks/{PkChatbotViewChat-s-Vx4U1E.js → PkChatbotViewChat-X9L9a53H.js} +8 -8
  115. package/dist-vue/_chunks/{PkChatbotViewChat-s-Vx4U1E.js.map → PkChatbotViewChat-X9L9a53H.js.map} +1 -1
  116. package/dist-vue/_chunks/{PkChatbotViewConversations-D7XHDBGS.js → PkChatbotViewConversations-NNzeW5c6.js} +4 -2
  117. package/dist-vue/_chunks/PkChatbotViewConversations-NNzeW5c6.js.map +1 -0
  118. package/dist-vue/_chunks/{PkChatbotViewFiles-t07w-VNZ.js → PkChatbotViewFiles-nn23dc0W.js} +3 -3
  119. package/dist-vue/_chunks/{PkChatbotViewFiles-t07w-VNZ.js.map → PkChatbotViewFiles-nn23dc0W.js.map} +1 -1
  120. package/dist-vue/_chunks/{PkChatbotViewProfile-DJT5AEkZ.js → PkChatbotViewProfile-CzY3lj4N.js} +3 -3
  121. package/dist-vue/_chunks/{PkChatbotViewProfile-DJT5AEkZ.js.map → PkChatbotViewProfile-CzY3lj4N.js.map} +1 -1
  122. package/dist-vue/_chunks/{PkLazyImg-CDxX9xnq.js → PkLazyImg-X5BMNU_R.js} +2 -1
  123. package/dist-vue/_chunks/PkLazyImg-X5BMNU_R.js.map +1 -0
  124. package/dist-vue/_chunks/{PkStreamingMarkdown-ALhm02o3.js → PkStreamingMarkdown-CCu2pX2c.js} +3 -3
  125. package/dist-vue/_chunks/{PkStreamingMarkdown-ALhm02o3.js.map → PkStreamingMarkdown-CCu2pX2c.js.map} +1 -1
  126. package/dist-vue/_chunks/{PkToolEditSpreadsheet-DU3RBd6q.js → PkToolEditSpreadsheet-DYcRLINr.js} +2 -2
  127. package/dist-vue/_chunks/{PkToolEditSpreadsheet-DU3RBd6q.js.map → PkToolEditSpreadsheet-DYcRLINr.js.map} +1 -1
  128. package/dist-vue/_chunks/{PkToolRequestGeolocation-CE4zQofM.js → PkToolRequestGeolocation-DLU21rbD.js} +6 -3
  129. package/dist-vue/_chunks/PkToolRequestGeolocation-DLU21rbD.js.map +1 -0
  130. package/dist-vue/_chunks/{PkToolRequestOAuthConnection-CAk5s541.js → PkToolRequestOAuthConnection-BS9Wtn1m.js} +2 -2
  131. package/dist-vue/_chunks/{PkToolRequestOAuthConnection-CAk5s541.js.map → PkToolRequestOAuthConnection-BS9Wtn1m.js.map} +1 -1
  132. package/dist-vue/_chunks/{PkToolShowArtifact-CA1sKasD.js → PkToolShowArtifact-B3b6LYSx.js} +2 -2
  133. package/dist-vue/_chunks/{PkToolShowArtifact-CA1sKasD.js.map → PkToolShowArtifact-B3b6LYSx.js.map} +1 -1
  134. package/dist-vue/_chunks/{PkToolShowCalendarEvent-Cb3lmDQZ.js → PkToolShowCalendarEvent-CL5valn9.js} +2 -2
  135. package/dist-vue/_chunks/PkToolShowCalendarEvent-CL5valn9.js.map +1 -0
  136. package/dist-vue/_chunks/{PkToolShowContactForm-C0QHEj5k.js → PkToolShowContactForm-C7LaYE_c.js} +3 -3
  137. package/dist-vue/_chunks/{PkToolShowContactForm-C0QHEj5k.js.map → PkToolShowContactForm-C7LaYE_c.js.map} +1 -1
  138. package/dist-vue/_chunks/{PkToolShowDiagram-CQUd_reA.js → PkToolShowDiagram-CR-TthJm.js} +2 -2
  139. package/dist-vue/_chunks/{PkToolShowDiagram-CQUd_reA.js.map → PkToolShowDiagram-CR-TthJm.js.map} +1 -1
  140. package/dist-vue/_chunks/{PkToolShowForm-B_ezmfuo.js → PkToolShowForm-BDaYT4E0.js} +100 -90
  141. package/dist-vue/_chunks/PkToolShowForm-BDaYT4E0.js.map +1 -0
  142. package/dist-vue/_chunks/{PkToolShowImageGallery-B8gmmHvk.js → PkToolShowImageGallery-ER7LyVJD.js} +2 -2
  143. package/dist-vue/_chunks/{PkToolShowImageGallery-B8gmmHvk.js.map → PkToolShowImageGallery-ER7LyVJD.js.map} +1 -1
  144. package/dist-vue/_chunks/{PkToolShowProductList-BMvt5mKe.js → PkToolShowProductList-B3iZIwOJ.js} +3 -3
  145. package/dist-vue/_chunks/{PkToolShowProductList-BMvt5mKe.js.map → PkToolShowProductList-B3iZIwOJ.js.map} +1 -1
  146. package/dist-vue/_chunks/PkToolShowSources-ITHEa-D-.js +263 -0
  147. package/dist-vue/_chunks/PkToolShowSources-ITHEa-D-.js.map +1 -0
  148. package/dist-vue/_chunks/{PkToolShowSuggestedReply-BE6gBA-2.js → PkToolShowSuggestedReply-CZm_THD0.js} +2 -2
  149. package/dist-vue/_chunks/{PkToolShowSuggestedReply-BE6gBA-2.js.map → PkToolShowSuggestedReply-CZm_THD0.js.map} +1 -1
  150. package/dist-vue/_chunks/{PkToolShowVideo-ZPDVzjPX.js → PkToolShowVideo-Pe0DhYm5.js} +2 -2
  151. package/dist-vue/_chunks/{PkToolShowVideo-ZPDVzjPX.js.map → PkToolShowVideo-Pe0DhYm5.js.map} +1 -1
  152. package/dist-vue/_chunks/{PkToolShowWebPages-dI4WMr7F.js → PkToolShowWebPages-ZfGH4XNP.js} +3 -3
  153. package/dist-vue/_chunks/{PkToolShowWebPages-dI4WMr7F.js.map → PkToolShowWebPages-ZfGH4XNP.js.map} +1 -1
  154. package/dist-vue/_chunks/{createChatbotApiClient-IlTQndxL.js → createChatbotApiClient-BVC9GxV_.js} +2 -2
  155. package/dist-vue/_chunks/createChatbotApiClient-BVC9GxV_.js.map +1 -0
  156. package/dist-vue/_chunks/{index.es-VzNLOQUv.js → index.es-Io4Mdm4X.js} +2 -2
  157. package/dist-vue/_chunks/{index.es-VzNLOQUv.js.map → index.es-Io4Mdm4X.js.map} +1 -1
  158. package/dist-vue/_chunks/{useChatbotStore-CtJ3bwuy.js → useChatbotStore-Drg3gBff.js} +3 -3
  159. package/dist-vue/_chunks/{useChatbotStore-CtJ3bwuy.js.map → useChatbotStore-Drg3gBff.js.map} +1 -1
  160. package/dist-vue/_chunks/{utils-BzypADaU.js → utils-wUVFCJMG.js} +2 -2
  161. package/dist-vue/_chunks/{utils-BzypADaU.js.map → utils-wUVFCJMG.js.map} +1 -1
  162. package/dist-vue/api.js +1 -1
  163. package/dist-vue/composables.js +261 -191
  164. package/dist-vue/composables.js.map +1 -1
  165. package/dist-vue/index.js +249 -201
  166. package/dist-vue/index.js.map +1 -1
  167. package/dist-vue/locales.js +171 -169
  168. package/dist-vue/packages/ability/src/types.d.ts +0 -1
  169. package/dist-vue/packages/components/src/chat/PkDocumentHeader.d.ts +5 -0
  170. package/dist-vue/packages/components/src/chat/PkMessageDetail.d.ts +2 -2
  171. package/dist-vue/packages/components/src/table/PkTableSortable.d.ts +4 -0
  172. package/dist-vue/packages/composable/src/useBranding.d.ts +0 -1
  173. package/dist-vue/packages/models/src/schema/Branding.d.ts +21 -9
  174. package/dist-vue/packages/models/src/schema/TimingLog.d.ts +4 -6
  175. package/dist-vue/style.css +1 -1
  176. package/package.json +1 -1
  177. package/dist/_chunks/Agent-Bz23Ejuh.js.map +0 -1
  178. package/dist/_chunks/PkLazyImg-Ci06XyhW.js.map +0 -1
  179. package/dist/_chunks/PkToolRequestGeolocation-D4rIR3LN.js.map +0 -1
  180. package/dist/_chunks/PkToolShowCalendarEvent-DwxqgAUr.js.map +0 -1
  181. package/dist/_chunks/PkToolShowForm-BpTuRgHg.js.map +0 -1
  182. package/dist/_chunks/PkToolShowSources-B9nZyCAn.js.map +0 -1
  183. package/dist-vue/_chunks/Agent-Ci7XnQ12.js.map +0 -1
  184. package/dist-vue/_chunks/PkAvatar-paEJByEA.js.map +0 -1
  185. package/dist-vue/_chunks/PkChatbotAuth-DD5RF7kY.js.map +0 -1
  186. package/dist-vue/_chunks/PkChatbotViewConversations-D7XHDBGS.js.map +0 -1
  187. package/dist-vue/_chunks/PkLazyImg-CDxX9xnq.js.map +0 -1
  188. package/dist-vue/_chunks/PkToolRequestGeolocation-CE4zQofM.js.map +0 -1
  189. package/dist-vue/_chunks/PkToolShowCalendarEvent-Cb3lmDQZ.js.map +0 -1
  190. package/dist-vue/_chunks/PkToolShowForm-B_ezmfuo.js.map +0 -1
  191. package/dist-vue/_chunks/PkToolShowSources-DEmjN0Ou.js +0 -242
  192. package/dist-vue/_chunks/PkToolShowSources-DEmjN0Ou.js.map +0 -1
  193. package/dist-vue/_chunks/createChatbotApiClient-IlTQndxL.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PkToolShowComparison-hDhhVvwp.js","names":["$t","__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_withCtx","_unref","_Fragment","_renderList","_normalizeClass","_createTextVNode","_createCommentVNode","_sfc_main","_style_0","withCtx","defineComponent","openBlock","init_runtime_core_esm_bundler","normalizeClass","toDisplayString","createCommentVNode","createTextVNode","unref","Fragment","createBaseVNode","init_reactivity_esm_bundler","computed","createElementBlock","createVNode","init_shared_esm_bundler","renderList","useClipboard","Qi","Ca","Ae","_plugin_vue_export_helper_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","PkToolShowComparison_default","props","__props","toolPart","features","items","valueColorClass","value","copyTable","header","i","rows","f","_component_VvIcon","_component_VvButton","_component_VvButtonGroup","_ctx","copied","_cache","item","feature"],"sources":["../../../../packages/components/src/chat/PkToolShowComparison.vue","../../../../packages/components/src/chat/PkToolShowComparison.vue","../../../../packages/components/src/chat/PkToolShowComparison.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useClipboard } from '@vueuse/core'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title?: string\n items: Array<{\n name: string\n values: Record<string, string>\n highlighted?: boolean\n }>\n }\n }\n return part\n })\n\n const features = computed(() => {\n const items = toolPart.value.input?.items\n if (!items || items.length === 0) {\n return []\n }\n return Object.keys(items[0].values)\n })\n\n // The tool contract asks for \"✓\" and \"✗\" on boolean features: the pair is\n // a verdict, so it wears one and the table reads by eye (DESIGN.md).\n const valueColorClass = (value?: string) => {\n if (value === '✓') {\n return 'text-success'\n }\n if (value === '✗') {\n return 'text-danger'\n }\n return 'text-word-2'\n }\n\n const copyTable = () => {\n const items = toolPart.value.input?.items\n if (!items) {\n return\n }\n const header = ['', ...items.map((i) => i.name)].join('\\t')\n const rows = features.value.map((f) =>\n [f.replace(/_/g, ' '), ...items.map((i) => i.values[f] ?? '')].join(\n '\\t',\n ),\n )\n copy([header, ...rows].join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.items?.length\"\n class=\"pk-tool-comparison border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:scales-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{\n toolPart.input.title ?? $t('label.comparison')\n }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyTable\" />\n </VvButtonGroup>\n </div>\n <!-- One row per feature, one column per item. In a narrow message\n each feature becomes a block that lists every item beside its\n value (`u-table--stack`), so a comparison still reads across. -->\n <div class=\"u-table-scroll\">\n <table class=\"u-table u-table--stack\" role=\"table\">\n <thead role=\"rowgroup\">\n <tr role=\"row\">\n <td></td>\n <th\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"columnheader\"\n scope=\"col\"\n class=\"pk-tool-comparison__item\"\n :class=\"{\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n }\">\n {{ item.name }}\n <small\n v-if=\"item.highlighted\"\n class=\"pk-tool-comparison__recommended\">\n {{ $t('label.recommended') }}\n </small>\n </th>\n </tr>\n </thead>\n <tbody role=\"rowgroup\">\n <tr v-for=\"feature in features\" :key=\"feature\" role=\"row\">\n <th\n role=\"rowheader\"\n scope=\"row\"\n class=\"pk-tool-comparison__feature\">\n {{ feature.replace(/_/g, ' ') }}\n </th>\n <td\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"cell\"\n :data-label=\"item.name\"\n :class=\"[\n valueColorClass(item.values[feature]),\n {\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n },\n ]\">\n {{ item.values[feature] ?? '-' }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n // Written under the block so it outweighs the `.u-table` rules.\n .pk-tool-comparison {\n // Stacked, the labels are the names of the items, longer than the\n // headings of a data table.\n --u-table-label-width: 8rem;\n\n // The items are what the table compares: their names are the titles\n // of the columns, not the small headings of a data table.\n & &__item {\n font-size: var(--text-14);\n color: var(--color-word-1);\n }\n\n & &__feature {\n font-weight: var(--font-medium);\n color: var(--color-word-3);\n }\n\n // The recommended item: a ground down its column and a word under its\n // name, no accent colour (DESIGN.md). Stacked, its name weighs more\n // than the others beside its value.\n & &__cell--highlighted {\n background-color: var(--color-surface-1);\n }\n\n &__recommended {\n display: block;\n font-size: var(--text-12);\n font-weight: var(--font-normal);\n color: var(--color-word-3);\n }\n\n @container (width < 30rem) {\n & &__cell--highlighted {\n background-color: transparent;\n\n &::before {\n font-weight: var(--font-semibold);\n color: var(--color-word-1);\n }\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useClipboard } from '@vueuse/core'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title?: string\n items: Array<{\n name: string\n values: Record<string, string>\n highlighted?: boolean\n }>\n }\n }\n return part\n })\n\n const features = computed(() => {\n const items = toolPart.value.input?.items\n if (!items || items.length === 0) {\n return []\n }\n return Object.keys(items[0].values)\n })\n\n // The tool contract asks for \"✓\" and \"✗\" on boolean features: the pair is\n // a verdict, so it wears one and the table reads by eye (DESIGN.md).\n const valueColorClass = (value?: string) => {\n if (value === '✓') {\n return 'text-success'\n }\n if (value === '✗') {\n return 'text-danger'\n }\n return 'text-word-2'\n }\n\n const copyTable = () => {\n const items = toolPart.value.input?.items\n if (!items) {\n return\n }\n const header = ['', ...items.map((i) => i.name)].join('\\t')\n const rows = features.value.map((f) =>\n [f.replace(/_/g, ' '), ...items.map((i) => i.values[f] ?? '')].join(\n '\\t',\n ),\n )\n copy([header, ...rows].join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.items?.length\"\n class=\"pk-tool-comparison border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:scales-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{\n toolPart.input.title ?? $t('label.comparison')\n }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyTable\" />\n </VvButtonGroup>\n </div>\n <!-- One row per feature, one column per item. In a narrow message\n each feature becomes a block that lists every item beside its\n value (`u-table--stack`), so a comparison still reads across. -->\n <div class=\"u-table-scroll\">\n <table class=\"u-table u-table--stack\" role=\"table\">\n <thead role=\"rowgroup\">\n <tr role=\"row\">\n <td></td>\n <th\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"columnheader\"\n scope=\"col\"\n class=\"pk-tool-comparison__item\"\n :class=\"{\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n }\">\n {{ item.name }}\n <small\n v-if=\"item.highlighted\"\n class=\"pk-tool-comparison__recommended\">\n {{ $t('label.recommended') }}\n </small>\n </th>\n </tr>\n </thead>\n <tbody role=\"rowgroup\">\n <tr v-for=\"feature in features\" :key=\"feature\" role=\"row\">\n <th\n role=\"rowheader\"\n scope=\"row\"\n class=\"pk-tool-comparison__feature\">\n {{ feature.replace(/_/g, ' ') }}\n </th>\n <td\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"cell\"\n :data-label=\"item.name\"\n :class=\"[\n valueColorClass(item.values[feature]),\n {\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n },\n ]\">\n {{ item.values[feature] ?? '-' }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n // Written under the block so it outweighs the `.u-table` rules.\n .pk-tool-comparison {\n // Stacked, the labels are the names of the items, longer than the\n // headings of a data table.\n --u-table-label-width: 8rem;\n\n // The items are what the table compares: their names are the titles\n // of the columns, not the small headings of a data table.\n & &__item {\n font-size: var(--text-14);\n color: var(--color-word-1);\n }\n\n & &__feature {\n font-weight: var(--font-medium);\n color: var(--color-word-3);\n }\n\n // The recommended item: a ground down its column and a word under its\n // name, no accent colour (DESIGN.md). Stacked, its name weighs more\n // than the others beside its value.\n & &__cell--highlighted {\n background-color: var(--color-surface-1);\n }\n\n &__recommended {\n display: block;\n font-size: var(--text-12);\n font-weight: var(--font-normal);\n color: var(--color-word-3);\n }\n\n @container (width < 30rem) {\n & &__cell--highlighted {\n background-color: transparent;\n\n &::before {\n font-weight: var(--font-semibold);\n color: var(--color-word-1);\n }\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useClipboard } from '@vueuse/core'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title?: string\n items: Array<{\n name: string\n values: Record<string, string>\n highlighted?: boolean\n }>\n }\n }\n return part\n })\n\n const features = computed(() => {\n const items = toolPart.value.input?.items\n if (!items || items.length === 0) {\n return []\n }\n return Object.keys(items[0].values)\n })\n\n // The tool contract asks for \"✓\" and \"✗\" on boolean features: the pair is\n // a verdict, so it wears one and the table reads by eye (DESIGN.md).\n const valueColorClass = (value?: string) => {\n if (value === '✓') {\n return 'text-success'\n }\n if (value === '✗') {\n return 'text-danger'\n }\n return 'text-word-2'\n }\n\n const copyTable = () => {\n const items = toolPart.value.input?.items\n if (!items) {\n return\n }\n const header = ['', ...items.map((i) => i.name)].join('\\t')\n const rows = features.value.map((f) =>\n [f.replace(/_/g, ' '), ...items.map((i) => i.values[f] ?? '')].join(\n '\\t',\n ),\n )\n copy([header, ...rows].join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.items?.length\"\n class=\"pk-tool-comparison border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:scales-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{\n toolPart.input.title ?? $t('label.comparison')\n }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyTable\" />\n </VvButtonGroup>\n </div>\n <!-- One row per feature, one column per item. In a narrow message\n each feature becomes a block that lists every item beside its\n value (`u-table--stack`), so a comparison still reads across. -->\n <div class=\"u-table-scroll\">\n <table class=\"u-table u-table--stack\" role=\"table\">\n <thead role=\"rowgroup\">\n <tr role=\"row\">\n <td></td>\n <th\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"columnheader\"\n scope=\"col\"\n class=\"pk-tool-comparison__item\"\n :class=\"{\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n }\">\n {{ item.name }}\n <small\n v-if=\"item.highlighted\"\n class=\"pk-tool-comparison__recommended\">\n {{ $t('label.recommended') }}\n </small>\n </th>\n </tr>\n </thead>\n <tbody role=\"rowgroup\">\n <tr v-for=\"feature in features\" :key=\"feature\" role=\"row\">\n <th\n role=\"rowheader\"\n scope=\"row\"\n class=\"pk-tool-comparison__feature\">\n {{ feature.replace(/_/g, ' ') }}\n </th>\n <td\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"cell\"\n :data-label=\"item.name\"\n :class=\"[\n valueColorClass(item.values[feature]),\n {\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n },\n ]\">\n {{ item.values[feature] ?? '-' }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n // Written under the block so it outweighs the `.u-table` rules.\n .pk-tool-comparison {\n // Stacked, the labels are the names of the items, longer than the\n // headings of a data table.\n --u-table-label-width: 8rem;\n\n // The items are what the table compares: their names are the titles\n // of the columns, not the small headings of a data table.\n & &__item {\n font-size: var(--text-14);\n color: var(--color-word-1);\n }\n\n & &__feature {\n font-weight: var(--font-medium);\n color: var(--color-word-3);\n }\n\n // The recommended item: a ground down its column and a word under its\n // name, no accent colour (DESIGN.md). Stacked, its name weighs more\n // than the others beside its value.\n & &__cell--highlighted {\n background-color: var(--color-surface-1);\n }\n\n &__recommended {\n display: block;\n font-size: var(--text-12);\n font-weight: var(--font-normal);\n color: var(--color-word-3);\n }\n\n @container (width < 30rem) {\n & &__cell--highlighted {\n background-color: transparent;\n\n &::before {\n font-weight: var(--font-semibold);\n color: var(--color-word-1);\n }\n }\n }\n }\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"PkToolShowComparison-DcXSOyMw.js","names":["$t","__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_withCtx","_unref","_Fragment","_renderList","_normalizeClass","_createTextVNode","_createCommentVNode","_sfc_main","_style_0","withCtx","defineComponent","openBlock","init_runtime_core_esm_bundler","normalizeClass","toDisplayString","createCommentVNode","createTextVNode","unref","Fragment","createBaseVNode","init_reactivity_esm_bundler","computed","createElementBlock","createVNode","init_shared_esm_bundler","renderList","useClipboard","Qi","Ca","Ae","_plugin_vue_export_helper_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","PkToolShowComparison_default","props","__props","toolPart","features","items","valueColorClass","value","copyTable","header","i","rows","f","_component_VvIcon","_component_VvButton","_component_VvButtonGroup","_ctx","copied","_cache","item","feature"],"sources":["../../../../packages/components/src/chat/PkToolShowComparison.vue","../../../../packages/components/src/chat/PkToolShowComparison.vue","../../../../packages/components/src/chat/PkToolShowComparison.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useClipboard } from '@vueuse/core'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title?: string\n items: Array<{\n name: string\n values: Record<string, string>\n highlighted?: boolean\n }>\n }\n }\n return part\n })\n\n const features = computed(() => {\n const items = toolPart.value.input?.items\n if (!items || items.length === 0) {\n return []\n }\n return Object.keys(items[0].values)\n })\n\n // The tool contract asks for \"✓\" and \"✗\" on boolean features: the pair is\n // a verdict, so it wears one and the table reads by eye (DESIGN.md).\n const valueColorClass = (value?: string) => {\n if (value === '✓') {\n return 'text-success'\n }\n if (value === '✗') {\n return 'text-danger'\n }\n return 'text-word-2'\n }\n\n const copyTable = () => {\n const items = toolPart.value.input?.items\n if (!items) {\n return\n }\n const header = ['', ...items.map((i) => i.name)].join('\\t')\n const rows = features.value.map((f) =>\n [f.replace(/_/g, ' '), ...items.map((i) => i.values[f] ?? '')].join(\n '\\t',\n ),\n )\n copy([header, ...rows].join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.items?.length\"\n class=\"pk-tool-comparison border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:scales-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{\n toolPart.input.title ?? $t('label.comparison')\n }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyTable\" />\n </VvButtonGroup>\n </div>\n <!-- One row per feature, one column per item. In a narrow message\n each feature becomes a block that lists every item beside its\n value (`u-table--stack`), so a comparison still reads across. -->\n <div class=\"u-table-scroll\">\n <table class=\"u-table u-table--stack\" role=\"table\">\n <thead role=\"rowgroup\">\n <tr role=\"row\">\n <td></td>\n <th\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"columnheader\"\n scope=\"col\"\n class=\"pk-tool-comparison__item\"\n :class=\"{\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n }\">\n {{ item.name }}\n <small\n v-if=\"item.highlighted\"\n class=\"pk-tool-comparison__recommended\">\n {{ $t('label.recommended') }}\n </small>\n </th>\n </tr>\n </thead>\n <tbody role=\"rowgroup\">\n <tr v-for=\"feature in features\" :key=\"feature\" role=\"row\">\n <th\n role=\"rowheader\"\n scope=\"row\"\n class=\"pk-tool-comparison__feature\">\n {{ feature.replace(/_/g, ' ') }}\n </th>\n <td\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"cell\"\n :data-label=\"item.name\"\n :class=\"[\n valueColorClass(item.values[feature]),\n {\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n },\n ]\">\n {{ item.values[feature] ?? '-' }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n // Written under the block so it outweighs the `.u-table` rules.\n .pk-tool-comparison {\n // Stacked, the labels are the names of the items, longer than the\n // headings of a data table.\n --u-table-label-width: 8rem;\n\n // The items are what the table compares: their names are the titles\n // of the columns, not the small headings of a data table.\n & &__item {\n font-size: var(--text-14);\n color: var(--color-word-1);\n }\n\n & &__feature {\n font-weight: var(--font-medium);\n color: var(--color-word-3);\n }\n\n // The recommended item: a ground down its column and a word under its\n // name, no accent colour (DESIGN.md). Stacked, its name weighs more\n // than the others beside its value.\n & &__cell--highlighted {\n background-color: var(--color-surface-1);\n }\n\n &__recommended {\n display: block;\n font-size: var(--text-12);\n font-weight: var(--font-normal);\n color: var(--color-word-3);\n }\n\n @container (width < 30rem) {\n & &__cell--highlighted {\n background-color: transparent;\n\n &::before {\n font-weight: var(--font-semibold);\n color: var(--color-word-1);\n }\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useClipboard } from '@vueuse/core'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title?: string\n items: Array<{\n name: string\n values: Record<string, string>\n highlighted?: boolean\n }>\n }\n }\n return part\n })\n\n const features = computed(() => {\n const items = toolPart.value.input?.items\n if (!items || items.length === 0) {\n return []\n }\n return Object.keys(items[0].values)\n })\n\n // The tool contract asks for \"✓\" and \"✗\" on boolean features: the pair is\n // a verdict, so it wears one and the table reads by eye (DESIGN.md).\n const valueColorClass = (value?: string) => {\n if (value === '✓') {\n return 'text-success'\n }\n if (value === '✗') {\n return 'text-danger'\n }\n return 'text-word-2'\n }\n\n const copyTable = () => {\n const items = toolPart.value.input?.items\n if (!items) {\n return\n }\n const header = ['', ...items.map((i) => i.name)].join('\\t')\n const rows = features.value.map((f) =>\n [f.replace(/_/g, ' '), ...items.map((i) => i.values[f] ?? '')].join(\n '\\t',\n ),\n )\n copy([header, ...rows].join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.items?.length\"\n class=\"pk-tool-comparison border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:scales-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{\n toolPart.input.title ?? $t('label.comparison')\n }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyTable\" />\n </VvButtonGroup>\n </div>\n <!-- One row per feature, one column per item. In a narrow message\n each feature becomes a block that lists every item beside its\n value (`u-table--stack`), so a comparison still reads across. -->\n <div class=\"u-table-scroll\">\n <table class=\"u-table u-table--stack\" role=\"table\">\n <thead role=\"rowgroup\">\n <tr role=\"row\">\n <td></td>\n <th\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"columnheader\"\n scope=\"col\"\n class=\"pk-tool-comparison__item\"\n :class=\"{\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n }\">\n {{ item.name }}\n <small\n v-if=\"item.highlighted\"\n class=\"pk-tool-comparison__recommended\">\n {{ $t('label.recommended') }}\n </small>\n </th>\n </tr>\n </thead>\n <tbody role=\"rowgroup\">\n <tr v-for=\"feature in features\" :key=\"feature\" role=\"row\">\n <th\n role=\"rowheader\"\n scope=\"row\"\n class=\"pk-tool-comparison__feature\">\n {{ feature.replace(/_/g, ' ') }}\n </th>\n <td\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"cell\"\n :data-label=\"item.name\"\n :class=\"[\n valueColorClass(item.values[feature]),\n {\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n },\n ]\">\n {{ item.values[feature] ?? '-' }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n // Written under the block so it outweighs the `.u-table` rules.\n .pk-tool-comparison {\n // Stacked, the labels are the names of the items, longer than the\n // headings of a data table.\n --u-table-label-width: 8rem;\n\n // The items are what the table compares: their names are the titles\n // of the columns, not the small headings of a data table.\n & &__item {\n font-size: var(--text-14);\n color: var(--color-word-1);\n }\n\n & &__feature {\n font-weight: var(--font-medium);\n color: var(--color-word-3);\n }\n\n // The recommended item: a ground down its column and a word under its\n // name, no accent colour (DESIGN.md). Stacked, its name weighs more\n // than the others beside its value.\n & &__cell--highlighted {\n background-color: var(--color-surface-1);\n }\n\n &__recommended {\n display: block;\n font-size: var(--text-12);\n font-weight: var(--font-normal);\n color: var(--color-word-3);\n }\n\n @container (width < 30rem) {\n & &__cell--highlighted {\n background-color: transparent;\n\n &::before {\n font-weight: var(--font-semibold);\n color: var(--color-word-1);\n }\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue'\n import { useClipboard } from '@vueuse/core'\n\n const props = defineProps<{\n part: unknown\n }>()\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n title?: string\n items: Array<{\n name: string\n values: Record<string, string>\n highlighted?: boolean\n }>\n }\n }\n return part\n })\n\n const features = computed(() => {\n const items = toolPart.value.input?.items\n if (!items || items.length === 0) {\n return []\n }\n return Object.keys(items[0].values)\n })\n\n // The tool contract asks for \"✓\" and \"✗\" on boolean features: the pair is\n // a verdict, so it wears one and the table reads by eye (DESIGN.md).\n const valueColorClass = (value?: string) => {\n if (value === '✓') {\n return 'text-success'\n }\n if (value === '✗') {\n return 'text-danger'\n }\n return 'text-word-2'\n }\n\n const copyTable = () => {\n const items = toolPart.value.input?.items\n if (!items) {\n return\n }\n const header = ['', ...items.map((i) => i.name)].join('\\t')\n const rows = features.value.map((f) =>\n [f.replace(/_/g, ' '), ...items.map((i) => i.values[f] ?? '')].join(\n '\\t',\n ),\n )\n copy([header, ...rows].join('\\n'))\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.items?.length\"\n class=\"pk-tool-comparison border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon name=\"ri:scales-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{\n toolPart.input.title ?? $t('label.comparison')\n }}</strong>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyTable\" />\n </VvButtonGroup>\n </div>\n <!-- One row per feature, one column per item. In a narrow message\n each feature becomes a block that lists every item beside its\n value (`u-table--stack`), so a comparison still reads across. -->\n <div class=\"u-table-scroll\">\n <table class=\"u-table u-table--stack\" role=\"table\">\n <thead role=\"rowgroup\">\n <tr role=\"row\">\n <td></td>\n <th\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"columnheader\"\n scope=\"col\"\n class=\"pk-tool-comparison__item\"\n :class=\"{\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n }\">\n {{ item.name }}\n <small\n v-if=\"item.highlighted\"\n class=\"pk-tool-comparison__recommended\">\n {{ $t('label.recommended') }}\n </small>\n </th>\n </tr>\n </thead>\n <tbody role=\"rowgroup\">\n <tr v-for=\"feature in features\" :key=\"feature\" role=\"row\">\n <th\n role=\"rowheader\"\n scope=\"row\"\n class=\"pk-tool-comparison__feature\">\n {{ feature.replace(/_/g, ' ') }}\n </th>\n <td\n v-for=\"item in toolPart.input.items\"\n :key=\"item.name\"\n role=\"cell\"\n :data-label=\"item.name\"\n :class=\"[\n valueColorClass(item.values[feature]),\n {\n 'pk-tool-comparison__cell--highlighted':\n item.highlighted,\n },\n ]\">\n {{ item.values[feature] ?? '-' }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n // Written under the block so it outweighs the `.u-table` rules.\n .pk-tool-comparison {\n // Stacked, the labels are the names of the items, longer than the\n // headings of a data table.\n --u-table-label-width: 8rem;\n\n // The items are what the table compares: their names are the titles\n // of the columns, not the small headings of a data table.\n & &__item {\n font-size: var(--text-14);\n color: var(--color-word-1);\n }\n\n & &__feature {\n font-weight: var(--font-medium);\n color: var(--color-word-3);\n }\n\n // The recommended item: a ground down its column and a word under its\n // name, no accent colour (DESIGN.md). Stacked, its name weighs more\n // than the others beside its value.\n & &__cell--highlighted {\n background-color: var(--color-surface-1);\n }\n\n &__recommended {\n display: block;\n font-size: var(--text-12);\n font-weight: var(--font-normal);\n color: var(--color-word-3);\n }\n\n @container (width < 30rem) {\n & &__cell--highlighted {\n background-color: transparent;\n\n &::before {\n font-weight: var(--font-semibold);\n color: var(--color-word-1);\n }\n }\n }\n }\n</style>\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { g as e, u as t, y as n } from "./zod-DNKa_yZf.js";
2
2
  import { $ as r, C as i, L as a, O as o, Tt as s, X as c, bt as l, ct as u, h as d, it as f, m as p, r as m, t as h, v as g, x as _, xt as v } from "./vue.runtime.esm-bundler-B-NVlZCY.js";
3
3
  import { r as y } from "./vue-i18n-BAndfHYX.js";
4
- import { t as b } from "./PkStreamingMarkdown-DbSttKVa.js";
5
- import { r as x, t as S } from "./index.es-B9zAw2XU.js";
6
- import { n as C, r as w, t as T } from "./index.es-D9VqgSyV.js";
4
+ import { t as b } from "./PkStreamingMarkdown-LBiDnEgV.js";
5
+ import { r as x, t as S } from "./index.es-D_E1Gj_U.js";
6
+ import { n as C, r as w, t as T } from "./index.es-DJbHM2zZ.js";
7
7
  //#region ../../packages/components/src/chat/PkToolShowContactForm.vue?vue&type=script&setup=true&lang.ts
8
8
  o(), f(), v(), m();
9
9
  var E = { class: "border border-surface-3 rounded-xl w-full overflow-hidden bg-surface" }, D = { class: "px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40" }, O = { class: "font-bold" }, k = {
@@ -117,4 +117,4 @@ var E = { class: "border border-surface-3 rounded-xl w-full overflow-hidden bg-s
117
117
  //#endregion
118
118
  export { I as default };
119
119
 
120
- //# sourceMappingURL=PkToolShowContactForm-ChaAOt5I.js.map
120
+ //# sourceMappingURL=PkToolShowContactForm-BjlnuEVy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PkToolShowContactForm-ChaAOt5I.js","names":["z.object","z.string","z.email","useForm","__unplugin_components_0","__unplugin_components_1","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_unref","_Transition","_withCtx","_isRef","PkStreamingMarkdown","_sfc_main","object","email","string","withCtx","defineComponent","openBlock","init_runtime_core_esm_bundler","toDisplayString","watch","unref","isRef","createBaseVNode","init_reactivity_esm_bundler","computed","init_runtime_dom_esm_bundler","Transition","createElementBlock","createVNode","init_shared_esm_bundler","useI18n","PkStreamingMarkdown_default","Ca","Ae","useLocalizedString","useSafeLocalStorage","Se","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","PkToolShowContactForm_default","__emit","$t","props","__props","toolPart","input","localSubmitted","LeadFormSchema","emit","newInput","submitted","isSubmitted","submitLead","data","privacyNotice","_component_VvIcon","_component_VvButton","VvForm","formData","_cache","$event","VvFormField"],"sources":["../../../../packages/components/src/chat/PkToolShowContactForm.vue","../../../../packages/components/src/chat/PkToolShowContactForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useForm } from '@volverjs/form-vue'\n import * as z from 'zod'\n import { useSafeLocalStorage, useLocalizedString } from 'composables'\n import type { LocalizedString } from 'models'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const props = defineProps<{\n part: unknown\n submitted?: boolean\n loading?: boolean\n error?: string\n readonly?: boolean\n privacyPolicyNotice?: LocalizedString\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n type: string\n toolCallId: string\n input?: {\n name: string\n email: string\n phone?: string\n conversationContext?: Record<string, unknown>\n }\n }\n return part\n })\n\n const input = computed(() => toolPart.value.input)\n\n const localSubmitted = useSafeLocalStorage<boolean>(\n computed(\n () =>\n `${toolPart.value.toolCallId}-${toolPart.value.type}-submitted`,\n ),\n false,\n )\n\n const LeadFormSchema = z.object({\n name: z.string().min(1).max(255).default(''),\n email: z.email().max(255).default(''),\n phone: z\n .string()\n .max(50)\n .regex(/^[+0-9\\s\\-.()]*$/, $t('validation.invalidPhoneNumber'))\n .optional(),\n })\n\n const emit = defineEmits<{\n submit: [data: Record<string, unknown>]\n }>()\n\n const { VvForm, VvFormField, formData } = useForm(LeadFormSchema, {\n lazyLoad: true,\n })\n\n // Pre-populate form with input values\n watch(\n input,\n (newInput) => {\n formData.value = {\n name: newInput?.name || '',\n email: newInput?.email || '',\n phone: newInput?.phone || '',\n }\n },\n { immediate: true },\n )\n\n watch(\n () => props.submitted,\n (submitted) => {\n if (submitted) {\n localSubmitted.value = true\n }\n },\n { immediate: true },\n )\n\n const isSubmitted = computed(() => {\n return props.submitted || localSubmitted.value\n })\n\n const submitLead = async (data: Record<string, unknown>): Promise<void> => {\n emit('submit', { ...data, metadata: input.value?.conversationContext })\n }\n\n const privacyNotice = useLocalizedString(\n () => props.privacyPolicyNotice,\n 'message.defaultPrivacyPolicyNotice',\n )\n</script>\n\n<template>\n <div\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:send-plane-2-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.contactUs') }}</strong>\n </div>\n\n <Transition mode=\"out-in\">\n <div v-if=\"!isSubmitted\" class=\"p-sm\">\n <VvForm v-model=\"formData\" :readonly @submit=\"submitLead\">\n <VvFormField\n name=\"name\"\n type=\"text\"\n :label=\"$t('label.name')\"\n :placeholder=\"$t('placeholder.name')\"\n icon=\"ri:user-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"email\"\n type=\"email\"\n :label=\"$t('label.email')\"\n :placeholder=\"$t('placeholder.email')\"\n icon=\"ri:mail-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"phone\"\n type=\"tel\"\n :label=\"$t('label.phone')\"\n :placeholder=\"$t('placeholder.phone')\"\n icon=\"ri:phone-line\"\n class=\"mb-md\"\n modifiers=\"compact no-label\" />\n\n <div class=\"flex justify-between items-center gap-16 mt-xs\">\n <div\n class=\"text-smaller text-word-3 flex items-center gap-8\">\n <VvIcon\n name=\"ri:shield-check-line\"\n class=\"text-16 shrink-0\" />\n <PkStreamingMarkdown\n :markdown=\"privacyNotice\"\n class=\"wysiwyg\" />\n </div>\n <VvButton\n type=\"submit\"\n modifiers=\"primary\"\n :loading\n :disabled=\"loading || readonly\"\n icon-position=\"right\"\n class=\"shrink-0\"\n :label=\"$t('action.submit')\" />\n </div>\n </VvForm>\n </div>\n <div v-else class=\"p-sm\">\n <!-- One confirmation row across every tool card: a green\n check, the title in weight, the body quiet. The check is\n the outcome, so it alone carries the colour (DESIGN.md). -->\n <div class=\"flex items-center gap-sm\">\n <VvIcon name=\"ri:check-line\" class=\"text-16 text-success\" />\n <div>\n <strong class=\"font-medium block text-word-1\">\n {{ $t('message.leadSubmittedTitle') }}\n </strong>\n <p class=\"text-word-3\">\n {{ $t('message.leadSubmittedMessage') }}\n </p>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useForm } from '@volverjs/form-vue'\n import * as z from 'zod'\n import { useSafeLocalStorage, useLocalizedString } from 'composables'\n import type { LocalizedString } from 'models'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const props = defineProps<{\n part: unknown\n submitted?: boolean\n loading?: boolean\n error?: string\n readonly?: boolean\n privacyPolicyNotice?: LocalizedString\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n type: string\n toolCallId: string\n input?: {\n name: string\n email: string\n phone?: string\n conversationContext?: Record<string, unknown>\n }\n }\n return part\n })\n\n const input = computed(() => toolPart.value.input)\n\n const localSubmitted = useSafeLocalStorage<boolean>(\n computed(\n () =>\n `${toolPart.value.toolCallId}-${toolPart.value.type}-submitted`,\n ),\n false,\n )\n\n const LeadFormSchema = z.object({\n name: z.string().min(1).max(255).default(''),\n email: z.email().max(255).default(''),\n phone: z\n .string()\n .max(50)\n .regex(/^[+0-9\\s\\-.()]*$/, $t('validation.invalidPhoneNumber'))\n .optional(),\n })\n\n const emit = defineEmits<{\n submit: [data: Record<string, unknown>]\n }>()\n\n const { VvForm, VvFormField, formData } = useForm(LeadFormSchema, {\n lazyLoad: true,\n })\n\n // Pre-populate form with input values\n watch(\n input,\n (newInput) => {\n formData.value = {\n name: newInput?.name || '',\n email: newInput?.email || '',\n phone: newInput?.phone || '',\n }\n },\n { immediate: true },\n )\n\n watch(\n () => props.submitted,\n (submitted) => {\n if (submitted) {\n localSubmitted.value = true\n }\n },\n { immediate: true },\n )\n\n const isSubmitted = computed(() => {\n return props.submitted || localSubmitted.value\n })\n\n const submitLead = async (data: Record<string, unknown>): Promise<void> => {\n emit('submit', { ...data, metadata: input.value?.conversationContext })\n }\n\n const privacyNotice = useLocalizedString(\n () => props.privacyPolicyNotice,\n 'message.defaultPrivacyPolicyNotice',\n )\n</script>\n\n<template>\n <div\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:send-plane-2-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.contactUs') }}</strong>\n </div>\n\n <Transition mode=\"out-in\">\n <div v-if=\"!isSubmitted\" class=\"p-sm\">\n <VvForm v-model=\"formData\" :readonly @submit=\"submitLead\">\n <VvFormField\n name=\"name\"\n type=\"text\"\n :label=\"$t('label.name')\"\n :placeholder=\"$t('placeholder.name')\"\n icon=\"ri:user-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"email\"\n type=\"email\"\n :label=\"$t('label.email')\"\n :placeholder=\"$t('placeholder.email')\"\n icon=\"ri:mail-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"phone\"\n type=\"tel\"\n :label=\"$t('label.phone')\"\n :placeholder=\"$t('placeholder.phone')\"\n icon=\"ri:phone-line\"\n class=\"mb-md\"\n modifiers=\"compact no-label\" />\n\n <div class=\"flex justify-between items-center gap-16 mt-xs\">\n <div\n class=\"text-smaller text-word-3 flex items-center gap-8\">\n <VvIcon\n name=\"ri:shield-check-line\"\n class=\"text-16 shrink-0\" />\n <PkStreamingMarkdown\n :markdown=\"privacyNotice\"\n class=\"wysiwyg\" />\n </div>\n <VvButton\n type=\"submit\"\n modifiers=\"primary\"\n :loading\n :disabled=\"loading || readonly\"\n icon-position=\"right\"\n class=\"shrink-0\"\n :label=\"$t('action.submit')\" />\n </div>\n </VvForm>\n </div>\n <div v-else class=\"p-sm\">\n <!-- One confirmation row across every tool card: a green\n check, the title in weight, the body quiet. The check is\n the outcome, so it alone carries the colour (DESIGN.md). -->\n <div class=\"flex items-center gap-sm\">\n <VvIcon name=\"ri:check-line\" class=\"text-16 text-success\" />\n <div>\n <strong class=\"font-medium block text-word-1\">\n {{ $t('message.leadSubmittedTitle') }}\n </strong>\n <p class=\"text-word-3\">\n {{ $t('message.leadSubmittedMessage') }}\n </p>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"PkToolShowContactForm-BjlnuEVy.js","names":["z.object","z.string","z.email","useForm","__unplugin_components_0","__unplugin_components_1","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_unref","_Transition","_withCtx","_isRef","PkStreamingMarkdown","_sfc_main","object","email","string","withCtx","defineComponent","openBlock","init_runtime_core_esm_bundler","toDisplayString","watch","unref","isRef","createBaseVNode","init_reactivity_esm_bundler","computed","init_runtime_dom_esm_bundler","Transition","createElementBlock","createVNode","init_shared_esm_bundler","useI18n","PkStreamingMarkdown_default","Ca","Ae","useLocalizedString","useSafeLocalStorage","Se","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","PkToolShowContactForm_default","__emit","$t","props","__props","toolPart","input","localSubmitted","LeadFormSchema","emit","newInput","submitted","isSubmitted","submitLead","data","privacyNotice","_component_VvIcon","_component_VvButton","VvForm","formData","_cache","$event","VvFormField"],"sources":["../../../../packages/components/src/chat/PkToolShowContactForm.vue","../../../../packages/components/src/chat/PkToolShowContactForm.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { computed, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useForm } from '@volverjs/form-vue'\n import * as z from 'zod'\n import { useSafeLocalStorage, useLocalizedString } from 'composables'\n import type { LocalizedString } from 'models'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const props = defineProps<{\n part: unknown\n submitted?: boolean\n loading?: boolean\n error?: string\n readonly?: boolean\n privacyPolicyNotice?: LocalizedString\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n type: string\n toolCallId: string\n input?: {\n name: string\n email: string\n phone?: string\n conversationContext?: Record<string, unknown>\n }\n }\n return part\n })\n\n const input = computed(() => toolPart.value.input)\n\n const localSubmitted = useSafeLocalStorage<boolean>(\n computed(\n () =>\n `${toolPart.value.toolCallId}-${toolPart.value.type}-submitted`,\n ),\n false,\n )\n\n const LeadFormSchema = z.object({\n name: z.string().min(1).max(255).default(''),\n email: z.email().max(255).default(''),\n phone: z\n .string()\n .max(50)\n .regex(/^[+0-9\\s\\-.()]*$/, $t('validation.invalidPhoneNumber'))\n .optional(),\n })\n\n const emit = defineEmits<{\n submit: [data: Record<string, unknown>]\n }>()\n\n const { VvForm, VvFormField, formData } = useForm(LeadFormSchema, {\n lazyLoad: true,\n })\n\n // Pre-populate form with input values\n watch(\n input,\n (newInput) => {\n formData.value = {\n name: newInput?.name || '',\n email: newInput?.email || '',\n phone: newInput?.phone || '',\n }\n },\n { immediate: true },\n )\n\n watch(\n () => props.submitted,\n (submitted) => {\n if (submitted) {\n localSubmitted.value = true\n }\n },\n { immediate: true },\n )\n\n const isSubmitted = computed(() => {\n return props.submitted || localSubmitted.value\n })\n\n const submitLead = async (data: Record<string, unknown>): Promise<void> => {\n emit('submit', { ...data, metadata: input.value?.conversationContext })\n }\n\n const privacyNotice = useLocalizedString(\n () => props.privacyPolicyNotice,\n 'message.defaultPrivacyPolicyNotice',\n )\n</script>\n\n<template>\n <div\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:send-plane-2-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.contactUs') }}</strong>\n </div>\n\n <Transition mode=\"out-in\">\n <div v-if=\"!isSubmitted\" class=\"p-sm\">\n <VvForm v-model=\"formData\" :readonly @submit=\"submitLead\">\n <VvFormField\n name=\"name\"\n type=\"text\"\n :label=\"$t('label.name')\"\n :placeholder=\"$t('placeholder.name')\"\n icon=\"ri:user-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"email\"\n type=\"email\"\n :label=\"$t('label.email')\"\n :placeholder=\"$t('placeholder.email')\"\n icon=\"ri:mail-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"phone\"\n type=\"tel\"\n :label=\"$t('label.phone')\"\n :placeholder=\"$t('placeholder.phone')\"\n icon=\"ri:phone-line\"\n class=\"mb-md\"\n modifiers=\"compact no-label\" />\n\n <div class=\"flex justify-between items-center gap-16 mt-xs\">\n <div\n class=\"text-smaller text-word-3 flex items-center gap-8\">\n <VvIcon\n name=\"ri:shield-check-line\"\n class=\"text-16 shrink-0\" />\n <PkStreamingMarkdown\n :markdown=\"privacyNotice\"\n class=\"wysiwyg\" />\n </div>\n <VvButton\n type=\"submit\"\n modifiers=\"primary\"\n :loading\n :disabled=\"loading || readonly\"\n icon-position=\"right\"\n class=\"shrink-0\"\n :label=\"$t('action.submit')\" />\n </div>\n </VvForm>\n </div>\n <div v-else class=\"p-sm\">\n <!-- One confirmation row across every tool card: a green\n check, the title in weight, the body quiet. The check is\n the outcome, so it alone carries the colour (DESIGN.md). -->\n <div class=\"flex items-center gap-sm\">\n <VvIcon name=\"ri:check-line\" class=\"text-16 text-success\" />\n <div>\n <strong class=\"font-medium block text-word-1\">\n {{ $t('message.leadSubmittedTitle') }}\n </strong>\n <p class=\"text-word-3\">\n {{ $t('message.leadSubmittedMessage') }}\n </p>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n","<script setup lang=\"ts\">\n import { computed, watch } from 'vue'\n import { useI18n } from 'vue-i18n'\n import { useForm } from '@volverjs/form-vue'\n import * as z from 'zod'\n import { useSafeLocalStorage, useLocalizedString } from 'composables'\n import type { LocalizedString } from 'models'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n const { t: $t } = useI18n({ useScope: 'global' })\n\n const props = defineProps<{\n part: unknown\n submitted?: boolean\n loading?: boolean\n error?: string\n readonly?: boolean\n privacyPolicyNotice?: LocalizedString\n }>()\n\n const toolPart = computed(() => {\n const part = props.part as {\n type: string\n toolCallId: string\n input?: {\n name: string\n email: string\n phone?: string\n conversationContext?: Record<string, unknown>\n }\n }\n return part\n })\n\n const input = computed(() => toolPart.value.input)\n\n const localSubmitted = useSafeLocalStorage<boolean>(\n computed(\n () =>\n `${toolPart.value.toolCallId}-${toolPart.value.type}-submitted`,\n ),\n false,\n )\n\n const LeadFormSchema = z.object({\n name: z.string().min(1).max(255).default(''),\n email: z.email().max(255).default(''),\n phone: z\n .string()\n .max(50)\n .regex(/^[+0-9\\s\\-.()]*$/, $t('validation.invalidPhoneNumber'))\n .optional(),\n })\n\n const emit = defineEmits<{\n submit: [data: Record<string, unknown>]\n }>()\n\n const { VvForm, VvFormField, formData } = useForm(LeadFormSchema, {\n lazyLoad: true,\n })\n\n // Pre-populate form with input values\n watch(\n input,\n (newInput) => {\n formData.value = {\n name: newInput?.name || '',\n email: newInput?.email || '',\n phone: newInput?.phone || '',\n }\n },\n { immediate: true },\n )\n\n watch(\n () => props.submitted,\n (submitted) => {\n if (submitted) {\n localSubmitted.value = true\n }\n },\n { immediate: true },\n )\n\n const isSubmitted = computed(() => {\n return props.submitted || localSubmitted.value\n })\n\n const submitLead = async (data: Record<string, unknown>): Promise<void> => {\n emit('submit', { ...data, metadata: input.value?.conversationContext })\n }\n\n const privacyNotice = useLocalizedString(\n () => props.privacyPolicyNotice,\n 'message.defaultPrivacyPolicyNotice',\n )\n</script>\n\n<template>\n <div\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden bg-surface\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8 min-h-40\">\n <VvIcon name=\"ri:send-plane-2-line\" class=\"text-16\" />\n <strong class=\"font-bold\">{{ $t('label.contactUs') }}</strong>\n </div>\n\n <Transition mode=\"out-in\">\n <div v-if=\"!isSubmitted\" class=\"p-sm\">\n <VvForm v-model=\"formData\" :readonly @submit=\"submitLead\">\n <VvFormField\n name=\"name\"\n type=\"text\"\n :label=\"$t('label.name')\"\n :placeholder=\"$t('placeholder.name')\"\n icon=\"ri:user-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"email\"\n type=\"email\"\n :label=\"$t('label.email')\"\n :placeholder=\"$t('placeholder.email')\"\n icon=\"ri:mail-line\"\n modifiers=\"compact no-label\"\n class=\"mb-md\" />\n <VvFormField\n name=\"phone\"\n type=\"tel\"\n :label=\"$t('label.phone')\"\n :placeholder=\"$t('placeholder.phone')\"\n icon=\"ri:phone-line\"\n class=\"mb-md\"\n modifiers=\"compact no-label\" />\n\n <div class=\"flex justify-between items-center gap-16 mt-xs\">\n <div\n class=\"text-smaller text-word-3 flex items-center gap-8\">\n <VvIcon\n name=\"ri:shield-check-line\"\n class=\"text-16 shrink-0\" />\n <PkStreamingMarkdown\n :markdown=\"privacyNotice\"\n class=\"wysiwyg\" />\n </div>\n <VvButton\n type=\"submit\"\n modifiers=\"primary\"\n :loading\n :disabled=\"loading || readonly\"\n icon-position=\"right\"\n class=\"shrink-0\"\n :label=\"$t('action.submit')\" />\n </div>\n </VvForm>\n </div>\n <div v-else class=\"p-sm\">\n <!-- One confirmation row across every tool card: a green\n check, the title in weight, the body quiet. The check is\n the outcome, so it alone carries the colour (DESIGN.md). -->\n <div class=\"flex items-center gap-sm\">\n <VvIcon name=\"ri:check-line\" class=\"text-16 text-success\" />\n <div>\n <strong class=\"font-medium block text-word-1\">\n {{ $t('message.leadSubmittedTitle') }}\n </strong>\n <p class=\"text-word-3\">\n {{ $t('message.leadSubmittedMessage') }}\n </p>\n </div>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { r as x } from "./vue-i18n-BAndfHYX.js";
3
3
  import "./src-CrSt0jv_.js";
4
4
  import { n as S } from "./text-DbSEK8si.js";
5
5
  import { i as C } from "./dist-Ce9Hi58x.js";
6
- import { a as w, r as T, t as E } from "./index.es-B9zAw2XU.js";
6
+ import { a as w, r as T, t as E } from "./index.es-D_E1Gj_U.js";
7
7
  import { t as D } from "./_plugin-vue_export-helper-B3ysoDQm.js";
8
8
  import { n as O } from "./useLightbox-Dxdaz_i1.js";
9
9
  //#region ../../packages/components/src/PkSvgViewer.vue?vue&type=script&setup=true&lang.ts
@@ -240,4 +240,4 @@ var M = {
240
240
  //#endregion
241
241
  export { B as default };
242
242
 
243
- //# sourceMappingURL=PkToolShowDiagram-CyNPq6j7.js.map
243
+ //# sourceMappingURL=PkToolShowDiagram-BgyU0CGk.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PkToolShowDiagram-CyNPq6j7.js","names":["_hoisted_1","_hoisted_2","__unplugin_components_0","__unplugin_components_1","_openBlock","_createElementBlock","_normalizeClass","_createElementVNode","_createCommentVNode","_normalizeStyle","_createVNode","_withCtx","_Transition","_unref","_createBlock","_sfc_main","_style_0","__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_unref","_withCtx","_createBlock","_createCommentVNode","PkSvgViewer","_sfc_main","_style_0","withCtx","defineComponent","onMounted","openBlock","init_runtime_core_esm_bundler","normalizeClass","toDisplayString","watch","createCommentVNode","unref","createBlock","createBaseVNode","init_reactivity_esm_bundler","computed","ref","init_runtime_dom_esm_bundler","Transition","createElementBlock","normalizeStyle","createVNode","init_shared_esm_bundler","useI18n","toSnakeCase","useClipboard","Qi","Ca","Ae","_plugin_vue_export_helper_default","useLightbox","_hoisted_1$1","_hoisted_2$1","PkSvgViewer_default","props","__props","$t","svgRef","galleryRef","scale","translateX","translateY","startX","startY","svgDataUrl","svgWidth","svgHeight","svgStyle","zoomIn","zoomOut","reset","openLightbox","lightbox","isDragging","onMouseDown","onMouseMove","onMouseUp","serializeSvg","svg","updateSvgExport","serialized","viewBox","init","_component_VvButton","_component_VvButtonGroup","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","DiagramType","\"Sequence\"","\"Class\"","\"State\"","\"ER\"","\"XYChart\"","\"Flowchart\"","\"Graph\"","PkToolShowDiagram_default","$te","toolPart","svgError","svgContent","diagramType","code","diagramTypeLabel","diagramTypeIcon","renderDiagram","theme","THEMES","renderMermaidSVG","downloadSvg","blob","url","anchor","copyCode","copy","_component_VvIcon","copied"],"sources":["../../../../packages/components/src/PkSvgViewer.vue","../../../../packages/components/src/PkSvgViewer.vue","../../../../packages/components/src/PkSvgViewer.vue","../../../../packages/components/src/chat/PkToolShowDiagram.vue","../../../../packages/components/src/chat/PkToolShowDiagram.vue","../../../../packages/components/src/chat/PkToolShowDiagram.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { ref, onMounted, computed, watch } from 'vue'\n import { useLightbox } from './composables/useLightbox'\n import { useI18n } from 'vue-i18n'\n\n const props = defineProps<{\n svg?: string\n title?: string\n }>()\n\n const { t: $t } = useI18n()\n\n const svgRef = ref<HTMLDivElement | null>(null)\n const galleryRef = ref<HTMLElement>()\n\n const scale = ref(1)\n const translateX = ref(0)\n const translateY = ref(0)\n const startX = ref(0)\n const startY = ref(0)\n\n // PhotoSwipe integration\n const svgDataUrl = ref('')\n const svgWidth = ref(0)\n const svgHeight = ref(0)\n\n const { lightbox, init } = useLightbox({\n gallery: galleryRef,\n downloadable: true,\n openInNewTab: false,\n })\n\n const svgStyle = computed(() => ({\n transform: `translate(${translateX.value}px, ${translateY.value}px) scale(${scale.value})`,\n }))\n\n const zoomIn = () => {\n scale.value = Math.min(scale.value * 1.2, 10)\n }\n\n const zoomOut = () => {\n scale.value = Math.max(scale.value / 1.2, 0.1)\n }\n\n const reset = () => {\n scale.value = 1\n translateX.value = 0\n translateY.value = 0\n }\n\n const openLightbox = () => {\n if (svgDataUrl.value) {\n lightbox.value?.loadAndOpen(0)\n }\n }\n\n const isDragging = ref(false)\n\n // Pan logic\n const onMouseDown = (e: MouseEvent) => {\n e.preventDefault()\n isDragging.value = true\n startX.value = e.clientX - translateX.value\n startY.value = e.clientY - translateY.value\n }\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isDragging.value) {\n return\n }\n translateX.value = e.clientX - startX.value\n translateY.value = e.clientY - startY.value\n }\n\n const onMouseUp = () => {\n isDragging.value = false\n }\n\n function serializeSvg(): string | null {\n const svg = svgRef.value?.querySelector('svg')\n if (!svg) {\n return null\n }\n return new XMLSerializer().serializeToString(svg)\n }\n\n function updateSvgExport() {\n const svg = svgRef.value?.querySelector('svg')\n const serialized = serializeSvg()\n if (!svg || !serialized) {\n return\n }\n\n const viewBox = svg.viewBox?.baseVal\n svgWidth.value =\n viewBox?.width || svg.getBoundingClientRect().width || 1200\n svgHeight.value =\n viewBox?.height || svg.getBoundingClientRect().height || 800\n svgDataUrl.value = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(serialized)}`\n }\n\n watch(\n () => props.svg,\n () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n },\n )\n\n onMounted(async () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n await init()\n })\n</script>\n\n<template>\n <div\n class=\"pk-svg-viewer\"\n :class=\"{\n 'pk-svg-viewer--dragging': isDragging,\n }\">\n <!-- Hidden Gallery for Lightbox -->\n <div ref=\"galleryRef\" class=\"hidden\">\n <a\n v-if=\"svgDataUrl\"\n :href=\"svgDataUrl\"\n :data-pswp-src=\"svgDataUrl\"\n :data-pswp-width=\"svgWidth\"\n :data-pswp-height=\"svgHeight\"\n :title=\"title\" />\n </div>\n\n <!-- SVG Stage -->\n <div\n class=\"pk-svg-viewer__stage\"\n @mousedown=\"onMouseDown\"\n @mousemove=\"onMouseMove\"\n @mouseup=\"onMouseUp\"\n @mouseleave=\"onMouseUp\">\n <div\n ref=\"svgRef\"\n :style=\"svgStyle\"\n class=\"pk-svg-viewer__content\" />\n </div>\n\n <!-- Floating Toolbar -->\n <div class=\"pk-svg-viewer__toolbar\">\n <VvButtonGroup\n modifiers=\"compact\"\n class=\"bg-surface-1 shadow-md overflow-hidden\">\n <transition name=\"fade\">\n <VvButton\n key=\"reset\"\n modifiers=\"action-small\"\n :disabled=\"\n scale === 1 && translateX === 0 && translateY === 0\n \"\n icon=\"ri:aspect-ratio-line\"\n :title=\"$t('action.reset')\"\n @click=\"reset\" />\n </transition>\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:zoom-out-line\"\n :title=\"$t('action.zoomOut')\"\n @click=\"zoomOut\" />\n <VvButton\n modifiers=\"action-small\"\n icon=\"ri:zoom-in-line\"\n :title=\"$t('action.zoomIn')\"\n @click=\"zoomIn\" />\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:fullscreen-line\"\n :title=\"$t('action.expand')\"\n @click=\"openLightbox\" />\n </VvButtonGroup>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-svg-viewer {\n position: relative;\n overflow: hidden;\n background-color: var(--color-surface-2);\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n\n &__content {\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n transition: transform 0.3s ease-out;\n transform-origin: center center;\n\n svg {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n width: auto;\n }\n }\n\n &__toolbar {\n position: absolute;\n top: var(--spacing-8);\n right: var(--spacing-8);\n z-index: var(--z-dropdown);\n opacity: 0;\n transition: var(--transition-opacity);\n }\n\n &__stage {\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n }\n\n &:hover {\n .pk-svg-viewer__toolbar {\n opacity: 1;\n }\n }\n\n &--dragging {\n .pk-svg-viewer__toolbar {\n opacity: 0.5 !important;\n pointer-events: none;\n\n & * {\n pointer-events: none;\n }\n }\n\n .pk-svg-viewer__content {\n cursor: grabbing !important;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { ref, onMounted, computed, watch } from 'vue'\n import { useLightbox } from './composables/useLightbox'\n import { useI18n } from 'vue-i18n'\n\n const props = defineProps<{\n svg?: string\n title?: string\n }>()\n\n const { t: $t } = useI18n()\n\n const svgRef = ref<HTMLDivElement | null>(null)\n const galleryRef = ref<HTMLElement>()\n\n const scale = ref(1)\n const translateX = ref(0)\n const translateY = ref(0)\n const startX = ref(0)\n const startY = ref(0)\n\n // PhotoSwipe integration\n const svgDataUrl = ref('')\n const svgWidth = ref(0)\n const svgHeight = ref(0)\n\n const { lightbox, init } = useLightbox({\n gallery: galleryRef,\n downloadable: true,\n openInNewTab: false,\n })\n\n const svgStyle = computed(() => ({\n transform: `translate(${translateX.value}px, ${translateY.value}px) scale(${scale.value})`,\n }))\n\n const zoomIn = () => {\n scale.value = Math.min(scale.value * 1.2, 10)\n }\n\n const zoomOut = () => {\n scale.value = Math.max(scale.value / 1.2, 0.1)\n }\n\n const reset = () => {\n scale.value = 1\n translateX.value = 0\n translateY.value = 0\n }\n\n const openLightbox = () => {\n if (svgDataUrl.value) {\n lightbox.value?.loadAndOpen(0)\n }\n }\n\n const isDragging = ref(false)\n\n // Pan logic\n const onMouseDown = (e: MouseEvent) => {\n e.preventDefault()\n isDragging.value = true\n startX.value = e.clientX - translateX.value\n startY.value = e.clientY - translateY.value\n }\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isDragging.value) {\n return\n }\n translateX.value = e.clientX - startX.value\n translateY.value = e.clientY - startY.value\n }\n\n const onMouseUp = () => {\n isDragging.value = false\n }\n\n function serializeSvg(): string | null {\n const svg = svgRef.value?.querySelector('svg')\n if (!svg) {\n return null\n }\n return new XMLSerializer().serializeToString(svg)\n }\n\n function updateSvgExport() {\n const svg = svgRef.value?.querySelector('svg')\n const serialized = serializeSvg()\n if (!svg || !serialized) {\n return\n }\n\n const viewBox = svg.viewBox?.baseVal\n svgWidth.value =\n viewBox?.width || svg.getBoundingClientRect().width || 1200\n svgHeight.value =\n viewBox?.height || svg.getBoundingClientRect().height || 800\n svgDataUrl.value = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(serialized)}`\n }\n\n watch(\n () => props.svg,\n () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n },\n )\n\n onMounted(async () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n await init()\n })\n</script>\n\n<template>\n <div\n class=\"pk-svg-viewer\"\n :class=\"{\n 'pk-svg-viewer--dragging': isDragging,\n }\">\n <!-- Hidden Gallery for Lightbox -->\n <div ref=\"galleryRef\" class=\"hidden\">\n <a\n v-if=\"svgDataUrl\"\n :href=\"svgDataUrl\"\n :data-pswp-src=\"svgDataUrl\"\n :data-pswp-width=\"svgWidth\"\n :data-pswp-height=\"svgHeight\"\n :title=\"title\" />\n </div>\n\n <!-- SVG Stage -->\n <div\n class=\"pk-svg-viewer__stage\"\n @mousedown=\"onMouseDown\"\n @mousemove=\"onMouseMove\"\n @mouseup=\"onMouseUp\"\n @mouseleave=\"onMouseUp\">\n <div\n ref=\"svgRef\"\n :style=\"svgStyle\"\n class=\"pk-svg-viewer__content\" />\n </div>\n\n <!-- Floating Toolbar -->\n <div class=\"pk-svg-viewer__toolbar\">\n <VvButtonGroup\n modifiers=\"compact\"\n class=\"bg-surface-1 shadow-md overflow-hidden\">\n <transition name=\"fade\">\n <VvButton\n key=\"reset\"\n modifiers=\"action-small\"\n :disabled=\"\n scale === 1 && translateX === 0 && translateY === 0\n \"\n icon=\"ri:aspect-ratio-line\"\n :title=\"$t('action.reset')\"\n @click=\"reset\" />\n </transition>\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:zoom-out-line\"\n :title=\"$t('action.zoomOut')\"\n @click=\"zoomOut\" />\n <VvButton\n modifiers=\"action-small\"\n icon=\"ri:zoom-in-line\"\n :title=\"$t('action.zoomIn')\"\n @click=\"zoomIn\" />\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:fullscreen-line\"\n :title=\"$t('action.expand')\"\n @click=\"openLightbox\" />\n </VvButtonGroup>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-svg-viewer {\n position: relative;\n overflow: hidden;\n background-color: var(--color-surface-2);\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n\n &__content {\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n transition: transform 0.3s ease-out;\n transform-origin: center center;\n\n svg {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n width: auto;\n }\n }\n\n &__toolbar {\n position: absolute;\n top: var(--spacing-8);\n right: var(--spacing-8);\n z-index: var(--z-dropdown);\n opacity: 0;\n transition: var(--transition-opacity);\n }\n\n &__stage {\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n }\n\n &:hover {\n .pk-svg-viewer__toolbar {\n opacity: 1;\n }\n }\n\n &--dragging {\n .pk-svg-viewer__toolbar {\n opacity: 0.5 !important;\n pointer-events: none;\n\n & * {\n pointer-events: none;\n }\n }\n\n .pk-svg-viewer__content {\n cursor: grabbing !important;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { ref, onMounted, computed, watch } from 'vue'\n import { useLightbox } from './composables/useLightbox'\n import { useI18n } from 'vue-i18n'\n\n const props = defineProps<{\n svg?: string\n title?: string\n }>()\n\n const { t: $t } = useI18n()\n\n const svgRef = ref<HTMLDivElement | null>(null)\n const galleryRef = ref<HTMLElement>()\n\n const scale = ref(1)\n const translateX = ref(0)\n const translateY = ref(0)\n const startX = ref(0)\n const startY = ref(0)\n\n // PhotoSwipe integration\n const svgDataUrl = ref('')\n const svgWidth = ref(0)\n const svgHeight = ref(0)\n\n const { lightbox, init } = useLightbox({\n gallery: galleryRef,\n downloadable: true,\n openInNewTab: false,\n })\n\n const svgStyle = computed(() => ({\n transform: `translate(${translateX.value}px, ${translateY.value}px) scale(${scale.value})`,\n }))\n\n const zoomIn = () => {\n scale.value = Math.min(scale.value * 1.2, 10)\n }\n\n const zoomOut = () => {\n scale.value = Math.max(scale.value / 1.2, 0.1)\n }\n\n const reset = () => {\n scale.value = 1\n translateX.value = 0\n translateY.value = 0\n }\n\n const openLightbox = () => {\n if (svgDataUrl.value) {\n lightbox.value?.loadAndOpen(0)\n }\n }\n\n const isDragging = ref(false)\n\n // Pan logic\n const onMouseDown = (e: MouseEvent) => {\n e.preventDefault()\n isDragging.value = true\n startX.value = e.clientX - translateX.value\n startY.value = e.clientY - translateY.value\n }\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isDragging.value) {\n return\n }\n translateX.value = e.clientX - startX.value\n translateY.value = e.clientY - startY.value\n }\n\n const onMouseUp = () => {\n isDragging.value = false\n }\n\n function serializeSvg(): string | null {\n const svg = svgRef.value?.querySelector('svg')\n if (!svg) {\n return null\n }\n return new XMLSerializer().serializeToString(svg)\n }\n\n function updateSvgExport() {\n const svg = svgRef.value?.querySelector('svg')\n const serialized = serializeSvg()\n if (!svg || !serialized) {\n return\n }\n\n const viewBox = svg.viewBox?.baseVal\n svgWidth.value =\n viewBox?.width || svg.getBoundingClientRect().width || 1200\n svgHeight.value =\n viewBox?.height || svg.getBoundingClientRect().height || 800\n svgDataUrl.value = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(serialized)}`\n }\n\n watch(\n () => props.svg,\n () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n },\n )\n\n onMounted(async () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n await init()\n })\n</script>\n\n<template>\n <div\n class=\"pk-svg-viewer\"\n :class=\"{\n 'pk-svg-viewer--dragging': isDragging,\n }\">\n <!-- Hidden Gallery for Lightbox -->\n <div ref=\"galleryRef\" class=\"hidden\">\n <a\n v-if=\"svgDataUrl\"\n :href=\"svgDataUrl\"\n :data-pswp-src=\"svgDataUrl\"\n :data-pswp-width=\"svgWidth\"\n :data-pswp-height=\"svgHeight\"\n :title=\"title\" />\n </div>\n\n <!-- SVG Stage -->\n <div\n class=\"pk-svg-viewer__stage\"\n @mousedown=\"onMouseDown\"\n @mousemove=\"onMouseMove\"\n @mouseup=\"onMouseUp\"\n @mouseleave=\"onMouseUp\">\n <div\n ref=\"svgRef\"\n :style=\"svgStyle\"\n class=\"pk-svg-viewer__content\" />\n </div>\n\n <!-- Floating Toolbar -->\n <div class=\"pk-svg-viewer__toolbar\">\n <VvButtonGroup\n modifiers=\"compact\"\n class=\"bg-surface-1 shadow-md overflow-hidden\">\n <transition name=\"fade\">\n <VvButton\n key=\"reset\"\n modifiers=\"action-small\"\n :disabled=\"\n scale === 1 && translateX === 0 && translateY === 0\n \"\n icon=\"ri:aspect-ratio-line\"\n :title=\"$t('action.reset')\"\n @click=\"reset\" />\n </transition>\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:zoom-out-line\"\n :title=\"$t('action.zoomOut')\"\n @click=\"zoomOut\" />\n <VvButton\n modifiers=\"action-small\"\n icon=\"ri:zoom-in-line\"\n :title=\"$t('action.zoomIn')\"\n @click=\"zoomIn\" />\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:fullscreen-line\"\n :title=\"$t('action.expand')\"\n @click=\"openLightbox\" />\n </VvButtonGroup>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-svg-viewer {\n position: relative;\n overflow: hidden;\n background-color: var(--color-surface-2);\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n\n &__content {\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n transition: transform 0.3s ease-out;\n transform-origin: center center;\n\n svg {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n width: auto;\n }\n }\n\n &__toolbar {\n position: absolute;\n top: var(--spacing-8);\n right: var(--spacing-8);\n z-index: var(--z-dropdown);\n opacity: 0;\n transition: var(--transition-opacity);\n }\n\n &__stage {\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n }\n\n &:hover {\n .pk-svg-viewer__toolbar {\n opacity: 1;\n }\n }\n\n &--dragging {\n .pk-svg-viewer__toolbar {\n opacity: 0.5 !important;\n pointer-events: none;\n\n & * {\n pointer-events: none;\n }\n }\n\n .pk-svg-viewer__content {\n cursor: grabbing !important;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, onMounted, ref, watch } from 'vue'\n import { useClipboard } from '@vueuse/core'\n import { useI18n } from 'vue-i18n'\n import { toSnakeCase } from 'utils'\n import PkSvgViewer from '../PkSvgViewer.vue'\n\n const props = defineProps<{\n part: unknown\n isDark?: boolean\n }>()\n\n const { t: $t, te: $te } = useI18n({\n useScope: 'global',\n })\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n code: string\n title?: string\n caption?: string\n }\n }\n return part\n })\n\n const svgError = ref(false)\n\n // Serialized SVG content\n const svgContent = ref('')\n\n enum DiagramType {\n Sequence = 'sequenceDiagram',\n Class = 'classDiagram',\n State = 'stateDiagram',\n ER = 'erDiagram',\n XYChart = 'xychart',\n Flowchart = 'flowchart',\n Graph = 'graph',\n }\n\n const diagramType = computed<DiagramType | undefined>(() => {\n const code = toolPart.value.input?.code?.trimStart()\n if (!code) {\n return undefined\n }\n const firstWord = code.match(/^[A-Za-z-]+/)?.[0]\n switch (firstWord) {\n case 'sequenceDiagram':\n return DiagramType.Sequence\n case 'classDiagram':\n return DiagramType.Class\n case 'stateDiagram':\n return DiagramType.State\n case 'erDiagram':\n return DiagramType.ER\n case 'xychart-beta':\n return DiagramType.XYChart\n case 'flowchart':\n return DiagramType.Flowchart\n case 'graph':\n return DiagramType.Graph\n default:\n return undefined\n }\n })\n\n const diagramTypeLabel = computed(() => {\n if (!diagramType.value) {\n return ''\n }\n return $te(`diagram.${diagramType.value}`)\n ? $t(`diagram.${diagramType.value}`)\n : diagramType.value\n })\n\n const diagramTypeIcon = computed(() => {\n switch (diagramType.value) {\n case DiagramType.Sequence:\n return 'ri:timeline-view'\n case DiagramType.Class:\n return 'ri:organization-chart'\n case DiagramType.State:\n return 'ri:organization-chart'\n case DiagramType.ER:\n return 'ri:organization-chart'\n case DiagramType.XYChart:\n return 'ri:line-chart-line'\n case DiagramType.Flowchart:\n return 'ri:flow-chart'\n case DiagramType.Graph:\n return 'ri:flow-chart'\n default:\n return 'ri:flow-chart'\n }\n })\n\n async function renderDiagram() {\n const code = toolPart.value.input?.code\n if (!code) {\n return\n }\n\n svgError.value = false\n try {\n const { renderMermaidSVG, THEMES } =\n await import('beautiful-mermaid')\n const theme = props.isDark\n ? THEMES['github-dark']\n : THEMES['github-light']\n svgContent.value = renderMermaidSVG(code, theme)\n } catch {\n svgError.value = true\n }\n }\n\n watch([() => toolPart.value.input?.code, () => props.isDark], renderDiagram)\n onMounted(async () => {\n await renderDiagram()\n })\n\n const downloadSvg = () => {\n if (!svgContent.value) {\n return\n }\n const blob = new Blob([svgContent.value], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = `${toSnakeCase(toolPart.value.input?.title || 'diagram')}.svg`\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n URL.revokeObjectURL(url)\n }\n\n const copyCode = () => {\n const code = toolPart.value.input?.code\n if (code) {\n copy(code)\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.code\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon :name=\"diagramTypeIcon\" class=\"text-16\" />\n <div class=\"flex flex-col items-start gap-2\">\n <strong class=\"font-bold\">{{\n diagramTypeLabel ?? $t('label.diagram')\n }}</strong>\n </div>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyCode\" />\n <VvButton\n v-if=\"svgContent\"\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :label=\"$t('action.download')\"\n @click=\"downloadSvg\" />\n </VvButtonGroup>\n </div>\n <div v-if=\"svgError\" class=\"text-12 text-danger py-8 px-sm\">\n {{ $t('message.diagramRenderError') }}\n </div>\n <PkSvgViewer\n v-else-if=\"svgContent\"\n class=\"pk-tool-show-diagram__stage\"\n :svg=\"svgContent\"\n :title=\"toolPart.input?.title\" />\n <div\n v-else\n class=\"pk-tool-show-diagram__stage flex justify-center items-center\">\n <VvIcon name=\"loading-loop\" class=\"w-24 h-24 text-word-5\" />\n </div>\n <div\n v-if=\"toolPart.input.caption\"\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-t border-surface-3 text-word-3\">\n {{ toolPart.input.caption }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-show-diagram {\n // Fixed stage height: the diagram renders lazily (async chunk +\n // dynamic mermaid import), so the loader and the rendered SVG must\n // occupy the same space or the chat scroll position jumps around.\n // The SVG scales to fit; zoom/pan and the lightbox cover the rest.\n &__stage {\n height: 384px;\n\n .pk-svg-viewer__stage,\n .pk-svg-viewer__content {\n height: 100%;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, onMounted, ref, watch } from 'vue'\n import { useClipboard } from '@vueuse/core'\n import { useI18n } from 'vue-i18n'\n import { toSnakeCase } from 'utils'\n import PkSvgViewer from '../PkSvgViewer.vue'\n\n const props = defineProps<{\n part: unknown\n isDark?: boolean\n }>()\n\n const { t: $t, te: $te } = useI18n({\n useScope: 'global',\n })\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n code: string\n title?: string\n caption?: string\n }\n }\n return part\n })\n\n const svgError = ref(false)\n\n // Serialized SVG content\n const svgContent = ref('')\n\n enum DiagramType {\n Sequence = 'sequenceDiagram',\n Class = 'classDiagram',\n State = 'stateDiagram',\n ER = 'erDiagram',\n XYChart = 'xychart',\n Flowchart = 'flowchart',\n Graph = 'graph',\n }\n\n const diagramType = computed<DiagramType | undefined>(() => {\n const code = toolPart.value.input?.code?.trimStart()\n if (!code) {\n return undefined\n }\n const firstWord = code.match(/^[A-Za-z-]+/)?.[0]\n switch (firstWord) {\n case 'sequenceDiagram':\n return DiagramType.Sequence\n case 'classDiagram':\n return DiagramType.Class\n case 'stateDiagram':\n return DiagramType.State\n case 'erDiagram':\n return DiagramType.ER\n case 'xychart-beta':\n return DiagramType.XYChart\n case 'flowchart':\n return DiagramType.Flowchart\n case 'graph':\n return DiagramType.Graph\n default:\n return undefined\n }\n })\n\n const diagramTypeLabel = computed(() => {\n if (!diagramType.value) {\n return ''\n }\n return $te(`diagram.${diagramType.value}`)\n ? $t(`diagram.${diagramType.value}`)\n : diagramType.value\n })\n\n const diagramTypeIcon = computed(() => {\n switch (diagramType.value) {\n case DiagramType.Sequence:\n return 'ri:timeline-view'\n case DiagramType.Class:\n return 'ri:organization-chart'\n case DiagramType.State:\n return 'ri:organization-chart'\n case DiagramType.ER:\n return 'ri:organization-chart'\n case DiagramType.XYChart:\n return 'ri:line-chart-line'\n case DiagramType.Flowchart:\n return 'ri:flow-chart'\n case DiagramType.Graph:\n return 'ri:flow-chart'\n default:\n return 'ri:flow-chart'\n }\n })\n\n async function renderDiagram() {\n const code = toolPart.value.input?.code\n if (!code) {\n return\n }\n\n svgError.value = false\n try {\n const { renderMermaidSVG, THEMES } =\n await import('beautiful-mermaid')\n const theme = props.isDark\n ? THEMES['github-dark']\n : THEMES['github-light']\n svgContent.value = renderMermaidSVG(code, theme)\n } catch {\n svgError.value = true\n }\n }\n\n watch([() => toolPart.value.input?.code, () => props.isDark], renderDiagram)\n onMounted(async () => {\n await renderDiagram()\n })\n\n const downloadSvg = () => {\n if (!svgContent.value) {\n return\n }\n const blob = new Blob([svgContent.value], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = `${toSnakeCase(toolPart.value.input?.title || 'diagram')}.svg`\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n URL.revokeObjectURL(url)\n }\n\n const copyCode = () => {\n const code = toolPart.value.input?.code\n if (code) {\n copy(code)\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.code\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon :name=\"diagramTypeIcon\" class=\"text-16\" />\n <div class=\"flex flex-col items-start gap-2\">\n <strong class=\"font-bold\">{{\n diagramTypeLabel ?? $t('label.diagram')\n }}</strong>\n </div>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyCode\" />\n <VvButton\n v-if=\"svgContent\"\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :label=\"$t('action.download')\"\n @click=\"downloadSvg\" />\n </VvButtonGroup>\n </div>\n <div v-if=\"svgError\" class=\"text-12 text-danger py-8 px-sm\">\n {{ $t('message.diagramRenderError') }}\n </div>\n <PkSvgViewer\n v-else-if=\"svgContent\"\n class=\"pk-tool-show-diagram__stage\"\n :svg=\"svgContent\"\n :title=\"toolPart.input?.title\" />\n <div\n v-else\n class=\"pk-tool-show-diagram__stage flex justify-center items-center\">\n <VvIcon name=\"loading-loop\" class=\"w-24 h-24 text-word-5\" />\n </div>\n <div\n v-if=\"toolPart.input.caption\"\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-t border-surface-3 text-word-3\">\n {{ toolPart.input.caption }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-show-diagram {\n // Fixed stage height: the diagram renders lazily (async chunk +\n // dynamic mermaid import), so the loader and the rendered SVG must\n // occupy the same space or the chat scroll position jumps around.\n // The SVG scales to fit; zoom/pan and the lightbox cover the rest.\n &__stage {\n height: 384px;\n\n .pk-svg-viewer__stage,\n .pk-svg-viewer__content {\n height: 100%;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, onMounted, ref, watch } from 'vue'\n import { useClipboard } from '@vueuse/core'\n import { useI18n } from 'vue-i18n'\n import { toSnakeCase } from 'utils'\n import PkSvgViewer from '../PkSvgViewer.vue'\n\n const props = defineProps<{\n part: unknown\n isDark?: boolean\n }>()\n\n const { t: $t, te: $te } = useI18n({\n useScope: 'global',\n })\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n code: string\n title?: string\n caption?: string\n }\n }\n return part\n })\n\n const svgError = ref(false)\n\n // Serialized SVG content\n const svgContent = ref('')\n\n enum DiagramType {\n Sequence = 'sequenceDiagram',\n Class = 'classDiagram',\n State = 'stateDiagram',\n ER = 'erDiagram',\n XYChart = 'xychart',\n Flowchart = 'flowchart',\n Graph = 'graph',\n }\n\n const diagramType = computed<DiagramType | undefined>(() => {\n const code = toolPart.value.input?.code?.trimStart()\n if (!code) {\n return undefined\n }\n const firstWord = code.match(/^[A-Za-z-]+/)?.[0]\n switch (firstWord) {\n case 'sequenceDiagram':\n return DiagramType.Sequence\n case 'classDiagram':\n return DiagramType.Class\n case 'stateDiagram':\n return DiagramType.State\n case 'erDiagram':\n return DiagramType.ER\n case 'xychart-beta':\n return DiagramType.XYChart\n case 'flowchart':\n return DiagramType.Flowchart\n case 'graph':\n return DiagramType.Graph\n default:\n return undefined\n }\n })\n\n const diagramTypeLabel = computed(() => {\n if (!diagramType.value) {\n return ''\n }\n return $te(`diagram.${diagramType.value}`)\n ? $t(`diagram.${diagramType.value}`)\n : diagramType.value\n })\n\n const diagramTypeIcon = computed(() => {\n switch (diagramType.value) {\n case DiagramType.Sequence:\n return 'ri:timeline-view'\n case DiagramType.Class:\n return 'ri:organization-chart'\n case DiagramType.State:\n return 'ri:organization-chart'\n case DiagramType.ER:\n return 'ri:organization-chart'\n case DiagramType.XYChart:\n return 'ri:line-chart-line'\n case DiagramType.Flowchart:\n return 'ri:flow-chart'\n case DiagramType.Graph:\n return 'ri:flow-chart'\n default:\n return 'ri:flow-chart'\n }\n })\n\n async function renderDiagram() {\n const code = toolPart.value.input?.code\n if (!code) {\n return\n }\n\n svgError.value = false\n try {\n const { renderMermaidSVG, THEMES } =\n await import('beautiful-mermaid')\n const theme = props.isDark\n ? THEMES['github-dark']\n : THEMES['github-light']\n svgContent.value = renderMermaidSVG(code, theme)\n } catch {\n svgError.value = true\n }\n }\n\n watch([() => toolPart.value.input?.code, () => props.isDark], renderDiagram)\n onMounted(async () => {\n await renderDiagram()\n })\n\n const downloadSvg = () => {\n if (!svgContent.value) {\n return\n }\n const blob = new Blob([svgContent.value], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = `${toSnakeCase(toolPart.value.input?.title || 'diagram')}.svg`\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n URL.revokeObjectURL(url)\n }\n\n const copyCode = () => {\n const code = toolPart.value.input?.code\n if (code) {\n copy(code)\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.code\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon :name=\"diagramTypeIcon\" class=\"text-16\" />\n <div class=\"flex flex-col items-start gap-2\">\n <strong class=\"font-bold\">{{\n diagramTypeLabel ?? $t('label.diagram')\n }}</strong>\n </div>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyCode\" />\n <VvButton\n v-if=\"svgContent\"\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :label=\"$t('action.download')\"\n @click=\"downloadSvg\" />\n </VvButtonGroup>\n </div>\n <div v-if=\"svgError\" class=\"text-12 text-danger py-8 px-sm\">\n {{ $t('message.diagramRenderError') }}\n </div>\n <PkSvgViewer\n v-else-if=\"svgContent\"\n class=\"pk-tool-show-diagram__stage\"\n :svg=\"svgContent\"\n :title=\"toolPart.input?.title\" />\n <div\n v-else\n class=\"pk-tool-show-diagram__stage flex justify-center items-center\">\n <VvIcon name=\"loading-loop\" class=\"w-24 h-24 text-word-5\" />\n </div>\n <div\n v-if=\"toolPart.input.caption\"\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-t border-surface-3 text-word-3\">\n {{ toolPart.input.caption }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-show-diagram {\n // Fixed stage height: the diagram renders lazily (async chunk +\n // dynamic mermaid import), so the loader and the rendered SVG must\n // occupy the same space or the chat scroll position jumps around.\n // The SVG scales to fit; zoom/pan and the lightbox cover the rest.\n &__stage {\n height: 384px;\n\n .pk-svg-viewer__stage,\n .pk-svg-viewer__content {\n height: 100%;\n }\n }\n }\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"PkToolShowDiagram-BgyU0CGk.js","names":["_hoisted_1","_hoisted_2","__unplugin_components_0","__unplugin_components_1","_openBlock","_createElementBlock","_normalizeClass","_createElementVNode","_createCommentVNode","_normalizeStyle","_createVNode","_withCtx","_Transition","_unref","_createBlock","_sfc_main","_style_0","__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","_openBlock","_createElementBlock","_createElementVNode","_createVNode","_toDisplayString","_unref","_withCtx","_createBlock","_createCommentVNode","PkSvgViewer","_sfc_main","_style_0","withCtx","defineComponent","onMounted","openBlock","init_runtime_core_esm_bundler","normalizeClass","toDisplayString","watch","createCommentVNode","unref","createBlock","createBaseVNode","init_reactivity_esm_bundler","computed","ref","init_runtime_dom_esm_bundler","Transition","createElementBlock","normalizeStyle","createVNode","init_shared_esm_bundler","useI18n","toSnakeCase","useClipboard","Qi","Ca","Ae","_plugin_vue_export_helper_default","useLightbox","_hoisted_1$1","_hoisted_2$1","PkSvgViewer_default","props","__props","$t","svgRef","galleryRef","scale","translateX","translateY","startX","startY","svgDataUrl","svgWidth","svgHeight","svgStyle","zoomIn","zoomOut","reset","openLightbox","lightbox","isDragging","onMouseDown","onMouseMove","onMouseUp","serializeSvg","svg","updateSvgExport","serialized","viewBox","init","_component_VvButton","_component_VvButtonGroup","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","DiagramType","\"Sequence\"","\"Class\"","\"State\"","\"ER\"","\"XYChart\"","\"Flowchart\"","\"Graph\"","PkToolShowDiagram_default","$te","toolPart","svgError","svgContent","diagramType","code","diagramTypeLabel","diagramTypeIcon","renderDiagram","theme","THEMES","renderMermaidSVG","downloadSvg","blob","url","anchor","copyCode","copy","_component_VvIcon","copied"],"sources":["../../../../packages/components/src/PkSvgViewer.vue","../../../../packages/components/src/PkSvgViewer.vue","../../../../packages/components/src/PkSvgViewer.vue","../../../../packages/components/src/chat/PkToolShowDiagram.vue","../../../../packages/components/src/chat/PkToolShowDiagram.vue","../../../../packages/components/src/chat/PkToolShowDiagram.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import { ref, onMounted, computed, watch } from 'vue'\n import { useLightbox } from './composables/useLightbox'\n import { useI18n } from 'vue-i18n'\n\n const props = defineProps<{\n svg?: string\n title?: string\n }>()\n\n const { t: $t } = useI18n()\n\n const svgRef = ref<HTMLDivElement | null>(null)\n const galleryRef = ref<HTMLElement>()\n\n const scale = ref(1)\n const translateX = ref(0)\n const translateY = ref(0)\n const startX = ref(0)\n const startY = ref(0)\n\n // PhotoSwipe integration\n const svgDataUrl = ref('')\n const svgWidth = ref(0)\n const svgHeight = ref(0)\n\n const { lightbox, init } = useLightbox({\n gallery: galleryRef,\n downloadable: true,\n openInNewTab: false,\n })\n\n const svgStyle = computed(() => ({\n transform: `translate(${translateX.value}px, ${translateY.value}px) scale(${scale.value})`,\n }))\n\n const zoomIn = () => {\n scale.value = Math.min(scale.value * 1.2, 10)\n }\n\n const zoomOut = () => {\n scale.value = Math.max(scale.value / 1.2, 0.1)\n }\n\n const reset = () => {\n scale.value = 1\n translateX.value = 0\n translateY.value = 0\n }\n\n const openLightbox = () => {\n if (svgDataUrl.value) {\n lightbox.value?.loadAndOpen(0)\n }\n }\n\n const isDragging = ref(false)\n\n // Pan logic\n const onMouseDown = (e: MouseEvent) => {\n e.preventDefault()\n isDragging.value = true\n startX.value = e.clientX - translateX.value\n startY.value = e.clientY - translateY.value\n }\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isDragging.value) {\n return\n }\n translateX.value = e.clientX - startX.value\n translateY.value = e.clientY - startY.value\n }\n\n const onMouseUp = () => {\n isDragging.value = false\n }\n\n function serializeSvg(): string | null {\n const svg = svgRef.value?.querySelector('svg')\n if (!svg) {\n return null\n }\n return new XMLSerializer().serializeToString(svg)\n }\n\n function updateSvgExport() {\n const svg = svgRef.value?.querySelector('svg')\n const serialized = serializeSvg()\n if (!svg || !serialized) {\n return\n }\n\n const viewBox = svg.viewBox?.baseVal\n svgWidth.value =\n viewBox?.width || svg.getBoundingClientRect().width || 1200\n svgHeight.value =\n viewBox?.height || svg.getBoundingClientRect().height || 800\n svgDataUrl.value = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(serialized)}`\n }\n\n watch(\n () => props.svg,\n () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n },\n )\n\n onMounted(async () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n await init()\n })\n</script>\n\n<template>\n <div\n class=\"pk-svg-viewer\"\n :class=\"{\n 'pk-svg-viewer--dragging': isDragging,\n }\">\n <!-- Hidden Gallery for Lightbox -->\n <div ref=\"galleryRef\" class=\"hidden\">\n <a\n v-if=\"svgDataUrl\"\n :href=\"svgDataUrl\"\n :data-pswp-src=\"svgDataUrl\"\n :data-pswp-width=\"svgWidth\"\n :data-pswp-height=\"svgHeight\"\n :title=\"title\" />\n </div>\n\n <!-- SVG Stage -->\n <div\n class=\"pk-svg-viewer__stage\"\n @mousedown=\"onMouseDown\"\n @mousemove=\"onMouseMove\"\n @mouseup=\"onMouseUp\"\n @mouseleave=\"onMouseUp\">\n <div\n ref=\"svgRef\"\n :style=\"svgStyle\"\n class=\"pk-svg-viewer__content\" />\n </div>\n\n <!-- Floating Toolbar -->\n <div class=\"pk-svg-viewer__toolbar\">\n <VvButtonGroup\n modifiers=\"compact\"\n class=\"bg-surface-1 shadow-md overflow-hidden\">\n <transition name=\"fade\">\n <VvButton\n key=\"reset\"\n modifiers=\"action-small\"\n :disabled=\"\n scale === 1 && translateX === 0 && translateY === 0\n \"\n icon=\"ri:aspect-ratio-line\"\n :title=\"$t('action.reset')\"\n @click=\"reset\" />\n </transition>\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:zoom-out-line\"\n :title=\"$t('action.zoomOut')\"\n @click=\"zoomOut\" />\n <VvButton\n modifiers=\"action-small\"\n icon=\"ri:zoom-in-line\"\n :title=\"$t('action.zoomIn')\"\n @click=\"zoomIn\" />\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:fullscreen-line\"\n :title=\"$t('action.expand')\"\n @click=\"openLightbox\" />\n </VvButtonGroup>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-svg-viewer {\n position: relative;\n overflow: hidden;\n background-color: var(--color-surface-2);\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n\n &__content {\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n transition: transform 0.3s ease-out;\n transform-origin: center center;\n\n svg {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n width: auto;\n }\n }\n\n &__toolbar {\n position: absolute;\n top: var(--spacing-8);\n right: var(--spacing-8);\n z-index: var(--z-dropdown);\n opacity: 0;\n transition: var(--transition-opacity);\n }\n\n &__stage {\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n }\n\n &:hover {\n .pk-svg-viewer__toolbar {\n opacity: 1;\n }\n }\n\n &--dragging {\n .pk-svg-viewer__toolbar {\n opacity: 0.5 !important;\n pointer-events: none;\n\n & * {\n pointer-events: none;\n }\n }\n\n .pk-svg-viewer__content {\n cursor: grabbing !important;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { ref, onMounted, computed, watch } from 'vue'\n import { useLightbox } from './composables/useLightbox'\n import { useI18n } from 'vue-i18n'\n\n const props = defineProps<{\n svg?: string\n title?: string\n }>()\n\n const { t: $t } = useI18n()\n\n const svgRef = ref<HTMLDivElement | null>(null)\n const galleryRef = ref<HTMLElement>()\n\n const scale = ref(1)\n const translateX = ref(0)\n const translateY = ref(0)\n const startX = ref(0)\n const startY = ref(0)\n\n // PhotoSwipe integration\n const svgDataUrl = ref('')\n const svgWidth = ref(0)\n const svgHeight = ref(0)\n\n const { lightbox, init } = useLightbox({\n gallery: galleryRef,\n downloadable: true,\n openInNewTab: false,\n })\n\n const svgStyle = computed(() => ({\n transform: `translate(${translateX.value}px, ${translateY.value}px) scale(${scale.value})`,\n }))\n\n const zoomIn = () => {\n scale.value = Math.min(scale.value * 1.2, 10)\n }\n\n const zoomOut = () => {\n scale.value = Math.max(scale.value / 1.2, 0.1)\n }\n\n const reset = () => {\n scale.value = 1\n translateX.value = 0\n translateY.value = 0\n }\n\n const openLightbox = () => {\n if (svgDataUrl.value) {\n lightbox.value?.loadAndOpen(0)\n }\n }\n\n const isDragging = ref(false)\n\n // Pan logic\n const onMouseDown = (e: MouseEvent) => {\n e.preventDefault()\n isDragging.value = true\n startX.value = e.clientX - translateX.value\n startY.value = e.clientY - translateY.value\n }\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isDragging.value) {\n return\n }\n translateX.value = e.clientX - startX.value\n translateY.value = e.clientY - startY.value\n }\n\n const onMouseUp = () => {\n isDragging.value = false\n }\n\n function serializeSvg(): string | null {\n const svg = svgRef.value?.querySelector('svg')\n if (!svg) {\n return null\n }\n return new XMLSerializer().serializeToString(svg)\n }\n\n function updateSvgExport() {\n const svg = svgRef.value?.querySelector('svg')\n const serialized = serializeSvg()\n if (!svg || !serialized) {\n return\n }\n\n const viewBox = svg.viewBox?.baseVal\n svgWidth.value =\n viewBox?.width || svg.getBoundingClientRect().width || 1200\n svgHeight.value =\n viewBox?.height || svg.getBoundingClientRect().height || 800\n svgDataUrl.value = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(serialized)}`\n }\n\n watch(\n () => props.svg,\n () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n },\n )\n\n onMounted(async () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n await init()\n })\n</script>\n\n<template>\n <div\n class=\"pk-svg-viewer\"\n :class=\"{\n 'pk-svg-viewer--dragging': isDragging,\n }\">\n <!-- Hidden Gallery for Lightbox -->\n <div ref=\"galleryRef\" class=\"hidden\">\n <a\n v-if=\"svgDataUrl\"\n :href=\"svgDataUrl\"\n :data-pswp-src=\"svgDataUrl\"\n :data-pswp-width=\"svgWidth\"\n :data-pswp-height=\"svgHeight\"\n :title=\"title\" />\n </div>\n\n <!-- SVG Stage -->\n <div\n class=\"pk-svg-viewer__stage\"\n @mousedown=\"onMouseDown\"\n @mousemove=\"onMouseMove\"\n @mouseup=\"onMouseUp\"\n @mouseleave=\"onMouseUp\">\n <div\n ref=\"svgRef\"\n :style=\"svgStyle\"\n class=\"pk-svg-viewer__content\" />\n </div>\n\n <!-- Floating Toolbar -->\n <div class=\"pk-svg-viewer__toolbar\">\n <VvButtonGroup\n modifiers=\"compact\"\n class=\"bg-surface-1 shadow-md overflow-hidden\">\n <transition name=\"fade\">\n <VvButton\n key=\"reset\"\n modifiers=\"action-small\"\n :disabled=\"\n scale === 1 && translateX === 0 && translateY === 0\n \"\n icon=\"ri:aspect-ratio-line\"\n :title=\"$t('action.reset')\"\n @click=\"reset\" />\n </transition>\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:zoom-out-line\"\n :title=\"$t('action.zoomOut')\"\n @click=\"zoomOut\" />\n <VvButton\n modifiers=\"action-small\"\n icon=\"ri:zoom-in-line\"\n :title=\"$t('action.zoomIn')\"\n @click=\"zoomIn\" />\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:fullscreen-line\"\n :title=\"$t('action.expand')\"\n @click=\"openLightbox\" />\n </VvButtonGroup>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-svg-viewer {\n position: relative;\n overflow: hidden;\n background-color: var(--color-surface-2);\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n\n &__content {\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n transition: transform 0.3s ease-out;\n transform-origin: center center;\n\n svg {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n width: auto;\n }\n }\n\n &__toolbar {\n position: absolute;\n top: var(--spacing-8);\n right: var(--spacing-8);\n z-index: var(--z-dropdown);\n opacity: 0;\n transition: var(--transition-opacity);\n }\n\n &__stage {\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n }\n\n &:hover {\n .pk-svg-viewer__toolbar {\n opacity: 1;\n }\n }\n\n &--dragging {\n .pk-svg-viewer__toolbar {\n opacity: 0.5 !important;\n pointer-events: none;\n\n & * {\n pointer-events: none;\n }\n }\n\n .pk-svg-viewer__content {\n cursor: grabbing !important;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { ref, onMounted, computed, watch } from 'vue'\n import { useLightbox } from './composables/useLightbox'\n import { useI18n } from 'vue-i18n'\n\n const props = defineProps<{\n svg?: string\n title?: string\n }>()\n\n const { t: $t } = useI18n()\n\n const svgRef = ref<HTMLDivElement | null>(null)\n const galleryRef = ref<HTMLElement>()\n\n const scale = ref(1)\n const translateX = ref(0)\n const translateY = ref(0)\n const startX = ref(0)\n const startY = ref(0)\n\n // PhotoSwipe integration\n const svgDataUrl = ref('')\n const svgWidth = ref(0)\n const svgHeight = ref(0)\n\n const { lightbox, init } = useLightbox({\n gallery: galleryRef,\n downloadable: true,\n openInNewTab: false,\n })\n\n const svgStyle = computed(() => ({\n transform: `translate(${translateX.value}px, ${translateY.value}px) scale(${scale.value})`,\n }))\n\n const zoomIn = () => {\n scale.value = Math.min(scale.value * 1.2, 10)\n }\n\n const zoomOut = () => {\n scale.value = Math.max(scale.value / 1.2, 0.1)\n }\n\n const reset = () => {\n scale.value = 1\n translateX.value = 0\n translateY.value = 0\n }\n\n const openLightbox = () => {\n if (svgDataUrl.value) {\n lightbox.value?.loadAndOpen(0)\n }\n }\n\n const isDragging = ref(false)\n\n // Pan logic\n const onMouseDown = (e: MouseEvent) => {\n e.preventDefault()\n isDragging.value = true\n startX.value = e.clientX - translateX.value\n startY.value = e.clientY - translateY.value\n }\n\n const onMouseMove = (e: MouseEvent) => {\n if (!isDragging.value) {\n return\n }\n translateX.value = e.clientX - startX.value\n translateY.value = e.clientY - startY.value\n }\n\n const onMouseUp = () => {\n isDragging.value = false\n }\n\n function serializeSvg(): string | null {\n const svg = svgRef.value?.querySelector('svg')\n if (!svg) {\n return null\n }\n return new XMLSerializer().serializeToString(svg)\n }\n\n function updateSvgExport() {\n const svg = svgRef.value?.querySelector('svg')\n const serialized = serializeSvg()\n if (!svg || !serialized) {\n return\n }\n\n const viewBox = svg.viewBox?.baseVal\n svgWidth.value =\n viewBox?.width || svg.getBoundingClientRect().width || 1200\n svgHeight.value =\n viewBox?.height || svg.getBoundingClientRect().height || 800\n svgDataUrl.value = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(serialized)}`\n }\n\n watch(\n () => props.svg,\n () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n },\n )\n\n onMounted(async () => {\n if (props.svg && svgRef.value) {\n svgRef.value.innerHTML = props.svg\n updateSvgExport()\n }\n await init()\n })\n</script>\n\n<template>\n <div\n class=\"pk-svg-viewer\"\n :class=\"{\n 'pk-svg-viewer--dragging': isDragging,\n }\">\n <!-- Hidden Gallery for Lightbox -->\n <div ref=\"galleryRef\" class=\"hidden\">\n <a\n v-if=\"svgDataUrl\"\n :href=\"svgDataUrl\"\n :data-pswp-src=\"svgDataUrl\"\n :data-pswp-width=\"svgWidth\"\n :data-pswp-height=\"svgHeight\"\n :title=\"title\" />\n </div>\n\n <!-- SVG Stage -->\n <div\n class=\"pk-svg-viewer__stage\"\n @mousedown=\"onMouseDown\"\n @mousemove=\"onMouseMove\"\n @mouseup=\"onMouseUp\"\n @mouseleave=\"onMouseUp\">\n <div\n ref=\"svgRef\"\n :style=\"svgStyle\"\n class=\"pk-svg-viewer__content\" />\n </div>\n\n <!-- Floating Toolbar -->\n <div class=\"pk-svg-viewer__toolbar\">\n <VvButtonGroup\n modifiers=\"compact\"\n class=\"bg-surface-1 shadow-md overflow-hidden\">\n <transition name=\"fade\">\n <VvButton\n key=\"reset\"\n modifiers=\"action-small\"\n :disabled=\"\n scale === 1 && translateX === 0 && translateY === 0\n \"\n icon=\"ri:aspect-ratio-line\"\n :title=\"$t('action.reset')\"\n @click=\"reset\" />\n </transition>\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:zoom-out-line\"\n :title=\"$t('action.zoomOut')\"\n @click=\"zoomOut\" />\n <VvButton\n modifiers=\"action-small\"\n icon=\"ri:zoom-in-line\"\n :title=\"$t('action.zoomIn')\"\n @click=\"zoomIn\" />\n <VvButton\n v-if=\"svgDataUrl\"\n modifiers=\"action-small\"\n icon=\"ri:fullscreen-line\"\n :title=\"$t('action.expand')\"\n @click=\"openLightbox\" />\n </VvButtonGroup>\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-svg-viewer {\n position: relative;\n overflow: hidden;\n background-color: var(--color-surface-2);\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n\n &__content {\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n transition: transform 0.3s ease-out;\n transform-origin: center center;\n\n svg {\n max-width: 100%;\n max-height: 100%;\n height: auto;\n width: auto;\n }\n }\n\n &__toolbar {\n position: absolute;\n top: var(--spacing-8);\n right: var(--spacing-8);\n z-index: var(--z-dropdown);\n opacity: 0;\n transition: var(--transition-opacity);\n }\n\n &__stage {\n width: 100%;\n height: auto;\n display: flex;\n align-items: center;\n justify-content: center;\n user-select: none;\n }\n\n &:hover {\n .pk-svg-viewer__toolbar {\n opacity: 1;\n }\n }\n\n &--dragging {\n .pk-svg-viewer__toolbar {\n opacity: 0.5 !important;\n pointer-events: none;\n\n & * {\n pointer-events: none;\n }\n }\n\n .pk-svg-viewer__content {\n cursor: grabbing !important;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, onMounted, ref, watch } from 'vue'\n import { useClipboard } from '@vueuse/core'\n import { useI18n } from 'vue-i18n'\n import { toSnakeCase } from 'utils'\n import PkSvgViewer from '../PkSvgViewer.vue'\n\n const props = defineProps<{\n part: unknown\n isDark?: boolean\n }>()\n\n const { t: $t, te: $te } = useI18n({\n useScope: 'global',\n })\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n code: string\n title?: string\n caption?: string\n }\n }\n return part\n })\n\n const svgError = ref(false)\n\n // Serialized SVG content\n const svgContent = ref('')\n\n enum DiagramType {\n Sequence = 'sequenceDiagram',\n Class = 'classDiagram',\n State = 'stateDiagram',\n ER = 'erDiagram',\n XYChart = 'xychart',\n Flowchart = 'flowchart',\n Graph = 'graph',\n }\n\n const diagramType = computed<DiagramType | undefined>(() => {\n const code = toolPart.value.input?.code?.trimStart()\n if (!code) {\n return undefined\n }\n const firstWord = code.match(/^[A-Za-z-]+/)?.[0]\n switch (firstWord) {\n case 'sequenceDiagram':\n return DiagramType.Sequence\n case 'classDiagram':\n return DiagramType.Class\n case 'stateDiagram':\n return DiagramType.State\n case 'erDiagram':\n return DiagramType.ER\n case 'xychart-beta':\n return DiagramType.XYChart\n case 'flowchart':\n return DiagramType.Flowchart\n case 'graph':\n return DiagramType.Graph\n default:\n return undefined\n }\n })\n\n const diagramTypeLabel = computed(() => {\n if (!diagramType.value) {\n return ''\n }\n return $te(`diagram.${diagramType.value}`)\n ? $t(`diagram.${diagramType.value}`)\n : diagramType.value\n })\n\n const diagramTypeIcon = computed(() => {\n switch (diagramType.value) {\n case DiagramType.Sequence:\n return 'ri:timeline-view'\n case DiagramType.Class:\n return 'ri:organization-chart'\n case DiagramType.State:\n return 'ri:organization-chart'\n case DiagramType.ER:\n return 'ri:organization-chart'\n case DiagramType.XYChart:\n return 'ri:line-chart-line'\n case DiagramType.Flowchart:\n return 'ri:flow-chart'\n case DiagramType.Graph:\n return 'ri:flow-chart'\n default:\n return 'ri:flow-chart'\n }\n })\n\n async function renderDiagram() {\n const code = toolPart.value.input?.code\n if (!code) {\n return\n }\n\n svgError.value = false\n try {\n const { renderMermaidSVG, THEMES } =\n await import('beautiful-mermaid')\n const theme = props.isDark\n ? THEMES['github-dark']\n : THEMES['github-light']\n svgContent.value = renderMermaidSVG(code, theme)\n } catch {\n svgError.value = true\n }\n }\n\n watch([() => toolPart.value.input?.code, () => props.isDark], renderDiagram)\n onMounted(async () => {\n await renderDiagram()\n })\n\n const downloadSvg = () => {\n if (!svgContent.value) {\n return\n }\n const blob = new Blob([svgContent.value], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = `${toSnakeCase(toolPart.value.input?.title || 'diagram')}.svg`\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n URL.revokeObjectURL(url)\n }\n\n const copyCode = () => {\n const code = toolPart.value.input?.code\n if (code) {\n copy(code)\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.code\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon :name=\"diagramTypeIcon\" class=\"text-16\" />\n <div class=\"flex flex-col items-start gap-2\">\n <strong class=\"font-bold\">{{\n diagramTypeLabel ?? $t('label.diagram')\n }}</strong>\n </div>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyCode\" />\n <VvButton\n v-if=\"svgContent\"\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :label=\"$t('action.download')\"\n @click=\"downloadSvg\" />\n </VvButtonGroup>\n </div>\n <div v-if=\"svgError\" class=\"text-12 text-danger py-8 px-sm\">\n {{ $t('message.diagramRenderError') }}\n </div>\n <PkSvgViewer\n v-else-if=\"svgContent\"\n class=\"pk-tool-show-diagram__stage\"\n :svg=\"svgContent\"\n :title=\"toolPart.input?.title\" />\n <div\n v-else\n class=\"pk-tool-show-diagram__stage flex justify-center items-center\">\n <VvIcon name=\"loading-loop\" class=\"w-24 h-24 text-word-5\" />\n </div>\n <div\n v-if=\"toolPart.input.caption\"\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-t border-surface-3 text-word-3\">\n {{ toolPart.input.caption }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-show-diagram {\n // Fixed stage height: the diagram renders lazily (async chunk +\n // dynamic mermaid import), so the loader and the rendered SVG must\n // occupy the same space or the chat scroll position jumps around.\n // The SVG scales to fit; zoom/pan and the lightbox cover the rest.\n &__stage {\n height: 384px;\n\n .pk-svg-viewer__stage,\n .pk-svg-viewer__content {\n height: 100%;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, onMounted, ref, watch } from 'vue'\n import { useClipboard } from '@vueuse/core'\n import { useI18n } from 'vue-i18n'\n import { toSnakeCase } from 'utils'\n import PkSvgViewer from '../PkSvgViewer.vue'\n\n const props = defineProps<{\n part: unknown\n isDark?: boolean\n }>()\n\n const { t: $t, te: $te } = useI18n({\n useScope: 'global',\n })\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n code: string\n title?: string\n caption?: string\n }\n }\n return part\n })\n\n const svgError = ref(false)\n\n // Serialized SVG content\n const svgContent = ref('')\n\n enum DiagramType {\n Sequence = 'sequenceDiagram',\n Class = 'classDiagram',\n State = 'stateDiagram',\n ER = 'erDiagram',\n XYChart = 'xychart',\n Flowchart = 'flowchart',\n Graph = 'graph',\n }\n\n const diagramType = computed<DiagramType | undefined>(() => {\n const code = toolPart.value.input?.code?.trimStart()\n if (!code) {\n return undefined\n }\n const firstWord = code.match(/^[A-Za-z-]+/)?.[0]\n switch (firstWord) {\n case 'sequenceDiagram':\n return DiagramType.Sequence\n case 'classDiagram':\n return DiagramType.Class\n case 'stateDiagram':\n return DiagramType.State\n case 'erDiagram':\n return DiagramType.ER\n case 'xychart-beta':\n return DiagramType.XYChart\n case 'flowchart':\n return DiagramType.Flowchart\n case 'graph':\n return DiagramType.Graph\n default:\n return undefined\n }\n })\n\n const diagramTypeLabel = computed(() => {\n if (!diagramType.value) {\n return ''\n }\n return $te(`diagram.${diagramType.value}`)\n ? $t(`diagram.${diagramType.value}`)\n : diagramType.value\n })\n\n const diagramTypeIcon = computed(() => {\n switch (diagramType.value) {\n case DiagramType.Sequence:\n return 'ri:timeline-view'\n case DiagramType.Class:\n return 'ri:organization-chart'\n case DiagramType.State:\n return 'ri:organization-chart'\n case DiagramType.ER:\n return 'ri:organization-chart'\n case DiagramType.XYChart:\n return 'ri:line-chart-line'\n case DiagramType.Flowchart:\n return 'ri:flow-chart'\n case DiagramType.Graph:\n return 'ri:flow-chart'\n default:\n return 'ri:flow-chart'\n }\n })\n\n async function renderDiagram() {\n const code = toolPart.value.input?.code\n if (!code) {\n return\n }\n\n svgError.value = false\n try {\n const { renderMermaidSVG, THEMES } =\n await import('beautiful-mermaid')\n const theme = props.isDark\n ? THEMES['github-dark']\n : THEMES['github-light']\n svgContent.value = renderMermaidSVG(code, theme)\n } catch {\n svgError.value = true\n }\n }\n\n watch([() => toolPart.value.input?.code, () => props.isDark], renderDiagram)\n onMounted(async () => {\n await renderDiagram()\n })\n\n const downloadSvg = () => {\n if (!svgContent.value) {\n return\n }\n const blob = new Blob([svgContent.value], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = `${toSnakeCase(toolPart.value.input?.title || 'diagram')}.svg`\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n URL.revokeObjectURL(url)\n }\n\n const copyCode = () => {\n const code = toolPart.value.input?.code\n if (code) {\n copy(code)\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.code\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon :name=\"diagramTypeIcon\" class=\"text-16\" />\n <div class=\"flex flex-col items-start gap-2\">\n <strong class=\"font-bold\">{{\n diagramTypeLabel ?? $t('label.diagram')\n }}</strong>\n </div>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyCode\" />\n <VvButton\n v-if=\"svgContent\"\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :label=\"$t('action.download')\"\n @click=\"downloadSvg\" />\n </VvButtonGroup>\n </div>\n <div v-if=\"svgError\" class=\"text-12 text-danger py-8 px-sm\">\n {{ $t('message.diagramRenderError') }}\n </div>\n <PkSvgViewer\n v-else-if=\"svgContent\"\n class=\"pk-tool-show-diagram__stage\"\n :svg=\"svgContent\"\n :title=\"toolPart.input?.title\" />\n <div\n v-else\n class=\"pk-tool-show-diagram__stage flex justify-center items-center\">\n <VvIcon name=\"loading-loop\" class=\"w-24 h-24 text-word-5\" />\n </div>\n <div\n v-if=\"toolPart.input.caption\"\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-t border-surface-3 text-word-3\">\n {{ toolPart.input.caption }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-show-diagram {\n // Fixed stage height: the diagram renders lazily (async chunk +\n // dynamic mermaid import), so the loader and the rendered SVG must\n // occupy the same space or the chat scroll position jumps around.\n // The SVG scales to fit; zoom/pan and the lightbox cover the rest.\n &__stage {\n height: 384px;\n\n .pk-svg-viewer__stage,\n .pk-svg-viewer__content {\n height: 100%;\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, onMounted, ref, watch } from 'vue'\n import { useClipboard } from '@vueuse/core'\n import { useI18n } from 'vue-i18n'\n import { toSnakeCase } from 'utils'\n import PkSvgViewer from '../PkSvgViewer.vue'\n\n const props = defineProps<{\n part: unknown\n isDark?: boolean\n }>()\n\n const { t: $t, te: $te } = useI18n({\n useScope: 'global',\n })\n\n const { copy, copied } = useClipboard()\n\n const toolPart = computed(() => {\n const part = props.part as {\n input?: {\n code: string\n title?: string\n caption?: string\n }\n }\n return part\n })\n\n const svgError = ref(false)\n\n // Serialized SVG content\n const svgContent = ref('')\n\n enum DiagramType {\n Sequence = 'sequenceDiagram',\n Class = 'classDiagram',\n State = 'stateDiagram',\n ER = 'erDiagram',\n XYChart = 'xychart',\n Flowchart = 'flowchart',\n Graph = 'graph',\n }\n\n const diagramType = computed<DiagramType | undefined>(() => {\n const code = toolPart.value.input?.code?.trimStart()\n if (!code) {\n return undefined\n }\n const firstWord = code.match(/^[A-Za-z-]+/)?.[0]\n switch (firstWord) {\n case 'sequenceDiagram':\n return DiagramType.Sequence\n case 'classDiagram':\n return DiagramType.Class\n case 'stateDiagram':\n return DiagramType.State\n case 'erDiagram':\n return DiagramType.ER\n case 'xychart-beta':\n return DiagramType.XYChart\n case 'flowchart':\n return DiagramType.Flowchart\n case 'graph':\n return DiagramType.Graph\n default:\n return undefined\n }\n })\n\n const diagramTypeLabel = computed(() => {\n if (!diagramType.value) {\n return ''\n }\n return $te(`diagram.${diagramType.value}`)\n ? $t(`diagram.${diagramType.value}`)\n : diagramType.value\n })\n\n const diagramTypeIcon = computed(() => {\n switch (diagramType.value) {\n case DiagramType.Sequence:\n return 'ri:timeline-view'\n case DiagramType.Class:\n return 'ri:organization-chart'\n case DiagramType.State:\n return 'ri:organization-chart'\n case DiagramType.ER:\n return 'ri:organization-chart'\n case DiagramType.XYChart:\n return 'ri:line-chart-line'\n case DiagramType.Flowchart:\n return 'ri:flow-chart'\n case DiagramType.Graph:\n return 'ri:flow-chart'\n default:\n return 'ri:flow-chart'\n }\n })\n\n async function renderDiagram() {\n const code = toolPart.value.input?.code\n if (!code) {\n return\n }\n\n svgError.value = false\n try {\n const { renderMermaidSVG, THEMES } =\n await import('beautiful-mermaid')\n const theme = props.isDark\n ? THEMES['github-dark']\n : THEMES['github-light']\n svgContent.value = renderMermaidSVG(code, theme)\n } catch {\n svgError.value = true\n }\n }\n\n watch([() => toolPart.value.input?.code, () => props.isDark], renderDiagram)\n onMounted(async () => {\n await renderDiagram()\n })\n\n const downloadSvg = () => {\n if (!svgContent.value) {\n return\n }\n const blob = new Blob([svgContent.value], {\n type: 'image/svg+xml;charset=utf-8',\n })\n const url = URL.createObjectURL(blob)\n const anchor = document.createElement('a')\n anchor.href = url\n anchor.download = `${toSnakeCase(toolPart.value.input?.title || 'diagram')}.svg`\n document.body.appendChild(anchor)\n anchor.click()\n document.body.removeChild(anchor)\n URL.revokeObjectURL(url)\n }\n\n const copyCode = () => {\n const code = toolPart.value.input?.code\n if (code) {\n copy(code)\n }\n }\n</script>\n\n<template>\n <div\n v-if=\"toolPart?.input?.code\"\n class=\"border border-surface-3 rounded-xl w-full overflow-hidden\">\n <div\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-b border-surface-3 text-word-3 flex items-center gap-8\">\n <VvIcon :name=\"diagramTypeIcon\" class=\"text-16\" />\n <div class=\"flex flex-col items-start gap-2\">\n <strong class=\"font-bold\">{{\n diagramTypeLabel ?? $t('label.diagram')\n }}</strong>\n </div>\n <VvButtonGroup modifiers=\"compact\" class=\"ml-auto shrink-0\">\n <VvButton\n modifiers=\"action-quiet-small\"\n :icon=\"copied ? 'ri:check-line' : 'ri:file-copy-line'\"\n :label=\"copied ? $t('action.copied') : $t('action.copy')\"\n @click=\"copyCode\" />\n <VvButton\n v-if=\"svgContent\"\n modifiers=\"action-quiet-small\"\n icon=\"ri:download-line\"\n :label=\"$t('action.download')\"\n @click=\"downloadSvg\" />\n </VvButtonGroup>\n </div>\n <div v-if=\"svgError\" class=\"text-12 text-danger py-8 px-sm\">\n {{ $t('message.diagramRenderError') }}\n </div>\n <PkSvgViewer\n v-else-if=\"svgContent\"\n class=\"pk-tool-show-diagram__stage\"\n :svg=\"svgContent\"\n :title=\"toolPart.input?.title\" />\n <div\n v-else\n class=\"pk-tool-show-diagram__stage flex justify-center items-center\">\n <VvIcon name=\"loading-loop\" class=\"w-24 h-24 text-word-5\" />\n </div>\n <div\n v-if=\"toolPart.input.caption\"\n class=\"px-sm py-6 bg-surface-1 min-h-40 text-12 border-t border-surface-3 text-word-3\">\n {{ toolPart.input.caption }}\n </div>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-tool-show-diagram {\n // Fixed stage height: the diagram renders lazily (async chunk +\n // dynamic mermaid import), so the loader and the rendered SVG must\n // occupy the same space or the chat scroll position jumps around.\n // The SVG scales to fit; zoom/pan and the lightbox cover the rest.\n &__stage {\n height: 384px;\n\n .pk-svg-viewer__stage,\n .pk-svg-viewer__content {\n height: 100%;\n }\n }\n }\n</style>\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { $ as e, C as t, Ct as n, L as r, O as i, T as a, Tt as o, b as s, bt as c, h as l, it as u, m as d, v as f, x as p, xt as m } from "./vue.runtime.esm-bundler-B-NVlZCY.js";
2
2
  import { i as h } from "./dist-Ce9Hi58x.js";
3
- import { a as g, d as _, r as v, t as y, u as b } from "./index.es-B9zAw2XU.js";
3
+ import { a as g, d as _, r as v, t as y, u as b } from "./index.es-D_E1Gj_U.js";
4
4
  import { n as x } from "./useShortUrlResolver-Ddb9IUei.js";
5
5
  //#region ../../packages/components/src/chat/PkToolShowEmail.vue?vue&type=script&setup=true&lang.ts
6
6
  i(), m(), u();
@@ -87,4 +87,4 @@ var S = { class: "border border-surface-3 rounded-xl w-full overflow-hidden bg-s
87
87
  //#endregion
88
88
  export { j as default };
89
89
 
90
- //# sourceMappingURL=PkToolShowEmail-BM16pMjW.js.map
90
+ //# sourceMappingURL=PkToolShowEmail-AWhVo3l3.js.map