@bbq-chat/widgets-angular
v1.0.8
Published
Angular components and services for BbQ ChatWidgets
Maintainers
Readme
@bbq-chat/widgets-angular
Angular components and services for BbQ ChatWidgets. This package provides Angular-native wrappers for the core @bbq-chat/widgets library.
Features
- ✨ Native Angular Components - All widgets render as Angular components with full framework support
- 🎨 Type-Safe - Full TypeScript support with comprehensive type definitions
- 🔄 Two-Way Data Binding - Leverage Angular's powerful data binding
- 🎯 Automatic Rendering - The
WidgetRendererComponentautomatically usesAngularWidgetRendererfor all built-in widgets - 🔧 Extensible - Easy custom widget registration with full Angular component support
Installation
npm install @bbq-chat/widgets-angular @bbq-chat/widgetsPeer Dependencies
This package requires:
@angular/common>= 17.0.0@angular/core>= 17.0.0@bbq-chat/widgets^1.0.0
Quick Start
1. Import the component
import { Component } from '@angular/core';
import { WidgetRendererComponent } from '@bbq-chat/widgets-angular';
import type { ChatWidget } from '@bbq-chat/widgets-angular';
@Component({
selector: 'app-chat',
standalone: true,
imports: [WidgetRendererComponent],
template: `
<bbq-widget-renderer
[widgets]="widgets"
(widgetAction)="handleWidgetAction($event)">
</bbq-widget-renderer>
`
})
export class ChatComponent {
widgets: ChatWidget[] = [];
handleWidgetAction(event: { actionName: string; payload: any }) {
console.log('Widget action:', event.actionName, event.payload);
// Handle the action (e.g., send to backend)
}
}2. Import styles
In your styles.css or styles.scss:
@import '@bbq-chat/widgets/styles';Or import a specific theme:
@import '@bbq-chat/widgets/styles/light';
@import '@bbq-chat/widgets/styles/dark';
@import '@bbq-chat/widgets/styles/corporate';Components
WidgetRendererComponent
The main component for rendering chat widgets. It automatically uses the AngularWidgetRenderer to render all built-in widgets as native Angular components.
Rendering Modes:
- Built-in widgets (button, card, form, etc.) are rendered as Angular components via
AngularWidgetRenderer - Custom widgets can use HTML functions, Angular components, or Angular templates
- Falls back to
SsrWidgetRenderer(HTML string rendering) if needed for compatibility
Inputs:
widgets: ChatWidget[] | null | undefined- Array of widgets to render
Outputs:
widgetAction: EventEmitter<{ actionName: string; payload: any }>- Emits when a widget action is triggered
Example:
<bbq-widget-renderer
[widgets]="messageWidgets"
(widgetAction)="onWidgetAction($event)">
</bbq-widget-renderer>Services
WidgetRegistryService
Service for registering custom widget types.
Example:
import { Component, OnInit } from '@angular/core';
import { WidgetRegistryService } from '@bbq-chat/widgets-angular';
export class MyCustomWidget {
type = 'myCustomWidget';
constructor(public label: string, public action: string) {}
}
@Component({
selector: 'app-root',
template: '...'
})
export class AppComponent implements OnInit {
constructor(private widgetRegistry: WidgetRegistryService) {}
ngOnInit() {
// Register custom widget factory
this.widgetRegistry.registerFactory('myCustomWidget', (obj) => {
if (obj.type === 'myCustomWidget') {
return new MyCustomWidget(obj.label, obj.action);
}
return null;
});
}
}Widget Types
All standard widget types from @bbq-chat/widgets are supported and rendered as native Angular components:
ButtonWidget- Clickable buttonsCardWidget- Information cardsFormWidget- Form containers with validationInputWidget- Text input fieldsTextAreaWidget- Multi-line text inputDropdownWidget- Dropdown selectsSliderWidget- Range slidersToggleWidget- Toggle switchesFileUploadWidget- File upload controlsDatePickerWidget- Date pickersMultiSelectWidget- Multi-select dropdownsThemeSwitcherWidget- Theme switcher controlsProgressBarWidget- Progress indicatorsImageWidget- Image displaysImageCollectionWidget- Image galleries
AngularWidgetRenderer
The AngularWidgetRenderer is automatically used by WidgetRendererComponent to render all built-in widgets as native Angular components instead of HTML strings. This provides several advantages:
Benefits
- Native Angular Components - Full Angular lifecycle hooks, change detection, and dependency injection
- Type Safety - Strong typing throughout the rendering pipeline
- Better Performance - No need for
innerHTMLor manual DOM manipulation - Reactive Updates - Leverage Angular's reactive forms and data binding
- Testability - Easier to test with Angular TestBed
- Easy Component Swapping - Simple API to replace any widget component with your own
How It Works
The WidgetRendererComponent automatically detects and uses AngularWidgetRenderer for all built-in widget types:
// The WidgetRendererComponent automatically uses AngularWidgetRenderer
// No configuration needed - it just works!
<bbq-widget-renderer
[widgets]="widgets"
(widgetAction)="handleWidgetAction($event)">
</bbq-widget-renderer>Swapping Widget Components
You can easily replace any built-in widget component with your own custom implementation:
import { Component, OnInit, Inject } from '@angular/core';
import { ANGULAR_WIDGET_RENDERER, AngularWidgetRenderer } from '@bbq-chat/widgets-angular';
import { MyCustomButtonComponent } from './my-custom-button.component';
@Component({
selector: 'app-root',
template: '...'
})
export class AppComponent implements OnInit {
constructor(@Inject(ANGULAR_WIDGET_RENDERER) private renderer: AngularWidgetRenderer) {}
ngOnInit() {
// Replace the built-in button component with your custom one
this.renderer.registerComponent('button', MyCustomButtonComponent);
// Or register multiple components at once
this.renderer.registerComponents({
button: MyCustomButtonComponent,
input: MyCustomInputComponent,
card: MyCustomCardComponent
});
}
}Built-in Widget Components
All built-in widgets are available as standalone Angular components:
import {
ButtonWidgetComponent,
CardWidgetComponent,
FormWidgetComponent,
InputWidgetComponent,
// ... and more
} from '@bbq-chat/widgets-angular';These components can be used directly in your templates if needed, though typically you'll use them through WidgetRendererComponent.
Form Widget Dynamic Rendering
The FormWidgetComponent uses dynamic component rendering to render form fields. Instead of inline HTML, it dynamically instantiates the appropriate widget component (InputWidget, SliderWidget, etc.) for each field. This ensures consistency across all widgets and makes the form behavior automatically inherit any custom widget component replacements.
Advanced Usage
Handling Widget Actions
Widget actions are emitted when users interact with widgets. Handle these actions in your component:
async handleWidgetAction(event: { actionName: string; payload: any }) {
const { actionName, payload } = event;
try {
const response = await fetch('/api/chat/action', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: actionName, payload })
});
const data = await response.json();
// Update widgets with response
this.widgets = data.widgets;
} catch (error) {
console.error('Failed to handle widget action:', error);
}
}Custom Widget Renderers
The library now supports three types of custom widget renderers for enhanced flexibility:
1. HTML Function Renderer
Simple function that returns HTML strings:
this.widgetRegistry.registerRenderer('myWidget', (widget) => {
return `<div class="my-widget">${widget.label}</div>`;
});2. Angular Component Renderer (Recommended)
Use Angular components for full framework features including data binding, change detection, and dependency injection:
import { Component, Input } from '@angular/core';
import { CustomWidgetComponent } from '@bbq-chat/widgets-angular';
@Component({
selector: 'app-my-widget',
standalone: true,
template: `
<div class="my-widget">
<h3>{{ myWidget.title }}</h3>
<button (click)="onClick()">Action</button>
</div>
`
})
export class MyWidgetComponent implements CustomWidgetComponent {
@Input() widget!: ChatWidget;
widgetAction?: (actionName: string, payload: unknown) => void;
get myWidget(): MyCustomWidget {
return this.widget as MyCustomWidget;
}
onClick() {
this.widgetAction?.('my_action', { data: 'example' });
}
}
// Register the component
this.widgetRegistry.registerRenderer('myWidget', MyWidgetComponent);3. Angular Template Renderer
Use inline templates with full Angular template syntax:
import { WidgetTemplateContext } from '@bbq-chat/widgets-angular';
@Component({
template: `
<ng-template #myTemplate let-widget let-emitAction="emitAction">
<div class="my-widget">
<h3>{{ widget.title }}</h3>
<button (click)="emitAction('my_action', { data: 'example' })">
Action
</button>
</div>
</ng-template>
`
})
export class AppComponent implements OnInit {
@ViewChild('myTemplate', { static: true }) myTemplate!: TemplateRef<WidgetTemplateContext>;
ngOnInit() {
this.widgetRegistry.registerRenderer('myWidget', this.myTemplate);
}
}See EXAMPLES.md for detailed examples and best practices.
License
MIT
Repository
https://github.com/JeanMarcMbouma/BbQ.ChatWidgets
