@meistrari/tela-build 1.74.0 → 1.74.1

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/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@ Latest updates and announcements.
4
4
 
5
5
  ## September 18, 2026
6
6
 
7
+ - [Floating chat](/templates/chat#floating) docs now show `TelaChatAnswer` docked above the prompt input inside the window.
8
+
9
+ - [Chat Answer](/templates/chat#answer) centers the card horizontally in its container and keeps it within the available width on narrow screens.
10
+
7
11
  - [Floating chat](/templates/chat) adds `closeOnOutsideClick` (default `true`); set it to `false` to keep the window open while using the surrounding page.
8
12
 
9
13
  ## September 17, 2026
@@ -174,7 +174,7 @@ function onKeydown(event: KeyboardEvent) {
174
174
 
175
175
  <template>
176
176
  <div ref="root" tabindex="-1" outline-none>
177
- <TelaCard size="sm" class="!p-0 w-400px" overflow-hidden>
177
+ <TelaCard size="sm" class="!p-0 w-450px" mx-auto max-w-full overflow-hidden>
178
178
  <TelaCollapsible :open="expanded" @update:open="emit('update:expanded', $event)">
179
179
  <div
180
180
  flex items-center justify-between gap-8px min-h-56px py-8px pl-16px pr-12px
@@ -149,8 +149,11 @@ The window opens over its own launcher: the surface springs out of the launcher'
149
149
 
150
150
  The widget header inside the window gets two extra actions automatically: **expand** grows the window until 8px from the top of the viewport (and back), and **minimize** closes it. See [Widget Header & History](#widget-header--history).
151
151
 
152
+ When the assistant needs a decision, dock a [`TelaChatAnswer`](#answer) above the prompt input: wrap both in one `[data-chat-composer]` element with a 12px gap so `TelaChatBody` pins and measures them together.
153
+
152
154
  ```vue
153
155
  <script setup lang="ts">
156
+ import type { TelaChatAnswerQuestion } from '@meistrari/tela-build/types'
154
157
  import { getMimeTypeIcon } from '@meistrari/tela-build/utils/files'
155
158
 
156
159
  const isOpen = ref(false)
@@ -164,20 +167,75 @@ const skills = [
164
167
  { id: 's1', label: 'Summarize document' },
165
168
  { id: 's2', label: 'Draft release announcement' },
166
169
  ]
167
- const messages = [
170
+ const messages = ref([
168
171
  { id: '1', role: 'user' as const, text: 'What changed in the latest release?' },
169
- { id: '2', role: 'assistant' as const, text: 'The chat primitives landed: a conversation viewport, a prompt input, and three shells you can compose freely.' },
170
- ]
172
+ { id: '2', role: 'assistant' as const, text: 'The chat primitives landed: a conversation viewport, a prompt input, and three shells you can compose freely. Want me to draft the announcement?' },
173
+ ])
171
174
  const conversations = [
172
175
  { id: 'c1', title: 'Release notes review' },
173
176
  { id: 'c2', title: 'Sidepanel layout questions' },
174
177
  { id: 'c3', title: 'Model selector options' },
175
178
  ]
179
+
180
+ // The assistant needs a decision before it continues. The host owns the
181
+ // question sequence and the selection; the card only emits intent.
182
+ const questions: TelaChatAnswerQuestion[] = [
183
+ {
184
+ id: 'tone',
185
+ title: 'Which tone should the announcement use?',
186
+ type: 'single',
187
+ recommendFirst: true,
188
+ options: [
189
+ { id: 'concise', label: 'Concise', description: 'Short and factual, for the changelog.' },
190
+ { id: 'friendly', label: 'Friendly', description: 'Warmer copy, for the newsletter.' },
191
+ { id: 'formal', label: 'Formal', description: 'For enterprise customers.' },
192
+ ],
193
+ },
194
+ {
195
+ id: 'sections',
196
+ title: 'Which sections should it include?',
197
+ type: 'multiple',
198
+ options: [
199
+ { id: 'highlights', label: 'Highlights' },
200
+ { id: 'breaking', label: 'Breaking changes' },
201
+ { id: 'upgrade', label: 'Upgrade guide' },
202
+ ],
203
+ },
204
+ ]
205
+ const index = ref(0)
206
+ const expanded = ref(true)
207
+ const answering = ref(true)
208
+ const answers = ref<Record<string, string[]>>({})
209
+ const question = computed(() => questions[index.value]!)
210
+ const selected = computed(() => answers.value[question.value.id] ?? [])
211
+
212
+ function select(id: string) {
213
+ answers.value[question.value.id] = [id]
214
+ }
215
+
216
+ function toggle(id: string, checked: boolean) {
217
+ answers.value[question.value.id] = checked
218
+ ? [...selected.value, id]
219
+ : selected.value.filter(value => value !== id)
220
+ }
221
+
222
+ function advance() {
223
+ if (index.value < questions.length - 1) {
224
+ index.value++
225
+ return
226
+ }
227
+
228
+ const summary = questions
229
+ .map(item => `${item.title} ${(answers.value[item.id] ?? []).join(', ') || 'skipped'}`)
230
+ .join(' ')
231
+ messages.value.push({ id: `${Date.now()}`, role: 'user', text: summary })
232
+ answering.value = false
233
+ }
176
234
  </script>
177
235
 
178
236
  <template>
179
237
  <!-- `contained` anchors the launcher to this box instead of the viewport. -->
180
- <div class="relative w-full h-560px">
238
+ <div class="relative w-full h-640px">
181
239
  <TelaChatFloatingWindow contained :open="isOpen" @update:open="isOpen = $event">
182
240
  <!-- The default launcher is TelaChatFloatingWindowTrigger; override it via the #launcher slot. -->
183
241
  <TelaChatWidgetHeader title="Release notes review">
@@ -197,53 +255,76 @@ const conversations = [
197
255
  </TelaChatConversationContent>
198
256
  </TelaChatConversation>
199
257
 
200
- <TelaChatPromptInput>
201
- <TelaChatPromptInputTextarea placeholder="Ask anything" :empty="!draft" />
202
- <TelaChatPromptInputToolbar>
203
- <TelaChatPromptInputTools>
204
- <TelaChatPromptInputActionMenu>
205
- <TelaChatPromptInputActionMenuTrigger />
206
- <TelaChatPromptInputActionMenuContent>
207
- <TelaChatPromptInputActionMenuItem icon="i-ph-paperclip">
208
- Add files or photos
209
- </TelaChatPromptInputActionMenuItem>
210
- <TelaChatPromptInputActionMenuSub>
211
- <TelaChatPromptInputActionMenuSubTrigger icon="i-ph-clock-counter-clockwise">
212
- Recent files
213
- </TelaChatPromptInputActionMenuSubTrigger>
214
- <TelaChatPromptInputActionMenuSubContent>
215
- <TelaChatPromptInputActionMenuItem
216
- v-for="file in recentFiles"
217
- :key="file.id"
218
- >
219
- <img :src="getMimeTypeIcon(file.type)" class="w-16px h-16px mr-8px shrink-0" alt="">
220
- <span class="min-w-0 max-w-200px truncate">{{ file.label }}</span>
221
- </TelaChatPromptInputActionMenuItem>
222
- </TelaChatPromptInputActionMenuSubContent>
223
- </TelaChatPromptInputActionMenuSub>
224
- <TelaMenubarSeparator />
225
- <TelaChatPromptInputActionMenuSub>
226
- <TelaChatPromptInputActionMenuSubTrigger icon="i-ph-notepad" icon-size="16px">
227
- Skills
228
- </TelaChatPromptInputActionMenuSubTrigger>
229
- <TelaChatPromptInputActionMenuSubContent>
230
- <TelaChatPromptInputActionMenuItem
231
- v-for="skill in skills"
232
- :key="skill.id"
233
- @click="draft = skill.label"
234
- >
235
- <span class="min-w-0 max-w-200px truncate">{{ skill.label }}</span>
236
- </TelaChatPromptInputActionMenuItem>
237
- </TelaChatPromptInputActionMenuSubContent>
238
- </TelaChatPromptInputActionMenuSub>
239
- </TelaChatPromptInputActionMenuContent>
240
- </TelaChatPromptInputActionMenu>
241
- </TelaChatPromptInputTools>
242
- <TelaChatPromptInputActions>
243
- <TelaChatPromptSubmitButton status="ready" :disabled="!draft.trim()" />
244
- </TelaChatPromptInputActions>
245
- </TelaChatPromptInputToolbar>
246
- </TelaChatPromptInput>
258
+ <!-- One composer wrapper: the answer card docks above the prompt input. -->
259
+ <div data-chat-composer class="flex flex-col gap-12px">
260
+ <TelaChatAnswer
261
+ v-if="answering"
262
+ v-model:expanded="expanded"
263
+ :question="question"
264
+ :selected="selected"
265
+ :current="index + 1"
266
+ :total="questions.length"
267
+ :can-continue="selected.length > 0"
268
+ show-navigation
269
+ :can-previous="index > 0"
270
+ :can-next="index < questions.length - 1"
271
+ @select="select"
272
+ @toggle="toggle"
273
+ @previous="index--"
274
+ @next="index++"
275
+ @skip="advance"
276
+ @continue="advance"
277
+ @dismiss="answering = false"
278
+ />
279
+
280
+ <TelaChatPromptInput>
281
+ <TelaChatPromptInputTextarea placeholder="Ask anything" :empty="!draft" />
282
+ <TelaChatPromptInputToolbar>
283
+ <TelaChatPromptInputTools>
284
+ <TelaChatPromptInputActionMenu>
285
+ <TelaChatPromptInputActionMenuTrigger />
286
+ <TelaChatPromptInputActionMenuContent>
287
+ <TelaChatPromptInputActionMenuItem icon="i-ph-paperclip">
288
+ Add files or photos
289
+ </TelaChatPromptInputActionMenuItem>
290
+ <TelaChatPromptInputActionMenuSub>
291
+ <TelaChatPromptInputActionMenuSubTrigger icon="i-ph-clock-counter-clockwise">
292
+ Recent files
293
+ </TelaChatPromptInputActionMenuSubTrigger>
294
+ <TelaChatPromptInputActionMenuSubContent>
295
+ <TelaChatPromptInputActionMenuItem
296
+ v-for="file in recentFiles"
297
+ :key="file.id"
298
+ >
299
+ <img :src="getMimeTypeIcon(file.type)" class="w-16px h-16px mr-8px shrink-0" alt="">
300
+ <span class="min-w-0 max-w-200px truncate">{{ file.label }}</span>
301
+ </TelaChatPromptInputActionMenuItem>
302
+ </TelaChatPromptInputActionMenuSubContent>
303
+ </TelaChatPromptInputActionMenuSub>
304
+ <TelaMenubarSeparator />
305
+ <TelaChatPromptInputActionMenuSub>
306
+ <TelaChatPromptInputActionMenuSubTrigger icon="i-ph-notepad" icon-size="16px">
307
+ Skills
308
+ </TelaChatPromptInputActionMenuSubTrigger>
309
+ <TelaChatPromptInputActionMenuSubContent>
310
+ <TelaChatPromptInputActionMenuItem
311
+ v-for="skill in skills"
312
+ :key="skill.id"
313
+ @click="draft = skill.label"
314
+ >
315
+ <span class="min-w-0 max-w-200px truncate">{{ skill.label }}</span>
316
+ </TelaChatPromptInputActionMenuItem>
317
+ </TelaChatPromptInputActionMenuSubContent>
318
+ </TelaChatPromptInputActionMenuSub>
319
+ </TelaChatPromptInputActionMenuContent>
320
+ </TelaChatPromptInputActionMenu>
321
+ </TelaChatPromptInputTools>
322
+ <TelaChatPromptInputActions>
323
+ <TelaChatPromptSubmitButton status="ready" :disabled="!draft.trim()" />
324
+ </TelaChatPromptInputActions>
325
+ </TelaChatPromptInputToolbar>
326
+ </TelaChatPromptInput>
327
+ </div>
247
328
  </TelaChatBody>
248
329
  </TelaChatFloatingWindow>
249
330
  </div>
@@ -1016,6 +1097,7 @@ const questions: TelaChatAnswerQuestion[] = [
1016
1097
  const index = ref(0)
1017
1098
  const expanded = ref(true)
1018
1099
  const done = ref(false)
1100
+ const dismissed = ref(false)
1019
1101
  const answers = ref<Record<string, string[]>>({})
1020
1102
 
1021
1103
  const question = computed(() => questions[index.value]!)
@@ -1045,6 +1127,7 @@ function restart() {
1045
1127
  index.value = 0
1046
1128
  answers.value = {}
1047
1129
  done.value = false
1130
+ dismissed.value = false
1048
1131
  expanded.value = true
1049
1132
  }
1050
1133
  </script>
@@ -1052,6 +1135,7 @@ function restart() {
1052
1135
  <template>
1053
1136
  <div class="flex flex-col items-start gap-12px w-full max-w-400px">
1054
1137
  <TelaChatAnswer
1138
+ v-if="!dismissed"
1055
1139
  v-model:expanded="expanded"
1056
1140
  class="w-full"
1057
1141
  :question="question"
@@ -1069,9 +1153,9 @@ function restart() {
1069
1153
  @next="index++"
1070
1154
  @skip="advance"
1071
1155
  @continue="advance"
1072
- @dismiss="expanded = false"
1156
+ @dismiss="dismissed = true"
1073
1157
  />
1074
- <TelaButton v-if="done" variant="secondary" size="sm" @click="restart">
1158
+ <TelaButton v-if="done || dismissed" variant="secondary" size="sm" @click="restart">
1075
1159
  Ask again
1076
1160
  </TelaButton>
1077
1161
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/tela-build",
3
- "version": "1.74.0",
3
+ "version": "1.74.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "app.config.ts",