@ruc-lib/widget 2.0.2 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -26
- package/fesm2022/ruc-lib-widget.mjs +243 -0
- package/fesm2022/ruc-lib-widget.mjs.map +1 -0
- package/index.d.ts +167 -4
- package/package.json +7 -19
- package/esm2020/index.mjs +0 -5
- package/esm2020/interface/widget.mjs +0 -2
- package/esm2020/lib/ruclib-widget/ruclib-widget.component.mjs +0 -108
- package/esm2020/lib/ruclib-widget-item/ruclib-widget-item.component.mjs +0 -103
- package/esm2020/lib/ruclib-widget.module.mjs +0 -34
- package/esm2020/model/default-values.mjs +0 -32
- package/esm2020/pipes/safe-html.pipe.mjs +0 -36
- package/esm2020/ruc-lib-widget.mjs +0 -5
- package/fesm2015/ruc-lib-widget.mjs +0 -307
- package/fesm2015/ruc-lib-widget.mjs.map +0 -1
- package/fesm2020/ruc-lib-widget.mjs +0 -305
- package/fesm2020/ruc-lib-widget.mjs.map +0 -1
- package/interface/widget.d.ts +0 -92
- package/lib/ruclib-widget/ruclib-widget.component.d.ts +0 -77
- package/lib/ruclib-widget-item/ruclib-widget-item.component.d.ts +0 -60
- package/lib/ruclib-widget.module.d.ts +0 -13
- package/model/default-values.d.ts +0 -2
- package/pipes/safe-html.pipe.d.ts +0 -24
package/README.md
CHANGED
|
@@ -32,34 +32,38 @@ If you only need the Widget component:
|
|
|
32
32
|
npm install @ruc-lib/widget
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
##
|
|
35
|
+
## Version Compatibility
|
|
36
|
+
|
|
37
|
+
Please ensure you install the correct version of `@ruc-lib/widget` based on your Angular version.
|
|
38
|
+
|
|
39
|
+
| Angular Version | Compatible `@ruc-lib/widget` Version |
|
|
40
|
+
|--------------------|---------------------------------------------|
|
|
41
|
+
| 15.x.x | `npm install @ruc-lib/widget@^3.0.0` |
|
|
42
|
+
| 16.x.x | `npm install @ruc-lib/widget@^3.0.0` |
|
|
36
43
|
|
|
37
|
-
### 1. Import the Module
|
|
38
|
-
In your Angular module file (e.g., `app.module.ts`), import the `RuclibWidgetModule`:
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
import {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
export class AppModule {}
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### 1. Import the Component
|
|
48
|
+
In your Angular component file (e.g., `app.component.ts`), import the `RuclibWidgetComponent`:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { Component } from '@angular/core';
|
|
52
|
+
|
|
53
|
+
// For Complete Library
|
|
54
|
+
import { RuclibWidgetComponent } from '@uxpractice/ruc-lib/widget';
|
|
55
|
+
|
|
56
|
+
// For Individual Package
|
|
57
|
+
import { RuclibWidgetComponent } from '@ruc-lib/widget';
|
|
58
|
+
|
|
59
|
+
@Component({
|
|
60
|
+
selector: 'app-root',
|
|
61
|
+
imports: [RuclibWidgetComponent],
|
|
62
|
+
templateUrl: './app.component.html',
|
|
63
|
+
})
|
|
64
|
+
export class AppComponent {
|
|
65
|
+
// Component code here
|
|
66
|
+
}
|
|
63
67
|
```
|
|
64
68
|
|
|
65
69
|
### 2. Use the Component
|
|
@@ -199,6 +203,22 @@ export class AppComponent {
|
|
|
199
203
|
}
|
|
200
204
|
```
|
|
201
205
|
|
|
206
|
+
> ⚠️ **IMPORTANT: Custom Theme Usage in Angular Material**
|
|
207
|
+
|
|
208
|
+
When implementing **custom themes**, such as:
|
|
209
|
+
|
|
210
|
+
```scss
|
|
211
|
+
.custom-theme-1 {
|
|
212
|
+
@include angular-material-theme($custom-theme);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// You must also include the typography mixin to ensure text styles are applied correctly as shown below:
|
|
216
|
+
.custom-theme-1 {
|
|
217
|
+
@include angular-material-theme($custom-theme);
|
|
218
|
+
@include mat.typography-level($theme-custom-typography-name, body-1);
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
202
222
|
|
|
203
223
|
# Contribution
|
|
204
224
|
|
|
@@ -0,0 +1,243 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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":";;;;;;;;;;;;AAGA;;;;;AAKG;MAEU,YAAY,CAAA;AACvB;;AAEG;AACH,IAAA,WAAA,CAAoB,SAAuB,EAAA;QAAvB,IAAA,CAAA,SAAS,GAAT,SAAS;IAAkB;AAC/C;;;;AAIG;AACH,IAAA,SAAS,CAAC,KAAU,EAAA;QAClB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE;AACzC,YAAA,OAAO,KAAK;QACd;QACA,OAAO,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,KAAK,CAAC;IACtD;8GAfW,YAAY,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,YAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,IAAA,EAAA,CAAA,CAAA;4GAAZ,YAAY,EAAA,YAAA,EAAA,IAAA,EAAA,IAAA,EAAA,UAAA,EAAA,CAAA,CAAA;;2FAAZ,YAAY,EAAA,UAAA,EAAA,CAAA;kBADxB,IAAI;AAAC,YAAA,IAAA,EAAA,CAAA,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAC,IAAI,EAAE;;;MCgB9B,yBAAyB,CAAA;AAkBpC;;;AAGG;IACH,WAAA,CAAoB,GAAsB,EAAU,SAAuB,EAAA;QAAvD,IAAA,CAAA,GAAG,GAAH,GAAG;QAA6B,IAAA,CAAA,SAAS,GAAT,SAAS;AAV7D;;;AAGG;QACK,IAAA,CAAA,mBAAmB,GAAiC,IAAI;IAMe;AAE/E;;;;AAIG;AACH,IAAA,WAAW,CAAC,OAAsB,EAAA;AAChC,QAAA,IAAI,OAAO,CAAC,cAAc,CAAC,EAAE;AAC3B,YAAA,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,KAAK,WAAW,IAAI,IAAI,CAAC,mBAAmB,EAAE;gBAC7E,IAAI,CAAC,kBAAkB,EAAE;YAC3B;iBAAO,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,KAAK,WAAW,EAAE;gBACxD,IAAI,CAAC,mBAAmB,EAAE;YAC5B;QACF;IACF;AAEA;;;AAGG;IACH,eAAe,GAAA;AACb,QAAA,IAAG,IAAI,CAAC,YAAY,EAAE;AACpB,YAAA,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,KAAK,WAAW,IAAI,IAAI,CAAC,mBAAmB,EAAE;gBAC7E,IAAI,CAAC,kBAAkB,EAAE;YAC3B;QACF;IAEF;AAEA;;;AAGG;IACK,kBAAkB,GAAA;QACxB,IAAI,CAAC,mBAAmB,EAAE;QAC1B,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,KAAK,WAAW,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,SAAS,EAAE;AAC7H,YAAA,IAAI,IAAI,CAAC,mBAAmB,EAAE;gBAClC,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,SAA0B;gBACxE,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,aAAa,CAAC;AAElF,gBAAA,IAAI,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,MAAM,IAAI,IAAI,CAAC,mBAAmB,EAAE,QAAQ,EAAE;AAC9E,oBAAA,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG,IAAG;AAC9D,wBAAA,IAAI,IAAI,CAAC,mBAAmB,IAAI,GAAG,IAAK,IAAI,CAAC,mBAAmB,CAAC,QAAgB,EAAE;AAChF,4BAAA,IAAI,CAAC,mBAAmB,CAAC,QAAgB,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC;wBAC7F;AACF,oBAAA,CAAC,CAAC;AACF,oBAAA,IAAI,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,aAAa,EAAE;gBAC5D;YACF;QACF;AACA,QAAA,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE;IAC1B;AAEA;;AAEG;IACK,mBAAmB,GAAA;AACzB,QAAA,IAAI,IAAI,CAAC,mBAAmB,EAAE;AAC5B,YAAA,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE;AAClC,YAAA,IAAI,CAAC,mBAAmB,GAAG,IAAI;QACjC;AACA,QAAA,IAAI,IAAI,CAAC,mBAAmB,EAAE;AAC5B,YAAA,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE;QAClC;IACF;AAEA;;;AAGG;IACH,WAAW,GAAA;QACT,IAAI,CAAC,mBAAmB,EAAE;IAC5B;8GA/FW,yBAAyB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,YAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAzB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,yBAAyB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,MAAA,EAAA,EAAA,YAAA,EAAA,cAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,qBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,IAAA,EAWM,gBAAgB,EAAA,CAAA,EAAA,aAAA,EAAA,IAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECpC5D,6gCA8BA,kJDTc,YAAY,EAAA,IAAA,EAAA,UAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;2FAIb,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBANrC,SAAS;+BACI,wBAAwB,EAAA,OAAA,EACzB,CAAC,YAAY,CAAC,EAAA,QAAA,EAAA,6gCAAA,EAAA,MAAA,EAAA,CAAA,+FAAA,CAAA,EAAA;;sBASxB;;sBAMA,SAAS;AAAC,gBAAA,IAAA,EAAA,CAAA,qBAAqB,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE;;;MEpBjD,qBAAqB,CAAA;AA0BhC;;AAEG;AACH,IAAA,WAAA,CAAoB,GAAsB,EAAA;QAAtB,IAAA,CAAA,GAAG,GAAH,GAAG;AAfvB;;;AAGG;AACO,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,YAAY,EAAU;AAElD;;;AAGG;AACO,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,YAAY,EAAsB;IAKlB;AAO9C;;;AAGG;IACH,eAAe,GAAA;AACb,QAAA,IAAI,IAAI,CAAC,uBAAuB,EAAE;YAChC,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,uBAAuB,CAAC,aAAa;AACrE,YAAA,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE;QAC1B;IACF;AAEA;;;AAGG;AACH,IAAA,YAAY,CAAC,QAAgB,EAAA;AAC3B,QAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;IACjC;AAEA;;;;;AAKG;IACH,aAAa,CAAC,MAAwB,EAAE,KAAmB,EAAA;AACzD,QAAA,MAAM,CAAC,QAAQ,GAAG,IAAI;IACxB;AAEA;;;;;;AAMG;IACH,WAAW,CAAC,MAAwB,EAAE,KAAiB,EAAA;AACrD,QAAA,MAAM,CAAC,QAAQ,GAAG,KAAK;QAEvB,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,mBAAmB,EAAE;QAEtD,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC;QAClD,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC;AAEpD,QAAA,MAAM,QAAQ,GAAG,YAAY,GAAG,WAAW,CAAC,CAAC;AAC7C,QAAA,MAAM,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC,CAAC;AAE/C,QAAA,MAAM,CAAC,GAAG,GAAG,CAAA,EAAG,QAAQ,IAAI;AAC5B,QAAA,MAAM,CAAC,IAAI,GAAG,CAAA,EAAG,SAAS,IAAI;AAE9B,QAAA,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE;AAEpB,QAAA,IAAI,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE;YAChC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC;QACvD;IACF;AAEA;;;AAGG;IACH,QAAQ,GAAA;AACN,QAAA,OAAO,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,SAAS;IAC9C;AAEA;;;AAGG;IACH,aAAa,GAAA;QACX,OAAO,OAAO,IAAI,CAAC,YAAY,CAAC,UAAU,KAAK,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,GAAG,EAAE;IAChG;8GA3GW,qBAAqB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,iBAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;kGAArB,qBAAqB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,YAAA,EAAA,cAAA,EAAA,WAAA,EAAA,aAAA,EAAA,EAAA,OAAA,EAAA,EAAA,WAAA,EAAA,aAAA,EAAA,aAAA,EAAA,eAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,yBAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,sBAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EChBlC,++GAkFA,EAAA,MAAA,EAAA,CAAA,0sDAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDxEc,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,OAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,SAAA,EAAA,SAAA,EAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACjC,eAAe,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,sFAAA,EAAA,QAAA,EAAA,CAAA,WAAA,EAAA,WAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACf,cAAc,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,WAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,iBAAA,EAAA,oBAAA,EAAA,iBAAA,EAAA,mBAAA,EAAA,yBAAA,EAAA,iBAAA,EAAA,0BAAA,EAAA,qBAAA,EAAA,yBAAA,EAAA,cAAA,CAAA,EAAA,OAAA,EAAA,CAAA,gBAAA,EAAA,iBAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,eAAA,EAAA,gBAAA,EAAA,cAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,CAAA,uBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,yBAAyB,EAAA,QAAA,EAAA,wBAAA,EAAA,MAAA,EAAA,CAAA,cAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;2FAIpC,qBAAqB,EAAA,UAAA,EAAA,CAAA;kBARjC,SAAS;AACI,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,mBAAmB,EAAA,OAAA,EACpB,CAAC,YAAY,EAAE,aAAa;wBACjC,eAAe;wBACf,cAAc,EAAE,yBAAyB,CAAC,EAAA,QAAA,EAAA,++GAAA,EAAA,MAAA,EAAA,CAAA,0sDAAA,CAAA,EAAA;;sBAU/C;;sBAMA;;sBAMA;;sBAMA;;sBAQA,SAAS;uBAAC,sBAAsB;;;AEhDnC;;AAEG;;;;"}
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,167 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Type, AfterViewInit, EventEmitter, ChangeDetectorRef, ElementRef } from '@angular/core';
|
|
3
|
+
import { CdkDragStart, CdkDragEnd } from '@angular/cdk/drag-drop';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Defines the input properties for the main `ruclib-widget` component.
|
|
7
|
+
*/
|
|
8
|
+
interface WidgetConfig {
|
|
9
|
+
/**
|
|
10
|
+
* The theme color to be applied to interactive elements like icons.
|
|
11
|
+
* @example 'primary', 'accent', 'warn'
|
|
12
|
+
* @optional
|
|
13
|
+
*/
|
|
14
|
+
color?: string;
|
|
15
|
+
/**
|
|
16
|
+
* An array of configuration objects, each defining a single widget.
|
|
17
|
+
* @optional
|
|
18
|
+
*/
|
|
19
|
+
widgetData?: WidgetConfigData[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Defines the configuration for a single widget within the container.
|
|
23
|
+
*/
|
|
24
|
+
interface WidgetConfigData {
|
|
25
|
+
/** A unique identifier for the widget. */
|
|
26
|
+
id: string;
|
|
27
|
+
/**
|
|
28
|
+
* The title to be displayed in the widget's header.
|
|
29
|
+
* @optional
|
|
30
|
+
*/
|
|
31
|
+
title?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The description or main text content, used when `contentType` is 'text'.
|
|
34
|
+
* @optional
|
|
35
|
+
*/
|
|
36
|
+
description?: string;
|
|
37
|
+
/**
|
|
38
|
+
* If true, a close icon is displayed in the header to allow the user to remove the widget.
|
|
39
|
+
* @optional
|
|
40
|
+
*/
|
|
41
|
+
showCloseIcon?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* If true, the widget is visually faded and cannot be interacted with (dragged, resized, etc.).
|
|
44
|
+
* @optional
|
|
45
|
+
*/
|
|
46
|
+
disabled?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* The CSS width of the widget.
|
|
49
|
+
* @example '300px', '50%', '33vw'
|
|
50
|
+
* @optional
|
|
51
|
+
*/
|
|
52
|
+
width?: string;
|
|
53
|
+
/**
|
|
54
|
+
* The CSS height of the widget.
|
|
55
|
+
* @example '200px', 'auto', '50vh'
|
|
56
|
+
* @optional
|
|
57
|
+
*/
|
|
58
|
+
height?: string;
|
|
59
|
+
/**
|
|
60
|
+
* If true, the widget can be dragged around the container.
|
|
61
|
+
* @optional
|
|
62
|
+
*/
|
|
63
|
+
draggable?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* If true, the widget can be resized by the user (requires a resizing library implementation).
|
|
66
|
+
* @optional
|
|
67
|
+
*/
|
|
68
|
+
resizable?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* The type of content the widget will display.
|
|
71
|
+
* @optional
|
|
72
|
+
*/
|
|
73
|
+
contentType?: 'text' | 'html' | 'component' | 'chart' | 'video' | 'audio';
|
|
74
|
+
/**
|
|
75
|
+
* The data for the content. The structure depends on the `contentType`.
|
|
76
|
+
* For 'component', it should be an object: `{ component: YourComponent, inputs: { ... } }`.
|
|
77
|
+
* @optional
|
|
78
|
+
*/
|
|
79
|
+
contentData?: any | {
|
|
80
|
+
component: Type<any>;
|
|
81
|
+
inputs?: {
|
|
82
|
+
[key: string]: any;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
/** The CSS `top` position for absolute positioning. @example '20px', '5%' @optional */
|
|
86
|
+
top?: string;
|
|
87
|
+
/** The CSS `left` position for absolute positioning. @example '20px', '5%' @optional */
|
|
88
|
+
left?: string;
|
|
89
|
+
/** The name of a Material icon to display in the header. @optional */
|
|
90
|
+
headerIcon?: string;
|
|
91
|
+
/** Internal state flag to indicate if the widget is being actively dragged or resized. @optional */
|
|
92
|
+
isActive?: boolean;
|
|
93
|
+
/** The CSS `background-color` for the widget. @example '#ffffff', 'rgba(0,0,0,0.1)' @optional */
|
|
94
|
+
backgroundColor?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
declare class RuclibWidgetComponent implements AfterViewInit {
|
|
98
|
+
private cdr;
|
|
99
|
+
/**
|
|
100
|
+
* The main configuration object for the widget container.
|
|
101
|
+
* It includes the array of widget data and global settings.
|
|
102
|
+
* @see WidgetConfig interface for detailed properties.
|
|
103
|
+
*/
|
|
104
|
+
rucInputData: WidgetConfig;
|
|
105
|
+
/**
|
|
106
|
+
* An optional custom theme class to be applied to the widget host container.
|
|
107
|
+
* @example 'dark-theme', 'custom-theme-one'
|
|
108
|
+
*/
|
|
109
|
+
customTheme: string | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* An event emitter that fires when a widget's close icon is clicked.
|
|
112
|
+
* It emits the unique ID of the widget to be closed.
|
|
113
|
+
*/
|
|
114
|
+
widgetClose: EventEmitter<string>;
|
|
115
|
+
/**
|
|
116
|
+
* An event emitter that fires when a widget is dragged and dropped.
|
|
117
|
+
* It emits the entire updated array of widget configurations, allowing the parent to save the new layout.
|
|
118
|
+
*/
|
|
119
|
+
layoutChanged: EventEmitter<WidgetConfigData[]>;
|
|
120
|
+
/**
|
|
121
|
+
* @param cdr The ChangeDetectorRef to manually trigger change detection when needed.
|
|
122
|
+
*/
|
|
123
|
+
constructor(cdr: ChangeDetectorRef);
|
|
124
|
+
/** A reference to the host container element, used to define the drag boundary. */
|
|
125
|
+
widgetsHostContainerRef: ElementRef<HTMLElement>;
|
|
126
|
+
/** The HTML element that serves as the boundary for all drag operations. */
|
|
127
|
+
dragBoundaryElement: HTMLElement;
|
|
128
|
+
/**
|
|
129
|
+
* After the view initializes, this hook captures the host container's native element
|
|
130
|
+
* and sets it as the boundary for dragging widgets.
|
|
131
|
+
*/
|
|
132
|
+
ngAfterViewInit(): void;
|
|
133
|
+
/**
|
|
134
|
+
* Handles the click event on a widget's close button.
|
|
135
|
+
* @param widgetId The ID of the widget to be closed.
|
|
136
|
+
*/
|
|
137
|
+
onCloseClick(widgetId: string): void;
|
|
138
|
+
/**
|
|
139
|
+
* Handles the start of a drag operation for a widget.
|
|
140
|
+
* Sets the widget's isActive state to true for visual feedback.
|
|
141
|
+
* @param widget The WidgetConfigData object being dragged.
|
|
142
|
+
* @param event The CdkDragStart event.
|
|
143
|
+
*/
|
|
144
|
+
onDragStarted(widget: WidgetConfigData, event: CdkDragStart): void;
|
|
145
|
+
/**
|
|
146
|
+
* Handles the end of a drag operation.
|
|
147
|
+
* It calculates the new top/left position, updates the widget's configuration,
|
|
148
|
+
* and emits the `layoutChanged` event with the new layout data.
|
|
149
|
+
* @param widget The WidgetConfigData object that was dragged.
|
|
150
|
+
* @param event The CdkDragEnd event.
|
|
151
|
+
*/
|
|
152
|
+
onDragEnded(widget: WidgetConfigData, event: CdkDragEnd): void;
|
|
153
|
+
/**
|
|
154
|
+
* Retrieves the color for UI elements like icons from the input data.
|
|
155
|
+
* @returns The color string (e.g., 'primary', 'accent') or 'primary' as a default.
|
|
156
|
+
*/
|
|
157
|
+
getColor(): string;
|
|
158
|
+
/**
|
|
159
|
+
* A safe getter for the widget data array from the main input configuration.
|
|
160
|
+
* @returns The array of widget configurations, or an empty array if not defined.
|
|
161
|
+
*/
|
|
162
|
+
getWidgetData(): WidgetConfigData[] | any;
|
|
163
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RuclibWidgetComponent, never>;
|
|
164
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RuclibWidgetComponent, "uxp-ruclib-widget", never, { "rucInputData": { "alias": "rucInputData"; "required": false; }; "customTheme": { "alias": "customTheme"; "required": false; }; }, { "widgetClose": "widgetClose"; "layoutChanged": "layoutChanged"; }, never, never, true, never>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export { RuclibWidgetComponent };
|
package/package.json
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ruc-lib/widget",
|
|
3
|
-
"version": "
|
|
4
|
-
"license": "MIT",
|
|
3
|
+
"version": "3.1.0",
|
|
5
4
|
"peerDependencies": {
|
|
6
|
-
"@angular/
|
|
7
|
-
"@angular/
|
|
8
|
-
"@angular/material": "^15.
|
|
9
|
-
"@angular/animations": "
|
|
5
|
+
"@angular/common": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0",
|
|
6
|
+
"@angular/core": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0",
|
|
7
|
+
"@angular/material": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0",
|
|
8
|
+
"@angular/animations": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0"
|
|
10
9
|
},
|
|
11
10
|
"dependencies": {
|
|
12
11
|
"tslib": "^2.3.0"
|
|
13
12
|
},
|
|
14
|
-
"publishConfig": {
|
|
15
|
-
"access": "public"
|
|
16
|
-
},
|
|
17
13
|
"sideEffects": false,
|
|
18
|
-
"module": "
|
|
19
|
-
"es2020": "fesm2020/ruc-lib-widget.mjs",
|
|
20
|
-
"esm2020": "esm2020/ruc-lib-widget.mjs",
|
|
21
|
-
"fesm2020": "fesm2020/ruc-lib-widget.mjs",
|
|
22
|
-
"fesm2015": "fesm2015/ruc-lib-widget.mjs",
|
|
14
|
+
"module": "fesm2022/ruc-lib-widget.mjs",
|
|
23
15
|
"typings": "index.d.ts",
|
|
24
16
|
"exports": {
|
|
25
17
|
"./package.json": {
|
|
@@ -27,11 +19,7 @@
|
|
|
27
19
|
},
|
|
28
20
|
".": {
|
|
29
21
|
"types": "./index.d.ts",
|
|
30
|
-
"
|
|
31
|
-
"es2020": "./fesm2020/ruc-lib-widget.mjs",
|
|
32
|
-
"es2015": "./fesm2015/ruc-lib-widget.mjs",
|
|
33
|
-
"node": "./fesm2015/ruc-lib-widget.mjs",
|
|
34
|
-
"default": "./fesm2020/ruc-lib-widget.mjs"
|
|
22
|
+
"default": "./fesm2022/ruc-lib-widget.mjs"
|
|
35
23
|
}
|
|
36
24
|
}
|
|
37
25
|
}
|
package/esm2020/index.mjs
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export * from './lib/ruclib-widget.module';
|
|
2
|
-
export * from './lib/ruclib-widget/ruclib-widget.component';
|
|
3
|
-
export * from './model/default-values';
|
|
4
|
-
export * from './interface/widget';
|
|
5
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLDZDQUE2QyxDQUFDO0FBQzVELGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyxvQkFBb0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCAqIGZyb20gJy4vbGliL3J1Y2xpYi13aWRnZXQubW9kdWxlJztcclxuZXhwb3J0ICogZnJvbSAnLi9saWIvcnVjbGliLXdpZGdldC9ydWNsaWItd2lkZ2V0LmNvbXBvbmVudCc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbW9kZWwvZGVmYXVsdC12YWx1ZXMnO1xyXG5leHBvcnQgKiBmcm9tICcuL2ludGVyZmFjZS93aWRnZXQnO1xyXG4iXX0=
|