@meistrari/chat-nuxt 4.4.0-rc.8 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +5 -0
  3. package/dist/runtime/conversations/components/chat-conversation-item.vue +50 -69
  4. package/dist/runtime/conversations/components/chat-conversation-list.vue +84 -61
  5. package/dist/runtime/conversations/composables/conversation-item.js +4 -0
  6. package/dist/runtime/conversations/composables/conversation-list.d.ts +2 -0
  7. package/dist/runtime/conversations/composables/conversation-list.js +33 -4
  8. package/dist/runtime/embed/components/chat-embed-inner.d.vue.ts +6 -2
  9. package/dist/runtime/embed/components/chat-embed-inner.vue +13 -2
  10. package/dist/runtime/embed/components/chat-embed-inner.vue.d.ts +6 -2
  11. package/dist/runtime/embed/components/chat-embed.d.vue.ts +4 -2
  12. package/dist/runtime/embed/components/chat-embed.vue +3 -0
  13. package/dist/runtime/embed/components/chat-embed.vue.d.ts +4 -2
  14. package/dist/runtime/embed/components/chat-topbar.d.vue.ts +11 -1
  15. package/dist/runtime/embed/components/chat-topbar.vue +7 -8
  16. package/dist/runtime/embed/components/chat-topbar.vue.d.ts +11 -1
  17. package/dist/runtime/embed/components/meistrari-chat-embed.d.vue.ts +2 -0
  18. package/dist/runtime/embed/components/meistrari-chat-embed.vue +3 -0
  19. package/dist/runtime/embed/components/meistrari-chat-embed.vue.d.ts +2 -0
  20. package/dist/runtime/embed/components/mobile/chat-mobile-drawer.vue +0 -1
  21. package/dist/runtime/messages/components/chat-message-input.vue +148 -138
  22. package/dist/runtime/messages/components/chat-message-list.vue +6 -10
  23. package/dist/runtime/messages/components/chat-reasoning-effort-selector.vue +11 -7
  24. package/dist/runtime/messages/components/reasoning/chat-reasoning-thought.vue +1 -1
  25. package/dist/runtime/messages/components/reasoning/chat-thinking-indicator.d.vue.ts +4 -1
  26. package/dist/runtime/messages/components/reasoning/chat-thinking-indicator.vue +15 -3
  27. package/dist/runtime/messages/components/reasoning/chat-thinking-indicator.vue.d.ts +4 -1
  28. package/package.json +2 -2
@@ -14,7 +14,11 @@ type __VLS_Props = {
14
14
  showUsageTab?: boolean;
15
15
  showDebugOption?: boolean;
16
16
  };
17
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
17
+ declare var __VLS_1: {};
18
+ type __VLS_Slots = {} & {
19
+ leading?: (props: typeof __VLS_1) => any;
20
+ };
21
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
18
22
  delete: () => any;
19
23
  rename: () => any;
20
24
  duplicate: () => any;
@@ -39,5 +43,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
39
43
  "onUpdate:editTitle"?: ((value: string) => any) | undefined;
40
44
  "onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
41
45
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
46
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
42
47
  declare const _default: typeof __VLS_export;
43
48
  export default _default;
49
+ type __VLS_WithSlots<T, S> = T & {
50
+ new (): {
51
+ $slots: S;
52
+ };
53
+ };
@@ -21,7 +21,7 @@ const titleInputRef = ref(null);
21
21
  const currentTab = computed(() => props.activeTab ?? "chat");
22
22
  const tabOptions = computed(() => {
23
23
  const options = [
24
- { id: "chat", name: "Chat" },
24
+ { id: "chat", name: "Conversa" },
25
25
  { id: "files", name: "Arquivos", count: props.filesCount }
26
26
  ];
27
27
  if (props.showUsageTab) {
@@ -62,7 +62,7 @@ const headerMenuItems = computed(() => {
62
62
  }
63
63
  items.push({
64
64
  label: "Excluir",
65
- icon: "i-ph-trash",
65
+ icon: "i-ph-trash-bold",
66
66
  color: "negative",
67
67
  click: () => emit("delete")
68
68
  });
@@ -90,13 +90,12 @@ watch(() => props.isEditing, (editing) => {
90
90
  <template>
91
91
  <div
92
92
  flex items-center gap-16px
93
- pl-24px pr-16px h-62px
94
- border-b-0.5px border
95
- bg="white/94"
96
- backdrop-blur-sm
97
- absolute top-0 right-0 z-10
93
+ pl-16px pr-16px h-56px
94
+ absolute top-0 right-0 z-10 class="bg-gradient-to-b from-white to-transparent"
98
95
  :style="{ left: 'var(--chat-panel-offset)' }"
99
96
  >
97
+ <slot name="leading" />
98
+
100
99
  <div flex="~ col 1" gap-1.5px min-w-0>
101
100
  <div
102
101
  v-if="isEditing"
@@ -160,7 +159,7 @@ watch(() => props.isEditing, (editing) => {
160
159
  </div>
161
160
  </div>
162
161
 
163
- <div flex="~" items-center shrink-0>
162
+ <div flex="~" items-center shrink-0 absolute top="50%" left="50%" translate-x="-50%" translate-y="-50%">
164
163
  <div p-4px bg-muted rounded-12px flex="~" items-center>
165
164
  <button
166
165
  v-for="option in tabOptions"
@@ -14,7 +14,11 @@ type __VLS_Props = {
14
14
  showUsageTab?: boolean;
15
15
  showDebugOption?: boolean;
16
16
  };
17
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
17
+ declare var __VLS_1: {};
18
+ type __VLS_Slots = {} & {
19
+ leading?: (props: typeof __VLS_1) => any;
20
+ };
21
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
18
22
  delete: () => any;
19
23
  rename: () => any;
20
24
  duplicate: () => any;
@@ -39,5 +43,11 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
39
43
  "onUpdate:editTitle"?: ((value: string) => any) | undefined;
40
44
  "onUpdate:isEditing"?: ((value: boolean) => any) | undefined;
41
45
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
46
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
42
47
  declare const _default: typeof __VLS_export;
43
48
  export default _default;
49
+ type __VLS_WithSlots<T, S> = T & {
50
+ new (): {
51
+ $slots: S;
52
+ };
53
+ };
@@ -24,6 +24,8 @@ type MeistrariChatEmbedEmits = {
24
24
  type MeistrariChatEmbedSlots = SlotsType<{
25
25
  /** Rendered in a dedicated bottom pane of the conversation sidebar, splitting it in half. Page variant only. */
26
26
  'sidebar-bottom'?: () => any;
27
+ /** Rendered at the start of the conversation topbar, before the title. Page variant only. */
28
+ 'topbar-leading'?: () => any;
27
29
  /** Rendered inside a failed assistant message's error box, next to "Tentar novamente"; receives the failed message. */
28
30
  'failed-message-actions'?: (props: { message: Message }) => any;
29
31
  }>;
@@ -118,6 +118,9 @@ const widgetEmbedProps = computed(() => ({
118
118
  <template v-if="$slots['sidebar-bottom']" #sidebar-bottom>
119
119
  <slot name="sidebar-bottom" />
120
120
  </template>
121
+ <template v-if="$slots['topbar-leading']" #topbar-leading>
122
+ <slot name="topbar-leading" />
123
+ </template>
121
124
  <template v-if="$slots['failed-message-actions']" #failed-message-actions="slotProps">
122
125
  <slot name="failed-message-actions" v-bind="slotProps" />
123
126
  </template>
@@ -24,6 +24,8 @@ type MeistrariChatEmbedEmits = {
24
24
  type MeistrariChatEmbedSlots = SlotsType<{
25
25
  /** Rendered in a dedicated bottom pane of the conversation sidebar, splitting it in half. Page variant only. */
26
26
  'sidebar-bottom'?: () => any;
27
+ /** Rendered at the start of the conversation topbar, before the title. Page variant only. */
28
+ 'topbar-leading'?: () => any;
27
29
  /** Rendered inside a failed assistant message's error box, next to "Tentar novamente"; receives the failed message. */
28
30
  'failed-message-actions'?: (props: { message: Message }) => any;
29
31
  }>;
@@ -283,7 +283,6 @@ async function handleConversationDrop(event, groupId) {
283
283
  <ChatConversationNewGroupButton />
284
284
  </div>
285
285
  <ChatConversationSearch v-model="conversationSearch" />
286
- <ChatConversationCreatorFilter />
287
286
  </div>
288
287
 
289
288
  <div flex-1 overflow-y-auto px-8px pb-8px>
@@ -137,6 +137,11 @@ const submitStatus = computed(() => {
137
137
  const promptShellLocked = computed(
138
138
  () => isLocked.value && submitStatus.value !== "streaming"
139
139
  );
140
+ const showStopRun = computed(() => submitStatus.value === "streaming");
141
+ watch(editorRef, (editor) => {
142
+ if (editor && content.value && !editor.textContent)
143
+ setDraft(content.value);
144
+ });
140
145
  watch(agentInputVariables, (variables) => {
141
146
  const variableNames = new Set(variables.map((input) => input.name));
142
147
  agentInputTexts.value = Object.fromEntries(
@@ -636,152 +641,157 @@ defineExpose({
636
641
  its nearest positioned ancestor; a positioned wrapper here
637
642
  would shrink the input. The dropdown positions itself fixed
638
643
  from the caret rect, so it needs no relative ancestor. -->
639
- <div>
640
- <ChatMentionDropdown
641
- v-if="mentionAutocomplete.isOpen"
642
- :items="mentionAutocomplete.filteredItems"
643
- :commands="mentionAutocomplete.filteredCommands"
644
- :highlighted-index="mentionAutocomplete.highlightedIndex"
645
- :trigger="mentionAutocomplete.activeTrigger"
646
- :query="mentionAutocomplete.query"
647
- :caret-rect="mentionAutocomplete.triggerCaretRect"
648
- @select="mentionAutocomplete.selectItem"
649
- @select-command="mentionAutocomplete.runCommand"
650
- />
644
+ <AnimatePresence mode="popLayout" :initial="false">
645
+ <TelaChatAnimateEnter v-if="showStopRun" key="stop-run">
646
+ <TelaChatStopRunButton label="Parar geração" @stop="emit('cancel')" />
647
+ </TelaChatAnimateEnter>
648
+ <TelaChatAnimateEnter v-else key="prompt-input">
649
+ <ChatMentionDropdown
650
+ v-if="mentionAutocomplete.isOpen"
651
+ :items="mentionAutocomplete.filteredItems"
652
+ :commands="mentionAutocomplete.filteredCommands"
653
+ :highlighted-index="mentionAutocomplete.highlightedIndex"
654
+ :trigger="mentionAutocomplete.activeTrigger"
655
+ :query="mentionAutocomplete.query"
656
+ :caret-rect="mentionAutocomplete.triggerCaretRect"
657
+ @select="mentionAutocomplete.selectItem"
658
+ @select-command="mentionAutocomplete.runCommand"
659
+ />
651
660
 
652
- <TelaChatPromptInput :locked="promptShellLocked" :class="centered && 'bg-white'">
653
- <TelaChatPromptInputAttachments v-if="hasAttachments">
654
- <TelaChatPromptInputAttachment
655
- v-for="pendingFile in pendingFiles"
656
- :key="pendingFile.id"
657
- :name="pendingFile.file.name"
658
- :icon="getFileIcon(getPendingFileMimeType(pendingFile))"
659
- :meta="formatFileSize(pendingFile.file.size)"
660
- remove-label="Remover anexo"
661
- @remove="removeFile(pendingFile.id)"
662
- >
663
- <select
664
- v-if="fileInputVariables.length > 0"
665
- class="agent-file-variable-select"
666
- :value="pendingFile.inputName ?? ''"
667
- :disabled="isLocked"
668
- @change="updatePendingFileInput(pendingFile.id, $event)"
669
- @click.stop
661
+ <TelaChatPromptInput :locked="promptShellLocked" :class="centered && 'bg-white'">
662
+ <TelaChatPromptInputAttachments v-if="hasAttachments">
663
+ <TelaChatPromptInputAttachment
664
+ v-for="pendingFile in pendingFiles"
665
+ :key="pendingFile.id"
666
+ :name="pendingFile.file.name"
667
+ :icon="getFileIcon(getPendingFileMimeType(pendingFile))"
668
+ :meta="formatFileSize(pendingFile.file.size)"
669
+ remove-label="Remover anexo"
670
+ @remove="removeFile(pendingFile.id)"
670
671
  >
671
- <option value="" disabled>
672
- Selecionar variável
673
- </option>
674
- <option
675
- v-for="input in fileInputVariables"
676
- :key="input.id || input.name"
677
- :value="input.name"
672
+ <select
673
+ v-if="fileInputVariables.length > 0"
674
+ class="agent-file-variable-select"
675
+ :value="pendingFile.inputName ?? ''"
676
+ :disabled="isLocked"
677
+ @change="updatePendingFileInput(pendingFile.id, $event)"
678
+ @click.stop
678
679
  >
679
- {{ input.name }}
680
- </option>
681
- </select>
682
- </TelaChatPromptInputAttachment>
683
- <component
684
- :is="composerExtension.attachmentsComponent"
685
- v-if="composerExtension?.attachmentsComponent"
686
- :disabled="isLocked"
687
- />
688
- </TelaChatPromptInputAttachments>
689
-
690
- <TelaChatPromptInputTextarea
691
- ref="promptTextareaRef"
692
- data-testid="chat-message-input"
693
- placeholder="Escreva sua mensagem..."
694
- :empty="!content.trim()"
695
- :flush="hasAttachments"
696
- :disabled="isLocked"
697
- @keydown="handleKeydown"
698
- @input="handleInput"
699
- @paste="handlePaste"
700
- @blur="handleBlur"
701
- />
702
-
703
- <TelaChatPromptInputToolbar>
704
- <TelaChatPromptInputTools>
705
- <TelaChatPromptInputActionMenu>
706
- <TelaChatPromptInputActionMenuTrigger :locked="isLocked" label="Abrir menu de ações" />
707
- <TelaChatPromptInputActionMenuContent>
708
- <TelaChatPromptInputActionMenuItem
709
- icon="i-ph-paperclip"
710
- :disabled="isLocked"
711
- @click="openFileDialog()"
680
+ <option value="" disabled>
681
+ Selecionar variável
682
+ </option>
683
+ <option
684
+ v-for="input in fileInputVariables"
685
+ :key="input.id || input.name"
686
+ :value="input.name"
712
687
  >
713
- Adicionar arquivos ou fotos
714
- </TelaChatPromptInputActionMenuItem>
715
- <TelaChatPromptInputActionMenuSub>
716
- <TelaChatPromptInputActionMenuSubTrigger icon="i-ph-clock-counter-clockwise">
717
- Arquivos recentes
718
- </TelaChatPromptInputActionMenuSubTrigger>
719
- <TelaChatPromptInputActionMenuSubContent>
720
- <TelaChatPromptInputActionMenuItem v-if="!fileItems.length" class="text-center" disabled>
721
- Nenhum arquivo recente
722
- </TelaChatPromptInputActionMenuItem>
723
- <TelaChatPromptInputActionMenuItem
724
- v-for="file in fileItems"
725
- :key="file.id"
726
- @click="insertMentionFromMenu(file)"
727
- >
728
- <img :src="file.iconUrl" class="w-16px h-16px mr-8px shrink-0" alt="">
729
- <span class="min-w-0 max-w-200px truncate">{{ file.label }}</span>
730
- </TelaChatPromptInputActionMenuItem>
731
- </TelaChatPromptInputActionMenuSubContent>
732
- </TelaChatPromptInputActionMenuSub>
733
- <TelaMenubarSeparator />
734
- <TelaChatPromptInputActionMenuSub>
735
- <TelaChatPromptInputActionMenuSubTrigger icon="i-ph-notepad" icon-size="16px">
736
- Skills
737
- </TelaChatPromptInputActionMenuSubTrigger>
738
- <TelaChatPromptInputActionMenuSubContent>
739
- <TelaChatPromptInputActionMenuItem v-if="!skillItems.length" class="text-center" disabled>
740
- Nenhuma skill disponível
741
- </TelaChatPromptInputActionMenuItem>
742
- <TelaChatPromptInputActionMenuItem
743
- v-for="skill in skillItems"
744
- :key="skill.id"
745
- @click="insertMentionFromMenu(skill)"
746
- >
747
- <span class="min-w-0 max-w-200px truncate">{{ skill.label }}</span>
748
- </TelaChatPromptInputActionMenuItem>
749
- </TelaChatPromptInputActionMenuSubContent>
750
- </TelaChatPromptInputActionMenuSub>
751
- </TelaChatPromptInputActionMenuContent>
752
- </TelaChatPromptInputActionMenu>
688
+ {{ input.name }}
689
+ </option>
690
+ </select>
691
+ </TelaChatPromptInputAttachment>
753
692
  <component
754
- :is="composerExtension.component"
755
- v-if="composerExtension?.component"
693
+ :is="composerExtension.attachmentsComponent"
694
+ v-if="composerExtension?.attachmentsComponent"
756
695
  :disabled="isLocked"
757
696
  />
758
- </TelaChatPromptInputTools>
697
+ </TelaChatPromptInputAttachments>
759
698
 
760
- <TelaChatPromptInputActions>
761
- <ChatReasoningEffortSelector
762
- v-model="selectedReasoningEffort"
763
- :disabled="isLocked"
764
- @click.stop
765
- />
766
- <ChatModelSelector
767
- v-model="selectedModel"
768
- :disabled="isLocked"
769
- @click.stop
770
- />
771
- <TelaChatPromptSubmitButton
772
- data-testid="chat-message-submit"
773
- :status="submitStatus"
774
- :disabled="!canSend"
775
- send-label="Enviar mensagem"
776
- stop-label="Parar geração"
777
- uploading-label="Enviando anexos"
778
- @send="handleSend"
779
- @stop="emit('cancel')"
780
- />
781
- </TelaChatPromptInputActions>
782
- </TelaChatPromptInputToolbar>
783
- </TelaChatPromptInput>
784
- </div>
699
+ <TelaChatPromptInputTextarea
700
+ ref="promptTextareaRef"
701
+ data-testid="chat-message-input"
702
+ placeholder="Escreva sua mensagem..."
703
+ :empty="!content.trim()"
704
+ :flush="hasAttachments"
705
+ :disabled="isLocked"
706
+ @keydown="handleKeydown"
707
+ @input="handleInput"
708
+ @paste="handlePaste"
709
+ @blur="handleBlur"
710
+ />
711
+
712
+ <TelaChatPromptInputToolbar>
713
+ <TelaChatPromptInputTools>
714
+ <TelaChatPromptInputActionMenu>
715
+ <TelaChatPromptInputActionMenuTrigger :locked="isLocked" label="Abrir menu de ações" />
716
+ <TelaChatPromptInputActionMenuContent>
717
+ <TelaChatPromptInputActionMenuItem
718
+ icon="i-ph-paperclip"
719
+ :disabled="isLocked"
720
+ @click="openFileDialog()"
721
+ >
722
+ Adicionar arquivos ou fotos
723
+ </TelaChatPromptInputActionMenuItem>
724
+ <TelaChatPromptInputActionMenuSub>
725
+ <TelaChatPromptInputActionMenuSubTrigger icon="i-ph-clock-counter-clockwise">
726
+ Arquivos recentes
727
+ </TelaChatPromptInputActionMenuSubTrigger>
728
+ <TelaChatPromptInputActionMenuSubContent>
729
+ <TelaChatPromptInputActionMenuItem v-if="!fileItems.length" class="text-center" disabled>
730
+ Nenhum arquivo recente
731
+ </TelaChatPromptInputActionMenuItem>
732
+ <TelaChatPromptInputActionMenuItem
733
+ v-for="file in fileItems"
734
+ :key="file.id"
735
+ @click="insertMentionFromMenu(file)"
736
+ >
737
+ <img :src="file.iconUrl" class="w-16px h-16px mr-8px shrink-0" alt="">
738
+ <span class="min-w-0 max-w-200px truncate">{{ file.label }}</span>
739
+ </TelaChatPromptInputActionMenuItem>
740
+ </TelaChatPromptInputActionMenuSubContent>
741
+ </TelaChatPromptInputActionMenuSub>
742
+ <TelaMenubarSeparator />
743
+ <TelaChatPromptInputActionMenuSub>
744
+ <TelaChatPromptInputActionMenuSubTrigger icon="i-ph-notepad" icon-size="16px">
745
+ Skills
746
+ </TelaChatPromptInputActionMenuSubTrigger>
747
+ <TelaChatPromptInputActionMenuSubContent>
748
+ <TelaChatPromptInputActionMenuItem v-if="!skillItems.length" class="text-center" disabled>
749
+ Nenhuma skill disponível
750
+ </TelaChatPromptInputActionMenuItem>
751
+ <TelaChatPromptInputActionMenuItem
752
+ v-for="skill in skillItems"
753
+ :key="skill.id"
754
+ @click="insertMentionFromMenu(skill)"
755
+ >
756
+ <span class="min-w-0 max-w-200px truncate">{{ skill.label }}</span>
757
+ </TelaChatPromptInputActionMenuItem>
758
+ </TelaChatPromptInputActionMenuSubContent>
759
+ </TelaChatPromptInputActionMenuSub>
760
+ </TelaChatPromptInputActionMenuContent>
761
+ </TelaChatPromptInputActionMenu>
762
+ <component
763
+ :is="composerExtension.component"
764
+ v-if="composerExtension?.component"
765
+ :disabled="isLocked"
766
+ />
767
+ </TelaChatPromptInputTools>
768
+
769
+ <TelaChatPromptInputActions>
770
+ <ChatReasoningEffortSelector
771
+ v-model="selectedReasoningEffort"
772
+ :disabled="isLocked"
773
+ @click.stop
774
+ />
775
+ <ChatModelSelector
776
+ v-model="selectedModel"
777
+ :disabled="isLocked"
778
+ @click.stop
779
+ />
780
+ <TelaChatPromptSubmitButton
781
+ data-testid="chat-message-submit"
782
+ :status="submitStatus"
783
+ :disabled="!canSend"
784
+ send-label="Enviar mensagem"
785
+ stop-label="Parar geração"
786
+ uploading-label="Enviando anexos"
787
+ @send="handleSend"
788
+ @stop="emit('cancel')"
789
+ />
790
+ </TelaChatPromptInputActions>
791
+ </TelaChatPromptInputToolbar>
792
+ </TelaChatPromptInput>
793
+ </TelaChatAnimateEnter>
794
+ </AnimatePresence>
785
795
  </div>
786
796
  </div>
787
797
  </template>
@@ -95,11 +95,8 @@ defineExpose({
95
95
  >
96
96
  <TelaChatConversation
97
97
  ref="conversationRef"
98
- :scroll-area="variant === 'widget'"
99
- :class="{
100
- 'pt-72px!': (variant ?? 'page') === 'page',
101
- 'pt-72px pb-24px px-16px': variant === 'mobile'
102
- }"
98
+ :scroll-area="variant !== 'mobile'"
99
+ :class="{ 'pb-24px px-16px': variant === 'mobile' }"
103
100
  >
104
101
  <TelaChatConversationContent class="max-w-700px! min-h-full">
105
102
  <template v-if="loading">
@@ -152,19 +149,18 @@ defineExpose({
152
149
  <button
153
150
  v-if="!isPinned && hasRoomBelow"
154
151
  type="button"
155
- class="chat-message-list__jump"
156
- bg="white/55"
157
- b=".5px border-default"
152
+ absolute z-2 left="50%" class="chat-message-list__jump bottom-[calc(var(--chat-input-height,0px)_+_32px)]"
153
+ bg border-0.5px border inline-flex size-32px flex items-center justify-center rounded-full
158
154
  aria-label="Ir para a mensagem mais recente"
159
155
  title="Ir para a mensagem mais recente"
160
156
  @click="scrollToBottom({ smooth: true })"
161
157
  >
162
- <TelaIcon name="i-ph-arrow-down" size="16px" color="icon-secondary" />
158
+ <TelaIcon name="i-ph-arrow-down-bold" size="16px" color="icon-tertiary" />
163
159
  </button>
164
160
  </Transition>
165
161
  </div>
166
162
  </template>
167
163
 
168
164
  <style scoped>
169
- .chat-message-list>:deep([data-chat-conversation]){flex:1 1 0%;min-height:0;overflow-y:auto}.chat-message-list__jump{align-items:center;backdrop-filter:blur(12px) saturate(1.4);-webkit-backdrop-filter:blur(12px) saturate(1.4);border-radius:999px;bottom:calc(var(--chat-input-height, 0px) + 40px);box-shadow:0 3px 12px rgba(0,0,0,.1);cursor:pointer;display:inline-flex;height:32px;justify-content:center;left:50%;position:absolute;transform:translateX(-50%);width:32px;z-index:2}.jump-to-latest-enter-active,.jump-to-latest-leave-active{transition:opacity .12s ease,transform .12s ease}.jump-to-latest-enter-from,.jump-to-latest-leave-to{opacity:0;transform:translateX(-50%) translateY(4px)}
165
+ .chat-message-list>:deep([data-chat-conversation]){flex:1 1 0%;min-height:0;overflow-y:auto}.chat-message-list:not([data-variant=widget]) :deep([data-chat-conversation]){padding-top:64px}.chat-message-list[data-variant=page] :deep(.chat-conversation-scrollbar){top:64px!important}.chat-message-list[data-variant=page] :deep(.scroll-fog [data-reka-scroll-area-viewport]){--chat-fog-size:calc(var(--chat-input-height, 64px) + 64px)}.chat-message-list__jump{transform:translateX(-50%);transform-origin:center}.jump-to-latest-enter-active,.jump-to-latest-leave-active{transition:opacity .12s ease,transform .12s ease}.jump-to-latest-enter-from,.jump-to-latest-leave-to{opacity:0;transform:translateX(-50%) scale(.7) translateY(10px)}
170
166
  </style>
@@ -84,24 +84,28 @@ function onKeydown(event) {
84
84
  <TelaPopoverTrigger as-child>
85
85
  <button
86
86
  type="button"
87
- class="effort-trigger hover:bg-muted! data-[state=open]:bg-muted!"
88
- :class="effort ? 'text-primary' : 'text-secondary'"
87
+ class="group pl-10px pr-8px py-7px rounded-8px flex items-center gap-6px duration-80 text-primary hover:bg-muted data-[state=open]:text-secondary data-[state=open]:bg-muted"
89
88
  :disabled="disabled"
90
89
  :aria-label="`Esfor\xE7o de racioc\xEDnio: ${selectedOption?.label ?? AGENT_DEFAULT_LABEL}`"
91
90
  >
92
91
  <span body-14-medium whitespace-nowrap>{{ triggerLabel }}</span>
93
- <span i-ph-caret-down class="effort-trigger-caret" icon-secondary aria-hidden="true" />
92
+ <TelaIcon
93
+ name="i-ph-caret-down-bold"
94
+ size="15px"
95
+ color="icon-tertiary"
96
+ class="shrink-0 transition-transform ease-out duration-150 group-data-[state=open]:rotate-180"
97
+ />
94
98
  </button>
95
99
  </TelaPopoverTrigger>
96
100
  <TelaPopoverContent
97
101
  side="top"
98
102
  align="end"
99
- :side-offset="8"
100
- class="effort-panel w-260px p-16px rounded-16px bg border-0.5px border [box-shadow:0_4px_16px_0_rgba(85,91,98,0.14)]"
103
+ :side-offset="3"
104
+ class="popover-enter-exit origin-[var(--reka-popover-content-transform-origin)] w-260px p-16px rounded-12px! bg border-0.5px! border! [box-shadow:0_4px_16px_0_rgba(85,91,98,0.14)]!"
101
105
  >
102
106
  <div flex="~ col" gap-16px>
103
- <div flex="~ col" items-center gap-4px text-center>
104
- <span body-14-medium text-primary>{{ selectedOption?.label ?? AGENT_DEFAULT_LABEL }}</span>
107
+ <div flex="~ col" items-center gap-2px text-center>
108
+ <span body-14-semibold text-primary>{{ selectedOption?.label ?? AGENT_DEFAULT_LABEL }}</span>
105
109
  <span body-12-regular text-secondary>{{ selectedOption?.description ?? AGENT_DEFAULT_DESCRIPTION }}</span>
106
110
  </div>
107
111
 
@@ -51,7 +51,7 @@ const liveFormattedDuration = computed(() => {
51
51
  <div class="chat-reasoning-stage" w-full>
52
52
  <Transition name="chat-reasoning-presence" :appear="!completed">
53
53
  <div v-if="!completed && !hasReasoning" key="thinking" class="chat-reasoning-placeholder">
54
- <ChatThinkingIndicator />
54
+ <ChatThinkingIndicator :started-at="startedAt" />
55
55
  </div>
56
56
 
57
57
  <!-- Com reasoning (loading ou completo): header clicável + steps colapsáveis -->
@@ -1,3 +1,6 @@
1
- declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
1
+ type __VLS_Props = {
2
+ startedAt?: Date | string;
3
+ };
4
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
2
5
  declare const _default: typeof __VLS_export;
3
6
  export default _default;
@@ -5,7 +5,16 @@ import {
5
5
  getNextChatLoadingMessageIndex,
6
6
  resolveChatLoadingMessages
7
7
  } from "../../../embed/loading-messages";
8
+ const props = defineProps({
9
+ startedAt: { type: [Date, String], required: false }
10
+ });
8
11
  const embedConfig = useEmbedConfig();
12
+ const startedAtMs = computed(() => {
13
+ if (!props.startedAt)
14
+ return void 0;
15
+ const ms = new Date(props.startedAt).getTime();
16
+ return Number.isNaN(ms) ? void 0 : ms;
17
+ });
9
18
  const currentTextIndex = ref(0);
10
19
  const dotCount = ref(0);
11
20
  const loadingState = computed(() => resolveChatLoadingMessages({
@@ -52,7 +61,10 @@ onUnmounted(() => {
52
61
  </script>
53
62
 
54
63
  <template>
55
- <TelaChatTextShimmer class="body-16-regular">
56
- {{ currentText }}
57
- </TelaChatTextShimmer>
64
+ <div flex flex-col gap-8px>
65
+ <TelaChatWorkingIndicator label="Trabalhando" :started-at="startedAtMs" />
66
+ <TelaChatTextShimmer class="body-16-regular">
67
+ {{ currentText }}
68
+ </TelaChatTextShimmer>
69
+ </div>
58
70
  </template>
@@ -1,3 +1,6 @@
1
- declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
1
+ type __VLS_Props = {
2
+ startedAt?: Date | string;
3
+ };
4
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
2
5
  declare const _default: typeof __VLS_export;
3
6
  export default _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/chat-nuxt",
3
- "version": "4.4.0-rc.8",
3
+ "version": "4.4.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {
@@ -53,7 +53,7 @@
53
53
  "@iconify/vue": "^5.0.0",
54
54
  "@meistrari/auth-nuxt": "3.31.0",
55
55
  "@meistrari/logger": "^2.1.3",
56
- "@meistrari/tela-build": "^1.74.2",
56
+ "@meistrari/tela-build": "^1.75.1",
57
57
  "@sentry/nuxt": "^10.0.0",
58
58
  "@vueuse/components": "^12.8.0",
59
59
  "@vueuse/core": "^12.8.0",