@acorex/components 20.2.38 → 20.2.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/button/index.d.ts +38 -17
- package/conversation2/README.md +426 -0
- package/conversation2/index.d.ts +6139 -0
- package/data-table/index.d.ts +78 -6
- package/fesm2022/acorex-components-button.mjs +50 -10
- package/fesm2022/acorex-components-button.mjs.map +1 -1
- package/fesm2022/acorex-components-command.mjs +1 -1
- package/fesm2022/acorex-components-command.mjs.map +1 -1
- package/fesm2022/acorex-components-conversation.mjs +1 -1
- package/fesm2022/acorex-components-conversation.mjs.map +1 -1
- package/fesm2022/acorex-components-conversation2.mjs +17641 -0
- package/fesm2022/acorex-components-conversation2.mjs.map +1 -0
- package/fesm2022/acorex-components-cron-job.mjs +6 -6
- package/fesm2022/acorex-components-cron-job.mjs.map +1 -1
- package/fesm2022/acorex-components-data-pager.mjs +1 -1
- package/fesm2022/acorex-components-data-pager.mjs.map +1 -1
- package/fesm2022/acorex-components-data-table.mjs +416 -62
- package/fesm2022/acorex-components-data-table.mjs.map +1 -1
- package/fesm2022/acorex-components-decorators.mjs +3 -10
- package/fesm2022/acorex-components-decorators.mjs.map +1 -1
- package/fesm2022/acorex-components-editor.mjs +5 -2
- package/fesm2022/acorex-components-editor.mjs.map +1 -1
- package/fesm2022/acorex-components-form.mjs +28 -5
- package/fesm2022/acorex-components-form.mjs.map +1 -1
- package/fesm2022/acorex-components-media-viewer.mjs +20 -5
- package/fesm2022/acorex-components-media-viewer.mjs.map +1 -1
- package/fesm2022/acorex-components-phone-box.mjs +1 -1
- package/fesm2022/acorex-components-phone-box.mjs.map +1 -1
- package/fesm2022/acorex-components-rrule.mjs +1 -1
- package/fesm2022/acorex-components-rrule.mjs.map +1 -1
- package/fesm2022/acorex-components-search-box.mjs +8 -3
- package/fesm2022/acorex-components-search-box.mjs.map +1 -1
- package/fesm2022/acorex-components-wysiwyg.mjs +11 -5
- package/fesm2022/acorex-components-wysiwyg.mjs.map +1 -1
- package/form/index.d.ts +3 -3
- package/media-viewer/index.d.ts +1 -1
- package/package.json +11 -7
- package/search-box/index.d.ts +6 -1
- package/wysiwyg/index.d.ts +2 -0
package/button/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
2
|
import { EventEmitter, QueryList, AfterViewInit } from '@angular/core';
|
|
3
3
|
import { MXInteractiveComponent, MXColorComponent, AXClickEvent, AXStyleColorType, AXItemClickEvent, AXStyleLookType, AXHotKeyAction, MXButtonBaseComponent } from '@acorex/cdk/common';
|
|
4
4
|
import * as polytype from 'polytype';
|
|
@@ -11,7 +11,9 @@ interface AXButtonItemListItem {
|
|
|
11
11
|
divided?: boolean;
|
|
12
12
|
disabled?: boolean;
|
|
13
13
|
selected?: boolean;
|
|
14
|
+
iconOnly?: boolean;
|
|
14
15
|
color?: AXStyleColorType;
|
|
16
|
+
loading?: boolean;
|
|
15
17
|
}
|
|
16
18
|
declare const AXButtonItemComponent_base: polytype.Polytype.ClusteredConstructor<[typeof MXInteractiveComponent, typeof MXColorComponent]>;
|
|
17
19
|
/**
|
|
@@ -93,8 +95,8 @@ declare class AXButtonItemComponent extends AXButtonItemComponent_base {
|
|
|
93
95
|
* @ignore
|
|
94
96
|
*/
|
|
95
97
|
tabindex: string;
|
|
96
|
-
static ɵfac:
|
|
97
|
-
static ɵcmp:
|
|
98
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXButtonItemComponent, never>;
|
|
99
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXButtonItemComponent, "ax-button-item", never, { "color": { "alias": "color"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "text": { "alias": "text"; "required": false; }; "selected": { "alias": "selected"; "required": false; }; "divided": { "alias": "divided"; "required": false; }; "data": { "alias": "data"; "required": false; }; "name": { "alias": "name"; "required": false; }; }, { "onClick": "onClick"; "onFocus": "onFocus"; "onBlur": "onBlur"; "disabledChange": "disabledChange"; }, never, ["ax-prefix", "ax-loading", "ax-icon", "ax-suffix", "ax-dropdown-panel"], true, never>;
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
/**
|
|
@@ -110,7 +112,20 @@ declare class AXButtonItemListComponent extends MXInteractiveComponent {
|
|
|
110
112
|
*
|
|
111
113
|
* @defaultValue []
|
|
112
114
|
*/
|
|
113
|
-
items:
|
|
115
|
+
items: _angular_core.InputSignal<AXButtonItemListItem[]>;
|
|
116
|
+
/**
|
|
117
|
+
* Determines if the parent closable component should be closed automatically when
|
|
118
|
+
* an item is clicked.
|
|
119
|
+
*
|
|
120
|
+
* @defaultValue true
|
|
121
|
+
*/
|
|
122
|
+
closeParentOnClick: _angular_core.InputSignal<boolean>;
|
|
123
|
+
/**
|
|
124
|
+
* Locks interaction for all items when any item is loading.
|
|
125
|
+
*
|
|
126
|
+
* @defaultValue false
|
|
127
|
+
*/
|
|
128
|
+
lockOnLoading: _angular_core.InputSignal<boolean>;
|
|
114
129
|
/**
|
|
115
130
|
* Emits an event when an item is clicked.
|
|
116
131
|
* The event contains details about the clicked item.
|
|
@@ -125,6 +140,8 @@ declare class AXButtonItemListComponent extends MXInteractiveComponent {
|
|
|
125
140
|
* @ignore
|
|
126
141
|
*/
|
|
127
142
|
constructor();
|
|
143
|
+
protected isDisabled(item: AXButtonItemListItem): boolean;
|
|
144
|
+
protected hasAnyLoadingItem(): boolean;
|
|
128
145
|
/**
|
|
129
146
|
* Initializes the content of the button item list.
|
|
130
147
|
* Binds events and properties to content button items and marks for change detection.
|
|
@@ -162,6 +179,10 @@ declare class AXButtonItemListComponent extends MXInteractiveComponent {
|
|
|
162
179
|
* @ignore
|
|
163
180
|
*/
|
|
164
181
|
_emitOnItemClickEvent(e: AXClickEvent, item: AXButtonItemComponent): void;
|
|
182
|
+
/**
|
|
183
|
+
* Closes the parent closable component if available.
|
|
184
|
+
*/
|
|
185
|
+
closeParent(): void;
|
|
165
186
|
/**
|
|
166
187
|
* Generates the CSS classes for the button item list host element.
|
|
167
188
|
* Includes classes for action list and vertical layout.
|
|
@@ -170,8 +191,8 @@ declare class AXButtonItemListComponent extends MXInteractiveComponent {
|
|
|
170
191
|
* @ignore
|
|
171
192
|
*/
|
|
172
193
|
private get __hostClass();
|
|
173
|
-
static ɵfac:
|
|
174
|
-
static ɵcmp:
|
|
194
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXButtonItemListComponent, never>;
|
|
195
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXButtonItemListComponent, "ax-button-item-list", never, { "items": { "alias": "items"; "required": false; "isSignal": true; }; "closeParentOnClick": { "alias": "closeParentOnClick"; "required": false; "isSignal": true; }; "lockOnLoading": { "alias": "lockOnLoading"; "required": false; "isSignal": true; }; }, { "onItemClick": "onItemClick"; }, ["_contentButtons"], ["*"], true, never>;
|
|
175
196
|
}
|
|
176
197
|
|
|
177
198
|
type AXButtonType = 'submit' | 'button' | 'cancel' | 'reset';
|
|
@@ -204,10 +225,10 @@ interface AXButtonItem {
|
|
|
204
225
|
* @category Components
|
|
205
226
|
*/
|
|
206
227
|
declare class AXButtonComponent extends MXButtonBaseComponent implements AfterViewInit {
|
|
207
|
-
iconOnly:
|
|
208
|
-
protected showIcon:
|
|
209
|
-
protected loadingIcon:
|
|
210
|
-
protected hasLoadingIcon:
|
|
228
|
+
iconOnly: _angular_core.InputSignal<boolean>;
|
|
229
|
+
protected showIcon: _angular_core.Signal<boolean>;
|
|
230
|
+
protected loadingIcon: _angular_core.Signal<AXLoadingComponent>;
|
|
231
|
+
protected hasLoadingIcon: _angular_core.Signal<boolean>;
|
|
211
232
|
/**
|
|
212
233
|
* Fires each time the user clicks the button.
|
|
213
234
|
* @event
|
|
@@ -218,13 +239,13 @@ declare class AXButtonComponent extends MXButtonBaseComponent implements AfterVi
|
|
|
218
239
|
*
|
|
219
240
|
* @defaultValue 'button'
|
|
220
241
|
*/
|
|
221
|
-
type:
|
|
242
|
+
type: _angular_core.InputSignal<AXButtonType>;
|
|
222
243
|
/**
|
|
223
244
|
* Defines the text displayed while the action sheet is loading.
|
|
224
245
|
*
|
|
225
246
|
* @defaultValue null
|
|
226
247
|
*/
|
|
227
|
-
loadingText:
|
|
248
|
+
loadingText: _angular_core.ModelSignal<string>;
|
|
228
249
|
/**
|
|
229
250
|
* @ignore
|
|
230
251
|
*/
|
|
@@ -255,14 +276,14 @@ declare class AXButtonComponent extends MXButtonBaseComponent implements AfterVi
|
|
|
255
276
|
* when the button loses focus.
|
|
256
277
|
*/
|
|
257
278
|
blur(): void;
|
|
258
|
-
static ɵfac:
|
|
259
|
-
static ɵcmp:
|
|
279
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXButtonComponent, never>;
|
|
280
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<AXButtonComponent, "ax-button", never, { "disabled": { "alias": "disabled"; "required": false; }; "size": { "alias": "size"; "required": false; }; "tabIndex": { "alias": "tabIndex"; "required": false; }; "color": { "alias": "color"; "required": false; }; "look": { "alias": "look"; "required": false; }; "text": { "alias": "text"; "required": false; }; "toggleable": { "alias": "toggleable"; "required": false; }; "selected": { "alias": "selected"; "required": false; }; "iconOnly": { "alias": "iconOnly"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "loadingText": { "alias": "loadingText"; "required": false; "isSignal": true; }; }, { "onBlur": "onBlur"; "onFocus": "onFocus"; "onClick": "onClick"; "selectedChange": "selectedChange"; "toggleableChange": "toggleableChange"; "lookChange": "lookChange"; "colorChange": "colorChange"; "disabledChange": "disabledChange"; "loadingText": "loadingTextChange"; }, ["loadingIcon"], ["ax-loading, ax-loading-spinner", "ax-prefix, ax-icon", "ax-content", "ax-suffix", "ax-dropdown-panel", ".tab-content", "*"], true, never>;
|
|
260
281
|
}
|
|
261
282
|
|
|
262
283
|
declare class AXButtonModule {
|
|
263
|
-
static ɵfac:
|
|
264
|
-
static ɵmod:
|
|
265
|
-
static ɵinj:
|
|
284
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AXButtonModule, never>;
|
|
285
|
+
static ɵmod: _angular_core.ɵɵNgModuleDeclaration<AXButtonModule, never, [typeof AXButtonComponent, typeof AXButtonItemComponent, typeof AXButtonItemListComponent], [typeof AXButtonComponent, typeof AXButtonItemComponent, typeof AXButtonItemListComponent]>;
|
|
286
|
+
static ɵinj: _angular_core.ɵɵInjectorDeclaration<AXButtonModule>;
|
|
266
287
|
}
|
|
267
288
|
|
|
268
289
|
export { AXButtonComponent, AXButtonItemComponent, AXButtonItemListComponent, AXButtonModule };
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
# @acorex/components/conversation2
|
|
2
|
+
|
|
3
|
+
A modern, fully-featured conversation/chat component for Angular 18+. Built with signals, standalone components, and extensibility in mind.
|
|
4
|
+
|
|
5
|
+
## 🚀 Features
|
|
6
|
+
|
|
7
|
+
- **Real-time Messaging** - Live message updates with WebSocket support
|
|
8
|
+
- **Multiple Message Types** - Text, images, videos, audio, voice, files, locations, stickers, contacts
|
|
9
|
+
- **Rich Interactions** - Reactions, replies, message editing, deletion, forwarding
|
|
10
|
+
- **Group & Private Chats** - Support for 1-on-1 and group conversations
|
|
11
|
+
- **Typing Indicators** - Real-time typing status
|
|
12
|
+
- **Read Receipts** - Message delivery and read status
|
|
13
|
+
- **Infinite Scroll** - Efficient pagination for message history
|
|
14
|
+
- **Search** - Search within conversations and messages
|
|
15
|
+
- **Extensible** - Plugin system for custom message renderers and actions
|
|
16
|
+
- **Responsive** - Mobile-friendly design
|
|
17
|
+
- **Accessibility** - ARIA labels and keyboard navigation
|
|
18
|
+
|
|
19
|
+
## 📦 Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @acorex/components/conversation2
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 🔧 Peer Dependencies
|
|
26
|
+
|
|
27
|
+
This package requires the following peer dependencies:
|
|
28
|
+
|
|
29
|
+
### Required Angular Dependencies
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"@angular/common": "^18.0.0",
|
|
34
|
+
"@angular/core": "^18.0.0",
|
|
35
|
+
"@angular/forms": "^18.0.0",
|
|
36
|
+
"rxjs": "^7.8.0"
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Required Acorex Dependencies
|
|
41
|
+
|
|
42
|
+
#### Core Packages
|
|
43
|
+
|
|
44
|
+
- `@acorex/cdk/common` - Common utilities and directives
|
|
45
|
+
- `@acorex/core/date-time` - Date and time formatting
|
|
46
|
+
- `@acorex/core/format` - General formatting utilities
|
|
47
|
+
|
|
48
|
+
#### Component Packages
|
|
49
|
+
|
|
50
|
+
- `@acorex/components/avatar` - User avatars
|
|
51
|
+
- `@acorex/components/badge` - Notification badges
|
|
52
|
+
- `@acorex/components/button` - Button components
|
|
53
|
+
- `@acorex/components/decorators` - Decorative elements
|
|
54
|
+
- `@acorex/components/dialog` - Dialog service
|
|
55
|
+
- `@acorex/components/dropdown` - Dropdown panels
|
|
56
|
+
- `@acorex/components/image` - Image components
|
|
57
|
+
- `@acorex/components/label` - Label components
|
|
58
|
+
- `@acorex/components/loading` - Loading indicators
|
|
59
|
+
- `@acorex/components/menu` - Context menus
|
|
60
|
+
- `@acorex/components/popover` - Popover components
|
|
61
|
+
- `@acorex/components/popup` - Popup service
|
|
62
|
+
- `@acorex/components/search-box` - Search functionality
|
|
63
|
+
- `@acorex/components/select-box` - Select dropdowns
|
|
64
|
+
- `@acorex/components/tabs` - Tab components
|
|
65
|
+
- `@acorex/components/text-area` - Text input areas
|
|
66
|
+
- `@acorex/components/text-box` - Text input boxes
|
|
67
|
+
- `@acorex/components/toast` - Toast notifications
|
|
68
|
+
- `@acorex/components/tooltip` - Tooltips
|
|
69
|
+
- `@acorex/components/uploader` - File upload functionality
|
|
70
|
+
|
|
71
|
+
## 🎯 Quick Start
|
|
72
|
+
|
|
73
|
+
> **New to Conversation2?** Check out our [5-Minute Quick Start Guide](./docs/QUICK-START.md) for the fastest way to get started!
|
|
74
|
+
|
|
75
|
+
### Detailed Setup
|
|
76
|
+
|
|
77
|
+
### 1. Standalone Application (Recommended)
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { ApplicationConfig } from '@angular/core';
|
|
81
|
+
import { provideConversation, AXIndexedDBApi } from '@acorex/components/conversation2';
|
|
82
|
+
|
|
83
|
+
export const appConfig: ApplicationConfig = {
|
|
84
|
+
providers: [
|
|
85
|
+
provideConversation({
|
|
86
|
+
api: AXIndexedDBApi, // or your custom API implementation
|
|
87
|
+
config: {
|
|
88
|
+
pageSize: 20,
|
|
89
|
+
maxFileSize: 10 * 1024 * 1024, // 10MB
|
|
90
|
+
allowedFileTypes: ['image/*', 'video/*', 'audio/*', 'application/pdf'],
|
|
91
|
+
},
|
|
92
|
+
registry: {
|
|
93
|
+
// Optional: Register custom message renderers, actions, etc.
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
]
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 2. NgModule Application (Legacy)
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { NgModule } from '@angular/core';
|
|
104
|
+
import { AXConversation2Module, AXIndexedDBApi } from '@acorex/components/conversation2';
|
|
105
|
+
|
|
106
|
+
@NgModule({
|
|
107
|
+
imports: [
|
|
108
|
+
AXConversation2Module.forRoot({
|
|
109
|
+
api: AXIndexedDBApi,
|
|
110
|
+
config: { /* ... */ }
|
|
111
|
+
})
|
|
112
|
+
]
|
|
113
|
+
})
|
|
114
|
+
export class AppModule { }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### 3. Use in Template
|
|
118
|
+
|
|
119
|
+
```html
|
|
120
|
+
<ax-conversation-container></ax-conversation-container>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## 🔌 API Implementation
|
|
124
|
+
|
|
125
|
+
You must provide an API implementation that extends `AXConversationApi`:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { Injectable } from '@angular/core';
|
|
129
|
+
import { HttpClient } from '@angular/common/http';
|
|
130
|
+
import { AXConversationApi, AXPagination, AXPaginatedResult } from '@acorex/components/conversation2';
|
|
131
|
+
|
|
132
|
+
@Injectable()
|
|
133
|
+
export class MyConversationApi extends AXConversationApi {
|
|
134
|
+
constructor(private http: HttpClient) {
|
|
135
|
+
super();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async connect(): Promise<void> {
|
|
139
|
+
// Initialize WebSocket connection
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async fetchConversations(pagination: AXPagination): Promise<AXPaginatedResult<AXConversation>> {
|
|
143
|
+
const response = await this.http.get('/api/conversations', {
|
|
144
|
+
params: { page: pagination.page, pageSize: pagination.pageSize }
|
|
145
|
+
}).toPromise();
|
|
146
|
+
return response;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Implement other required methods...
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Built-in API Implementations
|
|
154
|
+
|
|
155
|
+
#### IndexedDB API (Development/Demo)
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { AXIndexedDBApi } from '@acorex/components/conversation2';
|
|
159
|
+
|
|
160
|
+
// Provides in-memory storage with sample data
|
|
161
|
+
// Perfect for development and demos
|
|
162
|
+
provideConversation({ api: AXIndexedDBApi })
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
#### IndexedDB with AI API (AI-Powered Demo)
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import { AXIndexedDBAIApi } from '@acorex/components/conversation2';
|
|
169
|
+
|
|
170
|
+
// Includes AI-powered auto-responses
|
|
171
|
+
provideConversation({ api: AXIndexedDBAIApi })
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## ⚙️ Configuration
|
|
175
|
+
|
|
176
|
+
### Conversation Config
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
interface AXConversationConfig {
|
|
180
|
+
// Pagination
|
|
181
|
+
pageSize?: number; // Default: 20
|
|
182
|
+
infiniteScrollThreshold?: number; // Default: 200px
|
|
183
|
+
scrollThreshold?: number; // Default: 100px
|
|
184
|
+
|
|
185
|
+
// File Upload
|
|
186
|
+
maxFileSize?: number; // Default: 10MB
|
|
187
|
+
allowedFileTypes?: string[]; // Default: all types
|
|
188
|
+
|
|
189
|
+
// UI Behavior
|
|
190
|
+
messageHighlightDuration?: number; // Default: 2000ms
|
|
191
|
+
typingIndicatorTimeout?: number; // Default: 3000ms
|
|
192
|
+
|
|
193
|
+
// Features
|
|
194
|
+
enableReactions?: boolean; // Default: true
|
|
195
|
+
enableReplies?: boolean; // Default: true
|
|
196
|
+
enableEditing?: boolean; // Default: true
|
|
197
|
+
enableDeletion?: boolean; // Default: true
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Registry Configuration
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
interface AXRegistryConfiguration {
|
|
205
|
+
messageRenderers?: AXMessageRenderer[];
|
|
206
|
+
messageActions?: AXMessageAction[];
|
|
207
|
+
composerActions?: AXComposerAction[];
|
|
208
|
+
composerTabs?: AXComposerTab[];
|
|
209
|
+
conversationTabs?: AXConversationTab[];
|
|
210
|
+
infoBarActions?: AXInfoBarAction[];
|
|
211
|
+
conversationItemActions?: AXConversationItemAction[];
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## 🎨 Customization
|
|
216
|
+
|
|
217
|
+
### Custom Message Renderer
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
import { Component, input } from '@angular/core';
|
|
221
|
+
import { AXMessageRenderer } from '@acorex/components/conversation2';
|
|
222
|
+
|
|
223
|
+
@Component({
|
|
224
|
+
selector: 'my-custom-renderer',
|
|
225
|
+
template: `<div>{{ message().payload.customData }}</div>`
|
|
226
|
+
})
|
|
227
|
+
export class MyCustomRendererComponent {
|
|
228
|
+
message = input.required<AXMessage>();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const myRenderer: AXMessageRenderer = {
|
|
232
|
+
type: 'custom',
|
|
233
|
+
component: MyCustomRendererComponent,
|
|
234
|
+
priority: 100
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// Register in config
|
|
238
|
+
provideConversation({
|
|
239
|
+
api: MyApi,
|
|
240
|
+
registry: {
|
|
241
|
+
messageRenderers: [myRenderer]
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Custom Message Action
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
const forwardAction: AXMessageAction = {
|
|
250
|
+
id: 'forward',
|
|
251
|
+
label: 'Forward',
|
|
252
|
+
icon: 'forward',
|
|
253
|
+
shortcut: 'Ctrl+F',
|
|
254
|
+
enabled: (message, user) => message.senderId === user.id,
|
|
255
|
+
execute: async (message, service) => {
|
|
256
|
+
// Forward logic
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
provideConversation({
|
|
261
|
+
api: MyApi,
|
|
262
|
+
registry: {
|
|
263
|
+
messageActions: [forwardAction]
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## 📱 Components
|
|
269
|
+
|
|
270
|
+
### Main Components
|
|
271
|
+
|
|
272
|
+
- `<ax-conversation-container>` - Full conversation UI with sidebar, messages, and composer
|
|
273
|
+
- `<ax-conversation-sidebar>` - Conversation list sidebar
|
|
274
|
+
- `<ax-conversation-message-list>` - Message list with virtual scrolling
|
|
275
|
+
- `<ax-conversation-composer>` - Message input area
|
|
276
|
+
- `<ax-conversation-info-bar>` - Conversation header with actions
|
|
277
|
+
|
|
278
|
+
### Usage Examples
|
|
279
|
+
|
|
280
|
+
```html
|
|
281
|
+
<!-- Full conversation UI -->
|
|
282
|
+
<ax-conversation-container></ax-conversation-container>
|
|
283
|
+
|
|
284
|
+
<!-- Custom layout -->
|
|
285
|
+
<div class="my-chat-layout">
|
|
286
|
+
<ax-conversation-sidebar></ax-conversation-sidebar>
|
|
287
|
+
<div class="chat-main">
|
|
288
|
+
<ax-conversation-info-bar></ax-conversation-info-bar>
|
|
289
|
+
<ax-conversation-message-list></ax-conversation-message-list>
|
|
290
|
+
<ax-conversation-composer></ax-conversation-composer>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## 🎭 Services
|
|
296
|
+
|
|
297
|
+
### AXConversationService
|
|
298
|
+
|
|
299
|
+
Main service for conversation operations:
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
import { inject } from '@angular/core';
|
|
303
|
+
import { AXConversationService } from '@acorex/components/conversation2';
|
|
304
|
+
|
|
305
|
+
export class MyComponent {
|
|
306
|
+
private conversationService = inject(AXConversationService);
|
|
307
|
+
|
|
308
|
+
async sendMessage() {
|
|
309
|
+
await this.conversationService.sendMessage({
|
|
310
|
+
conversationId: 'conv-123',
|
|
311
|
+
type: 'text',
|
|
312
|
+
payload: { text: 'Hello!' }
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async createConversation() {
|
|
317
|
+
const conv = await this.conversationService.createConversation(
|
|
318
|
+
['user-1', 'user-2'],
|
|
319
|
+
'private'
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## 🧪 Testing
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
import { TestBed } from '@angular/core/testing';
|
|
329
|
+
import { provideConversation, AXConversationService } from '@acorex/components/conversation2';
|
|
330
|
+
import { MockConversationApi } from './mocks/mock-api';
|
|
331
|
+
|
|
332
|
+
describe('MyComponent', () => {
|
|
333
|
+
beforeEach(() => {
|
|
334
|
+
TestBed.configureTestingModule({
|
|
335
|
+
providers: [
|
|
336
|
+
provideConversation({ api: MockConversationApi })
|
|
337
|
+
]
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it('should send message', async () => {
|
|
342
|
+
const service = TestBed.inject(AXConversationService);
|
|
343
|
+
const message = await service.sendMessage({
|
|
344
|
+
conversationId: 'test',
|
|
345
|
+
type: 'text',
|
|
346
|
+
payload: { text: 'Test' }
|
|
347
|
+
});
|
|
348
|
+
expect(message).toBeDefined();
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## 🎯 Message Types
|
|
354
|
+
|
|
355
|
+
Supported message types out of the box:
|
|
356
|
+
|
|
357
|
+
- **text** - Plain text messages
|
|
358
|
+
- **image** - Image messages with thumbnails
|
|
359
|
+
- **video** - Video messages with playback
|
|
360
|
+
- **audio** - Audio file messages
|
|
361
|
+
- **voice** - Voice recordings
|
|
362
|
+
- **file** - Generic file attachments
|
|
363
|
+
- **location** - Location sharing
|
|
364
|
+
- **sticker** - Sticker messages
|
|
365
|
+
- **contact** - Contact card sharing
|
|
366
|
+
- **system** - System notifications
|
|
367
|
+
|
|
368
|
+
## 🔒 Security Considerations
|
|
369
|
+
|
|
370
|
+
- **API Keys**: Never hardcode API keys in source code. Use environment variables or injection tokens.
|
|
371
|
+
- **File Upload**: Validate file types and sizes on both client and server.
|
|
372
|
+
- **XSS Protection**: All user content is sanitized by default.
|
|
373
|
+
- **Authentication**: Implement proper authentication in your API layer.
|
|
374
|
+
|
|
375
|
+
## 📊 Performance Tips
|
|
376
|
+
|
|
377
|
+
1. **Virtual Scrolling**: Enabled by default for large message lists
|
|
378
|
+
2. **Lazy Loading**: Images and media are loaded on demand
|
|
379
|
+
3. **Pagination**: Messages are loaded in pages to reduce initial load
|
|
380
|
+
4. **Debouncing**: Typing indicators are debounced to reduce network traffic
|
|
381
|
+
5. **Memoization**: Use computed signals for expensive calculations
|
|
382
|
+
|
|
383
|
+
## 🐛 Troubleshooting
|
|
384
|
+
|
|
385
|
+
### Common Issues
|
|
386
|
+
|
|
387
|
+
**Issue**: Messages not appearing
|
|
388
|
+
|
|
389
|
+
- Check if API is connected: `conversationService.connectionStatus$()`
|
|
390
|
+
- Verify API implementation returns correct data structure
|
|
391
|
+
|
|
392
|
+
**Issue**: File upload fails
|
|
393
|
+
|
|
394
|
+
- Check `maxFileSize` and `allowedFileTypes` configuration
|
|
395
|
+
- Verify API `uploadFile()` implementation
|
|
396
|
+
|
|
397
|
+
**Issue**: Styling issues
|
|
398
|
+
|
|
399
|
+
- Ensure all Acorex component styles are imported
|
|
400
|
+
- Check for CSS conflicts with global styles
|
|
401
|
+
|
|
402
|
+
## 📚 Additional Resources
|
|
403
|
+
|
|
404
|
+
- [Quick Start Guide](./docs/QUICK-START.md) - Get started in 5 minutes
|
|
405
|
+
- [Architecture Overview](./docs/ARCHITECTURE-OVERVIEW.md) - Understand the module structure
|
|
406
|
+
- [API Documentation](./docs/ARCHITECTURE-APIS.md) - Implement custom backends
|
|
407
|
+
- [Component Guide](./docs/ARCHITECTURE-COMPONENTS.md) - Learn about components
|
|
408
|
+
- [Plugin System](./docs/ARCHITECTURE-PLUGINS.md) - Extend functionality
|
|
409
|
+
- [Usage Guide](./docs/USAGE-GUIDE.md) - Advanced usage patterns
|
|
410
|
+
|
|
411
|
+
## 🤝 Contributing
|
|
412
|
+
|
|
413
|
+
Contributions are welcome! Please read our [Contributing Guide](./CONTRIBUTING.md) for details.
|
|
414
|
+
|
|
415
|
+
## 📄 License
|
|
416
|
+
|
|
417
|
+
MIT License - see LICENSE file for details
|
|
418
|
+
|
|
419
|
+
## 🔄 Changelog
|
|
420
|
+
|
|
421
|
+
See [CHANGELOG.md](./CHANGELOG.md) for version history and updates.
|
|
422
|
+
|
|
423
|
+
## 💬 Support
|
|
424
|
+
|
|
425
|
+
- GitHub Issues: [Report a bug](https://github.com/acorexui/acorex-ui/issues)
|
|
426
|
+
- Discussions: [Ask questions](https://github.com/acorexui/acorex-ui/discussions)
|