UNPKG

@ngx-dynamic-components/tools

Version:

@ngx-dynamic-components/tools is Angular 7+ library what contains a core interfaces to build a configuration driven web pages.

495 lines (486 loc) 41.9 kB
import * as i0 from '@angular/core'; import { Component, Input, ViewChild, HostBinding, EventEmitter, Output, HostListener, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import * as i8 from 'angular-split'; import { AngularSplitModule } from 'angular-split'; import { MatToolbarModule } from '@angular/material/toolbar'; import * as i2$1 from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button'; import * as i4 from '@angular/material/tabs'; import { MatTabsModule } from '@angular/material/tabs'; import { MatDividerModule } from '@angular/material/divider'; import * as i5 from '@angular/material/card'; import { MatCardModule } from '@angular/material/card'; import * as i3 from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon'; import * as i4$1 from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip'; import * as i5$1 from '@angular/material/input'; import { MatInputModule } from '@angular/material/input'; import * as i6 from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field'; import * as i1$1 from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog'; import * as i3$1 from '@angular/material/list'; import { MatListModule } from '@angular/material/list'; import * as i2 from '@ngx-dynamic-components/core'; import { getComponentById, formatObjToJsonStr, CoreService, DynamicComponentsCoreModule } from '@ngx-dynamic-components/core'; import { DynamicComponentsBootstrapModule } from '@ngx-dynamic-components/bootstrap'; import { debounceTime, map } from 'rxjs/operators'; import { fromEvent } from 'rxjs'; import { edit } from 'ace-builds'; import { jsPython } from 'jspython-interpreter'; // eslint-disable-next-line no-shadow var Layout; (function (Layout) { Layout["horizontal"] = "horizontal"; Layout["vertical"] = "vertical"; })(Layout || (Layout = {})); class PreviewEditorComponent { scripts; initUiModel; initDataModel; title; uiModelEl; uiModelJSONEl; scriptsEl; dataModelEl; dynamicComponent; flex = 'initial'; dataModel; dataModelCopy; uiModel; uiModelEditor; uiModelJSONEditor; dataModelEditor; scriptsEditor; interpreter; editorOptions = { language: 'json', automaticLayout: true, }; direction = Layout.horizontal; codeSize = 50; async eventHandlers({ eventName, rootUIModel, parameters = null, sender, eventHandler }) { if (!this.interpreter) { return; } if (this.interpreter.hasFunction(this.scripts, eventHandler)) { try { if (parameters) { parameters[parameters.argsKey] = parameters.argsValue; } const res = await this.interpreter.evaluate(this.scripts, { rootUIModel, dataModel: this.dataModel, ...parameters, }, eventHandler); sender?.setEventHandlerResult(eventName, res); } catch (e) { alert(`${e.message}`); } } } ngOnInit() { this.interpreter = jsPython(); this.interpreter.addFunction('getComponentById', (uiModel, id) => getComponentById(uiModel, id)); this.interpreter.addFunction('alert', (msg) => alert(msg)); this.interpreter.assignGlobalContext({}); this.uiModel = this.initUiModel; this.dataModel = this.initDataModel; } ngAfterViewInit() { this.onDataModelChange(this.dynamicComponent.dataModel); this.initUIPreview(); } toggleSourceCode() { this.codeSize = !this.codeSize ? 50 : 0; } toggleLayout() { this.direction = this.direction === Layout.horizontal ? Layout.vertical : Layout.horizontal; } get isHorizontal() { return this.direction === Layout.horizontal; } onRendered(data) { console.log('rendered', data); } onDataModelChange(data) { if (data && this.dataModelEditor) { this.dataModelEditor.setValue(formatObjToJsonStr(data)); } else if (this.uiModelEditor) { this.uiModelEditor.setValue(formatObjToJsonStr(this.uiModel)); } } resize() { this.scriptsEditor.resize(); this.uiModelEditor.resize(); this.uiModelJSONEditor.resize(); this.dataModelEditor.resize(); } initUIPreview() { if (this.uiModelEl) { this.uiModelJSONEditor = edit(this.uiModelJSONEl.nativeElement, { mode: 'ace/mode/json', autoScrollEditorIntoView: true, tabSize: 2, useSoftTabs: true, readOnly: true, }); this.setJSONEditor(this.initUiModel); this.initEditor('uiModel', this.uiModelEl, this.initUiModel, 'ace/mode/xml').pipe(debounceTime(500)).subscribe((uiModel) => { this.dynamicComponent.containerRef.clear(); this.setJSONEditor(uiModel); this.refreshPreview(uiModel, this.dataModel); }); this.initEditor('dataModel', this.dataModelEl, this.initDataModel).subscribe((dataModel) => this.refreshPreview(this.uiModel, dataModel ? JSON.parse(dataModel) : dataModel)); this.initEditor('scripts', this.scriptsEl, this.scripts, 'ace/mode/python').subscribe((sc) => (this.scripts = sc)); } } setJSONEditor(uiModel) { const res = CoreService.parseXMLModel(uiModel); this.uiModelJSONEditor.setValue(formatObjToJsonStr(res), -1); this.uiModelJSONEditor.resize(); } refreshPreview(uiModel, dataModel) { this.uiModel = uiModel; this.dataModelCopy = JSON.parse(JSON.stringify(dataModel)); } // eslint-disable-next-line max-len initEditor(name, element, value, mode = 'ace/mode/json') { const editor = edit(element.nativeElement, { mode, autoScrollEditorIntoView: true, value: formatObjToJsonStr(value), tabSize: 2, useSoftTabs: true, indentedSoftWrap: true, }); editor.setOptions({ enableBasicAutocompletion: true, enableSnippets: false, enableLiveAutocompletion: true, }); this[`${name}Editor`] = editor; return fromEvent(editor, 'change').pipe(map(() => editor.getValue())); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: PreviewEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.6", type: PreviewEditorComponent, selector: "dc-preview-editor", inputs: { scripts: "scripts", initUiModel: "initUiModel", initDataModel: "initDataModel", title: "title" }, host: { properties: { "style.flex": "this.flex" } }, viewQueries: [{ propertyName: "uiModelEl", first: true, predicate: ["uiModelEl"], descendants: true }, { propertyName: "uiModelJSONEl", first: true, predicate: ["uiModelJSONEl"], descendants: true }, { propertyName: "scriptsEl", first: true, predicate: ["scriptsEl"], descendants: true }, { propertyName: "dataModelEl", first: true, predicate: ["dataModelEl"], descendants: true }, { propertyName: "dynamicComponent", first: true, predicate: ["dynamicComponent"], descendants: true }], ngImport: i0, template: "<mat-card *ngIf=\"initUiModel\" class=\"h-100 preview-card d-flex flex-column\">\r\n <mat-card-header>\r\n <span class=\"flex-fill align-self-center\">{{title}}</span>\r\n <button mat-icon-button *ngIf=\"codeSize\" (click)=\"toggleLayout()\"\r\n [matTooltip]=\"(isHorizontal ? 'Vertical' : 'Horizontal') + ' layout'\">\r\n <mat-icon>{{isHorizontal ? 'vertical_split' : 'horizontal_split'}}</mat-icon>\r\n </button>\r\n <button mat-icon-button matTooltip=\"Source code\" (click)=\"toggleSourceCode()\">\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n </mat-card-header>\r\n <mat-card-content class=\"h-100\">\r\n <as-split [useTransition]=\"true\" [direction]=\"direction\" unit=\"percent\" [gutterSize]=\"codeSize ? 11 : 0\">\r\n <as-split-area #area0=\"asSplitArea\" class=\"d-flex\" [size]=\"codeSize\">\r\n <mat-tab-group class=\"w-100 ui-model-tab\">\r\n <mat-tab label=\"UI Model\">\r\n <mat-tab-group class=\"w-100 h-100\" headerPosition=\"below\">\r\n <mat-tab label=\"XML\">\r\n <div #uiModelEl class=\"h-100\"></div>\r\n </mat-tab>\r\n <mat-tab label=\"JSON\">\r\n <div #uiModelJSONEl class=\"h-100\"></div>\r\n </mat-tab>\r\n </mat-tab-group>\r\n </mat-tab>\r\n <mat-tab label=\"Scripts\">\r\n <div #scriptsEl class=\"h-100\"></div>\r\n </mat-tab>\r\n <mat-tab label=\"Data Model\">\r\n <div #dataModelEl class=\"h-100\"></div>\r\n </mat-tab>\r\n </mat-tab-group>\r\n </as-split-area>\r\n <as-split-area [size]=\"100 - codeSize\" #area1=\"asSplitArea\">\r\n <div class=\"preview\">\r\n <ngx-dynamic-component class=\"d-block\" *ngIf=\"uiModel\" #dynamicComponent\r\n [xmlUIModel]='uiModel'\r\n [dataModel]='dataModel'\r\n (render)='onRendered($event)'\r\n (changedDataModel)=\"onDataModelChange($event)\"\r\n (eventHandlers)=\"eventHandlers($event)\"></ngx-dynamic-component>\r\n </div>\r\n </as-split-area>\r\n </as-split>\r\n </mat-card-content>\r\n</mat-card>\r\n", styles: [":host{display:flex}::ng-deep mat-card .mat-card-header-text{margin:0}::ng-deep mat-card .mat-mdc-tab-body-wrapper,::ng-deep mat-card .mat-tab-body-wrapper{display:block;overflow:visible;height:100%;min-height:200px}::ng-deep mat-card .mat-mdc-tab-body-wrapper mat-tab-body,::ng-deep mat-card .mat-tab-body-wrapper mat-tab-body{height:100%}.preview-card mat-card-content ::ng-deep .as-init .as-split-gutter,.preview-card mat-card-content .as-split-area{height:auto}.ui-model-tab ::ng-deep .mat-tab-label{height:24px;font-size:.85rem}mat-card{width:100%;padding:0}mat-card mat-card-header,mat-card mat-card-content{padding:1em}mat-card mat-divider{margin:1em 0;position:static}mat-card mat-card-header{color:#00000080;background:#eeeeee;padding:8px 20px}mat-card mat-card-header mat-icon{cursor:pointer}mat-card mat-card-header h3{margin:0}mat-card .preview{background:#eeeeee;padding:1em}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.NGXDynamicComponent, selector: "ngx-dynamic-component", inputs: ["dataModel", "xmlUIModel"], outputs: ["render", "changedDataModel", "eventHandlers"] }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i4.MatTab, selector: "mat-tab", inputs: ["disabled"], exportAs: ["matTab"] }, { kind: "component", type: i4.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "disableRipple", "fitInkBarToContent", "mat-stretch-tabs"], exportAs: ["matTabGroup"] }, { kind: "component", type: i5.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i5.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i5.MatCardHeader, selector: "mat-card-header" }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { kind: "component", type: i8.SplitComponent, selector: "as-split", inputs: ["direction", "unit", "gutterSize", "gutterStep", "restrictMove", "useTransition", "disabled", "dir", "gutterDblClickDuration", "gutterClickDeltaPx", "gutterAriaLabel"], outputs: ["transitionEnd", "dragStart", "dragEnd", "gutterClick", "gutterDblClick"], exportAs: ["asSplit"] }, { kind: "directive", type: i8.SplitAreaDirective, selector: "as-split-area, [as-split-area]", inputs: ["order", "size", "minSize", "maxSize", "lockSize", "visible"], exportAs: ["asSplitArea"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: PreviewEditorComponent, decorators: [{ type: Component, args: [{ selector: 'dc-preview-editor', template: "<mat-card *ngIf=\"initUiModel\" class=\"h-100 preview-card d-flex flex-column\">\r\n <mat-card-header>\r\n <span class=\"flex-fill align-self-center\">{{title}}</span>\r\n <button mat-icon-button *ngIf=\"codeSize\" (click)=\"toggleLayout()\"\r\n [matTooltip]=\"(isHorizontal ? 'Vertical' : 'Horizontal') + ' layout'\">\r\n <mat-icon>{{isHorizontal ? 'vertical_split' : 'horizontal_split'}}</mat-icon>\r\n </button>\r\n <button mat-icon-button matTooltip=\"Source code\" (click)=\"toggleSourceCode()\">\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n </mat-card-header>\r\n <mat-card-content class=\"h-100\">\r\n <as-split [useTransition]=\"true\" [direction]=\"direction\" unit=\"percent\" [gutterSize]=\"codeSize ? 11 : 0\">\r\n <as-split-area #area0=\"asSplitArea\" class=\"d-flex\" [size]=\"codeSize\">\r\n <mat-tab-group class=\"w-100 ui-model-tab\">\r\n <mat-tab label=\"UI Model\">\r\n <mat-tab-group class=\"w-100 h-100\" headerPosition=\"below\">\r\n <mat-tab label=\"XML\">\r\n <div #uiModelEl class=\"h-100\"></div>\r\n </mat-tab>\r\n <mat-tab label=\"JSON\">\r\n <div #uiModelJSONEl class=\"h-100\"></div>\r\n </mat-tab>\r\n </mat-tab-group>\r\n </mat-tab>\r\n <mat-tab label=\"Scripts\">\r\n <div #scriptsEl class=\"h-100\"></div>\r\n </mat-tab>\r\n <mat-tab label=\"Data Model\">\r\n <div #dataModelEl class=\"h-100\"></div>\r\n </mat-tab>\r\n </mat-tab-group>\r\n </as-split-area>\r\n <as-split-area [size]=\"100 - codeSize\" #area1=\"asSplitArea\">\r\n <div class=\"preview\">\r\n <ngx-dynamic-component class=\"d-block\" *ngIf=\"uiModel\" #dynamicComponent\r\n [xmlUIModel]='uiModel'\r\n [dataModel]='dataModel'\r\n (render)='onRendered($event)'\r\n (changedDataModel)=\"onDataModelChange($event)\"\r\n (eventHandlers)=\"eventHandlers($event)\"></ngx-dynamic-component>\r\n </div>\r\n </as-split-area>\r\n </as-split>\r\n </mat-card-content>\r\n</mat-card>\r\n", styles: [":host{display:flex}::ng-deep mat-card .mat-card-header-text{margin:0}::ng-deep mat-card .mat-mdc-tab-body-wrapper,::ng-deep mat-card .mat-tab-body-wrapper{display:block;overflow:visible;height:100%;min-height:200px}::ng-deep mat-card .mat-mdc-tab-body-wrapper mat-tab-body,::ng-deep mat-card .mat-tab-body-wrapper mat-tab-body{height:100%}.preview-card mat-card-content ::ng-deep .as-init .as-split-gutter,.preview-card mat-card-content .as-split-area{height:auto}.ui-model-tab ::ng-deep .mat-tab-label{height:24px;font-size:.85rem}mat-card{width:100%;padding:0}mat-card mat-card-header,mat-card mat-card-content{padding:1em}mat-card mat-divider{margin:1em 0;position:static}mat-card mat-card-header{color:#00000080;background:#eeeeee;padding:8px 20px}mat-card mat-card-header mat-icon{cursor:pointer}mat-card mat-card-header h3{margin:0}mat-card .preview{background:#eeeeee;padding:1em}\n"] }] }], propDecorators: { scripts: [{ type: Input }], initUiModel: [{ type: Input }], initDataModel: [{ type: Input }], title: [{ type: Input }], uiModelEl: [{ type: ViewChild, args: ['uiModelEl'] }], uiModelJSONEl: [{ type: ViewChild, args: ['uiModelJSONEl'] }], scriptsEl: [{ type: ViewChild, args: ['scriptsEl'] }], dataModelEl: [{ type: ViewChild, args: ['dataModelEl'] }], dynamicComponent: [{ type: ViewChild, args: ['dynamicComponent'] }], flex: [{ type: HostBinding, args: ['style.flex'] }] } }); class AddDialogComponent { dialogRef; categories = []; constructor(dialogRef) { this.dialogRef = dialogRef; } ngOnInit() { this.categories = []; } selectComponent(item) { this.dialogRef.close(item.defaultModel || item.example.uiModel || { type: `${item.packageName}:${item.name}`, itemProperties: {}, containerProperties: {} }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: AddDialogComponent, deps: [{ token: i1$1.MatDialogRef }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.6", type: AddDialogComponent, selector: "dc-add-dialog", ngImport: i0, template: ` <mat-list role="list" class="components" *ngFor="let cat of categories"> <h3 class="mat-h3">{{cat.name}}</h3> <mat-list-item role="listitem" (click)="selectComponent(item)" *ngFor="let item of cat.components"> {{item.name}} - {{item.description}} </mat-list-item> </mat-list> `, isInline: true, styles: [":host{min-width:300px;display:block}mat-list h3{margin:0;text-decoration:underline}.components mat-list-item{height:auto;cursor:pointer}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: i3$1.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i3$1.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: AddDialogComponent, decorators: [{ type: Component, args: [{ selector: 'dc-add-dialog', template: ` <mat-list role="list" class="components" *ngFor="let cat of categories"> <h3 class="mat-h3">{{cat.name}}</h3> <mat-list-item role="listitem" (click)="selectComponent(item)" *ngFor="let item of cat.components"> {{item.name}} - {{item.description}} </mat-list-item> </mat-list> `, styles: [":host{min-width:300px;display:block}mat-list h3{margin:0;text-decoration:underline}.components mat-list-item{height:auto;cursor:pointer}\n"] }] }], ctorParameters: function () { return [{ type: i1$1.MatDialogRef }]; } }); class PropertiesEditorComponent { uiModel; editorContainer; editBtn; updatedProperty = new EventEmitter(); itemProperties = []; properties = []; showEditor = false; get positionClass() { // eslint-disable-next-line no-underscore-dangle const btnPos = this.editBtn._elementRef.nativeElement.getBoundingClientRect().right; const docWidth = document.body.offsetWidth; return docWidth - btnPos < 200 ? 'left' : ''; } onClick(targetElement) { if (this.editorContainer) { const clickedInside = this.editorContainer.nativeElement.contains(targetElement); // eslint-disable-next-line no-underscore-dangle if (!clickedInside && this.editBtn._elementRef.nativeElement.contains(targetElement)) { // Clicked on button. const itemProps = this.uiModel.itemProperties || {}; this.properties = this.itemProperties.map(({ name }) => { let value = itemProps[name]; if (value === undefined) { value = ''; } else if (typeof value === 'object') { value = JSON.stringify(value); } return { name, value }; }); this.showEditor = true; } else if (!clickedInside) { // Clicked outside. this.showEditor = false; this.updatedProperty.emit(); } } } ngOnInit() { this.itemProperties = CoreService.getComponentProperties(this.uiModel.type); } updateProperty(evt, prop) { try { // If property value is an object or an array. this.uiModel.itemProperties[prop] = JSON.parse(evt.target.value); } catch { this.uiModel.itemProperties[prop] = evt.target.value; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: PropertiesEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.6", type: PropertiesEditorComponent, selector: "dc-properties-editor", inputs: { uiModel: "uiModel" }, outputs: { updatedProperty: "updatedProperty" }, host: { listeners: { "document:click": "onClick($event.target)" } }, viewQueries: [{ propertyName: "editorContainer", first: true, predicate: ["editorContainer"], descendants: true }, { propertyName: "editBtn", first: true, predicate: ["editBtn"], descendants: true }], ngImport: i0, template: ` <button mat-icon-button matTooltip="Edit properties" (click)="showEditor = true" #editBtn> <mat-icon>edit</mat-icon> </button> <div class="editor-container" #editorContainer fxLayout="column" *ngIf="showEditor" [ngClass]="positionClass"> <mat-form-field *ngFor="let property of properties"> <input matInput [placeholder]="property.name" [value]="property.value" (input)="updateProperty($event, property.name)"> </mat-form-field> </div> `, isInline: true, styles: [".editor-container{position:absolute;background:white;top:0;left:40px;z-index:3;padding:10px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.editor-container.left{left:-200px}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { kind: "directive", type: i5$1.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: PropertiesEditorComponent, decorators: [{ type: Component, args: [{ selector: 'dc-properties-editor', template: ` <button mat-icon-button matTooltip="Edit properties" (click)="showEditor = true" #editBtn> <mat-icon>edit</mat-icon> </button> <div class="editor-container" #editorContainer fxLayout="column" *ngIf="showEditor" [ngClass]="positionClass"> <mat-form-field *ngFor="let property of properties"> <input matInput [placeholder]="property.name" [value]="property.value" (input)="updateProperty($event, property.name)"> </mat-form-field> </div> `, styles: [".editor-container{position:absolute;background:white;top:0;left:40px;z-index:3;padding:10px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.editor-container.left{left:-200px}\n"] }] }], propDecorators: { uiModel: [{ type: Input }], editorContainer: [{ type: ViewChild, args: ['editorContainer'] }], editBtn: [{ type: ViewChild, args: ['editBtn'] }], updatedProperty: [{ type: Output }], onClick: [{ type: HostListener, args: ['document:click', ['$event.target']] }] } }); class ControlEditorComponent { dialog; uiModel; uiModelChanged = new EventEmitter(); uiModelRemoved = new EventEmitter(); constructor(dialog) { this.dialog = dialog; } openAddDialog() { const dialogRef = this.dialog.open(AddDialogComponent); dialogRef.afterClosed().subscribe(item => { this.uiModel.children.push(item); this.uiModelChanged.emit(); }); } onHover(evt) { const dragEl = this.getParentDrag(evt.target); dragEl.classList.add('drag-selected'); } onMouseLeave(evt) { const dragEl = this.getParentDrag(evt.target); dragEl.classList.remove('drag-selected'); } getDragTooltip() { return this.uiModel.type === 'material:flex-container' ? 'Drag container' : 'Drag component'; } getParentDrag(el) { let dragEl = el; while (!['item', 'row', 'col-sm'].some(c => Array.from(dragEl.classList).includes(c))) { dragEl = dragEl.parentNode; } return dragEl; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: ControlEditorComponent, deps: [{ token: i1$1.MatDialog }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.6", type: ControlEditorComponent, selector: "dc-control-editor", inputs: { uiModel: "uiModel" }, outputs: { uiModelChanged: "uiModelChanged", uiModelRemoved: "uiModelRemoved" }, ngImport: i0, template: ` <dc-properties-editor [uiModel]="uiModel" (updatedProperty)="uiModelChanged.emit()"></dc-properties-editor> <button mat-icon-button [matTooltip]="getDragTooltip()" (mouseover)="onHover($event)" (focus)="onHover($event)" (mouseleave)="onMouseLeave($event)" class="handle"> <svg width="24px" fill="currentColor" viewBox="0 0 24 24"> <path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"> </path> <path d="M0 0h24v24H0z" fill="none"></path> </svg> </button> <button mat-icon-button class="add-component" matTooltip="Add component" (click)="openAddDialog()"> <mat-icon>add</mat-icon> </button> <button mat-icon-button matTooltip="Remove" (click)="uiModelRemoved.emit()"> <mat-icon>clear</mat-icon> </button> `, isInline: true, styles: ["::ng-deep .preview dc-container dc-container-row.row{min-height:100px;border:1px dashed rgba(0,0,0,0)}::ng-deep .preview dc-container dc-container-row.row.active{border-color:gray}::ng-deep .preview.edit-mode dc-container dc-container-row.row{border-color:#00000040}::ng-deep .preview.edit-mode dc-container dc-container-row.row>dc-control-editor{left:-50px}::ng-deep .preview.edit-mode dc-container dc-container-row.row>dc-control-editor .handle{display:none}::ng-deep .preview.edit-mode dc-container dc-container-row.row>dc-control-editor .add-component{display:inline-block}::ng-deep .preview.edit-mode dc-container dc-container-row.row .col-sm dc-ui-flex-container+dc-control-editor{left:60px}::ng-deep .preview dc-ui-flex-container .item,::ng-deep .preview dc-container .item,::ng-deep .preview dc-container dc-container-row.row,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-]{position:relative;border:1px dashed rgba(0,0,0,0)}::ng-deep .preview dc-ui-flex-container .item:hover>dc-control-editor,::ng-deep .preview dc-container .item:hover>dc-control-editor,::ng-deep .preview dc-container dc-container-row.row:hover>dc-control-editor,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-]:hover>dc-control-editor{display:block}::ng-deep .preview dc-ui-flex-container .item.drag-selected,::ng-deep .preview dc-container .item.drag-selected,::ng-deep .preview dc-container dc-container-row.row.drag-selected,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-].drag-selected{border-color:gray}::ng-deep .preview dc-ui-flex-container .item.drag-selected dc-control-editor,::ng-deep .preview dc-container .item.drag-selected dc-control-editor,::ng-deep .preview dc-container dc-container-row.row.drag-selected dc-control-editor,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-].drag-selected dc-control-editor{display:block!important}::ng-deep .preview dc-ui-flex-container .item dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container .item dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container dc-container-row.row dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-] dc-ui-flex-container+dc-control-editor>.handle{color:#000000bf}::ng-deep .preview dc-ui-flex-container .item:hover dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container .item:hover dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container dc-container-row.row:hover dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-]:hover dc-ui-flex-container+dc-control-editor>.handle{color:#000c}::ng-deep .preview dc-ui-flex-container .item dc-ui-flex-container+dc-control-editor,::ng-deep .preview dc-container .item dc-ui-flex-container+dc-control-editor,::ng-deep .preview dc-container dc-container-row.row dc-ui-flex-container+dc-control-editor,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-] dc-ui-flex-container+dc-control-editor{left:-50px}::ng-deep .preview dc-container.container dc-container-row.row>dc-control-editor{left:-50px}::ng-deep .gu-mirror{position:fixed!important;margin:0!important;z-index:9999!important;opacity:.8;-ms-filter:\"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)\";filter:alpha(opacity=80);pointer-events:none;box-sizing:border-box;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;background:#eeeeee}::ng-deep .gu-mirror>dc-control-editor{display:block!important}::ng-deep .gu-mirror>dc-ui-flex-container+dc-control-editor{left:-50px}::ng-deep .gu-hide{left:-9999px!important}::ng-deep .gu-unselectable{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}::ng-deep .gu-transit{position:relative;transition:transform .25s cubic-bezier(0,0,.2,1)}::ng-deep .gu-transit:after{content:\" \";top:0;display:block;position:absolute;background:#ccc;width:100%;height:100%;z-index:1}::ng-deep .gu-transit dc-control-editor{display:none!important}:host{position:absolute;color:#00000080;top:0;right:0;z-index:2;max-width:105px;display:none;background:rgba(0,0,0,.25);border-radius:4px}:host:hover{cursor:move;color:#000000bf}:host ::ng-deep button{height:35px;line-height:35px;width:35px}:host .add-component{display:none}\n"], dependencies: [{ kind: "component", type: i2$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { kind: "component", type: PropertiesEditorComponent, selector: "dc-properties-editor", inputs: ["uiModel"], outputs: ["updatedProperty"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: ControlEditorComponent, decorators: [{ type: Component, args: [{ selector: 'dc-control-editor', template: ` <dc-properties-editor [uiModel]="uiModel" (updatedProperty)="uiModelChanged.emit()"></dc-properties-editor> <button mat-icon-button [matTooltip]="getDragTooltip()" (mouseover)="onHover($event)" (focus)="onHover($event)" (mouseleave)="onMouseLeave($event)" class="handle"> <svg width="24px" fill="currentColor" viewBox="0 0 24 24"> <path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"> </path> <path d="M0 0h24v24H0z" fill="none"></path> </svg> </button> <button mat-icon-button class="add-component" matTooltip="Add component" (click)="openAddDialog()"> <mat-icon>add</mat-icon> </button> <button mat-icon-button matTooltip="Remove" (click)="uiModelRemoved.emit()"> <mat-icon>clear</mat-icon> </button> `, styles: ["::ng-deep .preview dc-container dc-container-row.row{min-height:100px;border:1px dashed rgba(0,0,0,0)}::ng-deep .preview dc-container dc-container-row.row.active{border-color:gray}::ng-deep .preview.edit-mode dc-container dc-container-row.row{border-color:#00000040}::ng-deep .preview.edit-mode dc-container dc-container-row.row>dc-control-editor{left:-50px}::ng-deep .preview.edit-mode dc-container dc-container-row.row>dc-control-editor .handle{display:none}::ng-deep .preview.edit-mode dc-container dc-container-row.row>dc-control-editor .add-component{display:inline-block}::ng-deep .preview.edit-mode dc-container dc-container-row.row .col-sm dc-ui-flex-container+dc-control-editor{left:60px}::ng-deep .preview dc-ui-flex-container .item,::ng-deep .preview dc-container .item,::ng-deep .preview dc-container dc-container-row.row,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-]{position:relative;border:1px dashed rgba(0,0,0,0)}::ng-deep .preview dc-ui-flex-container .item:hover>dc-control-editor,::ng-deep .preview dc-container .item:hover>dc-control-editor,::ng-deep .preview dc-container dc-container-row.row:hover>dc-control-editor,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-]:hover>dc-control-editor{display:block}::ng-deep .preview dc-ui-flex-container .item.drag-selected,::ng-deep .preview dc-container .item.drag-selected,::ng-deep .preview dc-container dc-container-row.row.drag-selected,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-].drag-selected{border-color:gray}::ng-deep .preview dc-ui-flex-container .item.drag-selected dc-control-editor,::ng-deep .preview dc-container .item.drag-selected dc-control-editor,::ng-deep .preview dc-container dc-container-row.row.drag-selected dc-control-editor,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-].drag-selected dc-control-editor{display:block!important}::ng-deep .preview dc-ui-flex-container .item dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container .item dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container dc-container-row.row dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-] dc-ui-flex-container+dc-control-editor>.handle{color:#000000bf}::ng-deep .preview dc-ui-flex-container .item:hover dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container .item:hover dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container dc-container-row.row:hover dc-ui-flex-container+dc-control-editor>.handle,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-]:hover dc-ui-flex-container+dc-control-editor>.handle{color:#000c}::ng-deep .preview dc-ui-flex-container .item dc-ui-flex-container+dc-control-editor,::ng-deep .preview dc-container .item dc-ui-flex-container+dc-control-editor,::ng-deep .preview dc-container dc-container-row.row dc-ui-flex-container+dc-control-editor,::ng-deep .preview dc-container dc-container-row.row>div[class*=col-] dc-ui-flex-container+dc-control-editor{left:-50px}::ng-deep .preview dc-container.container dc-container-row.row>dc-control-editor{left:-50px}::ng-deep .gu-mirror{position:fixed!important;margin:0!important;z-index:9999!important;opacity:.8;-ms-filter:\"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)\";filter:alpha(opacity=80);pointer-events:none;box-sizing:border-box;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f;background:#eeeeee}::ng-deep .gu-mirror>dc-control-editor{display:block!important}::ng-deep .gu-mirror>dc-ui-flex-container+dc-control-editor{left:-50px}::ng-deep .gu-hide{left:-9999px!important}::ng-deep .gu-unselectable{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}::ng-deep .gu-transit{position:relative;transition:transform .25s cubic-bezier(0,0,.2,1)}::ng-deep .gu-transit:after{content:\" \";top:0;display:block;position:absolute;background:#ccc;width:100%;height:100%;z-index:1}::ng-deep .gu-transit dc-control-editor{display:none!important}:host{position:absolute;color:#00000080;top:0;right:0;z-index:2;max-width:105px;display:none;background:rgba(0,0,0,.25);border-radius:4px}:host:hover{cursor:move;color:#000000bf}:host ::ng-deep button{height:35px;line-height:35px;width:35px}:host .add-component{display:none}\n"] }] }], ctorParameters: function () { return [{ type: i1$1.MatDialog }]; }, propDecorators: { uiModel: [{ type: Input }], uiModelChanged: [{ type: Output }], uiModelRemoved: [{ type: Output }] } }); const angularSplitModuleForRoot = AngularSplitModule.forRoot(); class ToolsModule { static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: ToolsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.1.6", ngImport: i0, type: ToolsModule, declarations: [PreviewEditorComponent, ControlEditorComponent, PropertiesEditorComponent, AddDialogComponent], imports: [CommonModule, DynamicComponentsCoreModule, DynamicComponentsBootstrapModule, MatToolbarModule, MatButtonModule, MatTabsModule, MatDividerModule, MatCardModule, MatIconModule, MatTooltipModule, MatInputModule, MatFormFieldModule, MatDialogModule, MatListModule, FormsModule, ReactiveFormsModule, i8.AngularSplitModule], exports: [PreviewEditorComponent] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: ToolsModule, imports: [CommonModule, DynamicComponentsCoreModule, DynamicComponentsBootstrapModule, MatToolbarModule, MatButtonModule, MatTabsModule, MatDividerModule, MatCardModule, MatIconModule, MatTooltipModule, MatInputModule, MatFormFieldModule, MatDialogModule, MatListModule, FormsModule, ReactiveFormsModule, angularSplitModuleForRoot] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: ToolsModule, decorators: [{ type: NgModule, args: [{ declarations: [ PreviewEditorComponent, ControlEditorComponent, PropertiesEditorComponent, AddDialogComponent ], imports: [ CommonModule, DynamicComponentsCoreModule, DynamicComponentsBootstrapModule, MatToolbarModule, MatButtonModule, MatTabsModule, MatDividerModule, MatCardModule, MatIconModule, MatTooltipModule, MatInputModule, MatFormFieldModule, MatDialogModule, MatListModule, FormsModule, ReactiveFormsModule, angularSplitModuleForRoot ], exports: [PreviewEditorComponent] }] }] }); /* * Public API Surface of tools */ /** * Generated bundle index. Do not edit. */ export { PreviewEditorComponent, ToolsModule, angularSplitModuleForRoot }; //# sourceMappingURL=ngx-dynamic-components-tools.mjs.map