@copilotkitnext/angular 0.0.1 → 0.0.4

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 (171) hide show
  1. package/README.md +248 -0
  2. package/dist/README.md +248 -0
  3. package/dist/components/chat/copilot-chat-assistant-message.component.d.ts +10 -10
  4. package/dist/components/chat/copilot-chat-message-view.component.d.ts +42 -42
  5. package/dist/components/chat/copilot-chat-view.component.d.ts +14 -14
  6. package/dist/esm2022/components/chat/copilot-chat-assistant-message-buttons.component.mjs +384 -0
  7. package/dist/esm2022/components/chat/copilot-chat-assistant-message-renderer.component.mjs +286 -0
  8. package/dist/esm2022/components/chat/copilot-chat-assistant-message-toolbar.component.mjs +27 -0
  9. package/dist/esm2022/components/chat/copilot-chat-assistant-message.component.mjs +433 -0
  10. package/dist/esm2022/components/chat/copilot-chat-assistant-message.types.mjs +2 -0
  11. package/dist/esm2022/components/chat/copilot-chat-audio-recorder.component.mjs +202 -0
  12. package/dist/esm2022/components/chat/copilot-chat-buttons.component.mjs +321 -0
  13. package/dist/esm2022/components/chat/copilot-chat-input-defaults.mjs +38 -0
  14. package/dist/esm2022/components/chat/copilot-chat-input.component.mjs +666 -0
  15. package/dist/esm2022/components/chat/copilot-chat-input.types.mjs +10 -0
  16. package/dist/esm2022/components/chat/copilot-chat-message-view-cursor.component.mjs +45 -0
  17. package/dist/esm2022/components/chat/copilot-chat-message-view.component.mjs +296 -0
  18. package/dist/esm2022/components/chat/copilot-chat-message-view.types.mjs +2 -0
  19. package/dist/esm2022/components/chat/copilot-chat-textarea.component.mjs +188 -0
  20. package/dist/esm2022/components/chat/copilot-chat-tool-calls-view.component.mjs +216 -0
  21. package/dist/esm2022/components/chat/copilot-chat-toolbar.component.mjs +25 -0
  22. package/dist/esm2022/components/chat/copilot-chat-tools-menu.component.mjs +199 -0
  23. package/dist/esm2022/components/chat/copilot-chat-user-message-branch-navigation.component.mjs +137 -0
  24. package/dist/esm2022/components/chat/copilot-chat-user-message-buttons.component.mjs +207 -0
  25. package/dist/esm2022/components/chat/copilot-chat-user-message-renderer.component.mjs +35 -0
  26. package/dist/esm2022/components/chat/copilot-chat-user-message-toolbar.component.mjs +34 -0
  27. package/dist/esm2022/components/chat/copilot-chat-user-message.component.mjs +341 -0
  28. package/dist/esm2022/components/chat/copilot-chat-user-message.types.mjs +2 -0
  29. package/dist/esm2022/components/chat/copilot-chat-view-disclaimer.component.mjs +52 -0
  30. package/dist/esm2022/components/chat/copilot-chat-view-feather.component.mjs +55 -0
  31. package/dist/esm2022/components/chat/copilot-chat-view-handlers.service.mjs +19 -0
  32. package/dist/esm2022/components/chat/copilot-chat-view-input-container.component.mjs +110 -0
  33. package/dist/esm2022/components/chat/copilot-chat-view-scroll-to-bottom-button.component.mjs +93 -0
  34. package/dist/esm2022/components/chat/copilot-chat-view-scroll-view.component.mjs +443 -0
  35. package/dist/esm2022/components/chat/copilot-chat-view.component.mjs +479 -0
  36. package/dist/esm2022/components/chat/copilot-chat-view.types.mjs +2 -0
  37. package/dist/esm2022/components/chat/copilot-chat.component.mjs +214 -0
  38. package/dist/esm2022/components/copilotkit-tool-render.component.mjs +153 -0
  39. package/dist/esm2022/copilotkitnext-angular.mjs +5 -0
  40. package/dist/esm2022/core/chat-configuration/chat-configuration.providers.mjs +65 -0
  41. package/dist/esm2022/core/chat-configuration/chat-configuration.service.mjs +145 -0
  42. package/dist/esm2022/core/chat-configuration/chat-configuration.types.mjs +26 -0
  43. package/dist/esm2022/core/copilotkit.providers.mjs +34 -0
  44. package/dist/esm2022/core/copilotkit.service.mjs +430 -0
  45. package/dist/esm2022/core/copilotkit.types.mjs +12 -0
  46. package/dist/esm2022/directives/copilotkit-agent-context.directive.mjs +130 -0
  47. package/dist/esm2022/directives/copilotkit-agent.directive.mjs +217 -0
  48. package/dist/esm2022/directives/copilotkit-chat-config.directive.mjs +218 -0
  49. package/dist/esm2022/directives/copilotkit-config.directive.mjs +94 -0
  50. package/dist/esm2022/directives/copilotkit-frontend-tool.directive.mjs +130 -0
  51. package/dist/esm2022/directives/copilotkit-human-in-the-loop.directive.mjs +266 -0
  52. package/dist/esm2022/directives/stick-to-bottom.directive.mjs +181 -0
  53. package/dist/esm2022/index.mjs +70 -0
  54. package/dist/esm2022/lib/directives/tooltip.directive.mjs +211 -0
  55. package/dist/esm2022/lib/slots/copilot-slot.component.mjs +144 -0
  56. package/dist/esm2022/lib/slots/slot.types.mjs +6 -0
  57. package/dist/esm2022/lib/slots/slot.utils.mjs +222 -0
  58. package/dist/esm2022/lib/utils.mjs +10 -0
  59. package/dist/esm2022/services/resize-observer.service.mjs +152 -0
  60. package/dist/esm2022/services/scroll-position.service.mjs +124 -0
  61. package/dist/esm2022/types/frontend-tool.mjs +2 -0
  62. package/dist/esm2022/types/human-in-the-loop.mjs +2 -0
  63. package/dist/esm2022/utils/agent-context.utils.mjs +114 -0
  64. package/dist/esm2022/utils/agent.utils.mjs +204 -0
  65. package/dist/esm2022/utils/chat-config.utils.mjs +186 -0
  66. package/dist/esm2022/utils/copilotkit.utils.mjs +20 -0
  67. package/dist/esm2022/utils/frontend-tool.utils.mjs +228 -0
  68. package/dist/esm2022/utils/human-in-the-loop.utils.mjs +296 -0
  69. package/dist/fesm2022/copilotkitnext-angular.mjs +163 -164
  70. package/dist/fesm2022/copilotkitnext-angular.mjs.map +1 -1
  71. package/dist/styles.css +0 -27
  72. package/package.json +23 -20
  73. package/vitest.config.mts +32 -21
  74. package/.turbo/turbo-build.log +0 -39
  75. package/.turbo/turbo-check-types.log +0 -0
  76. package/.turbo/turbo-test.log +0 -71
  77. package/README-agent-context.md +0 -310
  78. package/ng-package.json +0 -19
  79. package/slots.md +0 -331
  80. package/src/components/chat/__tests__/copilot-chat-assistant-message.component.spec.ts +0 -282
  81. package/src/components/chat/__tests__/copilot-chat-input.component.spec.ts +0 -419
  82. package/src/components/chat/__tests__/copilot-chat-message-view.component.spec.ts +0 -372
  83. package/src/components/chat/__tests__/copilot-chat-user-message.component.spec.ts +0 -249
  84. package/src/components/chat/copilot-chat-assistant-message-buttons.component.ts +0 -292
  85. package/src/components/chat/copilot-chat-assistant-message-renderer.component.ts +0 -472
  86. package/src/components/chat/copilot-chat-assistant-message-toolbar.component.ts +0 -29
  87. package/src/components/chat/copilot-chat-assistant-message.component.ts +0 -463
  88. package/src/components/chat/copilot-chat-assistant-message.types.ts +0 -50
  89. package/src/components/chat/copilot-chat-audio-recorder.component.ts +0 -241
  90. package/src/components/chat/copilot-chat-buttons.component.ts +0 -308
  91. package/src/components/chat/copilot-chat-buttons.component.ts.bak +0 -471
  92. package/src/components/chat/copilot-chat-input-defaults.ts +0 -47
  93. package/src/components/chat/copilot-chat-input.component.ts +0 -512
  94. package/src/components/chat/copilot-chat-input.types.ts +0 -148
  95. package/src/components/chat/copilot-chat-message-view-cursor.component.ts +0 -51
  96. package/src/components/chat/copilot-chat-message-view.component.ts +0 -233
  97. package/src/components/chat/copilot-chat-message-view.types.ts +0 -39
  98. package/src/components/chat/copilot-chat-textarea.component.ts +0 -220
  99. package/src/components/chat/copilot-chat-tool-calls-view.component.ts +0 -261
  100. package/src/components/chat/copilot-chat-toolbar.component.ts +0 -35
  101. package/src/components/chat/copilot-chat-tools-menu.component.ts +0 -185
  102. package/src/components/chat/copilot-chat-user-message-branch-navigation.component.ts +0 -121
  103. package/src/components/chat/copilot-chat-user-message-buttons.component.ts +0 -170
  104. package/src/components/chat/copilot-chat-user-message-renderer.component.ts +0 -37
  105. package/src/components/chat/copilot-chat-user-message-toolbar.component.ts +0 -37
  106. package/src/components/chat/copilot-chat-user-message.component.ts +0 -247
  107. package/src/components/chat/copilot-chat-user-message.types.ts +0 -42
  108. package/src/components/chat/copilot-chat-view-disclaimer.component.ts +0 -51
  109. package/src/components/chat/copilot-chat-view-feather.component.ts +0 -47
  110. package/src/components/chat/copilot-chat-view-handlers.service.ts +0 -14
  111. package/src/components/chat/copilot-chat-view-input-container.component.ts +0 -87
  112. package/src/components/chat/copilot-chat-view-scroll-to-bottom-button.component.ts +0 -79
  113. package/src/components/chat/copilot-chat-view-scroll-view.component.ts +0 -322
  114. package/src/components/chat/copilot-chat-view.component.ts +0 -420
  115. package/src/components/chat/copilot-chat-view.types.ts +0 -52
  116. package/src/components/chat/copilot-chat.component.ts +0 -232
  117. package/src/components/copilotkit-tool-render.component.ts +0 -169
  118. package/src/core/__tests__/copilotkit.service.spec.ts +0 -1051
  119. package/src/core/__tests__/copilotkit.service.wildcard.spec.ts +0 -316
  120. package/src/core/chat-configuration/__tests__/chat-configuration.service.spec.ts +0 -287
  121. package/src/core/chat-configuration/chat-configuration.providers.ts +0 -71
  122. package/src/core/chat-configuration/chat-configuration.service.ts +0 -162
  123. package/src/core/chat-configuration/chat-configuration.types.ts +0 -57
  124. package/src/core/copilotkit.providers.ts +0 -59
  125. package/src/core/copilotkit.service.ts +0 -542
  126. package/src/core/copilotkit.types.ts +0 -132
  127. package/src/directives/__tests__/copilotkit-agent-context.directive.spec.ts +0 -384
  128. package/src/directives/__tests__/copilotkit-agent.directive.spec.ts +0 -253
  129. package/src/directives/__tests__/copilotkit-chat-config.directive.spec.ts +0 -385
  130. package/src/directives/__tests__/copilotkit-config.directive.spec.ts +0 -69
  131. package/src/directives/__tests__/copilotkit-frontend-tool-simple.directive.spec.ts +0 -60
  132. package/src/directives/__tests__/copilotkit-frontend-tool.directive.spec.ts +0 -108
  133. package/src/directives/__tests__/copilotkit-human-in-the-loop.directive.spec.ts +0 -452
  134. package/src/directives/copilotkit-agent-context.directive.ts +0 -138
  135. package/src/directives/copilotkit-agent.directive.ts +0 -225
  136. package/src/directives/copilotkit-chat-config.directive.ts +0 -241
  137. package/src/directives/copilotkit-config.directive.ts +0 -81
  138. package/src/directives/copilotkit-frontend-tool.directive.ts +0 -145
  139. package/src/directives/copilotkit-human-in-the-loop.directive.ts +0 -281
  140. package/src/directives/stick-to-bottom.directive.ts +0 -204
  141. package/src/index.ts +0 -105
  142. package/src/lib/directives/tooltip.directive.ts +0 -292
  143. package/src/lib/slots/__tests__/slot.utils.spec.ts +0 -377
  144. package/src/lib/slots/copilot-slot.component.ts +0 -135
  145. package/src/lib/slots/index.ts +0 -3
  146. package/src/lib/slots/slot.types.ts +0 -64
  147. package/src/lib/slots/slot.utils.ts +0 -289
  148. package/src/lib/utils.ts +0 -10
  149. package/src/public-api.ts +0 -1
  150. package/src/services/resize-observer.service.ts +0 -181
  151. package/src/services/scroll-position.service.ts +0 -169
  152. package/src/styles/globals.css +0 -266
  153. package/src/styles/index.css +0 -3
  154. package/src/test-setup.ts +0 -15
  155. package/src/testing/index.ts +0 -3
  156. package/src/testing/testing.utils.ts +0 -248
  157. package/src/types/frontend-tool.ts +0 -44
  158. package/src/types/human-in-the-loop.ts +0 -52
  159. package/src/utils/__tests__/agent.utils.spec.ts +0 -234
  160. package/src/utils/__tests__/chat-config.utils.spec.ts +0 -306
  161. package/src/utils/__tests__/frontend-tool-inject.spec.ts +0 -350
  162. package/src/utils/__tests__/frontend-tool-integration.spec.ts +0 -199
  163. package/src/utils/__tests__/frontend-tool.utils.spec.ts +0 -272
  164. package/src/utils/__tests__/human-in-the-loop.utils.spec.ts +0 -365
  165. package/src/utils/agent-context.utils.ts +0 -133
  166. package/src/utils/agent.utils.ts +0 -239
  167. package/src/utils/chat-config.utils.ts +0 -221
  168. package/src/utils/copilotkit.utils.ts +0 -20
  169. package/src/utils/frontend-tool.utils.ts +0 -266
  170. package/src/utils/human-in-the-loop.utils.ts +0 -359
  171. package/tsconfig.spec.json +0 -12
@@ -1,512 +0,0 @@
1
- import {
2
- Component,
3
- Input,
4
- Output,
5
- EventEmitter,
6
- ViewChild,
7
- TemplateRef,
8
- signal,
9
- computed,
10
- effect,
11
- inject,
12
- ChangeDetectionStrategy,
13
- AfterViewInit,
14
- OnDestroy,
15
- Type,
16
- ViewEncapsulation,
17
- ContentChild
18
- } from '@angular/core';
19
- import { CommonModule } from '@angular/common';
20
- import { CopilotSlotComponent } from '../../lib/slots/copilot-slot.component';
21
- import { CopilotChatConfigurationService } from '../../core/chat-configuration/chat-configuration.service';
22
- import { LucideAngularModule, ArrowUp } from 'lucide-angular';
23
- import { CopilotChatTextareaComponent } from './copilot-chat-textarea.component';
24
- import { CopilotChatAudioRecorderComponent } from './copilot-chat-audio-recorder.component';
25
- import {
26
- CopilotChatSendButtonComponent,
27
- CopilotChatStartTranscribeButtonComponent,
28
- CopilotChatCancelTranscribeButtonComponent,
29
- CopilotChatFinishTranscribeButtonComponent,
30
- CopilotChatAddFileButtonComponent
31
- } from './copilot-chat-buttons.component';
32
- import { CopilotChatToolbarComponent } from './copilot-chat-toolbar.component';
33
- import { CopilotChatToolsMenuComponent } from './copilot-chat-tools-menu.component';
34
- import type {
35
- CopilotChatInputMode,
36
- ToolsMenuItem
37
- } from './copilot-chat-input.types';
38
- import { cn } from '../../lib/utils';
39
-
40
- /**
41
- * Context provided to slot templates
42
- */
43
- export interface SendButtonContext {
44
- send: () => void;
45
- disabled: boolean;
46
- value: string;
47
- }
48
-
49
- export interface ToolbarContext {
50
- mode: CopilotChatInputMode;
51
- value: string;
52
- }
53
-
54
- @Component({
55
- selector: 'copilot-chat-input',
56
- standalone: true,
57
- imports: [
58
- CommonModule,
59
- CopilotSlotComponent,
60
- LucideAngularModule,
61
- CopilotChatTextareaComponent,
62
- CopilotChatAudioRecorderComponent,
63
- CopilotChatSendButtonComponent,
64
- CopilotChatStartTranscribeButtonComponent,
65
- CopilotChatCancelTranscribeButtonComponent,
66
- CopilotChatFinishTranscribeButtonComponent,
67
- CopilotChatAddFileButtonComponent,
68
- CopilotChatToolbarComponent,
69
- CopilotChatToolsMenuComponent
70
- ],
71
- changeDetection: ChangeDetectionStrategy.OnPush,
72
- encapsulation: ViewEncapsulation.None,
73
- template: `
74
- <div [class]="computedClass()">
75
- <!-- Main input area: either textarea or audio recorder -->
76
- @if (computedMode() === 'transcribe') {
77
- @if (audioRecorderTemplate || audioRecorderComponent) {
78
- <copilot-slot
79
- [slot]="audioRecorderTemplate || audioRecorderComponent"
80
- [context]="audioRecorderContext()"
81
- [defaultComponent]="defaultAudioRecorder"
82
- >
83
- </copilot-slot>
84
- } @else {
85
- <copilot-chat-audio-recorder
86
- [inputShowControls]="true">
87
- </copilot-chat-audio-recorder>
88
- }
89
- } @else {
90
- @if (textAreaTemplate || textAreaComponent) {
91
- <copilot-slot
92
- [slot]="textAreaTemplate || textAreaComponent"
93
- [context]="textAreaContext()"
94
- >
95
- </copilot-slot>
96
- } @else {
97
- <textarea copilotChatTextarea
98
- [inputValue]="computedValue()"
99
- [inputAutoFocus]="computedAutoFocus()"
100
- [inputDisabled]="computedMode() === 'processing'"
101
- [inputClass]="textAreaClass"
102
- [inputMaxRows]="textAreaMaxRows"
103
- [inputPlaceholder]="textAreaPlaceholder"
104
- (keyDown)="handleKeyDown($event)"
105
- (valueChange)="handleValueChange($event)"></textarea>
106
- }
107
- }
108
-
109
- <!-- Toolbar -->
110
- @if (toolbarTemplate || toolbarComponent) {
111
- <copilot-slot
112
- [slot]="toolbarTemplate || toolbarComponent"
113
- [context]="toolbarContext()"
114
- [defaultComponent]="CopilotChatToolbarComponent"
115
- >
116
- </copilot-slot>
117
- } @else {
118
- <div copilotChatToolbar>
119
- <div class="flex items-center">
120
- @if (addFile.observed) {
121
- @if (addFileButtonTemplate || addFileButtonComponent) {
122
- <copilot-slot
123
- [slot]="addFileButtonTemplate || addFileButtonComponent"
124
- [context]="{ inputDisabled: computedMode() === 'transcribe' }"
125
- [outputs]="addFileButtonOutputs"
126
- [defaultComponent]="CopilotChatAddFileButtonComponent"
127
- >
128
- </copilot-slot>
129
- } @else {
130
- <copilot-chat-add-file-button
131
- [disabled]="computedMode() === 'transcribe'"
132
- (clicked)="handleAddFile()">
133
- </copilot-chat-add-file-button>
134
- }
135
- }
136
- @if (computedToolsMenu().length > 0) {
137
- @if (toolsButtonTemplate || toolsButtonComponent) {
138
- <copilot-slot
139
- [slot]="toolsButtonTemplate || toolsButtonComponent"
140
- [context]="toolsContext()"
141
- [defaultComponent]="CopilotChatToolsMenuComponent"
142
- >
143
- </copilot-slot>
144
- } @else {
145
- <copilot-chat-tools-menu
146
- [inputToolsMenu]="computedToolsMenu()"
147
- [inputDisabled]="computedMode() === 'transcribe'">
148
- </copilot-chat-tools-menu>
149
- }
150
- }
151
- @if (additionalToolbarItems) {
152
- <ng-container *ngTemplateOutlet="additionalToolbarItems"></ng-container>
153
- }
154
- </div>
155
- <div class="flex items-center">
156
- @if (computedMode() === 'transcribe') {
157
- @if (cancelTranscribe.observed) {
158
- @if (cancelTranscribeButtonTemplate || cancelTranscribeButtonComponent) {
159
- <copilot-slot
160
- [slot]="cancelTranscribeButtonTemplate || cancelTranscribeButtonComponent"
161
- [context]="{}"
162
- [outputs]="cancelTranscribeButtonOutputs"
163
- [defaultComponent]="CopilotChatCancelTranscribeButtonComponent"
164
- >
165
- </copilot-slot>
166
- } @else {
167
- <copilot-chat-cancel-transcribe-button
168
- (clicked)="handleCancelTranscribe()">
169
- </copilot-chat-cancel-transcribe-button>
170
- }
171
- }
172
- @if (finishTranscribe.observed) {
173
- @if (finishTranscribeButtonTemplate || finishTranscribeButtonComponent) {
174
- <copilot-slot
175
- [slot]="finishTranscribeButtonTemplate || finishTranscribeButtonComponent"
176
- [context]="{}"
177
- [outputs]="finishTranscribeButtonOutputs"
178
- [defaultComponent]="CopilotChatFinishTranscribeButtonComponent"
179
- >
180
- </copilot-slot>
181
- } @else {
182
- <copilot-chat-finish-transcribe-button
183
- (clicked)="handleFinishTranscribe()">
184
- </copilot-chat-finish-transcribe-button>
185
- }
186
- }
187
- } @else {
188
- @if (startTranscribe.observed) {
189
- @if (startTranscribeButtonTemplate || startTranscribeButtonComponent) {
190
- <copilot-slot
191
- [slot]="startTranscribeButtonTemplate || startTranscribeButtonComponent"
192
- [context]="{}"
193
- [outputs]="startTranscribeButtonOutputs"
194
- [defaultComponent]="CopilotChatStartTranscribeButtonComponent"
195
- >
196
- </copilot-slot>
197
- } @else {
198
- <copilot-chat-start-transcribe-button
199
- (clicked)="handleStartTranscribe()">
200
- </copilot-chat-start-transcribe-button>
201
- }
202
- }
203
- <!-- Send button with slot -->
204
- @if (sendButtonTemplate || sendButtonComponent) {
205
- <copilot-slot
206
- [slot]="sendButtonTemplate || sendButtonComponent"
207
- [context]="sendButtonContext()"
208
- [outputs]="sendButtonOutputs"
209
- >
210
- </copilot-slot>
211
- } @else {
212
- <div class="mr-[10px]">
213
- <button
214
- type="button"
215
- [class]="sendButtonClass || defaultButtonClass"
216
- [disabled]="!computedValue().trim() || computedMode() === 'processing'"
217
- (click)="send()">
218
- <lucide-angular [img]="ArrowUpIcon" [size]="18"></lucide-angular>
219
- </button>
220
- </div>
221
- }
222
- }
223
- </div>
224
- </div>
225
- }
226
- </div>
227
- `,
228
- styles: [`
229
- :host {
230
- display: block;
231
- width: 100%;
232
- }
233
- .shadow-\\[0_4px_4px_0_\\#0000000a\\2c_0_0_1px_0_\\#0000009e\\] {
234
- box-shadow: 0 4px 4px 0 #0000000a, 0 0 1px 0 #0000009e !important;
235
- }
236
- `]
237
- })
238
- export class CopilotChatInputComponent implements AfterViewInit, OnDestroy {
239
- @ViewChild(CopilotChatTextareaComponent, { read: CopilotChatTextareaComponent })
240
- textAreaRef?: CopilotChatTextareaComponent;
241
-
242
- @ViewChild(CopilotChatAudioRecorderComponent)
243
- audioRecorderRef?: CopilotChatAudioRecorderComponent;
244
-
245
- // Capture templates from content projection
246
- @ContentChild('sendButton', { read: TemplateRef }) sendButtonTemplate?: TemplateRef<SendButtonContext>;
247
- @ContentChild('toolbar', { read: TemplateRef }) toolbarTemplate?: TemplateRef<ToolbarContext>;
248
- @ContentChild('textArea', { read: TemplateRef }) textAreaTemplate?: TemplateRef<any>;
249
- @ContentChild('audioRecorder', { read: TemplateRef }) audioRecorderTemplate?: TemplateRef<any>;
250
- @ContentChild('startTranscribeButton', { read: TemplateRef }) startTranscribeButtonTemplate?: TemplateRef<any>;
251
- @ContentChild('cancelTranscribeButton', { read: TemplateRef }) cancelTranscribeButtonTemplate?: TemplateRef<any>;
252
- @ContentChild('finishTranscribeButton', { read: TemplateRef }) finishTranscribeButtonTemplate?: TemplateRef<any>;
253
- @ContentChild('addFileButton', { read: TemplateRef }) addFileButtonTemplate?: TemplateRef<any>;
254
- @ContentChild('toolsButton', { read: TemplateRef }) toolsButtonTemplate?: TemplateRef<any>;
255
-
256
- // Class inputs for styling default components
257
- @Input() sendButtonClass?: string;
258
- @Input() toolbarClass?: string;
259
- @Input() textAreaClass?: string;
260
- @Input() textAreaMaxRows?: number;
261
- @Input() textAreaPlaceholder?: string;
262
- @Input() audioRecorderClass?: string;
263
- @Input() startTranscribeButtonClass?: string;
264
- @Input() cancelTranscribeButtonClass?: string;
265
- @Input() finishTranscribeButtonClass?: string;
266
- @Input() addFileButtonClass?: string;
267
- @Input() toolsButtonClass?: string;
268
-
269
- // Component inputs for overrides
270
- @Input() sendButtonComponent?: Type<any>;
271
- @Input() toolbarComponent?: Type<any>;
272
- @Input() textAreaComponent?: Type<any>;
273
- @Input() audioRecorderComponent?: Type<any>;
274
- @Input() startTranscribeButtonComponent?: Type<any>;
275
- @Input() cancelTranscribeButtonComponent?: Type<any>;
276
- @Input() finishTranscribeButtonComponent?: Type<any>;
277
- @Input() addFileButtonComponent?: Type<any>;
278
- @Input() toolsButtonComponent?: Type<any>;
279
-
280
- // Regular inputs
281
- @Input() set mode(val: CopilotChatInputMode | undefined) {
282
- this.modeSignal.set(val || 'input');
283
- }
284
- @Input() set toolsMenu(val: (ToolsMenuItem | '-')[] | undefined) {
285
- this.toolsMenuSignal.set(val || []);
286
- }
287
- @Input() set autoFocus(val: boolean | undefined) {
288
- this.autoFocusSignal.set(val ?? true);
289
- }
290
- @Input() set value(val: string | undefined) {
291
- this.valueSignal.set(val || '');
292
- }
293
- @Input() set inputClass(val: string | undefined) {
294
- this.customClass.set(val);
295
- }
296
- // Note: Prefer host `class` for styling this component;
297
- // keep only `inputClass` to style the internal wrapper if needed.
298
- @Input() additionalToolbarItems?: TemplateRef<any>;
299
-
300
- // Output events
301
- @Output() submitMessage = new EventEmitter<string>();
302
- @Output() startTranscribe = new EventEmitter<void>();
303
- @Output() cancelTranscribe = new EventEmitter<void>();
304
- @Output() finishTranscribe = new EventEmitter<void>();
305
- @Output() addFile = new EventEmitter<void>();
306
- @Output() valueChange = new EventEmitter<string>();
307
-
308
- // Icons and default classes
309
- readonly ArrowUpIcon = ArrowUp;
310
- readonly defaultButtonClass = cn(
311
- // Base button styles
312
- 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium',
313
- 'transition-all disabled:pointer-events-none disabled:opacity-50',
314
- 'shrink-0 outline-none',
315
- 'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
316
- // chatInputToolbarPrimary variant
317
- 'cursor-pointer',
318
- 'bg-black text-white',
319
- 'dark:bg-white dark:text-black dark:focus-visible:outline-white',
320
- 'rounded-full h-9 w-9',
321
- 'transition-colors',
322
- 'focus:outline-none',
323
- 'hover:opacity-70 disabled:hover:opacity-100',
324
- 'disabled:cursor-not-allowed disabled:bg-[#00000014] disabled:text-[rgb(13,13,13)]',
325
- 'dark:disabled:bg-[#454545] dark:disabled:text-white'
326
- );
327
-
328
- // Services
329
- private chatConfig = inject(CopilotChatConfigurationService, { optional: true });
330
-
331
- // Signals
332
- modeSignal = signal<CopilotChatInputMode>('input');
333
- toolsMenuSignal = signal<(ToolsMenuItem | '-')[]>([]);
334
- autoFocusSignal = signal<boolean>(true);
335
- valueSignal = signal<string>('');
336
- customClass = signal<string | undefined>(undefined);
337
-
338
- // Default components
339
- // Note: CopilotChatTextareaComponent uses attribute selector but is a component
340
- defaultAudioRecorder = CopilotChatAudioRecorderComponent;
341
- defaultSendButton: any = null; // Will be set to avoid circular dependency
342
- CopilotChatToolbarComponent = CopilotChatToolbarComponent;
343
- CopilotChatAddFileButtonComponent = CopilotChatAddFileButtonComponent;
344
- CopilotChatToolsMenuComponent = CopilotChatToolsMenuComponent;
345
- CopilotChatCancelTranscribeButtonComponent = CopilotChatCancelTranscribeButtonComponent;
346
- CopilotChatFinishTranscribeButtonComponent = CopilotChatFinishTranscribeButtonComponent;
347
- CopilotChatStartTranscribeButtonComponent = CopilotChatStartTranscribeButtonComponent;
348
-
349
- // Computed values
350
- computedMode = computed(() => this.modeSignal());
351
- computedToolsMenu = computed(() => this.toolsMenuSignal());
352
- computedAutoFocus = computed(() => this.autoFocusSignal());
353
- computedValue = computed(() => {
354
- const customValue = this.valueSignal();
355
- const configValue = this.chatConfig?.inputValue();
356
- return customValue || configValue || '';
357
- });
358
-
359
- computedClass = computed(() => {
360
- const baseClasses = cn(
361
- // Layout
362
- 'flex w-full flex-col items-center justify-center',
363
- // Interaction
364
- 'cursor-text',
365
- // Overflow and clipping
366
- 'overflow-visible bg-clip-padding contain-inline-size',
367
- // Background
368
- 'bg-white dark:bg-[#303030]',
369
- // Visual effects
370
- 'shadow-[0_4px_4px_0_#0000000a,0_0_1px_0_#0000009e] rounded-[28px]'
371
- );
372
- return cn(baseClasses, this.customClass());
373
- });
374
-
375
- // Context for slots (reactive via signals)
376
- sendButtonContext = computed<SendButtonContext>(() => ({
377
- send: () => this.send(),
378
- disabled: !this.computedValue().trim() || this.computedMode() === 'processing',
379
- value: this.computedValue()
380
- }));
381
-
382
- toolbarContext = computed<ToolbarContext>(() => ({
383
- mode: this.computedMode(),
384
- value: this.computedValue()
385
- }));
386
-
387
- textAreaContext = computed(() => ({
388
- value: this.computedValue(),
389
- autoFocus: this.computedAutoFocus(),
390
- disabled: this.computedMode() === 'processing',
391
- maxRows: this.textAreaMaxRows,
392
- placeholder: this.textAreaPlaceholder,
393
- inputClass: this.textAreaClass,
394
- onKeyDown: (event: KeyboardEvent) => this.handleKeyDown(event),
395
- onChange: (value: string) => this.handleValueChange(value)
396
- }));
397
-
398
- audioRecorderContext = computed(() => ({
399
- inputShowControls: true
400
- }));
401
-
402
- // Button contexts removed - now using outputs map for click handlers
403
-
404
- toolsContext = computed(() => ({
405
- inputToolsMenu: this.computedToolsMenu(),
406
- inputDisabled: this.computedMode() === 'transcribe'
407
- }));
408
-
409
- constructor() {
410
- // Effect to handle mode changes
411
- effect(() => {
412
- const currentMode = this.computedMode();
413
- if (currentMode === 'transcribe' && this.audioRecorderRef) {
414
- this.audioRecorderRef.start().catch(console.error);
415
- } else if (this.audioRecorderRef?.getState() === 'recording') {
416
- this.audioRecorderRef.stop().catch(console.error);
417
- }
418
- });
419
-
420
- // Sync with chat configuration
421
- effect(() => {
422
- const configValue = this.chatConfig?.inputValue();
423
- if (configValue !== undefined && !this.valueSignal()) {
424
- this.valueSignal.set(configValue);
425
- }
426
- });
427
- }
428
-
429
- // Output maps for slots
430
- addFileButtonOutputs = { clicked: () => this.handleAddFile() };
431
- cancelTranscribeButtonOutputs = { clicked: () => this.handleCancelTranscribe() };
432
- finishTranscribeButtonOutputs = { clicked: () => this.handleFinishTranscribe() };
433
- startTranscribeButtonOutputs = { clicked: () => this.handleStartTranscribe() };
434
- // Support both `clicked` (idiomatic in our slots) and `click` (legacy)
435
- sendButtonOutputs = { clicked: () => this.send(), click: () => this.send() };
436
-
437
- ngAfterViewInit(): void {
438
- // Auto-focus if needed
439
- if (this.computedAutoFocus() && this.textAreaRef) {
440
- setTimeout(() => {
441
- this.textAreaRef?.focus();
442
- });
443
- }
444
- }
445
-
446
- ngOnDestroy(): void {
447
- // Clean up any resources
448
- if (this.audioRecorderRef?.getState() === 'recording') {
449
- this.audioRecorderRef.stop().catch(console.error);
450
- }
451
- }
452
-
453
- handleKeyDown(event: KeyboardEvent): void {
454
- if (event.key === 'Enter' && !event.shiftKey) {
455
- event.preventDefault();
456
- this.send();
457
- }
458
- }
459
-
460
- handleValueChange(value: string): void {
461
- this.valueSignal.set(value);
462
- this.valueChange.emit(value);
463
-
464
- if (this.chatConfig) {
465
- this.chatConfig.setInputValue(value);
466
- }
467
- }
468
-
469
- send(): void {
470
- const trimmed = this.computedValue().trim();
471
- if (trimmed) {
472
- this.submitMessage.emit(trimmed);
473
-
474
- // Use chat config handler if available
475
- if (this.chatConfig) {
476
- this.chatConfig.submitInput(trimmed);
477
- }
478
-
479
- // Clear input
480
- this.valueSignal.set('');
481
- if (this.textAreaRef) {
482
- this.textAreaRef.setValue('');
483
- }
484
-
485
- // Refocus input
486
- if (this.textAreaRef) {
487
- setTimeout(() => {
488
- this.textAreaRef?.focus();
489
- });
490
- }
491
- }
492
- }
493
-
494
- handleStartTranscribe(): void {
495
- this.startTranscribe.emit();
496
- this.modeSignal.set('transcribe');
497
- }
498
-
499
- handleCancelTranscribe(): void {
500
- this.cancelTranscribe.emit();
501
- this.modeSignal.set('input');
502
- }
503
-
504
- handleFinishTranscribe(): void {
505
- this.finishTranscribe.emit();
506
- this.modeSignal.set('input');
507
- }
508
-
509
- handleAddFile(): void {
510
- this.addFile.emit();
511
- }
512
- }
@@ -1,148 +0,0 @@
1
- import type { Type, TemplateRef } from '@angular/core';
2
-
3
- /**
4
- * Mode of the chat input component
5
- */
6
- export type CopilotChatInputMode = 'input' | 'transcribe' | 'processing';
7
-
8
- /**
9
- * Represents a menu item in the tools menu
10
- */
11
- export type ToolsMenuItem = {
12
- label: string;
13
- } & (
14
- | {
15
- action: () => void;
16
- items?: never;
17
- }
18
- | {
19
- action?: never;
20
- items: (ToolsMenuItem | '-')[];
21
- }
22
- );
23
-
24
- /**
25
- * Audio recorder state
26
- */
27
- export type AudioRecorderState = 'idle' | 'recording' | 'processing';
28
-
29
- /**
30
- * Error class for audio recorder failures
31
- */
32
- export class AudioRecorderError extends Error {
33
- constructor(message: string) {
34
- super(message);
35
- this.name = 'AudioRecorderError';
36
- }
37
- }
38
-
39
- /**
40
- * Props for textarea component
41
- */
42
- export interface CopilotChatTextareaProps {
43
- value?: string;
44
- placeholder?: string;
45
- maxRows?: number;
46
- autoFocus?: boolean;
47
- disabled?: boolean;
48
- onChange?: (value: string) => void;
49
- onKeyDown?: (event: KeyboardEvent) => void;
50
- inputClass?: string;
51
- style?: any;
52
- rows?: number;
53
- cols?: number;
54
- readonly?: boolean;
55
- spellcheck?: boolean;
56
- wrap?: 'hard' | 'soft' | 'off';
57
- }
58
-
59
- /**
60
- * Props for button components
61
- */
62
- export interface CopilotChatButtonProps {
63
- disabled?: boolean;
64
- onClick?: () => void;
65
- inputClass?: string;
66
- style?: any;
67
- type?: 'button' | 'submit' | 'reset';
68
- ariaLabel?: string;
69
- ariaPressed?: boolean;
70
- ariaExpanded?: boolean;
71
- title?: string;
72
- }
73
-
74
- /**
75
- * Props for toolbar button with tooltip
76
- */
77
- export interface CopilotChatToolbarButtonProps extends CopilotChatButtonProps {
78
- icon?: TemplateRef<any>;
79
- tooltip?: string;
80
- variant?: 'primary' | 'secondary';
81
- }
82
-
83
- /**
84
- * Props for tools menu button
85
- */
86
- export interface CopilotChatToolsButtonProps extends CopilotChatButtonProps {
87
- toolsMenu?: (ToolsMenuItem | '-')[];
88
- }
89
-
90
- /**
91
- * Props for audio recorder
92
- */
93
- export interface CopilotChatAudioRecorderProps {
94
- inputClass?: string;
95
- style?: any;
96
- onStateChange?: (state: AudioRecorderState) => void;
97
- showControls?: boolean;
98
- maxDuration?: number;
99
- }
100
-
101
- /**
102
- * Props for toolbar
103
- */
104
- export interface CopilotChatToolbarProps {
105
- inputClass?: string;
106
- style?: any;
107
- position?: 'top' | 'bottom';
108
- alignment?: 'left' | 'center' | 'right' | 'space-between';
109
- }
110
-
111
- /**
112
- * Slot configuration for chat input
113
- */
114
- export interface CopilotChatInputSlots {
115
- textArea?: Type<any> | TemplateRef<any>;
116
- sendButton?: Type<any> | TemplateRef<any>;
117
- startTranscribeButton?: Type<any> | TemplateRef<any>;
118
- cancelTranscribeButton?: Type<any> | TemplateRef<any>;
119
- finishTranscribeButton?: Type<any> | TemplateRef<any>;
120
- addFileButton?: Type<any> | TemplateRef<any>;
121
- toolsButton?: Type<any> | TemplateRef<any>;
122
- toolbar?: Type<any> | TemplateRef<any>;
123
- audioRecorder?: Type<any> | TemplateRef<any>;
124
- }
125
-
126
- /**
127
- * Input configuration for the chat input component
128
- */
129
- export interface CopilotChatInputConfig {
130
- mode?: CopilotChatInputMode;
131
- toolsMenu?: (ToolsMenuItem | '-')[];
132
- autoFocus?: boolean;
133
- additionalToolbarItems?: TemplateRef<any>;
134
- value?: string;
135
- class?: string;
136
- }
137
-
138
- /**
139
- * Output events for the chat input component
140
- */
141
- export interface CopilotChatInputOutputs {
142
- submitMessage: (value: string) => void;
143
- startTranscribe: () => void;
144
- cancelTranscribe: () => void;
145
- finishTranscribe: () => void;
146
- addFile: () => void;
147
- changeValue: (value: string) => void;
148
- }