@bbq-chat/widgets-angular 1.0.0
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/README.md +252 -0
- package/dist/LICENSE +21 -0
- package/dist/README.md +252 -0
- package/dist/custom-widget-renderer.types.d.ts +79 -0
- package/dist/custom-widget-renderer.types.d.ts.map +1 -0
- package/dist/custom-widget-renderer.types.js +43 -0
- package/dist/custom-widget-renderer.types.js.map +1 -0
- package/dist/index.cjs +38 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/package.json +16 -0
- package/dist/widget-registry.service.d.ts +95 -0
- package/dist/widget-registry.service.d.ts.map +1 -0
- package/dist/widget-registry.service.js +129 -0
- package/dist/widget-registry.service.js.map +1 -0
- package/dist/widget-renderer.component.d.ts +93 -0
- package/dist/widget-renderer.component.d.ts.map +1 -0
- package/dist/widget-renderer.component.js +316 -0
- package/dist/widget-renderer.component.js.map +1 -0
- package/package.json +74 -0
- package/src/custom-widget-renderer.types.ts +120 -0
- package/src/index.ts +65 -0
- package/src/widget-registry.service.ts +128 -0
- package/src/widget-renderer.component.ts +384 -0
package/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# @bbq-chat/widgets-angular
|
|
2
|
+
|
|
3
|
+
Angular components and services for BbQ ChatWidgets. This package provides Angular-native wrappers for the core [@bbq-chat/widgets](https://www.npmjs.com/package/@bbq-chat/widgets) library.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @bbq-chat/widgets-angular @bbq-chat/widgets
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Peer Dependencies
|
|
12
|
+
|
|
13
|
+
This package requires:
|
|
14
|
+
- `@angular/common` >= 17.0.0
|
|
15
|
+
- `@angular/core` >= 17.0.0
|
|
16
|
+
- `@bbq-chat/widgets` ^1.0.0
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### 1. Import the component
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { Component } from '@angular/core';
|
|
24
|
+
import { WidgetRendererComponent } from '@bbq-chat/widgets-angular';
|
|
25
|
+
import type { ChatWidget } from '@bbq-chat/widgets-angular';
|
|
26
|
+
|
|
27
|
+
@Component({
|
|
28
|
+
selector: 'app-chat',
|
|
29
|
+
standalone: true,
|
|
30
|
+
imports: [WidgetRendererComponent],
|
|
31
|
+
template: `
|
|
32
|
+
<bbq-widget-renderer
|
|
33
|
+
[widgets]="widgets"
|
|
34
|
+
(widgetAction)="handleWidgetAction($event)">
|
|
35
|
+
</bbq-widget-renderer>
|
|
36
|
+
`
|
|
37
|
+
})
|
|
38
|
+
export class ChatComponent {
|
|
39
|
+
widgets: ChatWidget[] = [];
|
|
40
|
+
|
|
41
|
+
handleWidgetAction(event: { actionName: string; payload: any }) {
|
|
42
|
+
console.log('Widget action:', event.actionName, event.payload);
|
|
43
|
+
// Handle the action (e.g., send to backend)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Import styles
|
|
49
|
+
|
|
50
|
+
In your `styles.css` or `styles.scss`:
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
@import '@bbq-chat/widgets/styles';
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or import a specific theme:
|
|
57
|
+
|
|
58
|
+
```css
|
|
59
|
+
@import '@bbq-chat/widgets/styles/light';
|
|
60
|
+
@import '@bbq-chat/widgets/styles/dark';
|
|
61
|
+
@import '@bbq-chat/widgets/styles/corporate';
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Components
|
|
65
|
+
|
|
66
|
+
### WidgetRendererComponent
|
|
67
|
+
|
|
68
|
+
The main component for rendering chat widgets.
|
|
69
|
+
|
|
70
|
+
**Inputs:**
|
|
71
|
+
- `widgets: ChatWidget[] | null | undefined` - Array of widgets to render
|
|
72
|
+
|
|
73
|
+
**Outputs:**
|
|
74
|
+
- `widgetAction: EventEmitter<{ actionName: string; payload: any }>` - Emits when a widget action is triggered
|
|
75
|
+
|
|
76
|
+
**Example:**
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
<bbq-widget-renderer
|
|
80
|
+
[widgets]="messageWidgets"
|
|
81
|
+
(widgetAction)="onWidgetAction($event)">
|
|
82
|
+
</bbq-widget-renderer>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Services
|
|
86
|
+
|
|
87
|
+
### WidgetRegistryService
|
|
88
|
+
|
|
89
|
+
Service for registering custom widget types.
|
|
90
|
+
|
|
91
|
+
**Example:**
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { Component, OnInit } from '@angular/core';
|
|
95
|
+
import { WidgetRegistryService } from '@bbq-chat/widgets-angular';
|
|
96
|
+
|
|
97
|
+
export class MyCustomWidget {
|
|
98
|
+
type = 'myCustomWidget';
|
|
99
|
+
constructor(public label: string, public action: string) {}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@Component({
|
|
103
|
+
selector: 'app-root',
|
|
104
|
+
template: '...'
|
|
105
|
+
})
|
|
106
|
+
export class AppComponent implements OnInit {
|
|
107
|
+
constructor(private widgetRegistry: WidgetRegistryService) {}
|
|
108
|
+
|
|
109
|
+
ngOnInit() {
|
|
110
|
+
// Register custom widget factory
|
|
111
|
+
this.widgetRegistry.registerFactory('myCustomWidget', (obj) => {
|
|
112
|
+
if (obj.type === 'myCustomWidget') {
|
|
113
|
+
return new MyCustomWidget(obj.label, obj.action);
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Widget Types
|
|
122
|
+
|
|
123
|
+
All standard widget types from `@bbq-chat/widgets` are supported:
|
|
124
|
+
|
|
125
|
+
- `ButtonWidget` - Clickable buttons
|
|
126
|
+
- `CardWidget` - Information cards
|
|
127
|
+
- `FormWidget` - Form containers
|
|
128
|
+
- `InputWidget` - Text input fields
|
|
129
|
+
- `TextAreaWidget` - Multi-line text input
|
|
130
|
+
- `DropdownWidget` - Dropdown selects
|
|
131
|
+
- `SliderWidget` - Range sliders
|
|
132
|
+
- `ToggleWidget` - Toggle switches
|
|
133
|
+
- `FileUploadWidget` - File upload controls
|
|
134
|
+
- `DatePickerWidget` - Date pickers
|
|
135
|
+
- `MultiSelectWidget` - Multi-select dropdowns
|
|
136
|
+
- `ThemeSwitcherWidget` - Theme switcher controls
|
|
137
|
+
- `ProgressBarWidget` - Progress indicators
|
|
138
|
+
- `ImageWidget` - Image displays
|
|
139
|
+
- `ImageCollectionWidget` - Image galleries
|
|
140
|
+
|
|
141
|
+
## Advanced Usage
|
|
142
|
+
|
|
143
|
+
### Handling Widget Actions
|
|
144
|
+
|
|
145
|
+
Widget actions are emitted when users interact with widgets. Handle these actions in your component:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
async handleWidgetAction(event: { actionName: string; payload: any }) {
|
|
149
|
+
const { actionName, payload } = event;
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const response = await fetch('/api/chat/action', {
|
|
153
|
+
method: 'POST',
|
|
154
|
+
headers: { 'Content-Type': 'application/json' },
|
|
155
|
+
body: JSON.stringify({ action: actionName, payload })
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const data = await response.json();
|
|
159
|
+
// Update widgets with response
|
|
160
|
+
this.widgets = data.widgets;
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error('Failed to handle widget action:', error);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Custom Widget Renderers
|
|
168
|
+
|
|
169
|
+
The library now supports three types of custom widget renderers for enhanced flexibility:
|
|
170
|
+
|
|
171
|
+
#### 1. HTML Function Renderer
|
|
172
|
+
|
|
173
|
+
Simple function that returns HTML strings:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
this.widgetRegistry.registerRenderer('myWidget', (widget) => {
|
|
177
|
+
return `<div class="my-widget">${widget.label}</div>`;
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### 2. Angular Component Renderer (Recommended)
|
|
182
|
+
|
|
183
|
+
Use Angular components for full framework features including data binding, change detection, and dependency injection:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import { Component, Input } from '@angular/core';
|
|
187
|
+
import { CustomWidgetComponent } from '@bbq-chat/widgets-angular';
|
|
188
|
+
|
|
189
|
+
@Component({
|
|
190
|
+
selector: 'app-my-widget',
|
|
191
|
+
standalone: true,
|
|
192
|
+
template: `
|
|
193
|
+
<div class="my-widget">
|
|
194
|
+
<h3>{{ myWidget.title }}</h3>
|
|
195
|
+
<button (click)="onClick()">Action</button>
|
|
196
|
+
</div>
|
|
197
|
+
`
|
|
198
|
+
})
|
|
199
|
+
export class MyWidgetComponent implements CustomWidgetComponent {
|
|
200
|
+
@Input() widget!: ChatWidget;
|
|
201
|
+
widgetAction?: (actionName: string, payload: unknown) => void;
|
|
202
|
+
|
|
203
|
+
get myWidget(): MyCustomWidget {
|
|
204
|
+
return this.widget as MyCustomWidget;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
onClick() {
|
|
208
|
+
this.widgetAction?.('my_action', { data: 'example' });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Register the component
|
|
213
|
+
this.widgetRegistry.registerRenderer('myWidget', MyWidgetComponent);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### 3. Angular Template Renderer
|
|
217
|
+
|
|
218
|
+
Use inline templates with full Angular template syntax:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { WidgetTemplateContext } from '@bbq-chat/widgets-angular';
|
|
222
|
+
|
|
223
|
+
@Component({
|
|
224
|
+
template: `
|
|
225
|
+
<ng-template #myTemplate let-widget let-emitAction="emitAction">
|
|
226
|
+
<div class="my-widget">
|
|
227
|
+
<h3>{{ widget.title }}</h3>
|
|
228
|
+
<button (click)="emitAction('my_action', { data: 'example' })">
|
|
229
|
+
Action
|
|
230
|
+
</button>
|
|
231
|
+
</div>
|
|
232
|
+
</ng-template>
|
|
233
|
+
`
|
|
234
|
+
})
|
|
235
|
+
export class AppComponent implements OnInit {
|
|
236
|
+
@ViewChild('myTemplate', { static: true }) myTemplate!: TemplateRef<WidgetTemplateContext>;
|
|
237
|
+
|
|
238
|
+
ngOnInit() {
|
|
239
|
+
this.widgetRegistry.registerRenderer('myWidget', this.myTemplate);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
See [EXAMPLES.md](./EXAMPLES.md) for detailed examples and best practices.
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
MIT
|
|
249
|
+
|
|
250
|
+
## Repository
|
|
251
|
+
|
|
252
|
+
https://github.com/JeanMarcMbouma/BbQ.ChatWidgets
|
package/dist/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 BbQ ChatWidgets Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# @bbq-chat/widgets-angular
|
|
2
|
+
|
|
3
|
+
Angular components and services for BbQ ChatWidgets. This package provides Angular-native wrappers for the core [@bbq-chat/widgets](https://www.npmjs.com/package/@bbq-chat/widgets) library.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @bbq-chat/widgets-angular @bbq-chat/widgets
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Peer Dependencies
|
|
12
|
+
|
|
13
|
+
This package requires:
|
|
14
|
+
- `@angular/common` >= 17.0.0
|
|
15
|
+
- `@angular/core` >= 17.0.0
|
|
16
|
+
- `@bbq-chat/widgets` ^1.0.0
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### 1. Import the component
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { Component } from '@angular/core';
|
|
24
|
+
import { WidgetRendererComponent } from '@bbq-chat/widgets-angular';
|
|
25
|
+
import type { ChatWidget } from '@bbq-chat/widgets-angular';
|
|
26
|
+
|
|
27
|
+
@Component({
|
|
28
|
+
selector: 'app-chat',
|
|
29
|
+
standalone: true,
|
|
30
|
+
imports: [WidgetRendererComponent],
|
|
31
|
+
template: `
|
|
32
|
+
<bbq-widget-renderer
|
|
33
|
+
[widgets]="widgets"
|
|
34
|
+
(widgetAction)="handleWidgetAction($event)">
|
|
35
|
+
</bbq-widget-renderer>
|
|
36
|
+
`
|
|
37
|
+
})
|
|
38
|
+
export class ChatComponent {
|
|
39
|
+
widgets: ChatWidget[] = [];
|
|
40
|
+
|
|
41
|
+
handleWidgetAction(event: { actionName: string; payload: any }) {
|
|
42
|
+
console.log('Widget action:', event.actionName, event.payload);
|
|
43
|
+
// Handle the action (e.g., send to backend)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 2. Import styles
|
|
49
|
+
|
|
50
|
+
In your `styles.css` or `styles.scss`:
|
|
51
|
+
|
|
52
|
+
```css
|
|
53
|
+
@import '@bbq-chat/widgets/styles';
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or import a specific theme:
|
|
57
|
+
|
|
58
|
+
```css
|
|
59
|
+
@import '@bbq-chat/widgets/styles/light';
|
|
60
|
+
@import '@bbq-chat/widgets/styles/dark';
|
|
61
|
+
@import '@bbq-chat/widgets/styles/corporate';
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Components
|
|
65
|
+
|
|
66
|
+
### WidgetRendererComponent
|
|
67
|
+
|
|
68
|
+
The main component for rendering chat widgets.
|
|
69
|
+
|
|
70
|
+
**Inputs:**
|
|
71
|
+
- `widgets: ChatWidget[] | null | undefined` - Array of widgets to render
|
|
72
|
+
|
|
73
|
+
**Outputs:**
|
|
74
|
+
- `widgetAction: EventEmitter<{ actionName: string; payload: any }>` - Emits when a widget action is triggered
|
|
75
|
+
|
|
76
|
+
**Example:**
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
<bbq-widget-renderer
|
|
80
|
+
[widgets]="messageWidgets"
|
|
81
|
+
(widgetAction)="onWidgetAction($event)">
|
|
82
|
+
</bbq-widget-renderer>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Services
|
|
86
|
+
|
|
87
|
+
### WidgetRegistryService
|
|
88
|
+
|
|
89
|
+
Service for registering custom widget types.
|
|
90
|
+
|
|
91
|
+
**Example:**
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { Component, OnInit } from '@angular/core';
|
|
95
|
+
import { WidgetRegistryService } from '@bbq-chat/widgets-angular';
|
|
96
|
+
|
|
97
|
+
export class MyCustomWidget {
|
|
98
|
+
type = 'myCustomWidget';
|
|
99
|
+
constructor(public label: string, public action: string) {}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@Component({
|
|
103
|
+
selector: 'app-root',
|
|
104
|
+
template: '...'
|
|
105
|
+
})
|
|
106
|
+
export class AppComponent implements OnInit {
|
|
107
|
+
constructor(private widgetRegistry: WidgetRegistryService) {}
|
|
108
|
+
|
|
109
|
+
ngOnInit() {
|
|
110
|
+
// Register custom widget factory
|
|
111
|
+
this.widgetRegistry.registerFactory('myCustomWidget', (obj) => {
|
|
112
|
+
if (obj.type === 'myCustomWidget') {
|
|
113
|
+
return new MyCustomWidget(obj.label, obj.action);
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Widget Types
|
|
122
|
+
|
|
123
|
+
All standard widget types from `@bbq-chat/widgets` are supported:
|
|
124
|
+
|
|
125
|
+
- `ButtonWidget` - Clickable buttons
|
|
126
|
+
- `CardWidget` - Information cards
|
|
127
|
+
- `FormWidget` - Form containers
|
|
128
|
+
- `InputWidget` - Text input fields
|
|
129
|
+
- `TextAreaWidget` - Multi-line text input
|
|
130
|
+
- `DropdownWidget` - Dropdown selects
|
|
131
|
+
- `SliderWidget` - Range sliders
|
|
132
|
+
- `ToggleWidget` - Toggle switches
|
|
133
|
+
- `FileUploadWidget` - File upload controls
|
|
134
|
+
- `DatePickerWidget` - Date pickers
|
|
135
|
+
- `MultiSelectWidget` - Multi-select dropdowns
|
|
136
|
+
- `ThemeSwitcherWidget` - Theme switcher controls
|
|
137
|
+
- `ProgressBarWidget` - Progress indicators
|
|
138
|
+
- `ImageWidget` - Image displays
|
|
139
|
+
- `ImageCollectionWidget` - Image galleries
|
|
140
|
+
|
|
141
|
+
## Advanced Usage
|
|
142
|
+
|
|
143
|
+
### Handling Widget Actions
|
|
144
|
+
|
|
145
|
+
Widget actions are emitted when users interact with widgets. Handle these actions in your component:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
async handleWidgetAction(event: { actionName: string; payload: any }) {
|
|
149
|
+
const { actionName, payload } = event;
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const response = await fetch('/api/chat/action', {
|
|
153
|
+
method: 'POST',
|
|
154
|
+
headers: { 'Content-Type': 'application/json' },
|
|
155
|
+
body: JSON.stringify({ action: actionName, payload })
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const data = await response.json();
|
|
159
|
+
// Update widgets with response
|
|
160
|
+
this.widgets = data.widgets;
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error('Failed to handle widget action:', error);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Custom Widget Renderers
|
|
168
|
+
|
|
169
|
+
The library now supports three types of custom widget renderers for enhanced flexibility:
|
|
170
|
+
|
|
171
|
+
#### 1. HTML Function Renderer
|
|
172
|
+
|
|
173
|
+
Simple function that returns HTML strings:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
this.widgetRegistry.registerRenderer('myWidget', (widget) => {
|
|
177
|
+
return `<div class="my-widget">${widget.label}</div>`;
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### 2. Angular Component Renderer (Recommended)
|
|
182
|
+
|
|
183
|
+
Use Angular components for full framework features including data binding, change detection, and dependency injection:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import { Component, Input } from '@angular/core';
|
|
187
|
+
import { CustomWidgetComponent } from '@bbq-chat/widgets-angular';
|
|
188
|
+
|
|
189
|
+
@Component({
|
|
190
|
+
selector: 'app-my-widget',
|
|
191
|
+
standalone: true,
|
|
192
|
+
template: `
|
|
193
|
+
<div class="my-widget">
|
|
194
|
+
<h3>{{ myWidget.title }}</h3>
|
|
195
|
+
<button (click)="onClick()">Action</button>
|
|
196
|
+
</div>
|
|
197
|
+
`
|
|
198
|
+
})
|
|
199
|
+
export class MyWidgetComponent implements CustomWidgetComponent {
|
|
200
|
+
@Input() widget!: ChatWidget;
|
|
201
|
+
widgetAction?: (actionName: string, payload: unknown) => void;
|
|
202
|
+
|
|
203
|
+
get myWidget(): MyCustomWidget {
|
|
204
|
+
return this.widget as MyCustomWidget;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
onClick() {
|
|
208
|
+
this.widgetAction?.('my_action', { data: 'example' });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Register the component
|
|
213
|
+
this.widgetRegistry.registerRenderer('myWidget', MyWidgetComponent);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### 3. Angular Template Renderer
|
|
217
|
+
|
|
218
|
+
Use inline templates with full Angular template syntax:
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { WidgetTemplateContext } from '@bbq-chat/widgets-angular';
|
|
222
|
+
|
|
223
|
+
@Component({
|
|
224
|
+
template: `
|
|
225
|
+
<ng-template #myTemplate let-widget let-emitAction="emitAction">
|
|
226
|
+
<div class="my-widget">
|
|
227
|
+
<h3>{{ widget.title }}</h3>
|
|
228
|
+
<button (click)="emitAction('my_action', { data: 'example' })">
|
|
229
|
+
Action
|
|
230
|
+
</button>
|
|
231
|
+
</div>
|
|
232
|
+
</ng-template>
|
|
233
|
+
`
|
|
234
|
+
})
|
|
235
|
+
export class AppComponent implements OnInit {
|
|
236
|
+
@ViewChild('myTemplate', { static: true }) myTemplate!: TemplateRef<WidgetTemplateContext>;
|
|
237
|
+
|
|
238
|
+
ngOnInit() {
|
|
239
|
+
this.widgetRegistry.registerRenderer('myWidget', this.myTemplate);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
See [EXAMPLES.md](./EXAMPLES.md) for detailed examples and best practices.
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
MIT
|
|
249
|
+
|
|
250
|
+
## Repository
|
|
251
|
+
|
|
252
|
+
https://github.com/JeanMarcMbouma/BbQ.ChatWidgets
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Type, TemplateRef } from '@angular/core';
|
|
2
|
+
import { ChatWidget } from '@bbq-chat/widgets';
|
|
3
|
+
/**
|
|
4
|
+
* Context provided to template-based custom widget renderers
|
|
5
|
+
*/
|
|
6
|
+
export interface WidgetTemplateContext {
|
|
7
|
+
/**
|
|
8
|
+
* The widget instance being rendered
|
|
9
|
+
*/
|
|
10
|
+
$implicit: ChatWidget;
|
|
11
|
+
/**
|
|
12
|
+
* The widget instance (alternative access)
|
|
13
|
+
*/
|
|
14
|
+
widget: ChatWidget;
|
|
15
|
+
/**
|
|
16
|
+
* Emit a widget action
|
|
17
|
+
*/
|
|
18
|
+
emitAction: (actionName: string, payload: unknown) => void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Interface for component-based custom widget renderers
|
|
22
|
+
*/
|
|
23
|
+
export interface CustomWidgetComponent {
|
|
24
|
+
/**
|
|
25
|
+
* The widget instance to render
|
|
26
|
+
*/
|
|
27
|
+
widget: ChatWidget;
|
|
28
|
+
/**
|
|
29
|
+
* Event emitter for widget actions (optional, will be set by the renderer)
|
|
30
|
+
*/
|
|
31
|
+
widgetAction?: (actionName: string, payload: unknown) => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Type for custom widget renderer functions that return HTML strings
|
|
35
|
+
*/
|
|
36
|
+
export type CustomWidgetHtmlRenderer = (widget: ChatWidget) => string;
|
|
37
|
+
/**
|
|
38
|
+
* Type for custom widget renderer configurations
|
|
39
|
+
*/
|
|
40
|
+
export type CustomWidgetRenderer = CustomWidgetHtmlRenderer | Type<CustomWidgetComponent> | TemplateRef<WidgetTemplateContext>;
|
|
41
|
+
/**
|
|
42
|
+
* Configuration for registering a custom widget renderer
|
|
43
|
+
*/
|
|
44
|
+
export interface CustomWidgetRendererConfig {
|
|
45
|
+
/**
|
|
46
|
+
* The widget type identifier
|
|
47
|
+
*/
|
|
48
|
+
type: string;
|
|
49
|
+
/**
|
|
50
|
+
* The renderer: can be a function returning HTML, an Angular Component class, or a TemplateRef
|
|
51
|
+
*/
|
|
52
|
+
renderer: CustomWidgetRenderer;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Type guard to check if a renderer is a TemplateRef
|
|
56
|
+
*/
|
|
57
|
+
export declare function isTemplateRenderer(renderer: CustomWidgetRenderer): renderer is TemplateRef<WidgetTemplateContext>;
|
|
58
|
+
/**
|
|
59
|
+
* Type guard to check if a renderer is an Angular Component
|
|
60
|
+
*
|
|
61
|
+
* Note: This uses a heuristic check based on the following assumptions:
|
|
62
|
+
* 1. Components are constructor functions
|
|
63
|
+
* 2. Components have a prototype with a constructor property
|
|
64
|
+
* 3. Components typically use dependency injection (no required constructor params)
|
|
65
|
+
*
|
|
66
|
+
* Limitation: This may not detect components with required constructor parameters.
|
|
67
|
+
* For edge cases, explicitly check your component's constructor signature.
|
|
68
|
+
*
|
|
69
|
+
* Alternative: You can always register a wrapper component that has no required params.
|
|
70
|
+
*/
|
|
71
|
+
export declare function isComponentRenderer(renderer: CustomWidgetRenderer): renderer is Type<CustomWidgetComponent>;
|
|
72
|
+
/**
|
|
73
|
+
* Type guard to check if a renderer is an HTML function
|
|
74
|
+
*
|
|
75
|
+
* Note: This should be checked AFTER checking for component and template renderers
|
|
76
|
+
* since components are also functions but with additional properties.
|
|
77
|
+
*/
|
|
78
|
+
export declare function isHtmlRenderer(renderer: CustomWidgetRenderer): renderer is CustomWidgetHtmlRenderer;
|
|
79
|
+
//# sourceMappingURL=custom-widget-renderer.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-widget-renderer.types.d.ts","sourceRoot":"","sources":["../src/custom-widget-renderer.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,SAAS,EAAE,UAAU,CAAC;IAEtB;;OAEG;IACH,MAAM,EAAE,UAAU,CAAC;IAEnB;;OAEG;IACH,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC5D;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,MAAM,EAAE,UAAU,CAAC;IAEnB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/D;AAED;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,CAAC;AAEtE;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAC5B,wBAAwB,GACxB,IAAI,CAAC,qBAAqB,CAAC,GAC3B,WAAW,CAAC,qBAAqB,CAAC,CAAC;AAEvC;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,oBAAoB,CAAC;CAChC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,oBAAoB,GAC7B,QAAQ,IAAI,WAAW,CAAC,qBAAqB,CAAC,CAMhD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,oBAAoB,GAC7B,QAAQ,IAAI,IAAI,CAAC,qBAAqB,CAAC,CAazC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,oBAAoB,GAC7B,QAAQ,IAAI,wBAAwB,CAEtC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type guard to check if a renderer is a TemplateRef
|
|
3
|
+
*/
|
|
4
|
+
export function isTemplateRenderer(renderer) {
|
|
5
|
+
return (renderer !== null &&
|
|
6
|
+
typeof renderer === 'object' &&
|
|
7
|
+
'createEmbeddedView' in renderer);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Type guard to check if a renderer is an Angular Component
|
|
11
|
+
*
|
|
12
|
+
* Note: This uses a heuristic check based on the following assumptions:
|
|
13
|
+
* 1. Components are constructor functions
|
|
14
|
+
* 2. Components have a prototype with a constructor property
|
|
15
|
+
* 3. Components typically use dependency injection (no required constructor params)
|
|
16
|
+
*
|
|
17
|
+
* Limitation: This may not detect components with required constructor parameters.
|
|
18
|
+
* For edge cases, explicitly check your component's constructor signature.
|
|
19
|
+
*
|
|
20
|
+
* Alternative: You can always register a wrapper component that has no required params.
|
|
21
|
+
*/
|
|
22
|
+
export function isComponentRenderer(renderer) {
|
|
23
|
+
// Check if it's a function (constructor) but not a regular function renderer
|
|
24
|
+
if (typeof renderer !== 'function') {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
// Check for Angular component characteristics
|
|
28
|
+
// Components typically have prototype with constructor property
|
|
29
|
+
return (renderer.prototype !== undefined &&
|
|
30
|
+
renderer.prototype.constructor === renderer &&
|
|
31
|
+
renderer.length === 0 // Constructor with no required params (Angular DI)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Type guard to check if a renderer is an HTML function
|
|
36
|
+
*
|
|
37
|
+
* Note: This should be checked AFTER checking for component and template renderers
|
|
38
|
+
* since components are also functions but with additional properties.
|
|
39
|
+
*/
|
|
40
|
+
export function isHtmlRenderer(renderer) {
|
|
41
|
+
return typeof renderer === 'function';
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=custom-widget-renderer.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-widget-renderer.types.js","sourceRoot":"","sources":["../src/custom-widget-renderer.types.ts"],"names":[],"mappings":"AAkEA;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAA8B;IAE9B,OAAO,CACL,QAAQ,KAAK,IAAI;QACjB,OAAO,QAAQ,KAAK,QAAQ;QAC5B,oBAAoB,IAAI,QAAQ,CACjC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAA8B;IAE9B,6EAA6E;IAC7E,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8CAA8C;IAC9C,gEAAgE;IAChE,OAAO,CACL,QAAQ,CAAC,SAAS,KAAK,SAAS;QAChC,QAAQ,CAAC,SAAS,CAAC,WAAW,KAAK,QAAQ;QAC3C,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,mDAAmD;KAC1E,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,QAA8B;IAE9B,OAAO,OAAO,QAAQ,KAAK,UAAU,CAAC;AACxC,CAAC"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var index_exports = {};
|
|
20
|
+
__export(index_exports, {
|
|
21
|
+
ChatWidget: () => import_widgets.ChatWidget,
|
|
22
|
+
SsrWidgetRenderer: () => import_widgets2.SsrWidgetRenderer,
|
|
23
|
+
VERSION: () => VERSION,
|
|
24
|
+
WidgetEventManager: () => import_widgets2.WidgetEventManager,
|
|
25
|
+
WidgetRegistryService: () => import_widget_registry.WidgetRegistryService,
|
|
26
|
+
WidgetRendererComponent: () => import_widget_renderer.WidgetRendererComponent,
|
|
27
|
+
customWidgetRegistry: () => import_widgets2.customWidgetRegistry,
|
|
28
|
+
isComponentRenderer: () => import_custom_widget_renderer.isComponentRenderer,
|
|
29
|
+
isHtmlRenderer: () => import_custom_widget_renderer.isHtmlRenderer,
|
|
30
|
+
isTemplateRenderer: () => import_custom_widget_renderer.isTemplateRenderer
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(index_exports);
|
|
33
|
+
var import_widget_renderer = require("./widget-renderer.component");
|
|
34
|
+
var import_widget_registry = require("./widget-registry.service");
|
|
35
|
+
var import_custom_widget_renderer = require("./custom-widget-renderer.types");
|
|
36
|
+
var import_widgets = require("@bbq-chat/widgets");
|
|
37
|
+
var import_widgets2 = require("@bbq-chat/widgets");
|
|
38
|
+
const VERSION = "1.0.0";
|