@8wave/ai-elements 0.119.0-beta.1 → 0.119.0-beta.15
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.
- package/dist/_chunks/{PkStreamingMarkdown-kpEBZA4d.js → PkStreamingMarkdown-Bry3y6Ru.js} +3 -3
- package/dist/_chunks/PkStreamingMarkdown-Bry3y6Ru.js.map +1 -0
- package/dist/_chunks/{PkToolShowArtifact-B8TOTS6A.js → PkToolShowArtifact-CfJLe8vD.js} +2 -2
- package/dist/_chunks/{PkToolShowArtifact-B8TOTS6A.js.map → PkToolShowArtifact-CfJLe8vD.js.map} +1 -1
- package/dist/_chunks/{PkToolShowContactForm-B89p05XM.js → PkToolShowContactForm--9XOVqNB.js} +5 -5
- package/dist/_chunks/PkToolShowContactForm--9XOVqNB.js.map +1 -0
- package/dist/_chunks/{PkToolShowForm-DTKQtFij.js → PkToolShowForm-CGAc1O6K.js} +2 -2
- package/dist/_chunks/{PkToolShowForm-DTKQtFij.js.map → PkToolShowForm-CGAc1O6K.js.map} +1 -1
- package/dist/_chunks/{PkToolShowSources-CbwixpOb.js → PkToolShowSources-BJ-XFrLD.js} +3 -3
- package/dist/_chunks/{PkToolShowSources-CbwixpOb.js.map → PkToolShowSources-BJ-XFrLD.js.map} +1 -1
- package/dist/_chunks/{markdown-c59ir6tw.js → markdown-DpoAzJSk.js} +64 -61
- package/dist/_chunks/markdown-DpoAzJSk.js.map +1 -0
- package/dist/ai-elements.es.js +95 -36
- package/dist/ai-elements.es.js.map +1 -1
- package/dist-vue/PkChatbot.js +1 -1
- package/dist-vue/PkChatbotEmptyState.js +1 -1
- package/dist-vue/PkChatbotInput.js +1 -1
- package/dist-vue/PkChatbotMessages.js +1 -1
- package/dist-vue/PkChatbotStepPayload.js +1 -1
- package/dist-vue/PkChatbotStepToolDetail.js +1 -1
- package/dist-vue/PkChatbotSteps.js +1 -1
- package/dist-vue/PkChatbotViewChat.js +1 -1
- package/dist-vue/PkChatbotViewFiles.js +1 -1
- package/dist-vue/_chunks/{Document-B-oyVh7v.js → Document-CV-RJu_p.js} +64 -61
- package/dist-vue/_chunks/Document-CV-RJu_p.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbot-C_OzxC0s.js → PkChatbot-UzdAjTRl.js} +5 -5
- package/dist-vue/_chunks/PkChatbot-UzdAjTRl.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotEmptyState-BEQCnqui.js → PkChatbotEmptyState-Toj4CqXV.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotEmptyState-BEQCnqui.js.map → PkChatbotEmptyState-Toj4CqXV.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotInput-KJxWrDIT.js → PkChatbotInput-BfZqRpQ2.js} +2 -2
- package/dist-vue/_chunks/PkChatbotInput-BfZqRpQ2.js.map +1 -0
- package/dist-vue/_chunks/{PkChatbotMessages-Zhuxom46.js → PkChatbotMessages-D9uf0NMI.js} +14 -14
- package/dist-vue/_chunks/{PkChatbotMessages-Zhuxom46.js.map → PkChatbotMessages-D9uf0NMI.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotStepPayload-Da4N5CKa.js → PkChatbotStepPayload-D0eoPBQ8.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotStepPayload-Da4N5CKa.js.map → PkChatbotStepPayload-D0eoPBQ8.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotStepToolDetail-rrtImvq5.js → PkChatbotStepToolDetail-CMx4cw1D.js} +3 -3
- package/dist-vue/_chunks/{PkChatbotStepToolDetail-rrtImvq5.js.map → PkChatbotStepToolDetail-CMx4cw1D.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotSteps-LEfOolAc.js → PkChatbotSteps-DeZQhGRU.js} +5 -5
- package/dist-vue/_chunks/{PkChatbotSteps-LEfOolAc.js.map → PkChatbotSteps-DeZQhGRU.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewChat-BJ0YHCvA.js → PkChatbotViewChat-B_7IdZIz.js} +6 -6
- package/dist-vue/_chunks/{PkChatbotViewChat-BJ0YHCvA.js.map → PkChatbotViewChat-B_7IdZIz.js.map} +1 -1
- package/dist-vue/_chunks/{PkChatbotViewFiles-gqCumfod.js → PkChatbotViewFiles-CA20TBFY.js} +2 -2
- package/dist-vue/_chunks/{PkChatbotViewFiles-gqCumfod.js.map → PkChatbotViewFiles-CA20TBFY.js.map} +1 -1
- package/dist-vue/_chunks/{PkStreamingMarkdown-BWEvuFZm.js → PkStreamingMarkdown-C55Fi0Pd.js} +2 -2
- package/dist-vue/_chunks/{PkStreamingMarkdown-BWEvuFZm.js.map → PkStreamingMarkdown-C55Fi0Pd.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowArtifact-tNEG6-r_.js → PkToolShowArtifact-z1qTnFkA.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowArtifact-tNEG6-r_.js.map → PkToolShowArtifact-z1qTnFkA.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowContactForm-DBC6f9gR.js → PkToolShowContactForm-Y0lrHXhr.js} +5 -5
- package/dist-vue/_chunks/PkToolShowContactForm-Y0lrHXhr.js.map +1 -0
- package/dist-vue/_chunks/{PkToolShowDiagram-Bbq0ETt1.js → PkToolShowDiagram-BJ_ryTsD.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowDiagram-Bbq0ETt1.js.map → PkToolShowDiagram-BJ_ryTsD.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowForm-BG-8aTHy.js → PkToolShowForm-CZFWZub7.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowForm-BG-8aTHy.js.map → PkToolShowForm-CZFWZub7.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowImageGallery-DXn-bxHv.js → PkToolShowImageGallery-CkfXP_lD.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowImageGallery-DXn-bxHv.js.map → PkToolShowImageGallery-CkfXP_lD.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowProductList-BZ_fDRCq.js → PkToolShowProductList-De-PtmD-.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowProductList-BZ_fDRCq.js.map → PkToolShowProductList-De-PtmD-.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowSources-CUURb0PG.js → PkToolShowSources-CSN7S0zo.js} +3 -3
- package/dist-vue/_chunks/{PkToolShowSources-CUURb0PG.js.map → PkToolShowSources-CSN7S0zo.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowVideo-FNlPjswi.js → PkToolShowVideo-B_Q93E2y.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowVideo-FNlPjswi.js.map → PkToolShowVideo-B_Q93E2y.js.map} +1 -1
- package/dist-vue/_chunks/{PkToolShowWebPages-CWV79tsb.js → PkToolShowWebPages-D3CdjJUc.js} +2 -2
- package/dist-vue/_chunks/{PkToolShowWebPages-CWV79tsb.js.map → PkToolShowWebPages-D3CdjJUc.js.map} +1 -1
- package/dist-vue/_chunks/{utils-Dk2jFXR_.js → utils-CwIMEuAv.js} +3 -3
- package/dist-vue/_chunks/{utils-Dk2jFXR_.js.map → utils-CwIMEuAv.js.map} +1 -1
- package/dist-vue/composables.js +61 -3
- package/dist-vue/composables.js.map +1 -1
- package/dist-vue/index.js +4017 -4004
- package/dist-vue/index.js.map +1 -1
- package/dist-vue/locales.js +36 -8
- package/dist-vue/packages/models/src/schema/Document.d.ts +25 -0
- package/dist-vue/packages/models/src/schema/Notification.d.ts +2 -0
- package/dist-vue/packages/models/src/schema/Platform.d.ts +72 -0
- package/dist-vue/style.css +1 -1
- package/package.json +1 -1
- package/dist/_chunks/PkStreamingMarkdown-kpEBZA4d.js.map +0 -1
- package/dist/_chunks/PkToolShowContactForm-B89p05XM.js.map +0 -1
- package/dist/_chunks/markdown-c59ir6tw.js.map +0 -1
- package/dist-vue/_chunks/Document-B-oyVh7v.js.map +0 -1
- package/dist-vue/_chunks/PkChatbot-C_OzxC0s.js.map +0 -1
- package/dist-vue/_chunks/PkChatbotInput-KJxWrDIT.js.map +0 -1
- package/dist-vue/_chunks/PkToolShowContactForm-DBC6f9gR.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PkChatbot-UzdAjTRl.js","names":["_useModel","__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","__unplugin_components_3","__unplugin_components_4","__unplugin_components_5","_openBlock","_createElementBlock","_normalizeClass","_normalizeStyle","_createElementVNode","_unref","_Fragment","_createVNode","_mergeProps","_createBlock","PkAvatar","_createCommentVNode","_toDisplayString","_withCtx","_renderSlot","_normalizeProps","_guardReactiveProps","_createTextVNode","PkChatbotViewChat","_createSlots","_renderList","PkChatbotViewConversations","PkChatbotViewFiles","PkChatbotViewProfile","PkStreamingMarkdown","_sfc_main","provideChatImagePolicy","PkChatbotViewConversations_default","PkChatbotViewChat_default","provideShortUrlResolver","PkChatbotViewFiles_default","useLocalizedString","resolveContrastColor","agentThemeStyle","PkAvatar_default","ChatbotProfileContextKey","PkChatbotViewProfile_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","PkChatbot_default","defineComponent","\"chatId\"","\"chatIdModifiers\"","__expose","__emit","slots","useSlots","$t","useI18n","props","__props","emit","chatId","useModel","store","useChatbotStore","hashes","storeToRefs","storeAgentId","toRef","profile","inject","canManageProfile","computed","canSignIn","watch","canManage","activeView","navigate","watchEffect","id","localChatId","chatError","error","parsedError","isFullscreen","isPanel","chatbotEl","useTemplateRef","chatbotWidth","useElementSize","isPhoneWidth","isTightWidth","isWideWidth","isReasoningAgent","useColorsForAgentHeader","showHeaderMenu","themeClass","isDark","mainColor","contrastColor","themeStyle","footerMessage","title","isReady","chat","activeMessage","messages","newAgentId","newChatId","newView","message","_component_VvButton","VvButton","_component_VvIcon","VvIcon","_component_VvDropdownAction","VvDropdownAction","_component_VvDropdown","VvDropdown","_component_VvButtonGroup","VvButtonGroup","_component_VvAlert","VvAlert","openBlock","createElementBlock","normalizeClass","normalizeStyle","createCommentVNode","createElementVNode","unref","createBlock","Fragment","createVNode","mergeProps","_cache","toDisplayString","withCtx","renderSlot","_ctx","normalizeProps","guardReactiveProps","startNewChat","stopGeneration","createTextVNode","$event","createSlots","renderList","slotName","slotData","PkStreamingMarkdown_default"],"sources":["../../../../packages/components/src/chat/PkChatbot.vue","../../../../packages/components/src/chat/PkChatbot.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import {\n computed,\n inject,\n toRef,\n useTemplateRef,\n watch,\n watchEffect,\n useSlots,\n } from 'vue'\n import { useElementSize } from '@vueuse/core'\n import { storeToRefs } from 'pinia'\n import { useI18n } from 'vue-i18n'\n import type {\n AgentInterface,\n AgentModel,\n AgentFileUpload,\n AgentGatewayOptions,\n AgentVoiceCapability,\n ChatMessageActions,\n RevisedAnswer,\n UIChatMessage,\n AgentTools,\n } from 'models'\n import {\n useChatbotStore,\n useLocalizedString,\n provideShortUrlResolver,\n } from 'composables'\n import PkAvatar from './PkAvatar.vue'\n import PkChatbotViewChat from './PkChatbotViewChat.vue'\n import PkChatbotViewConversations from './PkChatbotViewConversations.vue'\n import PkChatbotViewFiles from './PkChatbotViewFiles.vue'\n import PkChatbotViewProfile from './PkChatbotViewProfile.vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import { ChatbotProfileContextKey } from './chatbotProfileContext'\n import { provideChatImagePolicy } from './chatImagePolicy'\n import { agentThemeStyle, resolveContrastColor } from './utils'\n\n // Captured in script setup to avoid TS7022 circular inference in template\n const slots = useSlots()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const props = defineProps<{\n baseUrl: string\n basePath?: string\n agentId: string\n agentType?: 'reasoning' | 'chat'\n userId?: string\n name?: string\n model?: string\n agentModel?: AgentModel\n agentTools?: AgentTools\n agentInterface?: AgentInterface\n actions?: ChatMessageActions[]\n revisedAnswers?: RevisedAnswer[]\n headers?: Record<string, string>\n systemTheme?: 'light' | 'dark'\n agentFileUpload?: AgentFileUpload\n /** Voice configuration from the agent settings: enables the talk button. */\n voice?: AgentVoiceCapability\n fallbackModels?: string[]\n gatewayOptions?: Partial<AgentGatewayOptions>\n externalContext?: Record<string, unknown>\n /** Layout modifier: `widget` (default) keeps the contained layout with header, `fullscreen` removes header/background for full-page usage (the page provides the chrome), `panel` keeps the header but slims it down for a docked side panel (the host provides background and border) */\n modifier?: 'widget' | 'fullscreen' | 'panel'\n /** Display name of the current user, used for the `{name}` placeholder in the fullscreen greeting */\n userName?: string\n /** Show the \"Files in this chat\" menu for hosts that don't provide the\n * profile context but whose user is authenticated (e.g. the backoffice\n * playground). The widget host relies on `canManageProfile` instead. */\n userFilesEnabled?: boolean\n }>()\n const emit = defineEmits<{\n 'message-update': [message: UIChatMessage]\n 'show-info': [message: UIChatMessage]\n revise: [message: UIChatMessage]\n error: [error: { type: string; title: string; status: number }]\n }>()\n\n const chatId = defineModel<string | undefined>('chatId', {\n type: String,\n default: undefined,\n })\n\n const store = useChatbotStore(props.agentId)\n\n // Resolve backend short-urls (`/api/r/<hash>`) back to their real target\n // for display in tool components. Batched + cached across the chat tree.\n provideShortUrlResolver((hashes) =>\n store.apiClient.resolveShortUrls(hashes),\n )\n\n const { messages, chat, localChatId, activeView, chatError, isDark } =\n storeToRefs(store)\n\n // Ref to store.agentId for watchers (avoids duplicate-key with agentId prop)\n const storeAgentId = toRef(store, 'agentId')\n\n const { startNewChat, stopGeneration, regenerate, navigate, sendMessage } =\n store\n\n // Images in the answers and the tool cards load by themselves only from\n // the backend this chat talks to and from the hosts the agent lists.\n provideChatImagePolicy(\n () => props.agentInterface?.imageHosts,\n () => props.baseUrl,\n )\n\n // Optional profile-management context provided by the host widget.\n // Present only for authenticated, non-anonymous sessions.\n const profile = inject(ChatbotProfileContextKey, undefined)\n const canManageProfile = computed(\n () => profile?.canManageProfile.value ?? false,\n )\n // Anonymous users get a \"Sign in\" entry instead of the profile one,\n // provided the host filled the `view-auth` slot and the agent has at\n // least one auth method enabled.\n const canSignIn = computed(\n () =>\n !canManageProfile.value &&\n (profile?.canSignIn?.value ?? false) &&\n slots['view-auth'] !== undefined,\n )\n\n // Once the sign-in completes (the session becomes non-anonymous) leave\n // the auth view and return to the conversation.\n watch(canManageProfile, (canManage) => {\n if (canManage && activeView.value === 'auth') {\n navigate('chat')\n }\n })\n\n // Sync props → store reactively\n watchEffect(() => {\n store.baseUrl = props.baseUrl\n store.basePath = props.basePath\n store.name = props.name\n store.agentType = props.agentType\n store.userId = props.userId\n store.agentInterface = props.agentInterface\n store.agentModel = props.agentModel\n store.agentTools = props.agentTools\n store.headers = props.headers\n store.revisedAnswers = props.revisedAnswers\n store.model = props.model\n store.actionsInput = props.actions\n store.agentFileUpload = props.agentFileUpload\n store.agentVoice = props.voice\n store.fallbackModels = props.fallbackModels\n store.gatewayOptions = props.gatewayOptions\n store.externalContext = props.externalContext\n store.systemTheme = props.systemTheme\n store.hideWelcomeMessage = props.modifier === 'fullscreen'\n })\n\n // Sync chatId v-model ↔ store (bidirectional)\n // Parent → store: if the parent provides an external chatId, push it into\n // the store so the Chat instance picks it up.\n watch(\n () => chatId.value,\n (id) => {\n if (id && id !== store.localChatId) {\n store.localChatId = id\n }\n },\n { immediate: true },\n )\n // Store → parent: keep the v-model in sync whenever the store changes\n // the chatId internally (e.g. startNewChat).\n watch(localChatId, (id) => {\n chatId.value = id\n })\n\n // Emit structured errors from chat to the parent component\n watch(chatError, (error) => {\n if (!error) {\n return\n }\n try {\n const parsedError = JSON.parse(error.message) as {\n type: string\n title: string\n status: number\n }\n emit('error', parsedError)\n } catch {\n // ignore non-JSON errors\n }\n })\n\n // ui\n const isFullscreen = computed(() => props.modifier === 'fullscreen')\n const isPanel = computed(() => props.modifier === 'panel')\n\n /**\n * How much room the chat has, measured on the chat and not on the window.\n *\n * The same chat renders in a phone page, in a 408px widget, in a docked\n * panel and in a preview frame that the side panels squeeze to phone width\n * on a desktop screen, so the viewport says nothing about the space the\n * layout actually has. A CSS container query would read the same number\n * with no JavaScript, but `container-type` makes the element a containing\n * block for `position: fixed` descendants on every engine except Chrome\n * 129 and later, which displaces every dropdown in the chat: see\n * docs/agents/gotchas.md, \"The chat measures its own width, and not with a\n * container query\".\n *\n * The thresholds carry the modifiers, so the CSS stays declarative:\n * `--phone` has as much room as a phone page, `--tight` is too tight for\n * the agent chip beside the field, `--wide` has room for the outline rail\n * beside the reading column. Before the first measurement the width is 0\n * and no modifier applies, which is the roomy layout the base CSS writes.\n */\n const chatbotEl = useTemplateRef<HTMLDivElement>('chatbotEl')\n const { width: chatbotWidth } = useElementSize(chatbotEl)\n const isPhoneWidth = computed(\n () => chatbotWidth.value > 0 && chatbotWidth.value < 576,\n )\n const isTightWidth = computed(\n () => chatbotWidth.value > 0 && chatbotWidth.value < 640,\n )\n const isWideWidth = computed(() => chatbotWidth.value >= 848)\n const isReasoningAgent = computed(() => props.agentType === 'reasoning')\n const useColorsForAgentHeader = computed(\n () => props.agentInterface?.useColorsForAgentHeader,\n )\n // Panel mode promotes the everyday actions (new chat, history) from the\n // dropdown to direct header buttons: the dropdown then only remains for\n // the secondary entries (files, profile, sign-in) and disappears when\n // none of them applies.\n const showHeaderMenu = computed(\n () =>\n !isPanel.value ||\n canManageProfile.value ||\n canSignIn.value ||\n (!!props.userFilesEnabled && !!localChatId.value),\n )\n const themeClass = computed(() => [\n 'theme',\n `theme--${isDark.value ? 'dark' : 'light'}`,\n ])\n const mainColor = computed(() => props.agentInterface?.mainColor)\n const contrastColor = computed(() =>\n resolveContrastColor(props.agentInterface?.textColor, mainColor.value),\n )\n const themeStyle = computed(() =>\n agentThemeStyle(mainColor.value, contrastColor.value),\n )\n const footerMessage = useLocalizedString(\n () => props.agentInterface?.footerMessage,\n )\n const title = computed(() => {\n if (activeView.value === 'conversations') {\n return $t('label.conversations')\n }\n if (activeView.value === 'profile') {\n return $t('label.profile')\n }\n if (activeView.value === 'auth') {\n return $t('label.authentication')\n }\n if (activeView.value === 'files') {\n return $t('userFiles.chatFilesTitle')\n }\n return props.name\n })\n\n // state\n const isReady = computed(() => chat.value.status === 'ready')\n const activeMessage = computed(() => {\n return messages.value?.[messages.value.length - 1]\n })\n\n // expose\n defineExpose({\n startNewChat,\n regenerate,\n stopGeneration,\n sendMessage,\n })\n\n // load chat, conversations and feedbacks on agent or chat change\n watch(\n [storeAgentId, localChatId],\n async ([newAgentId, newChatId]) => {\n await store.initialize(newAgentId, newChatId)\n },\n {\n immediate: true,\n },\n )\n // load conversations when navigating to conversations view\n watch(activeView, (newView) => {\n if (newView === 'conversations') {\n store.loadConversations(storeAgentId.value)\n } else if (newView === 'files') {\n store.loadChatFiles()\n }\n })\n // emit message updates for up-to-date context in parent components\n watch(\n activeMessage,\n (message) => {\n if (message) {\n emit('message-update', message)\n }\n },\n {\n deep: true,\n immediate: true,\n },\n )\n</script>\n\n<template>\n <div\n ref=\"chatbotEl\"\n class=\"pk-chatbot\"\n :class=\"[\n themeClass,\n {\n 'pk-chatbot--fullscreen': isFullscreen,\n 'pk-chatbot--panel': isPanel,\n 'pk-chatbot--phone': isPhoneWidth,\n 'pk-chatbot--tight': isTightWidth,\n 'pk-chatbot--wide': isWideWidth,\n },\n ]\"\n :style=\"themeStyle\">\n <!-- #region title -->\n <div\n v-if=\"!isFullscreen\"\n class=\"pk-chatbot__header\"\n :style=\"\n useColorsForAgentHeader\n ? {\n backgroundColor: mainColor,\n }\n : undefined\n \">\n <div class=\"pk-chatbot__header-start\">\n <template v-if=\"activeView !== 'chat'\">\n <VvButton\n v-bind=\"{\n modifiers: useColorsForAgentHeader\n ? `action-quiet-${contrastColor}`\n : 'action-quiet',\n icon: 'ri:arrow-left-s-line',\n title: $t('action.goBack'),\n }\"\n @click=\"navigate('chat')\" />\n <VvIcon\n :name=\"\n activeView === 'conversations'\n ? 'ri:history-line'\n : activeView === 'files'\n ? 'ri:attachment-2'\n : 'ri:user-line'\n \"\n class=\"pk-chatbot__nav-icon\"\n :style=\"\n useColorsForAgentHeader\n ? {\n color: contrastColor,\n }\n : undefined\n \" />\n </template>\n <!-- Panel mode: no avatar, the docked panel identifies the\n agent with the title alone -->\n <PkAvatar\n v-else-if=\"!isPanel\"\n modifiers=\"surface ring shrink-0\"\n class=\"pk-chatbot__avatar\"\n :name\n :img-src=\"agentInterface?.logo\" />\n <strong\n class=\"pk-chatbot__title\"\n :title=\"title\"\n :style=\"\n useColorsForAgentHeader\n ? {\n color: contrastColor,\n }\n : undefined\n \">\n {{ title }}\n </strong>\n </div>\n <VvButtonGroup class=\"pk-chatbot__header-end\" modifiers=\"compact\">\n <slot\n name=\"header-actions\"\n v-bind=\"{\n mainColor,\n useColorsForAgentHeader,\n contrastColor,\n startNewChat,\n stopGeneration,\n }\" />\n <template v-if=\"isPanel\">\n <VvButton\n :modifiers=\"\n useColorsForAgentHeader\n ? `action-quiet-${contrastColor}`\n : 'action-quiet'\n \"\n icon=\"ri:edit-box-line\"\n :disabled=\"!isReady\"\n :title=\"$t('action.startNewChat')\"\n @click=\"startNewChat()\" />\n <VvButton\n v-if=\"!isReasoningAgent\"\n :modifiers=\"\n useColorsForAgentHeader\n ? `action-quiet-${contrastColor}`\n : 'action-quiet'\n \"\n icon=\"ri:history-line\"\n :disabled=\"!isReady\"\n :title=\"$t('action.viewRecentChats')\"\n @click=\"navigate('conversations')\" />\n </template>\n <VvDropdown\n v-if=\"showHeaderMenu\"\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n strategy: 'fixed',\n }\">\n <VvButton\n v-bind=\"{\n modifiers: useColorsForAgentHeader\n ? `action-quiet-${contrastColor}`\n : 'action-quiet',\n icon: 'ri:more-2-fill',\n disabled: !isReady,\n title: $t('action.moreActions'),\n }\" />\n <template #items>\n <VvDropdownAction\n v-if=\"!isPanel\"\n @click=\"startNewChat()\">\n <VvIcon name=\"ri:edit-box-line\" />\n {{ $t('action.startNewChat') }}\n </VvDropdownAction>\n <VvDropdownAction\n v-if=\"!isReasoningAgent && !isPanel\"\n @click=\"navigate('conversations')\">\n <VvIcon name=\"ri:history-line\" />\n {{ $t('action.viewRecentChats') }}\n </VvDropdownAction>\n <VvDropdownAction\n v-if=\"\n (canManageProfile || userFilesEnabled) &&\n localChatId\n \"\n @click=\"navigate('files')\">\n <VvIcon name=\"ri:attachment-2\" />\n {{ $t('userFiles.chatFilesTitle') }}\n </VvDropdownAction>\n <VvDropdownAction\n v-if=\"canManageProfile\"\n @click=\"navigate('profile')\">\n <VvIcon name=\"ri:user-line\" />\n {{ $t('label.profile') }}\n </VvDropdownAction>\n <VvDropdownAction\n v-else-if=\"canSignIn\"\n @click=\"navigate('auth')\">\n <VvIcon name=\"ri:account-circle-line\" />\n {{ $t('action.signIn') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n <slot\n name=\"actions\"\n v-bind=\"{\n mainColor,\n useColorsForAgentHeader,\n contrastColor,\n startNewChat,\n stopGeneration,\n }\" />\n </VvButtonGroup>\n </div>\n <!-- #endregion -->\n\n <div v-if=\"isReasoningAgent\">\n <div class=\"pk-chatbot__warning-body\">\n <VvAlert modifiers=\"callout\">\n <div class=\"pk-chatbot__warning-header\">\n <VvIcon\n name=\"ri:alert-line\"\n class=\"pk-chatbot__warning-icon\" />\n <strong class=\"pk-chatbot__warning-title\">\n {{ $t('message.warning') }}\n </strong>\n </div>\n <p class=\"pk-chatbot__warning-text\">\n {{ $t('message.reasoningAgent') }}\n </p>\n </VvAlert>\n </div>\n </div>\n\n <!-- #region views -->\n <PkChatbotViewChat\n v-if=\"activeView === 'chat'\"\n :agent-id\n :modifier\n :user-name\n @show-info=\"emit('show-info', $event)\"\n @revise=\"emit('revise', $event)\">\n <template\n v-for=\"slotName in Object.keys(slots)\"\n #[slotName]=\"slotData\"\n ><slot :name=\"slotName\" v-bind=\"slotData\"\n /></template>\n </PkChatbotViewChat>\n <PkChatbotViewConversations\n v-else-if=\"activeView === 'conversations'\"\n :agent-id>\n <template\n v-for=\"slotName in Object.keys(slots)\"\n #[slotName]=\"slotData\"\n ><slot :name=\"slotName\" v-bind=\"slotData\"\n /></template>\n </PkChatbotViewConversations>\n <PkChatbotViewFiles v-else-if=\"activeView === 'files'\" :agent-id />\n <div\n v-else-if=\"activeView === 'auth'\"\n class=\"pk-chatbot__view-auth flex-1 min-h-0 overflow-y-auto\">\n <!-- Sign-in form provided by the host widget (owns the auth client) -->\n <slot name=\"view-auth\" />\n </div>\n <PkChatbotViewProfile v-else :agent-id>\n <template\n v-for=\"slotName in Object.keys(slots)\"\n #[slotName]=\"slotData\"\n ><slot :name=\"slotName\" v-bind=\"slotData\"\n /></template>\n </PkChatbotViewProfile>\n <!-- #endregion -->\n\n <!-- #region footer -->\n <div v-if=\"footerMessage\" class=\"pk-chatbot__footer\">\n <PkStreamingMarkdown :markdown=\"footerMessage\" class=\"wysiwyg\" />\n </div>\n <!-- #endregion -->\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot {\n display: flex;\n flex-direction: column;\n position: relative;\n height: 100%;\n background-color: var(--color-surface);\n\n &__header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n justify-content: space-between;\n gap: var(--spacing-14);\n background-color: var(--color-surface-1);\n padding: var(--spacing-14);\n border-bottom: 1px solid var(--color-surface-3);\n }\n\n &__header-start {\n display: flex;\n align-items: center;\n gap: var(--spacing-sm);\n min-width: 0;\n }\n\n &__nav-icon {\n font-size: var(--text-18);\n }\n\n &__avatar {\n width: var(--spacing-24);\n height: var(--spacing-24);\n }\n\n &__title {\n font-size: var(--text-16);\n font-weight: var(--font-semibold);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &__header-end {\n flex-shrink: 0;\n }\n\n &__warning-body {\n padding: var(--spacing-md);\n border-bottom: 1px solid var(--color-surface-3);\n }\n\n &__warning-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-4);\n margin-bottom: var(--spacing-4);\n }\n\n &__warning-icon {\n width: var(--spacing-16);\n height: var(--spacing-16);\n }\n\n &__warning-title {\n font-weight: 600;\n font-size: var(--text-14);\n }\n\n &__warning-text {\n font-size: var(--text-12);\n color: var(--color-word-3);\n }\n\n &__footer {\n padding: var(--spacing-md);\n border-top: 1px solid var(--color-surface-3);\n text-align: center;\n font-size: var(--text-12);\n color: var(--color-word-2);\n }\n\n // Modifier: fullscreen — layout full-page (Gemini-style): nessun\n // header interno, sfondo trasparente, input pill centrato.\n // Il chrome (sidebar, navigazione) è gestito dalla pagina ospite.\n &--fullscreen {\n // The dock, 60px. Declared rather than taken from the agent chip,\n // which the tight layout hides: the pill fell to 54px there and\n // the call bar that takes its place stayed at 60. There is no 60\n // in the spacing scale and a raw `60px` would stop following the\n // root font size, which the labels inside do follow.\n --pk-chat-fullscreen-dock-height: calc(\n var(--spacing-56) + var(--spacing-4)\n );\n // The pill, the notice that tucks into its top corners and the\n // call bar all round their ends on half of it.\n --pk-chat-dock-radius: calc(\n var(--pk-chat-fullscreen-dock-height) / 2\n );\n\n background-color: transparent;\n\n .pk-chatbot__footer {\n border-top: none;\n padding: 0 var(--spacing-md) var(--spacing-sm) var(--spacing-md);\n }\n\n // Reading column aligned with the input (Gemini-style). The\n // constraint lives on the inner wrapper so the scroll container\n // spans the page and the scrollbar sits at its edge.\n .pk-chatbot-messages {\n // Symmetric gutters: a visible scrollbar would otherwise\n // shrink the content box on one side only, shifting the\n // column off the input axis\n scrollbar-gutter: stable both-edges;\n // Dissolve the content at both edges (works on any page\n // background, dots included — a surface-colored fade band\n // would cut through the pattern instead)\n mask-image: linear-gradient(\n to bottom,\n transparent 0,\n #000 var(--spacing-40),\n #000 calc(100% - var(--spacing-40)),\n transparent 100%\n );\n // Resting clearance so the first/last lines sit inside the\n // fully opaque zone\n padding-block: var(--spacing-48);\n }\n\n .pk-chatbot-messages__wrapper {\n width: 100%;\n max-width: 768px;\n margin-inline: auto;\n }\n\n // Outline rail: wide chats only, measured on the chat and not on\n // the viewport, so a preview frame squeezed by side panels loses\n // it like a phone does. The rail sits at the edge of the scroll\n // area beside the reading column: below the `--wide` threshold\n // (768px column plus a 40px rail on each side) it would cover the\n // messages instead.\n .pk-chatbot-messages__outline {\n display: none;\n }\n\n &.pk-chatbot--wide .pk-chatbot-messages__outline {\n display: block;\n }\n\n .pk-chatbot-file-preview {\n background-color: var(--color-surface);\n }\n\n .pk-chatbot-input__notice {\n background-color: var(--color-surface);\n border-inline: 1px solid var(--color-surface-3);\n border-top: 1px solid var(--color-surface-2);\n padding: var(--spacing-10) var(--spacing-16);\n\n // As deep as the pill's corners, or the page shows through\n // where their curve leaves the side\n &::after {\n background-color: var(--color-surface);\n border-inline: 1px solid var(--color-surface-2);\n bottom: calc(-1 * var(--pk-chat-dock-radius));\n height: var(--pk-chat-dock-radius);\n left: -1px;\n right: -1px;\n }\n }\n\n .pk-chatbot-input {\n width: calc(100% - var(--spacing-sm) * 2);\n max-width: 768px;\n margin-inline: auto;\n\n &__form {\n // True semicircles at rest, concentric with the send\n // button, whose center sits 30px in. Not `rounded-full`:\n // once Shift+Enter grows the field the ends would swell\n // with it and cut into the first and last line.\n border-radius: var(--pk-chat-dock-radius);\n min-height: var(--pk-chat-fullscreen-dock-height);\n padding: var(--spacing-12) var(--spacing-16);\n background-color: var(--color-surface-1);\n border-color: var(--color-surface-2);\n box-shadow: none;\n transition:\n border-color var(--duration-200) var(--ease-in-out),\n box-shadow var(--duration-200) var(--ease-in-out);\n\n &:has(:focus-within) {\n border-color: var(--color-surface-4);\n box-shadow: var(--shadow-sm);\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n }\n\n &__textarea {\n background-color: transparent;\n }\n }\n\n // A live call takes the place of the input, so it takes its shape,\n // its column and its height: full-bleed here would break the\n // reading axis, and a different height would make the dock jump\n // the moment the call starts.\n .pk-voice-session {\n --pk-chat-dock-height: var(--pk-chat-fullscreen-dock-height);\n --pk-voice-orb-size: var(--spacing-40);\n --pk-voice-orb-bars-height: var(--spacing-20);\n --pk-voice-session-surface: var(--color-surface-1);\n width: calc(100% - var(--spacing-sm) * 2);\n max-width: 768px;\n margin-inline: auto;\n padding-inline: var(--spacing-16);\n border-color: var(--color-surface-2);\n border-radius: var(--pk-chat-dock-radius);\n box-shadow: none;\n\n &__timer {\n font-size: var(--text-14);\n }\n }\n }\n\n // Modifier: panel — compact chrome for a docked side panel: the host\n // container owns background and border, the header slims down and\n // drops its own surface so the chat blends into the panel.\n &--panel {\n background-color: transparent;\n\n .pk-chatbot__header {\n background-color: transparent;\n\n // Fixed height so the panel header lines up with the host's\n // own chrome. Custom properties inherit through the shadow\n // root: an embedding host can override it to match its\n // header (the default matches the platform header, 50px).\n height: var(--pk-chatbot-panel-header-height, 50px);\n align-items: center;\n padding-block: 0;\n padding-inline: var(--spacing-10);\n border-bottom: 1px solid var(--color-surface-3);\n }\n\n .pk-chatbot__title {\n font-size: var(--text-14);\n }\n\n .pk-chatbot__footer {\n border-top: none;\n padding: var(--spacing-6) var(--spacing-md);\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import {\n computed,\n inject,\n toRef,\n useTemplateRef,\n watch,\n watchEffect,\n useSlots,\n } from 'vue'\n import { useElementSize } from '@vueuse/core'\n import { storeToRefs } from 'pinia'\n import { useI18n } from 'vue-i18n'\n import type {\n AgentInterface,\n AgentModel,\n AgentFileUpload,\n AgentGatewayOptions,\n AgentVoiceCapability,\n ChatMessageActions,\n RevisedAnswer,\n UIChatMessage,\n AgentTools,\n } from 'models'\n import {\n useChatbotStore,\n useLocalizedString,\n provideShortUrlResolver,\n } from 'composables'\n import PkAvatar from './PkAvatar.vue'\n import PkChatbotViewChat from './PkChatbotViewChat.vue'\n import PkChatbotViewConversations from './PkChatbotViewConversations.vue'\n import PkChatbotViewFiles from './PkChatbotViewFiles.vue'\n import PkChatbotViewProfile from './PkChatbotViewProfile.vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import { ChatbotProfileContextKey } from './chatbotProfileContext'\n import { provideChatImagePolicy } from './chatImagePolicy'\n import { agentThemeStyle, resolveContrastColor } from './utils'\n\n // Captured in script setup to avoid TS7022 circular inference in template\n const slots = useSlots()\n\n const { t: $t } = useI18n({\n useScope: 'global',\n })\n\n const props = defineProps<{\n baseUrl: string\n basePath?: string\n agentId: string\n agentType?: 'reasoning' | 'chat'\n userId?: string\n name?: string\n model?: string\n agentModel?: AgentModel\n agentTools?: AgentTools\n agentInterface?: AgentInterface\n actions?: ChatMessageActions[]\n revisedAnswers?: RevisedAnswer[]\n headers?: Record<string, string>\n systemTheme?: 'light' | 'dark'\n agentFileUpload?: AgentFileUpload\n /** Voice configuration from the agent settings: enables the talk button. */\n voice?: AgentVoiceCapability\n fallbackModels?: string[]\n gatewayOptions?: Partial<AgentGatewayOptions>\n externalContext?: Record<string, unknown>\n /** Layout modifier: `widget` (default) keeps the contained layout with header, `fullscreen` removes header/background for full-page usage (the page provides the chrome), `panel` keeps the header but slims it down for a docked side panel (the host provides background and border) */\n modifier?: 'widget' | 'fullscreen' | 'panel'\n /** Display name of the current user, used for the `{name}` placeholder in the fullscreen greeting */\n userName?: string\n /** Show the \"Files in this chat\" menu for hosts that don't provide the\n * profile context but whose user is authenticated (e.g. the backoffice\n * playground). The widget host relies on `canManageProfile` instead. */\n userFilesEnabled?: boolean\n }>()\n const emit = defineEmits<{\n 'message-update': [message: UIChatMessage]\n 'show-info': [message: UIChatMessage]\n revise: [message: UIChatMessage]\n error: [error: { type: string; title: string; status: number }]\n }>()\n\n const chatId = defineModel<string | undefined>('chatId', {\n type: String,\n default: undefined,\n })\n\n const store = useChatbotStore(props.agentId)\n\n // Resolve backend short-urls (`/api/r/<hash>`) back to their real target\n // for display in tool components. Batched + cached across the chat tree.\n provideShortUrlResolver((hashes) =>\n store.apiClient.resolveShortUrls(hashes),\n )\n\n const { messages, chat, localChatId, activeView, chatError, isDark } =\n storeToRefs(store)\n\n // Ref to store.agentId for watchers (avoids duplicate-key with agentId prop)\n const storeAgentId = toRef(store, 'agentId')\n\n const { startNewChat, stopGeneration, regenerate, navigate, sendMessage } =\n store\n\n // Images in the answers and the tool cards load by themselves only from\n // the backend this chat talks to and from the hosts the agent lists.\n provideChatImagePolicy(\n () => props.agentInterface?.imageHosts,\n () => props.baseUrl,\n )\n\n // Optional profile-management context provided by the host widget.\n // Present only for authenticated, non-anonymous sessions.\n const profile = inject(ChatbotProfileContextKey, undefined)\n const canManageProfile = computed(\n () => profile?.canManageProfile.value ?? false,\n )\n // Anonymous users get a \"Sign in\" entry instead of the profile one,\n // provided the host filled the `view-auth` slot and the agent has at\n // least one auth method enabled.\n const canSignIn = computed(\n () =>\n !canManageProfile.value &&\n (profile?.canSignIn?.value ?? false) &&\n slots['view-auth'] !== undefined,\n )\n\n // Once the sign-in completes (the session becomes non-anonymous) leave\n // the auth view and return to the conversation.\n watch(canManageProfile, (canManage) => {\n if (canManage && activeView.value === 'auth') {\n navigate('chat')\n }\n })\n\n // Sync props → store reactively\n watchEffect(() => {\n store.baseUrl = props.baseUrl\n store.basePath = props.basePath\n store.name = props.name\n store.agentType = props.agentType\n store.userId = props.userId\n store.agentInterface = props.agentInterface\n store.agentModel = props.agentModel\n store.agentTools = props.agentTools\n store.headers = props.headers\n store.revisedAnswers = props.revisedAnswers\n store.model = props.model\n store.actionsInput = props.actions\n store.agentFileUpload = props.agentFileUpload\n store.agentVoice = props.voice\n store.fallbackModels = props.fallbackModels\n store.gatewayOptions = props.gatewayOptions\n store.externalContext = props.externalContext\n store.systemTheme = props.systemTheme\n store.hideWelcomeMessage = props.modifier === 'fullscreen'\n })\n\n // Sync chatId v-model ↔ store (bidirectional)\n // Parent → store: if the parent provides an external chatId, push it into\n // the store so the Chat instance picks it up.\n watch(\n () => chatId.value,\n (id) => {\n if (id && id !== store.localChatId) {\n store.localChatId = id\n }\n },\n { immediate: true },\n )\n // Store → parent: keep the v-model in sync whenever the store changes\n // the chatId internally (e.g. startNewChat).\n watch(localChatId, (id) => {\n chatId.value = id\n })\n\n // Emit structured errors from chat to the parent component\n watch(chatError, (error) => {\n if (!error) {\n return\n }\n try {\n const parsedError = JSON.parse(error.message) as {\n type: string\n title: string\n status: number\n }\n emit('error', parsedError)\n } catch {\n // ignore non-JSON errors\n }\n })\n\n // ui\n const isFullscreen = computed(() => props.modifier === 'fullscreen')\n const isPanel = computed(() => props.modifier === 'panel')\n\n /**\n * How much room the chat has, measured on the chat and not on the window.\n *\n * The same chat renders in a phone page, in a 408px widget, in a docked\n * panel and in a preview frame that the side panels squeeze to phone width\n * on a desktop screen, so the viewport says nothing about the space the\n * layout actually has. A CSS container query would read the same number\n * with no JavaScript, but `container-type` makes the element a containing\n * block for `position: fixed` descendants on every engine except Chrome\n * 129 and later, which displaces every dropdown in the chat: see\n * docs/agents/gotchas.md, \"The chat measures its own width, and not with a\n * container query\".\n *\n * The thresholds carry the modifiers, so the CSS stays declarative:\n * `--phone` has as much room as a phone page, `--tight` is too tight for\n * the agent chip beside the field, `--wide` has room for the outline rail\n * beside the reading column. Before the first measurement the width is 0\n * and no modifier applies, which is the roomy layout the base CSS writes.\n */\n const chatbotEl = useTemplateRef<HTMLDivElement>('chatbotEl')\n const { width: chatbotWidth } = useElementSize(chatbotEl)\n const isPhoneWidth = computed(\n () => chatbotWidth.value > 0 && chatbotWidth.value < 576,\n )\n const isTightWidth = computed(\n () => chatbotWidth.value > 0 && chatbotWidth.value < 640,\n )\n const isWideWidth = computed(() => chatbotWidth.value >= 848)\n const isReasoningAgent = computed(() => props.agentType === 'reasoning')\n const useColorsForAgentHeader = computed(\n () => props.agentInterface?.useColorsForAgentHeader,\n )\n // Panel mode promotes the everyday actions (new chat, history) from the\n // dropdown to direct header buttons: the dropdown then only remains for\n // the secondary entries (files, profile, sign-in) and disappears when\n // none of them applies.\n const showHeaderMenu = computed(\n () =>\n !isPanel.value ||\n canManageProfile.value ||\n canSignIn.value ||\n (!!props.userFilesEnabled && !!localChatId.value),\n )\n const themeClass = computed(() => [\n 'theme',\n `theme--${isDark.value ? 'dark' : 'light'}`,\n ])\n const mainColor = computed(() => props.agentInterface?.mainColor)\n const contrastColor = computed(() =>\n resolveContrastColor(props.agentInterface?.textColor, mainColor.value),\n )\n const themeStyle = computed(() =>\n agentThemeStyle(mainColor.value, contrastColor.value),\n )\n const footerMessage = useLocalizedString(\n () => props.agentInterface?.footerMessage,\n )\n const title = computed(() => {\n if (activeView.value === 'conversations') {\n return $t('label.conversations')\n }\n if (activeView.value === 'profile') {\n return $t('label.profile')\n }\n if (activeView.value === 'auth') {\n return $t('label.authentication')\n }\n if (activeView.value === 'files') {\n return $t('userFiles.chatFilesTitle')\n }\n return props.name\n })\n\n // state\n const isReady = computed(() => chat.value.status === 'ready')\n const activeMessage = computed(() => {\n return messages.value?.[messages.value.length - 1]\n })\n\n // expose\n defineExpose({\n startNewChat,\n regenerate,\n stopGeneration,\n sendMessage,\n })\n\n // load chat, conversations and feedbacks on agent or chat change\n watch(\n [storeAgentId, localChatId],\n async ([newAgentId, newChatId]) => {\n await store.initialize(newAgentId, newChatId)\n },\n {\n immediate: true,\n },\n )\n // load conversations when navigating to conversations view\n watch(activeView, (newView) => {\n if (newView === 'conversations') {\n store.loadConversations(storeAgentId.value)\n } else if (newView === 'files') {\n store.loadChatFiles()\n }\n })\n // emit message updates for up-to-date context in parent components\n watch(\n activeMessage,\n (message) => {\n if (message) {\n emit('message-update', message)\n }\n },\n {\n deep: true,\n immediate: true,\n },\n )\n</script>\n\n<template>\n <div\n ref=\"chatbotEl\"\n class=\"pk-chatbot\"\n :class=\"[\n themeClass,\n {\n 'pk-chatbot--fullscreen': isFullscreen,\n 'pk-chatbot--panel': isPanel,\n 'pk-chatbot--phone': isPhoneWidth,\n 'pk-chatbot--tight': isTightWidth,\n 'pk-chatbot--wide': isWideWidth,\n },\n ]\"\n :style=\"themeStyle\">\n <!-- #region title -->\n <div\n v-if=\"!isFullscreen\"\n class=\"pk-chatbot__header\"\n :style=\"\n useColorsForAgentHeader\n ? {\n backgroundColor: mainColor,\n }\n : undefined\n \">\n <div class=\"pk-chatbot__header-start\">\n <template v-if=\"activeView !== 'chat'\">\n <VvButton\n v-bind=\"{\n modifiers: useColorsForAgentHeader\n ? `action-quiet-${contrastColor}`\n : 'action-quiet',\n icon: 'ri:arrow-left-s-line',\n title: $t('action.goBack'),\n }\"\n @click=\"navigate('chat')\" />\n <VvIcon\n :name=\"\n activeView === 'conversations'\n ? 'ri:history-line'\n : activeView === 'files'\n ? 'ri:attachment-2'\n : 'ri:user-line'\n \"\n class=\"pk-chatbot__nav-icon\"\n :style=\"\n useColorsForAgentHeader\n ? {\n color: contrastColor,\n }\n : undefined\n \" />\n </template>\n <!-- Panel mode: no avatar, the docked panel identifies the\n agent with the title alone -->\n <PkAvatar\n v-else-if=\"!isPanel\"\n modifiers=\"surface ring shrink-0\"\n class=\"pk-chatbot__avatar\"\n :name\n :img-src=\"agentInterface?.logo\" />\n <strong\n class=\"pk-chatbot__title\"\n :title=\"title\"\n :style=\"\n useColorsForAgentHeader\n ? {\n color: contrastColor,\n }\n : undefined\n \">\n {{ title }}\n </strong>\n </div>\n <VvButtonGroup class=\"pk-chatbot__header-end\" modifiers=\"compact\">\n <slot\n name=\"header-actions\"\n v-bind=\"{\n mainColor,\n useColorsForAgentHeader,\n contrastColor,\n startNewChat,\n stopGeneration,\n }\" />\n <template v-if=\"isPanel\">\n <VvButton\n :modifiers=\"\n useColorsForAgentHeader\n ? `action-quiet-${contrastColor}`\n : 'action-quiet'\n \"\n icon=\"ri:edit-box-line\"\n :disabled=\"!isReady\"\n :title=\"$t('action.startNewChat')\"\n @click=\"startNewChat()\" />\n <VvButton\n v-if=\"!isReasoningAgent\"\n :modifiers=\"\n useColorsForAgentHeader\n ? `action-quiet-${contrastColor}`\n : 'action-quiet'\n \"\n icon=\"ri:history-line\"\n :disabled=\"!isReady\"\n :title=\"$t('action.viewRecentChats')\"\n @click=\"navigate('conversations')\" />\n </template>\n <VvDropdown\n v-if=\"showHeaderMenu\"\n v-bind=\"{\n placement: 'bottom-end',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n strategy: 'fixed',\n }\">\n <VvButton\n v-bind=\"{\n modifiers: useColorsForAgentHeader\n ? `action-quiet-${contrastColor}`\n : 'action-quiet',\n icon: 'ri:more-2-fill',\n disabled: !isReady,\n title: $t('action.moreActions'),\n }\" />\n <template #items>\n <VvDropdownAction\n v-if=\"!isPanel\"\n @click=\"startNewChat()\">\n <VvIcon name=\"ri:edit-box-line\" />\n {{ $t('action.startNewChat') }}\n </VvDropdownAction>\n <VvDropdownAction\n v-if=\"!isReasoningAgent && !isPanel\"\n @click=\"navigate('conversations')\">\n <VvIcon name=\"ri:history-line\" />\n {{ $t('action.viewRecentChats') }}\n </VvDropdownAction>\n <VvDropdownAction\n v-if=\"\n (canManageProfile || userFilesEnabled) &&\n localChatId\n \"\n @click=\"navigate('files')\">\n <VvIcon name=\"ri:attachment-2\" />\n {{ $t('userFiles.chatFilesTitle') }}\n </VvDropdownAction>\n <VvDropdownAction\n v-if=\"canManageProfile\"\n @click=\"navigate('profile')\">\n <VvIcon name=\"ri:user-line\" />\n {{ $t('label.profile') }}\n </VvDropdownAction>\n <VvDropdownAction\n v-else-if=\"canSignIn\"\n @click=\"navigate('auth')\">\n <VvIcon name=\"ri:account-circle-line\" />\n {{ $t('action.signIn') }}\n </VvDropdownAction>\n </template>\n </VvDropdown>\n <slot\n name=\"actions\"\n v-bind=\"{\n mainColor,\n useColorsForAgentHeader,\n contrastColor,\n startNewChat,\n stopGeneration,\n }\" />\n </VvButtonGroup>\n </div>\n <!-- #endregion -->\n\n <div v-if=\"isReasoningAgent\">\n <div class=\"pk-chatbot__warning-body\">\n <VvAlert modifiers=\"callout\">\n <div class=\"pk-chatbot__warning-header\">\n <VvIcon\n name=\"ri:alert-line\"\n class=\"pk-chatbot__warning-icon\" />\n <strong class=\"pk-chatbot__warning-title\">\n {{ $t('message.warning') }}\n </strong>\n </div>\n <p class=\"pk-chatbot__warning-text\">\n {{ $t('message.reasoningAgent') }}\n </p>\n </VvAlert>\n </div>\n </div>\n\n <!-- #region views -->\n <PkChatbotViewChat\n v-if=\"activeView === 'chat'\"\n :agent-id\n :modifier\n :user-name\n @show-info=\"emit('show-info', $event)\"\n @revise=\"emit('revise', $event)\">\n <template\n v-for=\"slotName in Object.keys(slots)\"\n #[slotName]=\"slotData\"\n ><slot :name=\"slotName\" v-bind=\"slotData\"\n /></template>\n </PkChatbotViewChat>\n <PkChatbotViewConversations\n v-else-if=\"activeView === 'conversations'\"\n :agent-id>\n <template\n v-for=\"slotName in Object.keys(slots)\"\n #[slotName]=\"slotData\"\n ><slot :name=\"slotName\" v-bind=\"slotData\"\n /></template>\n </PkChatbotViewConversations>\n <PkChatbotViewFiles v-else-if=\"activeView === 'files'\" :agent-id />\n <div\n v-else-if=\"activeView === 'auth'\"\n class=\"pk-chatbot__view-auth flex-1 min-h-0 overflow-y-auto\">\n <!-- Sign-in form provided by the host widget (owns the auth client) -->\n <slot name=\"view-auth\" />\n </div>\n <PkChatbotViewProfile v-else :agent-id>\n <template\n v-for=\"slotName in Object.keys(slots)\"\n #[slotName]=\"slotData\"\n ><slot :name=\"slotName\" v-bind=\"slotData\"\n /></template>\n </PkChatbotViewProfile>\n <!-- #endregion -->\n\n <!-- #region footer -->\n <div v-if=\"footerMessage\" class=\"pk-chatbot__footer\">\n <PkStreamingMarkdown :markdown=\"footerMessage\" class=\"wysiwyg\" />\n </div>\n <!-- #endregion -->\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot {\n display: flex;\n flex-direction: column;\n position: relative;\n height: 100%;\n background-color: var(--color-surface);\n\n &__header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n justify-content: space-between;\n gap: var(--spacing-14);\n background-color: var(--color-surface-1);\n padding: var(--spacing-14);\n border-bottom: 1px solid var(--color-surface-3);\n }\n\n &__header-start {\n display: flex;\n align-items: center;\n gap: var(--spacing-sm);\n min-width: 0;\n }\n\n &__nav-icon {\n font-size: var(--text-18);\n }\n\n &__avatar {\n width: var(--spacing-24);\n height: var(--spacing-24);\n }\n\n &__title {\n font-size: var(--text-16);\n font-weight: var(--font-semibold);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n &__header-end {\n flex-shrink: 0;\n }\n\n &__warning-body {\n padding: var(--spacing-md);\n border-bottom: 1px solid var(--color-surface-3);\n }\n\n &__warning-header {\n display: flex;\n align-items: center;\n gap: var(--spacing-4);\n margin-bottom: var(--spacing-4);\n }\n\n &__warning-icon {\n width: var(--spacing-16);\n height: var(--spacing-16);\n }\n\n &__warning-title {\n font-weight: 600;\n font-size: var(--text-14);\n }\n\n &__warning-text {\n font-size: var(--text-12);\n color: var(--color-word-3);\n }\n\n &__footer {\n padding: var(--spacing-md);\n border-top: 1px solid var(--color-surface-3);\n text-align: center;\n font-size: var(--text-12);\n color: var(--color-word-2);\n }\n\n // Modifier: fullscreen — layout full-page (Gemini-style): nessun\n // header interno, sfondo trasparente, input pill centrato.\n // Il chrome (sidebar, navigazione) è gestito dalla pagina ospite.\n &--fullscreen {\n // The dock, 60px. Declared rather than taken from the agent chip,\n // which the tight layout hides: the pill fell to 54px there and\n // the call bar that takes its place stayed at 60. There is no 60\n // in the spacing scale and a raw `60px` would stop following the\n // root font size, which the labels inside do follow.\n --pk-chat-fullscreen-dock-height: calc(\n var(--spacing-56) + var(--spacing-4)\n );\n // The pill, the notice that tucks into its top corners and the\n // call bar all round their ends on half of it.\n --pk-chat-dock-radius: calc(\n var(--pk-chat-fullscreen-dock-height) / 2\n );\n\n background-color: transparent;\n\n .pk-chatbot__footer {\n border-top: none;\n padding: 0 var(--spacing-md) var(--spacing-sm) var(--spacing-md);\n }\n\n // Reading column aligned with the input (Gemini-style). The\n // constraint lives on the inner wrapper so the scroll container\n // spans the page and the scrollbar sits at its edge.\n .pk-chatbot-messages {\n // Symmetric gutters: a visible scrollbar would otherwise\n // shrink the content box on one side only, shifting the\n // column off the input axis\n scrollbar-gutter: stable both-edges;\n // Dissolve the content at both edges (works on any page\n // background, dots included — a surface-colored fade band\n // would cut through the pattern instead)\n mask-image: linear-gradient(\n to bottom,\n transparent 0,\n #000 var(--spacing-40),\n #000 calc(100% - var(--spacing-40)),\n transparent 100%\n );\n // Resting clearance so the first/last lines sit inside the\n // fully opaque zone\n padding-block: var(--spacing-48);\n }\n\n .pk-chatbot-messages__wrapper {\n width: 100%;\n max-width: 768px;\n margin-inline: auto;\n }\n\n // Outline rail: wide chats only, measured on the chat and not on\n // the viewport, so a preview frame squeezed by side panels loses\n // it like a phone does. The rail sits at the edge of the scroll\n // area beside the reading column: below the `--wide` threshold\n // (768px column plus a 40px rail on each side) it would cover the\n // messages instead.\n .pk-chatbot-messages__outline {\n display: none;\n }\n\n &.pk-chatbot--wide .pk-chatbot-messages__outline {\n display: block;\n }\n\n .pk-chatbot-file-preview {\n background-color: var(--color-surface);\n }\n\n .pk-chatbot-input__notice {\n background-color: var(--color-surface);\n border-inline: 1px solid var(--color-surface-3);\n border-top: 1px solid var(--color-surface-2);\n padding: var(--spacing-10) var(--spacing-16);\n\n // As deep as the pill's corners, or the page shows through\n // where their curve leaves the side\n &::after {\n background-color: var(--color-surface);\n border-inline: 1px solid var(--color-surface-2);\n bottom: calc(-1 * var(--pk-chat-dock-radius));\n height: var(--pk-chat-dock-radius);\n left: -1px;\n right: -1px;\n }\n }\n\n .pk-chatbot-input {\n width: calc(100% - var(--spacing-sm) * 2);\n max-width: 768px;\n margin-inline: auto;\n\n &__form {\n // True semicircles at rest, concentric with the send\n // button, whose center sits 30px in. Not `rounded-full`:\n // once Shift+Enter grows the field the ends would swell\n // with it and cut into the first and last line.\n border-radius: var(--pk-chat-dock-radius);\n min-height: var(--pk-chat-fullscreen-dock-height);\n padding: var(--spacing-12) var(--spacing-16);\n background-color: var(--color-surface-1);\n border-color: var(--color-surface-2);\n box-shadow: none;\n transition:\n border-color var(--duration-200) var(--ease-in-out),\n box-shadow var(--duration-200) var(--ease-in-out);\n\n &:has(:focus-within) {\n border-color: var(--color-surface-4);\n box-shadow: var(--shadow-sm);\n }\n\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n }\n\n &__textarea {\n background-color: transparent;\n }\n }\n\n // A live call takes the place of the input, so it takes its shape,\n // its column and its height: full-bleed here would break the\n // reading axis, and a different height would make the dock jump\n // the moment the call starts.\n .pk-voice-session {\n --pk-chat-dock-height: var(--pk-chat-fullscreen-dock-height);\n --pk-voice-orb-size: var(--spacing-40);\n --pk-voice-orb-bars-height: var(--spacing-20);\n --pk-voice-session-surface: var(--color-surface-1);\n width: calc(100% - var(--spacing-sm) * 2);\n max-width: 768px;\n margin-inline: auto;\n padding-inline: var(--spacing-16);\n border-color: var(--color-surface-2);\n border-radius: var(--pk-chat-dock-radius);\n box-shadow: none;\n\n &__timer {\n font-size: var(--text-14);\n }\n }\n }\n\n // Modifier: panel — compact chrome for a docked side panel: the host\n // container owns background and border, the header slims down and\n // drops its own surface so the chat blends into the panel.\n &--panel {\n background-color: transparent;\n\n .pk-chatbot__header {\n background-color: transparent;\n\n // Fixed height so the panel header lines up with the host's\n // own chrome. Custom properties inherit through the shadow\n // root: an embedding host can override it to match its\n // header (the default matches the platform header, 50px).\n height: var(--pk-chatbot-panel-header-height, 50px);\n align-items: center;\n padding-block: 0;\n padding-inline: var(--spacing-10);\n border-bottom: 1px solid var(--color-surface-3);\n }\n\n .pk-chatbot__title {\n font-size: var(--text-14);\n }\n\n .pk-chatbot__footer {\n border-top: none;\n padding: var(--spacing-6) var(--spacing-md);\n }\n }\n }\n</style>\n"],"mappings":"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"}
|
package/dist-vue/_chunks/{PkChatbotEmptyState-BEQCnqui.js → PkChatbotEmptyState-Toj4CqXV.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as e } from "./PkStreamingMarkdown-
|
|
1
|
+
import { t as e } from "./PkStreamingMarkdown-C55Fi0Pd.js";
|
|
2
2
|
import { t } from "./PkAvatar-BTqu8tn9.js";
|
|
3
3
|
import { createBlock as n, createCommentVNode as r, createElementBlock as i, defineComponent as a, openBlock as o } from "vue";
|
|
4
4
|
//#region ../../packages/components/src/chat/PkChatbotEmptyState.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -27,4 +27,4 @@ var s = { class: "pk-chatbot-empty-state" }, c = /* @__PURE__ */ a({
|
|
|
27
27
|
//#endregion
|
|
28
28
|
export { c as t };
|
|
29
29
|
|
|
30
|
-
//# sourceMappingURL=PkChatbotEmptyState-
|
|
30
|
+
//# sourceMappingURL=PkChatbotEmptyState-Toj4CqXV.js.map
|
package/dist-vue/_chunks/{PkChatbotEmptyState-BEQCnqui.js.map → PkChatbotEmptyState-Toj4CqXV.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PkChatbotEmptyState-
|
|
1
|
+
{"version":3,"file":"PkChatbotEmptyState-Toj4CqXV.js","names":["_openBlock","_createElementBlock","_createBlock","PkAvatar","_createCommentVNode","PkStreamingMarkdown","_sfc_main","PkStreamingMarkdown_default","_hoisted_1","PkChatbotEmptyState_default","defineComponent","openBlock","createElementBlock","__props","createBlock","PkAvatar_default","createCommentVNode"],"sources":["../../../../packages/components/src/chat/PkChatbotEmptyState.vue","../../../../packages/components/src/chat/PkChatbotEmptyState.vue"],"sourcesContent":["<script setup lang=\"ts\">\n import PkAvatar from './PkAvatar.vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n defineProps<{\n greeting?: string\n /** Agent avatar shown above the greeting where the input chip is hidden (mobile) */\n logo?: string | null\n name?: string\n }>()\n</script>\n\n<template>\n <div class=\"pk-chatbot-empty-state\">\n <PkAvatar\n v-if=\"logo || name\"\n class=\"pk-chatbot-empty-state__avatar\"\n modifiers=\"surface\"\n :img-src=\"logo\"\n :name=\"name\" />\n <PkStreamingMarkdown\n v-if=\"greeting\"\n :markdown=\"greeting\"\n :animation=\"null\"\n class=\"wysiwyg pk-chatbot-empty-state__greeting\" />\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-empty-state {\n // Above the fullscreen ambient glow\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--spacing-sm);\n padding: var(--spacing-md);\n text-align: center;\n\n // Let the greeting wrap on a couple of lines (Gemini-like). Keyed on\n // the chat's own width (`--phone`, measured in PkChatbot): a narrow\n // preview frame on a desktop screen wraps like a phone\n .pk-chatbot--phone & {\n padding-inline: var(--spacing-56);\n }\n\n &__avatar {\n width: var(--spacing-64);\n height: var(--spacing-64);\n font-size: var(--text-20);\n border-radius: var(--rounded-full);\n\n // The agent identity lives in the input chip when that is\n // visible: the chip hides itself at `--tight`, so keying the\n // avatar on the absence of that modifier shows exactly one of\n // the two\n .pk-chatbot:not(.pk-chatbot--tight) & {\n display: none;\n }\n }\n\n &__greeting {\n font-size: var(--text-28);\n font-weight: var(--font-light);\n color: var(--color-word-1);\n text-wrap: balance;\n\n // Render the greeting markdown inline as a single heading line\n :first-child {\n margin-top: 0;\n }\n\n :last-child {\n margin-bottom: 0;\n }\n }\n\n // Enters fading in from below, in sync with the glow ignition\n &__avatar,\n &__greeting {\n animation: pk-chatbot-greeting-enter 600ms var(--ease-out) both;\n\n @media (prefers-reduced-motion: reduce) {\n animation: none;\n }\n }\n }\n\n @keyframes pk-chatbot-greeting-enter {\n from {\n opacity: 0;\n transform: translateY(var(--spacing-16));\n }\n }\n</style>\n","<script setup lang=\"ts\">\n import PkAvatar from './PkAvatar.vue'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n\n defineProps<{\n greeting?: string\n /** Agent avatar shown above the greeting where the input chip is hidden (mobile) */\n logo?: string | null\n name?: string\n }>()\n</script>\n\n<template>\n <div class=\"pk-chatbot-empty-state\">\n <PkAvatar\n v-if=\"logo || name\"\n class=\"pk-chatbot-empty-state__avatar\"\n modifiers=\"surface\"\n :img-src=\"logo\"\n :name=\"name\" />\n <PkStreamingMarkdown\n v-if=\"greeting\"\n :markdown=\"greeting\"\n :animation=\"null\"\n class=\"wysiwyg pk-chatbot-empty-state__greeting\" />\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-empty-state {\n // Above the fullscreen ambient glow\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--spacing-sm);\n padding: var(--spacing-md);\n text-align: center;\n\n // Let the greeting wrap on a couple of lines (Gemini-like). Keyed on\n // the chat's own width (`--phone`, measured in PkChatbot): a narrow\n // preview frame on a desktop screen wraps like a phone\n .pk-chatbot--phone & {\n padding-inline: var(--spacing-56);\n }\n\n &__avatar {\n width: var(--spacing-64);\n height: var(--spacing-64);\n font-size: var(--text-20);\n border-radius: var(--rounded-full);\n\n // The agent identity lives in the input chip when that is\n // visible: the chip hides itself at `--tight`, so keying the\n // avatar on the absence of that modifier shows exactly one of\n // the two\n .pk-chatbot:not(.pk-chatbot--tight) & {\n display: none;\n }\n }\n\n &__greeting {\n font-size: var(--text-28);\n font-weight: var(--font-light);\n color: var(--color-word-1);\n text-wrap: balance;\n\n // Render the greeting markdown inline as a single heading line\n :first-child {\n margin-top: 0;\n }\n\n :last-child {\n margin-bottom: 0;\n }\n }\n\n // Enters fading in from below, in sync with the glow ignition\n &__avatar,\n &__greeting {\n animation: pk-chatbot-greeting-enter 600ms var(--ease-out) both;\n\n @media (prefers-reduced-motion: reduce) {\n animation: none;\n }\n }\n }\n\n @keyframes pk-chatbot-greeting-enter {\n from {\n opacity: 0;\n transform: translateY(var(--spacing-16));\n }\n }\n</style>\n"],"mappings":";;;;;;;;;;;;oBAaIA,EAAA,GAAAC,EAYM,OAZNO,GAYM,CAVQK,EAAA,QAAQA,EAAA,QADlBb,EAAA,GAAAE,EAKmBC,GAAA;;GAHf,OAAM;GACN,WAAU;GACT,WAASU,EAAA;GACT,MAAMA,EAAA;EAED,GAAA,MAAA,GAAA,CAAA,WAAA,MAAA,CAAA,KAAAG,EAAA,IAAA,EAAA,GAAAH,EAAA,YADVb,EAAA,GAAAE,EAIuDG,GAAA;;GAFlD,UAAUQ,EAAA;GACV,WAAW;GACZ,OAAM"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as e } from "./PkStreamingMarkdown-
|
|
1
|
+
import { t as e } from "./PkStreamingMarkdown-C55Fi0Pd.js";
|
|
2
2
|
import { t } from "./PkChatbotFilePreview-DIP8KLkS.js";
|
|
3
3
|
import { VvButton as n, VvDropdown as r, VvDropdownAction as i, VvIcon as a } from "@volverjs/ui-vue/components";
|
|
4
4
|
import { Fragment as o, computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createTextVNode as f, createVNode as p, defineComponent as m, mergeModels as h, mergeProps as g, nextTick as _, normalizeClass as v, normalizeProps as ee, onBeforeUnmount as y, onMounted as b, openBlock as x, ref as S, renderList as te, renderSlot as C, toDisplayString as w, unref as T, useId as ne, useModel as E, useTemplateRef as D, watch as re, withCtx as O, withKeys as ie, withModifiers as ae } from "vue";
|
|
@@ -384,4 +384,4 @@ var N = M, P = ["type"], F = {
|
|
|
384
384
|
//#endregion
|
|
385
385
|
export { I as n, L as t };
|
|
386
386
|
|
|
387
|
-
//# sourceMappingURL=PkChatbotInput-
|
|
387
|
+
//# sourceMappingURL=PkChatbotInput-BfZqRpQ2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PkChatbotInput-BfZqRpQ2.js","names":["_hoisted_1","_hoisted_2","__unplugin_components_0","_openBlock","_createElementBlock","_normalizeClass","_createVNode","_toDisplayString","_createCommentVNode","_sfc_main","$t","$slots","$n","_useModel","__unplugin_components_0","__unplugin_components_1","__unplugin_components_2","__unplugin_components_3","_openBlock","_createElementBlock","_createBlock","_createCommentVNode","PkStreamingMarkdown","_toDisplayString","_createElementVNode","_withModifiers","_unref","_createVNode","_Fragment","_renderList","PkChatbotFilePreview","_renderSlot","_normalizeProps","_mergeProps","_withCtx","_createTextVNode","PkChatButton","_withKeys","_normalizeClass","_sfc_main","PkStreamingMarkdown_default","e","t","o","r","n","l","a","i","s","d","c","v","_hoisted_1$1","_hoisted_2$1","PkChatButton_default","defineComponent","_component_VvIcon","VvIcon","openBlock","createElementBlock","normalizeClass","__props","createVNode","toDisplayString","createCommentVNode","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","PkChatbotInput_default","\"modelValue\"","\"modelModifiers\"","\"pendingAttachments\"","\"pendingAttachmentsModifiers\"","__emit","modelValue","useModel","pendingAttachments","emit","props","textareaEl","useTemplateRef","fileInputEl","cameraInputEl","formEl","localValue","ref","syncTimer","cancelSync","flushSync","scheduleSync","onTextareaInput","nextTick","isStreaming","computed","isSubmitted","isInputDisabled","counterId","useId","currentLength","isOverLimit","isUploadingAnyFile","isSubmitEnabled","hasCaptureSupport","acceptMimeTypes","acceptImageMimeTypes","m","showCameraOption","openFilePicker","openCameraPicker","emitFiles","file","files","onFileChange","input","event","removeAttachment","att","id","isDragDropEnabled","useDropZone","isDismissableNoticeVisible","closeDismissableNotice","activeNotice","keepKeyboardFocus","stopGeneration","handleSubmit","onTextareaEnter","onMounted","onBeforeUnmount","_component_VvButton","VvButton","_component_VvDropdownAction","VvDropdownAction","_component_VvDropdown","VvDropdown","createBlock","_ctx","_cache","createElementVNode","withModifiers","unref","isOverDropZone","Fragment","renderList","PkChatbotFilePreview_default","renderSlot","normalizeProps","mergeProps","withCtx","init","aria","toggle","createTextVNode","withKeys"],"sources":["../../../../node_modules/.pnpm/autosize@6.0.1/node_modules/autosize/dist/autosize.esm.js","../../../../packages/components/src/chat/PkChatButton.vue","../../../../packages/components/src/chat/PkChatButton.vue","../../../../packages/components/src/chat/PkChatbotInput.vue","../../../../packages/components/src/chat/PkChatbotInput.vue"],"sourcesContent":["var e=new Map;function t(t){var o=e.get(t);o&&o.destroy()}function o(t){var o=e.get(t);o&&o.update()}var r=null;\"undefined\"==typeof window?((r=function(e){return e}).destroy=function(e){return e},r.update=function(e){return e}):((r=function(t,o){return t&&Array.prototype.forEach.call(t.length?t:[t],function(t){return function(t){if(t&&t.nodeName&&\"TEXTAREA\"===t.nodeName&&!e.has(t)){var o,r=null,n=window.getComputedStyle(t),i=(o=t.value,function(){a({testForHeightReduction:\"\"===o||!t.value.startsWith(o),restoreTextAlign:null}),o=t.value}),l=function(o){t.removeEventListener(\"autosize:destroy\",l),t.removeEventListener(\"autosize:update\",s),t.removeEventListener(\"input\",i),window.removeEventListener(\"resize\",s),Object.keys(o).forEach(function(e){return t.style[e]=o[e]}),e.delete(t)}.bind(t,{height:t.style.height,resize:t.style.resize,textAlign:t.style.textAlign,overflowY:t.style.overflowY,overflowX:t.style.overflowX,wordWrap:t.style.wordWrap});t.addEventListener(\"autosize:destroy\",l),t.addEventListener(\"autosize:update\",s),t.addEventListener(\"input\",i),window.addEventListener(\"resize\",s),t.style.overflowX=\"hidden\",t.style.wordWrap=\"break-word\",e.set(t,{destroy:l,update:s}),s()}function a(e){var o,i,l=e.restoreTextAlign,s=void 0===l?null:l,d=e.testForHeightReduction,u=void 0===d||d,c=n.overflowY;if(0!==t.scrollHeight&&(\"vertical\"===n.resize?t.style.resize=\"none\":\"both\"===n.resize&&(t.style.resize=\"horizontal\"),u&&(o=function(e){for(var t=[];e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&t.push([e.parentNode,e.parentNode.scrollTop]),e=e.parentNode;return function(){return t.forEach(function(e){var t=e[0],o=e[1];t.style.scrollBehavior=\"auto\",t.scrollTop=o,t.style.scrollBehavior=null})}}(t),t.style.height=\"\"),i=\"content-box\"===n.boxSizing?t.scrollHeight-(parseFloat(n.paddingTop)+parseFloat(n.paddingBottom)):t.scrollHeight+parseFloat(n.borderTopWidth)+parseFloat(n.borderBottomWidth),\"none\"!==n.maxHeight&&i>parseFloat(n.maxHeight)?(\"hidden\"===n.overflowY&&(t.style.overflow=\"scroll\"),i=parseFloat(n.maxHeight)):\"hidden\"!==n.overflowY&&(t.style.overflow=\"hidden\"),t.style.height=i+\"px\",s&&(t.style.textAlign=s),o&&o(),r!==i&&(t.dispatchEvent(new Event(\"autosize:resized\",{bubbles:!0})),r=i),c!==n.overflow&&!s)){var v=n.textAlign;\"hidden\"===n.overflow&&(t.style.textAlign=\"start\"===v?\"end\":\"start\"),a({restoreTextAlign:v,testForHeightReduction:!0})}}function s(){a({testForHeightReduction:!0,restoreTextAlign:null})}}(t)}),t}).destroy=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],t),e},r.update=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],o),e});var n=r;export default n;\n","<script lang=\"ts\" setup>\n /**\n * The icon button of the chat dock: attach, send and stop in the input,\n * mute and hang up in a live call. One component, because the call bar\n * takes the place of the input and the two must not look like two\n * different pieces of software.\n *\n * Native attributes fall through to the button, so `title`, `disabled` and\n * `aria-pressed` are written by the caller as they would be on a `<button>`.\n */\n withDefaults(\n defineProps<{\n icon: string\n /** Written next to the icon, for an action nobody should have to guess from a glyph. */\n label?: string\n type?: 'button' | 'submit'\n /** `primary` is the filled circle of send and stop, the one action the dock is for. */\n modifiers?: 'danger' | 'primary'\n }>(),\n { label: undefined, type: 'button', modifiers: undefined },\n )\n</script>\n\n<template>\n <button\n class=\"pk-chat-button\"\n :class=\"[\n modifiers ? `pk-chat-button--${modifiers}` : undefined,\n { 'pk-chat-button--labelled': label },\n ]\"\n :type=\"type\">\n <VvIcon :name=\"icon\" class=\"pk-chat-button__icon\" />\n <span v-if=\"label\" class=\"pk-chat-button__label\">{{ label }}</span>\n </button>\n</template>\n\n<style lang=\"scss\">\n .pk-chat-button {\n position: relative;\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n padding: var(--spacing-4);\n border: none;\n border-radius: var(--rounded);\n background-color: transparent;\n color: var(--color-word-1);\n cursor: pointer;\n transition: var(--transition-colors);\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n\n // The fields' focus ring: a 1px surface-5 line measured 1.3:1 on the\n // surface, under the 3:1 a focus indicator needs\n &:focus-visible {\n outline: var(--spacing-2) solid var(--input-focus-color);\n outline-offset: 0;\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n // A finger needs 40px and the button is drawn at 28: on a touch\n // screen it answers 8px around itself, in every layout of the chat\n // (it was the fullscreen one only) and in the call bar, which mounts\n // the same button\n @media (pointer: coarse) {\n &::after {\n content: '';\n position: absolute;\n inset: calc(-1 * var(--spacing-8));\n }\n }\n\n // A toggle has to survive a glance: a crossed-out glyph alone changes\n // too few pixels to notice mid-sentence.\n &[aria-pressed='true'] {\n background-color: var(--color-surface-3);\n color: var(--color-word);\n }\n\n // A wash of the same red rather than a lighter red behind it: the\n // `lighten-5` step lands close enough to the icon to leave it at about\n // 2:1, which is a button that disappears exactly while it is being\n // pointed at. The tint composites over whatever surface is behind, so\n // it holds in the dark theme too.\n &--danger {\n // The project's text shade of danger; the fill where a host app\n // loads only the library and this package's stylesheet\n color: var(--u-danger-text, var(--color-danger));\n\n &:hover {\n background-color: color-mix(\n in srgb,\n var(--color-danger) 12%,\n transparent\n );\n }\n }\n\n // Same 28px box as the ghost buttons, so the dock keeps its height,\n // with a smaller glyph because a filled shape needs air around it.\n // Its edge is visible, so it sits on the input's padding line just as\n // the text does: a ghost glyph sat 6px further in and made the two\n // sides of the input look unequal. Empty, it turns into a grey pad\n // with the fields' disabled ink: a light arrow on that pad vanished,\n // and with it the circle's edge, which is what squares the sides.\n // The agent's color when the widget has one, like the user's bubble.\n &--primary {\n --pk-chat-button-fill: var(\n --chatbot-main-color,\n var(--color-word-1)\n );\n\n padding: var(--spacing-6);\n border-radius: var(--rounded-full);\n background-color: var(--pk-chat-button-fill);\n color: var(--chatbot-contrast-color, var(--color-surface));\n\n &:hover {\n background-color: color-mix(\n in srgb,\n var(--pk-chat-button-fill) 85%,\n var(--color-surface)\n );\n }\n\n // Off the disc, or a dark ring would sink into a dark fill\n &:focus-visible {\n outline-offset: var(--spacing-2);\n }\n\n &:disabled {\n opacity: 1;\n background-color: var(--color-surface-3);\n color: var(--color-word-3);\n }\n\n .pk-chat-button__icon {\n width: var(--spacing-16);\n height: var(--spacing-16);\n }\n }\n\n &--labelled {\n gap: var(--spacing-4);\n padding-inline: var(--spacing-8);\n font-size: var(--text-12);\n }\n\n &__icon {\n display: block;\n width: var(--spacing-20);\n height: var(--spacing-20);\n }\n }\n</style>\n","<script lang=\"ts\" setup>\n /**\n * The icon button of the chat dock: attach, send and stop in the input,\n * mute and hang up in a live call. One component, because the call bar\n * takes the place of the input and the two must not look like two\n * different pieces of software.\n *\n * Native attributes fall through to the button, so `title`, `disabled` and\n * `aria-pressed` are written by the caller as they would be on a `<button>`.\n */\n withDefaults(\n defineProps<{\n icon: string\n /** Written next to the icon, for an action nobody should have to guess from a glyph. */\n label?: string\n type?: 'button' | 'submit'\n /** `primary` is the filled circle of send and stop, the one action the dock is for. */\n modifiers?: 'danger' | 'primary'\n }>(),\n { label: undefined, type: 'button', modifiers: undefined },\n )\n</script>\n\n<template>\n <button\n class=\"pk-chat-button\"\n :class=\"[\n modifiers ? `pk-chat-button--${modifiers}` : undefined,\n { 'pk-chat-button--labelled': label },\n ]\"\n :type=\"type\">\n <VvIcon :name=\"icon\" class=\"pk-chat-button__icon\" />\n <span v-if=\"label\" class=\"pk-chat-button__label\">{{ label }}</span>\n </button>\n</template>\n\n<style lang=\"scss\">\n .pk-chat-button {\n position: relative;\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n padding: var(--spacing-4);\n border: none;\n border-radius: var(--rounded);\n background-color: transparent;\n color: var(--color-word-1);\n cursor: pointer;\n transition: var(--transition-colors);\n\n &:hover {\n background-color: var(--color-surface-2);\n }\n\n // The fields' focus ring: a 1px surface-5 line measured 1.3:1 on the\n // surface, under the 3:1 a focus indicator needs\n &:focus-visible {\n outline: var(--spacing-2) solid var(--input-focus-color);\n outline-offset: 0;\n }\n\n &:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n // A finger needs 40px and the button is drawn at 28: on a touch\n // screen it answers 8px around itself, in every layout of the chat\n // (it was the fullscreen one only) and in the call bar, which mounts\n // the same button\n @media (pointer: coarse) {\n &::after {\n content: '';\n position: absolute;\n inset: calc(-1 * var(--spacing-8));\n }\n }\n\n // A toggle has to survive a glance: a crossed-out glyph alone changes\n // too few pixels to notice mid-sentence.\n &[aria-pressed='true'] {\n background-color: var(--color-surface-3);\n color: var(--color-word);\n }\n\n // A wash of the same red rather than a lighter red behind it: the\n // `lighten-5` step lands close enough to the icon to leave it at about\n // 2:1, which is a button that disappears exactly while it is being\n // pointed at. The tint composites over whatever surface is behind, so\n // it holds in the dark theme too.\n &--danger {\n // The project's text shade of danger; the fill where a host app\n // loads only the library and this package's stylesheet\n color: var(--u-danger-text, var(--color-danger));\n\n &:hover {\n background-color: color-mix(\n in srgb,\n var(--color-danger) 12%,\n transparent\n );\n }\n }\n\n // Same 28px box as the ghost buttons, so the dock keeps its height,\n // with a smaller glyph because a filled shape needs air around it.\n // Its edge is visible, so it sits on the input's padding line just as\n // the text does: a ghost glyph sat 6px further in and made the two\n // sides of the input look unequal. Empty, it turns into a grey pad\n // with the fields' disabled ink: a light arrow on that pad vanished,\n // and with it the circle's edge, which is what squares the sides.\n // The agent's color when the widget has one, like the user's bubble.\n &--primary {\n --pk-chat-button-fill: var(\n --chatbot-main-color,\n var(--color-word-1)\n );\n\n padding: var(--spacing-6);\n border-radius: var(--rounded-full);\n background-color: var(--pk-chat-button-fill);\n color: var(--chatbot-contrast-color, var(--color-surface));\n\n &:hover {\n background-color: color-mix(\n in srgb,\n var(--pk-chat-button-fill) 85%,\n var(--color-surface)\n );\n }\n\n // Off the disc, or a dark ring would sink into a dark fill\n &:focus-visible {\n outline-offset: var(--spacing-2);\n }\n\n &:disabled {\n opacity: 1;\n background-color: var(--color-surface-3);\n color: var(--color-word-3);\n }\n\n .pk-chat-button__icon {\n width: var(--spacing-16);\n height: var(--spacing-16);\n }\n }\n\n &--labelled {\n gap: var(--spacing-4);\n padding-inline: var(--spacing-8);\n font-size: var(--text-12);\n }\n\n &__icon {\n display: block;\n width: var(--spacing-20);\n height: var(--spacing-20);\n }\n }\n</style>\n","<script setup lang=\"ts\">\n // @ts-expect-error - no types for autosize\n import autosize from 'autosize'\n import {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n useId,\n useTemplateRef,\n watch,\n } from 'vue'\n import { useDropZone } from '@vueuse/core'\n import type { AgentFileUpload } from 'models'\n import type { PendingAttachment } from 'composables'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkChatbotFilePreview from './PkChatbotFilePreview.vue'\n import PkChatButton from './PkChatButton.vue'\n\n // --- Models & Props ---\n\n const modelValue = defineModel<string | undefined>({ default: undefined })\n const pendingAttachments = defineModel<PendingAttachment[]>(\n 'pendingAttachments',\n { default: () => [] },\n )\n\n const emit = defineEmits<{\n submit: []\n 'stop-generation': []\n 'file-select': [file: File]\n 'dismiss-attachment-notice': []\n 'voice-start': []\n }>()\n\n const props = defineProps<{\n placeholder?: string\n dismissableNotice?: string\n status?: 'submitted' | 'streaming' | 'ready' | 'error'\n maxMessageLength?: number\n fileUpload?: AgentFileUpload\n enableDragDrop?: boolean\n attachmentLimitReached?: boolean\n attachmentNotice?: string\n /** Show the talk button: the agent has voice enabled. */\n voiceEnabled?: boolean\n }>()\n\n // --- Template refs ---\n\n const textareaEl = useTemplateRef<HTMLTextAreaElement>('textareaEl')\n const fileInputEl = useTemplateRef<HTMLInputElement>('fileInputEl')\n const cameraInputEl = useTemplateRef<HTMLInputElement>('cameraInputEl')\n const formEl = useTemplateRef<HTMLFormElement>('formEl')\n\n // --- Input buffering (decouples typing from reactive model propagation) ---\n\n const localValue = ref(modelValue.value ?? '')\n let syncTimer: ReturnType<typeof setTimeout> | null = null\n\n const cancelSync = () => {\n if (syncTimer !== null) {\n clearTimeout(syncTimer)\n syncTimer = null\n }\n }\n\n const flushSync = () => {\n cancelSync()\n modelValue.value = localValue.value\n }\n\n const scheduleSync = () => {\n cancelSync()\n syncTimer = setTimeout(() => {\n modelValue.value = localValue.value\n syncTimer = null\n }, 300)\n }\n\n const onTextareaInput = () => {\n localValue.value = textareaEl.value?.value ?? ''\n scheduleSync()\n }\n\n watch(modelValue, (v) => {\n if (v !== localValue.value) {\n localValue.value = v ?? ''\n nextTick(() => {\n if (textareaEl.value) {\n autosize.update(textareaEl.value)\n }\n })\n }\n })\n\n // --- Status computeds ---\n\n const isStreaming = computed(() => props.status === 'streaming')\n const isSubmitted = computed(() => props.status === 'submitted')\n const isInputDisabled = computed(\n () => isStreaming.value || isSubmitted.value,\n )\n\n // --- Validation ---\n\n const counterId = useId()\n const currentLength = computed(() => localValue.value.length)\n\n const isOverLimit = computed(\n () =>\n props.maxMessageLength !== undefined &&\n currentLength.value > props.maxMessageLength,\n )\n\n const isUploadingAnyFile = computed(() =>\n pendingAttachments.value.some((a) => a.state === 'uploading'),\n )\n\n const isSubmitEnabled = computed(() => {\n if (\n isInputDisabled.value ||\n isUploadingAnyFile.value ||\n isOverLimit.value\n ) {\n return false\n }\n return localValue.value.trim().length > 0\n })\n\n // --- File upload ---\n\n const hasCaptureSupport = 'capture' in document.createElement('input')\n\n const acceptMimeTypes = computed(\n () => props.fileUpload?.allowedMimeTypes?.join(',') ?? '',\n )\n\n const acceptImageMimeTypes = computed(() =>\n (props.fileUpload?.allowedMimeTypes ?? [])\n .filter((m) => m.startsWith('image/'))\n .join(','),\n )\n\n const showCameraOption = computed(\n () => hasCaptureSupport && acceptImageMimeTypes.value.length > 0,\n )\n\n const openFilePicker = () => {\n fileInputEl.value?.click()\n }\n\n const openCameraPicker = () => {\n cameraInputEl.value?.click()\n }\n\n // The store owns the attachment limits and drops any overflow; the input\n // just forwards every picked/dropped file.\n const emitFiles = (files: File[]) => {\n for (const file of files) {\n emit('file-select', file)\n }\n }\n\n const onFileChange = (event: Event) => {\n const input = event.target as HTMLInputElement\n emitFiles(Array.from(input.files ?? []))\n input.value = ''\n }\n\n // --- Attachments ---\n\n const removeAttachment = (id: string) => {\n const att = pendingAttachments.value.find((a) => a.id === id)\n if (att) {\n URL.revokeObjectURL(att.localUrl)\n }\n pendingAttachments.value = pendingAttachments.value.filter(\n (a) => a.id !== id,\n )\n }\n\n // --- Drag & drop ---\n\n const isDragDropEnabled = computed(\n () => (props.enableDragDrop ?? true) && !!props.fileUpload?.enabled,\n )\n\n const handleDrop = (files: File[] | null) => {\n if (!isDragDropEnabled.value || !files) {\n return\n }\n emitFiles(files)\n }\n\n const { isOverDropZone } = useDropZone(formEl, {\n dataTypes: computed(() => props.fileUpload?.allowedMimeTypes ?? []),\n onDrop: handleDrop,\n })\n\n // --- Notice queue (single slot above the input, highest priority wins) ---\n\n type InputNotice = {\n id: string\n text?: string\n markdown?: string\n icon?: string\n dismiss?: () => void\n }\n\n const isDismissableNoticeVisible = ref(true)\n const closeDismissableNotice = () => {\n isDismissableNoticeVisible.value = false\n }\n\n const activeNotice = computed<InputNotice | null>(() => {\n // Order = priority. The alert takes precedence over the notice.\n if (props.attachmentNotice) {\n return {\n id: 'limit',\n icon: 'ri:information-line',\n text: props.attachmentNotice,\n dismiss: () => emit('dismiss-attachment-notice'),\n }\n }\n if (props.dismissableNotice && isDismissableNoticeVisible.value) {\n return {\n id: 'dismissable',\n markdown: props.dismissableNotice,\n dismiss: closeDismissableNotice,\n }\n }\n return null\n })\n\n // --- Submit ---\n\n /**\n * Send turns disabled and then gives way to stop, stop gives way to send:\n * a keyboard user who pressed one would be left on the page body. Hand\n * the focus to the textarea, but only after a keyboard press: a tap has no\n * focus to keep, and focusing would bring the phone keyboard back up over\n * the answer.\n */\n const keepKeyboardFocus = () => {\n if (formEl.value?.querySelector('button:focus-visible')) {\n textareaEl.value?.focus()\n }\n }\n\n const stopGeneration = () => {\n keepKeyboardFocus()\n emit('stop-generation')\n }\n\n const handleSubmit = () => {\n if (!isSubmitEnabled.value) {\n return\n }\n keepKeyboardFocus()\n flushSync()\n emit('submit')\n localValue.value = ''\n modelValue.value = ''\n nextTick(() => {\n if (textareaEl.value) {\n textareaEl.value.value = ''\n autosize.update(textareaEl.value)\n }\n })\n }\n\n /**\n * Enter sends, Shift+Enter goes to a new line. The Enter that confirms an\n * IME composition (Japanese, Chinese, Korean) belongs to the composition:\n * Safari reports it with `isComposing` already false, hence the 229.\n */\n const onTextareaEnter = (event: KeyboardEvent) => {\n if (event.shiftKey || event.isComposing || event.keyCode === 229) {\n return\n }\n event.preventDefault()\n handleSubmit()\n }\n\n // --- Lifecycle ---\n\n onMounted(() => {\n if (textareaEl.value) {\n autosize(textareaEl.value)\n }\n })\n\n onBeforeUnmount(() => {\n cancelSync()\n if (textareaEl.value) {\n autosize.destroy(textareaEl.value)\n }\n for (const att of pendingAttachments.value) {\n URL.revokeObjectURL(att.localUrl)\n }\n })\n</script>\n\n<template>\n <div class=\"pk-chatbot-input\">\n <div\n v-if=\"activeNotice\"\n :key=\"activeNotice.id\"\n class=\"pk-chatbot-input__notice\"\n role=\"status\">\n <VvIcon\n v-if=\"activeNotice.icon\"\n :name=\"activeNotice.icon\"\n class=\"pk-chatbot-input__notice-icon\" />\n <PkStreamingMarkdown\n v-if=\"activeNotice.markdown\"\n :markdown=\"activeNotice.markdown\"\n class=\"wysiwyg pk-chatbot-input__notice-text\" />\n <span v-else class=\"pk-chatbot-input__notice-text\">\n {{ activeNotice.text }}\n </span>\n <VvButton\n v-if=\"activeNotice.dismiss\"\n :title=\"$t('action.close')\"\n modifiers=\"action-quiet\"\n icon=\"ri:close-line\"\n class=\"w-18 h-18\"\n @click=\"activeNotice.dismiss()\" />\n </div>\n <form\n ref=\"formEl\"\n class=\"pk-chatbot-input__form\"\n @submit.prevent=\"handleSubmit\">\n <div\n v-if=\"isOverDropZone && isDragDropEnabled\"\n class=\"pk-chatbot-input__drop-overlay\">\n <VvIcon\n name=\"ri:upload-cloud-2-line\"\n class=\"pk-chatbot-input__drop-overlay-icon\" />\n <span>{{ $t('action.dropFile') }}</span>\n </div>\n <div\n v-if=\"pendingAttachments.length\"\n class=\"pk-chatbot-input__attachments\">\n <PkChatbotFilePreview\n v-for=\"att in pendingAttachments\"\n :key=\"att.id\"\n :media-type=\"att.file.type\"\n :url=\"att.localUrl\"\n :filename=\"att.file.name\"\n :size=\"att.file.size\"\n :loading=\"att.state === 'uploading'\"\n :error=\"att.state === 'error' ? att.error : undefined\"\n :removable=\"att.state !== 'uploading'\"\n compact\n @remove=\"removeAttachment(att.id)\" />\n </div>\n <div class=\"pk-chatbot-input__fieldset\">\n <slot name=\"prepend\" />\n <VvDropdown\n v-if=\"\n fileUpload &&\n fileUpload.enabled &&\n (showCameraOption || $slots['additional-actions'])\n \"\n v-bind=\"{\n placement: 'top-start',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n }\">\n <template #default=\"{ init, toggle, aria }\">\n <!-- The only one still written by hand: the dropdown\n anchors itself to whatever `init` receives, and that\n has to be the element, not a component instance -->\n <button\n :ref=\"(e: any) => init(e)\"\n v-bind=\"aria\"\n class=\"pk-chat-button\"\n type=\"button\"\n :title=\"$t('action.attachFile')\"\n :disabled=\"isInputDisabled\"\n @click=\"toggle\">\n <VvIcon\n name=\"ri:add-line\"\n class=\"pk-chat-button__icon\" />\n </button>\n </template>\n <template #items>\n <VvDropdownAction\n v-if=\"showCameraOption\"\n :disabled=\"\n isInputDisabled || attachmentLimitReached\n \"\n @click=\"openCameraPicker\">\n <VvIcon\n name=\"ri:camera-line\"\n class=\"pk-chatbot-input__dropdown-icon\" />\n {{ $t('action.takePhoto') }}\n </VvDropdownAction>\n <VvDropdownAction\n :disabled=\"\n isInputDisabled || attachmentLimitReached\n \"\n @click=\"openFilePicker\">\n <VvIcon\n name=\"ri:attachment-line\"\n class=\"pk-chatbot-input__dropdown-icon\" />\n {{ $t('action.attachFile') }}\n </VvDropdownAction>\n <slot name=\"additional-actions\" />\n </template>\n </VvDropdown>\n <PkChatButton\n v-else-if=\"fileUpload && fileUpload.enabled\"\n icon=\"ri:add-line\"\n :title=\"$t('action.attachFile')\"\n :disabled=\"isInputDisabled || attachmentLimitReached\"\n @click=\"openFilePicker\" />\n <input\n v-if=\"fileUpload && fileUpload.enabled\"\n ref=\"fileInputEl\"\n type=\"file\"\n hidden\n multiple\n :accept=\"acceptMimeTypes\"\n @change=\"onFileChange\" />\n <input\n v-if=\"fileUpload && fileUpload.enabled && showCameraOption\"\n ref=\"cameraInputEl\"\n type=\"file\"\n capture=\"environment\"\n hidden\n :accept=\"acceptImageMimeTypes\"\n @change=\"onFileChange\" />\n <div class=\"pk-chatbot-input__content\">\n <textarea\n ref=\"textareaEl\"\n :value=\"localValue\"\n class=\"pk-chatbot-input__textarea\"\n name=\"message\"\n rows=\"1\"\n enterkeyhint=\"send\"\n :aria-label=\"$t('label.message')\"\n :aria-describedby=\"\n maxMessageLength ? counterId : undefined\n \"\n :aria-invalid=\"isOverLimit || undefined\"\n :placeholder\n @input=\"onTextareaInput\"\n @keydown.enter=\"onTextareaEnter\"></textarea>\n </div>\n <div\n v-if=\"maxMessageLength\"\n :id=\"counterId\"\n class=\"pk-chatbot-input__counter\"\n :class=\"{ 'pk-chatbot-input__counter--over': isOverLimit }\">\n {{ $n(currentLength, 'integer') }}/<span\n class=\"opacity-60\"\n >{{ $n(maxMessageLength, 'integer') }}</span\n >\n </div>\n <PkChatButton\n v-if=\"voiceEnabled && !isStreaming\"\n icon=\"ri:mic-line\"\n :title=\"$t('action.talk')\"\n :disabled=\"isInputDisabled\"\n @click=\"emit('voice-start')\" />\n <PkChatButton\n v-if=\"isStreaming\"\n icon=\"ri:stop-fill\"\n modifiers=\"primary\"\n :title=\"$t('action.stop')\"\n @click=\"stopGeneration\" />\n <PkChatButton\n v-else\n type=\"submit\"\n modifiers=\"primary\"\n :icon=\"isSubmitted ? 'loading-loop' : 'ri:arrow-up-line'\"\n :title=\"$t('action.submit')\"\n :disabled=\"!isSubmitEnabled\" />\n </div>\n </form>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-input {\n position: relative;\n display: flex;\n flex-direction: column;\n margin-inline: var(--spacing-sm);\n margin-bottom: var(--spacing-sm);\n\n &__notice {\n position: relative;\n padding: var(--spacing-10) var(--spacing-sm);\n display: flex;\n align-items: flex-start;\n gap: var(--spacing-sm);\n background-color: var(--color-surface-1);\n border-top-left-radius: var(--rounded-xl);\n border-top-right-radius: var(--rounded-xl);\n transition-property: var(--transition-property-all);\n transition-duration: var(--duration-300);\n transition-timing-function: var(--ease-in-out);\n font-size: var(--text-12);\n color: var(--color-word-4);\n\n &::after {\n content: '';\n display: block;\n position: absolute;\n left: 0;\n right: 0;\n bottom: calc(-1 * var(--spacing-12));\n height: var(--spacing-12);\n background-color: var(--color-surface-1);\n z-index: 1;\n }\n\n &-icon {\n flex-shrink: 0;\n width: var(--spacing-18);\n height: var(--spacing-18);\n }\n\n &-text {\n flex: 1;\n min-width: 0;\n }\n }\n\n &__form {\n position: relative;\n display: flex;\n z-index: 1;\n flex-direction: column;\n\n // The composer is a field too: same border and focus ring as the\n // form fields, on top of the shadow and the 12px radius that make\n // it the container (12) of its 8px buttons\n border-radius: var(--rounded-xl);\n border: 1px solid var(--input-border-color);\n background-color: var(--color-surface);\n padding: var(--spacing-14);\n box-shadow: var(--shadow-lg);\n font-size: var(\n --text-16\n ); // prevent ios zoom on input focus by using a font size >= 16px\n gap: var(--spacing-xs);\n transition: var(--input-transition);\n\n @include media-breakpoint-up('sm', $breakpoints) {\n font-size: var(--text-14);\n padding: var(--spacing-10);\n }\n\n &:has(:focus-within) {\n border-color: var(--input-focus-color);\n box-shadow: var(--shadow-lg), var(--input-focus-ring);\n }\n }\n\n &__drop-overlay {\n position: absolute;\n inset: 0;\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-xs);\n border-radius: var(--rounded-xl);\n background-color: color-mix(\n in srgb,\n var(--color-surface) 85%,\n transparent\n );\n pointer-events: none;\n }\n\n &__fieldset {\n display: flex;\n align-items: center;\n gap: var(--spacing-xs);\n flex: 1;\n\n // The buttons answer 8px around themselves on a touch screen\n // (PkChatButton): 12px apart, neither takes the other's box\n @media (pointer: coarse) {\n gap: var(--spacing-12);\n }\n }\n\n &__content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: var(--spacing-4);\n min-width: 0;\n overflow: hidden;\n }\n\n &__textarea {\n display: block;\n border: none;\n outline: none;\n resize: none;\n width: 100%;\n max-height: 200px;\n color: var(--color-word-1);\n background-color: var(--color-surface);\n\n &::placeholder {\n color: var(--color-word-4);\n }\n }\n\n &__attachments {\n display: flex;\n flex-wrap: wrap;\n // Roomy gap so the uniform-height chips breathe in the row.\n gap: var(--spacing-12);\n padding-bottom: var(--spacing-xs);\n border-bottom: 1px solid var(--color-surface-2);\n }\n\n &__counter {\n background-color: var(--color-surface-1);\n border: 1px solid var(--color-surface-3);\n border-radius: var(--rounded-md);\n font-size: var(--text-12);\n color: var(--color-word-3);\n line-height: 1;\n padding-inline: var(--spacing-6);\n padding-block: var(--spacing-4);\n z-index: 1;\n font-variant-numeric: tabular-nums;\n font-family: var(--font-mono);\n font-weight: var(--font-bold);\n\n &--over {\n color: var(--u-danger-text, var(--color-danger));\n border-color: var(--color-danger-lighten-5);\n font-weight: var(--font-bold);\n }\n }\n }\n</style>\n","<script setup lang=\"ts\">\n // @ts-expect-error - no types for autosize\n import autosize from 'autosize'\n import {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n useId,\n useTemplateRef,\n watch,\n } from 'vue'\n import { useDropZone } from '@vueuse/core'\n import type { AgentFileUpload } from 'models'\n import type { PendingAttachment } from 'composables'\n import PkStreamingMarkdown from './PkStreamingMarkdown.vue'\n import PkChatbotFilePreview from './PkChatbotFilePreview.vue'\n import PkChatButton from './PkChatButton.vue'\n\n // --- Models & Props ---\n\n const modelValue = defineModel<string | undefined>({ default: undefined })\n const pendingAttachments = defineModel<PendingAttachment[]>(\n 'pendingAttachments',\n { default: () => [] },\n )\n\n const emit = defineEmits<{\n submit: []\n 'stop-generation': []\n 'file-select': [file: File]\n 'dismiss-attachment-notice': []\n 'voice-start': []\n }>()\n\n const props = defineProps<{\n placeholder?: string\n dismissableNotice?: string\n status?: 'submitted' | 'streaming' | 'ready' | 'error'\n maxMessageLength?: number\n fileUpload?: AgentFileUpload\n enableDragDrop?: boolean\n attachmentLimitReached?: boolean\n attachmentNotice?: string\n /** Show the talk button: the agent has voice enabled. */\n voiceEnabled?: boolean\n }>()\n\n // --- Template refs ---\n\n const textareaEl = useTemplateRef<HTMLTextAreaElement>('textareaEl')\n const fileInputEl = useTemplateRef<HTMLInputElement>('fileInputEl')\n const cameraInputEl = useTemplateRef<HTMLInputElement>('cameraInputEl')\n const formEl = useTemplateRef<HTMLFormElement>('formEl')\n\n // --- Input buffering (decouples typing from reactive model propagation) ---\n\n const localValue = ref(modelValue.value ?? '')\n let syncTimer: ReturnType<typeof setTimeout> | null = null\n\n const cancelSync = () => {\n if (syncTimer !== null) {\n clearTimeout(syncTimer)\n syncTimer = null\n }\n }\n\n const flushSync = () => {\n cancelSync()\n modelValue.value = localValue.value\n }\n\n const scheduleSync = () => {\n cancelSync()\n syncTimer = setTimeout(() => {\n modelValue.value = localValue.value\n syncTimer = null\n }, 300)\n }\n\n const onTextareaInput = () => {\n localValue.value = textareaEl.value?.value ?? ''\n scheduleSync()\n }\n\n watch(modelValue, (v) => {\n if (v !== localValue.value) {\n localValue.value = v ?? ''\n nextTick(() => {\n if (textareaEl.value) {\n autosize.update(textareaEl.value)\n }\n })\n }\n })\n\n // --- Status computeds ---\n\n const isStreaming = computed(() => props.status === 'streaming')\n const isSubmitted = computed(() => props.status === 'submitted')\n const isInputDisabled = computed(\n () => isStreaming.value || isSubmitted.value,\n )\n\n // --- Validation ---\n\n const counterId = useId()\n const currentLength = computed(() => localValue.value.length)\n\n const isOverLimit = computed(\n () =>\n props.maxMessageLength !== undefined &&\n currentLength.value > props.maxMessageLength,\n )\n\n const isUploadingAnyFile = computed(() =>\n pendingAttachments.value.some((a) => a.state === 'uploading'),\n )\n\n const isSubmitEnabled = computed(() => {\n if (\n isInputDisabled.value ||\n isUploadingAnyFile.value ||\n isOverLimit.value\n ) {\n return false\n }\n return localValue.value.trim().length > 0\n })\n\n // --- File upload ---\n\n const hasCaptureSupport = 'capture' in document.createElement('input')\n\n const acceptMimeTypes = computed(\n () => props.fileUpload?.allowedMimeTypes?.join(',') ?? '',\n )\n\n const acceptImageMimeTypes = computed(() =>\n (props.fileUpload?.allowedMimeTypes ?? [])\n .filter((m) => m.startsWith('image/'))\n .join(','),\n )\n\n const showCameraOption = computed(\n () => hasCaptureSupport && acceptImageMimeTypes.value.length > 0,\n )\n\n const openFilePicker = () => {\n fileInputEl.value?.click()\n }\n\n const openCameraPicker = () => {\n cameraInputEl.value?.click()\n }\n\n // The store owns the attachment limits and drops any overflow; the input\n // just forwards every picked/dropped file.\n const emitFiles = (files: File[]) => {\n for (const file of files) {\n emit('file-select', file)\n }\n }\n\n const onFileChange = (event: Event) => {\n const input = event.target as HTMLInputElement\n emitFiles(Array.from(input.files ?? []))\n input.value = ''\n }\n\n // --- Attachments ---\n\n const removeAttachment = (id: string) => {\n const att = pendingAttachments.value.find((a) => a.id === id)\n if (att) {\n URL.revokeObjectURL(att.localUrl)\n }\n pendingAttachments.value = pendingAttachments.value.filter(\n (a) => a.id !== id,\n )\n }\n\n // --- Drag & drop ---\n\n const isDragDropEnabled = computed(\n () => (props.enableDragDrop ?? true) && !!props.fileUpload?.enabled,\n )\n\n const handleDrop = (files: File[] | null) => {\n if (!isDragDropEnabled.value || !files) {\n return\n }\n emitFiles(files)\n }\n\n const { isOverDropZone } = useDropZone(formEl, {\n dataTypes: computed(() => props.fileUpload?.allowedMimeTypes ?? []),\n onDrop: handleDrop,\n })\n\n // --- Notice queue (single slot above the input, highest priority wins) ---\n\n type InputNotice = {\n id: string\n text?: string\n markdown?: string\n icon?: string\n dismiss?: () => void\n }\n\n const isDismissableNoticeVisible = ref(true)\n const closeDismissableNotice = () => {\n isDismissableNoticeVisible.value = false\n }\n\n const activeNotice = computed<InputNotice | null>(() => {\n // Order = priority. The alert takes precedence over the notice.\n if (props.attachmentNotice) {\n return {\n id: 'limit',\n icon: 'ri:information-line',\n text: props.attachmentNotice,\n dismiss: () => emit('dismiss-attachment-notice'),\n }\n }\n if (props.dismissableNotice && isDismissableNoticeVisible.value) {\n return {\n id: 'dismissable',\n markdown: props.dismissableNotice,\n dismiss: closeDismissableNotice,\n }\n }\n return null\n })\n\n // --- Submit ---\n\n /**\n * Send turns disabled and then gives way to stop, stop gives way to send:\n * a keyboard user who pressed one would be left on the page body. Hand\n * the focus to the textarea, but only after a keyboard press: a tap has no\n * focus to keep, and focusing would bring the phone keyboard back up over\n * the answer.\n */\n const keepKeyboardFocus = () => {\n if (formEl.value?.querySelector('button:focus-visible')) {\n textareaEl.value?.focus()\n }\n }\n\n const stopGeneration = () => {\n keepKeyboardFocus()\n emit('stop-generation')\n }\n\n const handleSubmit = () => {\n if (!isSubmitEnabled.value) {\n return\n }\n keepKeyboardFocus()\n flushSync()\n emit('submit')\n localValue.value = ''\n modelValue.value = ''\n nextTick(() => {\n if (textareaEl.value) {\n textareaEl.value.value = ''\n autosize.update(textareaEl.value)\n }\n })\n }\n\n /**\n * Enter sends, Shift+Enter goes to a new line. The Enter that confirms an\n * IME composition (Japanese, Chinese, Korean) belongs to the composition:\n * Safari reports it with `isComposing` already false, hence the 229.\n */\n const onTextareaEnter = (event: KeyboardEvent) => {\n if (event.shiftKey || event.isComposing || event.keyCode === 229) {\n return\n }\n event.preventDefault()\n handleSubmit()\n }\n\n // --- Lifecycle ---\n\n onMounted(() => {\n if (textareaEl.value) {\n autosize(textareaEl.value)\n }\n })\n\n onBeforeUnmount(() => {\n cancelSync()\n if (textareaEl.value) {\n autosize.destroy(textareaEl.value)\n }\n for (const att of pendingAttachments.value) {\n URL.revokeObjectURL(att.localUrl)\n }\n })\n</script>\n\n<template>\n <div class=\"pk-chatbot-input\">\n <div\n v-if=\"activeNotice\"\n :key=\"activeNotice.id\"\n class=\"pk-chatbot-input__notice\"\n role=\"status\">\n <VvIcon\n v-if=\"activeNotice.icon\"\n :name=\"activeNotice.icon\"\n class=\"pk-chatbot-input__notice-icon\" />\n <PkStreamingMarkdown\n v-if=\"activeNotice.markdown\"\n :markdown=\"activeNotice.markdown\"\n class=\"wysiwyg pk-chatbot-input__notice-text\" />\n <span v-else class=\"pk-chatbot-input__notice-text\">\n {{ activeNotice.text }}\n </span>\n <VvButton\n v-if=\"activeNotice.dismiss\"\n :title=\"$t('action.close')\"\n modifiers=\"action-quiet\"\n icon=\"ri:close-line\"\n class=\"w-18 h-18\"\n @click=\"activeNotice.dismiss()\" />\n </div>\n <form\n ref=\"formEl\"\n class=\"pk-chatbot-input__form\"\n @submit.prevent=\"handleSubmit\">\n <div\n v-if=\"isOverDropZone && isDragDropEnabled\"\n class=\"pk-chatbot-input__drop-overlay\">\n <VvIcon\n name=\"ri:upload-cloud-2-line\"\n class=\"pk-chatbot-input__drop-overlay-icon\" />\n <span>{{ $t('action.dropFile') }}</span>\n </div>\n <div\n v-if=\"pendingAttachments.length\"\n class=\"pk-chatbot-input__attachments\">\n <PkChatbotFilePreview\n v-for=\"att in pendingAttachments\"\n :key=\"att.id\"\n :media-type=\"att.file.type\"\n :url=\"att.localUrl\"\n :filename=\"att.file.name\"\n :size=\"att.file.size\"\n :loading=\"att.state === 'uploading'\"\n :error=\"att.state === 'error' ? att.error : undefined\"\n :removable=\"att.state !== 'uploading'\"\n compact\n @remove=\"removeAttachment(att.id)\" />\n </div>\n <div class=\"pk-chatbot-input__fieldset\">\n <slot name=\"prepend\" />\n <VvDropdown\n v-if=\"\n fileUpload &&\n fileUpload.enabled &&\n (showCameraOption || $slots['additional-actions'])\n \"\n v-bind=\"{\n placement: 'top-start',\n modifiers: 'menu',\n flip: true,\n offset: 3,\n }\">\n <template #default=\"{ init, toggle, aria }\">\n <!-- The only one still written by hand: the dropdown\n anchors itself to whatever `init` receives, and that\n has to be the element, not a component instance -->\n <button\n :ref=\"(e: any) => init(e)\"\n v-bind=\"aria\"\n class=\"pk-chat-button\"\n type=\"button\"\n :title=\"$t('action.attachFile')\"\n :disabled=\"isInputDisabled\"\n @click=\"toggle\">\n <VvIcon\n name=\"ri:add-line\"\n class=\"pk-chat-button__icon\" />\n </button>\n </template>\n <template #items>\n <VvDropdownAction\n v-if=\"showCameraOption\"\n :disabled=\"\n isInputDisabled || attachmentLimitReached\n \"\n @click=\"openCameraPicker\">\n <VvIcon\n name=\"ri:camera-line\"\n class=\"pk-chatbot-input__dropdown-icon\" />\n {{ $t('action.takePhoto') }}\n </VvDropdownAction>\n <VvDropdownAction\n :disabled=\"\n isInputDisabled || attachmentLimitReached\n \"\n @click=\"openFilePicker\">\n <VvIcon\n name=\"ri:attachment-line\"\n class=\"pk-chatbot-input__dropdown-icon\" />\n {{ $t('action.attachFile') }}\n </VvDropdownAction>\n <slot name=\"additional-actions\" />\n </template>\n </VvDropdown>\n <PkChatButton\n v-else-if=\"fileUpload && fileUpload.enabled\"\n icon=\"ri:add-line\"\n :title=\"$t('action.attachFile')\"\n :disabled=\"isInputDisabled || attachmentLimitReached\"\n @click=\"openFilePicker\" />\n <input\n v-if=\"fileUpload && fileUpload.enabled\"\n ref=\"fileInputEl\"\n type=\"file\"\n hidden\n multiple\n :accept=\"acceptMimeTypes\"\n @change=\"onFileChange\" />\n <input\n v-if=\"fileUpload && fileUpload.enabled && showCameraOption\"\n ref=\"cameraInputEl\"\n type=\"file\"\n capture=\"environment\"\n hidden\n :accept=\"acceptImageMimeTypes\"\n @change=\"onFileChange\" />\n <div class=\"pk-chatbot-input__content\">\n <textarea\n ref=\"textareaEl\"\n :value=\"localValue\"\n class=\"pk-chatbot-input__textarea\"\n name=\"message\"\n rows=\"1\"\n enterkeyhint=\"send\"\n :aria-label=\"$t('label.message')\"\n :aria-describedby=\"\n maxMessageLength ? counterId : undefined\n \"\n :aria-invalid=\"isOverLimit || undefined\"\n :placeholder\n @input=\"onTextareaInput\"\n @keydown.enter=\"onTextareaEnter\"></textarea>\n </div>\n <div\n v-if=\"maxMessageLength\"\n :id=\"counterId\"\n class=\"pk-chatbot-input__counter\"\n :class=\"{ 'pk-chatbot-input__counter--over': isOverLimit }\">\n {{ $n(currentLength, 'integer') }}/<span\n class=\"opacity-60\"\n >{{ $n(maxMessageLength, 'integer') }}</span\n >\n </div>\n <PkChatButton\n v-if=\"voiceEnabled && !isStreaming\"\n icon=\"ri:mic-line\"\n :title=\"$t('action.talk')\"\n :disabled=\"isInputDisabled\"\n @click=\"emit('voice-start')\" />\n <PkChatButton\n v-if=\"isStreaming\"\n icon=\"ri:stop-fill\"\n modifiers=\"primary\"\n :title=\"$t('action.stop')\"\n @click=\"stopGeneration\" />\n <PkChatButton\n v-else\n type=\"submit\"\n modifiers=\"primary\"\n :icon=\"isSubmitted ? 'loading-loop' : 'ri:arrow-up-line'\"\n :title=\"$t('action.submit')\"\n :disabled=\"!isSubmitEnabled\" />\n </div>\n </form>\n </div>\n</template>\n\n<style lang=\"scss\">\n .pk-chatbot-input {\n position: relative;\n display: flex;\n flex-direction: column;\n margin-inline: var(--spacing-sm);\n margin-bottom: var(--spacing-sm);\n\n &__notice {\n position: relative;\n padding: var(--spacing-10) var(--spacing-sm);\n display: flex;\n align-items: flex-start;\n gap: var(--spacing-sm);\n background-color: var(--color-surface-1);\n border-top-left-radius: var(--rounded-xl);\n border-top-right-radius: var(--rounded-xl);\n transition-property: var(--transition-property-all);\n transition-duration: var(--duration-300);\n transition-timing-function: var(--ease-in-out);\n font-size: var(--text-12);\n color: var(--color-word-4);\n\n &::after {\n content: '';\n display: block;\n position: absolute;\n left: 0;\n right: 0;\n bottom: calc(-1 * var(--spacing-12));\n height: var(--spacing-12);\n background-color: var(--color-surface-1);\n z-index: 1;\n }\n\n &-icon {\n flex-shrink: 0;\n width: var(--spacing-18);\n height: var(--spacing-18);\n }\n\n &-text {\n flex: 1;\n min-width: 0;\n }\n }\n\n &__form {\n position: relative;\n display: flex;\n z-index: 1;\n flex-direction: column;\n\n // The composer is a field too: same border and focus ring as the\n // form fields, on top of the shadow and the 12px radius that make\n // it the container (12) of its 8px buttons\n border-radius: var(--rounded-xl);\n border: 1px solid var(--input-border-color);\n background-color: var(--color-surface);\n padding: var(--spacing-14);\n box-shadow: var(--shadow-lg);\n font-size: var(\n --text-16\n ); // prevent ios zoom on input focus by using a font size >= 16px\n gap: var(--spacing-xs);\n transition: var(--input-transition);\n\n @include media-breakpoint-up('sm', $breakpoints) {\n font-size: var(--text-14);\n padding: var(--spacing-10);\n }\n\n &:has(:focus-within) {\n border-color: var(--input-focus-color);\n box-shadow: var(--shadow-lg), var(--input-focus-ring);\n }\n }\n\n &__drop-overlay {\n position: absolute;\n inset: 0;\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-xs);\n border-radius: var(--rounded-xl);\n background-color: color-mix(\n in srgb,\n var(--color-surface) 85%,\n transparent\n );\n pointer-events: none;\n }\n\n &__fieldset {\n display: flex;\n align-items: center;\n gap: var(--spacing-xs);\n flex: 1;\n\n // The buttons answer 8px around themselves on a touch screen\n // (PkChatButton): 12px apart, neither takes the other's box\n @media (pointer: coarse) {\n gap: var(--spacing-12);\n }\n }\n\n &__content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: var(--spacing-4);\n min-width: 0;\n overflow: hidden;\n }\n\n &__textarea {\n display: block;\n border: none;\n outline: none;\n resize: none;\n width: 100%;\n max-height: 200px;\n color: var(--color-word-1);\n background-color: var(--color-surface);\n\n &::placeholder {\n color: var(--color-word-4);\n }\n }\n\n &__attachments {\n display: flex;\n flex-wrap: wrap;\n // Roomy gap so the uniform-height chips breathe in the row.\n gap: var(--spacing-12);\n padding-bottom: var(--spacing-xs);\n border-bottom: 1px solid var(--color-surface-2);\n }\n\n &__counter {\n background-color: var(--color-surface-1);\n border: 1px solid var(--color-surface-3);\n border-radius: var(--rounded-md);\n font-size: var(--text-12);\n color: var(--color-word-3);\n line-height: 1;\n padding-inline: var(--spacing-6);\n padding-block: var(--spacing-4);\n z-index: 1;\n font-variant-numeric: tabular-nums;\n font-family: var(--font-mono);\n font-weight: var(--font-bold);\n\n &--over {\n color: var(--u-danger-text, var(--color-danger));\n border-color: var(--color-danger-lighten-5);\n font-weight: var(--font-bold);\n }\n }\n }\n</style>\n"],"ignoreList":[0],"mappings":";;;;;;AAAA,IAAIyC,oBAAE,IAAI,IAAE;AAAE,SAASC,EAAE,GAAE;CAAC,IAAIC,IAAEF,EAAE,IAAIC,CAAC;CAAE,KAAGC,EAAE,QAAQ;AAAC;AAAC,SAASA,EAAE,GAAE;CAAC,IAAIA,IAAEF,EAAE,IAAIC,CAAC;CAAE,KAAGC,EAAE,OAAO;AAAC;AAAC,IAAIC,IAAE;AAAkB,OAAO,SAApB,OAA4B,CAAC,IAAE,SAAS,GAAE;CAAC,OAAO;AAAC,EAAA,CAAG,UAAQ,SAAS,GAAE;CAAC,OAAO;AAAC,GAAE,EAAE,SAAO,SAAS,GAAE;CAAC,OAAO;AAAC,MAAI,CAAC,IAAE,SAAS,GAAE,GAAE;CAAC,OAAOF,KAAG,MAAM,UAAU,QAAQ,KAAKA,EAAE,SAAOA,IAAE,CAACA,CAAC,GAAE,SAAS,GAAE;EAAC,OAAO,SAAS,GAAE;GAAC,IAAGA,KAAGA,EAAE,YAAuBA,EAAE,aAAf,cAAyB,CAACD,EAAE,IAAIC,CAAC,GAAE;IAAC,IAAIC,GAAEC,IAAE,MAAKC,IAAE,OAAO,iBAAiBH,CAAC,GAAE,KAAG,IAAEA,EAAE,OAAM,WAAU;KAAC,EAAE;MAAC,wBAA4BC,MAAL,MAAQ,CAACD,EAAE,MAAM,WAAWC,CAAC;MAAE,kBAAiB;KAAI,CAAC,GAAE,IAAED,EAAE;IAAK,IAAGI,IAAE,SAAS,GAAE;KAAC,EAAE,oBAAoB,oBAAmBA,CAAC,GAAEJ,EAAE,oBAAoB,mBAAkB,CAAC,GAAEA,EAAE,oBAAoB,SAAQ,CAAC,GAAE,OAAO,oBAAoB,UAAS,CAAC,GAAE,OAAO,KAAKC,CAAC,CAAC,CAAC,QAAQ,SAAS,GAAE;MAAC,OAAO,EAAE,MAAMF,KAAGE,EAAEF;KAAE,CAAC,GAAEA,EAAE,OAAOC,CAAC;IAAC,EAAE,KAAKA,GAAE;KAAC,QAAOA,EAAE,MAAM;KAAO,QAAOA,EAAE,MAAM;KAAO,WAAUA,EAAE,MAAM;KAAU,WAAUA,EAAE,MAAM;KAAU,WAAUA,EAAE,MAAM;KAAU,UAASA,EAAE,MAAM;IAAQ,CAAC;IAAE,EAAE,iBAAiB,oBAAmBI,CAAC,GAAEJ,EAAE,iBAAiB,mBAAkB,CAAC,GAAEA,EAAE,iBAAiB,SAAQ,CAAC,GAAE,OAAO,iBAAiB,UAAS,CAAC,GAAE,EAAE,MAAM,YAAU,UAAS,EAAE,MAAM,WAAS,cAAaD,EAAE,IAAIC,GAAE;KAAC,SAAQI;KAAE,QAAO;IAAC,CAAC,GAAE,EAAE;GAAC;GAAC,SAASC,EAAE,GAAE;IAAC,IAAIJ,GAAEK,GAAEF,IAAEL,EAAE,kBAAiBQ,IAAWH,MAAT,KAAK,IAAM,OAAKA,GAAEI,IAAET,EAAE,wBAAuB,IAAWS,MAAT,KAAK,KAAOA,GAAEC,IAAEN,EAAE;IAAU,IAAOH,EAAE,iBAAN,MAAkCG,EAAE,WAAf,aAAsB,EAAE,MAAM,SAAO,SAAgBA,EAAE,WAAX,WAAoB,EAAE,MAAM,SAAO,eAAc,MAAI,IAAE,SAAS,GAAE;KAAC,KAAI,IAAI,IAAE,CAAC,GAAE,KAAG,EAAE,cAAY,EAAE,sBAAsB,UAAS,EAAE,WAAW,aAAW,EAAE,KAAK,CAAC,EAAE,YAAW,EAAE,WAAW,SAAS,CAAC,GAAE,IAAE,EAAE;KAAW,OAAO,WAAU;MAAC,OAAO,EAAE,QAAQ,SAAS,GAAE;OAAC,IAAI,IAAE,EAAE,IAAGF,IAAE,EAAE;OAAG,EAAE,MAAM,iBAAe,QAAO,EAAE,YAAUA,GAAE,EAAE,MAAM,iBAAe;MAAI,CAAC;KAAC;IAAC,EAAED,CAAC,GAAE,EAAE,MAAM,SAAO,KAAI,IAAkBG,EAAE,cAAlB,gBAA4BH,EAAE,gBAAc,WAAWG,EAAE,UAAU,IAAE,WAAWA,EAAE,aAAa,KAAGH,EAAE,eAAa,WAAWG,EAAE,cAAc,IAAE,WAAWA,EAAE,iBAAiB,GAAWA,EAAE,cAAX,UAAsBG,IAAE,WAAWH,EAAE,SAAS,KAAcA,EAAE,cAAb,aAAyB,EAAE,MAAM,WAAS,WAAU,IAAE,WAAWA,EAAE,SAAS,KAAcA,EAAE,cAAb,aAAyB,EAAE,MAAM,WAAS,WAAU,EAAE,MAAM,SAAOG,IAAE,MAAKC,MAAI,EAAE,MAAM,YAAUA,IAAGN,KAAGA,EAAE,GAAEC,MAAII,MAAIN,EAAE,cAAc,IAAI,MAAM,oBAAmB,EAAC,SAAQ,CAAC,EAAC,CAAC,CAAC,GAAE,IAAEM,IAAGG,MAAIN,EAAE,YAAU,CAACI,IAAG;KAAC,IAAIG,IAAEP,EAAE;KAAU,AAAWA,EAAE,aAAb,aAAwB,EAAE,MAAM,YAAoBO,MAAV,UAAY,QAAM,UAASL,EAAE;MAAC,kBAAiBK;MAAE,wBAAuB,CAAC;KAAC,CAAC;IAAC;GAAC;GAAC,SAAS,IAAG;IAAC,EAAE;KAAC,wBAAuB,CAAC;KAAE,kBAAiB;IAAI,CAAC;GAAC;EAAC,EAAEV,CAAC;CAAC,CAAC,GAAEA;AAAC,EAAA,CAAG,UAAQ,SAAS,GAAE;CAAC,OAAO,KAAG,MAAM,UAAU,QAAQ,KAAK,EAAE,SAAO,IAAE,CAAC,CAAC,GAAEA,CAAC,GAAE;AAAC,GAAE,EAAE,SAAO,SAAS,GAAE;CAAC,OAAO,KAAG,MAAM,UAAU,QAAQ,KAAK,EAAE,SAAO,IAAE,CAAC,CAAC,GAAEC,CAAC,GAAE;AAAC;AAAG,IAAIE,IAAED;;;;;;;;;;;;;;GCwBjlF,OAAAzC,EAAA,GAAAC,EASS,UAAA;IARL,OAAKC,EAAA,CAAC,kBAAgB,CACAyD,EAAA,YAAS,mBAAsBA,EAAA,cAAc,KAAA,GAAqD,EAAA,4BAAAA,EAAA,MAAK,CAAA,CAAA,CAAA;IAI5H,MAAMA,EAAA;GACPxD,GAAAA,CAAAA,EAAoDmD,GAAA;IAA3C,MAAMK,EAAA;IAAM,OAAM;GACf,GAAA,MAAA,GAAA,CAAA,MAAA,CAAA,GAAAA,EAAA,SAAZ3D,EAAA,GAAAC,EAAmE,QAAnEH,GAAmEM,EAAfuD,EAAA,KAAK,GAAA,CAAA,KAAAG,EAAA,IAAA,EAAA,CAAA,GAAA,IAAAZ,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EEV7D,IAAM+B,IAAavE,EAA+BiD,GAAA,YAAuB,GACnEwB,IAAqBzE,EACxBiD,GAAC,oBAEJ,GAEMyB,IAAOJ,GAQPK,IAAQ1B,GAeR2B,IAAaC,EAAoC,YAAY,GAC7DC,IAAcD,EAAiC,aAAa,GAC5DE,IAAgBF,EAAiC,eAAe,GAChEG,IAASH,EAAgC,QAAQ,GAIjDI,IAAaC,EAAIX,EAAW,SAAS,EAAE,GACzCY,IAAkD,MAEhDC,UAAmB;GACrB,AAAID,MAAc,SACd,aAAaA,CAAS,GACtB,IAAY;EAEpB,GAEME,WAAkB;GAEpB,AADAD,EAAW,GACX,EAAW,QAAQH,EAAW;EAClC,GAEMK,WAAqB;GAEvB,AADAF,EAAW,GACX,IAAY,iBAAiB;IAEzB,AADA,EAAW,QAAQH,EAAW,OAC9B,IAAY;GAChB,GAAG,GAAG;EACV,GAEMM,WAAwB;GAE1B,AADA,EAAW,QAAQX,EAAW,OAAO,SAAS,IAC9CU,GAAa;EACjB;EAEA,GAAMf,IAAa,MAAM;GACrB,AAAIhC,MAAM0C,EAAW,UACjB,EAAW,QAAQ1C,KAAK,IACxBiD,QAAe;IACX,AAAIZ,EAAW,SACX5C,EAAS,OAAO4C,EAAW,KAAK;GAExC,CAAC;EAET,CAAC;EAID,IAAMa,IAAcC,QAAef,EAAM,WAAW,WAAW,GACzDgB,IAAcD,QAAef,EAAM,WAAW,WAAW,GACzDiB,IAAkBF,QACdD,EAAY,SAASE,EAAY,KAC3C,GAIME,IAAYC,GAAM,GAClBC,IAAgBL,QAAeT,EAAW,MAAM,MAAM,GAEtDe,IAAcN,QAEZf,EAAM,qBAAqB,KAAA,KAC3BoB,EAAc,QAAQpB,EAAM,gBACpC,GAEMsB,KAAqBP,QACvBjB,EAAmB,MAAM,MAAM,MAAMvC,EAAE,UAAU,WAAW,CAChE,GAEMgE,IAAkBR,QAEhBE,EAAgB,SAChBK,GAAmB,SACnBD,EAAY,QAEL,KAEJf,EAAW,MAAM,KAAK,CAAC,CAAC,SAAS,CAC3C,GAIKkB,KAAoB,aAAa,SAAS,cAAc,OAAO,GAE/DC,KAAkBV,QACdf,EAAM,YAAY,kBAAkB,KAAK,GAAG,KAAK,EAC3D,GAEM0B,IAAuBX,SACxBf,EAAM,YAAY,oBAAoB,CAAC,EAAA,CACnC,QAAQ,MAAM2B,EAAE,WAAW,QAAQ,CAAC,CAAA,CACpC,KAAK,GAAG,CACjB,GAEMC,IAAmBb,QACfS,MAAqBE,EAAqB,MAAM,SAAS,CACnE,GAEMG,UAAuB;GACzB,EAAY,OAAO,MAAM;EAC7B,GAEMC,WAAyB;GAC3B,EAAc,OAAO,MAAM;EAC/B,GAIMC,KAAa,MAAkB;GACjC,KAAK,IAAMC,KAAQC,GACf,EAAK,eAAeD,CAAI;EAEhC,GAEME,MAAgB,MAAiB;GACnC,IAAMC,IAAQC,EAAM;GAEpB,AADAL,EAAU,MAAM,KAAKI,EAAM,SAAS,CAAC,CAAC,CAAC,GACvC,EAAM,QAAQ;EAClB,GAIME,MAAoB,MAAe;GACrC,IAAMC,IAAMxC,EAAmB,MAAM,MAAM,MAAMvC,EAAE,OAAOgF,CAAE;GAI5D,AAHID,KACA,IAAI,gBAAgBA,EAAI,QAAQ,GAEpC,EAAmB,QAAQxC,EAAmB,MAAM,QAC/C,MAAMvC,EAAE,OAAOgF,CACpB;EACJ,GAIMC,KAAoBzB,SACff,EAAM,kBAAkB,OAAS,CAAC,CAACA,EAAM,YAAY,OAChE,GASM,EAAE,uBAAmByC,GAAYpC,GAAQ;GAC3C,WAAWU,QAAef,EAAM,YAAY,oBAAoB,CAAC,CAAC;GAClE,SATgB,MAAyB;IACzC,AAAKwC,GAAkB,SAAUP,KAGjCF,EAAUE,CAAK;GACnB;EAKA,CAAC,GAYKS,KAA6BnC,EAAI,EAAI,GACrCoC,WAA+B;GACjC,GAA2B,QAAQ;EACvC,GAEMC,IAAe7B,QAEbf,EAAM,mBACC;GACH,IAAI;GACJ,MAAM;GACN,MAAMA,EAAM;GACZ,eAAeD,EAAK,2BAA2B;EACnD,IAEAC,EAAM,qBAAqB0C,GAA2B,QAC/C;GACH,IAAI;GACJ,UAAU1C,EAAM;GAChB,SAAS2C;EACb,IAEG,IACV,GAWKE,WAA0B;GAC5B,AAAIxC,EAAO,OAAO,cAAc,sBAAsB,KAClDJ,EAAW,OAAO,MAAM;EAEhC,GAEM6C,WAAuB;GAEzB,AADAD,GAAkB,GAClB9C,EAAK,iBAAiB;EAC1B,GAEMgD,WAAqB;GACvB,AAAKxB,EAAgB,UAGrBsB,GAAkB,GAClBnC,GAAU,GACVX,EAAK,QAAQ,GACb,EAAW,QAAQ,IACnB,EAAW,QAAQ,IACnBc,QAAe;IACX,AAAIZ,EAAW,UACX,EAAW,MAAM,QAAQ,IACzB5C,EAAS,OAAO4C,EAAW,KAAK;GAExC,CAAC;EACL,GAOM+C,MAAmB,MAAyB;GAC9C,AAAIZ,EAAM,YAAYA,EAAM,eAAeA,EAAM,YAAY,QAG7DA,EAAM,eAAe,GACrBW,GAAa;EACjB;SAIAE,QAAgB;GACZ,AAAIhD,EAAW,SACX5C,EAAS4C,EAAW,KAAK;EAEjC,CAAC,GAEDiD,QAAsB;GAElB,AADAzC,EAAW,GACPR,EAAW,SACX5C,EAAS,QAAQ4C,EAAW,KAAK;GAErC,KAAK,IAAMqC,KAAOxC,EAAmB,OACjC,IAAI,gBAAgBwC,EAAI,QAAQ;EAExC,CAAC;;GAID,OAAA5G,EAAA,GAAAC,EAmLM,OAnLN+C,IAmLM,CAjLQkE,EAAA,SADVlH,EAAA,GAAAC,EAuBM,OAAA;IArBD,KAAKiH,EAAA,MAAa;IACnB,OAAM;IACN,MAAK;;IAEKA,EAAA,MAAa,QADvBlH,EAAA,GAAAE,EAG4CqC,GAAA;;KADvC,MAAM2E,EAAA,MAAa;KACpB,OAAM;;IAEAA,EAAA,MAAa,YADvBlH,EAAA,GAAAE,EAGoDE,GAAA;;KAD/C,UAAU8G,EAAA,MAAa;KACxB,OAAM;IACVlH,GAAAA,MAAAA,GAAAA,CAAAA,UAAAA,CAAAA,MAAAA,EAAA,GAAAC,EAEO,QAFPgD,IAEO5C,EADA6G,EAAA,MAAa,IAAI,GAAA,CAAA;IAGdA,EAAA,MAAa,WADvBlH,EAAA,GAAAE,EAMsCuH,GAAA;;KAJjC,OAAOjI,EAAAA,GAAE,cAAA;KACV,WAAU;KACV,MAAK;KACL,OAAM;KACL,SAAK,AAAAyI,EAAA,QAAA,MAAEf,EAAA,MAAa,QAAO;;GAEpC5G,CAAAA,KAAAA,EAAAA,IAAAA,EAAAA,GAAAA,EAyJO,QAAA;IAxJC,SAAA;IAAJ,KAAIqE;IACJ,OAAM;IACL,UAAMpE,GAAU8G,IAAY,CAAA,SAAA,CAAA;;IAEnB7G,EAAA6H,EAAA,KAAkBvB,GAAA,SAD5B9G,EAAA,GAAAC,EAOM,OAPNiD,IAOM,CAJFzC,EAEkD8B,GAAA;KAD9C,MAAK;KACL,OAAM;IACVjC,CAAAA,GAAAA,EAAwC,QAAA,MAAAD,EAA/Bb,EAAAA,GAAE,iBAAA,CAAA,GAAA,CAAA,CAAA,CAAA,KAAAuD,EAAA,IAAA,EAAA;IAGLqB,EAAA,MAAmB,UAD7BpE,EAAA,GAAAC,EAeM,OAfNkD,IAeM,EAZFnD,EAAA,EAAA,GAAAC,EAWyCS,GAAA,MAAAC,GAVvByD,EAAA,QAAP,OADXpE,EAAA,GAAAE,EAWyCU,GAAA;KATpC,KAAKgG,EAAI;KACT,cAAYA,EAAI,KAAK;KACrB,KAAKA,EAAI;KACT,UAAUA,EAAI,KAAK;KACnB,MAAMA,EAAI,KAAK;KACf,SAASA,EAAI,UAAK;KAClB,OAAOA,EAAI,UAAK,UAAeA,EAAI,QAAQ,KAAA;KAC3C,WAAWA,EAAI,UAAK;KACrB,SAAA;KACC,WAAM,MAAED,GAAiBC,EAAI,EAAE;;;;;;;;;;;IAExCtG,EA4HM,OA5HN8C,IA4HM;KA3HFvC,EAAuBmH,EAAA,QAAA,SAAA;KAEYpF,EAAA,cAAsCA,EAAA,WAAW,YAAoCsD,EAAA,SAAoBzG,EAAAA,OAAM,0BADlJO,EAAA,GAAAE,EAqDa2H,GAAA/G,GAAAC,EAAA,EAAA,KAAA,EAAA,GA/CD;;;;;KAKP,CAAA,CAAA,GAAA;MACU,SAAOC,GAeL,EAfS,SAAM,WAAQ,cAAI,CAIpCV,EAWS,UAXTS,EAWS,EAVJ,MAAM,MAAW8H,EAAKtH,CAAC,EAChB,GAAAuH,GAAI;OACZ,OAAM;OACN,MAAK;OACJ,OAAOtJ,EAAAA,GAAE,mBAAA;OACT,UAAU+F,EAAA;OACV,SAAOwD;MACRtI,CAAAA,GAAAA,CAAAA,EAEmC8B,GAAA;OAD/B,MAAK;OACL,OAAM;;MAGP,OAAKvB,QAWO;OATTkF,EAAA,SADVlG,EAAA,GAAAE,EAUmByH,GAAA;;QARd,UAA2CpC,EAAA,SAAmB3C,EAAA;QAG9D,SAAOwD;;QACR,SAAApF,QAE8C,CAF9CP,EAE8C8B,GAAA;SAD1C,MAAK;SACL,OAAM;QAAoCtB,CAAAA,GAAAA,EAAA,MAC9CZ,EAAGb,EAAAA,GAAE,kBAAA,CAAA,GAAA,CAAA,CAAA,CAAA;;;OAETiB,EASmBkH,GAAA;QARd,UAA2CpC,EAAA,SAAmB3C,EAAA;QAG9D,SAAOuD;;QACR,SAAAnF,QAE8C,CAF9CP,EAE8C8B,GAAA;SAD1C,MAAK;SACL,OAAM;QAAoCtB,CAAAA,GAAAA,EAAA,MAC9CZ,EAAGb,EAAAA,GAAE,mBAAA,CAAA,GAAA,CAAA,CAAA,CAAA;;;OAETqB,EAAkCmH,EAAA,QAAA,oBAAA;;;KAI3B,GAAA,EAAA,KAAApF,EAAA,cAAcA,EAAA,WAAW,WADxC5C,EAAA,GAAAE,EAK8BgB,GAAA;;MAH1B,MAAK;MACJ,OAAO1B,EAAAA,GAAE,mBAAA;MACT,UAAU+F,EAAA,SAAmB3C,EAAA;MAC7B,SAAOuD;;KAEFvD,EAAA,cAAcA,EAAA,WAAW,WADnC5C,EAAA,GAAAC,EAO6B,SAAA;;MALrB,SAAA;MAAJ,KAAIwE;MACJ,MAAK;MACL,QAAA;MACA,UAAA;MACC,QAAQsB,GAAA;MACR,UAAQS;;KAEH5D,EAAA,cAAcA,EAAA,WAAW,WAAWsD,EAAA,SAD9ClG,EAAA,GAAAC,EAO6B,SAAA;;MALrB,SAAA;MAAJ,KAAIyE;MACJ,MAAK;MACL,SAAQ;MACR,QAAA;MACC,QAAQsB,EAAA;MACR,UAAQQ;;KACblG,EAgBM,OAhBNkD,IAgBM,CAfFlD,EAcgD,YAAA;MAbxC,SAAA;MAAJ,KAAIiE;MACH,OAAOK,EAAA;MACR,OAAM;MACN,MAAK;MACL,MAAK;MACL,cAAa;MACZ,cAAYpF,EAAAA,GAAE,eAAA;MACd,oBAA+CoD,EAAA,mBAAmBpC,EAAAgF,CAAA,IAAY,KAAA;MAG9E,gBAAcG,EAAA,SAAe,KAAA;MAC7B,aAAA/C,EAAA;MACA,SAAOsC;MACP,WAAO/D,GAAQmG,IAAe,CAAA,OAAA,CAAA;;KAG7B1E,EAAA,oBADV5C,EAAA,GAAAC,EASM,OAAA;;MAPD,IAAIO,EAAAgF,CAAA;MACL,OAAKpE,EAAA,CAAC,6BAA2B,EAAA,mCACYuE,EAAA,MAAW,CAAA,CAAA;KACrDjG,GAAAA,CAAAA,EAAAA,EAAAA,EAAAA,GAAGgG,EAAA,OAAa,SAAA,CAAA,IAAe,KAAC,CAAA,GAAApF,EAGlC,QAHkCqD,IAGlCtD,EADOX,EAAAA,GAAGkD,EAAA,kBAAgB,SAAA,CAAA,GAAA,CAAA,CAAA,GAAA,IAAAc,EAAA,KAAAX,EAAA,IAAA,EAAA;KAIrBH,EAAA,gBAAY,CAAKwC,EAAA,SAD3BpF,EAAA,GAAAE,EAKmCgB,GAAA;;MAH/B,MAAK;MACJ,OAAO1B,EAAAA,GAAE,aAAA;MACT,UAAU+F,EAAA;MACV,SAAK,AAAA0C,EAAA,QAAA,MAAE5D,EAAI,aAAA;;KAENe,EAAA,SADVpF,EAAA,GAAAE,EAK8BgB,GAAA;;MAH1B,MAAK;MACL,WAAU;MACT,OAAO1B,EAAAA,GAAE,aAAA;MACT,SAAO4H;KACZpH,GAAAA,MAAAA,GAAAA,CAAAA,OAAAA,CAAAA,MAAAA,EAAA,GAAAE,EAMmCgB,GAAA;;MAJ/B,MAAK;MACL,WAAU;MACT,MAAMoE,EAAA,QAAW,iBAAA;MACjB,OAAO9F,EAAAA,GAAE,eAAA;MACT,UAAQ,CAAGqG,EAAA"}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { A as e, E as t, S as n, n as r, v as i } from "./schemas-Bu1lick6.js";
|
|
2
2
|
import { a } from "./Media-C6RS-s98.js";
|
|
3
3
|
import { S as o, j as s, n as c, x as l } from "./Agent-dGF8mkG9.js";
|
|
4
|
-
import { t as u } from "./PkStreamingMarkdown-
|
|
4
|
+
import { t as u } from "./PkStreamingMarkdown-C55Fi0Pd.js";
|
|
5
5
|
import "./src-DCfvejyT.js";
|
|
6
6
|
import { c as d, i as f, l as p, n as m, o as h, s as g, t as _ } from "./message-BOiF6Bt5.js";
|
|
7
7
|
import { t as ee } from "./PkChatbotAudioTranscript-BUxBHanA.js";
|
|
8
8
|
import { t as v } from "./PkChatbotError-CRGbK09-.js";
|
|
9
9
|
import { t as te } from "./PkRelativeTime--1cIphlA.js";
|
|
10
|
-
import { C as y, S as ne, T as re, a as ie, f as b, h as x, m as ae, n as oe, o as se, p as ce, t as S, u as le, w as ue, x as de, y as fe } from "./utils-
|
|
10
|
+
import { C as y, S as ne, T as re, a as ie, f as b, h as x, m as ae, n as oe, o as se, p as ce, t as S, u as le, w as ue, x as de, y as fe } from "./utils-CwIMEuAv.js";
|
|
11
11
|
import { t as pe } from "./PkChatbotFilePreview-DIP8KLkS.js";
|
|
12
12
|
import { t as me } from "./PkChatbotFeedbackForm-CMFXjoKR.js";
|
|
13
13
|
import { t as he } from "./PkChatbotMessageFeedback-BYmrVaCE.js";
|
|
14
|
-
import { n as ge, t as _e } from "./PkChatbotSteps-
|
|
14
|
+
import { n as ge, t as _e } from "./PkChatbotSteps-DeZQhGRU.js";
|
|
15
15
|
import { t as ve } from "./PkChatbotOutlineRail-np4g6vsz.js";
|
|
16
16
|
import { VvButton as ye, VvButtonGroup as be, VvIcon as xe } from "@volverjs/ui-vue/components";
|
|
17
17
|
import { Fragment as C, Transition as w, computed as T, createBlock as E, createCommentVNode as D, createElementBlock as O, createElementVNode as k, createTextVNode as Se, createVNode as A, defineAsyncComponent as j, defineComponent as Ce, mergeProps as we, nextTick as M, normalizeClass as N, normalizeStyle as Te, onBeforeUnmount as Ee, onMounted as De, openBlock as P, ref as F, renderList as Oe, renderSlot as ke, resolveDynamicComponent as Ae, toDisplayString as I, unref as L, useSlots as je, useTemplateRef as Me, watch as R, withCtx as z, withModifiers as B } from "vue";
|
|
@@ -54,24 +54,24 @@ var H = (e) => e.state, Re = (e) => e.type.startsWith("tool-") ? e.type.slice(5)
|
|
|
54
54
|
return t;
|
|
55
55
|
}, Ve = (e) => e.normalize("NFD").replace(/[\u0300-\u036f]/g, ""), He = (e) => e ? e.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/[-_]+/g, " ") : "", Ue = (e) => e ? Ve(e).replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[^a-zA-Z0-9]+/g, "-").toLowerCase() : "", U = (e) => e ? Ve(e).replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-zA-Z0-9]+/g, "_").toLowerCase() : "", W = (e) => e ? e.charAt(0).toUpperCase() + e.slice(1) : "", We = {
|
|
56
56
|
requestOAuthConnection: j(() => import("./PkToolRequestOAuthConnection-GfSalEJG.js")),
|
|
57
|
-
showArtifact: j(() => import("./PkToolShowArtifact-
|
|
57
|
+
showArtifact: j(() => import("./PkToolShowArtifact-z1qTnFkA.js").then((e) => e.n)),
|
|
58
58
|
showCalendarEvent: j(() => import("./PkToolShowCalendarEvent-Dv_rss26.js").then((e) => e.n)),
|
|
59
59
|
showComparison: j(() => import("./PkToolShowComparison-DQs3E6-k.js").then((e) => e.n)),
|
|
60
|
-
showContactForm: j(() => import("./PkToolShowContactForm-
|
|
61
|
-
showDiagram: j(() => import("./PkToolShowDiagram-
|
|
60
|
+
showContactForm: j(() => import("./PkToolShowContactForm-Y0lrHXhr.js").then((e) => e.n)),
|
|
61
|
+
showDiagram: j(() => import("./PkToolShowDiagram-BJ_ryTsD.js")),
|
|
62
62
|
showEmail: j(() => import("./PkToolShowEmail-C591LR5N.js").then((e) => e.n)),
|
|
63
|
-
showImageGallery: j(() => import("./PkToolShowImageGallery-
|
|
63
|
+
showImageGallery: j(() => import("./PkToolShowImageGallery-CkfXP_lD.js").then((e) => e.n)),
|
|
64
64
|
showLocation: j(() => import("./PkToolShowLocation-Dyz6h_0n.js").then((e) => e.n)),
|
|
65
65
|
showMessage: j(() => import("./PkToolShowMessage-CbXERPHI.js").then((e) => e.n)),
|
|
66
|
-
showForm: j(() => import("./PkToolShowForm-
|
|
67
|
-
showMultipleChoice: j(() => import("./PkToolShowForm-
|
|
68
|
-
showProductList: j(() => import("./PkToolShowProductList-
|
|
66
|
+
showForm: j(() => import("./PkToolShowForm-CZFWZub7.js").then((e) => e.n)),
|
|
67
|
+
showMultipleChoice: j(() => import("./PkToolShowForm-CZFWZub7.js").then((e) => e.n)),
|
|
68
|
+
showProductList: j(() => import("./PkToolShowProductList-De-PtmD-.js").then((e) => e.n)),
|
|
69
69
|
showQrCode: j(() => import("./PkToolShowQrCode-DEAvfLFu.js").then((e) => e.n)),
|
|
70
|
-
showSources: j(() => import("./PkToolShowSources-
|
|
70
|
+
showSources: j(() => import("./PkToolShowSources-CSN7S0zo.js").then((e) => e.n)),
|
|
71
71
|
showSuggestedReply: j(() => import("./PkToolShowSuggestedReply-DjutyiEi.js").then((e) => e.n)),
|
|
72
|
-
showVideo: j(() => import("./PkToolShowVideo-
|
|
72
|
+
showVideo: j(() => import("./PkToolShowVideo-B_Q93E2y.js")),
|
|
73
73
|
showWeather: j(() => import("./PkToolShowWeather-BH-FtLpk.js")),
|
|
74
|
-
showWebPages: j(() => import("./PkToolShowWebPages-
|
|
74
|
+
showWebPages: j(() => import("./PkToolShowWebPages-D3CdjJUc.js").then((e) => e.n))
|
|
75
75
|
}, Ge = {
|
|
76
76
|
key: 0,
|
|
77
77
|
class: "text-12 text-word-3 m-0 mb-xs"
|
|
@@ -866,4 +866,4 @@ var Ze = ["aria-busy"], Qe = {
|
|
|
866
866
|
//#endregion
|
|
867
867
|
export { U as a, Ue as i, W as n, He as r, J as t };
|
|
868
868
|
|
|
869
|
-
//# sourceMappingURL=PkChatbotMessages-
|
|
869
|
+
//# sourceMappingURL=PkChatbotMessages-D9uf0NMI.js.map
|