@happyvertical/smrt-chat 0.34.5 → 0.34.7

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 (52) hide show
  1. package/dist/manifest.json +2 -2
  2. package/dist/smrt-knowledge.json +4 -4
  3. package/dist/svelte/components/agent/AgentChat.svelte +34 -49
  4. package/dist/svelte/components/agent/AgentChat.svelte.d.ts.map +1 -1
  5. package/dist/svelte/components/agent/AgentSelector.svelte +1 -0
  6. package/dist/svelte/components/agent/AgentSelector.svelte.d.ts.map +1 -1
  7. package/dist/svelte/components/agent/AgentSessionPanel.svelte +15 -16
  8. package/dist/svelte/components/agent/AgentSessionPanel.svelte.d.ts.map +1 -1
  9. package/dist/svelte/components/agent/ToolCallDisplay.svelte +1 -0
  10. package/dist/svelte/components/agent/ToolCallDisplay.svelte.d.ts.map +1 -1
  11. package/dist/svelte/components/dialogs/RoomCreateDialog.svelte +29 -94
  12. package/dist/svelte/components/dialogs/RoomCreateDialog.svelte.d.ts.map +1 -1
  13. package/dist/svelte/components/dialogs/SearchMessages.svelte +51 -36
  14. package/dist/svelte/components/dialogs/SearchMessages.svelte.d.ts.map +1 -1
  15. package/dist/svelte/components/layout/ChatLayout.svelte +1 -0
  16. package/dist/svelte/components/layout/ChatLayout.svelte.d.ts.map +1 -1
  17. package/dist/svelte/components/layout/MemberList.svelte +10 -15
  18. package/dist/svelte/components/layout/MemberList.svelte.d.ts.map +1 -1
  19. package/dist/svelte/components/layout/RoomHeader.svelte +13 -16
  20. package/dist/svelte/components/layout/RoomHeader.svelte.d.ts.map +1 -1
  21. package/dist/svelte/components/layout/RoomList.svelte +26 -17
  22. package/dist/svelte/components/layout/RoomList.svelte.d.ts.map +1 -1
  23. package/dist/svelte/components/messages/MessageInput.svelte +34 -48
  24. package/dist/svelte/components/messages/MessageInput.svelte.d.ts.map +1 -1
  25. package/dist/svelte/components/messages/MessageItem.svelte +52 -43
  26. package/dist/svelte/components/messages/MessageItem.svelte.d.ts.map +1 -1
  27. package/dist/svelte/components/messages/ThreadPanel.svelte +9 -9
  28. package/dist/svelte/components/messages/ThreadPanel.svelte.d.ts.map +1 -1
  29. package/dist/svelte/components/shared/FileUpload.svelte +23 -54
  30. package/dist/svelte/components/shared/FileUpload.svelte.d.ts.map +1 -1
  31. package/dist/svelte/components/shared/MentionAutocomplete.svelte +1 -0
  32. package/dist/svelte/components/shared/MentionAutocomplete.svelte.d.ts.map +1 -1
  33. package/dist/svelte/components/shared/ReactionPicker.svelte +15 -66
  34. package/dist/svelte/components/shared/ReactionPicker.svelte.d.ts.map +1 -1
  35. package/dist/svelte/components/tabs/ChatTab.svelte +20 -18
  36. package/dist/svelte/components/tabs/ChatTab.svelte.d.ts.map +1 -1
  37. package/dist/svelte/components/tabs/ChatTabList.svelte +13 -10
  38. package/dist/svelte/components/tabs/ChatTabList.svelte.d.ts.map +1 -1
  39. package/dist/svelte/components/tabs/MiniChat.svelte +21 -37
  40. package/dist/svelte/components/tabs/MiniChat.svelte.d.ts.map +1 -1
  41. package/dist/svelte/index.d.ts +1 -2
  42. package/dist/svelte/index.d.ts.map +1 -1
  43. package/dist/svelte/index.js +5 -4
  44. package/package.json +9 -8
  45. package/dist/svelte/components/shared/MessageBubble.svelte +0 -81
  46. package/dist/svelte/components/shared/MessageBubble.svelte.d.ts +0 -16
  47. package/dist/svelte/components/shared/MessageBubble.svelte.d.ts.map +0 -1
  48. package/dist/svelte/components/shared/TypingIndicator.svelte +0 -90
  49. package/dist/svelte/components/shared/TypingIndicator.svelte.d.ts +0 -12
  50. package/dist/svelte/components/shared/TypingIndicator.svelte.d.ts.map +0 -1
  51. package/dist/svelte/components/shared/__tests__/MessageBubble.test.js +0 -21
  52. package/dist/svelte/components/shared/__tests__/TypingIndicator.test.js +0 -27
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "version": "1.0.0",
3
- "timestamp": 1782261325121,
3
+ "timestamp": 1782290164480,
4
4
  "packageName": "@happyvertical/smrt-chat",
5
- "packageVersion": "0.34.5",
5
+ "packageVersion": "0.34.7",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-chat:AgentSessionCollection": {
8
8
  "name": "agentsessioncollection",
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-06-24T00:35:25.555Z",
3
+ "generatedAt": "2026-06-24T08:36:04.806Z",
4
4
  "packageName": "@happyvertical/smrt-chat",
5
- "packageVersion": "0.34.5",
5
+ "packageVersion": "0.34.7",
6
6
  "sourceManifestPath": "dist/manifest.json",
7
7
  "agentDocPath": "AGENTS.md",
8
8
  "sourceHashes": {
9
- "manifest": "23d035b24c816ce18408fba96b31ffd2b3f9616b1fdee7fe3f15fa66047fe551",
10
- "packageJson": "fc6d69f31fe2019af2204e062594b852fdf1164ba17538646acaa7c81191570f",
9
+ "manifest": "eb7dc5e132fb34b6c1588f1cec335f9f087d782e8762992c7dc7124023353fe3",
10
+ "packageJson": "ce14941c197b179f275a91e466bea275c71aa6cacb4aedd1d6f0b3a01ff53861",
11
11
  "agents": "e0a8c6788fbd48c2619a353295d4538e9ff6863d483bcd354af522fb7c6a31bc"
12
12
  },
13
13
  "exports": [
@@ -5,7 +5,9 @@
5
5
  * Agent messages are styled differently from user messages.
6
6
  */
7
7
 
8
+ import { Form, Textarea } from '@happyvertical/smrt-ui/forms';
8
9
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
10
+ import { Button } from '@happyvertical/smrt-ui/ui';
9
11
  import { M } from '../../i18n.js';
10
12
  import type {
11
13
  AgentSessionData,
@@ -91,13 +93,13 @@ $effect(() => {
91
93
  </script>
92
94
 
93
95
  <div class="agent-chat" aria-label={t(M['chat.agent_chat.conversation'])}>
94
- <form class="agent-chat__input-bar" onsubmit={(e) => handleSubmit(e)}>
96
+ <Form class="agent-chat__input-bar" onsubmit={(e) => handleSubmit(e)}>
95
97
  {#if !isActive}
96
98
  <div class="agent-chat__inactive-notice">
97
99
  {t(M['chat.agent_chat.inactive_notice'], { status: session.status })}
98
100
  </div>
99
101
  {:else}
100
- <textarea
102
+ <Textarea
101
103
  class="agent-chat__input"
102
104
  placeholder={t(M['chat.agent_chat.input_placeholder'])}
103
105
  bind:value={inputValue}
@@ -105,8 +107,9 @@ $effect(() => {
105
107
  rows={1}
106
108
  disabled={!isActive}
107
109
  aria-label={t(M['chat.agent_chat.message_input'])}
108
- ></textarea>
109
- <button
110
+ />
111
+ <Button
112
+ variant="ghost"
110
113
  class="agent-chat__send-btn"
111
114
  type="submit"
112
115
  disabled={!inputValue.trim() || !isActive}
@@ -115,9 +118,9 @@ $effect(() => {
115
118
  <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
116
119
  <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" />
117
120
  </svg>
118
- </button>
121
+ </Button>
119
122
  {/if}
120
- </form>
123
+ </Form>
121
124
 
122
125
  <div
123
126
  class="agent-chat__messages"
@@ -151,19 +154,21 @@ $effect(() => {
151
154
  {:else if block.type === 'fields'}
152
155
  <div class="field-update-block">
153
156
  <span class="applied-badge">{t(M['chat.agent_chat.updated_fields'], { count: Object.keys(block.fields).length, plural: Object.keys(block.fields).length !== 1 ? 's' : '' })}</span>
154
- <button class="diff-btn" type="button" onclick={() => showDiff(block.fields)}>Diff</button>
157
+ <Button variant="ghost" size="sm" class="diff-btn" type="button" onclick={() => showDiff(block.fields)}>Diff</Button>
155
158
  </div>
156
159
  {:else if block.type === 'markdown'}
157
160
  <div class="markdown-block">
158
161
  <pre class="markdown-block__content"><code>{block.content}</code></pre>
159
162
  {#if onapplychange}
160
- <button
163
+ <Button
164
+ variant="ghost"
165
+ size="sm"
161
166
  class="diff-btn"
162
167
  type="button"
163
168
  onclick={() => onapplychange(block.content)}
164
169
  >
165
170
  Apply
166
- </button>
171
+ </Button>
167
172
  {/if}
168
173
  </div>
169
174
  {/if}
@@ -198,7 +203,7 @@ $effect(() => {
198
203
  <dialog bind:this={diffDialog} class="diff-dialog">
199
204
  <div class="diff-dialog__header">
200
205
  <h4>{t(M['chat.agent_chat.field_changes'])}</h4>
201
- <button class="diff-dialog__close" type="button" onclick={closeDiff}>✕</button>
206
+ <Button variant="ghost" size="sm" class="diff-dialog__close" type="button" onclick={closeDiff}>✕</Button>
202
207
  </div>
203
208
  {#if diffDialogFields}
204
209
  <div class="diff-dialog__body">
@@ -307,7 +312,8 @@ $effect(() => {
307
312
  color: var(--smrt-color-outline, #74777f);
308
313
  }
309
314
 
310
- .agent-chat__input-bar {
315
+ /* :global() targets the Form primitive's rendered <form> (see #1589 scoping trap). */
316
+ :global(.agent-chat__input-bar) {
311
317
  display: flex;
312
318
  align-items: flex-end;
313
319
  gap: var(--smrt-spacing-2, 8px);
@@ -325,51 +331,30 @@ $effect(() => {
325
331
  font-style: italic;
326
332
  }
327
333
 
328
- .agent-chat__input {
334
+ /* Layout for the Textarea primitive's rendered <textarea> (tokenised styling
335
+ comes from the primitive; this only sizes it within the input bar). */
336
+ :global(.agent-chat__input) {
329
337
  flex: 1;
330
- border: none;
331
- border-radius: var(--smrt-radius-md, 8px);
332
- padding: var(--smrt-spacing-2, 8px) var(--smrt-spacing-3, 12px);
333
- font-size: var(--smrt-typography-body-medium-size, 0.8125rem);
334
- line-height: var(--smrt-typography-body-medium-line-height, 1.4);
335
- color: var(--smrt-color-on-surface, #1a1c1e);
336
- background: var(--smrt-color-surface-container-low, #f7f7fb);
337
338
  resize: none;
338
- outline: none;
339
339
  min-height: 34px;
340
340
  max-height: 80px;
341
341
  }
342
342
 
343
- .agent-chat__input:focus {
344
- outline: none;
345
- background: var(--smrt-color-surface-variant, #e1e2ec);
346
- }
347
-
348
- .agent-chat__input::placeholder {
349
- color: var(--smrt-color-outline, #74777f);
350
- }
351
-
352
- .agent-chat__send-btn {
353
- display: inline-flex;
354
- align-items: center;
355
- justify-content: center;
343
+ /* :global() pierces into the Button child's rendered <button> (see #1589).
344
+ The ancestor is the Form primitive's <form>, also global. */
345
+ :global(.agent-chat__input-bar .agent-chat__send-btn) {
356
346
  width: 34px;
357
347
  height: 34px;
358
- border: none;
348
+ padding: 0;
359
349
  background: var(--smrt-color-primary, #005ac1);
360
350
  color: var(--smrt-color-on-primary, #ffffff);
361
351
  border-radius: var(--smrt-radius-full, 9999px);
362
- cursor: pointer;
363
352
  flex-shrink: 0;
364
353
  transition: opacity 150ms;
365
354
  }
366
355
 
367
- .agent-chat__send-btn:disabled {
368
- opacity: 0.4;
369
- cursor: not-allowed;
370
- }
371
-
372
- .agent-chat__send-btn:not(:disabled):hover {
356
+ :global(.agent-chat__input-bar .agent-chat__send-btn:not(:disabled):hover) {
357
+ background: var(--smrt-color-primary, #005ac1);
373
358
  opacity: 0.85;
374
359
  }
375
360
 
@@ -411,7 +396,9 @@ $effect(() => {
411
396
  line-height: var(--smrt-typography-body-medium-line-height, 1.45);
412
397
  }
413
398
 
414
- .diff-btn {
399
+ /* :global() pierces into each Button's rendered <button> (see #1589). */
400
+ .field-update-block :global(.diff-btn),
401
+ .markdown-block :global(.diff-btn) {
415
402
  padding: var(--smrt-spacing-1, 4px) var(--smrt-spacing-2, 8px);
416
403
  font-size: var(--smrt-typography-label-small-size, 0.625rem);
417
404
  font-weight: var(--smrt-typography-weight-semibold, 600);
@@ -419,11 +406,10 @@ $effect(() => {
419
406
  border-radius: var(--smrt-radius-full, 9999px);
420
407
  background: none;
421
408
  color: var(--smrt-color-on-surface-variant, #43474e);
422
- cursor: pointer;
423
- transition: background 0.15s;
424
409
  }
425
410
 
426
- .diff-btn:hover {
411
+ .field-update-block :global(.diff-btn:hover),
412
+ .markdown-block :global(.diff-btn:hover) {
427
413
  background: var(--smrt-color-surface-variant, #e1e2ec);
428
414
  color: var(--smrt-color-primary, #005ac1);
429
415
  }
@@ -457,17 +443,16 @@ $effect(() => {
457
443
  font-weight: var(--smrt-typography-weight-semibold, 600);
458
444
  }
459
445
 
460
- .diff-dialog__close {
446
+ /* :global() pierces into the Button child's rendered <button> (see #1589). */
447
+ .diff-dialog__header :global(.diff-dialog__close) {
461
448
  background: none;
462
- border: none;
463
449
  font-size: var(--smrt-typography-body-large-size, 1rem);
464
- cursor: pointer;
465
450
  color: var(--smrt-color-outline, #74777f);
466
451
  padding: var(--smrt-spacing-1, 4px) var(--smrt-spacing-2, 8px);
467
452
  border-radius: var(--smrt-radius-sm, 4px);
468
453
  }
469
454
 
470
- .diff-dialog__close:hover {
455
+ .diff-dialog__header :global(.diff-dialog__close:hover) {
471
456
  background: var(--smrt-color-surface-variant, #e1e2ec);
472
457
  }
473
458
 
@@ -1 +1 @@
1
- {"version":3,"file":"AgentChat.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/agent/AgentChat.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AAMxB,MAAM,WAAW,KAAK;IACpB,yBAAyB;IACzB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,oCAAoC;IACpC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,gCAAgC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kCAAkC;IAClC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,4CAA4C;IAC5C,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAwKD,QAAA,MAAM,SAAS,2CAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"AgentChat.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/agent/AgentChat.svelte.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AAMxB,MAAM,WAAW,KAAK;IACpB,yBAAyB;IACzB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,oCAAoC;IACpC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,gCAAgC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IACzB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kCAAkC;IAClC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,4CAA4C;IAC5C,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AA0KD,QAAA,MAAM,SAAS,2CAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
@@ -26,6 +26,7 @@ const { t } = useI18n();
26
26
 
27
27
  <div class="agent-selector__grid" role="listbox" aria-label={t(M['chat.agent_selector.available_agents'])}>
28
28
  {#each agents as agent (agent.id)}
29
+ <!-- raw-primitive-allow: large pressable selection card with role=option wrapping rich content (avatar, name, description, unavailable badge) inside a role=listbox; no Button primitive owns this structural listbox-option pattern -->
29
30
  <button
30
31
  class="agent-selector__card"
31
32
  class:agent-selector__card--unavailable={!agent.isAvailable}
@@ -1 +1 @@
1
- {"version":3,"file":"AgentSelector.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/agent/AgentSelector.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,MAAM,WAAW,KAAK;IACpB,uBAAuB;IACvB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,sBAAsB;IACtB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AA6CD,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"AgentSelector.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/agent/AgentSelector.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,MAAM,WAAW,KAAK;IACpB,uBAAuB;IACvB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,sBAAsB;IACtB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AA8CD,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -5,6 +5,7 @@
5
5
  * Allows selecting an existing session or creating a new one.
6
6
  */
7
7
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
8
+ import { Button } from '@happyvertical/smrt-ui/ui';
8
9
  import { M } from '../../i18n.js';
9
10
  import type { AgentSessionData } from '../../types.js';
10
11
  import Avatar from '../shared/Avatar.svelte';
@@ -49,7 +50,8 @@ const statusLabel: Record<string, string> = {
49
50
  <div class="session-panel__header">
50
51
  <h2 class="session-panel__title">Sessions</h2>
51
52
  {#if onnewsession}
52
- <button
53
+ <Button
54
+ variant="ghost"
53
55
  class="session-panel__new-btn"
54
56
  type="button"
55
57
  onclick={onnewsession}
@@ -59,13 +61,14 @@ const statusLabel: Record<string, string> = {
59
61
  <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
60
62
  <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
61
63
  </svg>
62
- </button>
64
+ </Button>
63
65
  {/if}
64
66
  </div>
65
67
 
66
68
  <div class="session-panel__list" role="listbox" aria-label={t(M['chat.agent_session_panel.session_list'])}>
67
69
  {#each sessions as session (session.id)}
68
70
  {@const isCurrent = session.id === currentSessionId}
71
+ <!-- raw-primitive-allow: large pressable selection card with role=option wrapping rich content (avatar, name, date, status, message count, tool chips) inside a role=listbox; no Button primitive owns this structural listbox-option pattern -->
69
72
  <button
70
73
  class="session-panel__item"
71
74
  class:session-panel__item--active={isCurrent}
@@ -152,29 +155,22 @@ const statusLabel: Record<string, string> = {
152
155
  margin: 0;
153
156
  }
154
157
 
155
- .session-panel__new-btn {
156
- display: inline-flex;
157
- align-items: center;
158
- justify-content: center;
158
+ /* :global() pierces into the Button child's rendered <button> (see #1589). */
159
+ .session-panel__header :global(.session-panel__new-btn) {
159
160
  width: 36px;
160
161
  height: 36px;
161
- border: none;
162
+ padding: 0;
162
163
  background: var(--smrt-color-primary, #005ac1);
163
164
  color: var(--smrt-color-on-primary, #ffffff);
164
165
  border-radius: var(--smrt-radius-full, 9999px);
165
- cursor: pointer;
166
166
  transition: opacity var(--smrt-duration-short2, 150ms);
167
167
  }
168
168
 
169
- .session-panel__new-btn:hover {
169
+ .session-panel__header :global(.session-panel__new-btn:hover) {
170
+ background: var(--smrt-color-primary, #005ac1);
170
171
  opacity: 0.85;
171
172
  }
172
173
 
173
- .session-panel__new-btn:focus-visible {
174
- outline: 2px solid var(--smrt-color-primary, #005ac1);
175
- outline-offset: 2px;
176
- }
177
-
178
174
  .session-panel__list {
179
175
  flex: 1;
180
176
  overflow-y: auto;
@@ -314,8 +310,11 @@ const statusLabel: Record<string, string> = {
314
310
  }
315
311
 
316
312
  @media (prefers-reduced-motion: reduce) {
317
- .session-panel__item,
318
- .session-panel__new-btn {
313
+ .session-panel__item {
314
+ transition: none;
315
+ }
316
+
317
+ .session-panel__header :global(.session-panel__new-btn) {
319
318
  transition: none;
320
319
  }
321
320
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AgentSessionPanel.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/agent/AgentSessionPanel.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIvD,MAAM,WAAW,KAAK;IACpB,yBAAyB;IACzB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,kCAAkC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uBAAuB;IACvB,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,2BAA2B;IAC3B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAiGD,QAAA,MAAM,iBAAiB,2CAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"AgentSessionPanel.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/agent/AgentSessionPanel.svelte.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIvD,MAAM,WAAW,KAAK;IACpB,yBAAyB;IACzB,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,kCAAkC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uBAAuB;IACvB,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,2BAA2B;IAC3B,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAmGD,QAAA,MAAM,iBAAiB,2CAAwC,CAAC;AAChE,KAAK,iBAAiB,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC9D,eAAe,iBAAiB,CAAC"}
@@ -50,6 +50,7 @@ function formatDuration(ms: number | undefined): string {
50
50
  </script>
51
51
 
52
52
  <div class="tool-call tool-call--{toolCall.status}" aria-label={t(M['chat.tool_call_display.tool_call'], { toolName: toolCall.toolName })}>
53
+ <!-- raw-primitive-allow: full-width disclosure trigger with aria-expanded and aria-controls toggling an externally-rendered collapsible panel, wrapping rich content (status dot, name, duration, status label, rotating chevron); structural accordion header no Button primitive owns -->
53
54
  <button
54
55
  class="tool-call__header"
55
56
  type="button"
@@ -1 +1 @@
1
- {"version":3,"file":"ToolCallDisplay.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/agent/ToolCallDisplay.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1D,MAAM,WAAW,KAAK;IACpB,qBAAqB;IACrB,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAkGD,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"ToolCallDisplay.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/agent/ToolCallDisplay.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1D,MAAM,WAAW,KAAK;IACpB,qBAAqB;IACrB,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAmGD,QAAA,MAAM,eAAe,2CAAwC,CAAC;AAC9D,KAAK,eAAe,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,eAAe,eAAe,CAAC"}
@@ -8,7 +8,9 @@
8
8
  * hand-rolled backdrop it replaced had none of those.
9
9
  */
10
10
  import { Modal } from '@happyvertical/smrt-ui/feedback';
11
+ import { Form, Input, Textarea } from '@happyvertical/smrt-ui/forms';
11
12
  import { useI18n } from '@happyvertical/smrt-ui/i18n';
13
+ import { Button } from '@happyvertical/smrt-ui/ui';
12
14
  import { M } from '../../i18n.js';
13
15
 
14
16
  const { t } = useI18n();
@@ -31,7 +33,6 @@ let { isOpen, onclose, oncreate }: Props = $props();
31
33
  let name = $state('');
32
34
  let roomType = $state('public');
33
35
  let description = $state('');
34
- let nameInput = $state<HTMLInputElement | null>(null);
35
36
 
36
37
  const canCreate = $derived(name.trim().length > 0);
37
38
 
@@ -80,10 +81,15 @@ function resetForm() {
80
81
  }
81
82
 
82
83
  // Modal traps focus and moves it to the dialog itself; nudge initial focus to
83
- // the name field once the dialog is open and the input is mounted.
84
+ // the name field once the dialog is open and the input is mounted. The Input
85
+ // primitive doesn't expose its inner element, so resolve it by id.
84
86
  $effect(() => {
85
- if (isOpen && nameInput) {
86
- nameInput.focus();
87
+ if (isOpen && typeof document !== 'undefined') {
88
+ // Defer a frame so the Modal body (and the name input) is mounted first.
89
+ const raf = requestAnimationFrame(() => {
90
+ document.getElementById('room-name')?.focus();
91
+ });
92
+ return () => cancelAnimationFrame(raf);
87
93
  }
88
94
  });
89
95
  </script>
@@ -95,7 +101,7 @@ $effect(() => {
95
101
  size="md"
96
102
  ariaLabel={t(M['chat.room_create_dialog.title'])}
97
103
  >
98
- <form
104
+ <Form
99
105
  class="dialog__form"
100
106
  onsubmit={(e) => { e.preventDefault(); handleSubmit(); }}
101
107
  >
@@ -103,14 +109,12 @@ $effect(() => {
103
109
  <label class="field__label" for="room-name">
104
110
  {t(M['chat.room_create_dialog.room_name'])} <span class="field__required" aria-label={t(M['chat.room_create_dialog.required'])}>*</span>
105
111
  </label>
106
- <input
107
- bind:this={nameInput}
112
+ <Input
108
113
  bind:value={name}
109
114
  id="room-name"
110
115
  type="text"
111
- class="field__input"
112
116
  placeholder={t(M['chat.room_create_dialog.name_placeholder'])}
113
- maxlength="100"
117
+ maxlength={100}
114
118
  autocomplete="off"
115
119
  />
116
120
  </div>
@@ -123,6 +127,7 @@ $effect(() => {
123
127
  class="type-option"
124
128
  class:type-option--selected={roomType === option.value}
125
129
  >
130
+ <!-- raw-primitive-allow: native radio for single-choice room-type selection; no Provider-free radio primitive (Toggle is a switch with different semantics, CheckboxInput requires a Provider) -->
126
131
  <input
127
132
  type="radio"
128
133
  name="roomType"
@@ -141,42 +146,43 @@ $effect(() => {
141
146
 
142
147
  <div class="field">
143
148
  <label class="field__label" for="room-description">Description</label>
144
- <textarea
149
+ <Textarea
145
150
  bind:value={description}
146
151
  id="room-description"
147
- class="field__textarea"
148
152
  placeholder={t(M['chat.room_create_dialog.description_placeholder'])}
149
- rows="3"
150
- maxlength="500"
151
- ></textarea>
153
+ rows={3}
154
+ maxlength={500}
155
+ />
152
156
  <span class="field__hint">{description.length}/500</span>
153
157
  </div>
154
158
 
155
159
  <!-- Hidden submit keeps Enter-to-submit working inside the Modal body. -->
160
+ <!-- raw-primitive-allow: off-screen aria-hidden type=submit element with tabindex=-1 used only to enable native Enter-to-submit inside the Modal body; intentionally non-interactive and not a visible action button -->
156
161
  <button type="submit" class="visually-hidden" tabindex="-1" disabled={!canCreate} aria-hidden="true"></button>
157
- </form>
162
+ </Form>
158
163
 
159
164
  {#snippet footer()}
160
- <button
165
+ <Button
166
+ variant="secondary"
161
167
  type="button"
162
- class="btn btn--secondary"
163
168
  onclick={handleClose}
164
169
  >
165
170
  Cancel
166
- </button>
167
- <button
171
+ </Button>
172
+ <Button
173
+ variant="primary"
168
174
  type="button"
169
- class="btn btn--primary"
170
175
  disabled={!canCreate}
171
176
  onclick={handleSubmit}
172
177
  >
173
178
  {t(M['chat.room_create_dialog.create_room'])}
174
- </button>
179
+ </Button>
175
180
  {/snippet}
176
181
  </Modal>
177
182
 
178
183
  <style>
179
- .dialog__form {
184
+ /* :global() targets the Form primitive's rendered <form> (see #1589 scoping trap). */
185
+ :global(.dialog__form) {
180
186
  display: flex;
181
187
  flex-direction: column;
182
188
  gap: 1.25rem;
@@ -212,40 +218,6 @@ $effect(() => {
212
218
  color: var(--smrt-color-error, #b3261e);
213
219
  }
214
220
 
215
- .field__input {
216
- padding: 0.75rem;
217
- font: var(--smrt-typography-body-large-font, 1rem / 1.5 sans-serif);
218
- font-family: inherit;
219
- border: 1px solid var(--smrt-color-outline, #74777f);
220
- border-radius: var(--smrt-radius-medium, 0.5rem);
221
- background: var(--smrt-color-surface, #fefbff);
222
- color: var(--smrt-color-on-surface, #1a1c1e);
223
- }
224
-
225
- .field__input:focus {
226
- outline: none;
227
- border-color: var(--smrt-color-primary, #005ac1);
228
- box-shadow: 0 0 0 1px var(--smrt-color-primary, #005ac1);
229
- }
230
-
231
- .field__textarea {
232
- padding: 0.75rem;
233
- font: var(--smrt-typography-body-large-font, 1rem / 1.5 sans-serif);
234
- font-family: inherit;
235
- border: 1px solid var(--smrt-color-outline, #74777f);
236
- border-radius: var(--smrt-radius-medium, 0.5rem);
237
- background: var(--smrt-color-surface, #fefbff);
238
- color: var(--smrt-color-on-surface, #1a1c1e);
239
- resize: vertical;
240
- min-height: 80px;
241
- }
242
-
243
- .field__textarea:focus {
244
- outline: none;
245
- border-color: var(--smrt-color-primary, #005ac1);
246
- box-shadow: 0 0 0 1px var(--smrt-color-primary, #005ac1);
247
- }
248
-
249
221
  .field__hint {
250
222
  font: var(--smrt-typography-body-small-font, 0.75rem / 1.25 sans-serif);
251
223
  color: var(--smrt-color-on-surface-variant, #43474e);
@@ -301,45 +273,8 @@ $effect(() => {
301
273
  color: var(--smrt-color-on-surface-variant, #43474e);
302
274
  }
303
275
 
304
- .btn {
305
- display: inline-flex;
306
- align-items: center;
307
- justify-content: center;
308
- padding: 0.625rem 1.5rem;
309
- font: var(--smrt-typography-label-large-font, 500 0.875rem / 1.25 sans-serif);
310
- letter-spacing: 0.1px;
311
- border-radius: var(--smrt-radius-full, 9999px);
312
- border: none;
313
- cursor: pointer;
314
- transition: all var(--smrt-duration-short2, 150ms) var(--smrt-easing-standard, ease);
315
- }
316
-
317
- .btn:disabled {
318
- opacity: 0.38;
319
- cursor: not-allowed;
320
- }
321
-
322
- .btn--primary {
323
- background: var(--smrt-color-primary, #005ac1);
324
- color: var(--smrt-color-on-primary, #fff);
325
- }
326
-
327
- .btn--primary:hover:not(:disabled) {
328
- box-shadow: var(--smrt-elevation-1, 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 3px 1px rgba(0, 0, 0, 0.15));
329
- }
330
-
331
- .btn--secondary {
332
- background: transparent;
333
- color: var(--smrt-color-primary, #005ac1);
334
- }
335
-
336
- .btn--secondary:hover:not(:disabled) {
337
- background: color-mix(in srgb, var(--smrt-color-primary, #005ac1) 8%, transparent);
338
- }
339
-
340
276
  @media (prefers-reduced-motion: reduce) {
341
- .type-option,
342
- .btn {
277
+ .type-option {
343
278
  transition: none;
344
279
  }
345
280
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RoomCreateDialog.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/dialogs/RoomCreateDialog.svelte.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,KAAK;IACpB,iCAAiC;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,mCAAmC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,oCAAoC;IACpC,QAAQ,EAAE,CAAC,MAAM,EAAE;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;KACrB,KAAK,IAAI,CAAC;CACZ;AAwHD,QAAA,MAAM,gBAAgB,2CAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"RoomCreateDialog.svelte.d.ts","sourceRoot":"","sources":["../../../../src/svelte/components/dialogs/RoomCreateDialog.svelte.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,KAAK;IACpB,iCAAiC;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,mCAAmC;IACnC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,oCAAoC;IACpC,QAAQ,EAAE,CAAC,MAAM,EAAE;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;KACrB,KAAK,IAAI,CAAC;CACZ;AAgID,QAAA,MAAM,gBAAgB,2CAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}