@copilotkitnext/angular 0.0.2 → 0.0.5

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 (173) hide show
  1. package/README.md +3 -3
  2. package/dist/README.md +3 -3
  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/core/copilotkit.providers.d.ts +1 -1
  7. package/dist/core/copilotkit.service.d.ts +5 -5
  8. package/dist/core/copilotkit.types.d.ts +8 -10
  9. package/dist/directives/copilotkit-frontend-tool.directive.d.ts +1 -1
  10. package/dist/esm2022/components/chat/copilot-chat-assistant-message-buttons.component.mjs +384 -0
  11. package/dist/esm2022/components/chat/copilot-chat-assistant-message-renderer.component.mjs +286 -0
  12. package/dist/esm2022/components/chat/copilot-chat-assistant-message-toolbar.component.mjs +27 -0
  13. package/dist/esm2022/components/chat/copilot-chat-assistant-message.component.mjs +433 -0
  14. package/dist/esm2022/components/chat/copilot-chat-assistant-message.types.mjs +2 -0
  15. package/dist/esm2022/components/chat/copilot-chat-audio-recorder.component.mjs +202 -0
  16. package/dist/esm2022/components/chat/copilot-chat-buttons.component.mjs +321 -0
  17. package/dist/esm2022/components/chat/copilot-chat-input-defaults.mjs +38 -0
  18. package/dist/esm2022/components/chat/copilot-chat-input.component.mjs +666 -0
  19. package/dist/esm2022/components/chat/copilot-chat-input.types.mjs +10 -0
  20. package/dist/esm2022/components/chat/copilot-chat-message-view-cursor.component.mjs +45 -0
  21. package/dist/esm2022/components/chat/copilot-chat-message-view.component.mjs +296 -0
  22. package/dist/esm2022/components/chat/copilot-chat-message-view.types.mjs +2 -0
  23. package/dist/esm2022/components/chat/copilot-chat-textarea.component.mjs +188 -0
  24. package/dist/esm2022/components/chat/copilot-chat-tool-calls-view.component.mjs +216 -0
  25. package/dist/esm2022/components/chat/copilot-chat-toolbar.component.mjs +25 -0
  26. package/dist/esm2022/components/chat/copilot-chat-tools-menu.component.mjs +199 -0
  27. package/dist/esm2022/components/chat/copilot-chat-user-message-branch-navigation.component.mjs +137 -0
  28. package/dist/esm2022/components/chat/copilot-chat-user-message-buttons.component.mjs +207 -0
  29. package/dist/esm2022/components/chat/copilot-chat-user-message-renderer.component.mjs +35 -0
  30. package/dist/esm2022/components/chat/copilot-chat-user-message-toolbar.component.mjs +34 -0
  31. package/dist/esm2022/components/chat/copilot-chat-user-message.component.mjs +341 -0
  32. package/dist/esm2022/components/chat/copilot-chat-user-message.types.mjs +2 -0
  33. package/dist/esm2022/components/chat/copilot-chat-view-disclaimer.component.mjs +52 -0
  34. package/dist/esm2022/components/chat/copilot-chat-view-feather.component.mjs +55 -0
  35. package/dist/esm2022/components/chat/copilot-chat-view-handlers.service.mjs +19 -0
  36. package/dist/esm2022/components/chat/copilot-chat-view-input-container.component.mjs +110 -0
  37. package/dist/esm2022/components/chat/copilot-chat-view-scroll-to-bottom-button.component.mjs +93 -0
  38. package/dist/esm2022/components/chat/copilot-chat-view-scroll-view.component.mjs +443 -0
  39. package/dist/esm2022/components/chat/copilot-chat-view.component.mjs +479 -0
  40. package/dist/esm2022/components/chat/copilot-chat-view.types.mjs +2 -0
  41. package/dist/esm2022/components/chat/copilot-chat.component.mjs +214 -0
  42. package/dist/esm2022/components/copilotkit-tool-render.component.mjs +153 -0
  43. package/dist/esm2022/copilotkitnext-angular.mjs +5 -0
  44. package/dist/esm2022/core/chat-configuration/chat-configuration.providers.mjs +65 -0
  45. package/dist/esm2022/core/chat-configuration/chat-configuration.service.mjs +145 -0
  46. package/dist/esm2022/core/chat-configuration/chat-configuration.types.mjs +26 -0
  47. package/dist/esm2022/core/copilotkit.providers.mjs +34 -0
  48. package/dist/esm2022/core/copilotkit.service.mjs +426 -0
  49. package/dist/esm2022/core/copilotkit.types.mjs +13 -0
  50. package/dist/esm2022/directives/copilotkit-agent-context.directive.mjs +130 -0
  51. package/dist/esm2022/directives/copilotkit-agent.directive.mjs +217 -0
  52. package/dist/esm2022/directives/copilotkit-chat-config.directive.mjs +218 -0
  53. package/dist/esm2022/directives/copilotkit-config.directive.mjs +94 -0
  54. package/dist/esm2022/directives/copilotkit-frontend-tool.directive.mjs +128 -0
  55. package/dist/esm2022/directives/copilotkit-human-in-the-loop.directive.mjs +265 -0
  56. package/dist/esm2022/directives/stick-to-bottom.directive.mjs +181 -0
  57. package/dist/esm2022/index.mjs +70 -0
  58. package/dist/esm2022/lib/directives/tooltip.directive.mjs +211 -0
  59. package/dist/esm2022/lib/slots/copilot-slot.component.mjs +144 -0
  60. package/dist/esm2022/lib/slots/slot.types.mjs +6 -0
  61. package/dist/esm2022/lib/slots/slot.utils.mjs +222 -0
  62. package/dist/esm2022/lib/utils.mjs +10 -0
  63. package/dist/esm2022/services/resize-observer.service.mjs +152 -0
  64. package/dist/esm2022/services/scroll-position.service.mjs +124 -0
  65. package/dist/esm2022/types/frontend-tool.mjs +2 -0
  66. package/dist/esm2022/types/human-in-the-loop.mjs +2 -0
  67. package/dist/esm2022/utils/agent-context.utils.mjs +114 -0
  68. package/dist/esm2022/utils/agent.utils.mjs +204 -0
  69. package/dist/esm2022/utils/chat-config.utils.mjs +186 -0
  70. package/dist/esm2022/utils/copilotkit.utils.mjs +20 -0
  71. package/dist/esm2022/utils/frontend-tool.utils.mjs +224 -0
  72. package/dist/esm2022/utils/human-in-the-loop.utils.mjs +293 -0
  73. package/dist/fesm2022/copilotkitnext-angular.mjs +174 -187
  74. package/dist/fesm2022/copilotkitnext-angular.mjs.map +1 -1
  75. package/dist/utils/frontend-tool.utils.d.ts +1 -1
  76. package/package.json +23 -20
  77. package/vitest.config.mts +32 -21
  78. package/.turbo/turbo-build.log +0 -38
  79. package/.turbo/turbo-check-types.log +0 -0
  80. package/.turbo/turbo-test.log +0 -71
  81. package/ng-package.json +0 -19
  82. package/src/components/chat/__tests__/copilot-chat-assistant-message.component.spec.ts +0 -282
  83. package/src/components/chat/__tests__/copilot-chat-input.component.spec.ts +0 -419
  84. package/src/components/chat/__tests__/copilot-chat-message-view.component.spec.ts +0 -372
  85. package/src/components/chat/__tests__/copilot-chat-user-message.component.spec.ts +0 -249
  86. package/src/components/chat/copilot-chat-assistant-message-buttons.component.ts +0 -292
  87. package/src/components/chat/copilot-chat-assistant-message-renderer.component.ts +0 -472
  88. package/src/components/chat/copilot-chat-assistant-message-toolbar.component.ts +0 -29
  89. package/src/components/chat/copilot-chat-assistant-message.component.ts +0 -463
  90. package/src/components/chat/copilot-chat-assistant-message.types.ts +0 -50
  91. package/src/components/chat/copilot-chat-audio-recorder.component.ts +0 -241
  92. package/src/components/chat/copilot-chat-buttons.component.ts +0 -308
  93. package/src/components/chat/copilot-chat-buttons.component.ts.bak +0 -471
  94. package/src/components/chat/copilot-chat-input-defaults.ts +0 -47
  95. package/src/components/chat/copilot-chat-input.component.ts +0 -512
  96. package/src/components/chat/copilot-chat-input.types.ts +0 -148
  97. package/src/components/chat/copilot-chat-message-view-cursor.component.ts +0 -51
  98. package/src/components/chat/copilot-chat-message-view.component.ts +0 -233
  99. package/src/components/chat/copilot-chat-message-view.types.ts +0 -39
  100. package/src/components/chat/copilot-chat-textarea.component.ts +0 -220
  101. package/src/components/chat/copilot-chat-tool-calls-view.component.ts +0 -261
  102. package/src/components/chat/copilot-chat-toolbar.component.ts +0 -35
  103. package/src/components/chat/copilot-chat-tools-menu.component.ts +0 -185
  104. package/src/components/chat/copilot-chat-user-message-branch-navigation.component.ts +0 -121
  105. package/src/components/chat/copilot-chat-user-message-buttons.component.ts +0 -170
  106. package/src/components/chat/copilot-chat-user-message-renderer.component.ts +0 -37
  107. package/src/components/chat/copilot-chat-user-message-toolbar.component.ts +0 -37
  108. package/src/components/chat/copilot-chat-user-message.component.ts +0 -247
  109. package/src/components/chat/copilot-chat-user-message.types.ts +0 -42
  110. package/src/components/chat/copilot-chat-view-disclaimer.component.ts +0 -51
  111. package/src/components/chat/copilot-chat-view-feather.component.ts +0 -47
  112. package/src/components/chat/copilot-chat-view-handlers.service.ts +0 -14
  113. package/src/components/chat/copilot-chat-view-input-container.component.ts +0 -87
  114. package/src/components/chat/copilot-chat-view-scroll-to-bottom-button.component.ts +0 -79
  115. package/src/components/chat/copilot-chat-view-scroll-view.component.ts +0 -322
  116. package/src/components/chat/copilot-chat-view.component.ts +0 -420
  117. package/src/components/chat/copilot-chat-view.types.ts +0 -52
  118. package/src/components/chat/copilot-chat.component.ts +0 -232
  119. package/src/components/copilotkit-tool-render.component.ts +0 -169
  120. package/src/core/__tests__/copilotkit.service.spec.ts +0 -1051
  121. package/src/core/__tests__/copilotkit.service.wildcard.spec.ts +0 -316
  122. package/src/core/chat-configuration/__tests__/chat-configuration.service.spec.ts +0 -287
  123. package/src/core/chat-configuration/chat-configuration.providers.ts +0 -71
  124. package/src/core/chat-configuration/chat-configuration.service.ts +0 -162
  125. package/src/core/chat-configuration/chat-configuration.types.ts +0 -57
  126. package/src/core/copilotkit.providers.ts +0 -59
  127. package/src/core/copilotkit.service.ts +0 -542
  128. package/src/core/copilotkit.types.ts +0 -132
  129. package/src/directives/__tests__/copilotkit-agent-context.directive.spec.ts +0 -384
  130. package/src/directives/__tests__/copilotkit-agent.directive.spec.ts +0 -253
  131. package/src/directives/__tests__/copilotkit-chat-config.directive.spec.ts +0 -385
  132. package/src/directives/__tests__/copilotkit-config.directive.spec.ts +0 -69
  133. package/src/directives/__tests__/copilotkit-frontend-tool-simple.directive.spec.ts +0 -60
  134. package/src/directives/__tests__/copilotkit-frontend-tool.directive.spec.ts +0 -108
  135. package/src/directives/__tests__/copilotkit-human-in-the-loop.directive.spec.ts +0 -452
  136. package/src/directives/copilotkit-agent-context.directive.ts +0 -138
  137. package/src/directives/copilotkit-agent.directive.ts +0 -225
  138. package/src/directives/copilotkit-chat-config.directive.ts +0 -241
  139. package/src/directives/copilotkit-config.directive.ts +0 -81
  140. package/src/directives/copilotkit-frontend-tool.directive.ts +0 -145
  141. package/src/directives/copilotkit-human-in-the-loop.directive.ts +0 -281
  142. package/src/directives/stick-to-bottom.directive.ts +0 -204
  143. package/src/index.ts +0 -105
  144. package/src/lib/directives/tooltip.directive.ts +0 -292
  145. package/src/lib/slots/__tests__/slot.utils.spec.ts +0 -377
  146. package/src/lib/slots/copilot-slot.component.ts +0 -135
  147. package/src/lib/slots/index.ts +0 -3
  148. package/src/lib/slots/slot.types.ts +0 -64
  149. package/src/lib/slots/slot.utils.ts +0 -289
  150. package/src/lib/utils.ts +0 -10
  151. package/src/public-api.ts +0 -1
  152. package/src/services/resize-observer.service.ts +0 -181
  153. package/src/services/scroll-position.service.ts +0 -169
  154. package/src/styles/globals.css +0 -266
  155. package/src/styles/index.css +0 -3
  156. package/src/test-setup.ts +0 -15
  157. package/src/testing/index.ts +0 -3
  158. package/src/testing/testing.utils.ts +0 -248
  159. package/src/types/frontend-tool.ts +0 -44
  160. package/src/types/human-in-the-loop.ts +0 -52
  161. package/src/utils/__tests__/agent.utils.spec.ts +0 -234
  162. package/src/utils/__tests__/chat-config.utils.spec.ts +0 -306
  163. package/src/utils/__tests__/frontend-tool-inject.spec.ts +0 -350
  164. package/src/utils/__tests__/frontend-tool-integration.spec.ts +0 -199
  165. package/src/utils/__tests__/frontend-tool.utils.spec.ts +0 -272
  166. package/src/utils/__tests__/human-in-the-loop.utils.spec.ts +0 -365
  167. package/src/utils/agent-context.utils.ts +0 -133
  168. package/src/utils/agent.utils.ts +0 -239
  169. package/src/utils/chat-config.utils.ts +0 -221
  170. package/src/utils/copilotkit.utils.ts +0 -20
  171. package/src/utils/frontend-tool.utils.ts +0 -266
  172. package/src/utils/human-in-the-loop.utils.ts +0 -359
  173. package/tsconfig.spec.json +0 -12
@@ -1,87 +0,0 @@
1
- import {
2
- Component,
3
- Input,
4
- ChangeDetectionStrategy,
5
- ViewEncapsulation,
6
- forwardRef,
7
- ElementRef
8
- } from '@angular/core';
9
- import { CommonModule } from '@angular/common';
10
- import { CopilotSlotComponent } from '../../lib/slots/copilot-slot.component';
11
- import { CopilotChatInputComponent } from './copilot-chat-input.component';
12
- import { CopilotChatViewDisclaimerComponent } from './copilot-chat-view-disclaimer.component';
13
- import { cn } from '../../lib/utils';
14
-
15
- /**
16
- * InputContainer component for CopilotChatView
17
- * Container for input and disclaimer components
18
- * Uses ForwardRef for DOM access
19
- */
20
- @Component({
21
- selector: 'copilot-chat-view-input-container',
22
- standalone: true,
23
- imports: [
24
- CommonModule,
25
- CopilotSlotComponent,
26
- CopilotChatInputComponent,
27
- CopilotChatViewDisclaimerComponent
28
- ],
29
- changeDetection: ChangeDetectionStrategy.OnPush,
30
- encapsulation: ViewEncapsulation.None,
31
- providers: [
32
- {
33
- provide: ElementRef,
34
- useExisting: forwardRef(() => CopilotChatViewInputContainerComponent)
35
- }
36
- ],
37
- template: `
38
- <div [class]="computedClass">
39
- <!-- Input component -->
40
- <div class="max-w-3xl mx-auto py-0 px-4 sm:px-0">
41
- <copilot-slot
42
- [slot]="input"
43
- [context]="{ inputClass: inputClass }"
44
- [defaultComponent]="defaultInputComponent">
45
- </copilot-slot>
46
- </div>
47
-
48
- <!-- Disclaimer - always rendered like in React -->
49
- <copilot-slot
50
- [slot]="disclaimer"
51
- [context]="{ text: disclaimerText, inputClass: disclaimerClass }"
52
- [defaultComponent]="defaultDisclaimerComponent">
53
- </copilot-slot>
54
- </div>
55
- `
56
- })
57
- export class CopilotChatViewInputContainerComponent extends ElementRef {
58
- @Input() inputContainerClass?: string;
59
-
60
- // Input slot configuration
61
- @Input() input?: any;
62
- @Input() inputClass?: string;
63
-
64
- // Disclaimer slot configuration
65
- @Input() disclaimer?: any;
66
- @Input() disclaimerText?: string;
67
- @Input() disclaimerClass?: string;
68
-
69
- // Default components
70
- protected readonly defaultInputComponent = CopilotChatInputComponent;
71
- protected readonly defaultDisclaimerComponent = CopilotChatViewDisclaimerComponent;
72
-
73
- constructor(elementRef: ElementRef) {
74
- super(elementRef.nativeElement);
75
- }
76
-
77
-
78
- // Computed class matching React exactly
79
- get computedClass(): string {
80
- return cn(
81
- 'absolute bottom-0 left-0 right-0 z-20',
82
- this.inputContainerClass
83
- );
84
- }
85
-
86
- // Removed mergedInputContext - no longer needed
87
- }
@@ -1,79 +0,0 @@
1
- import {
2
- Component,
3
- Input,
4
- Output,
5
- EventEmitter,
6
- ChangeDetectionStrategy,
7
- ViewEncapsulation
8
- } from '@angular/core';
9
- import { CommonModule } from '@angular/common';
10
- import { LucideAngularModule, ChevronDown } from 'lucide-angular';
11
- import { cn } from '../../lib/utils';
12
-
13
- /**
14
- * ScrollToBottomButton component for CopilotChatView
15
- * Matches React implementation exactly with same Tailwind classes
16
- */
17
- @Component({
18
- selector: 'copilot-chat-view-scroll-to-bottom-button',
19
- standalone: true,
20
- imports: [CommonModule, LucideAngularModule],
21
- changeDetection: ChangeDetectionStrategy.OnPush,
22
- encapsulation: ViewEncapsulation.None,
23
- template: `
24
- <button
25
- type="button"
26
- [class]="computedClass"
27
- [disabled]="disabled"
28
- (click)="handleClick()">
29
- <lucide-angular
30
- [img]="ChevronDown"
31
- class="w-4 h-4 text-gray-600 dark:text-white">
32
- </lucide-angular>
33
- </button>
34
- `
35
- })
36
- export class CopilotChatViewScrollToBottomButtonComponent {
37
- @Input() inputClass?: string;
38
- @Input() disabled: boolean = false;
39
- // Support function-style click handler via slot context
40
- @Input() onClick?: () => void;
41
-
42
- // Simple, idiomatic Angular output
43
- @Output() clicked = new EventEmitter<void>();
44
-
45
- // Icon reference
46
- protected readonly ChevronDown = ChevronDown;
47
-
48
- // Computed class matching React exactly
49
- get computedClass(): string {
50
- return cn(
51
- // Base button styles
52
- 'rounded-full w-10 h-10 p-0',
53
- // Background colors
54
- 'bg-white dark:bg-gray-900',
55
- // Border and shadow
56
- 'shadow-lg border border-gray-200 dark:border-gray-700',
57
- // Hover states
58
- 'hover:bg-gray-50 dark:hover:bg-gray-800',
59
- // Layout
60
- 'flex items-center justify-center cursor-pointer',
61
- // Transition
62
- 'transition-colors',
63
- // Focus states
64
- 'focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2',
65
- // Custom classes
66
- this.inputClass
67
- );
68
- }
69
-
70
- handleClick(): void {
71
- if (!this.disabled) {
72
- // Call input handler if provided (slot-style)
73
- if (this.onClick) {
74
- this.onClick();
75
- }
76
- this.clicked.emit();
77
- }
78
- }
79
- }
@@ -1,322 +0,0 @@
1
- import {
2
- Component,
3
- Input,
4
- Output,
5
- EventEmitter,
6
- ViewChild,
7
- ElementRef,
8
- ChangeDetectionStrategy,
9
- ViewEncapsulation,
10
- signal,
11
- computed,
12
- OnInit,
13
- OnChanges,
14
- AfterViewInit,
15
- OnDestroy,
16
- inject,
17
- PLATFORM_ID,
18
- ChangeDetectorRef
19
- } from '@angular/core';
20
- import { CommonModule, isPlatformBrowser } from '@angular/common';
21
- import { CdkScrollable, ScrollingModule } from '@angular/cdk/scrolling';
22
- import { CopilotSlotComponent } from '../../lib/slots/copilot-slot.component';
23
- import { CopilotChatMessageViewComponent } from './copilot-chat-message-view.component';
24
- import { CopilotChatViewScrollToBottomButtonComponent } from './copilot-chat-view-scroll-to-bottom-button.component';
25
- import { StickToBottomDirective } from '../../directives/stick-to-bottom.directive';
26
- import { ScrollPositionService } from '../../services/scroll-position.service';
27
- import { Message } from '@ag-ui/client';
28
- import { cn } from '../../lib/utils';
29
- import { Subject } from 'rxjs';
30
- import { takeUntil } from 'rxjs/operators';
31
-
32
- /**
33
- * ScrollView component for CopilotChatView
34
- * Handles auto-scrolling and scroll position management
35
- */
36
- @Component({
37
- selector: 'copilot-chat-view-scroll-view',
38
- standalone: true,
39
- imports: [
40
- CommonModule,
41
- ScrollingModule,
42
- CopilotSlotComponent,
43
- CopilotChatMessageViewComponent,
44
- CopilotChatViewScrollToBottomButtonComponent,
45
- StickToBottomDirective
46
- ],
47
- changeDetection: ChangeDetectionStrategy.OnPush,
48
- encapsulation: ViewEncapsulation.None,
49
- providers: [ScrollPositionService],
50
- template: `
51
- @if (!hasMounted()) {
52
- <!-- SSR/Initial render without stick-to-bottom -->
53
- <div class="h-full max-h-full flex flex-col min-h-0 overflow-y-scroll overflow-x-hidden">
54
- <div class="px-4 sm:px-0">
55
- <ng-content></ng-content>
56
- </div>
57
- </div>
58
- } @else if (!autoScroll) {
59
- <!-- Manual scroll mode -->
60
- <div class="h-full max-h-full flex flex-col min-h-0 relative">
61
- <div
62
- #scrollContainer
63
- cdkScrollable
64
- [class]="computedClass()"
65
- class="overflow-y-scroll overflow-x-hidden">
66
- <div #contentContainer class="px-4 sm:px-0">
67
- <!-- Content with padding-bottom matching React -->
68
- <div [style.padding-bottom.px]="paddingBottom()">
69
- <div class="max-w-3xl mx-auto">
70
- @if (messageView) {
71
- <copilot-slot
72
- [slot]="messageView"
73
- [context]="messageViewContext()"
74
- [defaultComponent]="defaultMessageViewComponent">
75
- </copilot-slot>
76
- } @else {
77
- <copilot-chat-message-view
78
- [messages]="messages"
79
- [inputClass]="messageViewClass"
80
- [showCursor]="showCursor"
81
- (assistantMessageThumbsUp)="assistantMessageThumbsUp.emit($event)"
82
- (assistantMessageThumbsDown)="assistantMessageThumbsDown.emit($event)"
83
- (assistantMessageReadAloud)="assistantMessageReadAloud.emit($event)"
84
- (assistantMessageRegenerate)="assistantMessageRegenerate.emit($event)"
85
- (userMessageCopy)="userMessageCopy.emit($event)"
86
- (userMessageEdit)="userMessageEdit.emit($event)">
87
- </copilot-chat-message-view>
88
- }
89
- </div>
90
- </div>
91
- </div>
92
- </div>
93
-
94
- <!-- Scroll to bottom button for manual mode, OUTSIDE scrollable content -->
95
- @if (showScrollButton() && !isResizing) {
96
- <div
97
- class="absolute inset-x-0 flex justify-center z-30"
98
- [style.bottom.px]="inputContainerHeightSignal() + 16">
99
- <copilot-slot
100
- [slot]="scrollToBottomButton"
101
- [context]="scrollToBottomContext()"
102
- [defaultComponent]="defaultScrollToBottomButtonComponent"
103
- [outputs]="scrollToBottomOutputs">
104
- </copilot-slot>
105
- </div>
106
- }
107
- </div>
108
- } @else {
109
- <!-- Auto-scroll mode with StickToBottom directive -->
110
- <div class="h-full max-h-full flex flex-col min-h-0 relative">
111
- <div
112
- #scrollContainer
113
- cdkScrollable
114
- copilotStickToBottom
115
- [enabled]="autoScroll"
116
- [threshold]="10"
117
- [debounceMs]="0"
118
- [initialBehavior]="'smooth'"
119
- [resizeBehavior]="'smooth'"
120
- (isAtBottomChange)="onIsAtBottomChange($event)"
121
- [class]="computedClass()"
122
- class="overflow-y-scroll overflow-x-hidden">
123
-
124
- <!-- Scrollable content wrapper -->
125
- <div class="px-4 sm:px-0">
126
- <!-- Content with padding-bottom matching React -->
127
- <div [style.padding-bottom.px]="paddingBottom()">
128
- <div class="max-w-3xl mx-auto">
129
- @if (messageView) {
130
- <copilot-slot
131
- [slot]="messageView"
132
- [context]="messageViewContext()"
133
- [defaultComponent]="defaultMessageViewComponent">
134
- </copilot-slot>
135
- } @else {
136
- <copilot-chat-message-view
137
- [messages]="messages"
138
- [inputClass]="messageViewClass"
139
- [showCursor]="showCursor"
140
- (assistantMessageThumbsUp)="assistantMessageThumbsUp.emit($event)"
141
- (assistantMessageThumbsDown)="assistantMessageThumbsDown.emit($event)"
142
- (assistantMessageReadAloud)="assistantMessageReadAloud.emit($event)"
143
- (assistantMessageRegenerate)="assistantMessageRegenerate.emit($event)"
144
- (userMessageCopy)="userMessageCopy.emit($event)"
145
- (userMessageEdit)="userMessageEdit.emit($event)">
146
- </copilot-chat-message-view>
147
- }
148
- </div>
149
- </div>
150
- </div>
151
- </div>
152
-
153
- <!-- Scroll to bottom button - hidden during resize, OUTSIDE scrollable content -->
154
- @if (!isAtBottom() && !isResizing) {
155
- <div
156
- class="absolute inset-x-0 flex justify-center z-30"
157
- [style.bottom.px]="inputContainerHeightSignal() + 16">
158
- <copilot-slot
159
- [slot]="scrollToBottomButton"
160
- [context]="scrollToBottomFromStickContext()"
161
- [defaultComponent]="defaultScrollToBottomButtonComponent"
162
- [outputs]="scrollToBottomFromStickOutputs">
163
- </copilot-slot>
164
- </div>
165
- }
166
- </div>
167
- }
168
- `
169
- })
170
- export class CopilotChatViewScrollViewComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
171
- private cdr = inject(ChangeDetectorRef);
172
-
173
- @Input() autoScroll: boolean = true;
174
-
175
- private _inputContainerHeight: number = 0;
176
- @Input()
177
- set inputContainerHeight(value: number) {
178
- this._inputContainerHeight = value;
179
- this.inputContainerHeightSignal.set(value);
180
- this.cdr.markForCheck();
181
- }
182
- get inputContainerHeight(): number {
183
- return this._inputContainerHeight;
184
- }
185
-
186
- @Input() isResizing: boolean = false;
187
- @Input() inputClass?: string;
188
- @Input() messages: Message[] = [];
189
- @Input() messageView?: any;
190
- @Input() messageViewClass?: string;
191
- @Input() showCursor: boolean = false;
192
-
193
- // Handler availability flags removed in favor of DI service
194
-
195
- // Slot inputs
196
- @Input() scrollToBottomButton?: any;
197
- @Input() scrollToBottomButtonClass?: string;
198
-
199
- // Output events (bubbled from message view)
200
- @Output() assistantMessageThumbsUp = new EventEmitter<{ message: Message }>();
201
- @Output() assistantMessageThumbsDown = new EventEmitter<{ message: Message }>();
202
- @Output() assistantMessageReadAloud = new EventEmitter<{ message: Message }>();
203
- @Output() assistantMessageRegenerate = new EventEmitter<{ message: Message }>();
204
- @Output() userMessageCopy = new EventEmitter<{ message: Message }>();
205
- @Output() userMessageEdit = new EventEmitter<{ message: Message }>();
206
-
207
- // ViewChild references
208
- @ViewChild('scrollContainer', { read: ElementRef }) scrollContainer?: ElementRef<HTMLElement>;
209
- @ViewChild('contentContainer', { read: ElementRef }) contentContainer?: ElementRef<HTMLElement>;
210
- @ViewChild(StickToBottomDirective) stickToBottomDirective?: StickToBottomDirective;
211
-
212
- // Default components
213
- protected readonly defaultMessageViewComponent = CopilotChatMessageViewComponent;
214
- protected readonly defaultScrollToBottomButtonComponent = CopilotChatViewScrollToBottomButtonComponent;
215
-
216
- // Signals
217
- protected hasMounted = signal(false);
218
- protected showScrollButton = signal(false);
219
- protected isAtBottom = signal(true);
220
- protected inputContainerHeightSignal = signal(0);
221
- protected paddingBottom = computed(() => this.inputContainerHeightSignal() + 32);
222
-
223
- // Computed class
224
- protected computedClass = computed(() =>
225
- cn(this.inputClass)
226
- );
227
-
228
- private destroy$ = new Subject<void>();
229
- private platformId = inject(PLATFORM_ID);
230
- private scrollPositionService = inject(ScrollPositionService);
231
-
232
- ngOnInit(): void {
233
- // Check if we're in the browser
234
- if (isPlatformBrowser(this.platformId)) {
235
- // Set mounted after a tick to allow for hydration
236
- setTimeout(() => {
237
- this.hasMounted.set(true);
238
- }, 0);
239
- }
240
- }
241
-
242
- ngOnChanges(): void {
243
- // Update signals when inputs change
244
- // Force change detection when inputContainerHeight changes
245
- if (this.inputContainerHeight !== undefined) {
246
- this.cdr.detectChanges();
247
- }
248
- }
249
-
250
- ngAfterViewInit(): void {
251
- if (!this.autoScroll) {
252
- // Wait for the view to be fully rendered after hasMounted is set
253
- setTimeout(() => {
254
- if (this.scrollContainer) {
255
- // Check initial scroll position
256
- const initialState = this.scrollPositionService.getScrollState(this.scrollContainer.nativeElement, 10);
257
- this.showScrollButton.set(!initialState.isAtBottom);
258
-
259
- // Monitor scroll position for manual mode
260
- this.scrollPositionService.monitorScrollPosition(this.scrollContainer, 10)
261
- .pipe(takeUntil(this.destroy$))
262
- .subscribe(state => {
263
- this.showScrollButton.set(!state.isAtBottom);
264
- });
265
- }
266
- }, 100);
267
- }
268
- }
269
-
270
- /**
271
- * Handle isAtBottom change from StickToBottom directive
272
- */
273
- onIsAtBottomChange(isAtBottom: boolean): void {
274
- this.isAtBottom.set(isAtBottom);
275
- }
276
-
277
- /**
278
- * Scroll to bottom for manual mode
279
- */
280
- scrollToBottom(): void {
281
- if (this.scrollContainer) {
282
- this.scrollPositionService.scrollToBottom(this.scrollContainer, true);
283
- }
284
- }
285
-
286
- /**
287
- * Scroll to bottom for stick-to-bottom mode
288
- */
289
- scrollToBottomFromStick(): void {
290
- if (this.stickToBottomDirective) {
291
- this.stickToBottomDirective.scrollToBottom('smooth');
292
- }
293
- }
294
-
295
- ngOnDestroy(): void {
296
- this.destroy$.next();
297
- this.destroy$.complete();
298
- }
299
-
300
- // Output maps for slots
301
- scrollToBottomOutputs = { clicked: () => this.scrollToBottom() };
302
- scrollToBottomFromStickOutputs = { clicked: () => this.scrollToBottomFromStick() };
303
-
304
- // Context methods for templates
305
- messageViewContext(): any {
306
- return { messages: this.messages, inputClass: this.messageViewClass, showCursor: this.showCursor };
307
- }
308
-
309
- scrollToBottomContext(): any {
310
- return {
311
- inputClass: this.scrollToBottomButtonClass,
312
- onClick: () => this.scrollToBottom()
313
- };
314
- }
315
-
316
- scrollToBottomFromStickContext(): any {
317
- return {
318
- inputClass: this.scrollToBottomButtonClass,
319
- onClick: () => this.scrollToBottomFromStick()
320
- };
321
- }
322
- }