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.
- comfyui_frontend_package/static/assets/{AboutPanel-CHse5rOA.js → AboutPanel-lkjGFasi.js} +2 -2
- comfyui_frontend_package/static/assets/{AboutPanel-CHse5rOA.js.map → AboutPanel-lkjGFasi.js.map} +1 -1
- comfyui_frontend_package/static/assets/{AudioPreviewPlayer-CAa8V66L.js → AudioPreviewPlayer-BxCSKPl9.js} +2 -2
- comfyui_frontend_package/static/assets/{AudioPreviewPlayer-CAa8V66L.js.map → AudioPreviewPlayer-BxCSKPl9.js.map} +1 -1
- comfyui_frontend_package/static/assets/AudioPreviewPlayer-CkxKvcVf.js +1 -0
- comfyui_frontend_package/static/assets/{BaseViewTemplate-DA6zfigT.js → BaseViewTemplate-CjODF2hh.js} +2 -2
- comfyui_frontend_package/static/assets/{BaseViewTemplate-DA6zfigT.js.map → BaseViewTemplate-CjODF2hh.js.map} +1 -1
- comfyui_frontend_package/static/assets/{CloudAuthTimeoutView-9OPBS1hE.js → CloudAuthTimeoutView-D-QkjPNh.js} +2 -2
- comfyui_frontend_package/static/assets/{CloudAuthTimeoutView-9OPBS1hE.js.map → CloudAuthTimeoutView-D-QkjPNh.js.map} +1 -1
- comfyui_frontend_package/static/assets/{CloudBadge-BnLiAHDN.js → CloudBadge-B4nmLus2.js} +2 -2
- comfyui_frontend_package/static/assets/{CloudBadge-BnLiAHDN.js.map → CloudBadge-B4nmLus2.js.map} +1 -1
- comfyui_frontend_package/static/assets/{CloudForgotPasswordView-BqDR_C7K.js → CloudForgotPasswordView-DOEV9hGr.js} +2 -2
- comfyui_frontend_package/static/assets/{CloudForgotPasswordView-BqDR_C7K.js.map → CloudForgotPasswordView-DOEV9hGr.js.map} +1 -1
- comfyui_frontend_package/static/assets/{CloudLayoutView-vTrrVUOY.js → CloudLayoutView-ShKH6rRV.js} +2 -2
- comfyui_frontend_package/static/assets/{CloudLayoutView-vTrrVUOY.js.map → CloudLayoutView-ShKH6rRV.js.map} +1 -1
- comfyui_frontend_package/static/assets/{CloudLoginView-T17euJly.js → CloudLoginView-C3Te42U9.js} +2 -2
- comfyui_frontend_package/static/assets/{CloudLoginView-T17euJly.js.map → CloudLoginView-C3Te42U9.js.map} +1 -1
- comfyui_frontend_package/static/assets/CloudRunButtonWrapper-Cub7EB34.js +3 -0
- comfyui_frontend_package/static/assets/{CloudRunButtonWrapper-hQc4BNkX.js.map → CloudRunButtonWrapper-Cub7EB34.js.map} +1 -1
- comfyui_frontend_package/static/assets/{CloudSignupView-vEDby5k3.js → CloudSignupView-X2oiL3ZR.js} +2 -2
- comfyui_frontend_package/static/assets/{CloudSignupView-vEDby5k3.js.map → CloudSignupView-X2oiL3ZR.js.map} +1 -1
- comfyui_frontend_package/static/assets/{CloudSubscriptionRedirectView-DPyO745g.js → CloudSubscriptionRedirectView-UjNv8emo.js} +2 -2
- comfyui_frontend_package/static/assets/{CloudSubscriptionRedirectView-DPyO745g.js.map → CloudSubscriptionRedirectView-UjNv8emo.js.map} +1 -1
- comfyui_frontend_package/static/assets/{CloudSurveyView-CBtTd9Ru.js → CloudSurveyView-IaiucCTP.js} +2 -2
- comfyui_frontend_package/static/assets/{CloudSurveyView-CBtTd9Ru.js.map → CloudSurveyView-IaiucCTP.js.map} +1 -1
- comfyui_frontend_package/static/assets/ComfyQueueButton-BppnHbrl.js +1 -0
- comfyui_frontend_package/static/assets/{ComfyQueueButton-MZrp7wYJ.js → ComfyQueueButton-HjSIKZKO.js} +2 -2
- comfyui_frontend_package/static/assets/{ComfyQueueButton-MZrp7wYJ.js.map → ComfyQueueButton-HjSIKZKO.js.map} +1 -1
- comfyui_frontend_package/static/assets/{ExtensionPanel-CrWVGUtg.js → ExtensionPanel-Bzb9QtKj.js} +2 -2
- comfyui_frontend_package/static/assets/{ExtensionPanel-CrWVGUtg.js.map → ExtensionPanel-Bzb9QtKj.js.map} +1 -1
- comfyui_frontend_package/static/assets/{GlobalToast-BiCmpIvO.js → GlobalToast-BSCvu6Hw.js} +2 -2
- comfyui_frontend_package/static/assets/{GlobalToast-BiCmpIvO.js.map → GlobalToast-BSCvu6Hw.js.map} +1 -1
- comfyui_frontend_package/static/assets/{GraphView-BCkpNGgz.js → GraphView-gYVCtm1V.js} +5 -5
- comfyui_frontend_package/static/assets/GraphView-gYVCtm1V.js.map +1 -0
- comfyui_frontend_package/static/assets/{KeybindingPanel-CAXL5TlV.js → KeybindingPanel-DF-bG4iO.js} +2 -2
- comfyui_frontend_package/static/assets/{KeybindingPanel-CAXL5TlV.js.map → KeybindingPanel-DF-bG4iO.js.map} +1 -1
- comfyui_frontend_package/static/assets/{LegacyCreditsPanel-6vR8koQy.js → LegacyCreditsPanel-D-CboO8k.js} +2 -2
- comfyui_frontend_package/static/assets/{LegacyCreditsPanel-6vR8koQy.js.map → LegacyCreditsPanel-D-CboO8k.js.map} +1 -1
- comfyui_frontend_package/static/assets/Load3D-c9UwgGoI.js +1 -0
- comfyui_frontend_package/static/assets/{Load3D-ei1BUF9O.js → Load3D-vYr8M3jJ.js} +2 -2
- comfyui_frontend_package/static/assets/{Load3D-ei1BUF9O.js.map → Load3D-vYr8M3jJ.js.map} +1 -1
- comfyui_frontend_package/static/assets/{PanelTemplate-BjN5XNg2.js → PanelTemplate-BJda9e5J.js} +2 -2
- comfyui_frontend_package/static/assets/{PanelTemplate-BjN5XNg2.js.map → PanelTemplate-BJda9e5J.js.map} +1 -1
- comfyui_frontend_package/static/assets/{ServerConfigPanel-CxovH9Qk.js → ServerConfigPanel-VsC6xlZJ.js} +2 -2
- comfyui_frontend_package/static/assets/{ServerConfigPanel-CxovH9Qk.js.map → ServerConfigPanel-VsC6xlZJ.js.map} +1 -1
- comfyui_frontend_package/static/assets/{SubscribeButton-CTOQRkfg.js → SubscribeButton-DZBycfCA.js} +2 -2
- comfyui_frontend_package/static/assets/{SubscribeButton-CTOQRkfg.js.map → SubscribeButton-DZBycfCA.js.map} +1 -1
- comfyui_frontend_package/static/assets/{SubscribeToRun-DnXzV8y0.js → SubscribeToRun-4YolxBOL.js} +2 -2
- comfyui_frontend_package/static/assets/{SubscribeToRun-DnXzV8y0.js.map → SubscribeToRun-4YolxBOL.js.map} +1 -1
- comfyui_frontend_package/static/assets/{SubscriptionPanel-D9uv7z8f.js → SubscriptionPanel-B6txX4Vm.js} +2 -2
- comfyui_frontend_package/static/assets/{SubscriptionPanel-D9uv7z8f.js.map → SubscriptionPanel-B6txX4Vm.js.map} +1 -1
- comfyui_frontend_package/static/assets/{SubscriptionRequiredDialogContent--VmT16oc.js → SubscriptionRequiredDialogContent-COEF2VQ_.js} +2 -2
- comfyui_frontend_package/static/assets/{SubscriptionRequiredDialogContent--VmT16oc.js.map → SubscriptionRequiredDialogContent-COEF2VQ_.js.map} +1 -1
- comfyui_frontend_package/static/assets/{UserCheckView-spD3LyMu.js → UserCheckView-x-fkcYzc.js} +2 -2
- comfyui_frontend_package/static/assets/{UserCheckView-spD3LyMu.js.map → UserCheckView-x-fkcYzc.js.map} +1 -1
- comfyui_frontend_package/static/assets/{UserPanel-Su6NtJ5q.js → UserPanel-7N9QknQj.js} +2 -2
- comfyui_frontend_package/static/assets/{UserPanel-Su6NtJ5q.js.map → UserPanel-7N9QknQj.js.map} +1 -1
- comfyui_frontend_package/static/assets/{UserSelectView-C5LBOPcv.js → UserSelectView-BYjOkfSa.js} +2 -2
- comfyui_frontend_package/static/assets/{UserSelectView-C5LBOPcv.js.map → UserSelectView-BYjOkfSa.js.map} +1 -1
- comfyui_frontend_package/static/assets/{ValueControlPopover-BdlDzT8l.js → ValueControlPopover-BPAa35QG.js} +2 -2
- comfyui_frontend_package/static/assets/{ValueControlPopover-BdlDzT8l.js.map → ValueControlPopover-BPAa35QG.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetAudioUI-BDZxDx_r.js → WidgetAudioUI-Dw-r3Ews.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetAudioUI-BDZxDx_r.js.map → WidgetAudioUI-Dw-r3Ews.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetImageCrop-CYRW7t2Q.js → WidgetImageCrop-kERy9g5I.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetImageCrop-CYRW7t2Q.js.map → WidgetImageCrop-kERy9g5I.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetInputNumber-BOKO36G3.js → WidgetInputNumber-BaClCNAC.js} +1 -1
- comfyui_frontend_package/static/assets/WidgetInputNumber-DU_D0Fzy.js +3 -0
- comfyui_frontend_package/static/assets/WidgetInputNumber-DU_D0Fzy.js.map +1 -0
- comfyui_frontend_package/static/assets/{WidgetLegacy-Bslv9wZZ.js → WidgetLegacy-B4nipUM9.js} +1 -1
- comfyui_frontend_package/static/assets/{WidgetRecordAudio-Bzy8PIzN.js → WidgetRecordAudio-Nk8dH238.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetRecordAudio-Bzy8PIzN.js.map → WidgetRecordAudio-Nk8dH238.js.map} +1 -1
- comfyui_frontend_package/static/assets/WidgetSelect-DzZPpO_-.js +1 -0
- comfyui_frontend_package/static/assets/{WidgetSelect-zgrFVzHH.js → WidgetSelect-nSQrk_hd.js} +2 -2
- comfyui_frontend_package/static/assets/{WidgetSelect-zgrFVzHH.js.map → WidgetSelect-nSQrk_hd.js.map} +1 -1
- comfyui_frontend_package/static/assets/{WidgetWithControl-Dh2FWOiA.js → WidgetWithControl-Da6zUB5e.js} +3 -3
- comfyui_frontend_package/static/assets/{WidgetWithControl-Dh2FWOiA.js.map → WidgetWithControl-Da6zUB5e.js.map} +1 -1
- comfyui_frontend_package/static/assets/{api-CUAc7rDA.js → api-Dwq2LQIW.js} +4 -4
- comfyui_frontend_package/static/assets/api-Dwq2LQIW.js.map +1 -0
- comfyui_frontend_package/static/assets/{audioService-DvndbCi2.js → audioService-DvVaKhuU.js} +2 -2
- comfyui_frontend_package/static/assets/{audioService-DvndbCi2.js.map → audioService-DvVaKhuU.js.map} +1 -1
- comfyui_frontend_package/static/assets/{audioUtils-DpjpcKbH.js → audioUtils-DD4rUYVZ.js} +2 -2
- comfyui_frontend_package/static/assets/{audioUtils-DpjpcKbH.js.map → audioUtils-DD4rUYVZ.js.map} +1 -1
- comfyui_frontend_package/static/assets/{auth-B8ZZ0KKQ.js → auth-B9axG-yZ.js} +2 -2
- comfyui_frontend_package/static/assets/{auth-B8ZZ0KKQ.js.map → auth-B9axG-yZ.js.map} +1 -1
- comfyui_frontend_package/static/assets/auth-D74DTev8.js +1 -0
- comfyui_frontend_package/static/assets/{cloudBadges-C1a7fBky.js → cloudBadges-D5mGJbRy.js} +2 -2
- comfyui_frontend_package/static/assets/{cloudBadges-C1a7fBky.js.map → cloudBadges-D5mGJbRy.js.map} +1 -1
- comfyui_frontend_package/static/assets/{cloudFeedbackTopbarButton-DR0T8sWG.js → cloudFeedbackTopbarButton-RZUssOmb.js} +2 -2
- comfyui_frontend_package/static/assets/{cloudFeedbackTopbarButton-DR0T8sWG.js.map → cloudFeedbackTopbarButton-RZUssOmb.js.map} +1 -1
- comfyui_frontend_package/static/assets/{cloudRemoteConfig-DhMjC5TB.js → cloudRemoteConfig-F9J0iGyF.js} +2 -2
- comfyui_frontend_package/static/assets/{cloudRemoteConfig-DhMjC5TB.js.map → cloudRemoteConfig-F9J0iGyF.js.map} +1 -1
- comfyui_frontend_package/static/assets/{cloudSessionCookie-Duxk6ux1.js → cloudSessionCookie-MEORlqtg.js} +2 -2
- comfyui_frontend_package/static/assets/{cloudSessionCookie-Duxk6ux1.js.map → cloudSessionCookie-MEORlqtg.js.map} +1 -1
- comfyui_frontend_package/static/assets/{cloudSubscription-B8l6B9Nx.js → cloudSubscription-CuWNXKVx.js} +2 -2
- comfyui_frontend_package/static/assets/{cloudSubscription-B8l6B9Nx.js.map → cloudSubscription-CuWNXKVx.js.map} +1 -1
- comfyui_frontend_package/static/assets/{core-DBfeqMDR.js → core-IYu8XAIx.js} +4 -4
- comfyui_frontend_package/static/assets/{core-DBfeqMDR.js.map → core-IYu8XAIx.js.map} +1 -1
- comfyui_frontend_package/static/assets/{dialogService-BZ1FmjZL.js → dialogService-YG0RH337.js} +9 -9
- comfyui_frontend_package/static/assets/{dialogService-BZ1FmjZL.js.map → dialogService-YG0RH337.js.map} +1 -1
- comfyui_frontend_package/static/assets/firebaseAuthStore-DnNaPbuZ.js +1 -0
- comfyui_frontend_package/static/assets/{graphHasMissingNodes-C79Wi51S.js → graphHasMissingNodes-BhD1N6zI.js} +2 -2
- comfyui_frontend_package/static/assets/{graphHasMissingNodes-C79Wi51S.js.map → graphHasMissingNodes-BhD1N6zI.js.map} +1 -1
- comfyui_frontend_package/static/assets/{index-CGxJFSof.js → index-BMy3twho.js} +3 -3
- comfyui_frontend_package/static/assets/{index-CGxJFSof.js.map → index-BMy3twho.js.map} +1 -1
- comfyui_frontend_package/static/assets/{index-DNpOhRra.css → index-KMO9qFHH.css} +1 -1
- comfyui_frontend_package/static/assets/{keybindingService-B88NjeAU.js → keybindingService-CBLPjYHI.js} +2 -2
- comfyui_frontend_package/static/assets/{keybindingService-B88NjeAU.js.map → keybindingService-CBLPjYHI.js.map} +1 -1
- comfyui_frontend_package/static/assets/{releaseStore-x0vHjxrw.js → releaseStore-DDOxzkVb.js} +2 -2
- comfyui_frontend_package/static/assets/{releaseStore-x0vHjxrw.js.map → releaseStore-DDOxzkVb.js.map} +1 -1
- comfyui_frontend_package/static/assets/releaseStore-iVkqunL8.js +1 -0
- comfyui_frontend_package/static/assets/{subscriptionCheckoutUtil-B_OvUP2T.js → subscriptionCheckoutUtil-DswSOreM.js} +2 -2
- comfyui_frontend_package/static/assets/{subscriptionCheckoutUtil-B_OvUP2T.js.map → subscriptionCheckoutUtil-DswSOreM.js.map} +1 -1
- comfyui_frontend_package/static/assets/{useCurrentUser-BJcn2Vgo.js → useCurrentUser-NdaCJzIK.js} +1 -1
- comfyui_frontend_package/static/assets/{useErrorHandling-CI8_F4yx.js → useErrorHandling-Cfa5N_7c.js} +2 -2
- comfyui_frontend_package/static/assets/{useErrorHandling-CI8_F4yx.js.map → useErrorHandling-Cfa5N_7c.js.map} +1 -1
- comfyui_frontend_package/static/assets/{useSubscriptionDialog-Chxkdny5.js → useSubscriptionDialog-792qfEJ2.js} +3 -3
- comfyui_frontend_package/static/assets/{useSubscriptionDialog-Chxkdny5.js.map → useSubscriptionDialog-792qfEJ2.js.map} +1 -1
- comfyui_frontend_package/static/assets/useSubscriptionDialog-B-eGeK3j.js +1 -0
- comfyui_frontend_package/static/assets/{userStore-BkgQPjq6.js → userStore-BAS9m9W6.js} +2 -2
- comfyui_frontend_package/static/assets/{userStore-BkgQPjq6.js.map → userStore-BAS9m9W6.js.map} +1 -1
- comfyui_frontend_package/static/assets/vendor-three-BFcUNSs9.js.map +1 -1
- comfyui_frontend_package/static/index.html +1 -1
- {comfyui_frontend_package-1.38.5.dist-info → comfyui_frontend_package-1.38.6.dist-info}/METADATA +1 -1
- {comfyui_frontend_package-1.38.5.dist-info → comfyui_frontend_package-1.38.6.dist-info}/RECORD +126 -126
- comfyui_frontend_package/static/assets/AudioPreviewPlayer-BoEdyGI_.js +0 -1
- comfyui_frontend_package/static/assets/CloudRunButtonWrapper-hQc4BNkX.js +0 -3
- comfyui_frontend_package/static/assets/ComfyQueueButton-BbQnRThI.js +0 -1
- comfyui_frontend_package/static/assets/GraphView-BCkpNGgz.js.map +0 -1
- comfyui_frontend_package/static/assets/Load3D-DHBmC_AU.js +0 -1
- comfyui_frontend_package/static/assets/WidgetInputNumber-DGKypM5j.js +0 -3
- comfyui_frontend_package/static/assets/WidgetInputNumber-DGKypM5j.js.map +0 -1
- comfyui_frontend_package/static/assets/WidgetSelect-DsJGH12l.js +0 -1
- comfyui_frontend_package/static/assets/api-CUAc7rDA.js.map +0 -1
- comfyui_frontend_package/static/assets/auth-D3RiiqZ8.js +0 -1
- comfyui_frontend_package/static/assets/firebaseAuthStore-CZgxeMyf.js +0 -1
- comfyui_frontend_package/static/assets/releaseStore-CubqSv5t.js +0 -1
- comfyui_frontend_package/static/assets/useSubscriptionDialog-BzMzio2H.js +0 -1
- {comfyui_frontend_package-1.38.5.dist-info → comfyui_frontend_package-1.38.6.dist-info}/WHEEL +0 -0
- {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":"ValueControlPopover-
|
|
1
|
+
{"version":3,"file":"ValueControlPopover-BPAa35QG.js","names":[],"sources":["../../src/renderer/extensions/vueNodes/widgets/components/ValueControlPopover.vue","../../src/renderer/extensions/vueNodes/widgets/components/ValueControlPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport Popover from 'primevue/popover'\nimport RadioButton from 'primevue/radiobutton'\nimport { computed, ref } from 'vue'\n\nimport { useSettingStore } from '@/platform/settings/settingStore'\nimport type { ControlOptions } from '@/types/simplifiedWidget'\n\ntype ControlOption = {\n description: string\n mode: ControlOptions\n icon?: string\n text?: string\n title: string\n}\n\nconst popover = ref()\nconst settingStore = useSettingStore()\n\nconst toggle = (event: Event) => {\n popover.value.toggle(event)\n}\ndefineExpose({ toggle })\n\nconst controlOptions: ControlOption[] = [\n {\n mode: 'fixed',\n icon: 'icon-[lucide--pencil-off]',\n title: 'fixed',\n description: 'fixedDesc'\n },\n {\n mode: 'increment',\n text: '+1',\n title: 'increment',\n description: 'incrementDesc'\n },\n {\n mode: 'decrement',\n text: '-1',\n title: 'decrement',\n description: 'decrementDesc'\n },\n {\n mode: 'randomize',\n icon: 'icon-[lucide--shuffle]',\n title: 'randomize',\n description: 'randomizeDesc'\n }\n]\n\nconst widgetControlMode = computed(() =>\n settingStore.get('Comfy.WidgetControlMode')\n)\n\nconst controlMode = defineModel<ControlOptions>()\n</script>\n\n<template>\n <Popover\n ref=\"popover\"\n class=\"bg-interface-panel-surface border border-interface-stroke rounded-lg\"\n >\n <div class=\"w-113 max-w-md p-4 space-y-4\">\n <div class=\"text-sm text-muted-foreground leading-tight\">\n {{ $t('widgets.valueControl.header.prefix') }}\n <span class=\"text-base-foreground font-medium\">\n {{\n widgetControlMode === 'before'\n ? $t('widgets.valueControl.header.before')\n : $t('widgets.valueControl.header.after')\n }}\n </span>\n {{ $t('widgets.valueControl.header.postfix') }}\n </div>\n\n <div class=\"space-y-2\">\n <div\n v-for=\"option in controlOptions\"\n :key=\"option.mode\"\n class=\"flex items-center justify-between py-2 gap-7\"\n >\n <div class=\"flex items-center gap-2 flex-1 min-w-0\">\n <div\n class=\"flex items-center justify-center w-8 h-8 rounded-lg flex-shrink-0 bg-secondary-background border border-border-subtle\"\n >\n <i\n v-if=\"option.icon\"\n :class=\"option.icon\"\n class=\"text-base text-base-foreground\"\n />\n <span\n v-if=\"option.text\"\n class=\"text-xs font-normal text-base-foreground\"\n >\n {{ option.text }}\n </span>\n </div>\n\n <div class=\"flex flex-col gap-0.5 min-w-0 flex-1\">\n <div\n class=\"text-sm font-normal text-base-foreground leading-tight\"\n >\n <span>\n {{ $t(`widgets.valueControl.${option.title}`) }}\n </span>\n </div>\n <div\n class=\"text-sm font-normal text-muted-foreground leading-tight\"\n >\n {{ $t(`widgets.valueControl.${option.description}`) }}\n </div>\n </div>\n </div>\n\n <RadioButton\n v-model=\"controlMode\"\n class=\"flex-shrink-0\"\n :input-id=\"option.mode\"\n :value=\"option.mode\"\n />\n </div>\n </div>\n </div>\n </Popover>\n</template>\n","<script setup lang=\"ts\">\nimport Popover from 'primevue/popover'\nimport RadioButton from 'primevue/radiobutton'\nimport { computed, ref } from 'vue'\n\nimport { useSettingStore } from '@/platform/settings/settingStore'\nimport type { ControlOptions } from '@/types/simplifiedWidget'\n\ntype ControlOption = {\n description: string\n mode: ControlOptions\n icon?: string\n text?: string\n title: string\n}\n\nconst popover = ref()\nconst settingStore = useSettingStore()\n\nconst toggle = (event: Event) => {\n popover.value.toggle(event)\n}\ndefineExpose({ toggle })\n\nconst controlOptions: ControlOption[] = [\n {\n mode: 'fixed',\n icon: 'icon-[lucide--pencil-off]',\n title: 'fixed',\n description: 'fixedDesc'\n },\n {\n mode: 'increment',\n text: '+1',\n title: 'increment',\n description: 'incrementDesc'\n },\n {\n mode: 'decrement',\n text: '-1',\n title: 'decrement',\n description: 'decrementDesc'\n },\n {\n mode: 'randomize',\n icon: 'icon-[lucide--shuffle]',\n title: 'randomize',\n description: 'randomizeDesc'\n }\n]\n\nconst widgetControlMode = computed(() =>\n settingStore.get('Comfy.WidgetControlMode')\n)\n\nconst controlMode = defineModel<ControlOptions>()\n</script>\n\n<template>\n <Popover\n ref=\"popover\"\n class=\"bg-interface-panel-surface border border-interface-stroke rounded-lg\"\n >\n <div class=\"w-113 max-w-md p-4 space-y-4\">\n <div class=\"text-sm text-muted-foreground leading-tight\">\n {{ $t('widgets.valueControl.header.prefix') }}\n <span class=\"text-base-foreground font-medium\">\n {{\n widgetControlMode === 'before'\n ? $t('widgets.valueControl.header.before')\n : $t('widgets.valueControl.header.after')\n }}\n </span>\n {{ $t('widgets.valueControl.header.postfix') }}\n </div>\n\n <div class=\"space-y-2\">\n <div\n v-for=\"option in controlOptions\"\n :key=\"option.mode\"\n class=\"flex items-center justify-between py-2 gap-7\"\n >\n <div class=\"flex items-center gap-2 flex-1 min-w-0\">\n <div\n class=\"flex items-center justify-center w-8 h-8 rounded-lg flex-shrink-0 bg-secondary-background border border-border-subtle\"\n >\n <i\n v-if=\"option.icon\"\n :class=\"option.icon\"\n class=\"text-base text-base-foreground\"\n />\n <span\n v-if=\"option.text\"\n class=\"text-xs font-normal text-base-foreground\"\n >\n {{ option.text }}\n </span>\n </div>\n\n <div class=\"flex flex-col gap-0.5 min-w-0 flex-1\">\n <div\n class=\"text-sm font-normal text-base-foreground leading-tight\"\n >\n <span>\n {{ $t(`widgets.valueControl.${option.title}`) }}\n </span>\n </div>\n <div\n class=\"text-sm font-normal text-muted-foreground leading-tight\"\n >\n {{ $t(`widgets.valueControl.${option.description}`) }}\n </div>\n </div>\n </div>\n\n <RadioButton\n v-model=\"controlMode\"\n class=\"flex-shrink-0\"\n :input-id=\"option.mode\"\n :value=\"option.mode\"\n />\n </div>\n </div>\n </div>\n </Popover>\n</template>\n"],"mappings":"86CCgBA,MAAM,EAAU,EAAA,EACV,EAAe,EAAA,EAKrB,EAAa,CAAE,OAHT,EAAU,GAAiB,CAC/B,EAAQ,MAAM,OAAO,CAAA,GADjB,SAGS,CAAQ,EAEvB,MAAM,EAAkC,CACtC,CACE,KAAM,QACN,KAAM,4BACN,MAAO,QACP,YAAa,aAEf,CACE,KAAM,YACN,KAAM,KACN,MAAO,YACP,YAAa,iBAEf,CACE,KAAM,YACN,KAAM,KACN,MAAO,YACP,YAAa,iBAEf,CACE,KAAM,YACN,KAAM,yBACN,MAAO,YACP,YAAa,kBAIX,EAAoB,EAAA,IACxB,EAAa,IAAI,yBAAA,CAAyB,EAGtC,EAAc,EAA2B,EAAA,YAAA"}
|
comfyui_frontend_package/static/assets/{WidgetAudioUI-BDZxDx_r.js → WidgetAudioUI-Dw-r3Ews.js}
RENAMED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import"./vendor-primevue-DcMRXJN3.js";import{Ua as g,Ya as f,do as v,no as i,qa as l,xo as _,za as o}from"./vendor-other-DlQF6V2E.js";import"./api-
|
|
1
|
+
import"./vendor-primevue-DcMRXJN3.js";import{Ua as g,Ya as f,do as v,no as i,qa as l,xo as _,za as o}from"./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{P as u}from"./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{n as h}from"./audioUtils-DD4rUYVZ.js";import{n as w}from"./nodeFilterUtil-BYFD-MqA.js";import{t as y}from"./WidgetSelect-nSQrk_hd.js";import"./widgetPropFilter-CKhENku4.js";import"./layout-C9TPTaej.js";import"./LazyImage-D5qRMpUj.js";import"./WidgetWithControl-Da6zUB5e.js";import{t as V}from"./AudioPreviewPlayer-BxCSKPl9.js";var x={class:"w-full col-span-2 widget-expands grid grid-cols-[minmax(80px,max-content)_minmax(125px,auto)] gap-y-3 p-3"},I=f({__name:"WidgetAudioUI",props:i({widget:{},readonly:{type:Boolean},nodeId:{}},{modelValue:{},modelModifiers:{}}),emits:i(["update:modelValue"],["update:modelValue"]),setup(a){const t=a,r=_(a,"modelValue"),p=o(()=>!t.nodeId||!u.canvas.graph?null:u.canvas.graph.getNodeById(t.nodeId)),n=o(()=>{const e=p.value;return e?w(e):!1}),m=o(()=>t.widget.value),s=o(()=>{const e=m.value;return e?h(e,"input"):""});return(e,d)=>(v(),g("div",x,[l(y,{modelValue:r.value,"onUpdate:modelValue":d[0]||(d[0]=c=>r.value=c),widget:e.widget,class:"col-span-2"},null,8,["modelValue","widget"]),l(V,{class:"col-span-2","audio-url":s.value,readonly:e.readonly,"hide-when-empty":n.value,"show-options-button":!0},null,8,["audio-url","readonly","hide-when-empty"])]))}}),J=I;export{J as default};
|
|
2
2
|
|
|
3
|
-
//# sourceMappingURL=WidgetAudioUI-
|
|
3
|
+
//# sourceMappingURL=WidgetAudioUI-Dw-r3Ews.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetAudioUI-
|
|
1
|
+
{"version":3,"file":"WidgetAudioUI-Dw-r3Ews.js","names":[],"sources":["../../src/renderer/extensions/vueNodes/widgets/components/WidgetAudioUI.vue","../../src/renderer/extensions/vueNodes/widgets/components/WidgetAudioUI.vue"],"sourcesContent":["<template>\n <div\n class=\"w-full col-span-2 widget-expands grid grid-cols-[minmax(80px,max-content)_minmax(125px,auto)] gap-y-3 p-3\"\n >\n <WidgetSelect v-model=\"modelValue\" :widget class=\"col-span-2\" />\n <AudioPreviewPlayer\n class=\"col-span-2\"\n :audio-url=\"audioUrlFromWidget\"\n :readonly=\"readonly\"\n :hide-when-empty=\"isOutputNodeRef\"\n :show-options-button=\"true\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type { LGraphNode } from '@/lib/litegraph/src/litegraph'\nimport { app } from '@/scripts/app'\nimport type { SimplifiedWidget } from '@/types/simplifiedWidget'\nimport { isOutputNode } from '@/utils/nodeFilterUtil'\n\nimport { getAudioUrlFromPath } from '../utils/audioUtils'\nimport WidgetSelect from './WidgetSelect.vue'\nimport AudioPreviewPlayer from './audio/AudioPreviewPlayer.vue'\n\nconst props = defineProps<{\n widget: SimplifiedWidget<string | undefined>\n readonly?: boolean\n nodeId: string\n}>()\n\nconst modelValue = defineModel<string>('modelValue')\n\ndefineEmits<{\n 'update:modelValue': [value: string]\n}>()\n\n// Get litegraph node\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\n// Check if this is an output node (PreviewAudio, SaveAudio, etc)\nconst isOutputNodeRef = computed(() => {\n const node = litegraphNode.value\n if (!node) return false\n return isOutputNode(node)\n})\n\nconst audioFilePath = computed(() => props.widget.value as string)\n\n// Computed audio URL from widget value (for input files)\nconst audioUrlFromWidget = computed(() => {\n const path = audioFilePath.value\n if (!path) return ''\n return getAudioUrlFromPath(path, 'input')\n})\n</script>\n","<template>\n <div\n class=\"w-full col-span-2 widget-expands grid grid-cols-[minmax(80px,max-content)_minmax(125px,auto)] gap-y-3 p-3\"\n >\n <WidgetSelect v-model=\"modelValue\" :widget class=\"col-span-2\" />\n <AudioPreviewPlayer\n class=\"col-span-2\"\n :audio-url=\"audioUrlFromWidget\"\n :readonly=\"readonly\"\n :hide-when-empty=\"isOutputNodeRef\"\n :show-options-button=\"true\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type { LGraphNode } from '@/lib/litegraph/src/litegraph'\nimport { app } from '@/scripts/app'\nimport type { SimplifiedWidget } from '@/types/simplifiedWidget'\nimport { isOutputNode } from '@/utils/nodeFilterUtil'\n\nimport { getAudioUrlFromPath } from '../utils/audioUtils'\nimport WidgetSelect from './WidgetSelect.vue'\nimport AudioPreviewPlayer from './audio/AudioPreviewPlayer.vue'\n\nconst props = defineProps<{\n widget: SimplifiedWidget<string | undefined>\n readonly?: boolean\n nodeId: string\n}>()\n\nconst modelValue = defineModel<string>('modelValue')\n\ndefineEmits<{\n 'update:modelValue': [value: string]\n}>()\n\n// Get litegraph node\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\n// Check if this is an output node (PreviewAudio, SaveAudio, etc)\nconst isOutputNodeRef = computed(() => {\n const node = litegraphNode.value\n if (!node) return false\n return isOutputNode(node)\n})\n\nconst audioFilePath = computed(() => props.widget.value as string)\n\n// Computed audio URL from widget value (for input files)\nconst audioUrlFromWidget = computed(() => {\n const path = audioFilePath.value\n if (!path) return ''\n return getAudioUrlFromPath(path, 'input')\n})\n</script>\n"],"mappings":"2qCC2BA,MAAM,EAAQ,EAMR,EAAa,EAAmB,EAAC,YAAA,EAOjC,EAAgB,EAAA,IAChB,CAAC,EAAM,QAAU,CAAC,EAAI,OAAO,MAAc,KACxC,EAAI,OAAO,MAAM,YAAY,EAAM,MAAA,GAItC,EAAkB,EAAA,IAAe,CACrC,MAAM,EAAO,EAAc,MAC3B,OAAK,EACE,EAAa,CAAA,EADF,KAId,EAAgB,EAAA,IAAe,EAAM,OAAO,KAAA,EAG5C,EAAqB,EAAA,IAAe,CACxC,MAAM,EAAO,EAAc,MAC3B,OAAK,EACE,EAAoB,EAAM,OAAA,EADf"}
|
comfyui_frontend_package/static/assets/{WidgetImageCrop-CYRW7t2Q.js → WidgetImageCrop-kERy9g5I.js}
RENAMED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var be=Object.defineProperty;var o=(M,k)=>be(M,"name",{value:k,configurable:!0});import"./vendor-primevue-DcMRXJN3.js";import{$o as ce,Aa as De,Ba as L,Co as pe,Ha as Xe,Jo as n,Ma as Z,Oo as Re,Pa as Ye,Pi as ke,Qo as J,Ua as D,Xo as We,Ya as Be,co as He,do as X,no as Oe,po as Ne,qa as Ve,wo as me,xo as Le,za as R,zo as s}from"./vendor-other-DlQF6V2E.js";import"./api-
|
|
1
|
+
var be=Object.defineProperty;var o=(M,k)=>be(M,"name",{value:k,configurable:!0});import"./vendor-primevue-DcMRXJN3.js";import{$o as ce,Aa as De,Ba as L,Co as pe,Ha as Xe,Jo as n,Ma as Z,Oo as Re,Pa as Ye,Pi as ke,Qo as J,Ua as D,Xo as We,Ya as Be,co as He,do as X,no as Oe,po as Ne,qa as Ve,wo as me,xo as Le,za as R,zo as s}from"./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{P as Ue,ut as Ae}from"./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 je}from"./WidgetBoundingBox-mqU1kZgk.js";var d=8,u=10,_=16,ge=2;function Ze(M,k){const{imageEl:S,containerEl:I,modelValue:c}=k,w=Ae(),C=s(null),h=s(null),W=s(!1),p=s(0),$=s(0),m=s(0),E=s(0),i=s(1),P=s(0),Y=s(0),g=R({get:o(()=>c.value.x,"get"),set:o(e=>{c.value.x=e},"set")}),f=R({get:o(()=>c.value.y,"get"),set:o(e=>{c.value.y=e},"set")}),x=R({get:o(()=>c.value.width||512,"get"),set:o(e=>{c.value.width=e},"set")}),t=R({get:o(()=>c.value.height||512,"get"),set:o(e=>{c.value.height=e},"set")}),r=s(!1),y=s(0),Q=s(0),K=s(0),ee=s(0),U=s(!1),A=s(null),te=s(0),ae=s(0),B=s(0),H=s(0),O=s(0),N=s(0);ke(I,()=>{S.value&&h.value&&le()});const fe=o(()=>{if(!C.value)return null;const e=C.value.getInputNode(0);if(!e)return null;const l=w.getNodeImageUrls(e);return l?.length?l[0]:null},"getInputImageUrl"),F=o(()=>{h.value=fe()},"updateImageUrl"),le=o(()=>{if(!S.value||!I.value)return;const e=S.value,l=I.value;if(p.value=e.naturalWidth,$.value=e.naturalHeight,p.value<=0||$.value<=0){i.value=1;return}const a=l.clientWidth,v=l.clientHeight,z=p.value/$.value;z>a/v?(m.value=a,E.value=a/z,P.value=0,Y.value=(v-E.value)/2):(E.value=v,m.value=v*z,P.value=(a-m.value)/2,Y.value=0),p.value<=0||m.value<=0?i.value=1:i.value=m.value/p.value},"updateDisplayedDimensions"),oe=o(()=>{const e=I.value;if(!e||p.value<=0||m.value<=0)return 1;const l=e.getBoundingClientRect(),a=e.clientWidth;return!a||!l.width?1:m.value/a*l.width/p.value},"getEffectiveScale"),he=R(()=>({left:`${P.value+g.value*i.value-ge}px`,top:`${Y.value+f.value*i.value-ge}px`,width:`${x.value*i.value}px`,height:`${t.value*i.value}px`})),xe=R(()=>h.value?{backgroundImage:`url(${h.value})`,backgroundSize:`${m.value}px ${E.value}px`,backgroundPosition:`-${g.value*i.value}px -${f.value*i.value}px`,backgroundRepeat:"no-repeat"}:{}),we=R(()=>{const e=P.value+g.value*i.value,l=Y.value+f.value*i.value,a=x.value*i.value,v=t.value*i.value;return[{direction:"top",class:"h-2 cursor-ns-resize",style:{left:`${e+d}px`,top:`${l-d/2}px`,width:`${Math.max(0,a-d*2)}px`}},{direction:"bottom",class:"h-2 cursor-ns-resize",style:{left:`${e+d}px`,top:`${l+v-d/2}px`,width:`${Math.max(0,a-d*2)}px`}},{direction:"left",class:"w-2 cursor-ew-resize",style:{left:`${e-d/2}px`,top:`${l+d}px`,height:`${Math.max(0,v-d*2)}px`}},{direction:"right",class:"w-2 cursor-ew-resize",style:{left:`${e+a-d/2}px`,top:`${l+d}px`,height:`${Math.max(0,v-d*2)}px`}},{direction:"nw",class:"cursor-nwse-resize rounded-sm bg-white/80",style:{left:`${e-u/2}px`,top:`${l-u/2}px`,width:`${u}px`,height:`${u}px`}},{direction:"ne",class:"cursor-nesw-resize rounded-sm bg-white/80",style:{left:`${e+a-u/2}px`,top:`${l-u/2}px`,width:`${u}px`,height:`${u}px`}},{direction:"sw",class:"cursor-nesw-resize rounded-sm bg-white/80",style:{left:`${e-u/2}px`,top:`${l+v-u/2}px`,width:`${u}px`,height:`${u}px`}},{direction:"se",class:"cursor-nwse-resize rounded-sm bg-white/80",style:{left:`${e+a-u/2}px`,top:`${l+v-u/2}px`,width:`${u}px`,height:`${u}px`}}]}),$e=o(()=>{W.value=!1,le()},"handleImageLoad"),ye=o(()=>{W.value=!1,h.value=null},"handleImageError"),ne=o(e=>e.target.setPointerCapture(e.pointerId),"capturePointer"),se=o(e=>e.target.releasePointerCapture(e.pointerId),"releasePointer"),ze=o(e=>{h.value&&(r.value=!0,y.value=e.clientX,Q.value=e.clientY,K.value=g.value,ee.value=f.value,ne(e))},"handleDragStart"),Me=o(e=>{if(!r.value)return;const l=oe();if(l===0)return;const a=(e.clientX-y.value)/l,v=(e.clientY-Q.value)/l,z=p.value-x.value,j=$.value-t.value;g.value=Math.round(Math.max(0,Math.min(z,K.value+a))),f.value=Math.round(Math.max(0,Math.min(j,ee.value+v)))},"handleDragMove"),Se=o(e=>{r.value&&(r.value=!1,se(e))},"handleDragEnd"),Ie=o((e,l)=>{h.value&&(e.stopPropagation(),U.value=!0,A.value=l,te.value=e.clientX,ae.value=e.clientY,B.value=g.value,H.value=f.value,O.value=x.value,N.value=t.value,ne(e))},"handleResizeStart"),Ce=o(e=>{if(!U.value||!A.value)return;const l=oe();if(l===0)return;const a=A.value,v=(e.clientX-te.value)/l,z=(e.clientY-ae.value)/l,j=a==="left"||a==="nw"||a==="sw",re=a==="right"||a==="ne"||a==="se",ie=a==="top"||a==="nw"||a==="ne",ue=a==="bottom"||a==="sw"||a==="se";let ve=B.value,de=H.value,T=O.value,q=N.value;if(j){const b=O.value-_,G=-B.value,V=Math.max(G,Math.min(b,v));ve=B.value+V,T=O.value-V}else if(re){const b=p.value-B.value;T=Math.max(_,Math.min(b,O.value+v))}if(ie){const b=N.value-_,G=-H.value,V=Math.max(G,Math.min(b,z));de=H.value+V,q=N.value-V}else if(ue){const b=$.value-H.value;q=Math.max(_,Math.min(b,N.value+z))}(j||re)&&(g.value=Math.round(ve),x.value=Math.round(T)),(ie||ue)&&(f.value=Math.round(de),t.value=Math.round(q))},"handleResizeMove"),Ee=o(e=>{U.value&&(U.value=!1,A.value=null,se(e))},"handleResizeEnd"),Pe=o(()=>{M!=null&&(C.value=Ue.rootGraph?.getNodeById(M)||null),F()},"initialize");return me(()=>w.nodeOutputs,()=>F(),{deep:!0}),me(()=>w.nodePreviewImages,()=>F(),{deep:!0}),He(Pe),{imageUrl:h,isLoading:W,cropX:g,cropY:f,cropWidth:x,cropHeight:t,cropBoxStyle:he,cropImageStyle:xe,resizeHandles:we,handleImageLoad:$e,handleImageError:ye,handleDragStart:ze,handleDragMove:Me,handleDragEnd:Se,handleResizeStart:Ie,handleResizeMove:Ce,handleResizeEnd:Ee}}o(Ze,"useImageCrop");var _e={key:0,class:"flex size-full items-center justify-center"},Fe={class:"text-sm"},Te={key:1,class:"flex size-full flex-col items-center justify-center text-center"},qe={class:"text-sm"},Ge=["src","alt"],Je=["onPointerdown"],Qe=Be({__name:"WidgetImageCrop",props:Oe({nodeId:{}},{modelValue:{default:o(()=>({x:0,y:0,width:512,height:512}),"default")},modelModifiers:{}}),emits:["update:modelValue"],setup(M){const k=M,S=Le(M,"modelValue"),I=pe("imageEl"),c=pe("containerEl"),{imageUrl:w,isLoading:C,cropBoxStyle:h,cropImageStyle:W,resizeHandles:p,handleImageLoad:$,handleImageError:m,handleDragStart:E,handleDragMove:i,handleDragEnd:P,handleResizeStart:Y,handleResizeMove:g,handleResizeEnd:f}=Ze(k.nodeId,{imageEl:I,containerEl:c,modelValue:S});return(x,t)=>(X(),D("div",{class:"widget-expands relative flex h-full w-full flex-col gap-1",onPointerdown:t[9]||(t[9]=Z(()=>{},["stop"])),onPointermove:t[10]||(t[10]=Z(()=>{},["stop"])),onPointerup:t[11]||(t[11]=Z(()=>{},["stop"]))},[L("div",{ref_key:"containerEl",ref:c,class:"relative min-h-0 flex-1 overflow-hidden rounded-[5px] bg-node-component-surface"},[n(C)?(X(),D("div",_e,[L("span",Fe,ce(x.$t("imageCrop.loading")),1)])):n(w)?(X(),D("img",{key:2,ref_key:"imageEl",ref:I,src:n(w),alt:x.$t("imageCrop.cropPreviewAlt"),draggable:"false",class:"block size-full object-contain select-none brightness-50",onLoad:t[0]||(t[0]=(...r)=>n($)&&n($)(...r)),onError:t[1]||(t[1]=(...r)=>n(m)&&n(m)(...r)),onDragstart:t[2]||(t[2]=Z(()=>{},["prevent"]))},null,40,Ge)):(X(),D("div",Te,[t[12]||(t[12]=L("i",{class:"mb-2 icon-[lucide--image] h-12 w-12"},null,-1)),L("p",qe,ce(x.$t("imageCrop.noInputImage")),1)])),n(w)&&!n(C)?(X(),D("div",{key:3,class:"absolute box-content cursor-move overflow-hidden border-2 border-white",style:J(n(h)),onPointerdown:t[3]||(t[3]=(...r)=>n(E)&&n(E)(...r)),onPointermove:t[4]||(t[4]=(...r)=>n(i)&&n(i)(...r)),onPointerup:t[5]||(t[5]=(...r)=>n(P)&&n(P)(...r))},[L("div",{class:"pointer-events-none size-full",style:J(n(W))},null,4)],36)):Xe("",!0),(X(!0),D(Ye,null,Ne(n(p),r=>Re((X(),D("div",{key:r.direction,class:We(["absolute",r.class]),style:J(r.style),onPointerdown:o(y=>n(Y)(y,r.direction),"onPointerdown"),onPointermove:t[6]||(t[6]=(...y)=>n(g)&&n(g)(...y)),onPointerup:t[7]||(t[7]=(...y)=>n(f)&&n(f)(...y))},null,46,Je)),[[De,n(w)&&!n(C)]])),128))],512),Ve(je,{modelValue:S.value,"onUpdate:modelValue":t[8]||(t[8]=r=>S.value=r),class:"shrink-0"},null,8,["modelValue"])],32))}}),gt=Qe;export{gt as default};
|
|
2
2
|
|
|
3
|
-
//# sourceMappingURL=WidgetImageCrop-
|
|
3
|
+
//# sourceMappingURL=WidgetImageCrop-kERy9g5I.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetImageCrop-CYRW7t2Q.js","names":[],"sources":["../../src/composables/useImageCrop.ts","../../src/components/imagecrop/WidgetImageCrop.vue","../../src/components/imagecrop/WidgetImageCrop.vue"],"sourcesContent":["import { useResizeObserver } from '@vueuse/core'\nimport type { Ref } from 'vue'\nimport { computed, onMounted, ref, watch } from 'vue'\n\nimport type { LGraphNode, NodeId } from '@/lib/litegraph/src/LGraphNode'\nimport type { Bounds } from '@/renderer/core/layout/types'\nimport { app } from '@/scripts/app'\nimport { useNodeOutputStore } from '@/stores/imagePreviewStore'\n\ntype ResizeDirection =\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'nw'\n | 'ne'\n | 'sw'\n | 'se'\n\nconst HANDLE_SIZE = 8\nconst CORNER_SIZE = 10\nconst MIN_CROP_SIZE = 16\nconst CROP_BOX_BORDER = 2\n\ninterface UseImageCropOptions {\n imageEl: Ref<HTMLImageElement | null>\n containerEl: Ref<HTMLDivElement | null>\n modelValue: Ref<Bounds>\n}\n\nexport function useImageCrop(nodeId: NodeId, options: UseImageCropOptions) {\n const { imageEl, containerEl, modelValue } = options\n const nodeOutputStore = useNodeOutputStore()\n\n const node = ref<LGraphNode | null>(null)\n\n const imageUrl = ref<string | null>(null)\n const isLoading = ref(false)\n\n const naturalWidth = ref(0)\n const naturalHeight = ref(0)\n const displayedWidth = ref(0)\n const displayedHeight = ref(0)\n const scaleFactor = ref(1)\n const imageOffsetX = ref(0)\n const imageOffsetY = ref(0)\n\n const cropX = computed({\n get: () => modelValue.value.x,\n set: (v: number) => {\n modelValue.value.x = v\n }\n })\n\n const cropY = computed({\n get: () => modelValue.value.y,\n set: (v: number) => {\n modelValue.value.y = v\n }\n })\n\n const cropWidth = computed({\n get: () => modelValue.value.width || 512,\n set: (v: number) => {\n modelValue.value.width = v\n }\n })\n\n const cropHeight = computed({\n get: () => modelValue.value.height || 512,\n set: (v: number) => {\n modelValue.value.height = v\n }\n })\n\n const isDragging = ref(false)\n const dragStartX = ref(0)\n const dragStartY = ref(0)\n const dragStartCropX = ref(0)\n const dragStartCropY = ref(0)\n\n const isResizing = ref(false)\n const resizeDirection = ref<ResizeDirection | null>(null)\n const resizeStartX = ref(0)\n const resizeStartY = ref(0)\n const resizeStartCropX = ref(0)\n const resizeStartCropY = ref(0)\n const resizeStartCropWidth = ref(0)\n const resizeStartCropHeight = ref(0)\n\n useResizeObserver(containerEl, () => {\n if (imageEl.value && imageUrl.value) {\n updateDisplayedDimensions()\n }\n })\n\n const getInputImageUrl = (): string | null => {\n if (!node.value) return null\n\n const inputNode = node.value.getInputNode(0)\n\n if (!inputNode) return null\n\n const urls = nodeOutputStore.getNodeImageUrls(inputNode)\n\n if (urls?.length) {\n return urls[0]\n }\n\n return null\n }\n\n const updateImageUrl = () => {\n imageUrl.value = getInputImageUrl()\n }\n\n const updateDisplayedDimensions = () => {\n if (!imageEl.value || !containerEl.value) return\n\n const img = imageEl.value\n const container = containerEl.value\n\n naturalWidth.value = img.naturalWidth\n naturalHeight.value = img.naturalHeight\n\n if (naturalWidth.value <= 0 || naturalHeight.value <= 0) {\n scaleFactor.value = 1\n return\n }\n\n const containerWidth = container.clientWidth\n const containerHeight = container.clientHeight\n\n const imageAspect = naturalWidth.value / naturalHeight.value\n const containerAspect = containerWidth / containerHeight\n\n if (imageAspect > containerAspect) {\n displayedWidth.value = containerWidth\n displayedHeight.value = containerWidth / imageAspect\n imageOffsetX.value = 0\n imageOffsetY.value = (containerHeight - displayedHeight.value) / 2\n } else {\n displayedHeight.value = containerHeight\n displayedWidth.value = containerHeight * imageAspect\n imageOffsetX.value = (containerWidth - displayedWidth.value) / 2\n imageOffsetY.value = 0\n }\n\n if (naturalWidth.value <= 0 || displayedWidth.value <= 0) {\n scaleFactor.value = 1\n } else {\n scaleFactor.value = displayedWidth.value / naturalWidth.value\n }\n }\n\n const getEffectiveScale = (): number => {\n const container = containerEl.value\n\n if (!container || naturalWidth.value <= 0 || displayedWidth.value <= 0) {\n return 1\n }\n\n const rect = container.getBoundingClientRect()\n const clientWidth = container.clientWidth\n\n if (!clientWidth || !rect.width) return 1\n\n const renderedDisplayedWidth =\n (displayedWidth.value / clientWidth) * rect.width\n\n return renderedDisplayedWidth / naturalWidth.value\n }\n\n const cropBoxStyle = computed(() => ({\n left: `${imageOffsetX.value + cropX.value * scaleFactor.value - CROP_BOX_BORDER}px`,\n top: `${imageOffsetY.value + cropY.value * scaleFactor.value - CROP_BOX_BORDER}px`,\n width: `${cropWidth.value * scaleFactor.value}px`,\n height: `${cropHeight.value * scaleFactor.value}px`\n }))\n\n const cropImageStyle = computed(() => {\n if (!imageUrl.value) return {}\n\n return {\n backgroundImage: `url(${imageUrl.value})`,\n backgroundSize: `${displayedWidth.value}px ${displayedHeight.value}px`,\n backgroundPosition: `-${cropX.value * scaleFactor.value}px -${cropY.value * scaleFactor.value}px`,\n backgroundRepeat: 'no-repeat'\n }\n })\n\n interface ResizeHandle {\n direction: ResizeDirection\n class: string\n style: {\n left: string\n top: string\n width?: string\n height?: string\n }\n }\n\n const resizeHandles = computed<ResizeHandle[]>(() => {\n const x = imageOffsetX.value + cropX.value * scaleFactor.value\n const y = imageOffsetY.value + cropY.value * scaleFactor.value\n const w = cropWidth.value * scaleFactor.value\n const h = cropHeight.value * scaleFactor.value\n\n return [\n {\n direction: 'top',\n class: 'h-2 cursor-ns-resize',\n style: {\n left: `${x + HANDLE_SIZE}px`,\n top: `${y - HANDLE_SIZE / 2}px`,\n width: `${Math.max(0, w - HANDLE_SIZE * 2)}px`\n }\n },\n {\n direction: 'bottom',\n class: 'h-2 cursor-ns-resize',\n style: {\n left: `${x + HANDLE_SIZE}px`,\n top: `${y + h - HANDLE_SIZE / 2}px`,\n width: `${Math.max(0, w - HANDLE_SIZE * 2)}px`\n }\n },\n {\n direction: 'left',\n class: 'w-2 cursor-ew-resize',\n style: {\n left: `${x - HANDLE_SIZE / 2}px`,\n top: `${y + HANDLE_SIZE}px`,\n height: `${Math.max(0, h - HANDLE_SIZE * 2)}px`\n }\n },\n {\n direction: 'right',\n class: 'w-2 cursor-ew-resize',\n style: {\n left: `${x + w - HANDLE_SIZE / 2}px`,\n top: `${y + HANDLE_SIZE}px`,\n height: `${Math.max(0, h - HANDLE_SIZE * 2)}px`\n }\n },\n {\n direction: 'nw',\n class: 'cursor-nwse-resize rounded-sm bg-white/80',\n style: {\n left: `${x - CORNER_SIZE / 2}px`,\n top: `${y - CORNER_SIZE / 2}px`,\n width: `${CORNER_SIZE}px`,\n height: `${CORNER_SIZE}px`\n }\n },\n {\n direction: 'ne',\n class: 'cursor-nesw-resize rounded-sm bg-white/80',\n style: {\n left: `${x + w - CORNER_SIZE / 2}px`,\n top: `${y - CORNER_SIZE / 2}px`,\n width: `${CORNER_SIZE}px`,\n height: `${CORNER_SIZE}px`\n }\n },\n {\n direction: 'sw',\n class: 'cursor-nesw-resize rounded-sm bg-white/80',\n style: {\n left: `${x - CORNER_SIZE / 2}px`,\n top: `${y + h - CORNER_SIZE / 2}px`,\n width: `${CORNER_SIZE}px`,\n height: `${CORNER_SIZE}px`\n }\n },\n {\n direction: 'se',\n class: 'cursor-nwse-resize rounded-sm bg-white/80',\n style: {\n left: `${x + w - CORNER_SIZE / 2}px`,\n top: `${y + h - CORNER_SIZE / 2}px`,\n width: `${CORNER_SIZE}px`,\n height: `${CORNER_SIZE}px`\n }\n }\n ]\n })\n\n const handleImageLoad = () => {\n isLoading.value = false\n updateDisplayedDimensions()\n }\n\n const handleImageError = () => {\n isLoading.value = false\n imageUrl.value = null\n }\n\n const capturePointer = (e: PointerEvent) =>\n (e.target as HTMLElement).setPointerCapture(e.pointerId)\n\n const releasePointer = (e: PointerEvent) =>\n (e.target as HTMLElement).releasePointerCapture(e.pointerId)\n\n const handleDragStart = (e: PointerEvent) => {\n if (!imageUrl.value) return\n\n isDragging.value = true\n dragStartX.value = e.clientX\n dragStartY.value = e.clientY\n dragStartCropX.value = cropX.value\n dragStartCropY.value = cropY.value\n capturePointer(e)\n }\n\n const handleDragMove = (e: PointerEvent) => {\n if (!isDragging.value) return\n\n const effectiveScale = getEffectiveScale()\n if (effectiveScale === 0) return\n\n const deltaX = (e.clientX - dragStartX.value) / effectiveScale\n const deltaY = (e.clientY - dragStartY.value) / effectiveScale\n\n const maxX = naturalWidth.value - cropWidth.value\n const maxY = naturalHeight.value - cropHeight.value\n\n cropX.value = Math.round(\n Math.max(0, Math.min(maxX, dragStartCropX.value + deltaX))\n )\n cropY.value = Math.round(\n Math.max(0, Math.min(maxY, dragStartCropY.value + deltaY))\n )\n }\n\n const handleDragEnd = (e: PointerEvent) => {\n if (!isDragging.value) return\n\n isDragging.value = false\n releasePointer(e)\n }\n\n const handleResizeStart = (e: PointerEvent, direction: ResizeDirection) => {\n if (!imageUrl.value) return\n\n e.stopPropagation()\n isResizing.value = true\n resizeDirection.value = direction\n\n resizeStartX.value = e.clientX\n resizeStartY.value = e.clientY\n resizeStartCropX.value = cropX.value\n resizeStartCropY.value = cropY.value\n resizeStartCropWidth.value = cropWidth.value\n resizeStartCropHeight.value = cropHeight.value\n capturePointer(e)\n }\n\n const handleResizeMove = (e: PointerEvent) => {\n if (!isResizing.value || !resizeDirection.value) return\n\n const effectiveScale = getEffectiveScale()\n if (effectiveScale === 0) return\n\n const dir = resizeDirection.value\n const deltaX = (e.clientX - resizeStartX.value) / effectiveScale\n const deltaY = (e.clientY - resizeStartY.value) / effectiveScale\n\n const affectsLeft = dir === 'left' || dir === 'nw' || dir === 'sw'\n const affectsRight = dir === 'right' || dir === 'ne' || dir === 'se'\n const affectsTop = dir === 'top' || dir === 'nw' || dir === 'ne'\n const affectsBottom = dir === 'bottom' || dir === 'sw' || dir === 'se'\n\n let newX = resizeStartCropX.value\n let newY = resizeStartCropY.value\n let newWidth = resizeStartCropWidth.value\n let newHeight = resizeStartCropHeight.value\n\n if (affectsLeft) {\n const maxDeltaX = resizeStartCropWidth.value - MIN_CROP_SIZE\n const minDeltaX = -resizeStartCropX.value\n const clampedDeltaX = Math.max(minDeltaX, Math.min(maxDeltaX, deltaX))\n newX = resizeStartCropX.value + clampedDeltaX\n newWidth = resizeStartCropWidth.value - clampedDeltaX\n } else if (affectsRight) {\n const maxWidth = naturalWidth.value - resizeStartCropX.value\n newWidth = Math.max(\n MIN_CROP_SIZE,\n Math.min(maxWidth, resizeStartCropWidth.value + deltaX)\n )\n }\n\n if (affectsTop) {\n const maxDeltaY = resizeStartCropHeight.value - MIN_CROP_SIZE\n const minDeltaY = -resizeStartCropY.value\n const clampedDeltaY = Math.max(minDeltaY, Math.min(maxDeltaY, deltaY))\n newY = resizeStartCropY.value + clampedDeltaY\n newHeight = resizeStartCropHeight.value - clampedDeltaY\n } else if (affectsBottom) {\n const maxHeight = naturalHeight.value - resizeStartCropY.value\n newHeight = Math.max(\n MIN_CROP_SIZE,\n Math.min(maxHeight, resizeStartCropHeight.value + deltaY)\n )\n }\n\n if (affectsLeft || affectsRight) {\n cropX.value = Math.round(newX)\n cropWidth.value = Math.round(newWidth)\n }\n if (affectsTop || affectsBottom) {\n cropY.value = Math.round(newY)\n cropHeight.value = Math.round(newHeight)\n }\n }\n\n const handleResizeEnd = (e: PointerEvent) => {\n if (!isResizing.value) return\n\n isResizing.value = false\n resizeDirection.value = null\n releasePointer(e)\n }\n\n const initialize = () => {\n if (nodeId != null) {\n node.value = app.rootGraph?.getNodeById(nodeId) || null\n }\n\n updateImageUrl()\n }\n\n watch(\n () => nodeOutputStore.nodeOutputs,\n () => updateImageUrl(),\n { deep: true }\n )\n\n watch(\n () => nodeOutputStore.nodePreviewImages,\n () => updateImageUrl(),\n { deep: true }\n )\n\n onMounted(initialize)\n\n return {\n imageUrl,\n isLoading,\n\n cropX,\n cropY,\n cropWidth,\n cropHeight,\n\n cropBoxStyle,\n cropImageStyle,\n resizeHandles,\n\n handleImageLoad,\n handleImageError,\n handleDragStart,\n handleDragMove,\n handleDragEnd,\n handleResizeStart,\n handleResizeMove,\n handleResizeEnd\n }\n}\n","<template>\n <div\n class=\"widget-expands relative flex h-full w-full flex-col gap-1\"\n @pointerdown.stop\n @pointermove.stop\n @pointerup.stop\n >\n <!-- Image preview container -->\n <div\n ref=\"containerEl\"\n class=\"relative min-h-0 flex-1 overflow-hidden rounded-[5px] bg-node-component-surface\"\n >\n <div v-if=\"isLoading\" class=\"flex size-full items-center justify-center\">\n <span class=\"text-sm\">{{ $t('imageCrop.loading') }}</span>\n </div>\n\n <div\n v-else-if=\"!imageUrl\"\n class=\"flex size-full flex-col items-center justify-center text-center\"\n >\n <i class=\"mb-2 icon-[lucide--image] h-12 w-12\" />\n <p class=\"text-sm\">{{ $t('imageCrop.noInputImage') }}</p>\n </div>\n\n <img\n v-else\n ref=\"imageEl\"\n :src=\"imageUrl\"\n :alt=\"$t('imageCrop.cropPreviewAlt')\"\n draggable=\"false\"\n class=\"block size-full object-contain select-none brightness-50\"\n @load=\"handleImageLoad\"\n @error=\"handleImageError\"\n @dragstart.prevent\n />\n\n <div\n v-if=\"imageUrl && !isLoading\"\n class=\"absolute box-content cursor-move overflow-hidden border-2 border-white\"\n :style=\"cropBoxStyle\"\n @pointerdown=\"handleDragStart\"\n @pointermove=\"handleDragMove\"\n @pointerup=\"handleDragEnd\"\n >\n <div class=\"pointer-events-none size-full\" :style=\"cropImageStyle\" />\n </div>\n\n <div\n v-for=\"handle in resizeHandles\"\n v-show=\"imageUrl && !isLoading\"\n :key=\"handle.direction\"\n :class=\"['absolute', handle.class]\"\n :style=\"handle.style\"\n @pointerdown=\"(e) => handleResizeStart(e, handle.direction)\"\n @pointermove=\"handleResizeMove\"\n @pointerup=\"handleResizeEnd\"\n />\n </div>\n\n <WidgetBoundingBox v-model=\"modelValue\" class=\"shrink-0\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useTemplateRef } from 'vue'\n\nimport WidgetBoundingBox from '@/components/boundingbox/WidgetBoundingBox.vue'\nimport { useImageCrop } from '@/composables/useImageCrop'\nimport type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema'\nimport type { Bounds } from '@/renderer/core/layout/types'\n\nconst props = defineProps<{\n nodeId: NodeId\n}>()\n\nconst modelValue = defineModel<Bounds>({\n default: () => ({ x: 0, y: 0, width: 512, height: 512 })\n})\n\nconst imageEl = useTemplateRef<HTMLImageElement>('imageEl')\nconst containerEl = useTemplateRef<HTMLDivElement>('containerEl')\n\nconst {\n imageUrl,\n isLoading,\n\n cropBoxStyle,\n cropImageStyle,\n resizeHandles,\n\n handleImageLoad,\n handleImageError,\n handleDragStart,\n handleDragMove,\n handleDragEnd,\n handleResizeStart,\n handleResizeMove,\n handleResizeEnd\n} = useImageCrop(props.nodeId, { imageEl, containerEl, modelValue })\n</script>\n","<template>\n <div\n class=\"widget-expands relative flex h-full w-full flex-col gap-1\"\n @pointerdown.stop\n @pointermove.stop\n @pointerup.stop\n >\n <!-- Image preview container -->\n <div\n ref=\"containerEl\"\n class=\"relative min-h-0 flex-1 overflow-hidden rounded-[5px] bg-node-component-surface\"\n >\n <div v-if=\"isLoading\" class=\"flex size-full items-center justify-center\">\n <span class=\"text-sm\">{{ $t('imageCrop.loading') }}</span>\n </div>\n\n <div\n v-else-if=\"!imageUrl\"\n class=\"flex size-full flex-col items-center justify-center text-center\"\n >\n <i class=\"mb-2 icon-[lucide--image] h-12 w-12\" />\n <p class=\"text-sm\">{{ $t('imageCrop.noInputImage') }}</p>\n </div>\n\n <img\n v-else\n ref=\"imageEl\"\n :src=\"imageUrl\"\n :alt=\"$t('imageCrop.cropPreviewAlt')\"\n draggable=\"false\"\n class=\"block size-full object-contain select-none brightness-50\"\n @load=\"handleImageLoad\"\n @error=\"handleImageError\"\n @dragstart.prevent\n />\n\n <div\n v-if=\"imageUrl && !isLoading\"\n class=\"absolute box-content cursor-move overflow-hidden border-2 border-white\"\n :style=\"cropBoxStyle\"\n @pointerdown=\"handleDragStart\"\n @pointermove=\"handleDragMove\"\n @pointerup=\"handleDragEnd\"\n >\n <div class=\"pointer-events-none size-full\" :style=\"cropImageStyle\" />\n </div>\n\n <div\n v-for=\"handle in resizeHandles\"\n v-show=\"imageUrl && !isLoading\"\n :key=\"handle.direction\"\n :class=\"['absolute', handle.class]\"\n :style=\"handle.style\"\n @pointerdown=\"(e) => handleResizeStart(e, handle.direction)\"\n @pointermove=\"handleResizeMove\"\n @pointerup=\"handleResizeEnd\"\n />\n </div>\n\n <WidgetBoundingBox v-model=\"modelValue\" class=\"shrink-0\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useTemplateRef } from 'vue'\n\nimport WidgetBoundingBox from '@/components/boundingbox/WidgetBoundingBox.vue'\nimport { useImageCrop } from '@/composables/useImageCrop'\nimport type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema'\nimport type { Bounds } from '@/renderer/core/layout/types'\n\nconst props = defineProps<{\n nodeId: NodeId\n}>()\n\nconst modelValue = defineModel<Bounds>({\n default: () => ({ x: 0, y: 0, width: 512, height: 512 })\n})\n\nconst imageEl = useTemplateRef<HTMLImageElement>('imageEl')\nconst containerEl = useTemplateRef<HTMLDivElement>('containerEl')\n\nconst {\n imageUrl,\n isLoading,\n\n cropBoxStyle,\n cropImageStyle,\n resizeHandles,\n\n handleImageLoad,\n handleImageError,\n handleDragStart,\n handleDragMove,\n handleDragEnd,\n handleResizeStart,\n handleResizeMove,\n handleResizeEnd\n} = useImageCrop(props.nodeId, { imageEl, containerEl, modelValue })\n</script>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WidgetImageCrop-kERy9g5I.js","names":[],"sources":["../../src/composables/useImageCrop.ts","../../src/components/imagecrop/WidgetImageCrop.vue","../../src/components/imagecrop/WidgetImageCrop.vue"],"sourcesContent":["import { useResizeObserver } from '@vueuse/core'\nimport type { Ref } from 'vue'\nimport { computed, onMounted, ref, watch } from 'vue'\n\nimport type { LGraphNode, NodeId } from '@/lib/litegraph/src/LGraphNode'\nimport type { Bounds } from '@/renderer/core/layout/types'\nimport { app } from '@/scripts/app'\nimport { useNodeOutputStore } from '@/stores/imagePreviewStore'\n\ntype ResizeDirection =\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'nw'\n | 'ne'\n | 'sw'\n | 'se'\n\nconst HANDLE_SIZE = 8\nconst CORNER_SIZE = 10\nconst MIN_CROP_SIZE = 16\nconst CROP_BOX_BORDER = 2\n\ninterface UseImageCropOptions {\n imageEl: Ref<HTMLImageElement | null>\n containerEl: Ref<HTMLDivElement | null>\n modelValue: Ref<Bounds>\n}\n\nexport function useImageCrop(nodeId: NodeId, options: UseImageCropOptions) {\n const { imageEl, containerEl, modelValue } = options\n const nodeOutputStore = useNodeOutputStore()\n\n const node = ref<LGraphNode | null>(null)\n\n const imageUrl = ref<string | null>(null)\n const isLoading = ref(false)\n\n const naturalWidth = ref(0)\n const naturalHeight = ref(0)\n const displayedWidth = ref(0)\n const displayedHeight = ref(0)\n const scaleFactor = ref(1)\n const imageOffsetX = ref(0)\n const imageOffsetY = ref(0)\n\n const cropX = computed({\n get: () => modelValue.value.x,\n set: (v: number) => {\n modelValue.value.x = v\n }\n })\n\n const cropY = computed({\n get: () => modelValue.value.y,\n set: (v: number) => {\n modelValue.value.y = v\n }\n })\n\n const cropWidth = computed({\n get: () => modelValue.value.width || 512,\n set: (v: number) => {\n modelValue.value.width = v\n }\n })\n\n const cropHeight = computed({\n get: () => modelValue.value.height || 512,\n set: (v: number) => {\n modelValue.value.height = v\n }\n })\n\n const isDragging = ref(false)\n const dragStartX = ref(0)\n const dragStartY = ref(0)\n const dragStartCropX = ref(0)\n const dragStartCropY = ref(0)\n\n const isResizing = ref(false)\n const resizeDirection = ref<ResizeDirection | null>(null)\n const resizeStartX = ref(0)\n const resizeStartY = ref(0)\n const resizeStartCropX = ref(0)\n const resizeStartCropY = ref(0)\n const resizeStartCropWidth = ref(0)\n const resizeStartCropHeight = ref(0)\n\n useResizeObserver(containerEl, () => {\n if (imageEl.value && imageUrl.value) {\n updateDisplayedDimensions()\n }\n })\n\n const getInputImageUrl = (): string | null => {\n if (!node.value) return null\n\n const inputNode = node.value.getInputNode(0)\n\n if (!inputNode) return null\n\n const urls = nodeOutputStore.getNodeImageUrls(inputNode)\n\n if (urls?.length) {\n return urls[0]\n }\n\n return null\n }\n\n const updateImageUrl = () => {\n imageUrl.value = getInputImageUrl()\n }\n\n const updateDisplayedDimensions = () => {\n if (!imageEl.value || !containerEl.value) return\n\n const img = imageEl.value\n const container = containerEl.value\n\n naturalWidth.value = img.naturalWidth\n naturalHeight.value = img.naturalHeight\n\n if (naturalWidth.value <= 0 || naturalHeight.value <= 0) {\n scaleFactor.value = 1\n return\n }\n\n const containerWidth = container.clientWidth\n const containerHeight = container.clientHeight\n\n const imageAspect = naturalWidth.value / naturalHeight.value\n const containerAspect = containerWidth / containerHeight\n\n if (imageAspect > containerAspect) {\n displayedWidth.value = containerWidth\n displayedHeight.value = containerWidth / imageAspect\n imageOffsetX.value = 0\n imageOffsetY.value = (containerHeight - displayedHeight.value) / 2\n } else {\n displayedHeight.value = containerHeight\n displayedWidth.value = containerHeight * imageAspect\n imageOffsetX.value = (containerWidth - displayedWidth.value) / 2\n imageOffsetY.value = 0\n }\n\n if (naturalWidth.value <= 0 || displayedWidth.value <= 0) {\n scaleFactor.value = 1\n } else {\n scaleFactor.value = displayedWidth.value / naturalWidth.value\n }\n }\n\n const getEffectiveScale = (): number => {\n const container = containerEl.value\n\n if (!container || naturalWidth.value <= 0 || displayedWidth.value <= 0) {\n return 1\n }\n\n const rect = container.getBoundingClientRect()\n const clientWidth = container.clientWidth\n\n if (!clientWidth || !rect.width) return 1\n\n const renderedDisplayedWidth =\n (displayedWidth.value / clientWidth) * rect.width\n\n return renderedDisplayedWidth / naturalWidth.value\n }\n\n const cropBoxStyle = computed(() => ({\n left: `${imageOffsetX.value + cropX.value * scaleFactor.value - CROP_BOX_BORDER}px`,\n top: `${imageOffsetY.value + cropY.value * scaleFactor.value - CROP_BOX_BORDER}px`,\n width: `${cropWidth.value * scaleFactor.value}px`,\n height: `${cropHeight.value * scaleFactor.value}px`\n }))\n\n const cropImageStyle = computed(() => {\n if (!imageUrl.value) return {}\n\n return {\n backgroundImage: `url(${imageUrl.value})`,\n backgroundSize: `${displayedWidth.value}px ${displayedHeight.value}px`,\n backgroundPosition: `-${cropX.value * scaleFactor.value}px -${cropY.value * scaleFactor.value}px`,\n backgroundRepeat: 'no-repeat'\n }\n })\n\n interface ResizeHandle {\n direction: ResizeDirection\n class: string\n style: {\n left: string\n top: string\n width?: string\n height?: string\n }\n }\n\n const resizeHandles = computed<ResizeHandle[]>(() => {\n const x = imageOffsetX.value + cropX.value * scaleFactor.value\n const y = imageOffsetY.value + cropY.value * scaleFactor.value\n const w = cropWidth.value * scaleFactor.value\n const h = cropHeight.value * scaleFactor.value\n\n return [\n {\n direction: 'top',\n class: 'h-2 cursor-ns-resize',\n style: {\n left: `${x + HANDLE_SIZE}px`,\n top: `${y - HANDLE_SIZE / 2}px`,\n width: `${Math.max(0, w - HANDLE_SIZE * 2)}px`\n }\n },\n {\n direction: 'bottom',\n class: 'h-2 cursor-ns-resize',\n style: {\n left: `${x + HANDLE_SIZE}px`,\n top: `${y + h - HANDLE_SIZE / 2}px`,\n width: `${Math.max(0, w - HANDLE_SIZE * 2)}px`\n }\n },\n {\n direction: 'left',\n class: 'w-2 cursor-ew-resize',\n style: {\n left: `${x - HANDLE_SIZE / 2}px`,\n top: `${y + HANDLE_SIZE}px`,\n height: `${Math.max(0, h - HANDLE_SIZE * 2)}px`\n }\n },\n {\n direction: 'right',\n class: 'w-2 cursor-ew-resize',\n style: {\n left: `${x + w - HANDLE_SIZE / 2}px`,\n top: `${y + HANDLE_SIZE}px`,\n height: `${Math.max(0, h - HANDLE_SIZE * 2)}px`\n }\n },\n {\n direction: 'nw',\n class: 'cursor-nwse-resize rounded-sm bg-white/80',\n style: {\n left: `${x - CORNER_SIZE / 2}px`,\n top: `${y - CORNER_SIZE / 2}px`,\n width: `${CORNER_SIZE}px`,\n height: `${CORNER_SIZE}px`\n }\n },\n {\n direction: 'ne',\n class: 'cursor-nesw-resize rounded-sm bg-white/80',\n style: {\n left: `${x + w - CORNER_SIZE / 2}px`,\n top: `${y - CORNER_SIZE / 2}px`,\n width: `${CORNER_SIZE}px`,\n height: `${CORNER_SIZE}px`\n }\n },\n {\n direction: 'sw',\n class: 'cursor-nesw-resize rounded-sm bg-white/80',\n style: {\n left: `${x - CORNER_SIZE / 2}px`,\n top: `${y + h - CORNER_SIZE / 2}px`,\n width: `${CORNER_SIZE}px`,\n height: `${CORNER_SIZE}px`\n }\n },\n {\n direction: 'se',\n class: 'cursor-nwse-resize rounded-sm bg-white/80',\n style: {\n left: `${x + w - CORNER_SIZE / 2}px`,\n top: `${y + h - CORNER_SIZE / 2}px`,\n width: `${CORNER_SIZE}px`,\n height: `${CORNER_SIZE}px`\n }\n }\n ]\n })\n\n const handleImageLoad = () => {\n isLoading.value = false\n updateDisplayedDimensions()\n }\n\n const handleImageError = () => {\n isLoading.value = false\n imageUrl.value = null\n }\n\n const capturePointer = (e: PointerEvent) =>\n (e.target as HTMLElement).setPointerCapture(e.pointerId)\n\n const releasePointer = (e: PointerEvent) =>\n (e.target as HTMLElement).releasePointerCapture(e.pointerId)\n\n const handleDragStart = (e: PointerEvent) => {\n if (!imageUrl.value) return\n\n isDragging.value = true\n dragStartX.value = e.clientX\n dragStartY.value = e.clientY\n dragStartCropX.value = cropX.value\n dragStartCropY.value = cropY.value\n capturePointer(e)\n }\n\n const handleDragMove = (e: PointerEvent) => {\n if (!isDragging.value) return\n\n const effectiveScale = getEffectiveScale()\n if (effectiveScale === 0) return\n\n const deltaX = (e.clientX - dragStartX.value) / effectiveScale\n const deltaY = (e.clientY - dragStartY.value) / effectiveScale\n\n const maxX = naturalWidth.value - cropWidth.value\n const maxY = naturalHeight.value - cropHeight.value\n\n cropX.value = Math.round(\n Math.max(0, Math.min(maxX, dragStartCropX.value + deltaX))\n )\n cropY.value = Math.round(\n Math.max(0, Math.min(maxY, dragStartCropY.value + deltaY))\n )\n }\n\n const handleDragEnd = (e: PointerEvent) => {\n if (!isDragging.value) return\n\n isDragging.value = false\n releasePointer(e)\n }\n\n const handleResizeStart = (e: PointerEvent, direction: ResizeDirection) => {\n if (!imageUrl.value) return\n\n e.stopPropagation()\n isResizing.value = true\n resizeDirection.value = direction\n\n resizeStartX.value = e.clientX\n resizeStartY.value = e.clientY\n resizeStartCropX.value = cropX.value\n resizeStartCropY.value = cropY.value\n resizeStartCropWidth.value = cropWidth.value\n resizeStartCropHeight.value = cropHeight.value\n capturePointer(e)\n }\n\n const handleResizeMove = (e: PointerEvent) => {\n if (!isResizing.value || !resizeDirection.value) return\n\n const effectiveScale = getEffectiveScale()\n if (effectiveScale === 0) return\n\n const dir = resizeDirection.value\n const deltaX = (e.clientX - resizeStartX.value) / effectiveScale\n const deltaY = (e.clientY - resizeStartY.value) / effectiveScale\n\n const affectsLeft = dir === 'left' || dir === 'nw' || dir === 'sw'\n const affectsRight = dir === 'right' || dir === 'ne' || dir === 'se'\n const affectsTop = dir === 'top' || dir === 'nw' || dir === 'ne'\n const affectsBottom = dir === 'bottom' || dir === 'sw' || dir === 'se'\n\n let newX = resizeStartCropX.value\n let newY = resizeStartCropY.value\n let newWidth = resizeStartCropWidth.value\n let newHeight = resizeStartCropHeight.value\n\n if (affectsLeft) {\n const maxDeltaX = resizeStartCropWidth.value - MIN_CROP_SIZE\n const minDeltaX = -resizeStartCropX.value\n const clampedDeltaX = Math.max(minDeltaX, Math.min(maxDeltaX, deltaX))\n newX = resizeStartCropX.value + clampedDeltaX\n newWidth = resizeStartCropWidth.value - clampedDeltaX\n } else if (affectsRight) {\n const maxWidth = naturalWidth.value - resizeStartCropX.value\n newWidth = Math.max(\n MIN_CROP_SIZE,\n Math.min(maxWidth, resizeStartCropWidth.value + deltaX)\n )\n }\n\n if (affectsTop) {\n const maxDeltaY = resizeStartCropHeight.value - MIN_CROP_SIZE\n const minDeltaY = -resizeStartCropY.value\n const clampedDeltaY = Math.max(minDeltaY, Math.min(maxDeltaY, deltaY))\n newY = resizeStartCropY.value + clampedDeltaY\n newHeight = resizeStartCropHeight.value - clampedDeltaY\n } else if (affectsBottom) {\n const maxHeight = naturalHeight.value - resizeStartCropY.value\n newHeight = Math.max(\n MIN_CROP_SIZE,\n Math.min(maxHeight, resizeStartCropHeight.value + deltaY)\n )\n }\n\n if (affectsLeft || affectsRight) {\n cropX.value = Math.round(newX)\n cropWidth.value = Math.round(newWidth)\n }\n if (affectsTop || affectsBottom) {\n cropY.value = Math.round(newY)\n cropHeight.value = Math.round(newHeight)\n }\n }\n\n const handleResizeEnd = (e: PointerEvent) => {\n if (!isResizing.value) return\n\n isResizing.value = false\n resizeDirection.value = null\n releasePointer(e)\n }\n\n const initialize = () => {\n if (nodeId != null) {\n node.value = app.rootGraph?.getNodeById(nodeId) || null\n }\n\n updateImageUrl()\n }\n\n watch(\n () => nodeOutputStore.nodeOutputs,\n () => updateImageUrl(),\n { deep: true }\n )\n\n watch(\n () => nodeOutputStore.nodePreviewImages,\n () => updateImageUrl(),\n { deep: true }\n )\n\n onMounted(initialize)\n\n return {\n imageUrl,\n isLoading,\n\n cropX,\n cropY,\n cropWidth,\n cropHeight,\n\n cropBoxStyle,\n cropImageStyle,\n resizeHandles,\n\n handleImageLoad,\n handleImageError,\n handleDragStart,\n handleDragMove,\n handleDragEnd,\n handleResizeStart,\n handleResizeMove,\n handleResizeEnd\n }\n}\n","<template>\n <div\n class=\"widget-expands relative flex h-full w-full flex-col gap-1\"\n @pointerdown.stop\n @pointermove.stop\n @pointerup.stop\n >\n <!-- Image preview container -->\n <div\n ref=\"containerEl\"\n class=\"relative min-h-0 flex-1 overflow-hidden rounded-[5px] bg-node-component-surface\"\n >\n <div v-if=\"isLoading\" class=\"flex size-full items-center justify-center\">\n <span class=\"text-sm\">{{ $t('imageCrop.loading') }}</span>\n </div>\n\n <div\n v-else-if=\"!imageUrl\"\n class=\"flex size-full flex-col items-center justify-center text-center\"\n >\n <i class=\"mb-2 icon-[lucide--image] h-12 w-12\" />\n <p class=\"text-sm\">{{ $t('imageCrop.noInputImage') }}</p>\n </div>\n\n <img\n v-else\n ref=\"imageEl\"\n :src=\"imageUrl\"\n :alt=\"$t('imageCrop.cropPreviewAlt')\"\n draggable=\"false\"\n class=\"block size-full object-contain select-none brightness-50\"\n @load=\"handleImageLoad\"\n @error=\"handleImageError\"\n @dragstart.prevent\n />\n\n <div\n v-if=\"imageUrl && !isLoading\"\n class=\"absolute box-content cursor-move overflow-hidden border-2 border-white\"\n :style=\"cropBoxStyle\"\n @pointerdown=\"handleDragStart\"\n @pointermove=\"handleDragMove\"\n @pointerup=\"handleDragEnd\"\n >\n <div class=\"pointer-events-none size-full\" :style=\"cropImageStyle\" />\n </div>\n\n <div\n v-for=\"handle in resizeHandles\"\n v-show=\"imageUrl && !isLoading\"\n :key=\"handle.direction\"\n :class=\"['absolute', handle.class]\"\n :style=\"handle.style\"\n @pointerdown=\"(e) => handleResizeStart(e, handle.direction)\"\n @pointermove=\"handleResizeMove\"\n @pointerup=\"handleResizeEnd\"\n />\n </div>\n\n <WidgetBoundingBox v-model=\"modelValue\" class=\"shrink-0\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useTemplateRef } from 'vue'\n\nimport WidgetBoundingBox from '@/components/boundingbox/WidgetBoundingBox.vue'\nimport { useImageCrop } from '@/composables/useImageCrop'\nimport type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema'\nimport type { Bounds } from '@/renderer/core/layout/types'\n\nconst props = defineProps<{\n nodeId: NodeId\n}>()\n\nconst modelValue = defineModel<Bounds>({\n default: () => ({ x: 0, y: 0, width: 512, height: 512 })\n})\n\nconst imageEl = useTemplateRef<HTMLImageElement>('imageEl')\nconst containerEl = useTemplateRef<HTMLDivElement>('containerEl')\n\nconst {\n imageUrl,\n isLoading,\n\n cropBoxStyle,\n cropImageStyle,\n resizeHandles,\n\n handleImageLoad,\n handleImageError,\n handleDragStart,\n handleDragMove,\n handleDragEnd,\n handleResizeStart,\n handleResizeMove,\n handleResizeEnd\n} = useImageCrop(props.nodeId, { imageEl, containerEl, modelValue })\n</script>\n","<template>\n <div\n class=\"widget-expands relative flex h-full w-full flex-col gap-1\"\n @pointerdown.stop\n @pointermove.stop\n @pointerup.stop\n >\n <!-- Image preview container -->\n <div\n ref=\"containerEl\"\n class=\"relative min-h-0 flex-1 overflow-hidden rounded-[5px] bg-node-component-surface\"\n >\n <div v-if=\"isLoading\" class=\"flex size-full items-center justify-center\">\n <span class=\"text-sm\">{{ $t('imageCrop.loading') }}</span>\n </div>\n\n <div\n v-else-if=\"!imageUrl\"\n class=\"flex size-full flex-col items-center justify-center text-center\"\n >\n <i class=\"mb-2 icon-[lucide--image] h-12 w-12\" />\n <p class=\"text-sm\">{{ $t('imageCrop.noInputImage') }}</p>\n </div>\n\n <img\n v-else\n ref=\"imageEl\"\n :src=\"imageUrl\"\n :alt=\"$t('imageCrop.cropPreviewAlt')\"\n draggable=\"false\"\n class=\"block size-full object-contain select-none brightness-50\"\n @load=\"handleImageLoad\"\n @error=\"handleImageError\"\n @dragstart.prevent\n />\n\n <div\n v-if=\"imageUrl && !isLoading\"\n class=\"absolute box-content cursor-move overflow-hidden border-2 border-white\"\n :style=\"cropBoxStyle\"\n @pointerdown=\"handleDragStart\"\n @pointermove=\"handleDragMove\"\n @pointerup=\"handleDragEnd\"\n >\n <div class=\"pointer-events-none size-full\" :style=\"cropImageStyle\" />\n </div>\n\n <div\n v-for=\"handle in resizeHandles\"\n v-show=\"imageUrl && !isLoading\"\n :key=\"handle.direction\"\n :class=\"['absolute', handle.class]\"\n :style=\"handle.style\"\n @pointerdown=\"(e) => handleResizeStart(e, handle.direction)\"\n @pointermove=\"handleResizeMove\"\n @pointerup=\"handleResizeEnd\"\n />\n </div>\n\n <WidgetBoundingBox v-model=\"modelValue\" class=\"shrink-0\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { useTemplateRef } from 'vue'\n\nimport WidgetBoundingBox from '@/components/boundingbox/WidgetBoundingBox.vue'\nimport { useImageCrop } from '@/composables/useImageCrop'\nimport type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema'\nimport type { Bounds } from '@/renderer/core/layout/types'\n\nconst props = defineProps<{\n nodeId: NodeId\n}>()\n\nconst modelValue = defineModel<Bounds>({\n default: () => ({ x: 0, y: 0, width: 512, height: 512 })\n})\n\nconst imageEl = useTemplateRef<HTMLImageElement>('imageEl')\nconst containerEl = useTemplateRef<HTMLDivElement>('containerEl')\n\nconst {\n imageUrl,\n isLoading,\n\n cropBoxStyle,\n cropImageStyle,\n resizeHandles,\n\n handleImageLoad,\n handleImageError,\n handleDragStart,\n handleDragMove,\n handleDragEnd,\n handleResizeStart,\n handleResizeMove,\n handleResizeEnd\n} = useImageCrop(props.nodeId, { imageEl, containerEl, modelValue })\n</script>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./vendor-primevue-DcMRXJN3.js";import"./vendor-other-DlQF6V2E.js";import"./Button-Do2I1OAA.js";import"./widgetPropFilter-CKhENku4.js";import"./layout-C9TPTaej.js";import"./WidgetWithControl-
|
|
1
|
+
import"./vendor-primevue-DcMRXJN3.js";import"./vendor-other-DlQF6V2E.js";import"./Button-Do2I1OAA.js";import"./widgetPropFilter-CKhENku4.js";import"./layout-C9TPTaej.js";import"./WidgetWithControl-Da6zUB5e.js";import{t as a}from"./WidgetInputNumber-DU_D0Fzy.js";export{a as default};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var ne=Object.defineProperty;var m=(n,u)=>ne(n,"name",{value:u,configurable:!0});import{F as oe}from"./vendor-primevue-DcMRXJN3.js";import{Ba as M,Co as A,Do as H,Ha as T,Jo as d,Ko as le,Ma as h,Oo as ue,Qo as ie,Ua as F,Va as W,Xo as C,Ya as $,_o as re,do as b,go as se,ja as I,mi as de,mo as pe,no as U,qa as ve,ro as S,xo as L,za as r,zo as P}from"./vendor-other-DlQF6V2E.js";import{n as me}from"./vendor-vue-D9IUuwPJ.js";import{t as ce}from"./widget-DNFXpyU8.js";import{t as g}from"./src-DTrob8OL.js";import{t as fe}from"./_plugin-vue_export-helper-PHE0iSCb.js";import{t as ge}from"./Slider-De1ykl8L.js";import{a as be,o as j,r as we}from"./widgetPropFilter-CKhENku4.js";import{t as J}from"./layout-C9TPTaej.js";import{t as q}from"./WidgetLayoutField-DXI3EnEF.js";import{t as Ve}from"./WidgetWithControl-Da6zUB5e.js";var xe=["aria-label"],_e=["disabled"],Ne={class:"relative min-w-[4ch] flex-1 py-1.5 my-0.25"},ye=["aria-valuenow","aria-valuemin","aria-valuemax","value","disabled"],he=["disabled"],G="w-8 bg-transparent border-0 text-sm text-smoke-700",Ie=$({__name:"WidgetInputNumberInput",props:U({widget:{}},{modelValue:{default:0},modelModifiers:{}}),emits:["update:modelValue"],setup(n){const{n:u}=me(),a=n,s=A("widgetContainer"),o=A("inputField"),l=P(!1);de(s,()=>{l.value&&(l.value=!1)});const f=r(()=>u(1.1).replace(/\p{Number}/gu,"")),N=r(()=>u(11111).replace(/\p{Number}/gu,""));function k(e){return e.replaceAll(N.value,"").replaceAll(f.value,".")}m(k,"unformatValue");const i=L(n,"modelValue"),p=r(()=>{const e=c.value??i.value;return e===""||!isFinite(e)?`${e}`:u(e,{useGrouping:Q.value,minimumFractionDigits:_.value,maximumFractionDigits:_.value})});function B(e){const{target:t}=e;if(!(t instanceof HTMLInputElement))return;const x=ce(k(t.value));x!==void 0?i.value=Math.min(v.value.max,Math.max(v.value.min,x)):t.value=p.value,l.value=!1}m(B,"updateValue");const R=r(()=>i.value>v.value.min&&!a.widget.options?.disabled),z=r(()=>i.value<v.value.max&&!a.widget.options?.disabled),v=r(()=>j(a.widget.options,we)),_=r(()=>{const e=a.widget.options?.precision;return typeof e=="number"&&e>=0?e:void 0}),w=r(()=>{if(a.widget.options?.step2!==void 0)return Number(a.widget.options.step2);const e=a.widget.options?.step;return e!==void 0&&e>10?Number(e)/10:_.value!==void 0?_.value===0?1:Number((1/Math.pow(10,_.value)).toFixed(_.value)):0}),Q=r(()=>a.widget.options?.useGrouping===!0),E=r(()=>{const e=i.value??0;return!Number.isFinite(e)||Math.abs(e)>Number.MAX_SAFE_INTEGER});function D(e){i.value=Math.min(v.value.max,Math.max(v.value.min,i.value+e))}m(D,"updateValueBy");const c=P(),V=P(0);function Y(e){if(a.widget.options?.disabled)return;const{target:t}=e;t instanceof HTMLElement&&(t.setPointerCapture(e.pointerId),c.value=i.value,V.value=0)}m(Y,"handleMouseDown");function Z(e){if(c.value===void 0)return;V.value+=e.movementX;const t=c.value+(V.value/10|0)*w.value;V.value%=10,c.value=Math.min(v.value.max,Math.max(v.value.min,t))}m(Z,"handleMouseMove");function ee(){const e=c.value;e!==void 0&&(i.value=e,c.value=void 0,V.value===0&&(l.value=!0,o.value?.focus(),o.value?.setSelectionRange(0,-1)),V.value=0)}m(ee,"handleMouseUp");const te=r(()=>E.value?"Increment/decrement disabled: value exceeds JavaScript precision limit (±2^53)":null),ae=r(()=>{const{max:e,min:t,step:x}=v.value;return t===void 0||e===void 0||x===void 0||(e-t)/x>=100?0:(((c.value??i.value)-t)/(e-t)*100).toFixed(0)});return(e,t)=>{const x=se("tooltip");return b(),W(q,{widget:e.widget},{default:H(()=>[ue((b(),F("div",S({ref_key:"widgetContainer",ref:s},v.value,{"aria-label":e.widget.name,class:d(g)(d(J),"grow text-xs flex h-7 relative")}),[M("div",{class:"bg-primary-background/15 absolute left-0 bottom-0 h-full rounded-lg pointer-events-none",style:ie({width:`${ae.value}%`})},null,4),E.value?T("",!0):(b(),F("button",{key:0,"data-testid":"decrement",class:C(d(g)(G,"pi pi-minus",!R.value&&"opacity-60")),disabled:!R.value,tabindex:"-1",onClick:t[0]||(t[0]=y=>i.value-=w.value)},null,10,_e)),M("div",Ne,[M("input",{ref_key:"inputField",ref:o,"aria-valuenow":c.value??i.value,"aria-valuemin":v.value.min,"aria-valuemax":v.value.max,class:C(d(g)("bg-transparent border-0 focus:outline-0 p-1 truncate text-sm absolute inset-0")),inputmode:"decimal",value:p.value,role:"spinbutton",tabindex:"0",disabled:e.widget.options?.disabled,autocomplete:"off",autocorrect:"off",spellcheck:"false",onBlur:B,onKeyup:I(B,["enter"]),onKeydown:[t[1]||(t[1]=I(h(y=>D(w.value),["prevent"]),["up"])),t[2]||(t[2]=I(h(y=>D(-w.value),["prevent"]),["down"])),t[3]||(t[3]=I(h(y=>D(10*w.value),["prevent"]),["page-up"])),t[4]||(t[4]=I(h(y=>D(-10*w.value),["prevent"]),["page-down"]))],onDragstart:t[5]||(t[5]=h(()=>{},["prevent"]))},null,42,ye),M("div",{class:C(d(g)("absolute inset-0 z-10 cursor-ew-resize",l.value&&"hidden pointer-events-none")),onPointerdown:Y,onPointermove:Z,onPointerup:ee,onPointercancel:t[6]||(t[6]=()=>{c.value=void 0,V.value=0})},null,34)]),pe(e.$slots,"default"),E.value?T("",!0):(b(),F("button",{key:1,"data-testid":"increment",class:C(d(g)(G,"pi pi-plus",!z.value&&"opacity-60")),disabled:!z.value,tabindex:"-1",onClick:t[7]||(t[7]=y=>i.value+=w.value)},null,10,he))],16,xe)),[[x,te.value]])]),_:3},8,["widget"])}}}),X=Ie;function Me(n,u,a=!1){return r(()=>{const s=le(u);if(n?.step2!==void 0)return Number(n.step2);const o=n?.step;if(o!==void 0&&o>10)return Number(o)/10;if(s===void 0)return a?void 0:0;if(s===0)return 1;const l=1/Math.pow(10,s);return a?l:Number(l.toFixed(s))})}m(Me,"useNumberStepCalculation");var K=g("inline-flex items-center justify-center border-0 bg-transparent text-inherit transition-colors duration-150 ease-in-out ","hover:bg-node-component-surface-hovered active:bg-node-component-surface-selected","disabled:bg-node-component-disabled disabled:text-node-icon-disabled disabled:cursor-not-allowed");function Ce(n){const{roundedLeft:u=!1,roundedRight:a=!1}=n??{},s=g(K,a&&"rounded-r-lg"),o=g(K,u&&"rounded-l-lg");return{incrementButton:{class:s},decrementButton:{class:o}}}m(Ce,"useNumberWidgetButtonPt");var We=$({__name:"WidgetInputNumberSlider",props:U({widget:{}},{modelValue:{default:0},modelModifiers:{}}),emits:["update:modelValue"],setup(n){const u=L(n,"modelValue"),a=P(0),s=m(p=>{p?.length&&(u.value=p[0])},"updateLocalValue"),o=m(p=>{if(p!==void 0){s([p]);return}a.value+=1},"handleNumberInputUpdate"),l=r(()=>j(n.widget.options,be)),f=n.widget.options?.precision,N=typeof f=="number"&&f>=0?f:void 0,k=Me(n.widget.options,N,!0),i=Ce({roundedLeft:!0,roundedRight:!0});return(p,B)=>(b(),W(q,{widget:p.widget},{default:H(()=>[M("div",{class:C(d(g)(d(J),"flex items-center gap-2 pl-3 pr-2"))},[ve(ge,S({"model-value":[u.value]},l.value,{class:"flex-grow text-xs",step:d(k),"aria-label":p.widget.name,"onUpdate:modelValue":s}),null,16,["model-value","step","aria-label"]),(b(),W(d(oe),S({key:a.value,"model-value":u.value},l.value,{step:d(k),"min-fraction-digits":d(N),"max-fraction-digits":d(N),"aria-label":p.widget.name,size:"small","pt:pc-input-text:root":"min-w-[4ch] bg-transparent border-none text-center truncate",class:"w-16",pt:d(i),"onUpdate:modelValue":o}),null,16,["model-value","step","min-fraction-digits","max-fraction-digits","aria-label","pt"]))],2)]),_:1},8,["widget"]))}}),O=fe(We,[["__scopeId","data-v-989ee2f9"]]),ke=$({__name:"WidgetInputNumber",props:U({widget:{}},{modelValue:{default:0},modelModifiers:{}}),emits:["update:modelValue"],setup(n){const u=n,a=L(n,"modelValue"),s=r(()=>!!u.widget.controlWidget);return(o,l)=>s.value?(b(),W(Ve,{key:0,modelValue:a.value,"onUpdate:modelValue":l[0]||(l[0]=f=>a.value=f),widget:o.widget,component:o.widget.type==="slider"?O:X},null,8,["modelValue","widget","component"])):(b(),W(re(o.widget.type==="slider"?O:X),S({key:1,modelValue:a.value,"onUpdate:modelValue":l[1]||(l[1]=f=>a.value=f),widget:o.widget},o.$attrs),null,16,["modelValue","widget"]))}}),Te=ke;export{Te as t};
|
|
2
|
+
|
|
3
|
+
//# sourceMappingURL=WidgetInputNumber-DU_D0Fzy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WidgetInputNumber-DU_D0Fzy.js","names":[],"sources":["../../src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue","../../src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue","../../src/renderer/extensions/vueNodes/widgets/composables/useNumberStepCalculation.ts","../../src/renderer/extensions/vueNodes/widgets/composables/useNumberWidgetButtonPt.ts","../../src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vue","../../src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberSlider.vue","../../src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumber.vue","../../src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumber.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { onClickOutside } from '@vueuse/core'\nimport { computed, ref, useTemplateRef } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nimport { evaluateInput } from '@/lib/litegraph/src/utils/widget'\nimport type { SimplifiedWidget } from '@/types/simplifiedWidget'\nimport { cn } from '@/utils/tailwindUtil'\nimport {\n INPUT_EXCLUDED_PROPS,\n filterWidgetProps\n} from '@/utils/widgetPropFilter'\n\nimport { WidgetInputBaseClass } from './layout'\nimport WidgetLayoutField from './layout/WidgetLayoutField.vue'\n\nconst { n } = useI18n()\n\nconst props = defineProps<{\n widget: SimplifiedWidget<number>\n}>()\n\nconst widgetContainer = useTemplateRef<HTMLDivElement>('widgetContainer')\nconst inputField = useTemplateRef<HTMLInputElement>('inputField')\nconst textEdit = ref(false)\nonClickOutside(widgetContainer, () => {\n if (textEdit.value) {\n textEdit.value = false\n }\n})\n\nconst decimalSeparator = computed(() => n(1.1).replace(/\\p{Number}/gu, ''))\nconst groupSeparator = computed(() => n(11111).replace(/\\p{Number}/gu, ''))\nfunction unformatValue(value: string) {\n return value\n .replaceAll(groupSeparator.value, '')\n .replaceAll(decimalSeparator.value, '.')\n}\n\nconst modelValue = defineModel<number>({ default: 0 })\n\nconst formattedValue = computed(() => {\n const unformattedValue = dragValue.value ?? modelValue.value\n if ((unformattedValue as unknown) === '' || !isFinite(unformattedValue))\n return `${unformattedValue}`\n\n return n(unformattedValue, {\n useGrouping: useGrouping.value,\n minimumFractionDigits: precision.value,\n maximumFractionDigits: precision.value\n })\n})\n\nfunction updateValue(e: UIEvent) {\n const { target } = e\n if (!(target instanceof HTMLInputElement)) return\n const parsed = evaluateInput(unformatValue(target.value))\n if (parsed !== undefined)\n modelValue.value = Math.min(\n filteredProps.value.max,\n Math.max(filteredProps.value.min, parsed)\n )\n else target.value = formattedValue.value\n\n textEdit.value = false\n}\n\nconst sharedButtonClass = 'w-8 bg-transparent border-0 text-sm text-smoke-700'\nconst canDecrement = computed(\n () =>\n modelValue.value > filteredProps.value.min &&\n !props.widget.options?.disabled\n)\nconst canIncrement = computed(\n () =>\n modelValue.value < filteredProps.value.max &&\n !props.widget.options?.disabled\n)\n\nconst filteredProps = computed(() =>\n filterWidgetProps(props.widget.options, INPUT_EXCLUDED_PROPS)\n)\n\n// Get the precision value for proper number formatting\nconst precision = computed(() => {\n const p = props.widget.options?.precision\n // Treat negative or non-numeric precision as undefined\n return typeof p === 'number' && p >= 0 ? p : undefined\n})\n\n// Calculate the step value based on precision or widget options\nconst stepValue = computed(() => {\n // Use step2 (correct input spec value) if available\n if (props.widget.options?.step2 !== undefined) {\n return Number(props.widget.options.step2)\n }\n // Use step / 10 for custom large step values (> 10) to match litegraph behavior\n // This is important for extensions like Impact Pack that use custom step values (e.g., 640)\n // We skip default step values (1, 10) to avoid affecting normal widgets\n const step = props.widget.options?.step\n if (step !== undefined && step > 10) {\n return Number(step) / 10\n }\n // Otherwise, derive from precision\n if (precision.value !== undefined) {\n if (precision.value === 0) {\n return 1\n }\n // For precision > 0, step = 1 / (10^precision)\n // precision 1 → 0.1, precision 2 → 0.01, etc.\n return Number((1 / Math.pow(10, precision.value)).toFixed(precision.value))\n }\n // Default to 'any' for unrestricted stepping\n return 0\n})\n\n// Disable grouping separators by default unless explicitly enabled by the node author\nconst useGrouping = computed(() => {\n return props.widget.options?.useGrouping === true\n})\n\n// Check if increment/decrement buttons should be disabled due to precision limits\nconst buttonsDisabled = computed(() => {\n const currentValue = modelValue.value ?? 0\n return (\n !Number.isFinite(currentValue) ||\n Math.abs(currentValue) > Number.MAX_SAFE_INTEGER\n )\n})\n\nfunction updateValueBy(delta: number) {\n modelValue.value = Math.min(\n filteredProps.value.max,\n Math.max(filteredProps.value.min, modelValue.value + delta)\n )\n}\n\nconst dragValue = ref<number>()\nconst dragDelta = ref(0)\nfunction handleMouseDown(e: PointerEvent) {\n if (props.widget.options?.disabled) return\n const { target } = e\n if (!(target instanceof HTMLElement)) return\n target.setPointerCapture(e.pointerId)\n dragValue.value = modelValue.value\n dragDelta.value = 0\n}\nfunction handleMouseMove(e: PointerEvent) {\n if (dragValue.value === undefined) return\n dragDelta.value += e.movementX\n const unclippedValue =\n dragValue.value + ((dragDelta.value / 10) | 0) * stepValue.value\n dragDelta.value %= 10\n dragValue.value = Math.min(\n filteredProps.value.max,\n Math.max(filteredProps.value.min, unclippedValue)\n )\n}\nfunction handleMouseUp() {\n const newValue = dragValue.value\n if (newValue === undefined) return\n modelValue.value = newValue\n dragValue.value = undefined\n\n if (dragDelta.value === 0) {\n textEdit.value = true\n inputField.value?.focus()\n inputField.value?.setSelectionRange(0, -1)\n }\n dragDelta.value = 0\n}\n\nconst buttonTooltip = computed(() => {\n if (buttonsDisabled.value) {\n return 'Increment/decrement disabled: value exceeds JavaScript precision limit (±2^53)'\n }\n return null\n})\n\nconst sliderWidth = computed(() => {\n const { max, min, step } = filteredProps.value\n if (\n min === undefined ||\n max === undefined ||\n step === undefined ||\n (max - min) / step >= 100\n )\n return 0\n const value = dragValue.value ?? modelValue.value\n const ratio = (value - min) / (max - min)\n return (ratio * 100).toFixed(0)\n})\n</script>\n\n<template>\n <WidgetLayoutField :widget>\n <div\n ref=\"widgetContainer\"\n v-tooltip=\"buttonTooltip\"\n v-bind=\"filteredProps\"\n :aria-label=\"widget.name\"\n :class=\"cn(WidgetInputBaseClass, 'grow text-xs flex h-7 relative')\"\n >\n <div\n class=\"bg-primary-background/15 absolute left-0 bottom-0 h-full rounded-lg pointer-events-none\"\n :style=\"{ width: `${sliderWidth}%` }\"\n />\n <button\n v-if=\"!buttonsDisabled\"\n data-testid=\"decrement\"\n :class=\"\n cn(sharedButtonClass, 'pi pi-minus', !canDecrement && 'opacity-60')\n \"\n :disabled=\"!canDecrement\"\n tabindex=\"-1\"\n @click=\"modelValue -= stepValue\"\n />\n <div class=\"relative min-w-[4ch] flex-1 py-1.5 my-0.25\">\n <input\n ref=\"inputField\"\n :aria-valuenow=\"dragValue ?? modelValue\"\n :aria-valuemin=\"filteredProps.min\"\n :aria-valuemax=\"filteredProps.max\"\n :class=\"\n cn(\n 'bg-transparent border-0 focus:outline-0 p-1 truncate text-sm absolute inset-0'\n )\n \"\n inputmode=\"decimal\"\n :value=\"formattedValue\"\n role=\"spinbutton\"\n tabindex=\"0\"\n :disabled=\"widget.options?.disabled\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\"\n @blur=\"updateValue\"\n @keyup.enter=\"updateValue\"\n @keydown.up.prevent=\"updateValueBy(stepValue)\"\n @keydown.down.prevent=\"updateValueBy(-stepValue)\"\n @keydown.page-up.prevent=\"updateValueBy(10 * stepValue)\"\n @keydown.page-down.prevent=\"updateValueBy(-10 * stepValue)\"\n @dragstart.prevent\n />\n <div\n :class=\"\n cn(\n 'absolute inset-0 z-10 cursor-ew-resize',\n textEdit && 'hidden pointer-events-none'\n )\n \"\n @pointerdown=\"handleMouseDown\"\n @pointermove=\"handleMouseMove\"\n @pointerup=\"handleMouseUp\"\n @pointercancel=\"\n () => {\n dragValue = undefined\n dragDelta = 0\n }\n \"\n />\n </div>\n\n <slot />\n <button\n v-if=\"!buttonsDisabled\"\n data-testid=\"increment\"\n :class=\"\n cn(sharedButtonClass, 'pi pi-plus', !canIncrement && 'opacity-60')\n \"\n :disabled=\"!canIncrement\"\n tabindex=\"-1\"\n @click=\"modelValue += stepValue\"\n />\n </div>\n </WidgetLayoutField>\n</template>\n","<script setup lang=\"ts\">\nimport { onClickOutside } from '@vueuse/core'\nimport { computed, ref, useTemplateRef } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nimport { evaluateInput } from '@/lib/litegraph/src/utils/widget'\nimport type { SimplifiedWidget } from '@/types/simplifiedWidget'\nimport { cn } from '@/utils/tailwindUtil'\nimport {\n INPUT_EXCLUDED_PROPS,\n filterWidgetProps\n} from '@/utils/widgetPropFilter'\n\nimport { WidgetInputBaseClass } from './layout'\nimport WidgetLayoutField from './layout/WidgetLayoutField.vue'\n\nconst { n } = useI18n()\n\nconst props = defineProps<{\n widget: SimplifiedWidget<number>\n}>()\n\nconst widgetContainer = useTemplateRef<HTMLDivElement>('widgetContainer')\nconst inputField = useTemplateRef<HTMLInputElement>('inputField')\nconst textEdit = ref(false)\nonClickOutside(widgetContainer, () => {\n if (textEdit.value) {\n textEdit.value = false\n }\n})\n\nconst decimalSeparator = computed(() => n(1.1).replace(/\\p{Number}/gu, ''))\nconst groupSeparator = computed(() => n(11111).replace(/\\p{Number}/gu, ''))\nfunction unformatValue(value: string) {\n return value\n .replaceAll(groupSeparator.value, '')\n .replaceAll(decimalSeparator.value, '.')\n}\n\nconst modelValue = defineModel<number>({ default: 0 })\n\nconst formattedValue = computed(() => {\n const unformattedValue = dragValue.value ?? modelValue.value\n if ((unformattedValue as unknown) === '' || !isFinite(unformattedValue))\n return `${unformattedValue}`\n\n return n(unformattedValue, {\n useGrouping: useGrouping.value,\n minimumFractionDigits: precision.value,\n maximumFractionDigits: precision.value\n })\n})\n\nfunction updateValue(e: UIEvent) {\n const { target } = e\n if (!(target instanceof HTMLInputElement)) return\n const parsed = evaluateInput(unformatValue(target.value))\n if (parsed !== undefined)\n modelValue.value = Math.min(\n filteredProps.value.max,\n Math.max(filteredProps.value.min, parsed)\n )\n else target.value = formattedValue.value\n\n textEdit.value = false\n}\n\nconst sharedButtonClass = 'w-8 bg-transparent border-0 text-sm text-smoke-700'\nconst canDecrement = computed(\n () =>\n modelValue.value > filteredProps.value.min &&\n !props.widget.options?.disabled\n)\nconst canIncrement = computed(\n () =>\n modelValue.value < filteredProps.value.max &&\n !props.widget.options?.disabled\n)\n\nconst filteredProps = computed(() =>\n filterWidgetProps(props.widget.options, INPUT_EXCLUDED_PROPS)\n)\n\n// Get the precision value for proper number formatting\nconst precision = computed(() => {\n const p = props.widget.options?.precision\n // Treat negative or non-numeric precision as undefined\n return typeof p === 'number' && p >= 0 ? p : undefined\n})\n\n// Calculate the step value based on precision or widget options\nconst stepValue = computed(() => {\n // Use step2 (correct input spec value) if available\n if (props.widget.options?.step2 !== undefined) {\n return Number(props.widget.options.step2)\n }\n // Use step / 10 for custom large step values (> 10) to match litegraph behavior\n // This is important for extensions like Impact Pack that use custom step values (e.g., 640)\n // We skip default step values (1, 10) to avoid affecting normal widgets\n const step = props.widget.options?.step\n if (step !== undefined && step > 10) {\n return Number(step) / 10\n }\n // Otherwise, derive from precision\n if (precision.value !== undefined) {\n if (precision.value === 0) {\n return 1\n }\n // For precision > 0, step = 1 / (10^precision)\n // precision 1 → 0.1, precision 2 → 0.01, etc.\n return Number((1 / Math.pow(10, precision.value)).toFixed(precision.value))\n }\n // Default to 'any' for unrestricted stepping\n return 0\n})\n\n// Disable grouping separators by default unless explicitly enabled by the node author\nconst useGrouping = computed(() => {\n return props.widget.options?.useGrouping === true\n})\n\n// Check if increment/decrement buttons should be disabled due to precision limits\nconst buttonsDisabled = computed(() => {\n const currentValue = modelValue.value ?? 0\n return (\n !Number.isFinite(currentValue) ||\n Math.abs(currentValue) > Number.MAX_SAFE_INTEGER\n )\n})\n\nfunction updateValueBy(delta: number) {\n modelValue.value = Math.min(\n filteredProps.value.max,\n Math.max(filteredProps.value.min, modelValue.value + delta)\n )\n}\n\nconst dragValue = ref<number>()\nconst dragDelta = ref(0)\nfunction handleMouseDown(e: PointerEvent) {\n if (props.widget.options?.disabled) return\n const { target } = e\n if (!(target instanceof HTMLElement)) return\n target.setPointerCapture(e.pointerId)\n dragValue.value = modelValue.value\n dragDelta.value = 0\n}\nfunction handleMouseMove(e: PointerEvent) {\n if (dragValue.value === undefined) return\n dragDelta.value += e.movementX\n const unclippedValue =\n dragValue.value + ((dragDelta.value / 10) | 0) * stepValue.value\n dragDelta.value %= 10\n dragValue.value = Math.min(\n filteredProps.value.max,\n Math.max(filteredProps.value.min, unclippedValue)\n )\n}\nfunction handleMouseUp() {\n const newValue = dragValue.value\n if (newValue === undefined) return\n modelValue.value = newValue\n dragValue.value = undefined\n\n if (dragDelta.value === 0) {\n textEdit.value = true\n inputField.value?.focus()\n inputField.value?.setSelectionRange(0, -1)\n }\n dragDelta.value = 0\n}\n\nconst buttonTooltip = computed(() => {\n if (buttonsDisabled.value) {\n return 'Increment/decrement disabled: value exceeds JavaScript precision limit (±2^53)'\n }\n return null\n})\n\nconst sliderWidth = computed(() => {\n const { max, min, step } = filteredProps.value\n if (\n min === undefined ||\n max === undefined ||\n step === undefined ||\n (max - min) / step >= 100\n )\n return 0\n const value = dragValue.value ?? modelValue.value\n const ratio = (value - min) / (max - min)\n return (ratio * 100).toFixed(0)\n})\n</script>\n\n<template>\n <WidgetLayoutField :widget>\n <div\n ref=\"widgetContainer\"\n v-tooltip=\"buttonTooltip\"\n v-bind=\"filteredProps\"\n :aria-label=\"widget.name\"\n :class=\"cn(WidgetInputBaseClass, 'grow text-xs flex h-7 relative')\"\n >\n <div\n class=\"bg-primary-background/15 absolute left-0 bottom-0 h-full rounded-lg pointer-events-none\"\n :style=\"{ width: `${sliderWidth}%` }\"\n />\n <button\n v-if=\"!buttonsDisabled\"\n data-testid=\"decrement\"\n :class=\"\n cn(sharedButtonClass, 'pi pi-minus', !canDecrement && 'opacity-60')\n \"\n :disabled=\"!canDecrement\"\n tabindex=\"-1\"\n @click=\"modelValue -= stepValue\"\n />\n <div class=\"relative min-w-[4ch] flex-1 py-1.5 my-0.25\">\n <input\n ref=\"inputField\"\n :aria-valuenow=\"dragValue ?? modelValue\"\n :aria-valuemin=\"filteredProps.min\"\n :aria-valuemax=\"filteredProps.max\"\n :class=\"\n cn(\n 'bg-transparent border-0 focus:outline-0 p-1 truncate text-sm absolute inset-0'\n )\n \"\n inputmode=\"decimal\"\n :value=\"formattedValue\"\n role=\"spinbutton\"\n tabindex=\"0\"\n :disabled=\"widget.options?.disabled\"\n autocomplete=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\"\n @blur=\"updateValue\"\n @keyup.enter=\"updateValue\"\n @keydown.up.prevent=\"updateValueBy(stepValue)\"\n @keydown.down.prevent=\"updateValueBy(-stepValue)\"\n @keydown.page-up.prevent=\"updateValueBy(10 * stepValue)\"\n @keydown.page-down.prevent=\"updateValueBy(-10 * stepValue)\"\n @dragstart.prevent\n />\n <div\n :class=\"\n cn(\n 'absolute inset-0 z-10 cursor-ew-resize',\n textEdit && 'hidden pointer-events-none'\n )\n \"\n @pointerdown=\"handleMouseDown\"\n @pointermove=\"handleMouseMove\"\n @pointerup=\"handleMouseUp\"\n @pointercancel=\"\n () => {\n dragValue = undefined\n dragDelta = 0\n }\n \"\n />\n </div>\n\n <slot />\n <button\n v-if=\"!buttonsDisabled\"\n data-testid=\"increment\"\n :class=\"\n cn(sharedButtonClass, 'pi pi-plus', !canIncrement && 'opacity-60')\n \"\n :disabled=\"!canIncrement\"\n tabindex=\"-1\"\n @click=\"modelValue += stepValue\"\n />\n </div>\n </WidgetLayoutField>\n</template>\n","import { computed, toValue } from 'vue'\nimport type { MaybeRefOrGetter } from 'vue'\n\ninterface NumberWidgetOptions {\n step?: number\n step2?: number\n precision?: number\n}\n\n/**\n * Shared composable for calculating step values in number input widgets\n * Handles both explicit step2 values and precision-derived steps\n */\nexport function useNumberStepCalculation(\n options: NumberWidgetOptions | undefined,\n precisionArg: MaybeRefOrGetter<number | undefined>,\n returnUndefinedForDefault = false\n) {\n return computed(() => {\n const precision = toValue(precisionArg)\n // Use step2 (correct input spec value) if available\n if (options?.step2 !== undefined) {\n return Number(options.step2)\n }\n // Use step / 10 for custom large step values (> 10) to match litegraph behavior\n // This is important for extensions like Impact Pack that use custom step values (e.g., 640)\n // We skip default step values (1, 10) to avoid affecting normal widgets\n const step = options?.step\n if (step !== undefined && step > 10) {\n return Number(step) / 10\n }\n\n if (precision === undefined) {\n return returnUndefinedForDefault ? undefined : 0\n }\n\n if (precision === 0) return 1\n\n // For precision > 0, step = 1 / (10^precision)\n const calculatedStep = 1 / Math.pow(10, precision)\n return returnUndefinedForDefault\n ? calculatedStep\n : Number(calculatedStep.toFixed(precision))\n })\n}\n","import { cn } from '@comfyorg/tailwind-utils'\n\nconst sharedButtonClasses = cn(\n 'inline-flex items-center justify-center border-0 bg-transparent text-inherit transition-colors duration-150 ease-in-out ',\n 'hover:bg-node-component-surface-hovered active:bg-node-component-surface-selected',\n 'disabled:bg-node-component-disabled disabled:text-node-icon-disabled disabled:cursor-not-allowed'\n)\n\nexport function useNumberWidgetButtonPt(options?: {\n roundedLeft?: boolean\n roundedRight?: boolean\n}) {\n const { roundedLeft = false, roundedRight = false } = options ?? {}\n\n const increment = cn(sharedButtonClasses, roundedRight && 'rounded-r-lg')\n const decrement = cn(sharedButtonClasses, roundedLeft && 'rounded-l-lg')\n\n return {\n incrementButton: {\n class: increment\n },\n decrementButton: {\n class: decrement\n }\n }\n}\n","<template>\n <WidgetLayoutField :widget=\"widget\">\n <div :class=\"cn(WidgetInputBaseClass, 'flex items-center gap-2 pl-3 pr-2')\">\n <Slider\n :model-value=\"[modelValue]\"\n v-bind=\"filteredProps\"\n class=\"flex-grow text-xs\"\n :step=\"stepValue\"\n :aria-label=\"widget.name\"\n @update:model-value=\"updateLocalValue\"\n />\n <InputNumber\n :key=\"timesEmptied\"\n :model-value=\"modelValue\"\n v-bind=\"filteredProps\"\n :step=\"stepValue\"\n :min-fraction-digits=\"precision\"\n :max-fraction-digits=\"precision\"\n :aria-label=\"widget.name\"\n size=\"small\"\n pt:pc-input-text:root=\"min-w-[4ch] bg-transparent border-none text-center truncate\"\n class=\"w-16\"\n :pt=\"sliderNumberPt\"\n @update:model-value=\"handleNumberInputUpdate\"\n />\n </div>\n </WidgetLayoutField>\n</template>\n\n<script setup lang=\"ts\">\nimport InputNumber from 'primevue/inputnumber'\nimport { computed, ref } from 'vue'\n\nimport Slider from '@/components/ui/slider/Slider.vue'\nimport type { SimplifiedWidget } from '@/types/simplifiedWidget'\nimport { cn } from '@/utils/tailwindUtil'\nimport {\n STANDARD_EXCLUDED_PROPS,\n filterWidgetProps\n} from '@/utils/widgetPropFilter'\n\nimport { useNumberStepCalculation } from '../composables/useNumberStepCalculation'\nimport { useNumberWidgetButtonPt } from '../composables/useNumberWidgetButtonPt'\nimport { WidgetInputBaseClass } from './layout'\nimport WidgetLayoutField from './layout/WidgetLayoutField.vue'\n\nconst { widget } = defineProps<{\n widget: SimplifiedWidget<number>\n}>()\n\nconst modelValue = defineModel<number>({ default: 0 })\n\nconst timesEmptied = ref(0)\n\nconst updateLocalValue = (newValue: number[] | undefined): void => {\n if (newValue?.length) modelValue.value = newValue[0]\n}\n\nconst handleNumberInputUpdate = (newValue: number | undefined) => {\n if (newValue !== undefined) {\n updateLocalValue([newValue])\n return\n }\n timesEmptied.value += 1\n}\n\nconst filteredProps = computed(() =>\n filterWidgetProps(widget.options, STANDARD_EXCLUDED_PROPS)\n)\n\nconst p = widget.options?.precision\nconst precision = typeof p === 'number' && p >= 0 ? p : undefined\n\n// Calculate the step value based on precision or widget options\nconst stepValue = useNumberStepCalculation(widget.options, precision, true)\n\nconst sliderNumberPt = useNumberWidgetButtonPt({\n roundedLeft: true,\n roundedRight: true\n})\n</script>\n\n<style scoped>\n:deep(.p-inputnumber-button.p-disabled .pi),\n:deep(.p-inputnumber-button.p-disabled .p-icon) {\n color: var(--color-node-icon-disabled) !important;\n}\n</style>\n","<template>\n <WidgetLayoutField :widget=\"widget\">\n <div :class=\"cn(WidgetInputBaseClass, 'flex items-center gap-2 pl-3 pr-2')\">\n <Slider\n :model-value=\"[modelValue]\"\n v-bind=\"filteredProps\"\n class=\"flex-grow text-xs\"\n :step=\"stepValue\"\n :aria-label=\"widget.name\"\n @update:model-value=\"updateLocalValue\"\n />\n <InputNumber\n :key=\"timesEmptied\"\n :model-value=\"modelValue\"\n v-bind=\"filteredProps\"\n :step=\"stepValue\"\n :min-fraction-digits=\"precision\"\n :max-fraction-digits=\"precision\"\n :aria-label=\"widget.name\"\n size=\"small\"\n pt:pc-input-text:root=\"min-w-[4ch] bg-transparent border-none text-center truncate\"\n class=\"w-16\"\n :pt=\"sliderNumberPt\"\n @update:model-value=\"handleNumberInputUpdate\"\n />\n </div>\n </WidgetLayoutField>\n</template>\n\n<script setup lang=\"ts\">\nimport InputNumber from 'primevue/inputnumber'\nimport { computed, ref } from 'vue'\n\nimport Slider from '@/components/ui/slider/Slider.vue'\nimport type { SimplifiedWidget } from '@/types/simplifiedWidget'\nimport { cn } from '@/utils/tailwindUtil'\nimport {\n STANDARD_EXCLUDED_PROPS,\n filterWidgetProps\n} from '@/utils/widgetPropFilter'\n\nimport { useNumberStepCalculation } from '../composables/useNumberStepCalculation'\nimport { useNumberWidgetButtonPt } from '../composables/useNumberWidgetButtonPt'\nimport { WidgetInputBaseClass } from './layout'\nimport WidgetLayoutField from './layout/WidgetLayoutField.vue'\n\nconst { widget } = defineProps<{\n widget: SimplifiedWidget<number>\n}>()\n\nconst modelValue = defineModel<number>({ default: 0 })\n\nconst timesEmptied = ref(0)\n\nconst updateLocalValue = (newValue: number[] | undefined): void => {\n if (newValue?.length) modelValue.value = newValue[0]\n}\n\nconst handleNumberInputUpdate = (newValue: number | undefined) => {\n if (newValue !== undefined) {\n updateLocalValue([newValue])\n return\n }\n timesEmptied.value += 1\n}\n\nconst filteredProps = computed(() =>\n filterWidgetProps(widget.options, STANDARD_EXCLUDED_PROPS)\n)\n\nconst p = widget.options?.precision\nconst precision = typeof p === 'number' && p >= 0 ? p : undefined\n\n// Calculate the step value based on precision or widget options\nconst stepValue = useNumberStepCalculation(widget.options, precision, true)\n\nconst sliderNumberPt = useNumberWidgetButtonPt({\n roundedLeft: true,\n roundedRight: true\n})\n</script>\n\n<style scoped>\n:deep(.p-inputnumber-button.p-disabled .pi),\n:deep(.p-inputnumber-button.p-disabled .p-icon) {\n color: var(--color-node-icon-disabled) !important;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type {\n SimplifiedControlWidget,\n SimplifiedWidget\n} from '@/types/simplifiedWidget'\n\nimport WidgetInputNumberInput from './WidgetInputNumberInput.vue'\nimport WidgetInputNumberSlider from './WidgetInputNumberSlider.vue'\nimport WidgetWithControl from './WidgetWithControl.vue'\n\nconst props = defineProps<{\n widget: SimplifiedWidget<number>\n}>()\n\nconst modelValue = defineModel<number>({ default: 0 })\n\nconst hasControlAfterGenerate = computed(() => {\n return !!props.widget.controlWidget\n})\n</script>\n\n<template>\n <WidgetWithControl\n v-if=\"hasControlAfterGenerate\"\n v-model=\"modelValue\"\n :widget=\"widget as SimplifiedControlWidget<number>\"\n :component=\"\n widget.type === 'slider'\n ? WidgetInputNumberSlider\n : WidgetInputNumberInput\n \"\n />\n <component\n :is=\"\n widget.type === 'slider'\n ? WidgetInputNumberSlider\n : WidgetInputNumberInput\n \"\n v-else\n v-model=\"modelValue\"\n :widget=\"widget\"\n v-bind=\"$attrs\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type {\n SimplifiedControlWidget,\n SimplifiedWidget\n} from '@/types/simplifiedWidget'\n\nimport WidgetInputNumberInput from './WidgetInputNumberInput.vue'\nimport WidgetInputNumberSlider from './WidgetInputNumberSlider.vue'\nimport WidgetWithControl from './WidgetWithControl.vue'\n\nconst props = defineProps<{\n widget: SimplifiedWidget<number>\n}>()\n\nconst modelValue = defineModel<number>({ default: 0 })\n\nconst hasControlAfterGenerate = computed(() => {\n return !!props.widget.controlWidget\n})\n</script>\n\n<template>\n <WidgetWithControl\n v-if=\"hasControlAfterGenerate\"\n v-model=\"modelValue\"\n :widget=\"widget as SimplifiedControlWidget<number>\"\n :component=\"\n widget.type === 'slider'\n ? WidgetInputNumberSlider\n : WidgetInputNumberInput\n \"\n />\n <component\n :is=\"\n widget.type === 'slider'\n ? WidgetInputNumberSlider\n : WidgetInputNumberInput\n \"\n v-else\n v-model=\"modelValue\"\n :widget=\"widget\"\n v-bind=\"$attrs\"\n />\n</template>\n"],"mappings":"4+BCmEM,EAAoB,gMAnD1B,KAAM,CAAE,EAAA,CAAA,EAAM,GAAA,EAER,EAAQ,EAIR,EAAkB,EAA+B,iBAAA,EACjD,EAAa,EAAiC,YAAA,EAC9C,EAAW,EAAI,EAAA,EACrB,GAAe,EAAA,IAAuB,CAChC,EAAS,QACX,EAAS,MAAQ,MAIrB,MAAM,EAAmB,EAAA,IAAe,EAAE,GAAA,EAAK,QAAQ,eAAgB,EAAA,CAAG,EACpE,EAAiB,EAAA,IAAe,EAAE,KAAA,EAAO,QAAQ,eAAgB,EAAA,CAAG,EAC1E,SAAS,EAAc,EAAe,CACpC,OAAO,EACJ,WAAW,EAAe,MAAO,EAAA,EACjC,WAAW,EAAiB,MAAO,GAAA,EAH/B,EAAA,EAAA,iBAMT,MAAM,EAAa,EAAmB,EAAA,YAAA,EAEhC,EAAiB,EAAA,IAAe,CACpC,MAAM,EAAmB,EAAU,OAAS,EAAW,MACvD,OAAK,IAAiC,IAAM,CAAC,SAAS,CAAA,EAC7C,GAAG,CAAA,GAEL,EAAE,EAAkB,CACzB,YAAa,EAAY,MACzB,sBAAuB,EAAU,MACjC,sBAAuB,EAAU,MAClC,IAGH,SAAS,EAAY,EAAY,CAC/B,KAAM,CAAE,OAAA,CAAA,EAAW,EACnB,GAAI,EAAE,aAAkB,kBAAmB,OAC3C,MAAM,EAAS,GAAc,EAAc,EAAO,KAAA,CAAM,EACpD,IAAW,OACb,EAAW,MAAQ,KAAK,IACtB,EAAc,MAAM,IACpB,KAAK,IAAI,EAAc,MAAM,IAAK,CAAA,CAAM,EAEvC,EAAO,MAAQ,EAAe,MAEnC,EAAS,MAAQ,GAXV,EAAA,EAAA,eAeT,MAAM,EAAe,EAAA,IAEjB,EAAW,MAAQ,EAAc,MAAM,KACvC,CAAC,EAAM,OAAO,SAAS,QAAA,EAErB,EAAe,EAAA,IAEjB,EAAW,MAAQ,EAAc,MAAM,KACvC,CAAC,EAAM,OAAO,SAAS,QAAA,EAGrB,EAAgB,EAAA,IACpB,EAAkB,EAAM,OAAO,QAAS,EAAA,CAAoB,EAIxD,EAAY,EAAA,IAAe,CAC/B,MAAM,EAAI,EAAM,OAAO,SAAS,UAEhC,OAAO,OAAO,GAAM,UAAY,GAAK,EAAI,EAAI,SAIzC,EAAY,EAAA,IAAe,CAE/B,GAAI,EAAM,OAAO,SAAS,QAAU,OAClC,OAAO,OAAO,EAAM,OAAO,QAAQ,KAAA,EAKrC,MAAM,EAAO,EAAM,OAAO,SAAS,KACnC,OAAI,IAAS,QAAa,EAAO,GACxB,OAAO,CAAA,EAAQ,GAGpB,EAAU,QAAU,OAClB,EAAU,QAAU,EACf,EAIF,QAAQ,EAAI,KAAK,IAAI,GAAI,EAAU,KAAA,GAAQ,QAAQ,EAAU,KAAA,CAAM,EAGrE,IAIH,EAAc,EAAA,IACX,EAAM,OAAO,SAAS,cAAgB,IAIzC,EAAkB,EAAA,IAAe,CACrC,MAAM,EAAe,EAAW,OAAS,EACzC,MACE,CAAC,OAAO,SAAS,CAAA,GACjB,KAAK,IAAI,CAAA,EAAgB,OAAO,mBAIpC,SAAS,EAAc,EAAe,CACpC,EAAW,MAAQ,KAAK,IACtB,EAAc,MAAM,IACpB,KAAK,IAAI,EAAc,MAAM,IAAK,EAAW,MAAQ,CAAA,CAAK,EAHrD,EAAA,EAAA,iBAOT,MAAM,EAAY,EAAA,EACZ,EAAY,EAAI,CAAA,EACtB,SAAS,EAAgB,EAAiB,CACxC,GAAI,EAAM,OAAO,SAAS,SAAU,OACpC,KAAM,CAAE,OAAA,CAAA,EAAW,EACb,aAAkB,cACxB,EAAO,kBAAkB,EAAE,SAAA,EAC3B,EAAU,MAAQ,EAAW,MAC7B,EAAU,MAAQ,GANX,EAAA,EAAA,mBAQT,SAAS,EAAgB,EAAiB,CACxC,GAAI,EAAU,QAAU,OAAW,OACnC,EAAU,OAAS,EAAE,UACrB,MAAM,EACJ,EAAU,OAAU,EAAU,MAAQ,GAAM,GAAK,EAAU,MAC7D,EAAU,OAAS,GACnB,EAAU,MAAQ,KAAK,IACrB,EAAc,MAAM,IACpB,KAAK,IAAI,EAAc,MAAM,IAAK,CAAA,CAAc,EAR3C,EAAA,EAAA,mBAWT,SAAS,IAAgB,CACvB,MAAM,EAAW,EAAU,MACvB,IAAa,SACjB,EAAW,MAAQ,EACnB,EAAU,MAAQ,OAEd,EAAU,QAAU,IACtB,EAAS,MAAQ,GACjB,EAAW,OAAO,MAAA,EAClB,EAAW,OAAO,kBAAkB,EAAG,EAAA,GAEzC,EAAU,MAAQ,GAXX,EAAA,GAAA,iBAcT,MAAM,GAAgB,EAAA,IAChB,EAAgB,MACX,iFAEF,MAGH,GAAc,EAAA,IAAe,CACjC,KAAM,CAAE,IAAA,EAAK,IAAA,EAAK,KAAA,CAAA,EAAS,EAAc,MACzC,OACE,IAAQ,QACR,IAAQ,QACR,IAAS,SACR,EAAM,GAAO,GAAQ,IAEf,KACK,EAAU,OAAS,EAAW,OACrB,IAAQ,EAAM,GACrB,KAAK,QAAQ,CAAA,uxDCjL/B,SAAgB,GACd,EACA,EACA,EAA4B,GAC5B,CACA,OAAO,EAAA,IAAe,CACpB,MAAM,EAAY,GAAQ,CAAA,EAE1B,GAAI,GAAS,QAAU,OACrB,OAAO,OAAO,EAAQ,KAAA,EAKxB,MAAM,EAAO,GAAS,KACtB,GAAI,IAAS,QAAa,EAAO,GAC/B,OAAO,OAAO,CAAA,EAAQ,GAGxB,GAAI,IAAc,OAChB,OAAO,EAA4B,OAAY,EAGjD,GAAI,IAAc,EAAG,MAAO,GAG5B,MAAM,EAAiB,EAAI,KAAK,IAAI,GAAI,CAAA,EACxC,OAAO,EACH,EACA,OAAO,EAAe,QAAQ,CAAA,CAAU,IA7BhC,EAAA,GAAA,4BCXhB,IAAM,EAAsB,EAC1B,2HACA,oFACA,kGAAA,EAGF,SAAgB,GAAwB,EAGrC,CACD,KAAM,CAAE,YAAA,EAAc,GAAO,aAAA,EAAe,EAAA,EAAU,GAAW,CAAA,EAE3D,EAAY,EAAG,EAAqB,GAAgB,cAAA,EACpD,EAAY,EAAG,EAAqB,GAAe,cAAA,EAEzD,MAAO,CACL,gBAAiB,CACf,MAAO,CAAA,EAET,gBAAiB,CACf,MAAO,CAAA,GAdG,EAAA,GAAA,2KE0ChB,MAAM,EAAa,EAAmB,EAAA,YAAA,EAEhC,EAAe,EAAI,CAAA,EAEnB,EAAA,EAAoB,GAAyC,CAC7D,GAAU,SAAQ,EAAW,MAAQ,EAAS,CAAA,IAD9C,oBAIA,EAAA,EAA2B,GAAiC,CAChE,GAAI,IAAa,OAAW,CAC1B,EAAiB,CAAC,CAAA,CAAS,EAC3B,OAEF,EAAa,OAAS,GALlB,2BAQA,EAAgB,EAAA,IACpB,EAAkB,EAAA,OAAO,QAAS,EAAA,CAAuB,EAGrD,EAAI,EAAA,OAAO,SAAS,UACpB,EAAY,OAAO,GAAM,UAAY,GAAK,EAAI,EAAI,OAGlD,EAAY,GAAyB,EAAA,OAAO,QAAS,EAAW,EAAA,EAEhE,EAAiB,GAAwB,CAC7C,YAAa,GACb,aAAc,GACf,o4BEnED,MAAM,EAAQ,EAIR,EAAa,EAAmB,EAAA,YAAA,EAEhC,EAA0B,EAAA,IACvB,CAAC,CAAC,EAAM,OAAO"}
|
comfyui_frontend_package/static/assets/{WidgetLegacy-Bslv9wZZ.js → WidgetLegacy-B4nipUM9.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./vendor-primevue-DcMRXJN3.js";import"./vendor-other-DlQF6V2E.js";import"./api-
|
|
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{At as f}from"./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";export{f as default};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var O=Object.defineProperty;var a=(i,r)=>O(i,"name",{value:r,configurable:!0});import{$ as K}from"./vendor-primevue-DcMRXJN3.js";import{$o as S,Ba as h,Do as J,Ha as B,Jo as n,Ka as Q,Pa as X,Po as Y,Qo as G,Ua as b,Xi as Z,Ya as ee,co as ae,do as k,io as te,lo as U,n as ne,no as oe,po as re,qa as j,xo as le,za as F,zo as v}from"./vendor-other-DlQF6V2E.js";import{A as x,It as D}from"./api-CUAc7rDA.js";import"./remoteConfig-CZcEXsZS.js";import"./colorUtil-CzxntCbX.js";import"./useErrorHandling-CI8_F4yx.js";import"./Button-Do2I1OAA.js";import"./PanelTemplate-BjN5XNg2.js";import{P as q}from"./dialogService-BZ1FmjZL.js";import"./vendor-tiptap-_UqYL7N_.js";import"./vendor-xterm-BU_lcTPR.js";import"./vendor-three-BFcUNSs9.js";import"./markdownRendererUtil-DglHsU8t.js";import"./userStore-BkgQPjq6.js";import{t as ie}from"./audioUtils-DpjpcKbH.js";import{t as N}from"./audioService-DvndbCi2.js";var ue={viewBox:"0 0 24 24",width:"1.2em",height:"1.2em"};function se(i,r){return k(),b("svg",ue,[...r[0]||(r[0]=[h("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[h("path",{d:"M12 19v3m7-12v2a7 7 0 0 1-14 0v-2"}),h("rect",{width:"6",height:"13",x:"9",y:"2",rx:"3"})],-1)])])}a(se,"render");var de=Y({name:"lucide-mic",render:se});function ce(i,r={}){const o=v(!1),f=v(0),u=v(null);async function e(){if(!i.value)return!1;try{return await i.value.play(),o.value=!0,!0}catch(A){return console.warn("Audio playback failed:",A),o.value=!1,!1}}a(e,"play");function t(){i.value&&(i.value.pause(),i.value.currentTime=0),o.value=!1,r.onPlaybackEnded&&r.onPlaybackEnded()}a(t,"stop");function s(){o.value=!1,r.onPlaybackEnded&&r.onPlaybackEnded()}a(s,"onPlaybackEnded");function g(){i.value?.duration&&r.onMetadataLoaded&&r.onMetadataLoaded(i.value.duration)}a(g,"onMetadataLoaded");async function p(){f.value+=1,await te()}a(p,"resetAudioElement");function l(){return i.value?.currentTime||0}a(l,"getCurrentTime");function y(){return i.value?.duration||0}return a(y,"getDuration"),{isPlaying:o,audioElementKey:f,play:e,stop:t,onPlaybackEnded:s,onMetadataLoaded:g,resetAudioElement:p,getCurrentTime:l,getDuration:y,playbackTimerInterval:u}}a(ce,"useAudioPlayback");function ve(i={}){const r=v(!1),o=v(null),f=v([]),u=v(null),e=v(null);async function t(){try{e.value?.startsWith("blob:")&&URL.revokeObjectURL(e.value),f.value=[],e.value=null,await N().registerWavEncoder(),u.value=await navigator.mediaDevices.getUserMedia({audio:!0}),o.value=new ne(u.value,{mimeType:"audio/wav"}),o.value.ondataavailable=l=>{f.value.push(l.data)},o.value.onstop=async()=>{const l=new Blob(f.value,{type:"audio/wav"});e.value?.startsWith("blob:")&&URL.revokeObjectURL(e.value),e.value=URL.createObjectURL(l),i.onRecordingComplete&&await i.onRecordingComplete(l),g()},o.value.start(100),r.value=!0}catch(l){throw i.onError&&i.onError(l),l}}a(t,"startRecording");function s(){o.value&&o.value.state!=="inactive"?o.value.stop():g()}a(s,"stopRecording");function g(){r.value=!1,u.value&&(u.value.getTracks().forEach(l=>l.stop()),u.value=null)}a(g,"cleanup");function p(){s(),e.value&&(URL.revokeObjectURL(e.value),e.value=null)}return a(p,"dispose"),U(()=>{p()}),{isRecording:r,recordedURL:e,mediaRecorder:o,startRecording:t,stopRecording:s,dispose:p}}a(ve,"useAudioRecorder");function me(i={}){const{barCount:r=18,minHeight:o=4,maxHeight:f=32}=i,u=v(Array.from({length:r},()=>({height:16}))),e=v(null),t=v(null),s=v(null),g=v(null),p=v(null);function l(){u.value=Array.from({length:r},()=>({height:Math.random()*(f-o)+o}))}a(l,"initWaveform");function y(m){m.value&&(t.value&&s.value?A():w(),g.value=requestAnimationFrame(()=>y(m)))}a(y,"updateWaveform");function A(){if(!t.value||!s.value)return;t.value.getByteFrequencyData(s.value);const m=Math.floor(s.value.length/r);u.value=u.value.map((V,L)=>{let z=0;for(let _=0;_<m;_++)z+=s.value[L*m+_]||0;return{height:z/m/255*(f-o)+o}})}a(A,"updateWaveformFromAudio");function w(){u.value=u.value.map(m=>({height:Math.max(o,Math.min(f,m.height+(Math.random()-.5)*4))}))}a(w,"updateWaveformRandom");async function I(){e.value&&e.value.state!=="closed"&&await e.value.close(),e.value=null,p.value=null}a(I,"setupAudioContext");async function T(m){e.value=new window.AudioContext,t.value=e.value.createAnalyser(),e.value.createMediaStreamSource(m).connect(t.value),t.value.fftSize=256,s.value=new Uint8Array(t.value.frequencyBinCount)}a(T,"setupRecordingVisualization");async function P(m){return e.value&&e.value.state!=="closed"&&await e.value.close(),p.value=null,m?(e.value=new window.AudioContext,t.value=e.value.createAnalyser(),p.value=e.value.createMediaElementSource(m),p.value.connect(t.value),t.value.connect(e.value.destination),t.value.fftSize=256,s.value=new Uint8Array(t.value.frequencyBinCount),!0):!1}a(P,"setupPlaybackVisualization");function E(){g.value&&(cancelAnimationFrame(g.value),g.value=null)}a(E,"stopWaveform");function W(){E(),e.value&&e.value.state!=="closed"&&e.value.close(),e.value=null,p.value=null}return a(W,"dispose"),U(()=>{W()}),{waveformBars:u,initWaveform:l,updateWaveform:y,setupAudioContext:I,setupRecordingVisualization:T,setupPlaybackVisualization:P,stopWaveform:E,dispose:W}}a(me,"useAudioWaveform");var fe={class:"relative"},pe={class:"mb-4"},ge={key:0,class:"flex h-14 w-full min-w-0 items-center gap-2 rounded-lg px-3 bg-node-component-surface text-text-secondary"},ye={class:"flex shrink-0 items-center gap-1"},he={class:"text-xs"},be={class:"text-sm"},ke={class:"flex h-8 min-w-0 flex-1 items-center gap-2 overflow-hidden"},we=["title"],Re=["title"],xe=["title"],_e=["title"],Ae=["src"],Pe=ee({__name:"WidgetRecordAudio",props:oe({readonly:{type:Boolean},nodeId:{}},{modelValue:{default:""},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const r=i,o=v();let f="";const u=ve({onRecordingComplete:W,onError:a(()=>{D().addAlert(x("g.micPermissionDenied")||"Microphone permission denied")},"onError")}),e=me({barCount:18,minHeight:4,maxHeight:32}),t=ce(o,{onPlaybackEnded:_,onMetadataLoaded:a(c=>{!w.value&&!l.value&&(s.value=Math.floor(c))},"onMetadataLoaded")}),s=v(0),{pause:g,resume:p}=Z(()=>{s.value+=1},1e3,{immediate:!1}),{isRecording:l,recordedURL:y}=u,{waveformBars:A}=e,{isPlaying:w,audioElementKey:I}=t,T=F(()=>l.value||w.value),P=le(i,"modelValue"),E=F(()=>!r.nodeId||!q.canvas.graph?null:q.canvas.graph.getNodeById(r.nodeId));async function W(c){try{const d=await N().convertBlobToFileAndSubmit(c);P.value=d,f=d}catch{D().addAlert("Failed to upload recorded audio")}}a(W,"handleRecordingComplete");async function m(){if(!r.readonly)try{if(await e.setupAudioContext(),await u.startRecording(),u.mediaRecorder.value){const c=u.mediaRecorder.value.stream;c&&await e.setupRecordingVisualization(c)}s.value=0,p(),e.initWaveform(),e.updateWaveform(T)}catch(c){console.error("Failed to start recording:",c)}}a(m,"handleStartRecording");function V(){u.stopRecording(),g(),e.stopWaveform()}a(V,"handleStopRecording");async function L(){if(!y.value||(s.value=0,await t.resetAudioElement(),await new Promise(d=>setTimeout(d,50)),!o.value)||!await e.setupPlaybackVisualization(o.value))return;await t.play(),e.initWaveform(),e.updateWaveform(T);const c=setInterval(()=>{s.value=Math.floor(t.getCurrentTime())},100);t.playbackTimerInterval.value=c}a(L,"handlePlayRecording");function z(){t.stop(),_()}a(z,"handleStopPlayback");function _(){e.stopWaveform(),t.playbackTimerInterval.value!==null&&(clearInterval(t.playbackTimerInterval.value),t.playbackTimerInterval.value=null);const c=t.getDuration();c?s.value=Math.floor(c):s.value=0}a(_,"handlePlaybackEnded");async function H(){return l.value&&u.mediaRecorder.value&&(u.mediaRecorder.value.stop(),await new Promise((c,d)=>{let C=0;const R=50,M=a(()=>{!l.value&&P.value?c(void 0):++C>=R?d(new Error("Recording serialization timeout after 5 seconds")):setTimeout(M,100)},"checkRecording");M()})),P.value||f||""}a(H,"serializeValue");function $(){const c=E.value;if(!c?.widgets)return;const d=c.widgets.find(C=>C.name==="audio");d&&(d.serializeValue=H)}return a($,"registerWidgetSerialization"),ae(()=>{e.initWaveform(),$()}),U(()=>{t.playbackTimerInterval.value!==null&&(clearInterval(t.playbackTimerInterval.value),t.playbackTimerInterval.value=null)}),(c,d)=>{const C=de;return k(),b("div",fe,[h("div",pe,[j(n(K),{class:"text-base-foreground w-full border-0 bg-secondary-background hover:bg-secondary-background-hover",disabled:n(l)||c.readonly,onClick:m},{default:J(()=>[Q(S(n(x)("g.startRecording","Start Recording"))+" ",1),j(C,{class:"ml-1"})]),_:1},8,["disabled"])]),n(l)||n(w)||n(y)?(k(),b("div",ge,[h("div",ye,[h("span",he,S(n(l)?n(x)("g.listening","Listening..."):n(w)?n(x)("g.playing","Playing..."):n(y)?n(x)("g.ready","Ready"):""),1),h("span",be,S(n(ie)(s.value)),1)]),h("div",ke,[(k(!0),b(X,null,re(n(A),(R,M)=>(k(),b("div",{key:M,class:"max-h-8 min-h-1 w-0.75 rounded-[1.5px] bg-slate-100 transition-all duration-100",style:G({height:R.height+"px"}),title:`Bar ${M+1}: ${R.height}px`},null,12,we))),128))]),n(l)?(k(),b("button",{key:0,title:n(x)("g.stopRecording","Stop Recording"),class:"flex shrink-0 size-8 animate-pulse items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors",onClick:V},d[2]||(d[2]=[h("div",{class:"size-2.5 rounded-sm bg-danger-100"},null,-1)]),8,Re)):!n(l)&&n(y)&&!n(w)?(k(),b("button",{key:1,title:n(x)("g.playRecording")||"Play Recording",class:"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors",onClick:L},d[3]||(d[3]=[h("i",{class:"text-text-secondary icon-[lucide--play] size-4"},null,-1)]),8,xe)):n(w)?(k(),b("button",{key:2,title:n(x)("g.stopPlayback")||"Stop Playback",class:"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors",onClick:z},d[4]||(d[4]=[h("i",{class:"text-text-secondary icon-[lucide--square] size-4"},null,-1)]),8,_e)):B("",!0)])):B("",!0),n(y)?(k(),b("audio",{ref_key:"audioRef",ref:o,key:n(I),src:n(y),class:"hidden",onEnded:d[0]||(d[0]=(...R)=>n(t).onPlaybackEnded&&n(t).onPlaybackEnded(...R)),onLoadedmetadata:d[1]||(d[1]=(...R)=>n(t).onMetadataLoaded&&n(t).onMetadataLoaded(...R))},null,40,Ae)):B("",!0)])}}}),He=Pe;export{He as default};
|
|
1
|
+
var O=Object.defineProperty;var a=(i,r)=>O(i,"name",{value:r,configurable:!0});import{$ as K}from"./vendor-primevue-DcMRXJN3.js";import{$o as S,Ba as h,Do as J,Ha as B,Jo as n,Ka as Q,Pa as X,Po as Y,Qo as G,Ua as b,Xi as Z,Ya as ee,co as ae,do as k,io as te,lo as U,n as ne,no as oe,po as re,qa as j,xo as le,za as F,zo as v}from"./vendor-other-DlQF6V2E.js";import{A as x,It as D}from"./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{P as q}from"./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 ie}from"./audioUtils-DD4rUYVZ.js";import{t as N}from"./audioService-DvVaKhuU.js";var ue={viewBox:"0 0 24 24",width:"1.2em",height:"1.2em"};function se(i,r){return k(),b("svg",ue,[...r[0]||(r[0]=[h("g",{fill:"none",stroke:"currentColor","stroke-linecap":"round","stroke-linejoin":"round","stroke-width":"2"},[h("path",{d:"M12 19v3m7-12v2a7 7 0 0 1-14 0v-2"}),h("rect",{width:"6",height:"13",x:"9",y:"2",rx:"3"})],-1)])])}a(se,"render");var de=Y({name:"lucide-mic",render:se});function ce(i,r={}){const o=v(!1),f=v(0),u=v(null);async function e(){if(!i.value)return!1;try{return await i.value.play(),o.value=!0,!0}catch(A){return console.warn("Audio playback failed:",A),o.value=!1,!1}}a(e,"play");function t(){i.value&&(i.value.pause(),i.value.currentTime=0),o.value=!1,r.onPlaybackEnded&&r.onPlaybackEnded()}a(t,"stop");function s(){o.value=!1,r.onPlaybackEnded&&r.onPlaybackEnded()}a(s,"onPlaybackEnded");function g(){i.value?.duration&&r.onMetadataLoaded&&r.onMetadataLoaded(i.value.duration)}a(g,"onMetadataLoaded");async function p(){f.value+=1,await te()}a(p,"resetAudioElement");function l(){return i.value?.currentTime||0}a(l,"getCurrentTime");function y(){return i.value?.duration||0}return a(y,"getDuration"),{isPlaying:o,audioElementKey:f,play:e,stop:t,onPlaybackEnded:s,onMetadataLoaded:g,resetAudioElement:p,getCurrentTime:l,getDuration:y,playbackTimerInterval:u}}a(ce,"useAudioPlayback");function ve(i={}){const r=v(!1),o=v(null),f=v([]),u=v(null),e=v(null);async function t(){try{e.value?.startsWith("blob:")&&URL.revokeObjectURL(e.value),f.value=[],e.value=null,await N().registerWavEncoder(),u.value=await navigator.mediaDevices.getUserMedia({audio:!0}),o.value=new ne(u.value,{mimeType:"audio/wav"}),o.value.ondataavailable=l=>{f.value.push(l.data)},o.value.onstop=async()=>{const l=new Blob(f.value,{type:"audio/wav"});e.value?.startsWith("blob:")&&URL.revokeObjectURL(e.value),e.value=URL.createObjectURL(l),i.onRecordingComplete&&await i.onRecordingComplete(l),g()},o.value.start(100),r.value=!0}catch(l){throw i.onError&&i.onError(l),l}}a(t,"startRecording");function s(){o.value&&o.value.state!=="inactive"?o.value.stop():g()}a(s,"stopRecording");function g(){r.value=!1,u.value&&(u.value.getTracks().forEach(l=>l.stop()),u.value=null)}a(g,"cleanup");function p(){s(),e.value&&(URL.revokeObjectURL(e.value),e.value=null)}return a(p,"dispose"),U(()=>{p()}),{isRecording:r,recordedURL:e,mediaRecorder:o,startRecording:t,stopRecording:s,dispose:p}}a(ve,"useAudioRecorder");function me(i={}){const{barCount:r=18,minHeight:o=4,maxHeight:f=32}=i,u=v(Array.from({length:r},()=>({height:16}))),e=v(null),t=v(null),s=v(null),g=v(null),p=v(null);function l(){u.value=Array.from({length:r},()=>({height:Math.random()*(f-o)+o}))}a(l,"initWaveform");function y(m){m.value&&(t.value&&s.value?A():w(),g.value=requestAnimationFrame(()=>y(m)))}a(y,"updateWaveform");function A(){if(!t.value||!s.value)return;t.value.getByteFrequencyData(s.value);const m=Math.floor(s.value.length/r);u.value=u.value.map((V,L)=>{let z=0;for(let _=0;_<m;_++)z+=s.value[L*m+_]||0;return{height:z/m/255*(f-o)+o}})}a(A,"updateWaveformFromAudio");function w(){u.value=u.value.map(m=>({height:Math.max(o,Math.min(f,m.height+(Math.random()-.5)*4))}))}a(w,"updateWaveformRandom");async function I(){e.value&&e.value.state!=="closed"&&await e.value.close(),e.value=null,p.value=null}a(I,"setupAudioContext");async function T(m){e.value=new window.AudioContext,t.value=e.value.createAnalyser(),e.value.createMediaStreamSource(m).connect(t.value),t.value.fftSize=256,s.value=new Uint8Array(t.value.frequencyBinCount)}a(T,"setupRecordingVisualization");async function P(m){return e.value&&e.value.state!=="closed"&&await e.value.close(),p.value=null,m?(e.value=new window.AudioContext,t.value=e.value.createAnalyser(),p.value=e.value.createMediaElementSource(m),p.value.connect(t.value),t.value.connect(e.value.destination),t.value.fftSize=256,s.value=new Uint8Array(t.value.frequencyBinCount),!0):!1}a(P,"setupPlaybackVisualization");function E(){g.value&&(cancelAnimationFrame(g.value),g.value=null)}a(E,"stopWaveform");function W(){E(),e.value&&e.value.state!=="closed"&&e.value.close(),e.value=null,p.value=null}return a(W,"dispose"),U(()=>{W()}),{waveformBars:u,initWaveform:l,updateWaveform:y,setupAudioContext:I,setupRecordingVisualization:T,setupPlaybackVisualization:P,stopWaveform:E,dispose:W}}a(me,"useAudioWaveform");var fe={class:"relative"},pe={class:"mb-4"},ge={key:0,class:"flex h-14 w-full min-w-0 items-center gap-2 rounded-lg px-3 bg-node-component-surface text-text-secondary"},ye={class:"flex shrink-0 items-center gap-1"},he={class:"text-xs"},be={class:"text-sm"},ke={class:"flex h-8 min-w-0 flex-1 items-center gap-2 overflow-hidden"},we=["title"],Re=["title"],xe=["title"],_e=["title"],Ae=["src"],Pe=ee({__name:"WidgetRecordAudio",props:oe({readonly:{type:Boolean},nodeId:{}},{modelValue:{default:""},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const r=i,o=v();let f="";const u=ve({onRecordingComplete:W,onError:a(()=>{D().addAlert(x("g.micPermissionDenied")||"Microphone permission denied")},"onError")}),e=me({barCount:18,minHeight:4,maxHeight:32}),t=ce(o,{onPlaybackEnded:_,onMetadataLoaded:a(c=>{!w.value&&!l.value&&(s.value=Math.floor(c))},"onMetadataLoaded")}),s=v(0),{pause:g,resume:p}=Z(()=>{s.value+=1},1e3,{immediate:!1}),{isRecording:l,recordedURL:y}=u,{waveformBars:A}=e,{isPlaying:w,audioElementKey:I}=t,T=F(()=>l.value||w.value),P=le(i,"modelValue"),E=F(()=>!r.nodeId||!q.canvas.graph?null:q.canvas.graph.getNodeById(r.nodeId));async function W(c){try{const d=await N().convertBlobToFileAndSubmit(c);P.value=d,f=d}catch{D().addAlert("Failed to upload recorded audio")}}a(W,"handleRecordingComplete");async function m(){if(!r.readonly)try{if(await e.setupAudioContext(),await u.startRecording(),u.mediaRecorder.value){const c=u.mediaRecorder.value.stream;c&&await e.setupRecordingVisualization(c)}s.value=0,p(),e.initWaveform(),e.updateWaveform(T)}catch(c){console.error("Failed to start recording:",c)}}a(m,"handleStartRecording");function V(){u.stopRecording(),g(),e.stopWaveform()}a(V,"handleStopRecording");async function L(){if(!y.value||(s.value=0,await t.resetAudioElement(),await new Promise(d=>setTimeout(d,50)),!o.value)||!await e.setupPlaybackVisualization(o.value))return;await t.play(),e.initWaveform(),e.updateWaveform(T);const c=setInterval(()=>{s.value=Math.floor(t.getCurrentTime())},100);t.playbackTimerInterval.value=c}a(L,"handlePlayRecording");function z(){t.stop(),_()}a(z,"handleStopPlayback");function _(){e.stopWaveform(),t.playbackTimerInterval.value!==null&&(clearInterval(t.playbackTimerInterval.value),t.playbackTimerInterval.value=null);const c=t.getDuration();c?s.value=Math.floor(c):s.value=0}a(_,"handlePlaybackEnded");async function H(){return l.value&&u.mediaRecorder.value&&(u.mediaRecorder.value.stop(),await new Promise((c,d)=>{let C=0;const R=50,M=a(()=>{!l.value&&P.value?c(void 0):++C>=R?d(new Error("Recording serialization timeout after 5 seconds")):setTimeout(M,100)},"checkRecording");M()})),P.value||f||""}a(H,"serializeValue");function $(){const c=E.value;if(!c?.widgets)return;const d=c.widgets.find(C=>C.name==="audio");d&&(d.serializeValue=H)}return a($,"registerWidgetSerialization"),ae(()=>{e.initWaveform(),$()}),U(()=>{t.playbackTimerInterval.value!==null&&(clearInterval(t.playbackTimerInterval.value),t.playbackTimerInterval.value=null)}),(c,d)=>{const C=de;return k(),b("div",fe,[h("div",pe,[j(n(K),{class:"text-base-foreground w-full border-0 bg-secondary-background hover:bg-secondary-background-hover",disabled:n(l)||c.readonly,onClick:m},{default:J(()=>[Q(S(n(x)("g.startRecording","Start Recording"))+" ",1),j(C,{class:"ml-1"})]),_:1},8,["disabled"])]),n(l)||n(w)||n(y)?(k(),b("div",ge,[h("div",ye,[h("span",he,S(n(l)?n(x)("g.listening","Listening..."):n(w)?n(x)("g.playing","Playing..."):n(y)?n(x)("g.ready","Ready"):""),1),h("span",be,S(n(ie)(s.value)),1)]),h("div",ke,[(k(!0),b(X,null,re(n(A),(R,M)=>(k(),b("div",{key:M,class:"max-h-8 min-h-1 w-0.75 rounded-[1.5px] bg-slate-100 transition-all duration-100",style:G({height:R.height+"px"}),title:`Bar ${M+1}: ${R.height}px`},null,12,we))),128))]),n(l)?(k(),b("button",{key:0,title:n(x)("g.stopRecording","Stop Recording"),class:"flex shrink-0 size-8 animate-pulse items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors",onClick:V},d[2]||(d[2]=[h("div",{class:"size-2.5 rounded-sm bg-danger-100"},null,-1)]),8,Re)):!n(l)&&n(y)&&!n(w)?(k(),b("button",{key:1,title:n(x)("g.playRecording")||"Play Recording",class:"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors",onClick:L},d[3]||(d[3]=[h("i",{class:"text-text-secondary icon-[lucide--play] size-4"},null,-1)]),8,xe)):n(w)?(k(),b("button",{key:2,title:n(x)("g.stopPlayback")||"Stop Playback",class:"flex shrink-0 size-8 items-center justify-center rounded-full border-0 bg-smoke-500/33 transition-colors",onClick:z},d[4]||(d[4]=[h("i",{class:"text-text-secondary icon-[lucide--square] size-4"},null,-1)]),8,_e)):B("",!0)])):B("",!0),n(y)?(k(),b("audio",{ref_key:"audioRef",ref:o,key:n(I),src:n(y),class:"hidden",onEnded:d[0]||(d[0]=(...R)=>n(t).onPlaybackEnded&&n(t).onPlaybackEnded(...R)),onLoadedmetadata:d[1]||(d[1]=(...R)=>n(t).onMetadataLoaded&&n(t).onMetadataLoaded(...R))},null,40,Ae)):B("",!0)])}}}),He=Pe;export{He as default};
|
|
2
2
|
|
|
3
|
-
//# sourceMappingURL=WidgetRecordAudio-
|
|
3
|
+
//# sourceMappingURL=WidgetRecordAudio-Nk8dH238.js.map
|