@bbq-chat/widgets-angular 1.0.3 → 1.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.
@@ -0,0 +1,1992 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Input, Component, createComponent, ViewContainerRef, ViewChildren, InjectionToken, Injectable, EventEmitter, ViewChild, Output, Inject, Optional } from '@angular/core';
3
+ import * as i1 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import * as i2$1 from '@bbq-chat/widgets';
6
+ import { WidgetEventManager, SsrWidgetRenderer, customWidgetRegistry } from '@bbq-chat/widgets';
7
+ export { ChatWidget, SsrWidgetRenderer, WidgetEventManager, customWidgetRegistry } from '@bbq-chat/widgets';
8
+ import * as i2 from '@angular/forms';
9
+ import { FormsModule } from '@angular/forms';
10
+
11
+ /**
12
+ * Type guard to check if a renderer is a TemplateRef
13
+ */
14
+ function isTemplateRenderer(renderer) {
15
+ return (renderer !== null &&
16
+ typeof renderer === 'object' &&
17
+ 'createEmbeddedView' in renderer);
18
+ }
19
+ /**
20
+ * Type guard to check if a renderer is an Angular Component
21
+ *
22
+ * Note: This uses a heuristic check based on the following assumptions:
23
+ * 1. Components are constructor functions
24
+ * 2. Components have a prototype with a constructor property
25
+ * 3. Components typically use dependency injection (no required constructor params)
26
+ *
27
+ * Limitation: This may not detect components with required constructor parameters.
28
+ * For edge cases, explicitly check your component's constructor signature.
29
+ *
30
+ * Alternative: You can always register a wrapper component that has no required params.
31
+ */
32
+ function isComponentRenderer(renderer) {
33
+ // Check if it's a function (constructor) but not a regular function renderer
34
+ if (typeof renderer !== 'function') {
35
+ return false;
36
+ }
37
+ // Check for Angular component characteristics
38
+ // Components typically have prototype with constructor property
39
+ return (renderer.prototype !== undefined &&
40
+ renderer.prototype.constructor === renderer &&
41
+ renderer.length === 0 // Constructor with no required params (Angular DI)
42
+ );
43
+ }
44
+ /**
45
+ * Type guard to check if a renderer is an HTML function
46
+ *
47
+ * Note: This should be checked AFTER checking for component and template renderers
48
+ * since components are also functions but with additional properties.
49
+ */
50
+ function isHtmlRenderer(renderer) {
51
+ return typeof renderer === 'function';
52
+ }
53
+
54
+ /**
55
+ * Angular widget renderer
56
+ * Returns Angular component types for dynamic rendering
57
+ * Provides feature parity with SsrWidgetRenderer but uses Angular components
58
+ */
59
+ class AngularWidgetRenderer {
60
+ framework = 'Angular';
61
+ overrides;
62
+ componentRegistry = new Map();
63
+ constructor(options) {
64
+ this.overrides = options?.components;
65
+ }
66
+ /**
67
+ * Register all built-in widget components
68
+ * Must be called after components are imported to avoid circular dependencies
69
+ */
70
+ registerBuiltInComponents(components) {
71
+ for (const [type, component] of Object.entries(components)) {
72
+ this.componentRegistry.set(type, component);
73
+ }
74
+ }
75
+ /**
76
+ * Register or override a widget component
77
+ * Use this to replace built-in components or add custom ones
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * renderer.registerComponent('button', MyCustomButtonComponent);
82
+ * ```
83
+ */
84
+ registerComponent(type, component) {
85
+ this.componentRegistry.set(type, component);
86
+ }
87
+ /**
88
+ * Register multiple widget components at once
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * renderer.registerComponents({
93
+ * button: MyButtonComponent,
94
+ * card: MyCardComponent
95
+ * });
96
+ * ```
97
+ */
98
+ registerComponents(components) {
99
+ for (const [type, component] of Object.entries(components)) {
100
+ this.componentRegistry.set(type, component);
101
+ }
102
+ }
103
+ /**
104
+ * Get the Angular component type for a given widget
105
+ * Returns the component class that should be dynamically instantiated
106
+ */
107
+ getComponentType(widget) {
108
+ const type = widget.type;
109
+ // Check for custom override first
110
+ if (this.overrides && this.overrides[type]) {
111
+ return this.overrides[type];
112
+ }
113
+ // Check built-in registry
114
+ if (this.componentRegistry.has(type)) {
115
+ return this.componentRegistry.get(type);
116
+ }
117
+ return null;
118
+ }
119
+ /**
120
+ * Legacy method for IWidgetRenderer interface compatibility
121
+ * Not used in Angular rendering but required by interface
122
+ * @deprecated Use getComponentType() instead for Angular rendering
123
+ */
124
+ renderWidget(widget) {
125
+ // This method is not used in Angular rendering
126
+ // It's only here for interface compatibility
127
+ return `<!-- Angular component rendering for ${widget.type} -->`;
128
+ }
129
+ }
130
+
131
+ class ButtonWidgetComponent {
132
+ widget;
133
+ widgetAction;
134
+ get buttonWidget() {
135
+ return this.widget;
136
+ }
137
+ onClick() {
138
+ if (this.widgetAction) {
139
+ this.widgetAction(this.buttonWidget.action, {});
140
+ }
141
+ }
142
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ButtonWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
143
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: ButtonWidgetComponent, isStandalone: true, selector: "bbq-button-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
144
+ <button
145
+ class="bbq-widget bbq-button"
146
+ [attr.data-widget-type]="'button'"
147
+ [attr.data-action]="buttonWidget.action"
148
+ type="button"
149
+ (click)="onClick()">
150
+ {{ buttonWidget.label }}
151
+ </button>
152
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
153
+ }
154
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ButtonWidgetComponent, decorators: [{
155
+ type: Component,
156
+ args: [{ selector: 'bbq-button-widget', standalone: true, imports: [CommonModule], template: `
157
+ <button
158
+ class="bbq-widget bbq-button"
159
+ [attr.data-widget-type]="'button'"
160
+ [attr.data-action]="buttonWidget.action"
161
+ type="button"
162
+ (click)="onClick()">
163
+ {{ buttonWidget.label }}
164
+ </button>
165
+ ` }]
166
+ }], propDecorators: { widget: [{
167
+ type: Input
168
+ }] } });
169
+
170
+ class CardWidgetComponent {
171
+ widget;
172
+ widgetAction;
173
+ get cardWidget() {
174
+ return this.widget;
175
+ }
176
+ onClick() {
177
+ if (this.widgetAction) {
178
+ this.widgetAction(this.cardWidget.action, {});
179
+ }
180
+ }
181
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: CardWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
182
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: CardWidgetComponent, isStandalone: true, selector: "bbq-card-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
183
+ <div
184
+ class="bbq-widget bbq-card"
185
+ [attr.data-widget-type]="'card'"
186
+ [attr.data-action]="cardWidget.action"
187
+ role="article">
188
+ <h3 class="bbq-card-title">{{ cardWidget.title }}</h3>
189
+ @if (cardWidget.description) {
190
+ <p class="bbq-card-description">{{ cardWidget.description }}</p>
191
+ }
192
+ @if (cardWidget.imageUrl) {
193
+ <img
194
+ class="bbq-card-image"
195
+ [src]="cardWidget.imageUrl"
196
+ [alt]="cardWidget.title"
197
+ loading="lazy"
198
+ style="display:block;max-width:100%;height:auto;object-fit:cover;max-height:200px;border-radius:6px;margin-bottom:12px;" />
199
+ }
200
+ <button
201
+ class="bbq-card-action bbq-button"
202
+ [attr.data-action]="cardWidget.action"
203
+ type="button"
204
+ (click)="onClick()">
205
+ {{ cardWidget.label }}
206
+ </button>
207
+ </div>
208
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
209
+ }
210
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: CardWidgetComponent, decorators: [{
211
+ type: Component,
212
+ args: [{ selector: 'bbq-card-widget', standalone: true, imports: [CommonModule], template: `
213
+ <div
214
+ class="bbq-widget bbq-card"
215
+ [attr.data-widget-type]="'card'"
216
+ [attr.data-action]="cardWidget.action"
217
+ role="article">
218
+ <h3 class="bbq-card-title">{{ cardWidget.title }}</h3>
219
+ @if (cardWidget.description) {
220
+ <p class="bbq-card-description">{{ cardWidget.description }}</p>
221
+ }
222
+ @if (cardWidget.imageUrl) {
223
+ <img
224
+ class="bbq-card-image"
225
+ [src]="cardWidget.imageUrl"
226
+ [alt]="cardWidget.title"
227
+ loading="lazy"
228
+ style="display:block;max-width:100%;height:auto;object-fit:cover;max-height:200px;border-radius:6px;margin-bottom:12px;" />
229
+ }
230
+ <button
231
+ class="bbq-card-action bbq-button"
232
+ [attr.data-action]="cardWidget.action"
233
+ type="button"
234
+ (click)="onClick()">
235
+ {{ cardWidget.label }}
236
+ </button>
237
+ </div>
238
+ ` }]
239
+ }], propDecorators: { widget: [{
240
+ type: Input
241
+ }] } });
242
+
243
+ class InputWidgetComponent {
244
+ widget;
245
+ widgetAction;
246
+ value = '';
247
+ inputId = '';
248
+ get inputWidget() {
249
+ return this.widget;
250
+ }
251
+ get showLabel() {
252
+ const widget = this.inputWidget;
253
+ if (widget.hideLabel === true) {
254
+ return false;
255
+ }
256
+ if (widget.showLabel === false) {
257
+ return false;
258
+ }
259
+ return true;
260
+ }
261
+ get inputClasses() {
262
+ return this.isFormAppearance ? ['bbq-form-input'] : ['bbq-input'];
263
+ }
264
+ get isFormAppearance() {
265
+ return this.inputWidget.appearance === 'form';
266
+ }
267
+ ngOnInit() {
268
+ this.inputId = `bbq-${this.inputWidget.action.replace(/\s+/g, '-').toLowerCase()}-input`;
269
+ }
270
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: InputWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
271
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: InputWidgetComponent, isStandalone: true, selector: "bbq-input-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
272
+ <div
273
+ class="bbq-widget bbq-input"
274
+ [attr.data-widget-type]="'input'">
275
+ <label *ngIf="showLabel" class="bbq-input-label" [attr.for]="inputId">
276
+ {{ inputWidget.label }}
277
+ </label>
278
+ <input
279
+ type="text"
280
+ [id]="inputId"
281
+ [ngClass]="inputClasses"
282
+ [attr.data-action]="inputWidget.action"
283
+ [placeholder]="inputWidget.placeholder || ''"
284
+ [maxLength]="inputWidget.maxLength || 0"
285
+ [(ngModel)]="value" />
286
+ </div>
287
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
288
+ }
289
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: InputWidgetComponent, decorators: [{
290
+ type: Component,
291
+ args: [{ selector: 'bbq-input-widget', standalone: true, imports: [CommonModule, FormsModule], template: `
292
+ <div
293
+ class="bbq-widget bbq-input"
294
+ [attr.data-widget-type]="'input'">
295
+ <label *ngIf="showLabel" class="bbq-input-label" [attr.for]="inputId">
296
+ {{ inputWidget.label }}
297
+ </label>
298
+ <input
299
+ type="text"
300
+ [id]="inputId"
301
+ [ngClass]="inputClasses"
302
+ [attr.data-action]="inputWidget.action"
303
+ [placeholder]="inputWidget.placeholder || ''"
304
+ [maxLength]="inputWidget.maxLength || 0"
305
+ [(ngModel)]="value" />
306
+ </div>
307
+ ` }]
308
+ }], propDecorators: { widget: [{
309
+ type: Input
310
+ }] } });
311
+
312
+ class TextAreaWidgetComponent {
313
+ widget;
314
+ widgetAction;
315
+ value = '';
316
+ textareaId = '';
317
+ get textareaWidget() {
318
+ return this.widget;
319
+ }
320
+ get showLabel() {
321
+ const widget = this.textareaWidget;
322
+ if (widget.hideLabel === true) {
323
+ return false;
324
+ }
325
+ if (widget.showLabel === false) {
326
+ return false;
327
+ }
328
+ return true;
329
+ }
330
+ get textareaClasses() {
331
+ return this.isFormAppearance ? ['bbq-form-textarea'] : ['bbq-form-textarea', 'bbq-input'];
332
+ }
333
+ get isFormAppearance() {
334
+ return this.textareaWidget.appearance === 'form';
335
+ }
336
+ ngOnInit() {
337
+ this.textareaId = `bbq-${this.textareaWidget.action.replace(/\s+/g, '-').toLowerCase()}-textarea`;
338
+ }
339
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TextAreaWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
340
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: TextAreaWidgetComponent, isStandalone: true, selector: "bbq-textarea-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
341
+ <div
342
+ class="bbq-widget bbq-textarea"
343
+ [attr.data-widget-type]="'textarea'">
344
+ <label *ngIf="showLabel" class="bbq-textarea-label" [attr.for]="textareaId">
345
+ {{ textareaWidget.label }}
346
+ </label>
347
+ <textarea
348
+ [id]="textareaId"
349
+ [ngClass]="textareaClasses"
350
+ [attr.data-action]="textareaWidget.action"
351
+ [placeholder]="textareaWidget.placeholder || ''"
352
+ [maxLength]="textareaWidget.maxLength || 0"
353
+ [rows]="textareaWidget.rows || 4"
354
+ [(ngModel)]="value"></textarea>
355
+ </div>
356
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
357
+ }
358
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TextAreaWidgetComponent, decorators: [{
359
+ type: Component,
360
+ args: [{ selector: 'bbq-textarea-widget', standalone: true, imports: [CommonModule, FormsModule], template: `
361
+ <div
362
+ class="bbq-widget bbq-textarea"
363
+ [attr.data-widget-type]="'textarea'">
364
+ <label *ngIf="showLabel" class="bbq-textarea-label" [attr.for]="textareaId">
365
+ {{ textareaWidget.label }}
366
+ </label>
367
+ <textarea
368
+ [id]="textareaId"
369
+ [ngClass]="textareaClasses"
370
+ [attr.data-action]="textareaWidget.action"
371
+ [placeholder]="textareaWidget.placeholder || ''"
372
+ [maxLength]="textareaWidget.maxLength || 0"
373
+ [rows]="textareaWidget.rows || 4"
374
+ [(ngModel)]="value"></textarea>
375
+ </div>
376
+ ` }]
377
+ }], propDecorators: { widget: [{
378
+ type: Input
379
+ }] } });
380
+
381
+ class DropdownWidgetComponent {
382
+ widget;
383
+ widgetAction;
384
+ value = '';
385
+ selectId = '';
386
+ get dropdownWidget() {
387
+ return this.widget;
388
+ }
389
+ get showLabel() {
390
+ const widget = this.dropdownWidget;
391
+ if (widget.hideLabel === true) {
392
+ return false;
393
+ }
394
+ if (widget.showLabel === false) {
395
+ return false;
396
+ }
397
+ return true;
398
+ }
399
+ get selectClasses() {
400
+ return this.isFormAppearance ? ['bbq-form-select'] : ['bbq-dropdown'];
401
+ }
402
+ get isFormAppearance() {
403
+ return this.dropdownWidget.appearance === 'form';
404
+ }
405
+ ngOnInit() {
406
+ this.selectId = `bbq-${this.dropdownWidget.action.replace(/\s+/g, '-').toLowerCase()}-select`;
407
+ this.value = this.dropdownWidget.options[0] || '';
408
+ }
409
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DropdownWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
410
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: DropdownWidgetComponent, isStandalone: true, selector: "bbq-dropdown-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
411
+ <div
412
+ class="bbq-widget bbq-dropdown"
413
+ [attr.data-widget-type]="'dropdown'">
414
+ <label *ngIf="showLabel" class="bbq-dropdown-label" [attr.for]="selectId">
415
+ {{ dropdownWidget.label }}
416
+ </label>
417
+ <select
418
+ [id]="selectId"
419
+ [ngClass]="selectClasses"
420
+ [attr.data-action]="dropdownWidget.action"
421
+ [(ngModel)]="value">
422
+ @for (option of dropdownWidget.options; track option) {
423
+ <option [value]="option">{{ option }}</option>
424
+ }
425
+ </select>
426
+ </div>
427
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
428
+ }
429
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DropdownWidgetComponent, decorators: [{
430
+ type: Component,
431
+ args: [{ selector: 'bbq-dropdown-widget', standalone: true, imports: [CommonModule, FormsModule], template: `
432
+ <div
433
+ class="bbq-widget bbq-dropdown"
434
+ [attr.data-widget-type]="'dropdown'">
435
+ <label *ngIf="showLabel" class="bbq-dropdown-label" [attr.for]="selectId">
436
+ {{ dropdownWidget.label }}
437
+ </label>
438
+ <select
439
+ [id]="selectId"
440
+ [ngClass]="selectClasses"
441
+ [attr.data-action]="dropdownWidget.action"
442
+ [(ngModel)]="value">
443
+ @for (option of dropdownWidget.options; track option) {
444
+ <option [value]="option">{{ option }}</option>
445
+ }
446
+ </select>
447
+ </div>
448
+ ` }]
449
+ }], propDecorators: { widget: [{
450
+ type: Input
451
+ }] } });
452
+
453
+ class SliderWidgetComponent {
454
+ widget;
455
+ widgetAction;
456
+ value = 0;
457
+ sliderId = '';
458
+ get sliderWidget() {
459
+ return this.widget;
460
+ }
461
+ get showLabel() {
462
+ const widget = this.sliderWidget;
463
+ if (widget.hideLabel === true) {
464
+ return false;
465
+ }
466
+ if (widget.showLabel === false) {
467
+ return false;
468
+ }
469
+ return true;
470
+ }
471
+ get sliderClasses() {
472
+ return this.isFormAppearance ? ['bbq-form-slider'] : ['bbq-slider'];
473
+ }
474
+ get isFormAppearance() {
475
+ return this.sliderWidget.appearance === 'form';
476
+ }
477
+ ngOnInit() {
478
+ this.sliderId = `bbq-${this.sliderWidget.action.replace(/\s+/g, '-').toLowerCase()}-slider`;
479
+ this.value = this.sliderWidget.defaultValue ?? this.sliderWidget.min;
480
+ }
481
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SliderWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
482
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: SliderWidgetComponent, isStandalone: true, selector: "bbq-slider-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
483
+ <div
484
+ class="bbq-widget bbq-slider"
485
+ [attr.data-widget-type]="'slider'">
486
+ <label *ngIf="showLabel" class="bbq-slider-label" [attr.for]="sliderId">
487
+ {{ sliderWidget.label }}
488
+ </label>
489
+ <input
490
+ type="range"
491
+ [id]="sliderId"
492
+ [ngClass]="sliderClasses"
493
+ [min]="sliderWidget.min"
494
+ [max]="sliderWidget.max"
495
+ [step]="sliderWidget.step"
496
+ [attr.data-action]="sliderWidget.action"
497
+ [attr.aria-label]="sliderWidget.label"
498
+ [(ngModel)]="value" />
499
+ <span class="bbq-slider-value" aria-live="polite">{{ value }}</span>
500
+ </div>
501
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
502
+ }
503
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SliderWidgetComponent, decorators: [{
504
+ type: Component,
505
+ args: [{ selector: 'bbq-slider-widget', standalone: true, imports: [CommonModule, FormsModule], template: `
506
+ <div
507
+ class="bbq-widget bbq-slider"
508
+ [attr.data-widget-type]="'slider'">
509
+ <label *ngIf="showLabel" class="bbq-slider-label" [attr.for]="sliderId">
510
+ {{ sliderWidget.label }}
511
+ </label>
512
+ <input
513
+ type="range"
514
+ [id]="sliderId"
515
+ [ngClass]="sliderClasses"
516
+ [min]="sliderWidget.min"
517
+ [max]="sliderWidget.max"
518
+ [step]="sliderWidget.step"
519
+ [attr.data-action]="sliderWidget.action"
520
+ [attr.aria-label]="sliderWidget.label"
521
+ [(ngModel)]="value" />
522
+ <span class="bbq-slider-value" aria-live="polite">{{ value }}</span>
523
+ </div>
524
+ ` }]
525
+ }], propDecorators: { widget: [{
526
+ type: Input
527
+ }] } });
528
+
529
+ class ToggleWidgetComponent {
530
+ widget;
531
+ widgetAction;
532
+ checked = false;
533
+ checkboxId = '';
534
+ get toggleWidget() {
535
+ return this.widget;
536
+ }
537
+ get showLabel() {
538
+ const widget = this.toggleWidget;
539
+ if (widget.hideLabel === true) {
540
+ return false;
541
+ }
542
+ if (widget.showLabel === false) {
543
+ return false;
544
+ }
545
+ return true;
546
+ }
547
+ get checkboxClasses() {
548
+ return this.isFormAppearance ? ['bbq-toggle-input', 'bbq-form-toggle'] : ['bbq-toggle-input'];
549
+ }
550
+ get isFormAppearance() {
551
+ return this.toggleWidget.appearance === 'form';
552
+ }
553
+ ngOnInit() {
554
+ this.checkboxId = `bbq-${this.toggleWidget.action.replace(/\s+/g, '-').toLowerCase()}-checkbox`;
555
+ this.checked = this.toggleWidget.defaultValue ?? false;
556
+ }
557
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ToggleWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
558
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: ToggleWidgetComponent, isStandalone: true, selector: "bbq-toggle-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
559
+ <div
560
+ class="bbq-widget bbq-toggle"
561
+ [attr.data-widget-type]="'toggle'">
562
+ <label class="bbq-toggle-label" [attr.for]="checkboxId">
563
+ <input
564
+ type="checkbox"
565
+ [id]="checkboxId"
566
+ [ngClass]="checkboxClasses"
567
+ [attr.data-action]="toggleWidget.action"
568
+ [attr.aria-label]="toggleWidget.label"
569
+ [(ngModel)]="checked" />
570
+ <span *ngIf="showLabel" class="bbq-toggle-text">{{ toggleWidget.label }}</span>
571
+ </label>
572
+ </div>
573
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
574
+ }
575
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ToggleWidgetComponent, decorators: [{
576
+ type: Component,
577
+ args: [{ selector: 'bbq-toggle-widget', standalone: true, imports: [CommonModule, FormsModule], template: `
578
+ <div
579
+ class="bbq-widget bbq-toggle"
580
+ [attr.data-widget-type]="'toggle'">
581
+ <label class="bbq-toggle-label" [attr.for]="checkboxId">
582
+ <input
583
+ type="checkbox"
584
+ [id]="checkboxId"
585
+ [ngClass]="checkboxClasses"
586
+ [attr.data-action]="toggleWidget.action"
587
+ [attr.aria-label]="toggleWidget.label"
588
+ [(ngModel)]="checked" />
589
+ <span *ngIf="showLabel" class="bbq-toggle-text">{{ toggleWidget.label }}</span>
590
+ </label>
591
+ </div>
592
+ ` }]
593
+ }], propDecorators: { widget: [{
594
+ type: Input
595
+ }] } });
596
+
597
+ class FileUploadWidgetComponent {
598
+ widget;
599
+ widgetAction;
600
+ inputId = '';
601
+ get fileUploadWidget() {
602
+ return this.widget;
603
+ }
604
+ get showLabel() {
605
+ const widget = this.fileUploadWidget;
606
+ if (widget.hideLabel === true) {
607
+ return false;
608
+ }
609
+ if (widget.showLabel === false) {
610
+ return false;
611
+ }
612
+ return true;
613
+ }
614
+ get inputClasses() {
615
+ return this.isFormAppearance ? ['bbq-form-fileupload'] : ['bbq-file'];
616
+ }
617
+ get isFormAppearance() {
618
+ return this.fileUploadWidget.appearance === 'form';
619
+ }
620
+ ngOnInit() {
621
+ this.inputId = `bbq-${this.fileUploadWidget.action.replace(/\s+/g, '-').toLowerCase()}-file`;
622
+ }
623
+ onFileChange(event) {
624
+ const target = event.target;
625
+ if (target.files && target.files.length > 0) {
626
+ const file = target.files[0];
627
+ if (this.widgetAction) {
628
+ this.widgetAction(this.fileUploadWidget.action, { file });
629
+ }
630
+ }
631
+ }
632
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FileUploadWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
633
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: FileUploadWidgetComponent, isStandalone: true, selector: "bbq-fileupload-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
634
+ <div
635
+ class="bbq-widget bbq-file-upload"
636
+ [attr.data-widget-type]="'fileupload'">
637
+ <label *ngIf="showLabel" class="bbq-file-label" [attr.for]="inputId">
638
+ {{ fileUploadWidget.label }}
639
+ </label>
640
+ <input
641
+ type="file"
642
+ [id]="inputId"
643
+ [ngClass]="inputClasses"
644
+ [attr.data-action]="fileUploadWidget.action"
645
+ [accept]="fileUploadWidget.accept || ''"
646
+ [attr.data-max-bytes]="fileUploadWidget.maxBytes"
647
+ (change)="onFileChange($event)" />
648
+ </div>
649
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
650
+ }
651
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FileUploadWidgetComponent, decorators: [{
652
+ type: Component,
653
+ args: [{ selector: 'bbq-fileupload-widget', standalone: true, imports: [CommonModule], template: `
654
+ <div
655
+ class="bbq-widget bbq-file-upload"
656
+ [attr.data-widget-type]="'fileupload'">
657
+ <label *ngIf="showLabel" class="bbq-file-label" [attr.for]="inputId">
658
+ {{ fileUploadWidget.label }}
659
+ </label>
660
+ <input
661
+ type="file"
662
+ [id]="inputId"
663
+ [ngClass]="inputClasses"
664
+ [attr.data-action]="fileUploadWidget.action"
665
+ [accept]="fileUploadWidget.accept || ''"
666
+ [attr.data-max-bytes]="fileUploadWidget.maxBytes"
667
+ (change)="onFileChange($event)" />
668
+ </div>
669
+ ` }]
670
+ }], propDecorators: { widget: [{
671
+ type: Input
672
+ }] } });
673
+
674
+ class ThemeSwitcherWidgetComponent {
675
+ widget;
676
+ widgetAction;
677
+ value = '';
678
+ selectId = '';
679
+ get themeSwitcherWidget() {
680
+ return this.widget;
681
+ }
682
+ ngOnInit() {
683
+ this.selectId = `bbq-${this.themeSwitcherWidget.action.replace(/\s+/g, '-').toLowerCase()}-select`;
684
+ this.value = this.themeSwitcherWidget.themes[0] || '';
685
+ }
686
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ThemeSwitcherWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
687
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: ThemeSwitcherWidgetComponent, isStandalone: true, selector: "bbq-themeswitcher-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
688
+ <div
689
+ class="bbq-widget bbq-theme-switcher"
690
+ [attr.data-widget-type]="'themeswitcher'">
691
+ <label class="bbq-theme-switcher-label" [attr.for]="selectId">
692
+ {{ themeSwitcherWidget.label }}
693
+ </label>
694
+ <select
695
+ [id]="selectId"
696
+ class="bbq-theme-switcher-select"
697
+ [attr.data-action]="themeSwitcherWidget.action"
698
+ [(ngModel)]="value">
699
+ @for (theme of themeSwitcherWidget.themes; track theme) {
700
+ <option [value]="theme">{{ theme }}</option>
701
+ }
702
+ </select>
703
+ </div>
704
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
705
+ }
706
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ThemeSwitcherWidgetComponent, decorators: [{
707
+ type: Component,
708
+ args: [{ selector: 'bbq-themeswitcher-widget', standalone: true, imports: [CommonModule, FormsModule], template: `
709
+ <div
710
+ class="bbq-widget bbq-theme-switcher"
711
+ [attr.data-widget-type]="'themeswitcher'">
712
+ <label class="bbq-theme-switcher-label" [attr.for]="selectId">
713
+ {{ themeSwitcherWidget.label }}
714
+ </label>
715
+ <select
716
+ [id]="selectId"
717
+ class="bbq-theme-switcher-select"
718
+ [attr.data-action]="themeSwitcherWidget.action"
719
+ [(ngModel)]="value">
720
+ @for (theme of themeSwitcherWidget.themes; track theme) {
721
+ <option [value]="theme">{{ theme }}</option>
722
+ }
723
+ </select>
724
+ </div>
725
+ ` }]
726
+ }], propDecorators: { widget: [{
727
+ type: Input
728
+ }] } });
729
+
730
+ class DatePickerWidgetComponent {
731
+ widget;
732
+ widgetAction;
733
+ value = '';
734
+ inputId = '';
735
+ get datePickerWidget() {
736
+ return this.widget;
737
+ }
738
+ get showLabel() {
739
+ const widget = this.datePickerWidget;
740
+ if (widget.hideLabel === true) {
741
+ return false;
742
+ }
743
+ if (widget.showLabel === false) {
744
+ return false;
745
+ }
746
+ return true;
747
+ }
748
+ get inputClasses() {
749
+ return this.isFormAppearance ? ['bbq-form-datepicker'] : ['bbq-form-datepicker', 'bbq-input'];
750
+ }
751
+ get isFormAppearance() {
752
+ return this.datePickerWidget.appearance === 'form';
753
+ }
754
+ ngOnInit() {
755
+ this.inputId = `bbq-${this.datePickerWidget.action.replace(/\s+/g, '-').toLowerCase()}-date`;
756
+ }
757
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DatePickerWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
758
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: DatePickerWidgetComponent, isStandalone: true, selector: "bbq-datepicker-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
759
+ <div
760
+ class="bbq-widget bbq-date-picker"
761
+ [attr.data-widget-type]="'datepicker'">
762
+ <label *ngIf="showLabel" class="bbq-date-picker-label" [attr.for]="inputId">
763
+ {{ datePickerWidget.label }}
764
+ </label>
765
+ <input
766
+ type="date"
767
+ [id]="inputId"
768
+ [ngClass]="inputClasses"
769
+ [attr.data-action]="datePickerWidget.action"
770
+ [min]="datePickerWidget.minDate || ''"
771
+ [max]="datePickerWidget.maxDate || ''"
772
+ [(ngModel)]="value" />
773
+ </div>
774
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
775
+ }
776
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: DatePickerWidgetComponent, decorators: [{
777
+ type: Component,
778
+ args: [{ selector: 'bbq-datepicker-widget', standalone: true, imports: [CommonModule, FormsModule], template: `
779
+ <div
780
+ class="bbq-widget bbq-date-picker"
781
+ [attr.data-widget-type]="'datepicker'">
782
+ <label *ngIf="showLabel" class="bbq-date-picker-label" [attr.for]="inputId">
783
+ {{ datePickerWidget.label }}
784
+ </label>
785
+ <input
786
+ type="date"
787
+ [id]="inputId"
788
+ [ngClass]="inputClasses"
789
+ [attr.data-action]="datePickerWidget.action"
790
+ [min]="datePickerWidget.minDate || ''"
791
+ [max]="datePickerWidget.maxDate || ''"
792
+ [(ngModel)]="value" />
793
+ </div>
794
+ ` }]
795
+ }], propDecorators: { widget: [{
796
+ type: Input
797
+ }] } });
798
+
799
+ class MultiSelectWidgetComponent {
800
+ widget;
801
+ widgetAction;
802
+ values = [];
803
+ selectId = '';
804
+ get multiSelectWidget() {
805
+ return this.widget;
806
+ }
807
+ get showLabel() {
808
+ const widget = this.multiSelectWidget;
809
+ if (widget.hideLabel === true) {
810
+ return false;
811
+ }
812
+ if (widget.showLabel === false) {
813
+ return false;
814
+ }
815
+ return true;
816
+ }
817
+ get selectClasses() {
818
+ return this.isFormAppearance
819
+ ? ['bbq-form-multiselect', 'bbq-form-select']
820
+ : ['bbq-form-multiselect', 'bbq-form-select'];
821
+ }
822
+ get isFormAppearance() {
823
+ return this.multiSelectWidget.appearance === 'form';
824
+ }
825
+ ngOnInit() {
826
+ this.selectId = `bbq-${this.multiSelectWidget.action.replace(/\s+/g, '-').toLowerCase()}-select`;
827
+ }
828
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MultiSelectWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
829
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: MultiSelectWidgetComponent, isStandalone: true, selector: "bbq-multiselect-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
830
+ <div
831
+ class="bbq-widget bbq-multi-select"
832
+ [attr.data-widget-type]="'multiselect'">
833
+ <label *ngIf="showLabel" class="bbq-multi-select-label" [attr.for]="selectId">
834
+ {{ multiSelectWidget.label }}
835
+ </label>
836
+ <select
837
+ [id]="selectId"
838
+ [ngClass]="selectClasses"
839
+ [attr.data-action]="multiSelectWidget.action"
840
+ multiple
841
+ [(ngModel)]="values">
842
+ @for (option of multiSelectWidget.options; track option) {
843
+ <option [value]="option">{{ option }}</option>
844
+ }
845
+ </select>
846
+ </div>
847
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.SelectMultipleControlValueAccessor, selector: "select[multiple][formControlName],select[multiple][formControl],select[multiple][ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
848
+ }
849
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MultiSelectWidgetComponent, decorators: [{
850
+ type: Component,
851
+ args: [{ selector: 'bbq-multiselect-widget', standalone: true, imports: [CommonModule, FormsModule], template: `
852
+ <div
853
+ class="bbq-widget bbq-multi-select"
854
+ [attr.data-widget-type]="'multiselect'">
855
+ <label *ngIf="showLabel" class="bbq-multi-select-label" [attr.for]="selectId">
856
+ {{ multiSelectWidget.label }}
857
+ </label>
858
+ <select
859
+ [id]="selectId"
860
+ [ngClass]="selectClasses"
861
+ [attr.data-action]="multiSelectWidget.action"
862
+ multiple
863
+ [(ngModel)]="values">
864
+ @for (option of multiSelectWidget.options; track option) {
865
+ <option [value]="option">{{ option }}</option>
866
+ }
867
+ </select>
868
+ </div>
869
+ ` }]
870
+ }], propDecorators: { widget: [{
871
+ type: Input
872
+ }] } });
873
+
874
+ class ProgressBarWidgetComponent {
875
+ widget;
876
+ widgetAction;
877
+ progressId = '';
878
+ percentage = 0;
879
+ get progressBarWidget() {
880
+ return this.widget;
881
+ }
882
+ ngOnInit() {
883
+ this.progressId = `bbq-${this.progressBarWidget.action.replace(/\s+/g, '-').toLowerCase()}-progress`;
884
+ const max = this.progressBarWidget.max;
885
+ this.percentage = max > 0 ? Math.floor((this.progressBarWidget.value * 100) / max) : 0;
886
+ }
887
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ProgressBarWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
888
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: ProgressBarWidgetComponent, isStandalone: true, selector: "bbq-progressbar-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
889
+ <div
890
+ class="bbq-widget bbq-progress-bar"
891
+ [attr.data-widget-type]="'progressbar'">
892
+ <label class="bbq-progress-bar-label" [attr.for]="progressId">
893
+ {{ progressBarWidget.label }}
894
+ </label>
895
+ <progress
896
+ [id]="progressId"
897
+ class="bbq-progress-bar-element"
898
+ [value]="progressBarWidget.value"
899
+ [max]="progressBarWidget.max"
900
+ [attr.data-action]="progressBarWidget.action"
901
+ [attr.aria-label]="progressBarWidget.label"
902
+ [attr.aria-valuenow]="progressBarWidget.value"
903
+ [attr.aria-valuemin]="0"
904
+ [attr.aria-valuemax]="progressBarWidget.max">
905
+ {{ percentage }}%
906
+ </progress>
907
+ <span class="bbq-progress-bar-value" aria-live="polite">{{ percentage }}%</span>
908
+ </div>
909
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
910
+ }
911
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ProgressBarWidgetComponent, decorators: [{
912
+ type: Component,
913
+ args: [{ selector: 'bbq-progressbar-widget', standalone: true, imports: [CommonModule], template: `
914
+ <div
915
+ class="bbq-widget bbq-progress-bar"
916
+ [attr.data-widget-type]="'progressbar'">
917
+ <label class="bbq-progress-bar-label" [attr.for]="progressId">
918
+ {{ progressBarWidget.label }}
919
+ </label>
920
+ <progress
921
+ [id]="progressId"
922
+ class="bbq-progress-bar-element"
923
+ [value]="progressBarWidget.value"
924
+ [max]="progressBarWidget.max"
925
+ [attr.data-action]="progressBarWidget.action"
926
+ [attr.aria-label]="progressBarWidget.label"
927
+ [attr.aria-valuenow]="progressBarWidget.value"
928
+ [attr.aria-valuemin]="0"
929
+ [attr.aria-valuemax]="progressBarWidget.max">
930
+ {{ percentage }}%
931
+ </progress>
932
+ <span class="bbq-progress-bar-value" aria-live="polite">{{ percentage }}%</span>
933
+ </div>
934
+ ` }]
935
+ }], propDecorators: { widget: [{
936
+ type: Input
937
+ }] } });
938
+
939
+ /**
940
+ * Helper class to wrap form fields as widgets for dynamic rendering
941
+ */
942
+ class FormFieldWidget {
943
+ field;
944
+ formId;
945
+ type;
946
+ label;
947
+ action;
948
+ appearance = 'form';
949
+ hideLabel = true;
950
+ constructor(field, formId) {
951
+ this.field = field;
952
+ this.formId = formId;
953
+ this.type = this.mapFieldTypeToWidgetType(field.type);
954
+ this.label = field.label;
955
+ this.action = `${formId}_${field.name}`;
956
+ }
957
+ mapFieldTypeToWidgetType(fieldType) {
958
+ const typeMap = {
959
+ 'input': 'input',
960
+ 'text': 'input',
961
+ 'email': 'input',
962
+ 'number': 'input',
963
+ 'password': 'input',
964
+ 'textarea': 'textarea',
965
+ 'dropdown': 'dropdown',
966
+ 'select': 'dropdown',
967
+ 'slider': 'slider',
968
+ 'toggle': 'toggle',
969
+ 'datepicker': 'datepicker',
970
+ 'multiselect': 'multiselect',
971
+ 'fileupload': 'fileupload'
972
+ };
973
+ return typeMap[fieldType] || 'input';
974
+ }
975
+ // Map field properties to widget properties
976
+ get placeholder() {
977
+ return this.field.placeholder ?? undefined;
978
+ }
979
+ get maxLength() {
980
+ return this.field['maxLength'];
981
+ }
982
+ get rows() {
983
+ return this.field['rows'];
984
+ }
985
+ get options() {
986
+ return this.field['options'] || [];
987
+ }
988
+ get min() {
989
+ return this.field['min'] ?? 0;
990
+ }
991
+ get max() {
992
+ return this.field['max'] ?? 100;
993
+ }
994
+ get step() {
995
+ return this.field['step'] ?? 1;
996
+ }
997
+ get defaultValue() {
998
+ return this.field['defaultValue'] ?? (this.type === 'slider' ? this.min : undefined);
999
+ }
1000
+ get minDate() {
1001
+ return this.field['minDate'];
1002
+ }
1003
+ get maxDate() {
1004
+ return this.field['maxDate'];
1005
+ }
1006
+ get accept() {
1007
+ return this.field['accept'];
1008
+ }
1009
+ get maxBytes() {
1010
+ return this.field['maxBytes'];
1011
+ }
1012
+ // ChatWidget interface methods
1013
+ toJson() {
1014
+ return JSON.stringify(this.toObject());
1015
+ }
1016
+ toObject() {
1017
+ return {
1018
+ type: this.type,
1019
+ label: this.label,
1020
+ action: this.action,
1021
+ ...this.field
1022
+ };
1023
+ }
1024
+ }
1025
+ class FormWidgetComponent {
1026
+ injector;
1027
+ environmentInjector;
1028
+ widget;
1029
+ widgetAction;
1030
+ fieldContainers;
1031
+ formId = '';
1032
+ formData = {};
1033
+ showValidationMessage = false;
1034
+ componentRefs = [];
1035
+ // Component registry for field types
1036
+ fieldComponentRegistry = {
1037
+ 'input': InputWidgetComponent,
1038
+ 'text': InputWidgetComponent,
1039
+ 'email': InputWidgetComponent,
1040
+ 'number': InputWidgetComponent,
1041
+ 'password': InputWidgetComponent,
1042
+ 'textarea': TextAreaWidgetComponent,
1043
+ 'dropdown': DropdownWidgetComponent,
1044
+ 'select': DropdownWidgetComponent,
1045
+ 'slider': SliderWidgetComponent,
1046
+ 'toggle': ToggleWidgetComponent,
1047
+ 'datepicker': DatePickerWidgetComponent,
1048
+ 'multiselect': MultiSelectWidgetComponent,
1049
+ 'fileupload': FileUploadWidgetComponent,
1050
+ 'checkbox': ToggleWidgetComponent,
1051
+ 'radio': ToggleWidgetComponent,
1052
+ };
1053
+ get formWidget() {
1054
+ return this.widget;
1055
+ }
1056
+ constructor(injector, environmentInjector) {
1057
+ this.injector = injector;
1058
+ this.environmentInjector = environmentInjector;
1059
+ }
1060
+ ngOnInit() {
1061
+ this.formId = `bbq-${this.formWidget.action.replace(/\s+/g, '-').toLowerCase()}`;
1062
+ // Initialize form data with default values
1063
+ for (const field of this.formWidget.fields || []) {
1064
+ if (field.type === 'slider') {
1065
+ this.formData[field.name] = field['default'] ?? field['defaultValue'] ?? field['min'] ?? 0;
1066
+ }
1067
+ else if (field.type === 'toggle' || field.type === 'checkbox') {
1068
+ this.formData[field.name] = field['defaultValue'] ?? false;
1069
+ }
1070
+ else if (field.type === 'multiselect') {
1071
+ this.formData[field.name] = [];
1072
+ }
1073
+ else {
1074
+ this.formData[field.name] = '';
1075
+ }
1076
+ }
1077
+ }
1078
+ ngAfterViewInit() {
1079
+ // Render field widgets dynamically
1080
+ setTimeout(() => this.renderFieldWidgets(), 0);
1081
+ }
1082
+ ngOnDestroy() {
1083
+ // Clean up component refs
1084
+ this.componentRefs.forEach(ref => ref.destroy());
1085
+ this.componentRefs = [];
1086
+ }
1087
+ renderFieldWidgets() {
1088
+ const containers = this.fieldContainers.toArray();
1089
+ const fields = this.formWidget.fields || [];
1090
+ fields.forEach((field, index) => {
1091
+ const container = containers[index];
1092
+ if (!container)
1093
+ return;
1094
+ const componentType = this.fieldComponentRegistry[field.type];
1095
+ if (!componentType) {
1096
+ // Fallback to input for unknown types
1097
+ this.renderInputFallback(container, field);
1098
+ return;
1099
+ }
1100
+ // Create the field widget
1101
+ const fieldWidget = new FormFieldWidget(field, this.formId);
1102
+ // Create the component
1103
+ const componentRef = createComponent(componentType, {
1104
+ environmentInjector: this.environmentInjector,
1105
+ elementInjector: this.injector,
1106
+ });
1107
+ // Set component inputs
1108
+ const instance = componentRef.instance;
1109
+ instance['widget'] = fieldWidget;
1110
+ // Connect to form data via widgetAction
1111
+ instance['widgetAction'] = (actionName, payload) => {
1112
+ // Handle field value changes - for now, we'll sync via the rendered widget's internal state
1113
+ // The actual form submission will gather values from the DOM
1114
+ };
1115
+ // Attach to container
1116
+ container.insert(componentRef.hostView);
1117
+ this.componentRefs.push(componentRef);
1118
+ // Trigger change detection
1119
+ componentRef.changeDetectorRef.detectChanges();
1120
+ });
1121
+ }
1122
+ renderInputFallback(container, field) {
1123
+ // For unsupported field types, render a basic input
1124
+ const fieldWidget = new FormFieldWidget(field, this.formId);
1125
+ const componentRef = createComponent(InputWidgetComponent, {
1126
+ environmentInjector: this.environmentInjector,
1127
+ elementInjector: this.injector,
1128
+ });
1129
+ const instance = componentRef.instance;
1130
+ instance['widget'] = fieldWidget;
1131
+ container.insert(componentRef.hostView);
1132
+ this.componentRefs.push(componentRef);
1133
+ componentRef.changeDetectorRef.detectChanges();
1134
+ }
1135
+ getFieldId(fieldName) {
1136
+ // Match the ID format used by dynamically rendered input widgets
1137
+ return `bbq-${this.formId}_${fieldName}-input`;
1138
+ }
1139
+ getFieldProp(field, prop) {
1140
+ return field[prop];
1141
+ }
1142
+ onActionClick(actionType) {
1143
+ if (actionType === 'submit') {
1144
+ // Validate required fields
1145
+ const hasErrors = this.validateForm();
1146
+ if (hasErrors) {
1147
+ this.showValidationMessage = true;
1148
+ return;
1149
+ }
1150
+ this.showValidationMessage = false;
1151
+ // Gather form data from the DOM (since widgets manage their own state)
1152
+ this.gatherFormData();
1153
+ if (this.widgetAction) {
1154
+ this.widgetAction(this.formWidget.action, this.formData);
1155
+ }
1156
+ }
1157
+ else {
1158
+ // Cancel or other actions
1159
+ if (this.widgetAction) {
1160
+ this.widgetAction(this.formWidget.action, { actionType });
1161
+ }
1162
+ }
1163
+ }
1164
+ validateForm() {
1165
+ for (const field of this.formWidget.fields || []) {
1166
+ if (field.required) {
1167
+ const value = this.formData[field.name];
1168
+ if (value === undefined || value === null || value === '' ||
1169
+ (Array.isArray(value) && value.length === 0)) {
1170
+ return true; // Has errors
1171
+ }
1172
+ }
1173
+ }
1174
+ return false; // No errors
1175
+ }
1176
+ gatherFormData() {
1177
+ // Gather data from the rendered field widgets
1178
+ // Since each widget component manages its own state via ngModel,
1179
+ // we need to query the DOM to get the current values
1180
+ const fields = this.formWidget.fields || [];
1181
+ fields.forEach((field) => {
1182
+ const fieldId = this.getFieldId(field.name);
1183
+ const element = document.getElementById(fieldId);
1184
+ if (element) {
1185
+ if (element.type === 'checkbox') {
1186
+ this.formData[field.name] = element.checked;
1187
+ }
1188
+ else if (element.type === 'file') {
1189
+ this.formData[field.name] = element.files?.[0];
1190
+ }
1191
+ else if (element.tagName === 'SELECT' && element.multiple) {
1192
+ const select = element;
1193
+ this.formData[field.name] = Array.from(select.selectedOptions).map(opt => opt.value);
1194
+ }
1195
+ else {
1196
+ this.formData[field.name] = element.value;
1197
+ }
1198
+ }
1199
+ });
1200
+ }
1201
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FormWidgetComponent, deps: [{ token: i0.Injector }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Component });
1202
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: FormWidgetComponent, isStandalone: true, selector: "bbq-form-widget", inputs: { widget: "widget" }, viewQueries: [{ propertyName: "fieldContainers", predicate: ["fieldContainer"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: `
1203
+ <div
1204
+ class="bbq-widget bbq-form"
1205
+ [attr.data-widget-id]="formId"
1206
+ [attr.data-widget-type]="'form'"
1207
+ [attr.data-action]="formWidget.action">
1208
+ <fieldset class="bbq-form-fieldset">
1209
+ <legend class="bbq-form-title">{{ formWidget.title }}</legend>
1210
+
1211
+ @for (field of formWidget.fields; track field.name) {
1212
+ <div
1213
+ class="bbq-form-field"
1214
+ [class.bbq-form-field-required]="field.required"
1215
+ [attr.data-required]="field.required ? 'true' : null">
1216
+ <label class="bbq-form-field-label" [attr.for]="getFieldId(field.name)">
1217
+ {{ field.label }}
1218
+ @if (field.required) {
1219
+ <span class="bbq-form-required">*</span>
1220
+ }
1221
+ </label>
1222
+
1223
+ <div #fieldContainer class="bbq-form-field-widget"></div>
1224
+
1225
+ @if (getFieldProp(field, 'validationHint')) {
1226
+ <span class="bbq-form-field-hint">{{ getFieldProp(field, 'validationHint') }}</span>
1227
+ }
1228
+ </div>
1229
+ }
1230
+
1231
+ <div class="bbq-form-validation-message" [style.display]="showValidationMessage ? 'block' : 'none'">
1232
+ Please fill in all required fields before submitting.
1233
+ </div>
1234
+
1235
+ @if (formWidget.actions && formWidget.actions.length > 0) {
1236
+ <div class="bbq-form-actions">
1237
+ @for (action of formWidget.actions; track action.label) {
1238
+ <button
1239
+ type="button"
1240
+ class="bbq-form-button"
1241
+ [class.bbq-form-submit]="action.type === 'submit'"
1242
+ [class.bbq-form-cancel]="action.type !== 'submit'"
1243
+ [attr.data-action]="formWidget.action"
1244
+ [attr.data-action-type]="action.type"
1245
+ (click)="onActionClick(action.type)">
1246
+ {{ action.label }}
1247
+ </button>
1248
+ }
1249
+ </div>
1250
+ }
1251
+ </fieldset>
1252
+ </div>
1253
+ `, isInline: true, styles: [".bbq-form-field-widget{display:contents}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }] });
1254
+ }
1255
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: FormWidgetComponent, decorators: [{
1256
+ type: Component,
1257
+ args: [{ selector: 'bbq-form-widget', standalone: true, imports: [CommonModule, FormsModule], template: `
1258
+ <div
1259
+ class="bbq-widget bbq-form"
1260
+ [attr.data-widget-id]="formId"
1261
+ [attr.data-widget-type]="'form'"
1262
+ [attr.data-action]="formWidget.action">
1263
+ <fieldset class="bbq-form-fieldset">
1264
+ <legend class="bbq-form-title">{{ formWidget.title }}</legend>
1265
+
1266
+ @for (field of formWidget.fields; track field.name) {
1267
+ <div
1268
+ class="bbq-form-field"
1269
+ [class.bbq-form-field-required]="field.required"
1270
+ [attr.data-required]="field.required ? 'true' : null">
1271
+ <label class="bbq-form-field-label" [attr.for]="getFieldId(field.name)">
1272
+ {{ field.label }}
1273
+ @if (field.required) {
1274
+ <span class="bbq-form-required">*</span>
1275
+ }
1276
+ </label>
1277
+
1278
+ <div #fieldContainer class="bbq-form-field-widget"></div>
1279
+
1280
+ @if (getFieldProp(field, 'validationHint')) {
1281
+ <span class="bbq-form-field-hint">{{ getFieldProp(field, 'validationHint') }}</span>
1282
+ }
1283
+ </div>
1284
+ }
1285
+
1286
+ <div class="bbq-form-validation-message" [style.display]="showValidationMessage ? 'block' : 'none'">
1287
+ Please fill in all required fields before submitting.
1288
+ </div>
1289
+
1290
+ @if (formWidget.actions && formWidget.actions.length > 0) {
1291
+ <div class="bbq-form-actions">
1292
+ @for (action of formWidget.actions; track action.label) {
1293
+ <button
1294
+ type="button"
1295
+ class="bbq-form-button"
1296
+ [class.bbq-form-submit]="action.type === 'submit'"
1297
+ [class.bbq-form-cancel]="action.type !== 'submit'"
1298
+ [attr.data-action]="formWidget.action"
1299
+ [attr.data-action-type]="action.type"
1300
+ (click)="onActionClick(action.type)">
1301
+ {{ action.label }}
1302
+ </button>
1303
+ }
1304
+ </div>
1305
+ }
1306
+ </fieldset>
1307
+ </div>
1308
+ `, styles: [".bbq-form-field-widget{display:contents}\n"] }]
1309
+ }], ctorParameters: () => [{ type: i0.Injector }, { type: i0.EnvironmentInjector }], propDecorators: { widget: [{
1310
+ type: Input
1311
+ }], fieldContainers: [{
1312
+ type: ViewChildren,
1313
+ args: ['fieldContainer', { read: ViewContainerRef }]
1314
+ }] } });
1315
+
1316
+ class ImageWidgetComponent {
1317
+ widget;
1318
+ widgetAction;
1319
+ get imageWidget() {
1320
+ return this.widget;
1321
+ }
1322
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ImageWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1323
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.8", type: ImageWidgetComponent, isStandalone: true, selector: "bbq-image-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
1324
+ <div
1325
+ class="bbq-widget bbq-image"
1326
+ [attr.data-widget-type]="'image'"
1327
+ [attr.data-action]="imageWidget.action">
1328
+ <img
1329
+ class="bbq-image-img"
1330
+ [src]="imageWidget.imageUrl"
1331
+ [alt]="imageWidget.alt || 'Image'"
1332
+ [style.width]="imageWidget.width ? imageWidget.width + 'px' : 'auto'"
1333
+ [style.height]="imageWidget.height ? imageWidget.height + 'px' : 'auto'"
1334
+ loading="lazy" />
1335
+ </div>
1336
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
1337
+ }
1338
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ImageWidgetComponent, decorators: [{
1339
+ type: Component,
1340
+ args: [{ selector: 'bbq-image-widget', standalone: true, imports: [CommonModule], template: `
1341
+ <div
1342
+ class="bbq-widget bbq-image"
1343
+ [attr.data-widget-type]="'image'"
1344
+ [attr.data-action]="imageWidget.action">
1345
+ <img
1346
+ class="bbq-image-img"
1347
+ [src]="imageWidget.imageUrl"
1348
+ [alt]="imageWidget.alt || 'Image'"
1349
+ [style.width]="imageWidget.width ? imageWidget.width + 'px' : 'auto'"
1350
+ [style.height]="imageWidget.height ? imageWidget.height + 'px' : 'auto'"
1351
+ loading="lazy" />
1352
+ </div>
1353
+ ` }]
1354
+ }], propDecorators: { widget: [{
1355
+ type: Input
1356
+ }] } });
1357
+
1358
+ class ImageCollectionWidgetComponent {
1359
+ widget;
1360
+ widgetAction;
1361
+ get imageCollectionWidget() {
1362
+ return this.widget;
1363
+ }
1364
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ImageCollectionWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1365
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: ImageCollectionWidgetComponent, isStandalone: true, selector: "bbq-imagecollection-widget", inputs: { widget: "widget" }, ngImport: i0, template: `
1366
+ <div
1367
+ class="bbq-widget bbq-image-collection"
1368
+ [attr.data-widget-type]="'imagecollection'"
1369
+ [attr.data-action]="imageCollectionWidget.action">
1370
+ <div class="bbq-image-collection-grid">
1371
+ @for (image of imageCollectionWidget.images; track image.imageUrl) {
1372
+ <div class="bbq-image-collection-item">
1373
+ <img
1374
+ class="bbq-image-collection-img"
1375
+ [src]="image.imageUrl"
1376
+ [alt]="image.alt || 'Image'"
1377
+ [style.width]="image.width ? image.width + 'px' : 'auto'"
1378
+ [style.height]="image.height ? image.height + 'px' : 'auto'"
1379
+ loading="lazy" />
1380
+ </div>
1381
+ }
1382
+ </div>
1383
+ </div>
1384
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }] });
1385
+ }
1386
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ImageCollectionWidgetComponent, decorators: [{
1387
+ type: Component,
1388
+ args: [{ selector: 'bbq-imagecollection-widget', standalone: true, imports: [CommonModule], template: `
1389
+ <div
1390
+ class="bbq-widget bbq-image-collection"
1391
+ [attr.data-widget-type]="'imagecollection'"
1392
+ [attr.data-action]="imageCollectionWidget.action">
1393
+ <div class="bbq-image-collection-grid">
1394
+ @for (image of imageCollectionWidget.images; track image.imageUrl) {
1395
+ <div class="bbq-image-collection-item">
1396
+ <img
1397
+ class="bbq-image-collection-img"
1398
+ [src]="image.imageUrl"
1399
+ [alt]="image.alt || 'Image'"
1400
+ [style.width]="image.width ? image.width + 'px' : 'auto'"
1401
+ [style.height]="image.height ? image.height + 'px' : 'auto'"
1402
+ loading="lazy" />
1403
+ </div>
1404
+ }
1405
+ </div>
1406
+ </div>
1407
+ ` }]
1408
+ }], propDecorators: { widget: [{
1409
+ type: Input
1410
+ }] } });
1411
+
1412
+ /**
1413
+ * Built-in widget components
1414
+ * These components provide Angular implementations for all standard widget types
1415
+ */
1416
+
1417
+ /**
1418
+ * Registry of all built-in widget components
1419
+ * Maps widget type to Angular component class
1420
+ */
1421
+ const BUILT_IN_WIDGET_COMPONENTS = {
1422
+ button: ButtonWidgetComponent,
1423
+ card: CardWidgetComponent,
1424
+ input: InputWidgetComponent,
1425
+ textarea: TextAreaWidgetComponent,
1426
+ dropdown: DropdownWidgetComponent,
1427
+ slider: SliderWidgetComponent,
1428
+ toggle: ToggleWidgetComponent,
1429
+ fileupload: FileUploadWidgetComponent,
1430
+ themeswitcher: ThemeSwitcherWidgetComponent,
1431
+ datepicker: DatePickerWidgetComponent,
1432
+ multiselect: MultiSelectWidgetComponent,
1433
+ progressbar: ProgressBarWidgetComponent,
1434
+ form: FormWidgetComponent,
1435
+ image: ImageWidgetComponent,
1436
+ imagecollection: ImageCollectionWidgetComponent,
1437
+ };
1438
+
1439
+ const WIDGET_EVENT_MANAGER_FACTORY = new InjectionToken('WIDGET_EVENT_MANAGER_FACTORY');
1440
+ /**
1441
+ * Injection token for SsrWidgetRenderer
1442
+ *
1443
+ * Use this token to inject a SsrWidgetRenderer instance in your components.
1444
+ * By default, WidgetRendererComponent provides this token with a factory that creates
1445
+ * a new instance for each component.
1446
+ *
1447
+ * @example
1448
+ * ```typescript
1449
+ * constructor(@Inject(SSR_WIDGET_RENDERER) private renderer: SsrWidgetRenderer) {}
1450
+ * ```
1451
+ */
1452
+ const SSR_WIDGET_RENDERER = new InjectionToken('SSR_WIDGET_RENDERER');
1453
+ /**
1454
+ * Injection token for AngularWidgetRenderer
1455
+ *
1456
+ * Use this token to inject an AngularWidgetRenderer instance in your components.
1457
+ * This is the recommended renderer for Angular applications as it provides
1458
+ * native Angular component rendering instead of HTML string rendering.
1459
+ *
1460
+ * @example
1461
+ * ```typescript
1462
+ * constructor(@Inject(ANGULAR_WIDGET_RENDERER) private renderer: AngularWidgetRenderer) {}
1463
+ * ```
1464
+ */
1465
+ const ANGULAR_WIDGET_RENDERER = new InjectionToken('ANGULAR_WIDGET_RENDERER');
1466
+ /**
1467
+ * Factory function for creating WidgetEventManager instances
1468
+ *
1469
+ * This factory is used by default in WidgetRendererComponent's providers array.
1470
+ * You can override this in your own providers if you need custom initialization.
1471
+ *
1472
+ * @returns A factory function that creates WidgetEventManager instances
1473
+ */
1474
+ function widgetEventManagerFactoryProvider() {
1475
+ return (actionHandler) => new WidgetEventManager(actionHandler);
1476
+ }
1477
+ /**
1478
+ * Factory function for creating SsrWidgetRenderer instances
1479
+ *
1480
+ * This factory is used by default in WidgetRendererComponent's providers array.
1481
+ * You can override this in your own providers if you need custom initialization
1482
+ * or custom rendering options.
1483
+ *
1484
+ * @returns A new SsrWidgetRenderer instance
1485
+ */
1486
+ function ssrWidgetRendererFactory() {
1487
+ return new SsrWidgetRenderer();
1488
+ }
1489
+ /**
1490
+ * Factory function for creating AngularWidgetRenderer instances
1491
+ *
1492
+ * This factory creates an AngularWidgetRenderer with all built-in widget components
1493
+ * pre-registered. This is the recommended renderer for Angular applications.
1494
+ *
1495
+ * @returns A new AngularWidgetRenderer instance with built-in components registered
1496
+ */
1497
+ function angularWidgetRendererFactory() {
1498
+ const renderer = new AngularWidgetRenderer();
1499
+ renderer.registerBuiltInComponents(BUILT_IN_WIDGET_COMPONENTS);
1500
+ return renderer;
1501
+ }
1502
+
1503
+ /**
1504
+ * Service for registering custom widget factories and renderers
1505
+ *
1506
+ * This service provides a centralized way to register custom widget types
1507
+ * that extend the base widget functionality, including support for
1508
+ * Angular components and templates as custom renderers.
1509
+ *
1510
+ * @example
1511
+ * ```typescript
1512
+ * constructor(private widgetRegistry: WidgetRegistryService) {
1513
+ * // Register a widget factory
1514
+ * this.widgetRegistry.registerFactory('myWidget', (obj) => {
1515
+ * if (obj.type === 'myWidget') {
1516
+ * return new MyCustomWidget(obj.label, obj.action);
1517
+ * }
1518
+ * return null;
1519
+ * });
1520
+ *
1521
+ * // Register a component-based renderer
1522
+ * this.widgetRegistry.registerRenderer('myWidget', MyWidgetComponent);
1523
+ * }
1524
+ * ```
1525
+ */
1526
+ class WidgetRegistryService {
1527
+ customRenderers = new Map();
1528
+ /**
1529
+ * Register a custom widget factory function
1530
+ *
1531
+ * @param type - The widget type identifier
1532
+ * @param factory - Factory function that creates widget instances from plain objects
1533
+ */
1534
+ registerFactory(type, factory) {
1535
+ customWidgetRegistry.registerFactory(type, factory);
1536
+ }
1537
+ /**
1538
+ * Register a widget class with automatic factory creation
1539
+ *
1540
+ * @param type - The widget type identifier
1541
+ * @param ctor - Widget class constructor
1542
+ */
1543
+ registerClass(type, ctor) {
1544
+ customWidgetRegistry.registerClass(type, ctor);
1545
+ }
1546
+ /**
1547
+ * Get a factory for a specific widget type
1548
+ *
1549
+ * @param type - The widget type identifier
1550
+ * @returns The factory function if registered, undefined otherwise
1551
+ */
1552
+ getFactory(type) {
1553
+ return customWidgetRegistry.getFactory(type);
1554
+ }
1555
+ /**
1556
+ * Register a custom renderer for a specific widget type
1557
+ *
1558
+ * The renderer can be:
1559
+ * - A function that returns HTML string
1560
+ * - An Angular Component class
1561
+ * - An Angular TemplateRef
1562
+ *
1563
+ * @param type - The widget type identifier
1564
+ * @param renderer - The custom renderer (function, Component, or TemplateRef)
1565
+ *
1566
+ * @example
1567
+ * ```typescript
1568
+ * // HTML function renderer
1569
+ * widgetRegistry.registerRenderer('weather', (widget) => `<div>${widget.label}</div>`);
1570
+ *
1571
+ * // Component renderer
1572
+ * widgetRegistry.registerRenderer('weather', WeatherWidgetComponent);
1573
+ *
1574
+ * // Template renderer (from @ViewChild or elsewhere)
1575
+ * widgetRegistry.registerRenderer('weather', this.weatherTemplate);
1576
+ * ```
1577
+ */
1578
+ registerRenderer(type, renderer) {
1579
+ if (!type || typeof type !== 'string') {
1580
+ throw new Error('type must be a non-empty string');
1581
+ }
1582
+ if (!renderer) {
1583
+ throw new Error('renderer is required');
1584
+ }
1585
+ this.customRenderers.set(type, renderer);
1586
+ }
1587
+ /**
1588
+ * Get a custom renderer for a specific widget type
1589
+ *
1590
+ * @param type - The widget type identifier
1591
+ * @returns The custom renderer if registered, undefined otherwise
1592
+ */
1593
+ getRenderer(type) {
1594
+ return this.customRenderers.get(type);
1595
+ }
1596
+ /**
1597
+ * Check if a custom renderer is registered for a widget type
1598
+ *
1599
+ * @param type - The widget type identifier
1600
+ * @returns True if a custom renderer is registered, false otherwise
1601
+ */
1602
+ hasRenderer(type) {
1603
+ return this.customRenderers.has(type);
1604
+ }
1605
+ /**
1606
+ * Unregister a custom renderer for a widget type
1607
+ *
1608
+ * @param type - The widget type identifier
1609
+ * @returns True if a renderer was removed, false if none was registered
1610
+ */
1611
+ unregisterRenderer(type) {
1612
+ return this.customRenderers.delete(type);
1613
+ }
1614
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: WidgetRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1615
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: WidgetRegistryService, providedIn: 'root' });
1616
+ }
1617
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: WidgetRegistryService, decorators: [{
1618
+ type: Injectable,
1619
+ args: [{
1620
+ providedIn: 'root',
1621
+ }]
1622
+ }] });
1623
+
1624
+ /**
1625
+ * Angular component for rendering chat widgets
1626
+ *
1627
+ * This component handles rendering of chat widgets using the BbQ ChatWidgets library.
1628
+ * It manages widget lifecycle, event handling, and cleanup.
1629
+ *
1630
+ * Supports three types of custom widget renderers:
1631
+ * 1. HTML function renderers (return HTML strings)
1632
+ * 2. Angular Component renderers (render as dynamic components)
1633
+ * 3. Angular TemplateRef renderers (render as embedded views)
1634
+ *
1635
+ * @example
1636
+ * ```typescript
1637
+ * <bbq-widget-renderer
1638
+ * [widgets]="messageWidgets"
1639
+ * (widgetAction)="handleWidgetAction($event)">
1640
+ * </bbq-widget-renderer>
1641
+ * ```
1642
+ */
1643
+ class WidgetRendererComponent {
1644
+ renderer;
1645
+ angularRenderer;
1646
+ eventManagerFactory;
1647
+ widgetRegistry;
1648
+ injector;
1649
+ environmentInjector;
1650
+ /**
1651
+ * Array of widgets to render
1652
+ */
1653
+ widgets;
1654
+ /**
1655
+ * Emits when a widget action is triggered
1656
+ */
1657
+ widgetAction = new EventEmitter();
1658
+ containerRef;
1659
+ widgetItems = [];
1660
+ eventManager;
1661
+ isViewInitialized = false;
1662
+ dynamicComponents = [];
1663
+ dynamicViews = [];
1664
+ constructor(renderer, angularRenderer, eventManagerFactory, widgetRegistry, injector, environmentInjector) {
1665
+ this.renderer = renderer;
1666
+ this.angularRenderer = angularRenderer;
1667
+ this.eventManagerFactory = eventManagerFactory;
1668
+ this.widgetRegistry = widgetRegistry;
1669
+ this.injector = injector;
1670
+ this.environmentInjector = environmentInjector;
1671
+ }
1672
+ ngOnInit() {
1673
+ // this.updateWidgetHtml();
1674
+ }
1675
+ ngOnChanges(changes) {
1676
+ if (changes['widgets']) {
1677
+ this.updateWidgetHtml();
1678
+ }
1679
+ }
1680
+ ngAfterViewInit() {
1681
+ this.updateWidgetHtml();
1682
+ this.isViewInitialized = true;
1683
+ this.setupEventHandlers();
1684
+ // Render dynamic components/templates after view init
1685
+ this.renderDynamicWidgets();
1686
+ }
1687
+ ngOnDestroy() {
1688
+ this.cleanup();
1689
+ }
1690
+ /**
1691
+ * Base implementation for updating the rendered HTML for the current widgets.
1692
+ *
1693
+ * Subclasses may override this method to customize how widgets are rendered
1694
+ * (for example, to inject additional markup or perform preprocessing).
1695
+ *
1696
+ * Since this is the base implementation, overriding implementations are not
1697
+ * required to call `super.updateWidgetHtml()`.
1698
+ */
1699
+ updateWidgetHtml() {
1700
+ if (!this.widgets || this.widgets.length === 0) {
1701
+ this.widgetItems = [];
1702
+ return;
1703
+ }
1704
+ this.widgetItems = this.widgets.map((widget, index) => {
1705
+ const customRenderer = this.widgetRegistry.getRenderer(widget.type);
1706
+ // Check template renderer first (most specific)
1707
+ if (customRenderer && isTemplateRenderer(customRenderer)) {
1708
+ return {
1709
+ index,
1710
+ widget,
1711
+ isHtml: false,
1712
+ };
1713
+ }
1714
+ // Check component renderer second
1715
+ if (customRenderer && isComponentRenderer(customRenderer)) {
1716
+ return {
1717
+ index,
1718
+ widget,
1719
+ isHtml: false,
1720
+ };
1721
+ }
1722
+ // Check HTML function renderer last (most general, matches any function)
1723
+ if (customRenderer && isHtmlRenderer(customRenderer)) {
1724
+ return {
1725
+ index,
1726
+ widget,
1727
+ isHtml: true,
1728
+ html: customRenderer(widget),
1729
+ };
1730
+ }
1731
+ // Try to use AngularWidgetRenderer for built-in widgets
1732
+ if (this.angularRenderer) {
1733
+ const componentType = this.angularRenderer.getComponentType(widget);
1734
+ if (componentType) {
1735
+ return {
1736
+ index,
1737
+ widget,
1738
+ isHtml: false,
1739
+ };
1740
+ }
1741
+ }
1742
+ // Fallback: render using the SSR library renderer
1743
+ return {
1744
+ index,
1745
+ widget,
1746
+ isHtml: true,
1747
+ html: this.renderer.renderWidget(widget),
1748
+ };
1749
+ });
1750
+ // After view updates, reinitialize widgets only if view is already initialized
1751
+ if (this.isViewInitialized) {
1752
+ setTimeout(() => {
1753
+ this.setupEventHandlers();
1754
+ this.renderDynamicWidgets();
1755
+ }, 0);
1756
+ }
1757
+ }
1758
+ /**
1759
+ * Render dynamic components and templates for custom widgets
1760
+ */
1761
+ renderDynamicWidgets() {
1762
+ if (!this.containerRef?.nativeElement)
1763
+ return;
1764
+ // Use microtask to ensure Angular has completed change detection
1765
+ Promise.resolve().then(() => {
1766
+ if (!this.containerRef?.nativeElement)
1767
+ return;
1768
+ // Clean up existing dynamic components and views
1769
+ this.cleanupDynamicWidgets();
1770
+ const container = this.containerRef.nativeElement;
1771
+ // Query all widget divs without the data-rendered filter
1772
+ const dynamicWidgetDivs = Array.from(container.querySelectorAll('.bbq-widget'));
1773
+ let dynamicIndex = 0;
1774
+ this.widgetItems.forEach((item) => {
1775
+ if (!item.isHtml) {
1776
+ const customRenderer = this.widgetRegistry.getRenderer(item.widget.type);
1777
+ const targetDiv = dynamicWidgetDivs[dynamicIndex];
1778
+ if (!targetDiv)
1779
+ return;
1780
+ // Clear the div content before rendering
1781
+ targetDiv.innerHTML = '';
1782
+ // Handle custom renderers first
1783
+ if (customRenderer) {
1784
+ if (isComponentRenderer(customRenderer)) {
1785
+ this.renderComponent(customRenderer, item.widget, targetDiv);
1786
+ }
1787
+ else if (isTemplateRenderer(customRenderer)) {
1788
+ this.renderTemplate(customRenderer, item.widget, targetDiv);
1789
+ }
1790
+ }
1791
+ else if (this.angularRenderer) {
1792
+ // Try to render using AngularWidgetRenderer for built-in widgets
1793
+ const componentType = this.angularRenderer.getComponentType(item.widget);
1794
+ if (componentType) {
1795
+ this.renderComponent(componentType, item.widget, targetDiv);
1796
+ }
1797
+ }
1798
+ dynamicIndex++;
1799
+ }
1800
+ });
1801
+ });
1802
+ }
1803
+ /**
1804
+ * Render an Angular component for a custom widget
1805
+ *
1806
+ * Note: This method safely assigns properties to component instances
1807
+ * by checking for property existence at runtime. This approach is necessary
1808
+ * because we cannot statically verify that all components implement
1809
+ * the CustomWidgetComponent interface.
1810
+ */
1811
+ renderComponent(componentType, widget, targetElement) {
1812
+ // Create the component using Angular's createComponent API
1813
+ const componentRef = createComponent(componentType, {
1814
+ environmentInjector: this.environmentInjector,
1815
+ elementInjector: this.injector,
1816
+ });
1817
+ // Safely set component inputs if they exist
1818
+ const instance = componentRef.instance;
1819
+ // Set widget property if it exists in the prototype chain
1820
+ if (!instance['widget']) {
1821
+ instance['widget'] = widget;
1822
+ }
1823
+ // Set widgetAction property if it exists in the prototype chain
1824
+ if (!instance['widgetAction']) {
1825
+ instance['widgetAction'] = (actionName, payload) => {
1826
+ this.widgetAction.emit({ actionName, payload });
1827
+ };
1828
+ }
1829
+ // Attach the component's host view to the target element
1830
+ targetElement.appendChild(componentRef.location.nativeElement);
1831
+ // Store reference for cleanup
1832
+ this.dynamicComponents.push(componentRef);
1833
+ // Trigger change detection (use optional chaining for safety)
1834
+ componentRef.changeDetectorRef?.detectChanges();
1835
+ }
1836
+ /**
1837
+ * Render an Angular template for a custom widget
1838
+ */
1839
+ renderTemplate(templateRef, widget, targetElement) {
1840
+ const context = {
1841
+ $implicit: widget,
1842
+ widget: widget,
1843
+ emitAction: (actionName, payload) => {
1844
+ this.widgetAction.emit({ actionName, payload });
1845
+ },
1846
+ };
1847
+ const viewRef = templateRef.createEmbeddedView(context);
1848
+ // Attach the view's DOM nodes to the target element
1849
+ viewRef.rootNodes.forEach((node) => {
1850
+ targetElement.appendChild(node);
1851
+ });
1852
+ // Store reference for cleanup
1853
+ this.dynamicViews.push(viewRef);
1854
+ // Trigger change detection
1855
+ viewRef.detectChanges();
1856
+ }
1857
+ /**
1858
+ * Cleanup dynamic components and views
1859
+ */
1860
+ cleanupDynamicWidgets() {
1861
+ this.dynamicComponents.forEach((componentRef) => {
1862
+ componentRef.destroy();
1863
+ });
1864
+ this.dynamicComponents = [];
1865
+ this.dynamicViews.forEach((viewRef) => {
1866
+ viewRef.destroy();
1867
+ });
1868
+ this.dynamicViews = [];
1869
+ }
1870
+ setupEventHandlers() {
1871
+ if (!this.containerRef?.nativeElement)
1872
+ return;
1873
+ // Cleanup old resources before setting up new ones
1874
+ this.cleanup();
1875
+ const container = this.containerRef.nativeElement;
1876
+ // Create a custom action handler that emits events
1877
+ const actionHandler = {
1878
+ handle: async (action, payload) => {
1879
+ this.widgetAction.emit({ actionName: action, payload });
1880
+ },
1881
+ };
1882
+ // Use the injected factory to create an event manager with the component-specific action handler
1883
+ this.eventManager = this.eventManagerFactory(actionHandler);
1884
+ this.eventManager.attachHandlers(container);
1885
+ }
1886
+ handleClick(event) {
1887
+ const target = event.target;
1888
+ // Only trigger actions on non-form buttons and clickable elements (cards)
1889
+ // Don't trigger on input elements or form buttons (let WidgetEventManager handle those)
1890
+ const button = target.tagName === 'BUTTON' ? target : target.closest('button');
1891
+ if (button && !button.closest('[data-widget-type="form"]')) {
1892
+ const actionName = button.getAttribute('data-action');
1893
+ if (actionName) {
1894
+ try {
1895
+ const payloadStr = button.getAttribute('data-payload');
1896
+ const payload = payloadStr ? JSON.parse(payloadStr) : {};
1897
+ this.widgetAction.emit({ actionName, payload });
1898
+ }
1899
+ catch (err) {
1900
+ console.error('Failed to parse widget action payload:', err);
1901
+ }
1902
+ }
1903
+ }
1904
+ }
1905
+ /**
1906
+ * Cleanup all resources including event listeners.
1907
+ */
1908
+ cleanup() {
1909
+ // Cleanup dynamic widgets first
1910
+ this.cleanupDynamicWidgets();
1911
+ // Cleanup event manager
1912
+ this.eventManager = undefined;
1913
+ }
1914
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: WidgetRendererComponent, deps: [{ token: SSR_WIDGET_RENDERER }, { token: ANGULAR_WIDGET_RENDERER, optional: true }, { token: WIDGET_EVENT_MANAGER_FACTORY }, { token: WidgetRegistryService }, { token: i0.Injector }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Component });
1915
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: WidgetRendererComponent, isStandalone: true, selector: "bbq-widget-renderer", inputs: { widgets: "widgets" }, outputs: { widgetAction: "widgetAction" }, providers: [
1916
+ { provide: WIDGET_EVENT_MANAGER_FACTORY, useFactory: widgetEventManagerFactoryProvider },
1917
+ { provide: SSR_WIDGET_RENDERER, useFactory: ssrWidgetRendererFactory },
1918
+ { provide: ANGULAR_WIDGET_RENDERER, useFactory: angularWidgetRendererFactory },
1919
+ ], viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["widgetContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
1920
+ <div #widgetContainer class="bbq-widgets-container" (click)="handleClick($event)">
1921
+ @for (item of widgetItems; track item.index) {
1922
+ @if (item.isHtml) {
1923
+ <div class="bbq-widget" [innerHTML]="item.html"></div>
1924
+ } @else {
1925
+ <div class="bbq-widget" #dynamicWidget></div>
1926
+ }
1927
+ }
1928
+ </div>
1929
+ `, isInline: true, styles: [".bbq-widgets-container{margin-top:.5rem}.bbq-widget{margin-bottom:.5rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
1930
+ }
1931
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: WidgetRendererComponent, decorators: [{
1932
+ type: Component,
1933
+ args: [{ selector: 'bbq-widget-renderer', standalone: true, imports: [CommonModule], providers: [
1934
+ { provide: WIDGET_EVENT_MANAGER_FACTORY, useFactory: widgetEventManagerFactoryProvider },
1935
+ { provide: SSR_WIDGET_RENDERER, useFactory: ssrWidgetRendererFactory },
1936
+ { provide: ANGULAR_WIDGET_RENDERER, useFactory: angularWidgetRendererFactory },
1937
+ ], template: `
1938
+ <div #widgetContainer class="bbq-widgets-container" (click)="handleClick($event)">
1939
+ @for (item of widgetItems; track item.index) {
1940
+ @if (item.isHtml) {
1941
+ <div class="bbq-widget" [innerHTML]="item.html"></div>
1942
+ } @else {
1943
+ <div class="bbq-widget" #dynamicWidget></div>
1944
+ }
1945
+ }
1946
+ </div>
1947
+ `, styles: [".bbq-widgets-container{margin-top:.5rem}.bbq-widget{margin-bottom:.5rem}\n"] }]
1948
+ }], ctorParameters: () => [{ type: i2$1.SsrWidgetRenderer, decorators: [{
1949
+ type: Inject,
1950
+ args: [SSR_WIDGET_RENDERER]
1951
+ }] }, { type: AngularWidgetRenderer, decorators: [{
1952
+ type: Optional
1953
+ }, {
1954
+ type: Inject,
1955
+ args: [ANGULAR_WIDGET_RENDERER]
1956
+ }] }, { type: undefined, decorators: [{
1957
+ type: Inject,
1958
+ args: [WIDGET_EVENT_MANAGER_FACTORY]
1959
+ }] }, { type: WidgetRegistryService }, { type: i0.Injector }, { type: i0.EnvironmentInjector }], propDecorators: { widgets: [{
1960
+ type: Input
1961
+ }], widgetAction: [{
1962
+ type: Output
1963
+ }], containerRef: [{
1964
+ type: ViewChild,
1965
+ args: ['widgetContainer', { static: false }]
1966
+ }] } });
1967
+
1968
+ /**
1969
+ * Angular widget renderers
1970
+ */
1971
+
1972
+ /**
1973
+ * @bbq-chat/widgets-angular
1974
+ *
1975
+ * Angular components and services for BbQ ChatWidgets
1976
+ *
1977
+ * This package provides Angular-native components and services that wrap
1978
+ * the core @bbq-chat/widgets library, making it easy to integrate chat
1979
+ * widgets into Angular applications.
1980
+ *
1981
+ * @packageDocumentation
1982
+ */
1983
+ // Export components
1984
+ // Version
1985
+ const VERSION = '1.0.4';
1986
+
1987
+ /**
1988
+ * Generated bundle index. Do not edit.
1989
+ */
1990
+
1991
+ export { ANGULAR_WIDGET_RENDERER, AngularWidgetRenderer, BUILT_IN_WIDGET_COMPONENTS, ButtonWidgetComponent, CardWidgetComponent, DatePickerWidgetComponent, DropdownWidgetComponent, FileUploadWidgetComponent, FormWidgetComponent, ImageCollectionWidgetComponent, ImageWidgetComponent, InputWidgetComponent, MultiSelectWidgetComponent, ProgressBarWidgetComponent, SSR_WIDGET_RENDERER, SliderWidgetComponent, TextAreaWidgetComponent, ThemeSwitcherWidgetComponent, ToggleWidgetComponent, VERSION, WIDGET_EVENT_MANAGER_FACTORY, WidgetRegistryService, WidgetRendererComponent, angularWidgetRendererFactory, isComponentRenderer, isHtmlRenderer, isTemplateRenderer, ssrWidgetRendererFactory, widgetEventManagerFactoryProvider };
1992
+ //# sourceMappingURL=index.mjs.map