@ruc-lib/widget 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,243 +0,0 @@
1
- import * as i3 from '@angular/material/button';
2
- import { MatButtonModule } from '@angular/material/button';
3
- import * as i2 from '@angular/material/icon';
4
- import { MatIconModule } from '@angular/material/icon';
5
- import * as i0 from '@angular/core';
6
- import { Pipe, ViewContainerRef, ViewChild, Input, Component, EventEmitter, Output } from '@angular/core';
7
- import * as i4 from '@angular/cdk/drag-drop';
8
- import { DragDropModule } from '@angular/cdk/drag-drop';
9
- import * as i1$1 from '@angular/common';
10
- import { CommonModule } from '@angular/common';
11
- import * as i1 from '@angular/platform-browser';
12
-
13
- /**
14
- * @Pipe SafeHtmlPipe
15
- * @name safeHtml
16
- * @description A pipe that bypasses Angular's built-in security and sanitizes HTML content,
17
- * allowing it to be safely rendered in the DOM. Use with caution and only with trusted HTML sources.
18
- */
19
- class SafeHtmlPipe {
20
- /**
21
- * @param sanitizer - An instance of DomSanitizer used to bypass security.
22
- */
23
- constructor(sanitizer) {
24
- this.sanitizer = sanitizer;
25
- }
26
- /**
27
- * Transforms a string containing HTML into a SafeHtml object that can be bound to [innerHTML].
28
- * @param value - The HTML string to sanitize.
29
- * @returns A SafeHtml object, which Angular trusts as safe HTML.
30
- */
31
- transform(value) {
32
- if (value === null || value === undefined) {
33
- return value;
34
- }
35
- return this.sanitizer.bypassSecurityTrustHtml(value);
36
- }
37
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
38
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.9", ngImport: i0, type: SafeHtmlPipe, isStandalone: true, name: "safeHtml" }); }
39
- }
40
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: SafeHtmlPipe, decorators: [{
41
- type: Pipe,
42
- args: [{ name: 'safeHtml', standalone: true }]
43
- }], ctorParameters: () => [{ type: i1.DomSanitizer }] });
44
-
45
- class RuclibWidgetItemComponent {
46
- /**
47
- * @param cdr The ChangeDetectorRef to manually trigger change detection.
48
- * @param sanitizer The DomSanitizer service to prevent XSS attacks by sanitizing HTML.
49
- */
50
- constructor(cdr, sanitizer) {
51
- this.cdr = cdr;
52
- this.sanitizer = sanitizer;
53
- /**
54
- * A reference to the dynamically created component instance.
55
- * This is used to manage the lifecycle of the injected component.
56
- */
57
- this.dynamicComponentRef = null;
58
- }
59
- /**
60
- * A lifecycle hook that responds when Angular sets or resets data-bound input properties.
61
- * It checks for changes in `widgetConfig` and reloads the content accordingly.
62
- * @param changes An object of the changed properties.
63
- */
64
- ngOnChanges(changes) {
65
- if (changes['widgetConfig']) {
66
- if (this.widgetConfig.contentType === 'component' && this.widgetComponentHost) {
67
- this.loadDynamicContent();
68
- }
69
- else if (this.widgetConfig.contentType !== 'component') {
70
- this.clearDynamicContent();
71
- }
72
- }
73
- }
74
- /**
75
- * A lifecycle hook that is called after Angular has fully initialized a component's view.
76
- * It ensures that if the initial content type is 'component', it gets loaded.
77
- */
78
- ngAfterViewInit() {
79
- if (this.widgetConfig) {
80
- if (this.widgetConfig.contentType === 'component' && this.widgetComponentHost) {
81
- this.loadDynamicContent();
82
- }
83
- }
84
- }
85
- /**
86
- * Loads a dynamic component into the `widgetComponentHost` view container.
87
- * It reads the component type and any input data from the `widgetConfig`.
88
- */
89
- loadDynamicContent() {
90
- this.clearDynamicContent();
91
- if (this.widgetConfig.contentType === 'component' && this.widgetConfig.contentData && this.widgetConfig.contentData.component) {
92
- if (this.widgetComponentHost) {
93
- const componentType = this.widgetConfig.contentData.component;
94
- this.dynamicComponentRef = this.widgetComponentHost.createComponent(componentType);
95
- if (this.widgetConfig.contentData.inputs && this.dynamicComponentRef?.instance) {
96
- Object.keys(this.widgetConfig.contentData.inputs).forEach(key => {
97
- if (this.dynamicComponentRef && key in this.dynamicComponentRef.instance) {
98
- this.dynamicComponentRef.instance[key] = this.widgetConfig.contentData.inputs[key];
99
- }
100
- });
101
- this.dynamicComponentRef.changeDetectorRef.detectChanges();
102
- }
103
- }
104
- }
105
- this.cdr.detectChanges();
106
- }
107
- /**
108
- * Clears any dynamically loaded component from the view container and destroys its instance.
109
- */
110
- clearDynamicContent() {
111
- if (this.dynamicComponentRef) {
112
- this.dynamicComponentRef.destroy();
113
- this.dynamicComponentRef = null;
114
- }
115
- if (this.widgetComponentHost) {
116
- this.widgetComponentHost.clear();
117
- }
118
- }
119
- /**
120
- * A lifecycle hook that cleans up the component before it's destroyed.
121
- * Ensures that any dynamically created components are properly destroyed to avoid memory leaks.
122
- */
123
- ngOnDestroy() {
124
- this.clearDynamicContent();
125
- }
126
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: RuclibWidgetItemComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
127
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: RuclibWidgetItemComponent, isStandalone: true, selector: "uxp-ruclib-widget-item", inputs: { widgetConfig: "widgetConfig" }, viewQueries: [{ propertyName: "widgetComponentHost", first: true, predicate: ["widgetComponentHost"], descendants: true, read: ViewContainerRef }], usesOnChanges: true, ngImport: i0, template: "<!--\r\nThis container uses a switch to determine how to render the widget's content\r\nbased on the `contentType` property in the widget's configuration.\r\n-->\r\n@if (widgetConfig) {\r\n @switch (widgetConfig.contentType) {\r\n @case ('text') {\r\n <p>{{ widgetConfig.contentData }}</p>\r\n }\r\n @case ('html') {\r\n <div [innerHTML]=\"widgetConfig.contentData | safeHtml\"></div>\r\n }\r\n @case ('video') {\r\n <video\r\n [src]=\"widgetConfig.contentData.src\"\r\n [attr.type]=\"widgetConfig.contentData.type\"\r\n [controls]=\"widgetConfig.contentData.controls\"\r\n [autoplay]=\"widgetConfig.contentData.autoplay\"\r\n [loop]=\"widgetConfig.contentData.loop\"\r\n style=\"width: 100%; height: 100%; object-fit: contain\"\r\n ></video>\r\n }\r\n @case ('component') {\r\n <ng-template #widgetComponentHost></ng-template>\r\n }\r\n @default {\r\n <p>No content provided or content type not supported.</p>\r\n }\r\n }\r\n}\r\n", styles: [":host{display:block;height:100%;width:100%}video{max-width:100%;max-height:100%}p{margin:0}\n"], dependencies: [{ kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }] }); }
128
- }
129
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: RuclibWidgetItemComponent, decorators: [{
130
- type: Component,
131
- args: [{ selector: 'uxp-ruclib-widget-item', imports: [SafeHtmlPipe], template: "<!--\r\nThis container uses a switch to determine how to render the widget's content\r\nbased on the `contentType` property in the widget's configuration.\r\n-->\r\n@if (widgetConfig) {\r\n @switch (widgetConfig.contentType) {\r\n @case ('text') {\r\n <p>{{ widgetConfig.contentData }}</p>\r\n }\r\n @case ('html') {\r\n <div [innerHTML]=\"widgetConfig.contentData | safeHtml\"></div>\r\n }\r\n @case ('video') {\r\n <video\r\n [src]=\"widgetConfig.contentData.src\"\r\n [attr.type]=\"widgetConfig.contentData.type\"\r\n [controls]=\"widgetConfig.contentData.controls\"\r\n [autoplay]=\"widgetConfig.contentData.autoplay\"\r\n [loop]=\"widgetConfig.contentData.loop\"\r\n style=\"width: 100%; height: 100%; object-fit: contain\"\r\n ></video>\r\n }\r\n @case ('component') {\r\n <ng-template #widgetComponentHost></ng-template>\r\n }\r\n @default {\r\n <p>No content provided or content type not supported.</p>\r\n }\r\n }\r\n}\r\n", styles: [":host{display:block;height:100%;width:100%}video{max-width:100%;max-height:100%}p{margin:0}\n"] }]
132
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1.DomSanitizer }], propDecorators: { widgetConfig: [{
133
- type: Input
134
- }], widgetComponentHost: [{
135
- type: ViewChild,
136
- args: ['widgetComponentHost', { read: ViewContainerRef }]
137
- }] } });
138
-
139
- class RuclibWidgetComponent {
140
- /**
141
- * @param cdr The ChangeDetectorRef to manually trigger change detection when needed.
142
- */
143
- constructor(cdr) {
144
- this.cdr = cdr;
145
- /**
146
- * An event emitter that fires when a widget's close icon is clicked.
147
- * It emits the unique ID of the widget to be closed.
148
- */
149
- this.widgetClose = new EventEmitter();
150
- /**
151
- * An event emitter that fires when a widget is dragged and dropped.
152
- * It emits the entire updated array of widget configurations, allowing the parent to save the new layout.
153
- */
154
- this.layoutChanged = new EventEmitter();
155
- }
156
- /**
157
- * After the view initializes, this hook captures the host container's native element
158
- * and sets it as the boundary for dragging widgets.
159
- */
160
- ngAfterViewInit() {
161
- if (this.widgetsHostContainerRef) {
162
- this.dragBoundaryElement = this.widgetsHostContainerRef.nativeElement;
163
- this.cdr.detectChanges();
164
- }
165
- }
166
- /**
167
- * Handles the click event on a widget's close button.
168
- * @param widgetId The ID of the widget to be closed.
169
- */
170
- onCloseClick(widgetId) {
171
- this.widgetClose.emit(widgetId);
172
- }
173
- /**
174
- * Handles the start of a drag operation for a widget.
175
- * Sets the widget's isActive state to true for visual feedback.
176
- * @param widget The WidgetConfigData object being dragged.
177
- * @param event The CdkDragStart event.
178
- */
179
- onDragStarted(widget, event) {
180
- widget.isActive = true;
181
- }
182
- /**
183
- * Handles the end of a drag operation.
184
- * It calculates the new top/left position, updates the widget's configuration,
185
- * and emits the `layoutChanged` event with the new layout data.
186
- * @param widget The WidgetConfigData object that was dragged.
187
- * @param event The CdkDragEnd event.
188
- */
189
- onDragEnded(widget, event) {
190
- widget.isActive = false;
191
- const newPosition = event.source.getFreeDragPosition();
192
- const initialTopPx = parseFloat(widget.top || '0');
193
- const initialLeftPx = parseFloat(widget.left || '0');
194
- const newTopPx = initialTopPx + newPosition.y;
195
- const newLeftPx = initialLeftPx + newPosition.x;
196
- widget.top = `${newTopPx}px`;
197
- widget.left = `${newLeftPx}px`;
198
- event.source.reset();
199
- if (this.rucInputData.widgetData) {
200
- this.layoutChanged.emit(this.rucInputData.widgetData);
201
- }
202
- }
203
- /**
204
- * Retrieves the color for UI elements like icons from the input data.
205
- * @returns The color string (e.g., 'primary', 'accent') or 'primary' as a default.
206
- */
207
- getColor() {
208
- return this.rucInputData?.color || 'primary';
209
- }
210
- /**
211
- * A safe getter for the widget data array from the main input configuration.
212
- * @returns The array of widget configurations, or an empty array if not defined.
213
- */
214
- getWidgetData() {
215
- return typeof this.rucInputData.widgetData !== 'undefined' ? this.rucInputData.widgetData : [];
216
- }
217
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: RuclibWidgetComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
218
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: RuclibWidgetComponent, isStandalone: true, selector: "uxp-ruclib-widget", inputs: { rucInputData: "rucInputData", customTheme: "customTheme" }, outputs: { widgetClose: "widgetClose", layoutChanged: "layoutChanged" }, viewQueries: [{ propertyName: "widgetsHostContainerRef", first: true, predicate: ["widgetsHostContainer"], descendants: true }], ngImport: i0, template: "<!--\r\nThe main container for all widgets.\r\n- Applies a custom theme class if provided.\r\n- Acts as the boundary for dragging operations via the #widgetsHostContainer template reference.\r\n-->\r\n<div\r\n class=\"widgets-host-container {{ customTheme || '' }}\"\r\n #widgetsHostContainer\r\n >\r\n <!--\r\n Iterates through the widget data to render each individual widget.\r\n Each widget is a draggable container powered by Angular CDK.\r\n -->\r\n @for (widgetConfig of getWidgetData(); track widgetConfig) {\r\n <div\r\n [style.width]=\"widgetConfig.width ? widgetConfig.width : '200px'\"\r\n [style.height]=\"widgetConfig.height ? widgetConfig.height : '150px'\"\r\n [style.minWidth]=\"widgetConfig.width ? widgetConfig.width : '200px'\"\r\n [style.minHeight]=\"widgetConfig.height ? widgetConfig.height : '150px'\"\r\n [style.top]=\"widgetConfig.top\"\r\n [style.left]=\"widgetConfig.left\"\r\n [style.background-color]=\"widgetConfig.backgroundColor\"\r\n [class.disabled]=\"widgetConfig.disabled\"\r\n [class.draggable]=\"widgetConfig.draggable && !widgetConfig.disabled\"\r\n [class.resizable]=\"widgetConfig.resizable && !widgetConfig.disabled\"\r\n class=\"widget-container\"\r\n cdkDrag\r\n [cdkDragDisabled]=\"!widgetConfig.draggable || widgetConfig.disabled\"\r\n [cdkDragBoundary]=\"dragBoundaryElement\"\r\n (cdkDragStarted)=\"onDragStarted(widgetConfig, $event)\"\r\n (cdkDragEnded)=\"onDragEnded(widgetConfig, $event)\"\r\n [ngClass]=\"{ 'is-active': widgetConfig.isActive }\"\r\n >\r\n <!--\r\n Widget Header: Contains title and controls. Acts as the handle for dragging.\r\n -->\r\n <div class=\"widget-header\" cdkDragHandle>\r\n <div class=\"widget-header-left\">\r\n <!-- Draggable indicator icon, shown only if the widget is draggable and not disabled -->\r\n @if (widgetConfig.draggable && !widgetConfig.disabled) {\r\n <mat-icon\r\n class=\"widget-drag-handle\"\r\n aria-hidden=\"true\"\r\n >drag_indicator</mat-icon\r\n >\r\n }\r\n <!-- Optional header icon -->\r\n @if (widgetConfig.headerIcon) {\r\n <mat-icon class=\"widget-header-icon\">{{\r\n widgetConfig.headerIcon\r\n }}</mat-icon>\r\n }\r\n <!-- Widget Title -->\r\n @if (widgetConfig?.title) {\r\n <h3>{{ widgetConfig?.title }}</h3>\r\n }\r\n </div>\r\n <!-- Optional close button with accessibility label -->\r\n @if (widgetConfig?.showCloseIcon) {\r\n <button\r\n color=\"{{ getColor() }}\"\r\n mat-icon-button\r\n class=\"widget-close-button\"\r\n [disabled]=\"widgetConfig.disabled\"\r\n (click)=\"onCloseClick(widgetConfig.id)\"\r\n [attr.aria-label]=\"'Close widget ' + widgetConfig?.title\"\r\n >\r\n <mat-icon color=\"{{ getColor() }}\">close</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n <!--\r\n Widget Content: Renders the main content of the widget using the child uxp-ruclib-widget-item component.\r\n -->\r\n <div class=\"widget-content\">\r\n <uxp-ruclib-widget-item\r\n [widgetConfig]=\"widgetConfig\"\r\n ></uxp-ruclib-widget-item>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n", styles: [":host{display:block}.widget-container{border:1px solid #ccc;border-radius:8px;box-shadow:0 2px 4px #0000001a;display:flex;flex-direction:column;position:absolute;overflow:hidden;padding:15px;transition:box-shadow .2s ease-in-out,border-color .2s ease-in-out}.widget-container:hover{box-shadow:0 4px 8px #0003;border-color:#007bff;transform:translateY(-2px)}.widget-container.is-active{box-shadow:0 10px 20px #00000040,0 6px 6px #0000003b;border-color:#28a745;transform:scale(1.02);z-index:1000;cursor:grabbing!important}.widget-container .cdk-drag-placeholder{opacity:.4;background-color:#f0f0f0;border:1px dashed #999;transition:none}.widget-container .cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.widget-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.widget-container.draggable .widget-header{cursor:move}.widget-header-left{display:flex;align-items:center;gap:8px;overflow:hidden}.widget-header-icon{flex-shrink:0}.widget-header-left h3{margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.widget-header h3{margin:0;font-size:1.2em}.widget-drag-handle{color:#aaa;flex-shrink:0}.widget-close-button{background:none;border:none;cursor:pointer;padding:0;line-height:1;transition:color .2s ease-in-out}.widget-close-button mat-icon{font-size:20px;vertical-align:middle}.widget-content{flex-grow:1;overflow:auto;font-size:.9em}.widget-content p{margin-top:0;line-height:1.6}.widgets-host-container{position:relative;width:100%;min-height:600px;border:1px dashed #eee}.widget-container.disabled{opacity:.6;pointer-events:none;cursor:not-allowed}.widget-container.resizable{resize:both}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i4.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i4.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: RuclibWidgetItemComponent, selector: "uxp-ruclib-widget-item", inputs: ["widgetConfig"] }] }); }
219
- }
220
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: RuclibWidgetComponent, decorators: [{
221
- type: Component,
222
- args: [{ selector: 'uxp-ruclib-widget', imports: [CommonModule, MatIconModule,
223
- MatButtonModule,
224
- DragDropModule, RuclibWidgetItemComponent], template: "<!--\r\nThe main container for all widgets.\r\n- Applies a custom theme class if provided.\r\n- Acts as the boundary for dragging operations via the #widgetsHostContainer template reference.\r\n-->\r\n<div\r\n class=\"widgets-host-container {{ customTheme || '' }}\"\r\n #widgetsHostContainer\r\n >\r\n <!--\r\n Iterates through the widget data to render each individual widget.\r\n Each widget is a draggable container powered by Angular CDK.\r\n -->\r\n @for (widgetConfig of getWidgetData(); track widgetConfig) {\r\n <div\r\n [style.width]=\"widgetConfig.width ? widgetConfig.width : '200px'\"\r\n [style.height]=\"widgetConfig.height ? widgetConfig.height : '150px'\"\r\n [style.minWidth]=\"widgetConfig.width ? widgetConfig.width : '200px'\"\r\n [style.minHeight]=\"widgetConfig.height ? widgetConfig.height : '150px'\"\r\n [style.top]=\"widgetConfig.top\"\r\n [style.left]=\"widgetConfig.left\"\r\n [style.background-color]=\"widgetConfig.backgroundColor\"\r\n [class.disabled]=\"widgetConfig.disabled\"\r\n [class.draggable]=\"widgetConfig.draggable && !widgetConfig.disabled\"\r\n [class.resizable]=\"widgetConfig.resizable && !widgetConfig.disabled\"\r\n class=\"widget-container\"\r\n cdkDrag\r\n [cdkDragDisabled]=\"!widgetConfig.draggable || widgetConfig.disabled\"\r\n [cdkDragBoundary]=\"dragBoundaryElement\"\r\n (cdkDragStarted)=\"onDragStarted(widgetConfig, $event)\"\r\n (cdkDragEnded)=\"onDragEnded(widgetConfig, $event)\"\r\n [ngClass]=\"{ 'is-active': widgetConfig.isActive }\"\r\n >\r\n <!--\r\n Widget Header: Contains title and controls. Acts as the handle for dragging.\r\n -->\r\n <div class=\"widget-header\" cdkDragHandle>\r\n <div class=\"widget-header-left\">\r\n <!-- Draggable indicator icon, shown only if the widget is draggable and not disabled -->\r\n @if (widgetConfig.draggable && !widgetConfig.disabled) {\r\n <mat-icon\r\n class=\"widget-drag-handle\"\r\n aria-hidden=\"true\"\r\n >drag_indicator</mat-icon\r\n >\r\n }\r\n <!-- Optional header icon -->\r\n @if (widgetConfig.headerIcon) {\r\n <mat-icon class=\"widget-header-icon\">{{\r\n widgetConfig.headerIcon\r\n }}</mat-icon>\r\n }\r\n <!-- Widget Title -->\r\n @if (widgetConfig?.title) {\r\n <h3>{{ widgetConfig?.title }}</h3>\r\n }\r\n </div>\r\n <!-- Optional close button with accessibility label -->\r\n @if (widgetConfig?.showCloseIcon) {\r\n <button\r\n color=\"{{ getColor() }}\"\r\n mat-icon-button\r\n class=\"widget-close-button\"\r\n [disabled]=\"widgetConfig.disabled\"\r\n (click)=\"onCloseClick(widgetConfig.id)\"\r\n [attr.aria-label]=\"'Close widget ' + widgetConfig?.title\"\r\n >\r\n <mat-icon color=\"{{ getColor() }}\">close</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n <!--\r\n Widget Content: Renders the main content of the widget using the child uxp-ruclib-widget-item component.\r\n -->\r\n <div class=\"widget-content\">\r\n <uxp-ruclib-widget-item\r\n [widgetConfig]=\"widgetConfig\"\r\n ></uxp-ruclib-widget-item>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n", styles: [":host{display:block}.widget-container{border:1px solid #ccc;border-radius:8px;box-shadow:0 2px 4px #0000001a;display:flex;flex-direction:column;position:absolute;overflow:hidden;padding:15px;transition:box-shadow .2s ease-in-out,border-color .2s ease-in-out}.widget-container:hover{box-shadow:0 4px 8px #0003;border-color:#007bff;transform:translateY(-2px)}.widget-container.is-active{box-shadow:0 10px 20px #00000040,0 6px 6px #0000003b;border-color:#28a745;transform:scale(1.02);z-index:1000;cursor:grabbing!important}.widget-container .cdk-drag-placeholder{opacity:.4;background-color:#f0f0f0;border:1px dashed #999;transition:none}.widget-container .cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.widget-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.widget-container.draggable .widget-header{cursor:move}.widget-header-left{display:flex;align-items:center;gap:8px;overflow:hidden}.widget-header-icon{flex-shrink:0}.widget-header-left h3{margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.widget-header h3{margin:0;font-size:1.2em}.widget-drag-handle{color:#aaa;flex-shrink:0}.widget-close-button{background:none;border:none;cursor:pointer;padding:0;line-height:1;transition:color .2s ease-in-out}.widget-close-button mat-icon{font-size:20px;vertical-align:middle}.widget-content{flex-grow:1;overflow:auto;font-size:.9em}.widget-content p{margin-top:0;line-height:1.6}.widgets-host-container{position:relative;width:100%;min-height:600px;border:1px dashed #eee}.widget-container.disabled{opacity:.6;pointer-events:none;cursor:not-allowed}.widget-container.resizable{resize:both}\n"] }]
225
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { rucInputData: [{
226
- type: Input
227
- }], customTheme: [{
228
- type: Input
229
- }], widgetClose: [{
230
- type: Output
231
- }], layoutChanged: [{
232
- type: Output
233
- }], widgetsHostContainerRef: [{
234
- type: ViewChild,
235
- args: ['widgetsHostContainer']
236
- }] } });
237
-
238
- /**
239
- * Generated bundle index. Do not edit.
240
- */
241
-
242
- export { RuclibWidgetComponent };
243
- //# sourceMappingURL=ruc-lib-widget.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ruc-lib-widget.mjs","sources":["../../src/pipes/safe-html.pipe.ts","../../src/lib/ruclib-widget-item/ruclib-widget-item.component.ts","../../src/lib/ruclib-widget-item/ruclib-widget-item.component.html","../../src/lib/ruclib-widget/ruclib-widget.component.ts","../../src/lib/ruclib-widget/ruclib-widget.component.html","../../src/ruc-lib-widget.ts"],"sourcesContent":["import { Pipe, PipeTransform } from '@angular/core';\r\nimport { DomSanitizer } from '@angular/platform-browser';\r\n\r\n/**\r\n * @Pipe SafeHtmlPipe\r\n * @name safeHtml\r\n * @description A pipe that bypasses Angular's built-in security and sanitizes HTML content,\r\n * allowing it to be safely rendered in the DOM. Use with caution and only with trusted HTML sources.\r\n */\r\n@Pipe({ name: 'safeHtml', standalone:true })\r\nexport class SafeHtmlPipe implements PipeTransform {\r\n /**\r\n * @param sanitizer - An instance of DomSanitizer used to bypass security.\r\n */\r\n constructor(private sanitizer: DomSanitizer) { }\r\n /**\r\n * Transforms a string containing HTML into a SafeHtml object that can be bound to [innerHTML].\r\n * @param value - The HTML string to sanitize.\r\n * @returns A SafeHtml object, which Angular trusts as safe HTML.\r\n */\r\n transform(value: any) {\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n return this.sanitizer.bypassSecurityTrustHtml(value);\r\n }\r\n}\r\n","import {\r\n Component,\r\n Input,\r\n ViewChild,\r\n ViewContainerRef,\r\n ComponentRef,\r\n OnChanges,\r\n SimpleChanges,\r\n OnDestroy,\r\n Type,\r\n ChangeDetectorRef,\r\n AfterViewInit\r\n} from '@angular/core';\r\nimport { DomSanitizer } from '@angular/platform-browser';\r\nimport { WidgetConfigData } from '../../interface/widget';\r\n\r\nimport { SafeHtmlPipe } from '../../pipes/safe-html.pipe';\r\n\r\n\r\n@Component({\r\n selector: 'uxp-ruclib-widget-item',\r\n imports: [SafeHtmlPipe],\r\n templateUrl: './ruclib-widget-item.component.html',\r\n styleUrl: './ruclib-widget-item.component.scss'\r\n})\r\nexport class RuclibWidgetItemComponent implements OnChanges, OnDestroy, AfterViewInit {\r\n /**\r\n * The configuration object for this specific widget item.\r\n * It determines the type of content to render and provides the necessary data.\r\n */\r\n @Input() widgetConfig!: WidgetConfigData;\r\n\r\n /**\r\n * A reference to the view container where a dynamic component will be injected.\r\n * This is used when `widgetConfig.contentType` is 'component'.\r\n */\r\n @ViewChild('widgetComponentHost', { read: ViewContainerRef }) widgetComponentHost!: ViewContainerRef;\r\n /**\r\n * A reference to the dynamically created component instance.\r\n * This is used to manage the lifecycle of the injected component.\r\n */\r\n private dynamicComponentRef: ComponentRef<unknown> | null = null;\r\n\r\n /**\r\n * @param cdr The ChangeDetectorRef to manually trigger change detection.\r\n * @param sanitizer The DomSanitizer service to prevent XSS attacks by sanitizing HTML.\r\n */\r\n constructor(private cdr: ChangeDetectorRef, private sanitizer: DomSanitizer) { }\r\n\r\n /**\r\n * A lifecycle hook that responds when Angular sets or resets data-bound input properties.\r\n * It checks for changes in `widgetConfig` and reloads the content accordingly.\r\n * @param changes An object of the changed properties.\r\n */\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['widgetConfig']) {\r\n if (this.widgetConfig.contentType === 'component' && this.widgetComponentHost) {\r\n this.loadDynamicContent();\r\n } else if (this.widgetConfig.contentType !== 'component') {\r\n this.clearDynamicContent();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * A lifecycle hook that is called after Angular has fully initialized a component's view.\r\n * It ensures that if the initial content type is 'component', it gets loaded.\r\n */\r\n ngAfterViewInit(): void {\r\n if(this.widgetConfig) {\r\n if (this.widgetConfig.contentType === 'component' && this.widgetComponentHost) {\r\n this.loadDynamicContent();\r\n }\r\n }\r\n\r\n }\r\n\r\n /**\r\n * Loads a dynamic component into the `widgetComponentHost` view container.\r\n * It reads the component type and any input data from the `widgetConfig`.\r\n */\r\n private loadDynamicContent(): void {\r\n this.clearDynamicContent();\r\n if (this.widgetConfig.contentType === 'component' && this.widgetConfig.contentData && this.widgetConfig.contentData.component) {\r\n if (this.widgetComponentHost) {\r\n const componentType = this.widgetConfig.contentData.component as Type<unknown>;\r\n this.dynamicComponentRef = this.widgetComponentHost.createComponent(componentType);\r\n\r\n if (this.widgetConfig.contentData.inputs && this.dynamicComponentRef?.instance) {\r\n Object.keys(this.widgetConfig.contentData.inputs).forEach(key => {\r\n if (this.dynamicComponentRef && key in (this.dynamicComponentRef.instance as any)) {\r\n (this.dynamicComponentRef.instance as any)[key] = this.widgetConfig.contentData.inputs[key];\r\n }\r\n });\r\n this.dynamicComponentRef.changeDetectorRef.detectChanges();\r\n }\r\n }\r\n }\r\n this.cdr.detectChanges();\r\n }\r\n\r\n /**\r\n * Clears any dynamically loaded component from the view container and destroys its instance.\r\n */\r\n private clearDynamicContent(): void {\r\n if (this.dynamicComponentRef) {\r\n this.dynamicComponentRef.destroy();\r\n this.dynamicComponentRef = null;\r\n }\r\n if (this.widgetComponentHost) {\r\n this.widgetComponentHost.clear();\r\n }\r\n }\r\n\r\n /**\r\n * A lifecycle hook that cleans up the component before it's destroyed.\r\n * Ensures that any dynamically created components are properly destroyed to avoid memory leaks.\r\n */\r\n ngOnDestroy(): void {\r\n this.clearDynamicContent();\r\n }\r\n}\r\n","<!--\r\nThis container uses a switch to determine how to render the widget's content\r\nbased on the `contentType` property in the widget's configuration.\r\n-->\r\n@if (widgetConfig) {\r\n @switch (widgetConfig.contentType) {\r\n @case ('text') {\r\n <p>{{ widgetConfig.contentData }}</p>\r\n }\r\n @case ('html') {\r\n <div [innerHTML]=\"widgetConfig.contentData | safeHtml\"></div>\r\n }\r\n @case ('video') {\r\n <video\r\n [src]=\"widgetConfig.contentData.src\"\r\n [attr.type]=\"widgetConfig.contentData.type\"\r\n [controls]=\"widgetConfig.contentData.controls\"\r\n [autoplay]=\"widgetConfig.contentData.autoplay\"\r\n [loop]=\"widgetConfig.contentData.loop\"\r\n style=\"width: 100%; height: 100%; object-fit: contain\"\r\n ></video>\r\n }\r\n @case ('component') {\r\n <ng-template #widgetComponentHost></ng-template>\r\n }\r\n @default {\r\n <p>No content provided or content type not supported.</p>\r\n }\r\n }\r\n}\r\n","import { MatButtonModule } from '@angular/material/button';\r\nimport { MatIconModule } from '@angular/material/icon';\r\nimport { Component, Input, Output, EventEmitter, ViewChild, ElementRef, AfterViewInit, ChangeDetectorRef } from '@angular/core';\r\nimport { WidgetConfig, WidgetConfigData } from '../../interface/widget';\r\nimport { CdkDragStart, CdkDragEnd, DragDropModule } from '@angular/cdk/drag-drop';\r\nimport { CommonModule } from '@angular/common';\r\nimport { RuclibWidgetItemComponent } from '../ruclib-widget-item/ruclib-widget-item.component';\r\n\r\n@Component({\r\n selector: 'uxp-ruclib-widget',\r\n imports: [CommonModule, MatIconModule,\r\n MatButtonModule,\r\n DragDropModule, RuclibWidgetItemComponent],\r\n templateUrl: './ruclib-widget.component.html',\r\n styleUrl: './ruclib-widget.component.scss'\r\n})\r\nexport class RuclibWidgetComponent implements AfterViewInit {\r\n /**\r\n * The main configuration object for the widget container.\r\n * It includes the array of widget data and global settings.\r\n * @see WidgetConfig interface for detailed properties.\r\n */\r\n @Input() rucInputData!: WidgetConfig;\r\n\r\n /**\r\n * An optional custom theme class to be applied to the widget host container.\r\n * @example 'dark-theme', 'custom-theme-one'\r\n */\r\n @Input() customTheme: string | undefined;\r\n\r\n /**\r\n * An event emitter that fires when a widget's close icon is clicked.\r\n * It emits the unique ID of the widget to be closed.\r\n */\r\n @Output() widgetClose = new EventEmitter<string>();\r\n\r\n /**\r\n * An event emitter that fires when a widget is dragged and dropped.\r\n * It emits the entire updated array of widget configurations, allowing the parent to save the new layout.\r\n */\r\n @Output() layoutChanged = new EventEmitter<WidgetConfigData[]>();\r\n\r\n /**\r\n * @param cdr The ChangeDetectorRef to manually trigger change detection when needed.\r\n */\r\n constructor(private cdr: ChangeDetectorRef) { }\r\n\r\n /** A reference to the host container element, used to define the drag boundary. */\r\n @ViewChild('widgetsHostContainer') widgetsHostContainerRef!: ElementRef<HTMLElement>;\r\n /** The HTML element that serves as the boundary for all drag operations. */\r\n public dragBoundaryElement!: HTMLElement;\r\n\r\n /**\r\n * After the view initializes, this hook captures the host container's native element\r\n * and sets it as the boundary for dragging widgets.\r\n */\r\n ngAfterViewInit(): void {\r\n if (this.widgetsHostContainerRef) {\r\n this.dragBoundaryElement = this.widgetsHostContainerRef.nativeElement;\r\n this.cdr.detectChanges();\r\n }\r\n }\r\n\r\n /**\r\n * Handles the click event on a widget's close button.\r\n * @param widgetId The ID of the widget to be closed.\r\n */\r\n onCloseClick(widgetId: string): void {\r\n this.widgetClose.emit(widgetId);\r\n }\r\n\r\n /**\r\n * Handles the start of a drag operation for a widget.\r\n * Sets the widget's isActive state to true for visual feedback.\r\n * @param widget The WidgetConfigData object being dragged.\r\n * @param event The CdkDragStart event.\r\n */\r\n onDragStarted(widget: WidgetConfigData, event: CdkDragStart): void {\r\n widget.isActive = true;\r\n }\r\n\r\n /**\r\n * Handles the end of a drag operation.\r\n * It calculates the new top/left position, updates the widget's configuration,\r\n * and emits the `layoutChanged` event with the new layout data.\r\n * @param widget The WidgetConfigData object that was dragged.\r\n * @param event The CdkDragEnd event.\r\n */\r\n onDragEnded(widget: WidgetConfigData, event: CdkDragEnd): void {\r\n widget.isActive = false;\r\n\r\n const newPosition = event.source.getFreeDragPosition();\r\n\r\n const initialTopPx = parseFloat(widget.top || '0');\r\n const initialLeftPx = parseFloat(widget.left || '0');\r\n\r\n const newTopPx = initialTopPx + newPosition.y;\r\n const newLeftPx = initialLeftPx + newPosition.x;\r\n\r\n widget.top = `${newTopPx}px`;\r\n widget.left = `${newLeftPx}px`;\r\n\r\n event.source.reset();\r\n\r\n if (this.rucInputData.widgetData) {\r\n this.layoutChanged.emit(this.rucInputData.widgetData);\r\n }\r\n }\r\n\r\n /**\r\n * Retrieves the color for UI elements like icons from the input data.\r\n * @returns The color string (e.g., 'primary', 'accent') or 'primary' as a default.\r\n */\r\n getColor(): string {\r\n return this.rucInputData?.color || 'primary';\r\n }\r\n\r\n /**\r\n * A safe getter for the widget data array from the main input configuration.\r\n * @returns The array of widget configurations, or an empty array if not defined.\r\n */\r\n getWidgetData(): WidgetConfigData[] | any {\r\n return typeof this.rucInputData.widgetData !== 'undefined' ? this.rucInputData.widgetData : [];\r\n }\r\n}\r\n\r\n","<!--\r\nThe main container for all widgets.\r\n- Applies a custom theme class if provided.\r\n- Acts as the boundary for dragging operations via the #widgetsHostContainer template reference.\r\n-->\r\n<div\r\n class=\"widgets-host-container {{ customTheme || '' }}\"\r\n #widgetsHostContainer\r\n >\r\n <!--\r\n Iterates through the widget data to render each individual widget.\r\n Each widget is a draggable container powered by Angular CDK.\r\n -->\r\n @for (widgetConfig of getWidgetData(); track widgetConfig) {\r\n <div\r\n [style.width]=\"widgetConfig.width ? widgetConfig.width : '200px'\"\r\n [style.height]=\"widgetConfig.height ? widgetConfig.height : '150px'\"\r\n [style.minWidth]=\"widgetConfig.width ? widgetConfig.width : '200px'\"\r\n [style.minHeight]=\"widgetConfig.height ? widgetConfig.height : '150px'\"\r\n [style.top]=\"widgetConfig.top\"\r\n [style.left]=\"widgetConfig.left\"\r\n [style.background-color]=\"widgetConfig.backgroundColor\"\r\n [class.disabled]=\"widgetConfig.disabled\"\r\n [class.draggable]=\"widgetConfig.draggable && !widgetConfig.disabled\"\r\n [class.resizable]=\"widgetConfig.resizable && !widgetConfig.disabled\"\r\n class=\"widget-container\"\r\n cdkDrag\r\n [cdkDragDisabled]=\"!widgetConfig.draggable || widgetConfig.disabled\"\r\n [cdkDragBoundary]=\"dragBoundaryElement\"\r\n (cdkDragStarted)=\"onDragStarted(widgetConfig, $event)\"\r\n (cdkDragEnded)=\"onDragEnded(widgetConfig, $event)\"\r\n [ngClass]=\"{ 'is-active': widgetConfig.isActive }\"\r\n >\r\n <!--\r\n Widget Header: Contains title and controls. Acts as the handle for dragging.\r\n -->\r\n <div class=\"widget-header\" cdkDragHandle>\r\n <div class=\"widget-header-left\">\r\n <!-- Draggable indicator icon, shown only if the widget is draggable and not disabled -->\r\n @if (widgetConfig.draggable && !widgetConfig.disabled) {\r\n <mat-icon\r\n class=\"widget-drag-handle\"\r\n aria-hidden=\"true\"\r\n >drag_indicator</mat-icon\r\n >\r\n }\r\n <!-- Optional header icon -->\r\n @if (widgetConfig.headerIcon) {\r\n <mat-icon class=\"widget-header-icon\">{{\r\n widgetConfig.headerIcon\r\n }}</mat-icon>\r\n }\r\n <!-- Widget Title -->\r\n @if (widgetConfig?.title) {\r\n <h3>{{ widgetConfig?.title }}</h3>\r\n }\r\n </div>\r\n <!-- Optional close button with accessibility label -->\r\n @if (widgetConfig?.showCloseIcon) {\r\n <button\r\n color=\"{{ getColor() }}\"\r\n mat-icon-button\r\n class=\"widget-close-button\"\r\n [disabled]=\"widgetConfig.disabled\"\r\n (click)=\"onCloseClick(widgetConfig.id)\"\r\n [attr.aria-label]=\"'Close widget ' + widgetConfig?.title\"\r\n >\r\n <mat-icon color=\"{{ getColor() }}\">close</mat-icon>\r\n </button>\r\n }\r\n </div>\r\n <!--\r\n Widget Content: Renders the main content of the widget using the child uxp-ruclib-widget-item component.\r\n -->\r\n <div class=\"widget-content\">\r\n <uxp-ruclib-widget-item\r\n [widgetConfig]=\"widgetConfig\"\r\n ></uxp-ruclib-widget-item>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1"],"mappings":"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"}