comfyui-frontend-package 1.38.5__py3-none-any.whl → 1.38.6__py3-none-any.whl

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 (139) hide show
  1. comfyui_frontend_package/static/assets/{AboutPanel-CHse5rOA.js → AboutPanel-lkjGFasi.js} +2 -2
  2. comfyui_frontend_package/static/assets/{AboutPanel-CHse5rOA.js.map → AboutPanel-lkjGFasi.js.map} +1 -1
  3. comfyui_frontend_package/static/assets/{AudioPreviewPlayer-CAa8V66L.js → AudioPreviewPlayer-BxCSKPl9.js} +2 -2
  4. comfyui_frontend_package/static/assets/{AudioPreviewPlayer-CAa8V66L.js.map → AudioPreviewPlayer-BxCSKPl9.js.map} +1 -1
  5. comfyui_frontend_package/static/assets/AudioPreviewPlayer-CkxKvcVf.js +1 -0
  6. comfyui_frontend_package/static/assets/{BaseViewTemplate-DA6zfigT.js → BaseViewTemplate-CjODF2hh.js} +2 -2
  7. comfyui_frontend_package/static/assets/{BaseViewTemplate-DA6zfigT.js.map → BaseViewTemplate-CjODF2hh.js.map} +1 -1
  8. comfyui_frontend_package/static/assets/{CloudAuthTimeoutView-9OPBS1hE.js → CloudAuthTimeoutView-D-QkjPNh.js} +2 -2
  9. comfyui_frontend_package/static/assets/{CloudAuthTimeoutView-9OPBS1hE.js.map → CloudAuthTimeoutView-D-QkjPNh.js.map} +1 -1
  10. comfyui_frontend_package/static/assets/{CloudBadge-BnLiAHDN.js → CloudBadge-B4nmLus2.js} +2 -2
  11. comfyui_frontend_package/static/assets/{CloudBadge-BnLiAHDN.js.map → CloudBadge-B4nmLus2.js.map} +1 -1
  12. comfyui_frontend_package/static/assets/{CloudForgotPasswordView-BqDR_C7K.js → CloudForgotPasswordView-DOEV9hGr.js} +2 -2
  13. comfyui_frontend_package/static/assets/{CloudForgotPasswordView-BqDR_C7K.js.map → CloudForgotPasswordView-DOEV9hGr.js.map} +1 -1
  14. comfyui_frontend_package/static/assets/{CloudLayoutView-vTrrVUOY.js → CloudLayoutView-ShKH6rRV.js} +2 -2
  15. comfyui_frontend_package/static/assets/{CloudLayoutView-vTrrVUOY.js.map → CloudLayoutView-ShKH6rRV.js.map} +1 -1
  16. comfyui_frontend_package/static/assets/{CloudLoginView-T17euJly.js → CloudLoginView-C3Te42U9.js} +2 -2
  17. comfyui_frontend_package/static/assets/{CloudLoginView-T17euJly.js.map → CloudLoginView-C3Te42U9.js.map} +1 -1
  18. comfyui_frontend_package/static/assets/CloudRunButtonWrapper-Cub7EB34.js +3 -0
  19. comfyui_frontend_package/static/assets/{CloudRunButtonWrapper-hQc4BNkX.js.map → CloudRunButtonWrapper-Cub7EB34.js.map} +1 -1
  20. comfyui_frontend_package/static/assets/{CloudSignupView-vEDby5k3.js → CloudSignupView-X2oiL3ZR.js} +2 -2
  21. comfyui_frontend_package/static/assets/{CloudSignupView-vEDby5k3.js.map → CloudSignupView-X2oiL3ZR.js.map} +1 -1
  22. comfyui_frontend_package/static/assets/{CloudSubscriptionRedirectView-DPyO745g.js → CloudSubscriptionRedirectView-UjNv8emo.js} +2 -2
  23. comfyui_frontend_package/static/assets/{CloudSubscriptionRedirectView-DPyO745g.js.map → CloudSubscriptionRedirectView-UjNv8emo.js.map} +1 -1
  24. comfyui_frontend_package/static/assets/{CloudSurveyView-CBtTd9Ru.js → CloudSurveyView-IaiucCTP.js} +2 -2
  25. comfyui_frontend_package/static/assets/{CloudSurveyView-CBtTd9Ru.js.map → CloudSurveyView-IaiucCTP.js.map} +1 -1
  26. comfyui_frontend_package/static/assets/ComfyQueueButton-BppnHbrl.js +1 -0
  27. comfyui_frontend_package/static/assets/{ComfyQueueButton-MZrp7wYJ.js → ComfyQueueButton-HjSIKZKO.js} +2 -2
  28. comfyui_frontend_package/static/assets/{ComfyQueueButton-MZrp7wYJ.js.map → ComfyQueueButton-HjSIKZKO.js.map} +1 -1
  29. comfyui_frontend_package/static/assets/{ExtensionPanel-CrWVGUtg.js → ExtensionPanel-Bzb9QtKj.js} +2 -2
  30. comfyui_frontend_package/static/assets/{ExtensionPanel-CrWVGUtg.js.map → ExtensionPanel-Bzb9QtKj.js.map} +1 -1
  31. comfyui_frontend_package/static/assets/{GlobalToast-BiCmpIvO.js → GlobalToast-BSCvu6Hw.js} +2 -2
  32. comfyui_frontend_package/static/assets/{GlobalToast-BiCmpIvO.js.map → GlobalToast-BSCvu6Hw.js.map} +1 -1
  33. comfyui_frontend_package/static/assets/{GraphView-BCkpNGgz.js → GraphView-gYVCtm1V.js} +5 -5
  34. comfyui_frontend_package/static/assets/GraphView-gYVCtm1V.js.map +1 -0
  35. comfyui_frontend_package/static/assets/{KeybindingPanel-CAXL5TlV.js → KeybindingPanel-DF-bG4iO.js} +2 -2
  36. comfyui_frontend_package/static/assets/{KeybindingPanel-CAXL5TlV.js.map → KeybindingPanel-DF-bG4iO.js.map} +1 -1
  37. comfyui_frontend_package/static/assets/{LegacyCreditsPanel-6vR8koQy.js → LegacyCreditsPanel-D-CboO8k.js} +2 -2
  38. comfyui_frontend_package/static/assets/{LegacyCreditsPanel-6vR8koQy.js.map → LegacyCreditsPanel-D-CboO8k.js.map} +1 -1
  39. comfyui_frontend_package/static/assets/Load3D-c9UwgGoI.js +1 -0
  40. comfyui_frontend_package/static/assets/{Load3D-ei1BUF9O.js → Load3D-vYr8M3jJ.js} +2 -2
  41. comfyui_frontend_package/static/assets/{Load3D-ei1BUF9O.js.map → Load3D-vYr8M3jJ.js.map} +1 -1
  42. comfyui_frontend_package/static/assets/{PanelTemplate-BjN5XNg2.js → PanelTemplate-BJda9e5J.js} +2 -2
  43. comfyui_frontend_package/static/assets/{PanelTemplate-BjN5XNg2.js.map → PanelTemplate-BJda9e5J.js.map} +1 -1
  44. comfyui_frontend_package/static/assets/{ServerConfigPanel-CxovH9Qk.js → ServerConfigPanel-VsC6xlZJ.js} +2 -2
  45. comfyui_frontend_package/static/assets/{ServerConfigPanel-CxovH9Qk.js.map → ServerConfigPanel-VsC6xlZJ.js.map} +1 -1
  46. comfyui_frontend_package/static/assets/{SubscribeButton-CTOQRkfg.js → SubscribeButton-DZBycfCA.js} +2 -2
  47. comfyui_frontend_package/static/assets/{SubscribeButton-CTOQRkfg.js.map → SubscribeButton-DZBycfCA.js.map} +1 -1
  48. comfyui_frontend_package/static/assets/{SubscribeToRun-DnXzV8y0.js → SubscribeToRun-4YolxBOL.js} +2 -2
  49. comfyui_frontend_package/static/assets/{SubscribeToRun-DnXzV8y0.js.map → SubscribeToRun-4YolxBOL.js.map} +1 -1
  50. comfyui_frontend_package/static/assets/{SubscriptionPanel-D9uv7z8f.js → SubscriptionPanel-B6txX4Vm.js} +2 -2
  51. comfyui_frontend_package/static/assets/{SubscriptionPanel-D9uv7z8f.js.map → SubscriptionPanel-B6txX4Vm.js.map} +1 -1
  52. comfyui_frontend_package/static/assets/{SubscriptionRequiredDialogContent--VmT16oc.js → SubscriptionRequiredDialogContent-COEF2VQ_.js} +2 -2
  53. comfyui_frontend_package/static/assets/{SubscriptionRequiredDialogContent--VmT16oc.js.map → SubscriptionRequiredDialogContent-COEF2VQ_.js.map} +1 -1
  54. comfyui_frontend_package/static/assets/{UserCheckView-spD3LyMu.js → UserCheckView-x-fkcYzc.js} +2 -2
  55. comfyui_frontend_package/static/assets/{UserCheckView-spD3LyMu.js.map → UserCheckView-x-fkcYzc.js.map} +1 -1
  56. comfyui_frontend_package/static/assets/{UserPanel-Su6NtJ5q.js → UserPanel-7N9QknQj.js} +2 -2
  57. comfyui_frontend_package/static/assets/{UserPanel-Su6NtJ5q.js.map → UserPanel-7N9QknQj.js.map} +1 -1
  58. comfyui_frontend_package/static/assets/{UserSelectView-C5LBOPcv.js → UserSelectView-BYjOkfSa.js} +2 -2
  59. comfyui_frontend_package/static/assets/{UserSelectView-C5LBOPcv.js.map → UserSelectView-BYjOkfSa.js.map} +1 -1
  60. comfyui_frontend_package/static/assets/{ValueControlPopover-BdlDzT8l.js → ValueControlPopover-BPAa35QG.js} +2 -2
  61. comfyui_frontend_package/static/assets/{ValueControlPopover-BdlDzT8l.js.map → ValueControlPopover-BPAa35QG.js.map} +1 -1
  62. comfyui_frontend_package/static/assets/{WidgetAudioUI-BDZxDx_r.js → WidgetAudioUI-Dw-r3Ews.js} +2 -2
  63. comfyui_frontend_package/static/assets/{WidgetAudioUI-BDZxDx_r.js.map → WidgetAudioUI-Dw-r3Ews.js.map} +1 -1
  64. comfyui_frontend_package/static/assets/{WidgetImageCrop-CYRW7t2Q.js → WidgetImageCrop-kERy9g5I.js} +2 -2
  65. comfyui_frontend_package/static/assets/{WidgetImageCrop-CYRW7t2Q.js.map → WidgetImageCrop-kERy9g5I.js.map} +1 -1
  66. comfyui_frontend_package/static/assets/{WidgetInputNumber-BOKO36G3.js → WidgetInputNumber-BaClCNAC.js} +1 -1
  67. comfyui_frontend_package/static/assets/WidgetInputNumber-DU_D0Fzy.js +3 -0
  68. comfyui_frontend_package/static/assets/WidgetInputNumber-DU_D0Fzy.js.map +1 -0
  69. comfyui_frontend_package/static/assets/{WidgetLegacy-Bslv9wZZ.js → WidgetLegacy-B4nipUM9.js} +1 -1
  70. comfyui_frontend_package/static/assets/{WidgetRecordAudio-Bzy8PIzN.js → WidgetRecordAudio-Nk8dH238.js} +2 -2
  71. comfyui_frontend_package/static/assets/{WidgetRecordAudio-Bzy8PIzN.js.map → WidgetRecordAudio-Nk8dH238.js.map} +1 -1
  72. comfyui_frontend_package/static/assets/WidgetSelect-DzZPpO_-.js +1 -0
  73. comfyui_frontend_package/static/assets/{WidgetSelect-zgrFVzHH.js → WidgetSelect-nSQrk_hd.js} +2 -2
  74. comfyui_frontend_package/static/assets/{WidgetSelect-zgrFVzHH.js.map → WidgetSelect-nSQrk_hd.js.map} +1 -1
  75. comfyui_frontend_package/static/assets/{WidgetWithControl-Dh2FWOiA.js → WidgetWithControl-Da6zUB5e.js} +3 -3
  76. comfyui_frontend_package/static/assets/{WidgetWithControl-Dh2FWOiA.js.map → WidgetWithControl-Da6zUB5e.js.map} +1 -1
  77. comfyui_frontend_package/static/assets/{api-CUAc7rDA.js → api-Dwq2LQIW.js} +4 -4
  78. comfyui_frontend_package/static/assets/api-Dwq2LQIW.js.map +1 -0
  79. comfyui_frontend_package/static/assets/{audioService-DvndbCi2.js → audioService-DvVaKhuU.js} +2 -2
  80. comfyui_frontend_package/static/assets/{audioService-DvndbCi2.js.map → audioService-DvVaKhuU.js.map} +1 -1
  81. comfyui_frontend_package/static/assets/{audioUtils-DpjpcKbH.js → audioUtils-DD4rUYVZ.js} +2 -2
  82. comfyui_frontend_package/static/assets/{audioUtils-DpjpcKbH.js.map → audioUtils-DD4rUYVZ.js.map} +1 -1
  83. comfyui_frontend_package/static/assets/{auth-B8ZZ0KKQ.js → auth-B9axG-yZ.js} +2 -2
  84. comfyui_frontend_package/static/assets/{auth-B8ZZ0KKQ.js.map → auth-B9axG-yZ.js.map} +1 -1
  85. comfyui_frontend_package/static/assets/auth-D74DTev8.js +1 -0
  86. comfyui_frontend_package/static/assets/{cloudBadges-C1a7fBky.js → cloudBadges-D5mGJbRy.js} +2 -2
  87. comfyui_frontend_package/static/assets/{cloudBadges-C1a7fBky.js.map → cloudBadges-D5mGJbRy.js.map} +1 -1
  88. comfyui_frontend_package/static/assets/{cloudFeedbackTopbarButton-DR0T8sWG.js → cloudFeedbackTopbarButton-RZUssOmb.js} +2 -2
  89. comfyui_frontend_package/static/assets/{cloudFeedbackTopbarButton-DR0T8sWG.js.map → cloudFeedbackTopbarButton-RZUssOmb.js.map} +1 -1
  90. comfyui_frontend_package/static/assets/{cloudRemoteConfig-DhMjC5TB.js → cloudRemoteConfig-F9J0iGyF.js} +2 -2
  91. comfyui_frontend_package/static/assets/{cloudRemoteConfig-DhMjC5TB.js.map → cloudRemoteConfig-F9J0iGyF.js.map} +1 -1
  92. comfyui_frontend_package/static/assets/{cloudSessionCookie-Duxk6ux1.js → cloudSessionCookie-MEORlqtg.js} +2 -2
  93. comfyui_frontend_package/static/assets/{cloudSessionCookie-Duxk6ux1.js.map → cloudSessionCookie-MEORlqtg.js.map} +1 -1
  94. comfyui_frontend_package/static/assets/{cloudSubscription-B8l6B9Nx.js → cloudSubscription-CuWNXKVx.js} +2 -2
  95. comfyui_frontend_package/static/assets/{cloudSubscription-B8l6B9Nx.js.map → cloudSubscription-CuWNXKVx.js.map} +1 -1
  96. comfyui_frontend_package/static/assets/{core-DBfeqMDR.js → core-IYu8XAIx.js} +4 -4
  97. comfyui_frontend_package/static/assets/{core-DBfeqMDR.js.map → core-IYu8XAIx.js.map} +1 -1
  98. comfyui_frontend_package/static/assets/{dialogService-BZ1FmjZL.js → dialogService-YG0RH337.js} +9 -9
  99. comfyui_frontend_package/static/assets/{dialogService-BZ1FmjZL.js.map → dialogService-YG0RH337.js.map} +1 -1
  100. comfyui_frontend_package/static/assets/firebaseAuthStore-DnNaPbuZ.js +1 -0
  101. comfyui_frontend_package/static/assets/{graphHasMissingNodes-C79Wi51S.js → graphHasMissingNodes-BhD1N6zI.js} +2 -2
  102. comfyui_frontend_package/static/assets/{graphHasMissingNodes-C79Wi51S.js.map → graphHasMissingNodes-BhD1N6zI.js.map} +1 -1
  103. comfyui_frontend_package/static/assets/{index-CGxJFSof.js → index-BMy3twho.js} +3 -3
  104. comfyui_frontend_package/static/assets/{index-CGxJFSof.js.map → index-BMy3twho.js.map} +1 -1
  105. comfyui_frontend_package/static/assets/{index-DNpOhRra.css → index-KMO9qFHH.css} +1 -1
  106. comfyui_frontend_package/static/assets/{keybindingService-B88NjeAU.js → keybindingService-CBLPjYHI.js} +2 -2
  107. comfyui_frontend_package/static/assets/{keybindingService-B88NjeAU.js.map → keybindingService-CBLPjYHI.js.map} +1 -1
  108. comfyui_frontend_package/static/assets/{releaseStore-x0vHjxrw.js → releaseStore-DDOxzkVb.js} +2 -2
  109. comfyui_frontend_package/static/assets/{releaseStore-x0vHjxrw.js.map → releaseStore-DDOxzkVb.js.map} +1 -1
  110. comfyui_frontend_package/static/assets/releaseStore-iVkqunL8.js +1 -0
  111. comfyui_frontend_package/static/assets/{subscriptionCheckoutUtil-B_OvUP2T.js → subscriptionCheckoutUtil-DswSOreM.js} +2 -2
  112. comfyui_frontend_package/static/assets/{subscriptionCheckoutUtil-B_OvUP2T.js.map → subscriptionCheckoutUtil-DswSOreM.js.map} +1 -1
  113. comfyui_frontend_package/static/assets/{useCurrentUser-BJcn2Vgo.js → useCurrentUser-NdaCJzIK.js} +1 -1
  114. comfyui_frontend_package/static/assets/{useErrorHandling-CI8_F4yx.js → useErrorHandling-Cfa5N_7c.js} +2 -2
  115. comfyui_frontend_package/static/assets/{useErrorHandling-CI8_F4yx.js.map → useErrorHandling-Cfa5N_7c.js.map} +1 -1
  116. comfyui_frontend_package/static/assets/{useSubscriptionDialog-Chxkdny5.js → useSubscriptionDialog-792qfEJ2.js} +3 -3
  117. comfyui_frontend_package/static/assets/{useSubscriptionDialog-Chxkdny5.js.map → useSubscriptionDialog-792qfEJ2.js.map} +1 -1
  118. comfyui_frontend_package/static/assets/useSubscriptionDialog-B-eGeK3j.js +1 -0
  119. comfyui_frontend_package/static/assets/{userStore-BkgQPjq6.js → userStore-BAS9m9W6.js} +2 -2
  120. comfyui_frontend_package/static/assets/{userStore-BkgQPjq6.js.map → userStore-BAS9m9W6.js.map} +1 -1
  121. comfyui_frontend_package/static/assets/vendor-three-BFcUNSs9.js.map +1 -1
  122. comfyui_frontend_package/static/index.html +1 -1
  123. {comfyui_frontend_package-1.38.5.dist-info → comfyui_frontend_package-1.38.6.dist-info}/METADATA +1 -1
  124. {comfyui_frontend_package-1.38.5.dist-info → comfyui_frontend_package-1.38.6.dist-info}/RECORD +126 -126
  125. comfyui_frontend_package/static/assets/AudioPreviewPlayer-BoEdyGI_.js +0 -1
  126. comfyui_frontend_package/static/assets/CloudRunButtonWrapper-hQc4BNkX.js +0 -3
  127. comfyui_frontend_package/static/assets/ComfyQueueButton-BbQnRThI.js +0 -1
  128. comfyui_frontend_package/static/assets/GraphView-BCkpNGgz.js.map +0 -1
  129. comfyui_frontend_package/static/assets/Load3D-DHBmC_AU.js +0 -1
  130. comfyui_frontend_package/static/assets/WidgetInputNumber-DGKypM5j.js +0 -3
  131. comfyui_frontend_package/static/assets/WidgetInputNumber-DGKypM5j.js.map +0 -1
  132. comfyui_frontend_package/static/assets/WidgetSelect-DsJGH12l.js +0 -1
  133. comfyui_frontend_package/static/assets/api-CUAc7rDA.js.map +0 -1
  134. comfyui_frontend_package/static/assets/auth-D3RiiqZ8.js +0 -1
  135. comfyui_frontend_package/static/assets/firebaseAuthStore-CZgxeMyf.js +0 -1
  136. comfyui_frontend_package/static/assets/releaseStore-CubqSv5t.js +0 -1
  137. comfyui_frontend_package/static/assets/useSubscriptionDialog-BzMzio2H.js +0 -1
  138. {comfyui_frontend_package-1.38.5.dist-info → comfyui_frontend_package-1.38.6.dist-info}/WHEEL +0 -0
  139. {comfyui_frontend_package-1.38.5.dist-info → comfyui_frontend_package-1.38.6.dist-info}/top_level.txt +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetRecordAudio-Bzy8PIzN.js","names":[],"sources":["../../src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioPlayback.ts","../../src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioRecorder.ts","../../src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioWaveform.ts","../../src/renderer/extensions/vueNodes/widgets/components/WidgetRecordAudio.vue","../../src/renderer/extensions/vueNodes/widgets/components/WidgetRecordAudio.vue"],"sourcesContent":["import { nextTick, ref } from 'vue'\nimport type { Ref } from 'vue'\n\ninterface AudioPlaybackOptions {\n onPlaybackEnded?: () => void\n onMetadataLoaded?: (duration: number) => void\n}\n\nexport function useAudioPlayback(\n audioRef: Ref<HTMLAudioElement | undefined>,\n options: AudioPlaybackOptions = {}\n) {\n const isPlaying = ref(false)\n const audioElementKey = ref(0)\n const playbackTimerInterval = ref<ReturnType<typeof setInterval> | null>(null)\n\n async function play() {\n if (!audioRef.value) return false\n\n try {\n await audioRef.value.play()\n isPlaying.value = true\n return true\n } catch (error) {\n console.warn('Audio playback failed:', error)\n isPlaying.value = false\n return false\n }\n }\n\n function stop() {\n if (audioRef.value) {\n audioRef.value.pause()\n audioRef.value.currentTime = 0\n }\n isPlaying.value = false\n if (options.onPlaybackEnded) {\n options.onPlaybackEnded()\n }\n }\n\n function onPlaybackEnded() {\n isPlaying.value = false\n if (options.onPlaybackEnded) {\n options.onPlaybackEnded()\n }\n }\n\n function onMetadataLoaded() {\n if (audioRef.value?.duration && options.onMetadataLoaded) {\n options.onMetadataLoaded(audioRef.value.duration)\n }\n }\n\n async function resetAudioElement() {\n audioElementKey.value += 1\n await nextTick()\n }\n\n function getCurrentTime() {\n return audioRef.value?.currentTime || 0\n }\n\n function getDuration() {\n return audioRef.value?.duration || 0\n }\n\n return {\n isPlaying,\n audioElementKey,\n play,\n stop,\n onPlaybackEnded,\n onMetadataLoaded,\n resetAudioElement,\n getCurrentTime,\n getDuration,\n playbackTimerInterval\n }\n}\n","import { MediaRecorder as ExtendableMediaRecorder } from 'extendable-media-recorder'\nimport { onUnmounted, ref } from 'vue'\n\nimport { useAudioService } from '@/services/audioService'\n\ninterface AudioRecorderOptions {\n onRecordingComplete?: (audioBlob: Blob) => Promise<void>\n onError?: (error: Error) => void\n}\n\nexport function useAudioRecorder(options: AudioRecorderOptions = {}) {\n const isRecording = ref(false)\n const mediaRecorder = ref<MediaRecorder | null>(null)\n const audioChunks = ref<Blob[]>([])\n const stream = ref<MediaStream | null>(null)\n const recordedURL = ref<string | null>(null)\n\n async function startRecording() {\n try {\n // Clean up previous recording\n if (recordedURL.value?.startsWith('blob:')) {\n URL.revokeObjectURL(recordedURL.value)\n }\n\n // Initialize\n audioChunks.value = []\n recordedURL.value = null\n\n // Register wav encoder and get media stream\n await useAudioService().registerWavEncoder()\n stream.value = await navigator.mediaDevices.getUserMedia({ audio: true })\n\n // Create media recorder\n mediaRecorder.value = new ExtendableMediaRecorder(stream.value, {\n mimeType: 'audio/wav'\n }) as unknown as MediaRecorder\n\n mediaRecorder.value.ondataavailable = (e) => {\n audioChunks.value.push(e.data)\n }\n\n mediaRecorder.value.onstop = async () => {\n const blob = new Blob(audioChunks.value, { type: 'audio/wav' })\n\n // Create blob URL for preview\n if (recordedURL.value?.startsWith('blob:')) {\n URL.revokeObjectURL(recordedURL.value)\n }\n recordedURL.value = URL.createObjectURL(blob)\n\n // Notify completion\n if (options.onRecordingComplete) {\n await options.onRecordingComplete(blob)\n }\n\n cleanup()\n }\n\n // Start recording\n mediaRecorder.value.start(100)\n isRecording.value = true\n } catch (err) {\n if (options.onError) {\n options.onError(err as Error)\n }\n throw err\n }\n }\n\n function stopRecording() {\n if (mediaRecorder.value && mediaRecorder.value.state !== 'inactive') {\n mediaRecorder.value.stop()\n } else {\n cleanup()\n }\n }\n\n function cleanup() {\n isRecording.value = false\n\n if (stream.value) {\n stream.value.getTracks().forEach((track) => track.stop())\n stream.value = null\n }\n }\n\n function dispose() {\n stopRecording()\n if (recordedURL.value) {\n URL.revokeObjectURL(recordedURL.value)\n recordedURL.value = null\n }\n }\n\n onUnmounted(() => {\n dispose()\n })\n\n return {\n isRecording,\n recordedURL,\n mediaRecorder,\n startRecording,\n stopRecording,\n dispose\n }\n}\n","import { onUnmounted, ref } from 'vue'\nimport type { Ref } from 'vue'\n\ninterface WaveformBar {\n height: number\n}\n\ninterface AudioWaveformOptions {\n barCount?: number\n minHeight?: number\n maxHeight?: number\n}\n\nexport function useAudioWaveform(options: AudioWaveformOptions = {}) {\n const { barCount = 18, minHeight = 4, maxHeight = 32 } = options\n\n const waveformBars = ref<WaveformBar[]>(\n Array.from({ length: barCount }, () => ({ height: 16 }))\n )\n const audioContext = ref<AudioContext | null>(null)\n const analyser = ref<AnalyserNode | null>(null)\n const dataArray = ref<Uint8Array | null>(null)\n const animationId = ref<number | null>(null)\n const mediaElementSource = ref<MediaElementAudioSourceNode | null>(null)\n\n function initWaveform() {\n waveformBars.value = Array.from({ length: barCount }, () => ({\n height: Math.random() * (maxHeight - minHeight) + minHeight\n }))\n }\n\n function updateWaveform(isActive: Ref<boolean>) {\n if (!isActive.value) return\n\n if (analyser.value && dataArray.value) {\n updateWaveformFromAudio()\n } else {\n updateWaveformRandom()\n }\n\n animationId.value = requestAnimationFrame(() => updateWaveform(isActive))\n }\n\n function updateWaveformFromAudio() {\n if (!analyser.value || !dataArray.value) return\n\n analyser.value.getByteFrequencyData(\n dataArray.value as Uint8Array<ArrayBuffer>\n )\n const samplesPerBar = Math.floor(dataArray.value.length / barCount)\n\n waveformBars.value = waveformBars.value.map((_, i) => {\n let sum = 0\n for (let j = 0; j < samplesPerBar; j++) {\n sum += dataArray.value![i * samplesPerBar + j] || 0\n }\n const average = sum / samplesPerBar\n const normalizedHeight =\n (average / 255) * (maxHeight - minHeight) + minHeight\n return { height: normalizedHeight }\n })\n }\n\n function updateWaveformRandom() {\n waveformBars.value = waveformBars.value.map((bar) => ({\n height: Math.max(\n minHeight,\n Math.min(maxHeight, bar.height + (Math.random() - 0.5) * 4)\n )\n }))\n }\n\n async function setupAudioContext() {\n if (audioContext.value && audioContext.value.state !== 'closed') {\n await audioContext.value.close()\n }\n audioContext.value = null\n mediaElementSource.value = null\n }\n\n async function setupRecordingVisualization(stream: MediaStream) {\n audioContext.value = new window.AudioContext()\n analyser.value = audioContext.value.createAnalyser()\n const source = audioContext.value.createMediaStreamSource(stream)\n source.connect(analyser.value)\n\n analyser.value.fftSize = 256\n dataArray.value = new Uint8Array(analyser.value.frequencyBinCount)\n }\n\n async function setupPlaybackVisualization(audioElement: HTMLAudioElement) {\n if (audioContext.value && audioContext.value.state !== 'closed') {\n await audioContext.value.close()\n }\n\n mediaElementSource.value = null\n\n if (!audioElement) return false\n\n audioContext.value = new window.AudioContext()\n analyser.value = audioContext.value.createAnalyser()\n\n mediaElementSource.value =\n audioContext.value.createMediaElementSource(audioElement)\n\n mediaElementSource.value.connect(analyser.value)\n analyser.value.connect(audioContext.value.destination)\n\n analyser.value.fftSize = 256\n dataArray.value = new Uint8Array(analyser.value.frequencyBinCount)\n\n return true\n }\n\n function stopWaveform() {\n if (animationId.value) {\n cancelAnimationFrame(animationId.value)\n animationId.value = null\n }\n }\n\n function dispose() {\n stopWaveform()\n if (audioContext.value && audioContext.value.state !== 'closed') {\n void audioContext.value.close()\n }\n audioContext.value = null\n mediaElementSource.value = null\n }\n\n onUnmounted(() => {\n dispose()\n })\n\n return {\n waveformBars,\n initWaveform,\n updateWaveform,\n setupAudioContext,\n setupRecordingVisualization,\n setupPlaybackVisualization,\n stopWaveform,\n dispose\n }\n}\n","<template>\n <div class=\"relative\">\n <div class=\"mb-4\">\n <Button\n class=\"text-base-foreground w-full border-0 bg-secondary-background hover:bg-secondary-background-hover\"\n :disabled=\"isRecording || readonly\"\n @click=\"handleStartRecording\"\n >\n {{ t('g.startRecording', 'Start Recording') }}\n <i-lucide:mic class=\"ml-1\" />\n </Button>\n </div>\n <div\n v-if=\"isRecording || isPlaying || recordedURL\"\n class=\"flex h-14 w-full min-w-0 items-center gap-2 rounded-lg px-3 bg-node-component-surface text-text-secondary\"\n >\n <!-- Recording Status -->\n <div class=\"flex shrink-0 items-center gap-1\">\n <span class=\"text-xs\">\n {{\n isRecording\n ? t('g.listening', 'Listening...')\n : isPlaying\n ? t('g.playing', 'Playing...')\n : recordedURL\n ? t('g.ready', 'Ready')\n : ''\n }}\n </span>\n <span class=\"text-sm\">{{ formatTime(timer) }}</span>\n </div>\n\n <!-- Waveform Visualization -->\n <div class=\"flex h-8 min-w-0 flex-1 items-center gap-2 overflow-hidden\">\n <div\n v-for=\"(bar, index) in waveformBars\"\n :key=\"index\"\n class=\"max-h-8 min-h-1 w-0.75 rounded-[1.5px] bg-slate-100 transition-all duration-100\"\n :style=\"{ height: bar.height + 'px' }\"\n :title=\"`Bar ${index + 1}: ${bar.height}px`\"\n />\n </div>\n\n <!-- Control Button -->\n <button\n v-if=\"isRecording\"\n :title=\"t('g.stopRecording', 'Stop Recording')\"\n class=\"flex shrink-0 size-8 animate-pulse items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handleStopRecording\"\n >\n <div class=\"size-2.5 rounded-sm bg-danger-100\" />\n </button>\n\n <button\n v-else-if=\"!isRecording && recordedURL && !isPlaying\"\n :title=\"t('g.playRecording') || 'Play Recording'\"\n class=\"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handlePlayRecording\"\n >\n <i class=\"text-text-secondary icon-[lucide--play] size-4\" />\n </button>\n\n <button\n v-else-if=\"isPlaying\"\n :title=\"t('g.stopPlayback') || 'Stop Playback'\"\n class=\"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handleStopPlayback\"\n >\n <i class=\"text-text-secondary icon-[lucide--square] size-4\" />\n </button>\n </div>\n <audio\n v-if=\"recordedURL\"\n ref=\"audioRef\"\n :key=\"audioElementKey\"\n :src=\"recordedURL\"\n class=\"hidden\"\n @ended=\"playback.onPlaybackEnded\"\n @loadedmetadata=\"playback.onMetadataLoaded\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useIntervalFn } from '@vueuse/core'\nimport { Button } from 'primevue'\nimport { computed, onMounted, onUnmounted, ref } from 'vue'\n\nimport { t } from '@/i18n'\nimport type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'\nimport type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'\nimport { useToastStore } from '@/platform/updates/common/toastStore'\nimport { app } from '@/scripts/app'\nimport { useAudioService } from '@/services/audioService'\n\nimport { useAudioPlayback } from '../composables/audio/useAudioPlayback'\nimport { useAudioRecorder } from '../composables/audio/useAudioRecorder'\nimport { useAudioWaveform } from '../composables/audio/useAudioWaveform'\nimport { formatTime } from '../utils/audioUtils'\n\nconst props = defineProps<{\n readonly?: boolean\n nodeId: string\n}>()\n\n// Audio element ref\nconst audioRef = ref<HTMLAudioElement>()\n\n// Keep track of the last uploaded path as a backup\nlet lastUploadedPath = ''\n\n// Composables\nconst recorder = useAudioRecorder({\n onRecordingComplete: handleRecordingComplete,\n onError: () => {\n useToastStore().addAlert(\n t('g.micPermissionDenied') || 'Microphone permission denied'\n )\n }\n})\n\nconst waveform = useAudioWaveform({\n barCount: 18,\n minHeight: 4,\n maxHeight: 32\n})\n\nconst playback = useAudioPlayback(audioRef, {\n onPlaybackEnded: handlePlaybackEnded,\n onMetadataLoaded: (duration) => {\n if (!isPlaying.value && !isRecording.value) {\n timer.value = Math.floor(duration)\n }\n }\n})\n\n// Timer for recording\nconst timer = ref(0)\nconst { pause: pauseTimer, resume: resumeTimer } = useIntervalFn(\n () => {\n timer.value += 1\n },\n 1000,\n { immediate: false }\n)\n\n// Destructure for template access\nconst { isRecording, recordedURL } = recorder\nconst { waveformBars } = waveform\nconst { isPlaying, audioElementKey } = playback\n\n// Computed for waveform animation\nconst isWaveformActive = computed(() => isRecording.value || isPlaying.value)\n\nconst modelValue = defineModel<string>({ default: '' })\n\nconst litegraphNode = computed(() => {\n if (!props.nodeId || !app.canvas.graph) return null\n return app.canvas.graph.getNodeById(props.nodeId) as LGraphNode | null\n})\n\nasync function handleRecordingComplete(blob: Blob) {\n try {\n const path = await useAudioService().convertBlobToFileAndSubmit(blob)\n modelValue.value = path\n lastUploadedPath = path\n } catch (e) {\n useToastStore().addAlert('Failed to upload recorded audio')\n }\n}\n\nasync function handleStartRecording() {\n if (props.readonly) return\n\n try {\n await waveform.setupAudioContext()\n await recorder.startRecording()\n\n // Setup waveform visualization for recording\n if (recorder.mediaRecorder.value) {\n const stream = recorder.mediaRecorder.value.stream\n if (stream) {\n await waveform.setupRecordingVisualization(stream)\n }\n }\n\n // Start timer\n timer.value = 0\n resumeTimer()\n waveform.initWaveform()\n waveform.updateWaveform(isWaveformActive)\n } catch (err) {\n console.error('Failed to start recording:', err)\n }\n}\n\nfunction handleStopRecording() {\n recorder.stopRecording()\n pauseTimer()\n waveform.stopWaveform()\n}\n\nasync function handlePlayRecording() {\n if (!recordedURL.value) return\n\n // Reset timer\n timer.value = 0\n\n // Reset and setup audio element\n await playback.resetAudioElement()\n\n // Wait for audio element to be ready\n await new Promise((resolve) => setTimeout(resolve, 50))\n\n if (!audioRef.value) return\n\n // Setup waveform visualization for playback\n const setupSuccess = await waveform.setupPlaybackVisualization(audioRef.value)\n if (!setupSuccess) return\n\n // Start playback\n await playback.play()\n\n // Update waveform\n waveform.initWaveform()\n waveform.updateWaveform(isWaveformActive)\n\n // Update timer from audio current time\n const timerInterval = setInterval(() => {\n timer.value = Math.floor(playback.getCurrentTime())\n }, 100)\n\n // Store interval for cleanup\n playback.playbackTimerInterval.value = timerInterval\n}\n\nfunction handleStopPlayback() {\n playback.stop()\n handlePlaybackEnded()\n}\n\nfunction handlePlaybackEnded() {\n waveform.stopWaveform()\n\n // Clear playback timer interval\n if (playback.playbackTimerInterval.value !== null) {\n clearInterval(playback.playbackTimerInterval.value)\n playback.playbackTimerInterval.value = null\n }\n\n const duration = playback.getDuration()\n if (duration) {\n timer.value = Math.floor(duration)\n } else {\n timer.value = 0\n }\n}\n\n// Serialization function for workflow execution\nasync function serializeValue() {\n if (isRecording.value && recorder.mediaRecorder.value) {\n recorder.mediaRecorder.value.stop()\n\n await new Promise((resolve, reject) => {\n let attempts = 0\n const maxAttempts = 50 // 5 seconds max (50 * 100ms)\n const checkRecording = () => {\n if (!isRecording.value && modelValue.value) {\n resolve(undefined)\n } else if (++attempts >= maxAttempts) {\n reject(new Error('Recording serialization timeout after 5 seconds'))\n } else {\n setTimeout(checkRecording, 100)\n }\n }\n checkRecording()\n })\n }\n\n return modelValue.value || lastUploadedPath || ''\n}\n\nfunction registerWidgetSerialization() {\n const node = litegraphNode.value\n if (!node?.widgets) return\n const targetWidget = node.widgets.find((w: IBaseWidget) => w.name === 'audio')\n if (targetWidget) {\n targetWidget.serializeValue = serializeValue\n }\n}\n\nonMounted(() => {\n waveform.initWaveform()\n registerWidgetSerialization()\n})\n\nonUnmounted(() => {\n if (playback.playbackTimerInterval.value !== null) {\n clearInterval(playback.playbackTimerInterval.value)\n playback.playbackTimerInterval.value = null\n }\n})\n</script>\n","<template>\n <div class=\"relative\">\n <div class=\"mb-4\">\n <Button\n class=\"text-base-foreground w-full border-0 bg-secondary-background hover:bg-secondary-background-hover\"\n :disabled=\"isRecording || readonly\"\n @click=\"handleStartRecording\"\n >\n {{ t('g.startRecording', 'Start Recording') }}\n <i-lucide:mic class=\"ml-1\" />\n </Button>\n </div>\n <div\n v-if=\"isRecording || isPlaying || recordedURL\"\n class=\"flex h-14 w-full min-w-0 items-center gap-2 rounded-lg px-3 bg-node-component-surface text-text-secondary\"\n >\n <!-- Recording Status -->\n <div class=\"flex shrink-0 items-center gap-1\">\n <span class=\"text-xs\">\n {{\n isRecording\n ? t('g.listening', 'Listening...')\n : isPlaying\n ? t('g.playing', 'Playing...')\n : recordedURL\n ? t('g.ready', 'Ready')\n : ''\n }}\n </span>\n <span class=\"text-sm\">{{ formatTime(timer) }}</span>\n </div>\n\n <!-- Waveform Visualization -->\n <div class=\"flex h-8 min-w-0 flex-1 items-center gap-2 overflow-hidden\">\n <div\n v-for=\"(bar, index) in waveformBars\"\n :key=\"index\"\n class=\"max-h-8 min-h-1 w-0.75 rounded-[1.5px] bg-slate-100 transition-all duration-100\"\n :style=\"{ height: bar.height + 'px' }\"\n :title=\"`Bar ${index + 1}: ${bar.height}px`\"\n />\n </div>\n\n <!-- Control Button -->\n <button\n v-if=\"isRecording\"\n :title=\"t('g.stopRecording', 'Stop Recording')\"\n class=\"flex shrink-0 size-8 animate-pulse items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handleStopRecording\"\n >\n <div class=\"size-2.5 rounded-sm bg-danger-100\" />\n </button>\n\n <button\n v-else-if=\"!isRecording && recordedURL && !isPlaying\"\n :title=\"t('g.playRecording') || 'Play Recording'\"\n class=\"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handlePlayRecording\"\n >\n <i class=\"text-text-secondary icon-[lucide--play] size-4\" />\n </button>\n\n <button\n v-else-if=\"isPlaying\"\n :title=\"t('g.stopPlayback') || 'Stop Playback'\"\n class=\"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handleStopPlayback\"\n >\n <i class=\"text-text-secondary icon-[lucide--square] size-4\" />\n </button>\n </div>\n <audio\n v-if=\"recordedURL\"\n ref=\"audioRef\"\n :key=\"audioElementKey\"\n :src=\"recordedURL\"\n class=\"hidden\"\n @ended=\"playback.onPlaybackEnded\"\n @loadedmetadata=\"playback.onMetadataLoaded\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useIntervalFn } from '@vueuse/core'\nimport { Button } from 'primevue'\nimport { computed, onMounted, onUnmounted, ref } from 'vue'\n\nimport { t } from '@/i18n'\nimport type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'\nimport type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'\nimport { useToastStore } from '@/platform/updates/common/toastStore'\nimport { app } from '@/scripts/app'\nimport { useAudioService } from '@/services/audioService'\n\nimport { useAudioPlayback } from '../composables/audio/useAudioPlayback'\nimport { useAudioRecorder } from '../composables/audio/useAudioRecorder'\nimport { useAudioWaveform } from '../composables/audio/useAudioWaveform'\nimport { formatTime } from '../utils/audioUtils'\n\nconst props = defineProps<{\n readonly?: boolean\n nodeId: string\n}>()\n\n// Audio element ref\nconst audioRef = ref<HTMLAudioElement>()\n\n// Keep track of the last uploaded path as a backup\nlet lastUploadedPath = ''\n\n// Composables\nconst recorder = useAudioRecorder({\n onRecordingComplete: handleRecordingComplete,\n onError: () => {\n useToastStore().addAlert(\n t('g.micPermissionDenied') || 'Microphone permission denied'\n )\n }\n})\n\nconst waveform = useAudioWaveform({\n barCount: 18,\n minHeight: 4,\n maxHeight: 32\n})\n\nconst playback = useAudioPlayback(audioRef, {\n onPlaybackEnded: handlePlaybackEnded,\n onMetadataLoaded: (duration) => {\n if (!isPlaying.value && !isRecording.value) {\n timer.value = Math.floor(duration)\n }\n }\n})\n\n// Timer for recording\nconst timer = ref(0)\nconst { pause: pauseTimer, resume: resumeTimer } = useIntervalFn(\n () => {\n timer.value += 1\n },\n 1000,\n { immediate: false }\n)\n\n// Destructure for template access\nconst { isRecording, recordedURL } = recorder\nconst { waveformBars } = waveform\nconst { isPlaying, audioElementKey } = playback\n\n// Computed for waveform animation\nconst isWaveformActive = computed(() => isRecording.value || isPlaying.value)\n\nconst modelValue = defineModel<string>({ default: '' })\n\nconst litegraphNode = computed(() => {\n if (!props.nodeId || !app.canvas.graph) return null\n return app.canvas.graph.getNodeById(props.nodeId) as LGraphNode | null\n})\n\nasync function handleRecordingComplete(blob: Blob) {\n try {\n const path = await useAudioService().convertBlobToFileAndSubmit(blob)\n modelValue.value = path\n lastUploadedPath = path\n } catch (e) {\n useToastStore().addAlert('Failed to upload recorded audio')\n }\n}\n\nasync function handleStartRecording() {\n if (props.readonly) return\n\n try {\n await waveform.setupAudioContext()\n await recorder.startRecording()\n\n // Setup waveform visualization for recording\n if (recorder.mediaRecorder.value) {\n const stream = recorder.mediaRecorder.value.stream\n if (stream) {\n await waveform.setupRecordingVisualization(stream)\n }\n }\n\n // Start timer\n timer.value = 0\n resumeTimer()\n waveform.initWaveform()\n waveform.updateWaveform(isWaveformActive)\n } catch (err) {\n console.error('Failed to start recording:', err)\n }\n}\n\nfunction handleStopRecording() {\n recorder.stopRecording()\n pauseTimer()\n waveform.stopWaveform()\n}\n\nasync function handlePlayRecording() {\n if (!recordedURL.value) return\n\n // Reset timer\n timer.value = 0\n\n // Reset and setup audio element\n await playback.resetAudioElement()\n\n // Wait for audio element to be ready\n await new Promise((resolve) => setTimeout(resolve, 50))\n\n if (!audioRef.value) return\n\n // Setup waveform visualization for playback\n const setupSuccess = await waveform.setupPlaybackVisualization(audioRef.value)\n if (!setupSuccess) return\n\n // Start playback\n await playback.play()\n\n // Update waveform\n waveform.initWaveform()\n waveform.updateWaveform(isWaveformActive)\n\n // Update timer from audio current time\n const timerInterval = setInterval(() => {\n timer.value = Math.floor(playback.getCurrentTime())\n }, 100)\n\n // Store interval for cleanup\n playback.playbackTimerInterval.value = timerInterval\n}\n\nfunction handleStopPlayback() {\n playback.stop()\n handlePlaybackEnded()\n}\n\nfunction handlePlaybackEnded() {\n waveform.stopWaveform()\n\n // Clear playback timer interval\n if (playback.playbackTimerInterval.value !== null) {\n clearInterval(playback.playbackTimerInterval.value)\n playback.playbackTimerInterval.value = null\n }\n\n const duration = playback.getDuration()\n if (duration) {\n timer.value = Math.floor(duration)\n } else {\n timer.value = 0\n }\n}\n\n// Serialization function for workflow execution\nasync function serializeValue() {\n if (isRecording.value && recorder.mediaRecorder.value) {\n recorder.mediaRecorder.value.stop()\n\n await new Promise((resolve, reject) => {\n let attempts = 0\n const maxAttempts = 50 // 5 seconds max (50 * 100ms)\n const checkRecording = () => {\n if (!isRecording.value && modelValue.value) {\n resolve(undefined)\n } else if (++attempts >= maxAttempts) {\n reject(new Error('Recording serialization timeout after 5 seconds'))\n } else {\n setTimeout(checkRecording, 100)\n }\n }\n checkRecording()\n })\n }\n\n return modelValue.value || lastUploadedPath || ''\n}\n\nfunction registerWidgetSerialization() {\n const node = litegraphNode.value\n if (!node?.widgets) return\n const targetWidget = node.widgets.find((w: IBaseWidget) => w.name === 'audio')\n if (targetWidget) {\n targetWidget.serializeValue = serializeValue\n }\n}\n\nonMounted(() => {\n waveform.initWaveform()\n registerWidgetSerialization()\n})\n\nonUnmounted(() => {\n if (playback.playbackTimerInterval.value !== null) {\n clearInterval(playback.playbackTimerInterval.value)\n playback.playbackTimerInterval.value = null\n }\n})\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"WidgetRecordAudio-Nk8dH238.js","names":[],"sources":["../../src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioPlayback.ts","../../src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioRecorder.ts","../../src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioWaveform.ts","../../src/renderer/extensions/vueNodes/widgets/components/WidgetRecordAudio.vue","../../src/renderer/extensions/vueNodes/widgets/components/WidgetRecordAudio.vue"],"sourcesContent":["import { nextTick, ref } from 'vue'\nimport type { Ref } from 'vue'\n\ninterface AudioPlaybackOptions {\n onPlaybackEnded?: () => void\n onMetadataLoaded?: (duration: number) => void\n}\n\nexport function useAudioPlayback(\n audioRef: Ref<HTMLAudioElement | undefined>,\n options: AudioPlaybackOptions = {}\n) {\n const isPlaying = ref(false)\n const audioElementKey = ref(0)\n const playbackTimerInterval = ref<ReturnType<typeof setInterval> | null>(null)\n\n async function play() {\n if (!audioRef.value) return false\n\n try {\n await audioRef.value.play()\n isPlaying.value = true\n return true\n } catch (error) {\n console.warn('Audio playback failed:', error)\n isPlaying.value = false\n return false\n }\n }\n\n function stop() {\n if (audioRef.value) {\n audioRef.value.pause()\n audioRef.value.currentTime = 0\n }\n isPlaying.value = false\n if (options.onPlaybackEnded) {\n options.onPlaybackEnded()\n }\n }\n\n function onPlaybackEnded() {\n isPlaying.value = false\n if (options.onPlaybackEnded) {\n options.onPlaybackEnded()\n }\n }\n\n function onMetadataLoaded() {\n if (audioRef.value?.duration && options.onMetadataLoaded) {\n options.onMetadataLoaded(audioRef.value.duration)\n }\n }\n\n async function resetAudioElement() {\n audioElementKey.value += 1\n await nextTick()\n }\n\n function getCurrentTime() {\n return audioRef.value?.currentTime || 0\n }\n\n function getDuration() {\n return audioRef.value?.duration || 0\n }\n\n return {\n isPlaying,\n audioElementKey,\n play,\n stop,\n onPlaybackEnded,\n onMetadataLoaded,\n resetAudioElement,\n getCurrentTime,\n getDuration,\n playbackTimerInterval\n }\n}\n","import { MediaRecorder as ExtendableMediaRecorder } from 'extendable-media-recorder'\nimport { onUnmounted, ref } from 'vue'\n\nimport { useAudioService } from '@/services/audioService'\n\ninterface AudioRecorderOptions {\n onRecordingComplete?: (audioBlob: Blob) => Promise<void>\n onError?: (error: Error) => void\n}\n\nexport function useAudioRecorder(options: AudioRecorderOptions = {}) {\n const isRecording = ref(false)\n const mediaRecorder = ref<MediaRecorder | null>(null)\n const audioChunks = ref<Blob[]>([])\n const stream = ref<MediaStream | null>(null)\n const recordedURL = ref<string | null>(null)\n\n async function startRecording() {\n try {\n // Clean up previous recording\n if (recordedURL.value?.startsWith('blob:')) {\n URL.revokeObjectURL(recordedURL.value)\n }\n\n // Initialize\n audioChunks.value = []\n recordedURL.value = null\n\n // Register wav encoder and get media stream\n await useAudioService().registerWavEncoder()\n stream.value = await navigator.mediaDevices.getUserMedia({ audio: true })\n\n // Create media recorder\n mediaRecorder.value = new ExtendableMediaRecorder(stream.value, {\n mimeType: 'audio/wav'\n }) as unknown as MediaRecorder\n\n mediaRecorder.value.ondataavailable = (e) => {\n audioChunks.value.push(e.data)\n }\n\n mediaRecorder.value.onstop = async () => {\n const blob = new Blob(audioChunks.value, { type: 'audio/wav' })\n\n // Create blob URL for preview\n if (recordedURL.value?.startsWith('blob:')) {\n URL.revokeObjectURL(recordedURL.value)\n }\n recordedURL.value = URL.createObjectURL(blob)\n\n // Notify completion\n if (options.onRecordingComplete) {\n await options.onRecordingComplete(blob)\n }\n\n cleanup()\n }\n\n // Start recording\n mediaRecorder.value.start(100)\n isRecording.value = true\n } catch (err) {\n if (options.onError) {\n options.onError(err as Error)\n }\n throw err\n }\n }\n\n function stopRecording() {\n if (mediaRecorder.value && mediaRecorder.value.state !== 'inactive') {\n mediaRecorder.value.stop()\n } else {\n cleanup()\n }\n }\n\n function cleanup() {\n isRecording.value = false\n\n if (stream.value) {\n stream.value.getTracks().forEach((track) => track.stop())\n stream.value = null\n }\n }\n\n function dispose() {\n stopRecording()\n if (recordedURL.value) {\n URL.revokeObjectURL(recordedURL.value)\n recordedURL.value = null\n }\n }\n\n onUnmounted(() => {\n dispose()\n })\n\n return {\n isRecording,\n recordedURL,\n mediaRecorder,\n startRecording,\n stopRecording,\n dispose\n }\n}\n","import { onUnmounted, ref } from 'vue'\nimport type { Ref } from 'vue'\n\ninterface WaveformBar {\n height: number\n}\n\ninterface AudioWaveformOptions {\n barCount?: number\n minHeight?: number\n maxHeight?: number\n}\n\nexport function useAudioWaveform(options: AudioWaveformOptions = {}) {\n const { barCount = 18, minHeight = 4, maxHeight = 32 } = options\n\n const waveformBars = ref<WaveformBar[]>(\n Array.from({ length: barCount }, () => ({ height: 16 }))\n )\n const audioContext = ref<AudioContext | null>(null)\n const analyser = ref<AnalyserNode | null>(null)\n const dataArray = ref<Uint8Array | null>(null)\n const animationId = ref<number | null>(null)\n const mediaElementSource = ref<MediaElementAudioSourceNode | null>(null)\n\n function initWaveform() {\n waveformBars.value = Array.from({ length: barCount }, () => ({\n height: Math.random() * (maxHeight - minHeight) + minHeight\n }))\n }\n\n function updateWaveform(isActive: Ref<boolean>) {\n if (!isActive.value) return\n\n if (analyser.value && dataArray.value) {\n updateWaveformFromAudio()\n } else {\n updateWaveformRandom()\n }\n\n animationId.value = requestAnimationFrame(() => updateWaveform(isActive))\n }\n\n function updateWaveformFromAudio() {\n if (!analyser.value || !dataArray.value) return\n\n analyser.value.getByteFrequencyData(\n dataArray.value as Uint8Array<ArrayBuffer>\n )\n const samplesPerBar = Math.floor(dataArray.value.length / barCount)\n\n waveformBars.value = waveformBars.value.map((_, i) => {\n let sum = 0\n for (let j = 0; j < samplesPerBar; j++) {\n sum += dataArray.value![i * samplesPerBar + j] || 0\n }\n const average = sum / samplesPerBar\n const normalizedHeight =\n (average / 255) * (maxHeight - minHeight) + minHeight\n return { height: normalizedHeight }\n })\n }\n\n function updateWaveformRandom() {\n waveformBars.value = waveformBars.value.map((bar) => ({\n height: Math.max(\n minHeight,\n Math.min(maxHeight, bar.height + (Math.random() - 0.5) * 4)\n )\n }))\n }\n\n async function setupAudioContext() {\n if (audioContext.value && audioContext.value.state !== 'closed') {\n await audioContext.value.close()\n }\n audioContext.value = null\n mediaElementSource.value = null\n }\n\n async function setupRecordingVisualization(stream: MediaStream) {\n audioContext.value = new window.AudioContext()\n analyser.value = audioContext.value.createAnalyser()\n const source = audioContext.value.createMediaStreamSource(stream)\n source.connect(analyser.value)\n\n analyser.value.fftSize = 256\n dataArray.value = new Uint8Array(analyser.value.frequencyBinCount)\n }\n\n async function setupPlaybackVisualization(audioElement: HTMLAudioElement) {\n if (audioContext.value && audioContext.value.state !== 'closed') {\n await audioContext.value.close()\n }\n\n mediaElementSource.value = null\n\n if (!audioElement) return false\n\n audioContext.value = new window.AudioContext()\n analyser.value = audioContext.value.createAnalyser()\n\n mediaElementSource.value =\n audioContext.value.createMediaElementSource(audioElement)\n\n mediaElementSource.value.connect(analyser.value)\n analyser.value.connect(audioContext.value.destination)\n\n analyser.value.fftSize = 256\n dataArray.value = new Uint8Array(analyser.value.frequencyBinCount)\n\n return true\n }\n\n function stopWaveform() {\n if (animationId.value) {\n cancelAnimationFrame(animationId.value)\n animationId.value = null\n }\n }\n\n function dispose() {\n stopWaveform()\n if (audioContext.value && audioContext.value.state !== 'closed') {\n void audioContext.value.close()\n }\n audioContext.value = null\n mediaElementSource.value = null\n }\n\n onUnmounted(() => {\n dispose()\n })\n\n return {\n waveformBars,\n initWaveform,\n updateWaveform,\n setupAudioContext,\n setupRecordingVisualization,\n setupPlaybackVisualization,\n stopWaveform,\n dispose\n }\n}\n","<template>\n <div class=\"relative\">\n <div class=\"mb-4\">\n <Button\n class=\"text-base-foreground w-full border-0 bg-secondary-background hover:bg-secondary-background-hover\"\n :disabled=\"isRecording || readonly\"\n @click=\"handleStartRecording\"\n >\n {{ t('g.startRecording', 'Start Recording') }}\n <i-lucide:mic class=\"ml-1\" />\n </Button>\n </div>\n <div\n v-if=\"isRecording || isPlaying || recordedURL\"\n class=\"flex h-14 w-full min-w-0 items-center gap-2 rounded-lg px-3 bg-node-component-surface text-text-secondary\"\n >\n <!-- Recording Status -->\n <div class=\"flex shrink-0 items-center gap-1\">\n <span class=\"text-xs\">\n {{\n isRecording\n ? t('g.listening', 'Listening...')\n : isPlaying\n ? t('g.playing', 'Playing...')\n : recordedURL\n ? t('g.ready', 'Ready')\n : ''\n }}\n </span>\n <span class=\"text-sm\">{{ formatTime(timer) }}</span>\n </div>\n\n <!-- Waveform Visualization -->\n <div class=\"flex h-8 min-w-0 flex-1 items-center gap-2 overflow-hidden\">\n <div\n v-for=\"(bar, index) in waveformBars\"\n :key=\"index\"\n class=\"max-h-8 min-h-1 w-0.75 rounded-[1.5px] bg-slate-100 transition-all duration-100\"\n :style=\"{ height: bar.height + 'px' }\"\n :title=\"`Bar ${index + 1}: ${bar.height}px`\"\n />\n </div>\n\n <!-- Control Button -->\n <button\n v-if=\"isRecording\"\n :title=\"t('g.stopRecording', 'Stop Recording')\"\n class=\"flex shrink-0 size-8 animate-pulse items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handleStopRecording\"\n >\n <div class=\"size-2.5 rounded-sm bg-danger-100\" />\n </button>\n\n <button\n v-else-if=\"!isRecording && recordedURL && !isPlaying\"\n :title=\"t('g.playRecording') || 'Play Recording'\"\n class=\"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handlePlayRecording\"\n >\n <i class=\"text-text-secondary icon-[lucide--play] size-4\" />\n </button>\n\n <button\n v-else-if=\"isPlaying\"\n :title=\"t('g.stopPlayback') || 'Stop Playback'\"\n class=\"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handleStopPlayback\"\n >\n <i class=\"text-text-secondary icon-[lucide--square] size-4\" />\n </button>\n </div>\n <audio\n v-if=\"recordedURL\"\n ref=\"audioRef\"\n :key=\"audioElementKey\"\n :src=\"recordedURL\"\n class=\"hidden\"\n @ended=\"playback.onPlaybackEnded\"\n @loadedmetadata=\"playback.onMetadataLoaded\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useIntervalFn } from '@vueuse/core'\nimport { Button } from 'primevue'\nimport { computed, onMounted, onUnmounted, ref } from 'vue'\n\nimport { t } from '@/i18n'\nimport type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'\nimport type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'\nimport { useToastStore } from '@/platform/updates/common/toastStore'\nimport { app } from '@/scripts/app'\nimport { useAudioService } from '@/services/audioService'\n\nimport { useAudioPlayback } from '../composables/audio/useAudioPlayback'\nimport { useAudioRecorder } from '../composables/audio/useAudioRecorder'\nimport { useAudioWaveform } from '../composables/audio/useAudioWaveform'\nimport { formatTime } from '../utils/audioUtils'\n\nconst props = defineProps<{\n readonly?: boolean\n nodeId: string\n}>()\n\n// Audio element ref\nconst audioRef = ref<HTMLAudioElement>()\n\n// Keep track of the last uploaded path as a backup\nlet lastUploadedPath = ''\n\n// Composables\nconst recorder = useAudioRecorder({\n onRecordingComplete: handleRecordingComplete,\n onError: () => {\n useToastStore().addAlert(\n t('g.micPermissionDenied') || 'Microphone permission denied'\n )\n }\n})\n\nconst waveform = useAudioWaveform({\n barCount: 18,\n minHeight: 4,\n maxHeight: 32\n})\n\nconst playback = useAudioPlayback(audioRef, {\n onPlaybackEnded: handlePlaybackEnded,\n onMetadataLoaded: (duration) => {\n if (!isPlaying.value && !isRecording.value) {\n timer.value = Math.floor(duration)\n }\n }\n})\n\n// Timer for recording\nconst timer = ref(0)\nconst { pause: pauseTimer, resume: resumeTimer } = useIntervalFn(\n () => {\n timer.value += 1\n },\n 1000,\n { immediate: false }\n)\n\n// Destructure for template access\nconst { isRecording, recordedURL } = recorder\nconst { waveformBars } = waveform\nconst { isPlaying, audioElementKey } = playback\n\n// Computed for waveform animation\nconst isWaveformActive = computed(() => isRecording.value || isPlaying.value)\n\nconst modelValue = defineModel<string>({ default: '' })\n\nconst litegraphNode = computed(() => {\n if (!props.nodeId || !app.canvas.graph) return null\n return app.canvas.graph.getNodeById(props.nodeId) as LGraphNode | null\n})\n\nasync function handleRecordingComplete(blob: Blob) {\n try {\n const path = await useAudioService().convertBlobToFileAndSubmit(blob)\n modelValue.value = path\n lastUploadedPath = path\n } catch (e) {\n useToastStore().addAlert('Failed to upload recorded audio')\n }\n}\n\nasync function handleStartRecording() {\n if (props.readonly) return\n\n try {\n await waveform.setupAudioContext()\n await recorder.startRecording()\n\n // Setup waveform visualization for recording\n if (recorder.mediaRecorder.value) {\n const stream = recorder.mediaRecorder.value.stream\n if (stream) {\n await waveform.setupRecordingVisualization(stream)\n }\n }\n\n // Start timer\n timer.value = 0\n resumeTimer()\n waveform.initWaveform()\n waveform.updateWaveform(isWaveformActive)\n } catch (err) {\n console.error('Failed to start recording:', err)\n }\n}\n\nfunction handleStopRecording() {\n recorder.stopRecording()\n pauseTimer()\n waveform.stopWaveform()\n}\n\nasync function handlePlayRecording() {\n if (!recordedURL.value) return\n\n // Reset timer\n timer.value = 0\n\n // Reset and setup audio element\n await playback.resetAudioElement()\n\n // Wait for audio element to be ready\n await new Promise((resolve) => setTimeout(resolve, 50))\n\n if (!audioRef.value) return\n\n // Setup waveform visualization for playback\n const setupSuccess = await waveform.setupPlaybackVisualization(audioRef.value)\n if (!setupSuccess) return\n\n // Start playback\n await playback.play()\n\n // Update waveform\n waveform.initWaveform()\n waveform.updateWaveform(isWaveformActive)\n\n // Update timer from audio current time\n const timerInterval = setInterval(() => {\n timer.value = Math.floor(playback.getCurrentTime())\n }, 100)\n\n // Store interval for cleanup\n playback.playbackTimerInterval.value = timerInterval\n}\n\nfunction handleStopPlayback() {\n playback.stop()\n handlePlaybackEnded()\n}\n\nfunction handlePlaybackEnded() {\n waveform.stopWaveform()\n\n // Clear playback timer interval\n if (playback.playbackTimerInterval.value !== null) {\n clearInterval(playback.playbackTimerInterval.value)\n playback.playbackTimerInterval.value = null\n }\n\n const duration = playback.getDuration()\n if (duration) {\n timer.value = Math.floor(duration)\n } else {\n timer.value = 0\n }\n}\n\n// Serialization function for workflow execution\nasync function serializeValue() {\n if (isRecording.value && recorder.mediaRecorder.value) {\n recorder.mediaRecorder.value.stop()\n\n await new Promise((resolve, reject) => {\n let attempts = 0\n const maxAttempts = 50 // 5 seconds max (50 * 100ms)\n const checkRecording = () => {\n if (!isRecording.value && modelValue.value) {\n resolve(undefined)\n } else if (++attempts >= maxAttempts) {\n reject(new Error('Recording serialization timeout after 5 seconds'))\n } else {\n setTimeout(checkRecording, 100)\n }\n }\n checkRecording()\n })\n }\n\n return modelValue.value || lastUploadedPath || ''\n}\n\nfunction registerWidgetSerialization() {\n const node = litegraphNode.value\n if (!node?.widgets) return\n const targetWidget = node.widgets.find((w: IBaseWidget) => w.name === 'audio')\n if (targetWidget) {\n targetWidget.serializeValue = serializeValue\n }\n}\n\nonMounted(() => {\n waveform.initWaveform()\n registerWidgetSerialization()\n})\n\nonUnmounted(() => {\n if (playback.playbackTimerInterval.value !== null) {\n clearInterval(playback.playbackTimerInterval.value)\n playback.playbackTimerInterval.value = null\n }\n})\n</script>\n","<template>\n <div class=\"relative\">\n <div class=\"mb-4\">\n <Button\n class=\"text-base-foreground w-full border-0 bg-secondary-background hover:bg-secondary-background-hover\"\n :disabled=\"isRecording || readonly\"\n @click=\"handleStartRecording\"\n >\n {{ t('g.startRecording', 'Start Recording') }}\n <i-lucide:mic class=\"ml-1\" />\n </Button>\n </div>\n <div\n v-if=\"isRecording || isPlaying || recordedURL\"\n class=\"flex h-14 w-full min-w-0 items-center gap-2 rounded-lg px-3 bg-node-component-surface text-text-secondary\"\n >\n <!-- Recording Status -->\n <div class=\"flex shrink-0 items-center gap-1\">\n <span class=\"text-xs\">\n {{\n isRecording\n ? t('g.listening', 'Listening...')\n : isPlaying\n ? t('g.playing', 'Playing...')\n : recordedURL\n ? t('g.ready', 'Ready')\n : ''\n }}\n </span>\n <span class=\"text-sm\">{{ formatTime(timer) }}</span>\n </div>\n\n <!-- Waveform Visualization -->\n <div class=\"flex h-8 min-w-0 flex-1 items-center gap-2 overflow-hidden\">\n <div\n v-for=\"(bar, index) in waveformBars\"\n :key=\"index\"\n class=\"max-h-8 min-h-1 w-0.75 rounded-[1.5px] bg-slate-100 transition-all duration-100\"\n :style=\"{ height: bar.height + 'px' }\"\n :title=\"`Bar ${index + 1}: ${bar.height}px`\"\n />\n </div>\n\n <!-- Control Button -->\n <button\n v-if=\"isRecording\"\n :title=\"t('g.stopRecording', 'Stop Recording')\"\n class=\"flex shrink-0 size-8 animate-pulse items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handleStopRecording\"\n >\n <div class=\"size-2.5 rounded-sm bg-danger-100\" />\n </button>\n\n <button\n v-else-if=\"!isRecording && recordedURL && !isPlaying\"\n :title=\"t('g.playRecording') || 'Play Recording'\"\n class=\"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handlePlayRecording\"\n >\n <i class=\"text-text-secondary icon-[lucide--play] size-4\" />\n </button>\n\n <button\n v-else-if=\"isPlaying\"\n :title=\"t('g.stopPlayback') || 'Stop Playback'\"\n class=\"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors\"\n @click=\"handleStopPlayback\"\n >\n <i class=\"text-text-secondary icon-[lucide--square] size-4\" />\n </button>\n </div>\n <audio\n v-if=\"recordedURL\"\n ref=\"audioRef\"\n :key=\"audioElementKey\"\n :src=\"recordedURL\"\n class=\"hidden\"\n @ended=\"playback.onPlaybackEnded\"\n @loadedmetadata=\"playback.onMetadataLoaded\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useIntervalFn } from '@vueuse/core'\nimport { Button } from 'primevue'\nimport { computed, onMounted, onUnmounted, ref } from 'vue'\n\nimport { t } from '@/i18n'\nimport type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'\nimport type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'\nimport { useToastStore } from '@/platform/updates/common/toastStore'\nimport { app } from '@/scripts/app'\nimport { useAudioService } from '@/services/audioService'\n\nimport { useAudioPlayback } from '../composables/audio/useAudioPlayback'\nimport { useAudioRecorder } from '../composables/audio/useAudioRecorder'\nimport { useAudioWaveform } from '../composables/audio/useAudioWaveform'\nimport { formatTime } from '../utils/audioUtils'\n\nconst props = defineProps<{\n readonly?: boolean\n nodeId: string\n}>()\n\n// Audio element ref\nconst audioRef = ref<HTMLAudioElement>()\n\n// Keep track of the last uploaded path as a backup\nlet lastUploadedPath = ''\n\n// Composables\nconst recorder = useAudioRecorder({\n onRecordingComplete: handleRecordingComplete,\n onError: () => {\n useToastStore().addAlert(\n t('g.micPermissionDenied') || 'Microphone permission denied'\n )\n }\n})\n\nconst waveform = useAudioWaveform({\n barCount: 18,\n minHeight: 4,\n maxHeight: 32\n})\n\nconst playback = useAudioPlayback(audioRef, {\n onPlaybackEnded: handlePlaybackEnded,\n onMetadataLoaded: (duration) => {\n if (!isPlaying.value && !isRecording.value) {\n timer.value = Math.floor(duration)\n }\n }\n})\n\n// Timer for recording\nconst timer = ref(0)\nconst { pause: pauseTimer, resume: resumeTimer } = useIntervalFn(\n () => {\n timer.value += 1\n },\n 1000,\n { immediate: false }\n)\n\n// Destructure for template access\nconst { isRecording, recordedURL } = recorder\nconst { waveformBars } = waveform\nconst { isPlaying, audioElementKey } = playback\n\n// Computed for waveform animation\nconst isWaveformActive = computed(() => isRecording.value || isPlaying.value)\n\nconst modelValue = defineModel<string>({ default: '' })\n\nconst litegraphNode = computed(() => {\n if (!props.nodeId || !app.canvas.graph) return null\n return app.canvas.graph.getNodeById(props.nodeId) as LGraphNode | null\n})\n\nasync function handleRecordingComplete(blob: Blob) {\n try {\n const path = await useAudioService().convertBlobToFileAndSubmit(blob)\n modelValue.value = path\n lastUploadedPath = path\n } catch (e) {\n useToastStore().addAlert('Failed to upload recorded audio')\n }\n}\n\nasync function handleStartRecording() {\n if (props.readonly) return\n\n try {\n await waveform.setupAudioContext()\n await recorder.startRecording()\n\n // Setup waveform visualization for recording\n if (recorder.mediaRecorder.value) {\n const stream = recorder.mediaRecorder.value.stream\n if (stream) {\n await waveform.setupRecordingVisualization(stream)\n }\n }\n\n // Start timer\n timer.value = 0\n resumeTimer()\n waveform.initWaveform()\n waveform.updateWaveform(isWaveformActive)\n } catch (err) {\n console.error('Failed to start recording:', err)\n }\n}\n\nfunction handleStopRecording() {\n recorder.stopRecording()\n pauseTimer()\n waveform.stopWaveform()\n}\n\nasync function handlePlayRecording() {\n if (!recordedURL.value) return\n\n // Reset timer\n timer.value = 0\n\n // Reset and setup audio element\n await playback.resetAudioElement()\n\n // Wait for audio element to be ready\n await new Promise((resolve) => setTimeout(resolve, 50))\n\n if (!audioRef.value) return\n\n // Setup waveform visualization for playback\n const setupSuccess = await waveform.setupPlaybackVisualization(audioRef.value)\n if (!setupSuccess) return\n\n // Start playback\n await playback.play()\n\n // Update waveform\n waveform.initWaveform()\n waveform.updateWaveform(isWaveformActive)\n\n // Update timer from audio current time\n const timerInterval = setInterval(() => {\n timer.value = Math.floor(playback.getCurrentTime())\n }, 100)\n\n // Store interval for cleanup\n playback.playbackTimerInterval.value = timerInterval\n}\n\nfunction handleStopPlayback() {\n playback.stop()\n handlePlaybackEnded()\n}\n\nfunction handlePlaybackEnded() {\n waveform.stopWaveform()\n\n // Clear playback timer interval\n if (playback.playbackTimerInterval.value !== null) {\n clearInterval(playback.playbackTimerInterval.value)\n playback.playbackTimerInterval.value = null\n }\n\n const duration = playback.getDuration()\n if (duration) {\n timer.value = Math.floor(duration)\n } else {\n timer.value = 0\n }\n}\n\n// Serialization function for workflow execution\nasync function serializeValue() {\n if (isRecording.value && recorder.mediaRecorder.value) {\n recorder.mediaRecorder.value.stop()\n\n await new Promise((resolve, reject) => {\n let attempts = 0\n const maxAttempts = 50 // 5 seconds max (50 * 100ms)\n const checkRecording = () => {\n if (!isRecording.value && modelValue.value) {\n resolve(undefined)\n } else if (++attempts >= maxAttempts) {\n reject(new Error('Recording serialization timeout after 5 seconds'))\n } else {\n setTimeout(checkRecording, 100)\n }\n }\n checkRecording()\n })\n }\n\n return modelValue.value || lastUploadedPath || ''\n}\n\nfunction registerWidgetSerialization() {\n const node = litegraphNode.value\n if (!node?.widgets) return\n const targetWidget = node.widgets.find((w: IBaseWidget) => w.name === 'audio')\n if (targetWidget) {\n targetWidget.serializeValue = serializeValue\n }\n}\n\nonMounted(() => {\n waveform.initWaveform()\n registerWidgetSerialization()\n})\n\nonUnmounted(() => {\n if (playback.playbackTimerInterval.value !== null) {\n clearInterval(playback.playbackTimerInterval.value)\n playback.playbackTimerInterval.value = null\n }\n})\n</script>\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ import"./vendor-primevue-DcMRXJN3.js";import"./vendor-other-DlQF6V2E.js";import"./api-Dwq2LQIW.js";import"./remoteConfig-CZcEXsZS.js";import"./colorUtil-CzxntCbX.js";import"./useErrorHandling-Cfa5N_7c.js";import"./Button-Do2I1OAA.js";import"./PanelTemplate-BJda9e5J.js";import"./dialogService-YG0RH337.js";import"./vendor-tiptap-_UqYL7N_.js";import"./vendor-xterm-BU_lcTPR.js";import"./vendor-three-BFcUNSs9.js";import"./markdownRendererUtil-DglHsU8t.js";import"./userStore-BAS9m9W6.js";import{t as x}from"./WidgetSelect-nSQrk_hd.js";import"./widgetPropFilter-CKhENku4.js";import"./layout-C9TPTaej.js";import"./LazyImage-D5qRMpUj.js";import"./WidgetWithControl-Da6zUB5e.js";export{x as default};
@@ -1,3 +1,3 @@
1
- var ve=Object.defineProperty;var v=(t,e)=>ve(t,"name",{value:e,configurable:!0});import{et as oe,tt as ge}from"./vendor-primevue-DcMRXJN3.js";import{$o as W,Ba as k,Co as Z,Do as K,Ha as _,Jo as h,Ka as ye,Ko as R,Lr as we,Oo as be,Pa as G,Ua as $,Va as z,Wo as he,Xo as F,Ya as O,do as y,eo as Se,fo as ke,go as Me,mo as $e,no as P,po as ee,qa as T,ro as ae,wo as se,xo as A,za as d,zo as L}from"./vendor-other-DlQF6V2E.js";import{A as B,It as re,Lt as ne,r as De}from"./api-CUAc7rDA.js";import{t as x}from"./src-DTrob8OL.js";import{t as xe}from"./Button-Do2I1OAA.js";import{Hn as Ce,Jn as Fe,Un as ie,or as Ae,qn as Ue,vn as Ie,yr as Ve}from"./dialogService-BZ1FmjZL.js";import{i as de,o as ue}from"./widgetPropFilter-CKhENku4.js";import{t as ce}from"./layout-C9TPTaej.js";import{t as pe}from"./WidgetLayoutField-DXI3EnEF.js";import{i as ze,t as Oe}from"./LazyImage-D5qRMpUj.js";import{t as Te}from"./WidgetWithControl-Dh2FWOiA.js";var Le={name:"SelectPlus",extends:ge,emits:["hide"],methods:{onOverlayLeave(){this.unbindOutsideClickListener(),this.unbindScrollListener(),this.unbindResizeListener(),this.$emit("hide"),this.overlay=null}}},_e=Le;function fe(t={}){return d(()=>({appendTo:"self",...t}))}v(fe,"useTransformCompatOverlayProps");var Pe={class:"absolute top-5 right-8 h-4 w-7 -translate-y-4/5 flex"},Be=O({__name:"WidgetSelectDefault",props:P({widget:{}},{modelValue:{default(t){return t.widget.options?.values?.[0]||""}},modelModifiers:{}}),emits:["update:modelValue"],setup(t){const e=t,n=A(t,"modelValue"),w=fe(),i=d(()=>{const a=e.widget.options;return a?.values&&Array.isArray(a.values)?a.values:[]}),g=d(()=>!!n.value&&!i.value.includes(n.value)),p=d(()=>({...ue(e.widget.options,de),...w.value,...g.value?{placeholder:`${n.value}`}:{}}));return(a,l)=>(y(),z(pe,{widget:a.widget},{default:K(()=>[T(_e,ae({modelValue:n.value,"onUpdate:modelValue":l[0]||(l[0]=f=>n.value=f),invalid:g.value,filter:i.value.length>4,"auto-filter-focus":"",options:i.value},p.value,{class:h(x)(h(ce),"w-full text-xs"),"aria-label":a.widget.name,size:"small",pt:{option:"text-xs",dropdown:"w-8",label:h(x)("truncate min-w-[4ch]",a.$slots.default&&"mr-5"),overlay:"w-fit min-w-full"},"data-capture-wheel":"true"}),null,16,["modelValue","invalid","filter","options","class","aria-label","pt"]),k("div",Pe,[$e(a.$slots,"default")])]),_:3},8,["widget"]))}}),te=Be,We={class:"min-w-0 flex-1 px-1 py-2 text-left truncate"},Qe={key:0},je={key:1},Re=["multiple","disabled","accept"],Ke=O({__name:"FormDropdownInput",props:{isOpen:{type:Boolean,default:!1},placeholder:{default:"Select..."},items:{},selected:{},maxSelectable:{},uploadable:{type:Boolean},disabled:{type:Boolean},accept:{}},emits:["select-click","file-change"],setup(t,{emit:e}){const n=t,w=e,i=d(()=>n.items.filter(p=>n.selected.has(p.id))),g=d(()=>x("border-0 bg-component-node-widget-background outline-none text-text-secondary",n.disabled?"cursor-not-allowed":"hover:bg-component-node-widget-background-hovered cursor-pointer",i.value.length>0&&"text-text-primary"));return(p,a)=>(y(),$("div",{class:F(h(x)(h(ce),"flex text-base leading-none",{"opacity-50 cursor-not-allowed !outline-zinc-300/10":p.disabled}))},[k("button",{class:F(h(x)(g.value,"flex justify-between items-center flex-1 min-w-0 h-8",{"rounded-l-lg":p.uploadable,"rounded-lg":!p.uploadable})),onClick:a[0]||(a[0]=l=>w("select-click",l))},[k("span",We,[i.value.length?(y(),$("span",je,W(i.value.map(l=>l.label??l.name).join(", ")),1)):(y(),$("span",Qe,W(p.placeholder),1))]),k("i",{class:F(["icon-[lucide--chevron-down]",h(x)("mr-2 size-4 transition-transform duration-200 flex-shrink-0 text-component-node-foreground-secondary",p.isOpen&&"rotate-180")])},null,2)],2),p.uploadable?(y(),$("label",{key:0,class:F(h(x)(g.value,"relative","size-8 flex justify-center items-center border-l rounded-r-lg border-zinc-300/10"))},[a[2]||(a[2]=k("i",{class:"icon-[lucide--folder-search] size-4"},null,-1)),k("input",{type:"file",class:"absolute inset-0 -z-1 opacity-0",multiple:p.maxSelectable>1,disabled:p.disabled,accept:p.accept,onChange:a[1]||(a[1]=l=>w("file-change",l))},null,40,Re)],2)):_("",!0)],2))}}),Ee=Ke,Ne={class:"text-secondary flex gap-2 px-4"},He={key:0,class:"absolute top-[-2px] left-[-2px] size-2 rounded-full bg-component-node-widget-background-highlighted"},qe=["onClick"],Je={key:0,class:"icon-[lucide--check] size-4"},q="bg-transparent border-0 outline-0 ring-0 text-left",le="size-6 flex justify-center items-center rounded-sm cursor-pointer transition-all duration-150 hover:scale-108 hover:text-base-foreground active:scale-95",Xe=O({__name:"FormDropdownMenuActions",props:P({searcher:{type:Function},sortOptions:{}},{layoutMode:{},layoutModeModifiers:{},searchQuery:{},searchQueryModifiers:{},sortSelected:{},sortSelectedModifiers:{}}),emits:["update:layoutMode","update:searchQuery","update:sortSelected"],setup(t){const e=A(t,"layoutMode"),n=A(t,"searchQuery"),w=A(t,"sortSelected"),i=x("h-8 bg-zinc-500/20 rounded-lg outline outline-1 outline-offset-[-1px] outline-node-component-border transition-all duration-150"),g=Z("sortPopoverRef"),p=Z("sortTriggerRef"),a=L(!1);function l(s){!g.value||!p.value||(a.value=!a.value,g.value.toggle(s,p.value))}v(l,"toggleSortPopover");function f(){a.value=!1,g.value?.hide()}v(f,"closeSortPopover");function o(s){w.value=s.id,f()}return v(o,"handleSortSelected"),(s,u)=>(y(),$("div",Ne,[T(ze,{modelValue:n.value,"onUpdate:modelValue":u[0]||(u[0]=S=>n.value=S),searcher:s.searcher,class:F(h(x)(h(i),"hover:outline-component-node-widget-background-highlighted/80","focus-within:outline-component-node-widget-background-highlighted/80 focus-within:ring-0"))},null,8,["modelValue","searcher","class"]),k("button",{ref_key:"sortTriggerRef",ref:p,class:F(h(x)(q,h(i),"relative w-8 flex justify-center items-center cursor-pointer","hover:outline-component-node-widget-background-highlighted","active:!scale-95")),onClick:l},[w.value!=="default"?(y(),$("div",He)):_("",!0),u[4]||(u[4]=k("i",{class:"icon-[lucide--arrow-up-down] size-4"},null,-1))],2),T(h(oe),{ref_key:"sortPopoverRef",ref:g,dismissable:!0,"close-on-escape":!0,unstyled:"",pt:{root:{class:"absolute z-50"},content:{class:["bg-transparent border-none p-0 pt-2 rounded-lg shadow-lg"]}},onHide:u[1]||(u[1]=S=>a.value=!1)},{default:K(()=>[k("div",{class:F(h(x)("flex flex-col gap-2 p-2 min-w-32","bg-component-node-background","rounded-lg outline outline-offset-[-1px] outline-component-node-border"))},[(y(!0),$(G,null,ee(s.sortOptions,S=>(y(),$("button",{key:S.name,class:F(h(x)(q,"flex justify-between items-center h-6 cursor-pointer","hover:!text-blue-500")),onClick:v(U=>o(S),"onClick")},[k("span",null,W(S.name),1),w.value===S.id?(y(),$("i",Je)):_("",!0)],10,qe))),128))],2)]),_:1},512),k("div",{class:F(h(x)(h(i),"flex justify-center items-center p-1 gap-1 hover:outline-component-node-widget-background-highlighted"))},[k("button",{class:F(h(x)(q,le,e.value==="list"?"bg-neutral-500/50 text-base-foreground":"")),onClick:u[2]||(u[2]=S=>e.value="list")},u[5]||(u[5]=[k("i",{class:"icon-[lucide--list] size-4"},null,-1)]),2),k("button",{class:F(h(x)(q,le,e.value==="grid"?"bg-neutral-500/50 text-base-foreground":"")),onClick:u[3]||(u[3]=S=>e.value="grid")},u[6]||(u[6]=[k("i",{class:"icon-[lucide--layout-grid] size-4"},null,-1)]),2)],2)]))}}),Ye=Xe,Ze={class:"text-secondary mb-4 flex gap-1 px-4 justify-start"},Ge=["disabled","onClick"],et=O({__name:"FormDropdownMenuFilter",props:P({filterOptions:{}},{filterSelected:{},filterSelectedModifiers:{}}),emits:["update:filterSelected"],setup(t){const e=A(t,"filterSelected"),{isUploadButtonEnabled:n,showUploadDialog:w}=Ce(),i=d(()=>t.filterOptions.length===1);return(g,p)=>(y(),$("div",Ze,[(y(!0),$(G,null,ee(g.filterOptions,a=>(y(),$("button",{key:a.id,type:"button",disabled:i.value,class:F(h(x)("px-4 py-2 rounded-md inline-flex justify-center items-center select-none appearance-none border-0 text-base-foreground",!i.value&&"transition-all duration-150 hover:text-base-foreground hover:bg-interface-menu-component-surface-hovered cursor-pointer active:scale-95",!i.value&&e.value===a.id?"!bg-interface-menu-component-surface-selected text-base-foreground":"bg-transparent")),onClick:v(l=>e.value=a.id,"onClick")},W(a.name),11,Ge))),128)),h(n)&&i.value?(y(),z(xe,{key:0,class:"ml-auto",size:"md",variant:"textonly",onClick:h(w)},{default:K(()=>[p[0]||(p[0]=k("i",{class:"icon-[lucide--folder-input]"},null,-1)),k("span",null,W(g.$t("g.import")),1)]),_:1},8,["onClick"])):_("",!0)]))}}),tt=et;const me=Symbol("assetKind");var lt={key:0,class:"absolute top-1 left-1 size-4 rounded-full border-1 border-base-foreground bg-primary-background"},ot=["src"],at={key:3,class:"size-full bg-gradient-to-tr from-blue-400 via-teal-500 to-green-400"},st={class:"text-secondary block text-xs"},rt=O({__name:"FormDropdownMenuItem",props:{index:{},selected:{type:Boolean},mediaSrc:{},name:{},label:{},metadata:{},layout:{}},emits:["click","mediaLoad"],setup(t,{emit:e}){const n=t,w=e,i=L(null),g=Se(me),p=d(()=>g?.value==="video");function a(){w("click",n.index)}v(a,"handleClick");function l(o){if(w("mediaLoad",o),!o.target||!(o.target instanceof HTMLImageElement))return;const s=o.target;s.naturalWidth&&s.naturalHeight&&(i.value=`${s.naturalWidth} x ${s.naturalHeight}`)}v(l,"handleImageLoad");function f(o){if(w("mediaLoad",o),!o.target||!(o.target instanceof HTMLVideoElement))return;const s=o.target;s.videoWidth&&s.videoHeight&&(i.value=`${s.videoWidth} x ${s.videoHeight}`)}return v(f,"handleVideoLoad"),(o,s)=>{const u=Me("tooltip");return y(),$("div",{class:F(h(x)("flex gap-1 select-none group/item cursor-pointer bg-component-node-widget-background","transition-all duration-150",{"flex-col text-center":o.layout==="grid","flex-row text-left max-h-16 rounded-lg hover:scale-102 active:scale-98":o.layout==="list","flex-row text-left hover:bg-component-node-widget-background-hovered rounded-lg":o.layout==="list-small","ring-2 ring-component-node-widget-background-highlighted":o.layout==="list"&&o.selected})),onClick:a},[o.layout!=="list-small"?(y(),$("div",{key:0,class:F(h(x)("relative","w-full aspect-square overflow-hidden outline-1 outline-offset-[-1px] outline-interface-stroke","transition-all duration-150",{"min-w-16 max-w-16 rounded-l-lg":o.layout==="list","rounded-sm group-hover/item:scale-108 group-active/item:scale-95":o.layout==="grid","ring-2 ring-component-node-widget-background-highlighted":o.layout==="grid"&&o.selected}))},[o.selected?(y(),$("div",lt,s[0]||(s[0]=[k("i",{class:"icon-[lucide--check] size-3 translate-y-[-0.5px] text-base-foreground bold"},null,-1)]))):_("",!0),o.mediaSrc&&p.value?(y(),$("video",{key:1,src:o.mediaSrc,class:"size-full object-cover",preload:"metadata",muted:"",onLoadeddata:f},null,40,ot)):o.mediaSrc?(y(),z(Oe,{key:2,src:o.mediaSrc,alt:o.name,"image-class":"size-full object-cover",onLoad:l},null,8,["src","alt"])):(y(),$("div",at))],2)):_("",!0),k("div",{class:F(h(x)("flex gap-1",{"flex-col":o.layout==="grid","flex-col px-4 py-1 w-full justify-center min-w-0":o.layout==="list","flex-row p-2 items-center justify-between w-full":o.layout==="list-small"}))},[be((y(),$("span",{class:F(h(x)("block text-xs line-clamp-2 break-words overflow-hidden","transition-colors duration-150",!!o.selected&&"text-base-foreground"))},[ye(W(o.label??o.name),1)],2)),[[u,o.layout==="grid"?o.label??o.name:void 0]]),k("span",st,W(o.metadata||i.value),1)],2)],2)}}}),nt=rt,it={class:"flex max-h-[640px] w-103 flex-col rounded-lg bg-component-node-background pt-4 outline outline-offset-[-1px] outline-node-component-border"},dt={class:"relative flex h-full mt-2 overflow-y-scroll"},ut={key:0,class:"h-50 col-span-full flex items-center justify-center"},ct=["title","aria-label"],pt=O({__name:"FormDropdownMenu",props:P({items:{},isSelected:{type:Function},filterOptions:{},sortOptions:{},searcher:{type:Function}},{filterSelected:{},filterSelectedModifiers:{},layoutMode:{},layoutModeModifiers:{},sortSelected:{},sortSelectedModifiers:{},searchQuery:{},searchQueryModifiers:{}}),emits:P(["item-click"],["update:filterSelected","update:layoutMode","update:sortSelected","update:searchQuery"]),setup(t,{emit:e}){const n=e,w=A(t,"filterSelected"),i=A(t,"layoutMode"),g=A(t,"sortSelected"),p=A(t,"searchQuery");return(a,l)=>(y(),$("div",it,[a.filterOptions.length>0?(y(),z(tt,{key:0,"filter-selected":w.value,"onUpdate:filterSelected":l[0]||(l[0]=f=>w.value=f),"filter-options":a.filterOptions},null,8,["filter-selected","filter-options"])):_("",!0),T(Ye,{"layout-mode":i.value,"onUpdate:layoutMode":l[1]||(l[1]=f=>i.value=f),"sort-selected":g.value,"onUpdate:sortSelected":l[2]||(l[2]=f=>g.value=f),"search-query":p.value,"onUpdate:searchQuery":l[3]||(l[3]=f=>p.value=f),"sort-options":a.sortOptions,searcher:a.searcher},null,8,["layout-mode","sort-selected","search-query","sort-options","searcher"]),k("div",dt,[k("div",{class:F(h(x)("h-full max-h-full grid gap-x-2 gap-y-4 overflow-y-auto px-4 pt-4 pb-4 w-full",{"grid-cols-4":i.value==="grid","grid-cols-1 gap-y-2":i.value==="list","grid-cols-1 gap-y-1":i.value==="list-small"}))},[l[4]||(l[4]=k("div",{class:"pointer-events-none absolute inset-x-3 top-0 z-10 h-5"},null,-1)),a.items.length===0?(y(),$("div",ut,[k("i",{title:a.$t("g.noItems"),"aria-label":a.$t("g.noItems"),class:"icon-[lucide--circle-off] size-30 text-zinc-500/20"},null,8,ct)])):_("",!0),(y(!0),$(G,null,ee(a.items,(f,o)=>(y(),z(nt,{key:f.id,index:o,selected:a.isSelected(f,o),"media-src":f.mediaSrc,name:f.name,label:f.label,metadata:f.metadata,layout:i.value,onClick:v(s=>n("item-click",f,o),"onClick")},null,8,["index","selected","media-src","name","label","metadata","layout","onClick"]))),128))],2)])]))}}),ft=pt;async function mt(t,e){if(t.trim()==="")return e;const n=t.trim().toLowerCase().split(" ");return e.filter(w=>{const i=w.name.toLowerCase();return n.every(g=>i.includes(g))})}v(mt,"defaultSearcher");function vt(){return[{name:"Default",id:"default",sorter:v(({items:t})=>t.slice(),"sorter")},{name:"A-Z",id:"a-z",sorter:v(({items:t})=>t.slice().sort((e,n)=>e.name.localeCompare(n.name)),"sorter")}]}v(vt,"getDefaultSortOptions");var gt=O({__name:"FormDropdown",props:P({items:{},placeholder:{default:B("widgets.uploadSelect.placeholder")},multiple:{type:[Boolean,Number],default:!1},uploadable:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},accept:{},filterOptions:{default:v(()=>[],"default")},sortOptions:{default:v(()=>vt(),"default")},isSelected:{type:Function,default:v((t,e,n)=>t.has(e.id),"default")},searcher:{type:Function,default:mt}},{selected:{default:new Set},selectedModifiers:{},filterSelected:{default:""},filterSelectedModifiers:{},sortSelected:{default:"default"},sortSelectedModifiers:{},layoutMode:{default:"grid"},layoutModeModifiers:{},files:{default:[]},filesModifiers:{},searchQuery:{default:""},searchQueryModifiers:{}}),emits:["update:selected","update:filterSelected","update:sortSelected","update:layoutMode","update:files","update:searchQuery"],setup(t){const e=t,n=A(t,"selected"),w=A(t,"filterSelected"),i=A(t,"sortSelected"),g=A(t,"layoutMode"),p=A(t,"files"),a=A(t,"searchQuery"),l=re(),f=L(),o=Z("triggerRef"),s=L(!1),u=d(()=>e.multiple===!0?1/0:typeof e.multiple=="number"?e.multiple:1),S=L([]),U=d(()=>e.sortOptions.find(b=>b.id==="default")?.sorter||(({items:b})=>b.slice())),j=d(()=>i.value==="default"?U.value:e.sortOptions.find(b=>b.id===i.value)?.sorter||U.value),I=d(()=>j.value({items:S.value})||[]);function V(b,M){return e.isSelected?.(n.value,b,M)??!1}v(V,"internalIsSelected");const J=v(b=>{e.disabled||f.value&&o.value&&(f.value.toggle(b,o.value),s.value=!s.value)},"toggleDropdown"),E=v(()=>{f.value&&(f.value.hide(),s.value=!1)},"closeDropdown");function N(b){if(e.disabled)return;const M=b.target;M.files&&(p.value=Array.from(M.files)),M.value=""}v(N,"handleFileChange");function X(b,M){if(e.disabled)return;const D=n.value;if(V(b,M))D.delete(b.id);else if(D.size<u.value)D.add(b.id);else if(u.value===1)D.clear(),D.add(b.id);else{l.addAlert("Maximum selection limit reached");return}n.value=new Set(D),u.value===1&&E()}v(X,"handleSelection");async function Y(b,M){let D=!1,c;M(()=>{D=!0,c?.()}),await e.searcher(b,e.items,r=>c=r).then(r=>{D||(S.value=r)})}return v(Y,"customSearcher"),(b,M)=>(y(),$("div",{ref_key:"triggerRef",ref:o},[T(Ee,{files:p.value,"is-open":s.value,placeholder:b.placeholder,items:b.items,"max-selectable":u.value,selected:n.value,uploadable:b.uploadable,disabled:b.disabled,accept:b.accept,onSelectClick:J,onFileChange:N},null,8,["files","is-open","placeholder","items","max-selectable","selected","uploadable","disabled","accept"]),T(h(oe),{ref_key:"popoverRef",ref:f,dismissable:!0,"close-on-escape":!0,unstyled:"",pt:{root:{class:"absolute z-50"},content:{class:["bg-transparent border-none p-0 pt-2 rounded-lg shadow-lg"]}},onHide:M[4]||(M[4]=D=>s.value=!1)},{default:K(()=>[T(ft,{"filter-selected":w.value,"onUpdate:filterSelected":M[0]||(M[0]=D=>w.value=D),"layout-mode":g.value,"onUpdate:layoutMode":M[1]||(M[1]=D=>g.value=D),"sort-selected":i.value,"onUpdate:sortSelected":M[2]||(M[2]=D=>i.value=D),"search-query":a.value,"onUpdate:searchQuery":M[3]||(M[3]=D=>a.value=D),"filter-options":b.filterOptions,"sort-options":b.sortOptions,disabled:b.disabled,searcher:Y,items:I.value,"is-selected":V,"max-selectable":u.value,onClose:E,onItemClick:X},null,8,["filter-selected","layout-mode","sort-selected","search-query","filter-options","sort-options","disabled","items","max-selectable"])]),_:1},512)],512))}}),yt=gt;function wt(t){if(ne){const e=ie(),n=Fe(),w=d(()=>{const l=R(t);return l?n.getCategoryForNodeType(l):void 0}),i=d(()=>{const l=R(t);return l?e.modelAssetsByNodeType.get(l)??[]:[]}),g=d(()=>{const l=R(t);return l?e.modelLoadingByNodeType.get(l)??!1:!1}),p=d(()=>{const l=R(t);return l?e.modelErrorByNodeType.get(l)??null:null}),a=d(()=>i.value.map(l=>({id:l.id,name:l.user_metadata?.filename??l.name,label:l.name,mediaSrc:l.preview_url??"",metadata:""})));return se(()=>R(t),async l=>{l&&(e.modelAssetsByNodeType.has(l)||await e.updateModelsForNodeType(l))},{immediate:!0}),{category:w,assets:i,dropdownItems:a,isLoading:g,error:p}}return{category:d(()=>{}),assets:d(()=>[]),dropdownItems:d(()=>[]),isLoading:d(()=>!1),error:d(()=>null)}}v(wt,"useAssetWidgetData");var bt=O({__name:"WidgetSelectDropdown",props:P({widget:{},nodeType:{},assetKind:{},allowUpload:{type:Boolean},uploadFolder:{},isAssetMode:{type:Boolean},defaultLayoutMode:{}},{modelValue:{default(t){return t.widget.options?.values?.[0]||""}},modelModifiers:{}}),emits:["update:modelValue"],setup(t){const e=t;ke(me,d(()=>e.assetKind));const n=A(t,"modelValue"),w=re(),i=Ie(),g=fe(),p=d(()=>({...ue(e.widget.options,de),...g.value})),l=v(()=>{const c=e.widget.options?.nodeType??e.nodeType;return e.isAssetMode&&c?wt(he(c)):null},"getAssetData")(),f=L("all"),o=d(()=>e.isAssetMode?[{id:"all",name:we(l?.category.value??"All")}]:[{id:"all",name:"All"},{id:"inputs",name:"Inputs"},{id:"outputs",name:"Outputs"}]),s=L(new Set);function u(c){const r=e.widget.options?.getOptionLabel;if(!r)return c;try{return r(c)}catch(m){return console.error("Failed to map value:",m),c}}v(u,"getDisplayLabel");const S=d(()=>{const c=e.widget.options?.values||[];return Array.isArray(c)?c.map((r,m)=>({id:`input-${m}`,mediaSrc:D(r,"input"),name:r,label:u(r),metadata:""})):[]}),U=d(()=>{if(!["image","video"].includes(e.assetKind??""))return[];const c=new Set;return i.historyTasks.forEach(r=>{r.flatOutputs.forEach(m=>{const C=e.assetKind==="image"&&m.mediaType==="images"||e.assetKind==="video"&&m.mediaType==="video";if(m.type==="output"&&C){const Q=`${m.subfolder?`${m.subfolder}/${m.filename}`:m.filename} [output]`;c.add(Q)}})}),Array.from(c).map(r=>({id:`output-${r}`,mediaSrc:D(r.replace(" [output]",""),"output"),name:r,label:u(r),metadata:""}))}),j=d(()=>e.isAssetMode&&l?l.dropdownItems.value:[...S.value,...U.value]),I=d(()=>{if(e.isAssetMode)return j.value;switch(f.value){case"inputs":return S.value;case"outputs":return U.value;case"all":default:return[...S.value,...U.value]}}),V=d(()=>{const c=e.widget.options;if(c?.placeholder)return c.placeholder;switch(e.assetKind){case"image":return B("widgets.uploadSelect.placeholderImage");case"video":return B("widgets.uploadSelect.placeholderVideo");case"audio":return B("widgets.uploadSelect.placeholderAudio");case"model":return B("widgets.uploadSelect.placeholderModel");case"unknown":return B("widgets.uploadSelect.placeholderUnknown")}return B("widgets.uploadSelect.placeholder")}),J=d(()=>e.isAssetMode?!1:e.allowUpload===!0),E=d(()=>{switch(e.assetKind){case"image":return"image/*";case"video":return"video/*";case"audio":return"audio/*";default:return}}),N=L(e.defaultLayoutMode??"grid");se([n,I],([c,r])=>{if(c===void 0){s.value.clear();return}const m=I.value.find(C=>C.name===c);m&&(s.value.clear(),s.value.add(m.id))},{immediate:!0});function X(c){let r;if(c.size>0&&(r=c.values().next().value),r==null){n.value=void 0;return}const m=I.value.find(C=>C.id===r)?.name;if(!m){n.value=void 0;return}n.value=m}v(X,"updateSelectedItems");const Y=v(async(c,r=!1,m={})=>{const C=new FormData;C.append("image",c),r&&C.append("subfolder","pasted"),m.type&&C.append("type",m.type);const Q=await De.fetchApi("/upload/image",{method:"POST",body:C});if(Q.status!==200)return w.addAlert(Q.status+" - "+Q.statusText),null;const H=await Q.json();return(m.type==="input"||!m.type&&!r)&&await ie().updateInputs(),H.subfolder?`${H.subfolder}/${H.name}`:H.name},"uploadFile"),b=v(async c=>{const r=e.uploadFolder??"input",m=c.map(C=>Y(C,!1,{type:r}));return(await Promise.all(m)).filter(C=>C!==null)},"uploadFiles");async function M(c){if(!(!c||c.length===0))try{const r=await b(c);if(r.length===0){w.addAlert("File upload failed");return}e.widget.options?.values&&r.forEach(m=>{const C=e.widget.options.values;C.includes(m)||C.push(m)}),n.value=r[0],e.widget.callback&&e.widget.callback(r[0])}catch(r){console.error("Upload error:",r),w.addAlert(`Upload failed: ${r}`)}}v(M,"handleFilesUpdate");function D(c,r="input"){return["image","video"].includes(e.assetKind??"")?`/api/view?filename=${encodeURIComponent(c)}&type=${r}`:""}return v(D,"getMediaUrl"),(c,r)=>(y(),z(pe,{widget:c.widget},{default:K(()=>[T(yt,ae({selected:s.value,"onUpdate:selected":r[0]||(r[0]=m=>s.value=m),"filter-selected":f.value,"onUpdate:filterSelected":r[1]||(r[1]=m=>f.value=m),"layout-mode":N.value,"onUpdate:layoutMode":r[2]||(r[2]=m=>N.value=m),items:I.value,placeholder:V.value,multiple:!1,uploadable:J.value,accept:E.value,"filter-options":o.value},p.value,{class:"w-full","onUpdate:selected":X,"onUpdate:files":M}),null,16,["selected","filter-selected","layout-mode","items","placeholder","uploadable","accept","filter-options"])]),_:1},8,["widget"]))}}),ht=bt,St=O({__name:"WidgetSelect",props:P({widget:{},nodeType:{}},{modelValue:{},modelModifiers:{}}),emits:["update:modelValue"],setup(t){const e=t,n=A(t,"modelValue"),w=d(()=>{if(e.widget.spec&&Ae(e.widget.spec))return e.widget.spec}),i=d(()=>{const s=w.value;if(!s)return{kind:"unknown",allowUpload:!1,folder:void 0};const{image_upload:u,animated_image_upload:S,video_upload:U,image_folder:j,audio_upload:I}=s;let V="unknown";return U?V="video":u||S?V="image":I&&(V="audio"),{kind:V,allowUpload:u===!0||S===!0||U===!0||I===!0,folder:j}}),g=d(()=>{if(ne){const s=Ve().get("Comfy.Assets.UseAssetAPI"),u=Ue.isAssetBrowserEligible(e.nodeType,e.widget.name)||e.widget.type==="asset";return s&&u}return!1}),p=d(()=>i.value.kind),a=d(()=>g.value||p.value!=="unknown"),l=d(()=>i.value.allowUpload),f=d(()=>i.value.folder??"input"),o=d(()=>g.value?"list":"grid");return(s,u)=>a.value?(y(),z(ht,{key:0,modelValue:n.value,"onUpdate:modelValue":u[0]||(u[0]=S=>n.value=S),widget:s.widget,"node-type":s.widget.nodeType??s.nodeType,"asset-kind":p.value,"allow-upload":l.value,"upload-folder":f.value,"is-asset-mode":g.value,"default-layout-mode":o.value},null,8,["modelValue","widget","node-type","asset-kind","allow-upload","upload-folder","is-asset-mode","default-layout-mode"])):s.widget.controlWidget?(y(),z(Te,{key:1,modelValue:n.value,"onUpdate:modelValue":u[1]||(u[1]=S=>n.value=S),component:te,widget:s.widget},null,8,["modelValue","widget"])):(y(),z(te,{key:2,modelValue:n.value,"onUpdate:modelValue":u[2]||(u[2]=S=>n.value=S),widget:s.widget},null,8,["modelValue","widget"]))}}),Ot=St;export{Ot as t};
1
+ var ve=Object.defineProperty;var v=(t,e)=>ve(t,"name",{value:e,configurable:!0});import{et as oe,tt as ge}from"./vendor-primevue-DcMRXJN3.js";import{$o as W,Ba as k,Co as Z,Do as K,Ha as _,Jo as h,Ka as ye,Ko as R,Lr as we,Oo as be,Pa as G,Ua as $,Va as z,Wo as he,Xo as F,Ya as O,do as y,eo as Se,fo as ke,go as Me,mo as $e,no as P,po as ee,qa as T,ro as ae,wo as se,xo as A,za as d,zo as L}from"./vendor-other-DlQF6V2E.js";import{A as B,It as re,Lt as ne,r as De}from"./api-Dwq2LQIW.js";import{t as x}from"./src-DTrob8OL.js";import{t as xe}from"./Button-Do2I1OAA.js";import{Hn as Ce,Jn as Fe,Un as ie,or as Ae,qn as Ue,vn as Ie,yr as Ve}from"./dialogService-YG0RH337.js";import{i as de,o as ue}from"./widgetPropFilter-CKhENku4.js";import{t as ce}from"./layout-C9TPTaej.js";import{t as pe}from"./WidgetLayoutField-DXI3EnEF.js";import{i as ze,t as Oe}from"./LazyImage-D5qRMpUj.js";import{t as Te}from"./WidgetWithControl-Da6zUB5e.js";var Le={name:"SelectPlus",extends:ge,emits:["hide"],methods:{onOverlayLeave(){this.unbindOutsideClickListener(),this.unbindScrollListener(),this.unbindResizeListener(),this.$emit("hide"),this.overlay=null}}},_e=Le;function fe(t={}){return d(()=>({appendTo:"self",...t}))}v(fe,"useTransformCompatOverlayProps");var Pe={class:"absolute top-5 right-8 h-4 w-7 -translate-y-4/5 flex"},Be=O({__name:"WidgetSelectDefault",props:P({widget:{}},{modelValue:{default(t){return t.widget.options?.values?.[0]||""}},modelModifiers:{}}),emits:["update:modelValue"],setup(t){const e=t,n=A(t,"modelValue"),w=fe(),i=d(()=>{const a=e.widget.options;return a?.values&&Array.isArray(a.values)?a.values:[]}),g=d(()=>!!n.value&&!i.value.includes(n.value)),p=d(()=>({...ue(e.widget.options,de),...w.value,...g.value?{placeholder:`${n.value}`}:{}}));return(a,l)=>(y(),z(pe,{widget:a.widget},{default:K(()=>[T(_e,ae({modelValue:n.value,"onUpdate:modelValue":l[0]||(l[0]=f=>n.value=f),invalid:g.value,filter:i.value.length>4,"auto-filter-focus":"",options:i.value},p.value,{class:h(x)(h(ce),"w-full text-xs"),"aria-label":a.widget.name,size:"small",pt:{option:"text-xs",dropdown:"w-8",label:h(x)("truncate min-w-[4ch]",a.$slots.default&&"mr-5"),overlay:"w-fit min-w-full"},"data-capture-wheel":"true"}),null,16,["modelValue","invalid","filter","options","class","aria-label","pt"]),k("div",Pe,[$e(a.$slots,"default")])]),_:3},8,["widget"]))}}),te=Be,We={class:"min-w-0 flex-1 px-1 py-2 text-left truncate"},Qe={key:0},je={key:1},Re=["multiple","disabled","accept"],Ke=O({__name:"FormDropdownInput",props:{isOpen:{type:Boolean,default:!1},placeholder:{default:"Select..."},items:{},selected:{},maxSelectable:{},uploadable:{type:Boolean},disabled:{type:Boolean},accept:{}},emits:["select-click","file-change"],setup(t,{emit:e}){const n=t,w=e,i=d(()=>n.items.filter(p=>n.selected.has(p.id))),g=d(()=>x("border-0 bg-component-node-widget-background outline-none text-text-secondary",n.disabled?"cursor-not-allowed":"hover:bg-component-node-widget-background-hovered cursor-pointer",i.value.length>0&&"text-text-primary"));return(p,a)=>(y(),$("div",{class:F(h(x)(h(ce),"flex text-base leading-none",{"opacity-50 cursor-not-allowed !outline-zinc-300/10":p.disabled}))},[k("button",{class:F(h(x)(g.value,"flex justify-between items-center flex-1 min-w-0 h-8",{"rounded-l-lg":p.uploadable,"rounded-lg":!p.uploadable})),onClick:a[0]||(a[0]=l=>w("select-click",l))},[k("span",We,[i.value.length?(y(),$("span",je,W(i.value.map(l=>l.label??l.name).join(", ")),1)):(y(),$("span",Qe,W(p.placeholder),1))]),k("i",{class:F(["icon-[lucide--chevron-down]",h(x)("mr-2 size-4 transition-transform duration-200 flex-shrink-0 text-component-node-foreground-secondary",p.isOpen&&"rotate-180")])},null,2)],2),p.uploadable?(y(),$("label",{key:0,class:F(h(x)(g.value,"relative","size-8 flex justify-center items-center border-l rounded-r-lg border-zinc-300/10"))},[a[2]||(a[2]=k("i",{class:"icon-[lucide--folder-search] size-4"},null,-1)),k("input",{type:"file",class:"absolute inset-0 -z-1 opacity-0",multiple:p.maxSelectable>1,disabled:p.disabled,accept:p.accept,onChange:a[1]||(a[1]=l=>w("file-change",l))},null,40,Re)],2)):_("",!0)],2))}}),Ee=Ke,Ne={class:"text-secondary flex gap-2 px-4"},He={key:0,class:"absolute top-[-2px] left-[-2px] size-2 rounded-full bg-component-node-widget-background-highlighted"},qe=["onClick"],Je={key:0,class:"icon-[lucide--check] size-4"},q="bg-transparent border-0 outline-0 ring-0 text-left",le="size-6 flex justify-center items-center rounded-sm cursor-pointer transition-all duration-150 hover:scale-108 hover:text-base-foreground active:scale-95",Xe=O({__name:"FormDropdownMenuActions",props:P({searcher:{type:Function},sortOptions:{}},{layoutMode:{},layoutModeModifiers:{},searchQuery:{},searchQueryModifiers:{},sortSelected:{},sortSelectedModifiers:{}}),emits:["update:layoutMode","update:searchQuery","update:sortSelected"],setup(t){const e=A(t,"layoutMode"),n=A(t,"searchQuery"),w=A(t,"sortSelected"),i=x("h-8 bg-zinc-500/20 rounded-lg outline outline-1 outline-offset-[-1px] outline-node-component-border transition-all duration-150"),g=Z("sortPopoverRef"),p=Z("sortTriggerRef"),a=L(!1);function l(s){!g.value||!p.value||(a.value=!a.value,g.value.toggle(s,p.value))}v(l,"toggleSortPopover");function f(){a.value=!1,g.value?.hide()}v(f,"closeSortPopover");function o(s){w.value=s.id,f()}return v(o,"handleSortSelected"),(s,u)=>(y(),$("div",Ne,[T(ze,{modelValue:n.value,"onUpdate:modelValue":u[0]||(u[0]=S=>n.value=S),searcher:s.searcher,class:F(h(x)(h(i),"hover:outline-component-node-widget-background-highlighted/80","focus-within:outline-component-node-widget-background-highlighted/80 focus-within:ring-0"))},null,8,["modelValue","searcher","class"]),k("button",{ref_key:"sortTriggerRef",ref:p,class:F(h(x)(q,h(i),"relative w-8 flex justify-center items-center cursor-pointer","hover:outline-component-node-widget-background-highlighted","active:!scale-95")),onClick:l},[w.value!=="default"?(y(),$("div",He)):_("",!0),u[4]||(u[4]=k("i",{class:"icon-[lucide--arrow-up-down] size-4"},null,-1))],2),T(h(oe),{ref_key:"sortPopoverRef",ref:g,dismissable:!0,"close-on-escape":!0,unstyled:"",pt:{root:{class:"absolute z-50"},content:{class:["bg-transparent border-none p-0 pt-2 rounded-lg shadow-lg"]}},onHide:u[1]||(u[1]=S=>a.value=!1)},{default:K(()=>[k("div",{class:F(h(x)("flex flex-col gap-2 p-2 min-w-32","bg-component-node-background","rounded-lg outline outline-offset-[-1px] outline-component-node-border"))},[(y(!0),$(G,null,ee(s.sortOptions,S=>(y(),$("button",{key:S.name,class:F(h(x)(q,"flex justify-between items-center h-6 cursor-pointer","hover:!text-blue-500")),onClick:v(U=>o(S),"onClick")},[k("span",null,W(S.name),1),w.value===S.id?(y(),$("i",Je)):_("",!0)],10,qe))),128))],2)]),_:1},512),k("div",{class:F(h(x)(h(i),"flex justify-center items-center p-1 gap-1 hover:outline-component-node-widget-background-highlighted"))},[k("button",{class:F(h(x)(q,le,e.value==="list"?"bg-neutral-500/50 text-base-foreground":"")),onClick:u[2]||(u[2]=S=>e.value="list")},u[5]||(u[5]=[k("i",{class:"icon-[lucide--list] size-4"},null,-1)]),2),k("button",{class:F(h(x)(q,le,e.value==="grid"?"bg-neutral-500/50 text-base-foreground":"")),onClick:u[3]||(u[3]=S=>e.value="grid")},u[6]||(u[6]=[k("i",{class:"icon-[lucide--layout-grid] size-4"},null,-1)]),2)],2)]))}}),Ye=Xe,Ze={class:"text-secondary mb-4 flex gap-1 px-4 justify-start"},Ge=["disabled","onClick"],et=O({__name:"FormDropdownMenuFilter",props:P({filterOptions:{}},{filterSelected:{},filterSelectedModifiers:{}}),emits:["update:filterSelected"],setup(t){const e=A(t,"filterSelected"),{isUploadButtonEnabled:n,showUploadDialog:w}=Ce(),i=d(()=>t.filterOptions.length===1);return(g,p)=>(y(),$("div",Ze,[(y(!0),$(G,null,ee(g.filterOptions,a=>(y(),$("button",{key:a.id,type:"button",disabled:i.value,class:F(h(x)("px-4 py-2 rounded-md inline-flex justify-center items-center select-none appearance-none border-0 text-base-foreground",!i.value&&"transition-all duration-150 hover:text-base-foreground hover:bg-interface-menu-component-surface-hovered cursor-pointer active:scale-95",!i.value&&e.value===a.id?"!bg-interface-menu-component-surface-selected text-base-foreground":"bg-transparent")),onClick:v(l=>e.value=a.id,"onClick")},W(a.name),11,Ge))),128)),h(n)&&i.value?(y(),z(xe,{key:0,class:"ml-auto",size:"md",variant:"textonly",onClick:h(w)},{default:K(()=>[p[0]||(p[0]=k("i",{class:"icon-[lucide--folder-input]"},null,-1)),k("span",null,W(g.$t("g.import")),1)]),_:1},8,["onClick"])):_("",!0)]))}}),tt=et;const me=Symbol("assetKind");var lt={key:0,class:"absolute top-1 left-1 size-4 rounded-full border-1 border-base-foreground bg-primary-background"},ot=["src"],at={key:3,class:"size-full bg-gradient-to-tr from-blue-400 via-teal-500 to-green-400"},st={class:"text-secondary block text-xs"},rt=O({__name:"FormDropdownMenuItem",props:{index:{},selected:{type:Boolean},mediaSrc:{},name:{},label:{},metadata:{},layout:{}},emits:["click","mediaLoad"],setup(t,{emit:e}){const n=t,w=e,i=L(null),g=Se(me),p=d(()=>g?.value==="video");function a(){w("click",n.index)}v(a,"handleClick");function l(o){if(w("mediaLoad",o),!o.target||!(o.target instanceof HTMLImageElement))return;const s=o.target;s.naturalWidth&&s.naturalHeight&&(i.value=`${s.naturalWidth} x ${s.naturalHeight}`)}v(l,"handleImageLoad");function f(o){if(w("mediaLoad",o),!o.target||!(o.target instanceof HTMLVideoElement))return;const s=o.target;s.videoWidth&&s.videoHeight&&(i.value=`${s.videoWidth} x ${s.videoHeight}`)}return v(f,"handleVideoLoad"),(o,s)=>{const u=Me("tooltip");return y(),$("div",{class:F(h(x)("flex gap-1 select-none group/item cursor-pointer bg-component-node-widget-background","transition-all duration-150",{"flex-col text-center":o.layout==="grid","flex-row text-left max-h-16 rounded-lg hover:scale-102 active:scale-98":o.layout==="list","flex-row text-left hover:bg-component-node-widget-background-hovered rounded-lg":o.layout==="list-small","ring-2 ring-component-node-widget-background-highlighted":o.layout==="list"&&o.selected})),onClick:a},[o.layout!=="list-small"?(y(),$("div",{key:0,class:F(h(x)("relative","w-full aspect-square overflow-hidden outline-1 outline-offset-[-1px] outline-interface-stroke","transition-all duration-150",{"min-w-16 max-w-16 rounded-l-lg":o.layout==="list","rounded-sm group-hover/item:scale-108 group-active/item:scale-95":o.layout==="grid","ring-2 ring-component-node-widget-background-highlighted":o.layout==="grid"&&o.selected}))},[o.selected?(y(),$("div",lt,s[0]||(s[0]=[k("i",{class:"icon-[lucide--check] size-3 translate-y-[-0.5px] text-base-foreground bold"},null,-1)]))):_("",!0),o.mediaSrc&&p.value?(y(),$("video",{key:1,src:o.mediaSrc,class:"size-full object-cover",preload:"metadata",muted:"",onLoadeddata:f},null,40,ot)):o.mediaSrc?(y(),z(Oe,{key:2,src:o.mediaSrc,alt:o.name,"image-class":"size-full object-cover",onLoad:l},null,8,["src","alt"])):(y(),$("div",at))],2)):_("",!0),k("div",{class:F(h(x)("flex gap-1",{"flex-col":o.layout==="grid","flex-col px-4 py-1 w-full justify-center min-w-0":o.layout==="list","flex-row p-2 items-center justify-between w-full":o.layout==="list-small"}))},[be((y(),$("span",{class:F(h(x)("block text-xs line-clamp-2 break-words overflow-hidden","transition-colors duration-150",!!o.selected&&"text-base-foreground"))},[ye(W(o.label??o.name),1)],2)),[[u,o.layout==="grid"?o.label??o.name:void 0]]),k("span",st,W(o.metadata||i.value),1)],2)],2)}}}),nt=rt,it={class:"flex max-h-[640px] w-103 flex-col rounded-lg bg-component-node-background pt-4 outline outline-offset-[-1px] outline-node-component-border"},dt={class:"relative flex h-full mt-2 overflow-y-scroll"},ut={key:0,class:"h-50 col-span-full flex items-center justify-center"},ct=["title","aria-label"],pt=O({__name:"FormDropdownMenu",props:P({items:{},isSelected:{type:Function},filterOptions:{},sortOptions:{},searcher:{type:Function}},{filterSelected:{},filterSelectedModifiers:{},layoutMode:{},layoutModeModifiers:{},sortSelected:{},sortSelectedModifiers:{},searchQuery:{},searchQueryModifiers:{}}),emits:P(["item-click"],["update:filterSelected","update:layoutMode","update:sortSelected","update:searchQuery"]),setup(t,{emit:e}){const n=e,w=A(t,"filterSelected"),i=A(t,"layoutMode"),g=A(t,"sortSelected"),p=A(t,"searchQuery");return(a,l)=>(y(),$("div",it,[a.filterOptions.length>0?(y(),z(tt,{key:0,"filter-selected":w.value,"onUpdate:filterSelected":l[0]||(l[0]=f=>w.value=f),"filter-options":a.filterOptions},null,8,["filter-selected","filter-options"])):_("",!0),T(Ye,{"layout-mode":i.value,"onUpdate:layoutMode":l[1]||(l[1]=f=>i.value=f),"sort-selected":g.value,"onUpdate:sortSelected":l[2]||(l[2]=f=>g.value=f),"search-query":p.value,"onUpdate:searchQuery":l[3]||(l[3]=f=>p.value=f),"sort-options":a.sortOptions,searcher:a.searcher},null,8,["layout-mode","sort-selected","search-query","sort-options","searcher"]),k("div",dt,[k("div",{class:F(h(x)("h-full max-h-full grid gap-x-2 gap-y-4 overflow-y-auto px-4 pt-4 pb-4 w-full",{"grid-cols-4":i.value==="grid","grid-cols-1 gap-y-2":i.value==="list","grid-cols-1 gap-y-1":i.value==="list-small"}))},[l[4]||(l[4]=k("div",{class:"pointer-events-none absolute inset-x-3 top-0 z-10 h-5"},null,-1)),a.items.length===0?(y(),$("div",ut,[k("i",{title:a.$t("g.noItems"),"aria-label":a.$t("g.noItems"),class:"icon-[lucide--circle-off] size-30 text-zinc-500/20"},null,8,ct)])):_("",!0),(y(!0),$(G,null,ee(a.items,(f,o)=>(y(),z(nt,{key:f.id,index:o,selected:a.isSelected(f,o),"media-src":f.mediaSrc,name:f.name,label:f.label,metadata:f.metadata,layout:i.value,onClick:v(s=>n("item-click",f,o),"onClick")},null,8,["index","selected","media-src","name","label","metadata","layout","onClick"]))),128))],2)])]))}}),ft=pt;async function mt(t,e){if(t.trim()==="")return e;const n=t.trim().toLowerCase().split(" ");return e.filter(w=>{const i=w.name.toLowerCase();return n.every(g=>i.includes(g))})}v(mt,"defaultSearcher");function vt(){return[{name:"Default",id:"default",sorter:v(({items:t})=>t.slice(),"sorter")},{name:"A-Z",id:"a-z",sorter:v(({items:t})=>t.slice().sort((e,n)=>e.name.localeCompare(n.name)),"sorter")}]}v(vt,"getDefaultSortOptions");var gt=O({__name:"FormDropdown",props:P({items:{},placeholder:{default:B("widgets.uploadSelect.placeholder")},multiple:{type:[Boolean,Number],default:!1},uploadable:{type:Boolean,default:!1},disabled:{type:Boolean,default:!1},accept:{},filterOptions:{default:v(()=>[],"default")},sortOptions:{default:v(()=>vt(),"default")},isSelected:{type:Function,default:v((t,e,n)=>t.has(e.id),"default")},searcher:{type:Function,default:mt}},{selected:{default:new Set},selectedModifiers:{},filterSelected:{default:""},filterSelectedModifiers:{},sortSelected:{default:"default"},sortSelectedModifiers:{},layoutMode:{default:"grid"},layoutModeModifiers:{},files:{default:[]},filesModifiers:{},searchQuery:{default:""},searchQueryModifiers:{}}),emits:["update:selected","update:filterSelected","update:sortSelected","update:layoutMode","update:files","update:searchQuery"],setup(t){const e=t,n=A(t,"selected"),w=A(t,"filterSelected"),i=A(t,"sortSelected"),g=A(t,"layoutMode"),p=A(t,"files"),a=A(t,"searchQuery"),l=re(),f=L(),o=Z("triggerRef"),s=L(!1),u=d(()=>e.multiple===!0?1/0:typeof e.multiple=="number"?e.multiple:1),S=L([]),U=d(()=>e.sortOptions.find(b=>b.id==="default")?.sorter||(({items:b})=>b.slice())),j=d(()=>i.value==="default"?U.value:e.sortOptions.find(b=>b.id===i.value)?.sorter||U.value),I=d(()=>j.value({items:S.value})||[]);function V(b,M){return e.isSelected?.(n.value,b,M)??!1}v(V,"internalIsSelected");const J=v(b=>{e.disabled||f.value&&o.value&&(f.value.toggle(b,o.value),s.value=!s.value)},"toggleDropdown"),E=v(()=>{f.value&&(f.value.hide(),s.value=!1)},"closeDropdown");function N(b){if(e.disabled)return;const M=b.target;M.files&&(p.value=Array.from(M.files)),M.value=""}v(N,"handleFileChange");function X(b,M){if(e.disabled)return;const D=n.value;if(V(b,M))D.delete(b.id);else if(D.size<u.value)D.add(b.id);else if(u.value===1)D.clear(),D.add(b.id);else{l.addAlert("Maximum selection limit reached");return}n.value=new Set(D),u.value===1&&E()}v(X,"handleSelection");async function Y(b,M){let D=!1,c;M(()=>{D=!0,c?.()}),await e.searcher(b,e.items,r=>c=r).then(r=>{D||(S.value=r)})}return v(Y,"customSearcher"),(b,M)=>(y(),$("div",{ref_key:"triggerRef",ref:o},[T(Ee,{files:p.value,"is-open":s.value,placeholder:b.placeholder,items:b.items,"max-selectable":u.value,selected:n.value,uploadable:b.uploadable,disabled:b.disabled,accept:b.accept,onSelectClick:J,onFileChange:N},null,8,["files","is-open","placeholder","items","max-selectable","selected","uploadable","disabled","accept"]),T(h(oe),{ref_key:"popoverRef",ref:f,dismissable:!0,"close-on-escape":!0,unstyled:"",pt:{root:{class:"absolute z-50"},content:{class:["bg-transparent border-none p-0 pt-2 rounded-lg shadow-lg"]}},onHide:M[4]||(M[4]=D=>s.value=!1)},{default:K(()=>[T(ft,{"filter-selected":w.value,"onUpdate:filterSelected":M[0]||(M[0]=D=>w.value=D),"layout-mode":g.value,"onUpdate:layoutMode":M[1]||(M[1]=D=>g.value=D),"sort-selected":i.value,"onUpdate:sortSelected":M[2]||(M[2]=D=>i.value=D),"search-query":a.value,"onUpdate:searchQuery":M[3]||(M[3]=D=>a.value=D),"filter-options":b.filterOptions,"sort-options":b.sortOptions,disabled:b.disabled,searcher:Y,items:I.value,"is-selected":V,"max-selectable":u.value,onClose:E,onItemClick:X},null,8,["filter-selected","layout-mode","sort-selected","search-query","filter-options","sort-options","disabled","items","max-selectable"])]),_:1},512)],512))}}),yt=gt;function wt(t){if(ne){const e=ie(),n=Fe(),w=d(()=>{const l=R(t);return l?n.getCategoryForNodeType(l):void 0}),i=d(()=>{const l=R(t);return l?e.modelAssetsByNodeType.get(l)??[]:[]}),g=d(()=>{const l=R(t);return l?e.modelLoadingByNodeType.get(l)??!1:!1}),p=d(()=>{const l=R(t);return l?e.modelErrorByNodeType.get(l)??null:null}),a=d(()=>i.value.map(l=>({id:l.id,name:l.user_metadata?.filename??l.name,label:l.name,mediaSrc:l.preview_url??"",metadata:""})));return se(()=>R(t),async l=>{l&&(e.modelAssetsByNodeType.has(l)||await e.updateModelsForNodeType(l))},{immediate:!0}),{category:w,assets:i,dropdownItems:a,isLoading:g,error:p}}return{category:d(()=>{}),assets:d(()=>[]),dropdownItems:d(()=>[]),isLoading:d(()=>!1),error:d(()=>null)}}v(wt,"useAssetWidgetData");var bt=O({__name:"WidgetSelectDropdown",props:P({widget:{},nodeType:{},assetKind:{},allowUpload:{type:Boolean},uploadFolder:{},isAssetMode:{type:Boolean},defaultLayoutMode:{}},{modelValue:{default(t){return t.widget.options?.values?.[0]||""}},modelModifiers:{}}),emits:["update:modelValue"],setup(t){const e=t;ke(me,d(()=>e.assetKind));const n=A(t,"modelValue"),w=re(),i=Ie(),g=fe(),p=d(()=>({...ue(e.widget.options,de),...g.value})),l=v(()=>{const c=e.widget.options?.nodeType??e.nodeType;return e.isAssetMode&&c?wt(he(c)):null},"getAssetData")(),f=L("all"),o=d(()=>e.isAssetMode?[{id:"all",name:we(l?.category.value??"All")}]:[{id:"all",name:"All"},{id:"inputs",name:"Inputs"},{id:"outputs",name:"Outputs"}]),s=L(new Set);function u(c){const r=e.widget.options?.getOptionLabel;if(!r)return c;try{return r(c)}catch(m){return console.error("Failed to map value:",m),c}}v(u,"getDisplayLabel");const S=d(()=>{const c=e.widget.options?.values||[];return Array.isArray(c)?c.map((r,m)=>({id:`input-${m}`,mediaSrc:D(r,"input"),name:r,label:u(r),metadata:""})):[]}),U=d(()=>{if(!["image","video"].includes(e.assetKind??""))return[];const c=new Set;return i.historyTasks.forEach(r=>{r.flatOutputs.forEach(m=>{const C=e.assetKind==="image"&&m.mediaType==="images"||e.assetKind==="video"&&m.mediaType==="video";if(m.type==="output"&&C){const Q=`${m.subfolder?`${m.subfolder}/${m.filename}`:m.filename} [output]`;c.add(Q)}})}),Array.from(c).map(r=>({id:`output-${r}`,mediaSrc:D(r.replace(" [output]",""),"output"),name:r,label:u(r),metadata:""}))}),j=d(()=>e.isAssetMode&&l?l.dropdownItems.value:[...S.value,...U.value]),I=d(()=>{if(e.isAssetMode)return j.value;switch(f.value){case"inputs":return S.value;case"outputs":return U.value;case"all":default:return[...S.value,...U.value]}}),V=d(()=>{const c=e.widget.options;if(c?.placeholder)return c.placeholder;switch(e.assetKind){case"image":return B("widgets.uploadSelect.placeholderImage");case"video":return B("widgets.uploadSelect.placeholderVideo");case"audio":return B("widgets.uploadSelect.placeholderAudio");case"model":return B("widgets.uploadSelect.placeholderModel");case"unknown":return B("widgets.uploadSelect.placeholderUnknown")}return B("widgets.uploadSelect.placeholder")}),J=d(()=>e.isAssetMode?!1:e.allowUpload===!0),E=d(()=>{switch(e.assetKind){case"image":return"image/*";case"video":return"video/*";case"audio":return"audio/*";default:return}}),N=L(e.defaultLayoutMode??"grid");se([n,I],([c,r])=>{if(c===void 0){s.value.clear();return}const m=I.value.find(C=>C.name===c);m&&(s.value.clear(),s.value.add(m.id))},{immediate:!0});function X(c){let r;if(c.size>0&&(r=c.values().next().value),r==null){n.value=void 0;return}const m=I.value.find(C=>C.id===r)?.name;if(!m){n.value=void 0;return}n.value=m}v(X,"updateSelectedItems");const Y=v(async(c,r=!1,m={})=>{const C=new FormData;C.append("image",c),r&&C.append("subfolder","pasted"),m.type&&C.append("type",m.type);const Q=await De.fetchApi("/upload/image",{method:"POST",body:C});if(Q.status!==200)return w.addAlert(Q.status+" - "+Q.statusText),null;const H=await Q.json();return(m.type==="input"||!m.type&&!r)&&await ie().updateInputs(),H.subfolder?`${H.subfolder}/${H.name}`:H.name},"uploadFile"),b=v(async c=>{const r=e.uploadFolder??"input",m=c.map(C=>Y(C,!1,{type:r}));return(await Promise.all(m)).filter(C=>C!==null)},"uploadFiles");async function M(c){if(!(!c||c.length===0))try{const r=await b(c);if(r.length===0){w.addAlert("File upload failed");return}e.widget.options?.values&&r.forEach(m=>{const C=e.widget.options.values;C.includes(m)||C.push(m)}),n.value=r[0],e.widget.callback&&e.widget.callback(r[0])}catch(r){console.error("Upload error:",r),w.addAlert(`Upload failed: ${r}`)}}v(M,"handleFilesUpdate");function D(c,r="input"){return["image","video"].includes(e.assetKind??"")?`/api/view?filename=${encodeURIComponent(c)}&type=${r}`:""}return v(D,"getMediaUrl"),(c,r)=>(y(),z(pe,{widget:c.widget},{default:K(()=>[T(yt,ae({selected:s.value,"onUpdate:selected":r[0]||(r[0]=m=>s.value=m),"filter-selected":f.value,"onUpdate:filterSelected":r[1]||(r[1]=m=>f.value=m),"layout-mode":N.value,"onUpdate:layoutMode":r[2]||(r[2]=m=>N.value=m),items:I.value,placeholder:V.value,multiple:!1,uploadable:J.value,accept:E.value,"filter-options":o.value},p.value,{class:"w-full","onUpdate:selected":X,"onUpdate:files":M}),null,16,["selected","filter-selected","layout-mode","items","placeholder","uploadable","accept","filter-options"])]),_:1},8,["widget"]))}}),ht=bt,St=O({__name:"WidgetSelect",props:P({widget:{},nodeType:{}},{modelValue:{},modelModifiers:{}}),emits:["update:modelValue"],setup(t){const e=t,n=A(t,"modelValue"),w=d(()=>{if(e.widget.spec&&Ae(e.widget.spec))return e.widget.spec}),i=d(()=>{const s=w.value;if(!s)return{kind:"unknown",allowUpload:!1,folder:void 0};const{image_upload:u,animated_image_upload:S,video_upload:U,image_folder:j,audio_upload:I}=s;let V="unknown";return U?V="video":u||S?V="image":I&&(V="audio"),{kind:V,allowUpload:u===!0||S===!0||U===!0||I===!0,folder:j}}),g=d(()=>{if(ne){const s=Ve().get("Comfy.Assets.UseAssetAPI"),u=Ue.isAssetBrowserEligible(e.nodeType,e.widget.name)||e.widget.type==="asset";return s&&u}return!1}),p=d(()=>i.value.kind),a=d(()=>g.value||p.value!=="unknown"),l=d(()=>i.value.allowUpload),f=d(()=>i.value.folder??"input"),o=d(()=>g.value?"list":"grid");return(s,u)=>a.value?(y(),z(ht,{key:0,modelValue:n.value,"onUpdate:modelValue":u[0]||(u[0]=S=>n.value=S),widget:s.widget,"node-type":s.widget.nodeType??s.nodeType,"asset-kind":p.value,"allow-upload":l.value,"upload-folder":f.value,"is-asset-mode":g.value,"default-layout-mode":o.value},null,8,["modelValue","widget","node-type","asset-kind","allow-upload","upload-folder","is-asset-mode","default-layout-mode"])):s.widget.controlWidget?(y(),z(Te,{key:1,modelValue:n.value,"onUpdate:modelValue":u[1]||(u[1]=S=>n.value=S),component:te,widget:s.widget},null,8,["modelValue","widget"])):(y(),z(te,{key:2,modelValue:n.value,"onUpdate:modelValue":u[2]||(u[2]=S=>n.value=S),widget:s.widget},null,8,["modelValue","widget"]))}}),Ot=St;export{Ot as t};
2
2
 
3
- //# sourceMappingURL=WidgetSelect-zgrFVzHH.js.map
3
+ //# sourceMappingURL=WidgetSelect-nSQrk_hd.js.map